Merge llvm trunk r300422 and resolve conflicts.
This commit is contained in:
commit
990b41b569
@ -44,6 +44,9 @@ void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM);
|
||||
/** See llvm::createCFGSimplificationPass function. */
|
||||
void LLVMAddCFGSimplificationPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createLateCFGSimplificationPass function. */
|
||||
void LLVMAddLateCFGSimplificationPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createDeadStoreEliminationPass function. */
|
||||
void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
@ -551,7 +551,7 @@ lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
|
||||
lto_bool_t ShouldEmbedUselists);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @} // endgoup LLVMCLTO
|
||||
* @defgroup LLVMCTLTO ThinLTO
|
||||
* @ingroup LLVMC
|
||||
*
|
||||
@ -668,75 +668,6 @@ const char *thinlto_module_get_object_file(thinlto_code_gen_t cg,
|
||||
extern lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg,
|
||||
lto_codegen_model);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control
|
||||
* @ingroup LLVMCTLTO
|
||||
*
|
||||
* These entry points control the ThinLTO cache. The cache is intended to
|
||||
* support incremental build, and thus needs to be persistent accross build.
|
||||
* The client enabled the cache by supplying a path to an existing directory.
|
||||
* The code generator will use this to store objects files that may be reused
|
||||
* during a subsequent build.
|
||||
* To avoid filling the disk space, a few knobs are provided:
|
||||
* - The pruning interval limit the frequency at which the garbage collector
|
||||
* will try to scan the cache directory to prune it from expired entries.
|
||||
* Setting to -1 disable the pruning (default).
|
||||
* - The pruning expiration time indicates to the garbage collector how old an
|
||||
* entry needs to be to be removed.
|
||||
* - Finally, the garbage collector can be instructed to prune the cache till
|
||||
* the occupied space goes below a threshold.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the path to a directory to use as a cache storage for incremental build.
|
||||
* Setting this activates caching.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg,
|
||||
const char *cache_dir);
|
||||
|
||||
/**
|
||||
* Sets the cache pruning interval (in seconds). A negative value disable the
|
||||
* pruning. An unspecified default value will be applied, and a value of 0 will
|
||||
* be ignored.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg,
|
||||
int interval);
|
||||
|
||||
/**
|
||||
* Sets the maximum cache size that can be persistent across build, in terms of
|
||||
* percentage of the available space on the the disk. Set to 100 to indicate
|
||||
* no limit, 50 to indicate that the cache size will not be left over half the
|
||||
* available space. A value over 100 will be reduced to 100, a value of 0 will
|
||||
* be ignored. An unspecified default value will be applied.
|
||||
*
|
||||
* The formula looks like:
|
||||
* AvailableSpace = FreeSpace + ExistingCacheSize
|
||||
* NewCacheSize = AvailableSpace * P/100
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_final_cache_size_relative_to_available_space(
|
||||
thinlto_code_gen_t cg, unsigned percentage);
|
||||
|
||||
/**
|
||||
* Sets the expiration (in seconds) for an entry in the cache. An unspecified
|
||||
* default value will be applied. A value of 0 will be ignored.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
|
||||
unsigned expiration);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the path to a directory to use as a storage for temporary bitcode files.
|
||||
* The intention is to make the bitcode files available for debugging at various
|
||||
@ -820,12 +751,77 @@ extern void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg,
|
||||
const char *name,
|
||||
int length);
|
||||
|
||||
/**
|
||||
* @} // endgoup LLVMCTLTO
|
||||
* @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control
|
||||
* @ingroup LLVMCTLTO
|
||||
*
|
||||
* These entry points control the ThinLTO cache. The cache is intended to
|
||||
* support incremental build, and thus needs to be persistent accross build.
|
||||
* The client enabled the cache by supplying a path to an existing directory.
|
||||
* The code generator will use this to store objects files that may be reused
|
||||
* during a subsequent build.
|
||||
* To avoid filling the disk space, a few knobs are provided:
|
||||
* - The pruning interval limit the frequency at which the garbage collector
|
||||
* will try to scan the cache directory to prune it from expired entries.
|
||||
* Setting to -1 disable the pruning (default).
|
||||
* - The pruning expiration time indicates to the garbage collector how old an
|
||||
* entry needs to be to be removed.
|
||||
* - Finally, the garbage collector can be instructed to prune the cache till
|
||||
* the occupied space goes below a threshold.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the path to a directory to use as a cache storage for incremental build.
|
||||
* Setting this activates caching.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg,
|
||||
const char *cache_dir);
|
||||
|
||||
/**
|
||||
* Sets the cache pruning interval (in seconds). A negative value disable the
|
||||
* pruning. An unspecified default value will be applied, and a value of 0 will
|
||||
* be ignored.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg,
|
||||
int interval);
|
||||
|
||||
/**
|
||||
* Sets the maximum cache size that can be persistent across build, in terms of
|
||||
* percentage of the available space on the the disk. Set to 100 to indicate
|
||||
* no limit, 50 to indicate that the cache size will not be left over half the
|
||||
* available space. A value over 100 will be reduced to 100, a value of 0 will
|
||||
* be ignored. An unspecified default value will be applied.
|
||||
*
|
||||
* The formula looks like:
|
||||
* AvailableSpace = FreeSpace + ExistingCacheSize
|
||||
* NewCacheSize = AvailableSpace * P/100
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_final_cache_size_relative_to_available_space(
|
||||
thinlto_code_gen_t cg, unsigned percentage);
|
||||
|
||||
/**
|
||||
* Sets the expiration (in seconds) for an entry in the cache. An unspecified
|
||||
* default value will be applied. A value of 0 will be ignored.
|
||||
*
|
||||
* \since LTO_API_VERSION=18
|
||||
*/
|
||||
extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
|
||||
unsigned expiration);
|
||||
|
||||
/**
|
||||
* @} // endgroup LLVMCTLTO_CACHING
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* LLVM_C_LTO_H */
|
||||
|
@ -18,9 +18,19 @@
|
||||
#define LLVM_ADT_APFLOAT_H
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <memory>
|
||||
|
||||
#define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL) \
|
||||
do { \
|
||||
if (usesLayout<IEEEFloat>(getSemantics())) \
|
||||
return U.IEEE.METHOD_CALL; \
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics())) \
|
||||
return U.Double.METHOD_CALL; \
|
||||
llvm_unreachable("Unexpected semantics"); \
|
||||
} while (false)
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct fltSemantics;
|
||||
@ -42,7 +52,7 @@ enum lostFraction { // Example of truncated bits:
|
||||
lfMoreThanHalf // 1xxxxx x's not all zero
|
||||
};
|
||||
|
||||
/// \brief A self-contained host- and target-independent arbitrary-precision
|
||||
/// A self-contained host- and target-independent arbitrary-precision
|
||||
/// floating-point software implementation.
|
||||
///
|
||||
/// APFloat uses bignum integer arithmetic as provided by static functions in
|
||||
@ -130,22 +140,25 @@ enum lostFraction { // Example of truncated bits:
|
||||
// implementation classes. This struct should not define any non-static data
|
||||
// members.
|
||||
struct APFloatBase {
|
||||
// TODO remove this and use APInt typedef directly.
|
||||
typedef APInt::WordType integerPart;
|
||||
|
||||
/// A signed type to represent a floating point numbers unbiased exponent.
|
||||
typedef signed short ExponentType;
|
||||
|
||||
/// \name Floating Point Semantics.
|
||||
/// @{
|
||||
|
||||
static const fltSemantics &IEEEhalf();
|
||||
static const fltSemantics &IEEEsingle();
|
||||
static const fltSemantics &IEEEdouble();
|
||||
static const fltSemantics &IEEEquad();
|
||||
static const fltSemantics &PPCDoubleDouble();
|
||||
static const fltSemantics &x87DoubleExtended();
|
||||
static const fltSemantics &IEEEhalf() LLVM_READNONE;
|
||||
static const fltSemantics &IEEEsingle() LLVM_READNONE;
|
||||
static const fltSemantics &IEEEdouble() LLVM_READNONE;
|
||||
static const fltSemantics &IEEEquad() LLVM_READNONE;
|
||||
static const fltSemantics &PPCDoubleDouble() LLVM_READNONE;
|
||||
static const fltSemantics &x87DoubleExtended() LLVM_READNONE;
|
||||
|
||||
/// A Pseudo fltsemantic used to construct APFloats that cannot conflict with
|
||||
/// anything real.
|
||||
static const fltSemantics &Bogus();
|
||||
static const fltSemantics &Bogus() LLVM_READNONE;
|
||||
|
||||
/// @}
|
||||
|
||||
@ -191,7 +204,7 @@ struct APFloatBase {
|
||||
uninitialized
|
||||
};
|
||||
|
||||
/// \brief Enumeration of \c ilogb error results.
|
||||
/// Enumeration of \c ilogb error results.
|
||||
enum IlogbErrorKinds {
|
||||
IEK_Zero = INT_MIN + 1,
|
||||
IEK_NaN = INT_MIN,
|
||||
@ -227,7 +240,7 @@ class IEEEFloat final : public APFloatBase {
|
||||
|
||||
/// @}
|
||||
|
||||
/// \brief Returns whether this instance allocated memory.
|
||||
/// Returns whether this instance allocated memory.
|
||||
bool needsCleanup() const { return partCount() > 1; }
|
||||
|
||||
/// \name Convenience "constructors"
|
||||
@ -235,10 +248,6 @@ class IEEEFloat final : public APFloatBase {
|
||||
|
||||
/// @}
|
||||
|
||||
/// Used to insert APFloat objects, or objects that contain APFloat objects,
|
||||
/// into FoldingSets.
|
||||
void Profile(FoldingSetNodeID &NID) const;
|
||||
|
||||
/// \name Arithmetic
|
||||
/// @{
|
||||
|
||||
@ -255,53 +264,12 @@ class IEEEFloat final : public APFloatBase {
|
||||
/// IEEE-754R 5.3.1: nextUp/nextDown.
|
||||
opStatus next(bool nextDown);
|
||||
|
||||
/// \brief Operator+ overload which provides the default
|
||||
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
|
||||
IEEEFloat operator+(const IEEEFloat &RHS) const {
|
||||
IEEEFloat Result = *this;
|
||||
Result.add(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// \brief Operator- overload which provides the default
|
||||
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
|
||||
IEEEFloat operator-(const IEEEFloat &RHS) const {
|
||||
IEEEFloat Result = *this;
|
||||
Result.subtract(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// \brief Operator* overload which provides the default
|
||||
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
|
||||
IEEEFloat operator*(const IEEEFloat &RHS) const {
|
||||
IEEEFloat Result = *this;
|
||||
Result.multiply(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// \brief Operator/ overload which provides the default
|
||||
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
|
||||
IEEEFloat operator/(const IEEEFloat &RHS) const {
|
||||
IEEEFloat Result = *this;
|
||||
Result.divide(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Sign operations.
|
||||
/// @{
|
||||
|
||||
void changeSign();
|
||||
void clearSign();
|
||||
void copySign(const IEEEFloat &);
|
||||
|
||||
/// \brief A static helper to produce a copy of an APFloat value with its sign
|
||||
/// copied from some other APFloat.
|
||||
static IEEEFloat copySign(IEEEFloat Value, const IEEEFloat &Sign) {
|
||||
Value.copySign(Sign);
|
||||
return Value;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
@ -309,9 +277,8 @@ class IEEEFloat final : public APFloatBase {
|
||||
/// @{
|
||||
|
||||
opStatus convert(const fltSemantics &, roundingMode, bool *);
|
||||
opStatus convertToInteger(integerPart *, unsigned int, bool, roundingMode,
|
||||
bool *) const;
|
||||
opStatus convertToInteger(APSInt &, roundingMode, bool *) const;
|
||||
opStatus convertToInteger(MutableArrayRef<integerPart>, unsigned int, bool,
|
||||
roundingMode, bool *) const;
|
||||
opStatus convertFromAPInt(const APInt &, bool, roundingMode);
|
||||
opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
|
||||
bool, roundingMode);
|
||||
@ -398,7 +365,7 @@ class IEEEFloat final : public APFloatBase {
|
||||
/// Returns true if and only if the number has the largest possible finite
|
||||
/// magnitude in the current semantics.
|
||||
bool isLargest() const;
|
||||
|
||||
|
||||
/// Returns true if and only if the number is an exact integer.
|
||||
bool isInteger() const;
|
||||
|
||||
@ -407,7 +374,7 @@ class IEEEFloat final : public APFloatBase {
|
||||
IEEEFloat &operator=(const IEEEFloat &);
|
||||
IEEEFloat &operator=(IEEEFloat &&);
|
||||
|
||||
/// \brief Overload to compute a hash code for an APFloat value.
|
||||
/// Overload to compute a hash code for an APFloat value.
|
||||
///
|
||||
/// Note that the use of hash codes for floating point values is in general
|
||||
/// frought with peril. Equality is hard to define for these values. For
|
||||
@ -443,9 +410,9 @@ class IEEEFloat final : public APFloatBase {
|
||||
|
||||
/// If this value has an exact multiplicative inverse, store it in inv and
|
||||
/// return true.
|
||||
bool getExactInverse(IEEEFloat *inv) const;
|
||||
bool getExactInverse(APFloat *inv) const;
|
||||
|
||||
/// \brief Returns the exponent of the internal representation of the APFloat.
|
||||
/// Returns the exponent of the internal representation of the APFloat.
|
||||
///
|
||||
/// Because the radix of APFloat is 2, this is equivalent to floor(log2(x)).
|
||||
/// For special APFloat values, this returns special error codes:
|
||||
@ -456,7 +423,7 @@ class IEEEFloat final : public APFloatBase {
|
||||
///
|
||||
friend int ilogb(const IEEEFloat &Arg);
|
||||
|
||||
/// \brief Returns: X * 2^Exp for integral exponents.
|
||||
/// Returns: X * 2^Exp for integral exponents.
|
||||
friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode);
|
||||
|
||||
friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode);
|
||||
@ -532,8 +499,9 @@ class IEEEFloat final : public APFloatBase {
|
||||
opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract);
|
||||
opStatus handleOverflow(roundingMode);
|
||||
bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const;
|
||||
opStatus convertToSignExtendedInteger(integerPart *, unsigned int, bool,
|
||||
roundingMode, bool *) const;
|
||||
opStatus convertToSignExtendedInteger(MutableArrayRef<integerPart>,
|
||||
unsigned int, bool, roundingMode,
|
||||
bool *) const;
|
||||
opStatus convertFromUnsignedParts(const integerPart *, unsigned int,
|
||||
roundingMode);
|
||||
opStatus convertFromHexadecimalString(StringRef, roundingMode);
|
||||
@ -636,6 +604,13 @@ class DoubleAPFloat final : public APFloatBase {
|
||||
|
||||
opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
|
||||
opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
|
||||
opStatus multiply(const DoubleAPFloat &RHS, roundingMode RM);
|
||||
opStatus divide(const DoubleAPFloat &RHS, roundingMode RM);
|
||||
opStatus remainder(const DoubleAPFloat &RHS);
|
||||
opStatus mod(const DoubleAPFloat &RHS);
|
||||
opStatus fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
|
||||
const DoubleAPFloat &Addend, roundingMode RM);
|
||||
opStatus roundToIntegral(roundingMode RM);
|
||||
void changeSign();
|
||||
cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
|
||||
|
||||
@ -643,9 +618,49 @@ class DoubleAPFloat final : public APFloatBase {
|
||||
bool isNegative() const;
|
||||
|
||||
void makeInf(bool Neg);
|
||||
void makeZero(bool Neg);
|
||||
void makeLargest(bool Neg);
|
||||
void makeSmallest(bool Neg);
|
||||
void makeSmallestNormalized(bool Neg);
|
||||
void makeNaN(bool SNaN, bool Neg, const APInt *fill);
|
||||
|
||||
cmpResult compare(const DoubleAPFloat &RHS) const;
|
||||
bool bitwiseIsEqual(const DoubleAPFloat &RHS) const;
|
||||
APInt bitcastToAPInt() const;
|
||||
opStatus convertFromString(StringRef, roundingMode);
|
||||
opStatus next(bool nextDown);
|
||||
|
||||
opStatus convertToInteger(MutableArrayRef<integerPart> Input,
|
||||
unsigned int Width, bool IsSigned, roundingMode RM,
|
||||
bool *IsExact) const;
|
||||
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM);
|
||||
opStatus convertFromSignExtendedInteger(const integerPart *Input,
|
||||
unsigned int InputSize, bool IsSigned,
|
||||
roundingMode RM);
|
||||
opStatus convertFromZeroExtendedInteger(const integerPart *Input,
|
||||
unsigned int InputSize, bool IsSigned,
|
||||
roundingMode RM);
|
||||
unsigned int convertToHexString(char *DST, unsigned int HexDigits,
|
||||
bool UpperCase, roundingMode RM) const;
|
||||
|
||||
bool isDenormal() const;
|
||||
bool isSmallest() const;
|
||||
bool isLargest() const;
|
||||
bool isInteger() const;
|
||||
|
||||
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
|
||||
unsigned FormatMaxPadding) const;
|
||||
|
||||
bool getExactInverse(APFloat *inv) const;
|
||||
|
||||
friend int ilogb(const DoubleAPFloat &Arg);
|
||||
friend DoubleAPFloat scalbn(DoubleAPFloat X, int Exp, roundingMode);
|
||||
friend DoubleAPFloat frexp(const DoubleAPFloat &X, int &Exp, roundingMode);
|
||||
friend hash_code hash_value(const DoubleAPFloat &Arg);
|
||||
};
|
||||
|
||||
hash_code hash_value(const DoubleAPFloat &Arg);
|
||||
|
||||
} // End detail namespace
|
||||
|
||||
// This is a interface class that is currently forwarding functionalities from
|
||||
@ -770,26 +785,24 @@ class APFloat : public APFloatBase {
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
|
||||
void makeZero(bool Neg) { getIEEE().makeZero(Neg); }
|
||||
void makeZero(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeZero(Neg)); }
|
||||
|
||||
void makeInf(bool Neg) {
|
||||
if (usesLayout<IEEEFloat>(*U.semantics))
|
||||
return U.IEEE.makeInf(Neg);
|
||||
if (usesLayout<DoubleAPFloat>(*U.semantics))
|
||||
return U.Double.makeInf(Neg);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
void makeInf(bool Neg) { APFLOAT_DISPATCH_ON_SEMANTICS(makeInf(Neg)); }
|
||||
|
||||
void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
|
||||
getIEEE().makeNaN(SNaN, Neg, fill);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(makeNaN(SNaN, Neg, fill));
|
||||
}
|
||||
|
||||
void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); }
|
||||
void makeLargest(bool Neg) {
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(makeLargest(Neg));
|
||||
}
|
||||
|
||||
void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); }
|
||||
void makeSmallest(bool Neg) {
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallest(Neg));
|
||||
}
|
||||
|
||||
void makeSmallestNormalized(bool Neg) {
|
||||
getIEEE().makeSmallestNormalized(Neg);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(makeSmallestNormalized(Neg));
|
||||
}
|
||||
|
||||
// FIXME: This is due to clang 3.3 (or older version) always checks for the
|
||||
@ -804,7 +817,8 @@ class APFloat : public APFloatBase {
|
||||
: U(std::move(F), S) {}
|
||||
|
||||
cmpResult compareAbsoluteValue(const APFloat &RHS) const {
|
||||
assert(&getSemantics() == &RHS.getSemantics());
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only compare APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.compareAbsoluteValue(RHS.U.IEEE);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
@ -827,13 +841,7 @@ class APFloat : public APFloatBase {
|
||||
|
||||
~APFloat() = default;
|
||||
|
||||
bool needsCleanup() const {
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.needsCleanup();
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.needsCleanup();
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
bool needsCleanup() const { APFLOAT_DISPATCH_ON_SEMANTICS(needsCleanup()); }
|
||||
|
||||
/// Factory for Positive and Negative Zero.
|
||||
///
|
||||
@ -920,9 +928,13 @@ class APFloat : public APFloatBase {
|
||||
/// \param isIEEE - If 128 bit number, select between PPC and IEEE
|
||||
static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
|
||||
|
||||
void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
|
||||
/// Used to insert APFloat objects, or objects that contain APFloat objects,
|
||||
/// into FoldingSets.
|
||||
void Profile(FoldingSetNodeID &NID) const;
|
||||
|
||||
opStatus add(const APFloat &RHS, roundingMode RM) {
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only call on two APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.add(RHS.U.IEEE, RM);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
@ -930,6 +942,8 @@ class APFloat : public APFloatBase {
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus subtract(const APFloat &RHS, roundingMode RM) {
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only call on two APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.subtract(RHS.U.IEEE, RM);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
@ -937,95 +951,172 @@ class APFloat : public APFloatBase {
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus multiply(const APFloat &RHS, roundingMode RM) {
|
||||
return getIEEE().multiply(RHS.getIEEE(), RM);
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only call on two APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.multiply(RHS.U.IEEE, RM);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.multiply(RHS.U.Double, RM);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus divide(const APFloat &RHS, roundingMode RM) {
|
||||
return getIEEE().divide(RHS.getIEEE(), RM);
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only call on two APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.divide(RHS.U.IEEE, RM);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.divide(RHS.U.Double, RM);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus remainder(const APFloat &RHS) {
|
||||
return getIEEE().remainder(RHS.getIEEE());
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only call on two APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.remainder(RHS.U.IEEE);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.remainder(RHS.U.Double);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus mod(const APFloat &RHS) {
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only call on two APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.mod(RHS.U.IEEE);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.mod(RHS.U.Double);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus mod(const APFloat &RHS) { return getIEEE().mod(RHS.getIEEE()); }
|
||||
opStatus fusedMultiplyAdd(const APFloat &Multiplicand, const APFloat &Addend,
|
||||
roundingMode RM) {
|
||||
return getIEEE().fusedMultiplyAdd(Multiplicand.getIEEE(), Addend.getIEEE(),
|
||||
RM);
|
||||
assert(&getSemantics() == &Multiplicand.getSemantics() &&
|
||||
"Should only call on APFloats with the same semantics");
|
||||
assert(&getSemantics() == &Addend.getSemantics() &&
|
||||
"Should only call on APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.fusedMultiplyAdd(Multiplicand.U.IEEE, Addend.U.IEEE, RM);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.fusedMultiplyAdd(Multiplicand.U.Double, Addend.U.Double,
|
||||
RM);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
opStatus roundToIntegral(roundingMode RM) {
|
||||
return getIEEE().roundToIntegral(RM);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(roundToIntegral(RM));
|
||||
}
|
||||
opStatus next(bool nextDown) { return getIEEE().next(nextDown); }
|
||||
|
||||
// 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 {
|
||||
return APFloat(getIEEE() + RHS.getIEEE(), getSemantics());
|
||||
APFloat Result(*this);
|
||||
(void)Result.add(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Subtract two APFloats, rounding ties to the nearest even.
|
||||
/// No error checking.
|
||||
APFloat operator-(const APFloat &RHS) const {
|
||||
return APFloat(getIEEE() - RHS.getIEEE(), getSemantics());
|
||||
APFloat Result(*this);
|
||||
(void)Result.subtract(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Multiply two APFloats, rounding ties to the nearest even.
|
||||
/// No error checking.
|
||||
APFloat operator*(const APFloat &RHS) const {
|
||||
return APFloat(getIEEE() * RHS.getIEEE(), getSemantics());
|
||||
APFloat Result(*this);
|
||||
(void)Result.multiply(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Divide the first APFloat by the second, rounding ties to the nearest even.
|
||||
/// No error checking.
|
||||
APFloat operator/(const APFloat &RHS) const {
|
||||
return APFloat(getIEEE() / RHS.getIEEE(), getSemantics());
|
||||
APFloat Result(*this);
|
||||
(void)Result.divide(RHS, rmNearestTiesToEven);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void changeSign() { getIEEE().changeSign(); }
|
||||
void clearSign() { getIEEE().clearSign(); }
|
||||
void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); }
|
||||
void changeSign() { APFLOAT_DISPATCH_ON_SEMANTICS(changeSign()); }
|
||||
void clearSign() {
|
||||
if (isNegative())
|
||||
changeSign();
|
||||
}
|
||||
void copySign(const APFloat &RHS) {
|
||||
if (isNegative() != RHS.isNegative())
|
||||
changeSign();
|
||||
}
|
||||
|
||||
/// A static helper to produce a copy of an APFloat value with its sign
|
||||
/// copied from some other APFloat.
|
||||
static APFloat copySign(APFloat Value, const APFloat &Sign) {
|
||||
return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()),
|
||||
Value.getSemantics());
|
||||
Value.copySign(Sign);
|
||||
return Value;
|
||||
}
|
||||
|
||||
opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
|
||||
bool *losesInfo);
|
||||
opStatus convertToInteger(integerPart *Input, unsigned int Width,
|
||||
bool IsSigned, roundingMode RM,
|
||||
opStatus convertToInteger(MutableArrayRef<integerPart> Input,
|
||||
unsigned int Width, bool IsSigned, roundingMode RM,
|
||||
bool *IsExact) const {
|
||||
return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(
|
||||
convertToInteger(Input, Width, IsSigned, RM, IsExact));
|
||||
}
|
||||
opStatus convertToInteger(APSInt &Result, roundingMode RM,
|
||||
bool *IsExact) const {
|
||||
return getIEEE().convertToInteger(Result, RM, IsExact);
|
||||
}
|
||||
bool *IsExact) const;
|
||||
opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
|
||||
roundingMode RM) {
|
||||
return getIEEE().convertFromAPInt(Input, IsSigned, RM);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(convertFromAPInt(Input, IsSigned, RM));
|
||||
}
|
||||
opStatus convertFromSignExtendedInteger(const integerPart *Input,
|
||||
unsigned int InputSize, bool IsSigned,
|
||||
roundingMode RM) {
|
||||
return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned,
|
||||
RM);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(
|
||||
convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM));
|
||||
}
|
||||
opStatus convertFromZeroExtendedInteger(const integerPart *Input,
|
||||
unsigned int InputSize, bool IsSigned,
|
||||
roundingMode RM) {
|
||||
return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
|
||||
RM);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(
|
||||
convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM));
|
||||
}
|
||||
opStatus convertFromString(StringRef, roundingMode);
|
||||
APInt bitcastToAPInt() const { return getIEEE().bitcastToAPInt(); }
|
||||
APInt bitcastToAPInt() const {
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt());
|
||||
}
|
||||
double convertToDouble() const { return getIEEE().convertToDouble(); }
|
||||
float convertToFloat() const { return getIEEE().convertToFloat(); }
|
||||
|
||||
bool operator==(const APFloat &) const = delete;
|
||||
|
||||
cmpResult compare(const APFloat &RHS) const {
|
||||
return getIEEE().compare(RHS.getIEEE());
|
||||
assert(&getSemantics() == &RHS.getSemantics() &&
|
||||
"Should only compare APFloats with the same semantics");
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.compare(RHS.U.IEEE);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.compare(RHS.U.Double);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
|
||||
bool bitwiseIsEqual(const APFloat &RHS) const {
|
||||
return getIEEE().bitwiseIsEqual(RHS.getIEEE());
|
||||
if (&getSemantics() != &RHS.getSemantics())
|
||||
return false;
|
||||
if (usesLayout<IEEEFloat>(getSemantics()))
|
||||
return U.IEEE.bitwiseIsEqual(RHS.U.IEEE);
|
||||
if (usesLayout<DoubleAPFloat>(getSemantics()))
|
||||
return U.Double.bitwiseIsEqual(RHS.U.Double);
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
|
||||
unsigned int convertToHexString(char *DST, unsigned int HexDigits,
|
||||
bool UpperCase, roundingMode RM) const {
|
||||
return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(
|
||||
convertToHexString(DST, HexDigits, UpperCase, RM));
|
||||
}
|
||||
|
||||
bool isZero() const { return getCategory() == fcZero; }
|
||||
@ -1033,7 +1124,7 @@ class APFloat : public APFloatBase {
|
||||
bool isNaN() const { return getCategory() == fcNaN; }
|
||||
|
||||
bool isNegative() const { return getIEEE().isNegative(); }
|
||||
bool isDenormal() const { return getIEEE().isDenormal(); }
|
||||
bool isDenormal() const { APFLOAT_DISPATCH_ON_SEMANTICS(isDenormal()); }
|
||||
bool isSignaling() const { return getIEEE().isSignaling(); }
|
||||
|
||||
bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
|
||||
@ -1045,30 +1136,24 @@ class APFloat : public APFloatBase {
|
||||
bool isFiniteNonZero() const { return isFinite() && !isZero(); }
|
||||
bool isPosZero() const { return isZero() && !isNegative(); }
|
||||
bool isNegZero() const { return isZero() && isNegative(); }
|
||||
bool isSmallest() const { return getIEEE().isSmallest(); }
|
||||
bool isLargest() const { return getIEEE().isLargest(); }
|
||||
bool isInteger() const { return getIEEE().isInteger(); }
|
||||
bool isSmallest() const { APFLOAT_DISPATCH_ON_SEMANTICS(isSmallest()); }
|
||||
bool isLargest() const { APFLOAT_DISPATCH_ON_SEMANTICS(isLargest()); }
|
||||
bool isInteger() const { APFLOAT_DISPATCH_ON_SEMANTICS(isInteger()); }
|
||||
|
||||
APFloat &operator=(const APFloat &RHS) = default;
|
||||
APFloat &operator=(APFloat &&RHS) = default;
|
||||
|
||||
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
|
||||
unsigned FormatMaxPadding = 3) const {
|
||||
return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding);
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(
|
||||
toString(Str, FormatPrecision, FormatMaxPadding));
|
||||
}
|
||||
|
||||
void print(raw_ostream &) const;
|
||||
void dump() const;
|
||||
|
||||
bool getExactInverse(APFloat *inv) const {
|
||||
return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr);
|
||||
}
|
||||
|
||||
// This is for internal test only.
|
||||
// TODO: Remove it after the PPCDoubleDouble transition.
|
||||
const APFloat &getSecondFloat() const {
|
||||
assert(&getSemantics() == &PPCDoubleDouble());
|
||||
return U.Double.getSecond();
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(getExactInverse(inv));
|
||||
}
|
||||
|
||||
friend hash_code hash_value(const APFloat &Arg);
|
||||
@ -1085,22 +1170,36 @@ class APFloat : public APFloatBase {
|
||||
/// xlC compiler.
|
||||
hash_code hash_value(const APFloat &Arg);
|
||||
inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
|
||||
return APFloat(scalbn(X.getIEEE(), Exp, RM), X.getSemantics());
|
||||
if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
|
||||
return APFloat(scalbn(X.U.IEEE, Exp, RM), X.getSemantics());
|
||||
if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
|
||||
return APFloat(scalbn(X.U.Double, Exp, RM), X.getSemantics());
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
|
||||
/// \brief Equivalent of C standard library function.
|
||||
/// Equivalent of C standard library function.
|
||||
///
|
||||
/// While the C standard says Exp is an unspecified value for infinity and nan,
|
||||
/// this returns INT_MAX for infinities, and INT_MIN for NaNs.
|
||||
inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) {
|
||||
return APFloat(frexp(X.getIEEE(), Exp, RM), X.getSemantics());
|
||||
if (APFloat::usesLayout<detail::IEEEFloat>(X.getSemantics()))
|
||||
return APFloat(frexp(X.U.IEEE, Exp, RM), X.getSemantics());
|
||||
if (APFloat::usesLayout<detail::DoubleAPFloat>(X.getSemantics()))
|
||||
return APFloat(frexp(X.U.Double, Exp, RM), X.getSemantics());
|
||||
llvm_unreachable("Unexpected semantics");
|
||||
}
|
||||
/// \brief Returns the absolute value of the argument.
|
||||
/// Returns the absolute value of the argument.
|
||||
inline APFloat abs(APFloat X) {
|
||||
X.clearSign();
|
||||
return X;
|
||||
}
|
||||
|
||||
/// \brief Returns the negated value of the argument.
|
||||
inline APFloat neg(APFloat X) {
|
||||
X.changeSign();
|
||||
return X;
|
||||
}
|
||||
|
||||
/// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if
|
||||
/// both are not NaN. If either argument is a NaN, returns the other argument.
|
||||
LLVM_READONLY
|
||||
@ -1125,4 +1224,5 @@ inline APFloat maxnum(const APFloat &A, const APFloat &B) {
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#undef APFLOAT_DISPATCH_ON_SEMANTICS
|
||||
#endif // LLVM_ADT_APFLOAT_H
|
||||
|
@ -32,14 +32,6 @@ class raw_ostream;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
template <typename T> class ArrayRef;
|
||||
|
||||
// An unsigned host type used as a single part of a multi-part
|
||||
// bignum.
|
||||
typedef uint64_t integerPart;
|
||||
|
||||
const unsigned int host_char_bit = 8;
|
||||
const unsigned int integerPartWidth =
|
||||
host_char_bit * static_cast<unsigned int>(sizeof(integerPart));
|
||||
|
||||
class APInt;
|
||||
|
||||
inline APInt operator-(APInt);
|
||||
@ -75,8 +67,18 @@ inline APInt operator-(APInt);
|
||||
/// uses in its IR. This simplifies its use for LLVM.
|
||||
///
|
||||
class LLVM_NODISCARD APInt {
|
||||
unsigned BitWidth; ///< The number of bits in this APInt.
|
||||
public:
|
||||
typedef uint64_t WordType;
|
||||
|
||||
/// This enum is used to hold the constants we needed for APInt.
|
||||
enum : unsigned {
|
||||
/// Byte size of a word.
|
||||
APINT_WORD_SIZE = sizeof(WordType),
|
||||
/// Bits in a word.
|
||||
APINT_BITS_PER_WORD = APINT_WORD_SIZE * CHAR_BIT
|
||||
};
|
||||
|
||||
private:
|
||||
/// This union is used to store the integer value. When the
|
||||
/// integer bit-width <= 64, it uses VAL, otherwise it uses pVal.
|
||||
union {
|
||||
@ -84,14 +86,7 @@ class LLVM_NODISCARD APInt {
|
||||
uint64_t *pVal; ///< Used to store the >64 bits integer value.
|
||||
};
|
||||
|
||||
/// This enum is used to hold the constants we needed for APInt.
|
||||
enum {
|
||||
/// Bits in a word
|
||||
APINT_BITS_PER_WORD =
|
||||
static_cast<unsigned int>(sizeof(uint64_t)) * CHAR_BIT,
|
||||
/// Byte size of a word
|
||||
APINT_WORD_SIZE = static_cast<unsigned int>(sizeof(uint64_t))
|
||||
};
|
||||
unsigned BitWidth; ///< The number of bits in this APInt.
|
||||
|
||||
friend struct DenseMapAPIntKeyInfo;
|
||||
|
||||
@ -99,7 +94,7 @@ class LLVM_NODISCARD APInt {
|
||||
///
|
||||
/// This constructor is used only internally for speed of construction of
|
||||
/// temporaries. It is unsafe for general use so it is not public.
|
||||
APInt(uint64_t *val, unsigned bits) : BitWidth(bits), pVal(val) {}
|
||||
APInt(uint64_t *val, unsigned bits) : pVal(val), BitWidth(bits) {}
|
||||
|
||||
/// \brief Determine if this APInt just has one word to store value.
|
||||
///
|
||||
@ -147,7 +142,7 @@ class LLVM_NODISCARD APInt {
|
||||
return *this;
|
||||
|
||||
// Mask out the high bits.
|
||||
uint64_t mask = ~uint64_t(0ULL) >> (APINT_BITS_PER_WORD - wordBits);
|
||||
uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - wordBits);
|
||||
if (isSingleWord())
|
||||
VAL &= mask;
|
||||
else
|
||||
@ -196,32 +191,38 @@ class LLVM_NODISCARD APInt {
|
||||
/// out-of-line slow case for shl
|
||||
APInt shlSlowCase(unsigned shiftAmt) const;
|
||||
|
||||
/// out-of-line slow case for operator&
|
||||
APInt AndSlowCase(const APInt &RHS) const;
|
||||
|
||||
/// out-of-line slow case for operator|
|
||||
APInt OrSlowCase(const APInt &RHS) const;
|
||||
|
||||
/// out-of-line slow case for operator^
|
||||
APInt XorSlowCase(const APInt &RHS) const;
|
||||
|
||||
/// out-of-line slow case for operator=
|
||||
APInt &AssignSlowCase(const APInt &RHS);
|
||||
|
||||
/// out-of-line slow case for operator==
|
||||
bool EqualSlowCase(const APInt &RHS) const;
|
||||
bool EqualSlowCase(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for operator==
|
||||
bool EqualSlowCase(uint64_t Val) const;
|
||||
bool EqualSlowCase(uint64_t Val) const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for countLeadingZeros
|
||||
unsigned countLeadingZerosSlowCase() const;
|
||||
unsigned countLeadingZerosSlowCase() const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for countTrailingOnes
|
||||
unsigned countTrailingOnesSlowCase() const;
|
||||
unsigned countTrailingOnesSlowCase() const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for countPopulation
|
||||
unsigned countPopulationSlowCase() const;
|
||||
unsigned countPopulationSlowCase() const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for setBits.
|
||||
void setBitsSlowCase(unsigned loBit, unsigned hiBit);
|
||||
|
||||
/// out-of-line slow case for flipAllBits.
|
||||
void flipAllBitsSlowCase();
|
||||
|
||||
/// out-of-line slow case for operator&=.
|
||||
APInt& AndAssignSlowCase(const APInt& RHS);
|
||||
|
||||
/// out-of-line slow case for operator|=.
|
||||
APInt& OrAssignSlowCase(const APInt& RHS);
|
||||
|
||||
/// out-of-line slow case for operator^=.
|
||||
APInt& XorAssignSlowCase(const APInt& RHS);
|
||||
|
||||
public:
|
||||
/// \name Constructors
|
||||
@ -238,13 +239,14 @@ class LLVM_NODISCARD 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), VAL(0) {
|
||||
: BitWidth(numBits) {
|
||||
assert(BitWidth && "bitwidth too small");
|
||||
if (isSingleWord())
|
||||
if (isSingleWord()) {
|
||||
VAL = val;
|
||||
else
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
initSlowCase(val, isSigned);
|
||||
clearUnusedBits();
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Construct an APInt of numBits width, initialized as bigVal[].
|
||||
@ -280,7 +282,7 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// Simply makes *this a copy of that.
|
||||
/// @brief Copy Constructor.
|
||||
APInt(const APInt &that) : BitWidth(that.BitWidth), VAL(0) {
|
||||
APInt(const APInt &that) : BitWidth(that.BitWidth) {
|
||||
if (isSingleWord())
|
||||
VAL = that.VAL;
|
||||
else
|
||||
@ -288,7 +290,7 @@ class LLVM_NODISCARD APInt {
|
||||
}
|
||||
|
||||
/// \brief Move Constructor.
|
||||
APInt(APInt &&that) : BitWidth(that.BitWidth), VAL(that.VAL) {
|
||||
APInt(APInt &&that) : VAL(that.VAL), BitWidth(that.BitWidth) {
|
||||
that.BitWidth = 0;
|
||||
}
|
||||
|
||||
@ -303,7 +305,7 @@ class LLVM_NODISCARD APInt {
|
||||
///
|
||||
/// This is useful for object deserialization (pair this with the static
|
||||
/// method Read).
|
||||
explicit APInt() : BitWidth(1), VAL(0) {}
|
||||
explicit APInt() : VAL(0), BitWidth(1) {}
|
||||
|
||||
/// \brief Returns whether this instance allocated memory.
|
||||
bool needsCleanup() const { return !isSingleWord(); }
|
||||
@ -341,7 +343,7 @@ class LLVM_NODISCARD APInt {
|
||||
/// This checks to see if the value has all bits of the APInt are set or not.
|
||||
bool isAllOnesValue() const {
|
||||
if (isSingleWord())
|
||||
return VAL == ~integerPart(0) >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return VAL == UINT64_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return countPopulationSlowCase() == BitWidth;
|
||||
}
|
||||
|
||||
@ -406,7 +408,7 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// If this value is smaller than the specified limit, return it, otherwise
|
||||
/// return the limit value. This causes the value to saturate to the limit.
|
||||
uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const {
|
||||
uint64_t getLimitedValue(uint64_t Limit = UINT64_MAX) const {
|
||||
return (getActiveBits() > 64 || getZExtValue() > Limit) ? Limit
|
||||
: getZExtValue();
|
||||
}
|
||||
@ -418,6 +420,36 @@ class LLVM_NODISCARD APInt {
|
||||
/// width without remainder.
|
||||
bool isSplat(unsigned SplatSizeInBits) const;
|
||||
|
||||
/// \returns true if this APInt value is a sequence of \param numBits ones
|
||||
/// starting at the least significant bit with the remainder zero.
|
||||
bool isMask(unsigned numBits) const {
|
||||
assert(numBits != 0 && "numBits must be non-zero");
|
||||
assert(numBits <= BitWidth && "numBits out of range");
|
||||
if (isSingleWord())
|
||||
return VAL == (UINT64_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
unsigned Ones = countTrailingOnes();
|
||||
return (numBits == Ones) && ((Ones + countLeadingZeros()) == BitWidth);
|
||||
}
|
||||
|
||||
/// \returns true if this APInt is a non-empty sequence of ones starting at
|
||||
/// the least significant bit with the remainder zero.
|
||||
/// Ex. isMask(0x0000FFFFU) == true.
|
||||
bool isMask() const {
|
||||
if (isSingleWord())
|
||||
return isMask_64(VAL);
|
||||
unsigned Ones = countTrailingOnes();
|
||||
return (Ones > 0) && ((Ones + countLeadingZeros()) == BitWidth);
|
||||
}
|
||||
|
||||
/// \brief Return true if this APInt value contains a sequence of ones with
|
||||
/// the remainder zero.
|
||||
bool isShiftedMask() const {
|
||||
if (isSingleWord())
|
||||
return isShiftedMask_64(VAL);
|
||||
unsigned Ones = countPopulation();
|
||||
return (Ones + countTrailingZeros() + countLeadingZeros()) == BitWidth;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// \name Value Generators
|
||||
/// @{
|
||||
@ -501,12 +533,26 @@ class LLVM_NODISCARD APInt {
|
||||
///
|
||||
/// \returns An APInt value with the requested bits set.
|
||||
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit) {
|
||||
assert(hiBit <= numBits && "hiBit out of range");
|
||||
assert(loBit < numBits && "loBit out of range");
|
||||
if (hiBit < loBit)
|
||||
return getLowBitsSet(numBits, hiBit) |
|
||||
getHighBitsSet(numBits, numBits - loBit);
|
||||
return getLowBitsSet(numBits, hiBit - loBit).shl(loBit);
|
||||
APInt Res(numBits, 0);
|
||||
Res.setBits(loBit, hiBit);
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// \brief Get a value with upper bits starting at loBit set.
|
||||
///
|
||||
/// Constructs an APInt value that has a contiguous range of bits set. The
|
||||
/// bits from loBit (inclusive) to numBits (exclusive) will be set. All other
|
||||
/// bits will be zero. For example, with parameters(32, 12) you would get
|
||||
/// 0xFFFFF000.
|
||||
///
|
||||
/// \param numBits the intended bit width of the result
|
||||
/// \param loBit the index of the lowest bit to set.
|
||||
///
|
||||
/// \returns An APInt value with the requested bits set.
|
||||
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit) {
|
||||
APInt Res(numBits, 0);
|
||||
Res.setBitsFrom(loBit);
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// \brief Get a value with high bits set
|
||||
@ -516,15 +562,9 @@ class LLVM_NODISCARD APInt {
|
||||
/// \param numBits the bitwidth of the result
|
||||
/// \param hiBitsSet the number of high-order bits set in the result.
|
||||
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet) {
|
||||
assert(hiBitsSet <= numBits && "Too many bits to set!");
|
||||
// Handle a degenerate case, to avoid shifting by word size
|
||||
if (hiBitsSet == 0)
|
||||
return APInt(numBits, 0);
|
||||
unsigned shiftAmt = numBits - hiBitsSet;
|
||||
// For small values, return quickly
|
||||
if (numBits <= APINT_BITS_PER_WORD)
|
||||
return APInt(numBits, ~0ULL << shiftAmt);
|
||||
return getAllOnesValue(numBits).shl(shiftAmt);
|
||||
APInt Res(numBits, 0);
|
||||
Res.setHighBits(hiBitsSet);
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// \brief Get a value with low bits set
|
||||
@ -534,16 +574,9 @@ class LLVM_NODISCARD APInt {
|
||||
/// \param numBits the bitwidth of the result
|
||||
/// \param loBitsSet the number of low-order bits set in the result.
|
||||
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet) {
|
||||
assert(loBitsSet <= numBits && "Too many bits to set!");
|
||||
// Handle a degenerate case, to avoid shifting by word size
|
||||
if (loBitsSet == 0)
|
||||
return APInt(numBits, 0);
|
||||
if (loBitsSet == APINT_BITS_PER_WORD)
|
||||
return APInt(numBits, UINT64_MAX);
|
||||
// For small values, return quickly.
|
||||
if (loBitsSet <= APINT_BITS_PER_WORD)
|
||||
return APInt(numBits, UINT64_MAX >> (APINT_BITS_PER_WORD - loBitsSet));
|
||||
return getAllOnesValue(numBits).lshr(numBits - loBitsSet);
|
||||
APInt Res(numBits, 0);
|
||||
Res.setLowBits(loBitsSet);
|
||||
return Res;
|
||||
}
|
||||
|
||||
/// \brief Return a value containing V broadcasted over NewLen bits.
|
||||
@ -587,7 +620,9 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// \brief Postfix increment operator.
|
||||
///
|
||||
/// \returns a new APInt value representing *this incremented by one
|
||||
/// Increments *this by 1.
|
||||
///
|
||||
/// \returns a new APInt value representing the original value of *this.
|
||||
const APInt operator++(int) {
|
||||
APInt API(*this);
|
||||
++(*this);
|
||||
@ -601,7 +636,9 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// \brief Postfix decrement operator.
|
||||
///
|
||||
/// \returns a new APInt representing *this decremented by one.
|
||||
/// Decrements *this by 1.
|
||||
///
|
||||
/// \returns a new APInt value representing the original value of *this.
|
||||
const APInt operator--(int) {
|
||||
APInt API(*this);
|
||||
--(*this);
|
||||
@ -613,30 +650,13 @@ class LLVM_NODISCARD APInt {
|
||||
/// \returns *this decremented by one.
|
||||
APInt &operator--();
|
||||
|
||||
/// \brief Unary bitwise complement operator.
|
||||
///
|
||||
/// Performs a bitwise complement operation on this APInt.
|
||||
///
|
||||
/// \returns an APInt that is the bitwise complement of *this
|
||||
APInt operator~() const {
|
||||
APInt Result(*this);
|
||||
Result.flipAllBits();
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// \brief Logical negation operator.
|
||||
///
|
||||
/// Performs logical negation operation on this APInt.
|
||||
///
|
||||
/// \returns true if *this is zero, false otherwise.
|
||||
bool operator!() const {
|
||||
if (isSingleWord())
|
||||
return !VAL;
|
||||
|
||||
for (unsigned i = 0; i != getNumWords(); ++i)
|
||||
if (pVal[i])
|
||||
return false;
|
||||
return true;
|
||||
return *this == 0;
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -688,7 +708,16 @@ class LLVM_NODISCARD APInt {
|
||||
/// than 64, the value is zero filled in the unspecified high order bits.
|
||||
///
|
||||
/// \returns *this after assignment of RHS value.
|
||||
APInt &operator=(uint64_t RHS);
|
||||
APInt &operator=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL = RHS;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
pVal[0] = RHS;
|
||||
memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Bitwise AND assignment operator.
|
||||
///
|
||||
@ -696,7 +725,29 @@ class LLVM_NODISCARD APInt {
|
||||
/// assigned to *this.
|
||||
///
|
||||
/// \returns *this after ANDing with RHS.
|
||||
APInt &operator&=(const APInt &RHS);
|
||||
APInt &operator&=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
VAL &= RHS.VAL;
|
||||
return *this;
|
||||
}
|
||||
return AndAssignSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// \brief Bitwise AND assignment operator.
|
||||
///
|
||||
/// Performs a bitwise AND operation on this APInt and RHS. RHS is
|
||||
/// logically zero-extended or truncated to match the bit-width of
|
||||
/// the LHS.
|
||||
APInt &operator&=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL &= RHS;
|
||||
return *this;
|
||||
}
|
||||
pVal[0] &= RHS;
|
||||
memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Bitwise OR assignment operator.
|
||||
///
|
||||
@ -704,7 +755,14 @@ class LLVM_NODISCARD APInt {
|
||||
/// assigned *this;
|
||||
///
|
||||
/// \returns *this after ORing with RHS.
|
||||
APInt &operator|=(const APInt &RHS);
|
||||
APInt &operator|=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
VAL |= RHS.VAL;
|
||||
return *this;
|
||||
}
|
||||
return OrAssignSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// \brief Bitwise OR assignment operator.
|
||||
///
|
||||
@ -727,7 +785,29 @@ class LLVM_NODISCARD APInt {
|
||||
/// assigned to *this.
|
||||
///
|
||||
/// \returns *this after XORing with RHS.
|
||||
APInt &operator^=(const APInt &RHS);
|
||||
APInt &operator^=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
VAL ^= RHS.VAL;
|
||||
return *this;
|
||||
}
|
||||
return XorAssignSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// \brief Bitwise XOR assignment operator.
|
||||
///
|
||||
/// Performs a bitwise XOR operation on this APInt and RHS. RHS is
|
||||
/// logically zero-extended or truncated to match the bit-width of
|
||||
/// the LHS.
|
||||
APInt &operator^=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL ^= RHS;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
pVal[0] ^= RHS;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Multiplication assignment operator.
|
||||
///
|
||||
@ -766,59 +846,6 @@ class LLVM_NODISCARD APInt {
|
||||
/// \name Binary Operators
|
||||
/// @{
|
||||
|
||||
/// \brief Bitwise AND operator.
|
||||
///
|
||||
/// Performs a bitwise AND operation on *this and RHS.
|
||||
///
|
||||
/// \returns An APInt value representing the bitwise AND of *this and RHS.
|
||||
APInt operator&(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return APInt(getBitWidth(), VAL & RHS.VAL);
|
||||
return AndSlowCase(RHS);
|
||||
}
|
||||
APInt And(const APInt &RHS) const { return this->operator&(RHS); }
|
||||
|
||||
/// \brief Bitwise OR operator.
|
||||
///
|
||||
/// Performs a bitwise OR operation on *this and RHS.
|
||||
///
|
||||
/// \returns An APInt value representing the bitwise OR of *this and RHS.
|
||||
APInt operator|(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return APInt(getBitWidth(), VAL | RHS.VAL);
|
||||
return OrSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// \brief Bitwise OR function.
|
||||
///
|
||||
/// Performs a bitwise or on *this and RHS. This is implemented by simply
|
||||
/// calling operator|.
|
||||
///
|
||||
/// \returns An APInt value representing the bitwise OR of *this and RHS.
|
||||
APInt Or(const APInt &RHS) const { return this->operator|(RHS); }
|
||||
|
||||
/// \brief Bitwise XOR operator.
|
||||
///
|
||||
/// Performs a bitwise XOR operation on *this and RHS.
|
||||
///
|
||||
/// \returns An APInt value representing the bitwise XOR of *this and RHS.
|
||||
APInt operator^(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return APInt(BitWidth, VAL ^ RHS.VAL);
|
||||
return XorSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// \brief Bitwise XOR function.
|
||||
///
|
||||
/// Performs a bitwise XOR operation on *this and RHS. This is implemented
|
||||
/// through the usage of operator^.
|
||||
///
|
||||
/// \returns An APInt value representing the bitwise XOR of *this and RHS.
|
||||
APInt Xor(const APInt &RHS) const { return this->operator^(RHS); }
|
||||
|
||||
/// \brief Multiplication operator.
|
||||
///
|
||||
/// Multiplies this APInt by RHS and returns the result.
|
||||
@ -842,7 +869,14 @@ class LLVM_NODISCARD APInt {
|
||||
/// \brief Logical right-shift function.
|
||||
///
|
||||
/// Logical right-shift this APInt by shiftAmt.
|
||||
APInt lshr(unsigned shiftAmt) const;
|
||||
APInt lshr(unsigned shiftAmt) const {
|
||||
APInt R(*this);
|
||||
R.lshrInPlace(shiftAmt);
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Logical right-shift this APInt by shiftAmt in place.
|
||||
void lshrInPlace(unsigned shiftAmt);
|
||||
|
||||
/// \brief Left-shift function.
|
||||
///
|
||||
@ -1012,7 +1046,7 @@ class LLVM_NODISCARD APInt {
|
||||
/// the validity of the less-than relationship.
|
||||
///
|
||||
/// \returns true if *this < RHS when both are considered unsigned.
|
||||
bool ult(const APInt &RHS) const;
|
||||
bool ult(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// \brief Unsigned less than comparison
|
||||
///
|
||||
@ -1030,7 +1064,7 @@ class LLVM_NODISCARD APInt {
|
||||
/// validity of the less-than relationship.
|
||||
///
|
||||
/// \returns true if *this < RHS when both are considered signed.
|
||||
bool slt(const APInt &RHS) const;
|
||||
bool slt(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// \brief Signed less than comparison
|
||||
///
|
||||
@ -1144,7 +1178,11 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// This operation tests if there are any pairs of corresponding bits
|
||||
/// between this APInt and RHS that are both set.
|
||||
bool intersects(const APInt &RHS) const { return (*this & RHS) != 0; }
|
||||
bool intersects(const APInt &RHS) const {
|
||||
APInt temp(*this);
|
||||
temp &= RHS;
|
||||
return temp != 0;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// \name Resizing Operators
|
||||
@ -1203,11 +1241,9 @@ class LLVM_NODISCARD APInt {
|
||||
void setAllBits() {
|
||||
if (isSingleWord())
|
||||
VAL = UINT64_MAX;
|
||||
else {
|
||||
else
|
||||
// Set all the bits in all the words.
|
||||
for (unsigned i = 0; i < getNumWords(); ++i)
|
||||
pVal[i] = UINT64_MAX;
|
||||
}
|
||||
memset(pVal, -1, getNumWords() * APINT_WORD_SIZE);
|
||||
// Clear the unused ones
|
||||
clearUnusedBits();
|
||||
}
|
||||
@ -1217,6 +1253,49 @@ class LLVM_NODISCARD APInt {
|
||||
/// Set the given bit to 1 whose position is given as "bitPosition".
|
||||
void setBit(unsigned bitPosition);
|
||||
|
||||
/// Set the sign bit to 1.
|
||||
void setSignBit() {
|
||||
setBit(BitWidth - 1);
|
||||
}
|
||||
|
||||
/// Set the bits from loBit (inclusive) to hiBit (exclusive) to 1.
|
||||
void setBits(unsigned loBit, unsigned hiBit) {
|
||||
assert(hiBit <= BitWidth && "hiBit out of range");
|
||||
assert(loBit <= BitWidth && "loBit out of range");
|
||||
if (loBit == hiBit)
|
||||
return;
|
||||
if (loBit > hiBit) {
|
||||
setLowBits(hiBit);
|
||||
setHighBits(BitWidth - loBit);
|
||||
return;
|
||||
}
|
||||
if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) {
|
||||
uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
|
||||
mask <<= loBit;
|
||||
if (isSingleWord())
|
||||
VAL |= mask;
|
||||
else
|
||||
pVal[0] |= mask;
|
||||
} else {
|
||||
setBitsSlowCase(loBit, hiBit);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the top bits starting from loBit.
|
||||
void setBitsFrom(unsigned loBit) {
|
||||
return setBits(loBit, BitWidth);
|
||||
}
|
||||
|
||||
/// Set the bottom loBits bits.
|
||||
void setLowBits(unsigned loBits) {
|
||||
return setBits(0, loBits);
|
||||
}
|
||||
|
||||
/// Set the top hiBits bits.
|
||||
void setHighBits(unsigned hiBits) {
|
||||
return setBits(BitWidth - hiBits, BitWidth);
|
||||
}
|
||||
|
||||
/// \brief Set every bit to 0.
|
||||
void clearAllBits() {
|
||||
if (isSingleWord())
|
||||
@ -1232,13 +1311,12 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// \brief Toggle every bit to its opposite value.
|
||||
void flipAllBits() {
|
||||
if (isSingleWord())
|
||||
if (isSingleWord()) {
|
||||
VAL ^= UINT64_MAX;
|
||||
else {
|
||||
for (unsigned i = 0; i < getNumWords(); ++i)
|
||||
pVal[i] ^= UINT64_MAX;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
flipAllBitsSlowCase();
|
||||
}
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
||||
/// \brief Toggles a given bit to its opposite value.
|
||||
@ -1247,6 +1325,12 @@ class LLVM_NODISCARD APInt {
|
||||
/// as "bitPosition".
|
||||
void flipBit(unsigned bitPosition);
|
||||
|
||||
/// Insert the bits from a smaller APInt starting at bitPosition.
|
||||
void insertBits(const APInt &SubBits, unsigned bitPosition);
|
||||
|
||||
/// Return an APInt with the extracted bits [bitPosition,bitPosition+numBits).
|
||||
APInt extractBits(unsigned numBits, unsigned bitPosition) const;
|
||||
|
||||
/// @}
|
||||
/// \name Value Characterization Functions
|
||||
/// @{
|
||||
@ -1356,7 +1440,7 @@ class LLVM_NODISCARD APInt {
|
||||
///
|
||||
/// \returns 0 if the high order bit is not set, otherwise returns the number
|
||||
/// of 1 bits from the most significant to the least
|
||||
unsigned countLeadingOnes() const;
|
||||
unsigned countLeadingOnes() const LLVM_READONLY;
|
||||
|
||||
/// Computes the number of leading bits of this APInt that are equal to its
|
||||
/// sign bit.
|
||||
@ -1372,7 +1456,7 @@ class LLVM_NODISCARD APInt {
|
||||
///
|
||||
/// \returns BitWidth if the value is zero, otherwise returns the number of
|
||||
/// zeros from the least significant bit to the first one bit.
|
||||
unsigned countTrailingZeros() const;
|
||||
unsigned countTrailingZeros() const LLVM_READONLY;
|
||||
|
||||
/// \brief Count the number of trailing one bits.
|
||||
///
|
||||
@ -1589,46 +1673,50 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// Sets the least significant part of a bignum to the input value, and zeroes
|
||||
/// out higher parts.
|
||||
static void tcSet(integerPart *, integerPart, unsigned int);
|
||||
static void tcSet(WordType *, WordType, unsigned);
|
||||
|
||||
/// Assign one bignum to another.
|
||||
static void tcAssign(integerPart *, const integerPart *, unsigned int);
|
||||
static void tcAssign(WordType *, const WordType *, unsigned);
|
||||
|
||||
/// Returns true if a bignum is zero, false otherwise.
|
||||
static bool tcIsZero(const integerPart *, unsigned int);
|
||||
static bool tcIsZero(const WordType *, unsigned);
|
||||
|
||||
/// Extract the given bit of a bignum; returns 0 or 1. Zero-based.
|
||||
static int tcExtractBit(const integerPart *, unsigned int bit);
|
||||
static int tcExtractBit(const WordType *, unsigned bit);
|
||||
|
||||
/// Copy the bit vector of width srcBITS from SRC, starting at bit srcLSB, to
|
||||
/// DST, of dstCOUNT parts, such that the bit srcLSB becomes the least
|
||||
/// significant bit of DST. All high bits above srcBITS in DST are
|
||||
/// zero-filled.
|
||||
static void tcExtract(integerPart *, unsigned int dstCount,
|
||||
const integerPart *, unsigned int srcBits,
|
||||
unsigned int srcLSB);
|
||||
static void tcExtract(WordType *, unsigned dstCount,
|
||||
const WordType *, unsigned srcBits,
|
||||
unsigned srcLSB);
|
||||
|
||||
/// Set the given bit of a bignum. Zero-based.
|
||||
static void tcSetBit(integerPart *, unsigned int bit);
|
||||
static void tcSetBit(WordType *, unsigned bit);
|
||||
|
||||
/// Clear the given bit of a bignum. Zero-based.
|
||||
static void tcClearBit(integerPart *, unsigned int bit);
|
||||
static void tcClearBit(WordType *, unsigned bit);
|
||||
|
||||
/// Returns the bit number of the least or most significant set bit of a
|
||||
/// number. If the input number has no bits set -1U is returned.
|
||||
static unsigned int tcLSB(const integerPart *, unsigned int);
|
||||
static unsigned int tcMSB(const integerPart *parts, unsigned int n);
|
||||
static unsigned tcLSB(const WordType *, unsigned n);
|
||||
static unsigned tcMSB(const WordType *parts, unsigned n);
|
||||
|
||||
/// Negate a bignum in-place.
|
||||
static void tcNegate(integerPart *, unsigned int);
|
||||
static void tcNegate(WordType *, unsigned);
|
||||
|
||||
/// DST += RHS + CARRY where CARRY is zero or one. Returns the carry flag.
|
||||
static integerPart tcAdd(integerPart *, const integerPart *,
|
||||
integerPart carry, unsigned);
|
||||
static WordType tcAdd(WordType *, const WordType *,
|
||||
WordType carry, unsigned);
|
||||
/// DST += RHS. Returns the carry flag.
|
||||
static WordType tcAddPart(WordType *, WordType, unsigned);
|
||||
|
||||
/// DST -= RHS + CARRY where CARRY is zero or one. Returns the carry flag.
|
||||
static integerPart tcSubtract(integerPart *, const integerPart *,
|
||||
integerPart carry, unsigned);
|
||||
static WordType tcSubtract(WordType *, const WordType *,
|
||||
WordType carry, unsigned);
|
||||
/// DST -= RHS. Returns the carry flag.
|
||||
static WordType tcSubtractPart(WordType *, WordType, unsigned);
|
||||
|
||||
/// DST += SRC * MULTIPLIER + PART if add is true
|
||||
/// DST = SRC * MULTIPLIER + PART if add is false
|
||||
@ -1640,23 +1728,23 @@ class LLVM_NODISCARD APInt {
|
||||
/// Otherwise DST is filled with the least significant DSTPARTS parts of the
|
||||
/// result, and if all of the omitted higher parts were zero return zero,
|
||||
/// otherwise overflow occurred and return one.
|
||||
static int tcMultiplyPart(integerPart *dst, const integerPart *src,
|
||||
integerPart multiplier, integerPart carry,
|
||||
unsigned int srcParts, unsigned int dstParts,
|
||||
static int tcMultiplyPart(WordType *dst, const WordType *src,
|
||||
WordType multiplier, WordType carry,
|
||||
unsigned srcParts, unsigned dstParts,
|
||||
bool add);
|
||||
|
||||
/// DST = LHS * RHS, where DST has the same width as the operands and is
|
||||
/// filled with the least significant parts of the result. Returns one if
|
||||
/// overflow occurred, otherwise zero. DST must be disjoint from both
|
||||
/// operands.
|
||||
static int tcMultiply(integerPart *, const integerPart *, const integerPart *,
|
||||
static int tcMultiply(WordType *, const WordType *, const WordType *,
|
||||
unsigned);
|
||||
|
||||
/// DST = LHS * RHS, where DST has width the sum of the widths of the
|
||||
/// operands. No overflow occurs. DST must be disjoint from both
|
||||
/// operands. Returns the number of parts required to hold the result.
|
||||
static unsigned int tcFullMultiply(integerPart *, const integerPart *,
|
||||
const integerPart *, unsigned, unsigned);
|
||||
static unsigned tcFullMultiply(WordType *, const WordType *,
|
||||
const WordType *, unsigned, unsigned);
|
||||
|
||||
/// If RHS is zero LHS and REMAINDER are left unchanged, return one.
|
||||
/// Otherwise set LHS to LHS / RHS with the fractional part discarded, set
|
||||
@ -1667,38 +1755,39 @@ class LLVM_NODISCARD APInt {
|
||||
/// SCRATCH is a bignum of the same size as the operands and result for use by
|
||||
/// the routine; its contents need not be initialized and are destroyed. LHS,
|
||||
/// REMAINDER and SCRATCH must be distinct.
|
||||
static int tcDivide(integerPart *lhs, const integerPart *rhs,
|
||||
integerPart *remainder, integerPart *scratch,
|
||||
unsigned int parts);
|
||||
static int tcDivide(WordType *lhs, const WordType *rhs,
|
||||
WordType *remainder, WordType *scratch,
|
||||
unsigned parts);
|
||||
|
||||
/// Shift a bignum left COUNT bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on COUNT.
|
||||
static void tcShiftLeft(integerPart *, unsigned int parts,
|
||||
unsigned int count);
|
||||
static void tcShiftLeft(WordType *, unsigned parts, unsigned count);
|
||||
|
||||
/// Shift a bignum right COUNT bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on COUNT.
|
||||
static void tcShiftRight(integerPart *, unsigned int parts,
|
||||
unsigned int count);
|
||||
static void tcShiftRight(WordType *, unsigned parts, unsigned count);
|
||||
|
||||
/// The obvious AND, OR and XOR and complement operations.
|
||||
static void tcAnd(integerPart *, const integerPart *, unsigned int);
|
||||
static void tcOr(integerPart *, const integerPart *, unsigned int);
|
||||
static void tcXor(integerPart *, const integerPart *, unsigned int);
|
||||
static void tcComplement(integerPart *, unsigned int);
|
||||
static void tcAnd(WordType *, const WordType *, unsigned);
|
||||
static void tcOr(WordType *, const WordType *, unsigned);
|
||||
static void tcXor(WordType *, const WordType *, unsigned);
|
||||
static void tcComplement(WordType *, unsigned);
|
||||
|
||||
/// Comparison (unsigned) of two bignums.
|
||||
static int tcCompare(const integerPart *, const integerPart *, unsigned int);
|
||||
static int tcCompare(const WordType *, const WordType *, unsigned);
|
||||
|
||||
/// Increment a bignum in-place. Return the carry flag.
|
||||
static integerPart tcIncrement(integerPart *, unsigned int);
|
||||
static WordType tcIncrement(WordType *dst, unsigned parts) {
|
||||
return tcAddPart(dst, 1, parts);
|
||||
}
|
||||
|
||||
/// Decrement a bignum in-place. Return the borrow flag.
|
||||
static integerPart tcDecrement(integerPart *, unsigned int);
|
||||
static WordType tcDecrement(WordType *dst, unsigned parts) {
|
||||
return tcSubtractPart(dst, 1, parts);
|
||||
}
|
||||
|
||||
/// Set the least significant BITS and clear the rest.
|
||||
static void tcSetLeastSignificantBits(integerPart *, unsigned int,
|
||||
unsigned int bits);
|
||||
static void tcSetLeastSignificantBits(WordType *, unsigned, unsigned bits);
|
||||
|
||||
/// \brief debug method
|
||||
void dump() const;
|
||||
@ -1723,6 +1812,74 @@ inline bool operator==(uint64_t V1, const APInt &V2) { return V2 == V1; }
|
||||
|
||||
inline bool operator!=(uint64_t V1, const APInt &V2) { return V2 != V1; }
|
||||
|
||||
/// \brief Unary bitwise complement operator.
|
||||
///
|
||||
/// \returns an APInt that is the bitwise complement of \p v.
|
||||
inline APInt operator~(APInt v) {
|
||||
v.flipAllBits();
|
||||
return v;
|
||||
}
|
||||
|
||||
inline APInt operator&(APInt a, const APInt &b) {
|
||||
a &= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline APInt operator&(const APInt &a, APInt &&b) {
|
||||
b &= a;
|
||||
return std::move(b);
|
||||
}
|
||||
|
||||
inline APInt operator&(APInt a, uint64_t RHS) {
|
||||
a &= RHS;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline APInt operator&(uint64_t LHS, APInt b) {
|
||||
b &= LHS;
|
||||
return b;
|
||||
}
|
||||
|
||||
inline APInt operator|(APInt a, const APInt &b) {
|
||||
a |= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline APInt operator|(const APInt &a, APInt &&b) {
|
||||
b |= a;
|
||||
return std::move(b);
|
||||
}
|
||||
|
||||
inline APInt operator|(APInt a, uint64_t RHS) {
|
||||
a |= RHS;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline APInt operator|(uint64_t LHS, APInt b) {
|
||||
b |= LHS;
|
||||
return b;
|
||||
}
|
||||
|
||||
inline APInt operator^(APInt a, const APInt &b) {
|
||||
a ^= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline APInt operator^(const APInt &a, APInt &&b) {
|
||||
b ^= a;
|
||||
return std::move(b);
|
||||
}
|
||||
|
||||
inline APInt operator^(APInt a, uint64_t RHS) {
|
||||
a ^= RHS;
|
||||
return a;
|
||||
}
|
||||
|
||||
inline APInt operator^(uint64_t LHS, APInt b) {
|
||||
b ^= LHS;
|
||||
return b;
|
||||
}
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const APInt &I) {
|
||||
I.print(OS, true);
|
||||
return OS;
|
||||
@ -1799,47 +1956,13 @@ inline const APInt &umax(const APInt &A, const APInt &B) {
|
||||
return A.ugt(B) ? A : B;
|
||||
}
|
||||
|
||||
/// \brief Check if the specified APInt has a N-bits unsigned integer value.
|
||||
inline bool isIntN(unsigned N, const APInt &APIVal) { return APIVal.isIntN(N); }
|
||||
|
||||
/// \brief Check if the specified APInt has a N-bits signed integer value.
|
||||
inline bool isSignedIntN(unsigned N, const APInt &APIVal) {
|
||||
return APIVal.isSignedIntN(N);
|
||||
}
|
||||
|
||||
/// \returns true if the argument APInt value is a sequence of ones starting at
|
||||
/// the least significant bit with the remainder zero.
|
||||
inline bool isMask(unsigned numBits, const APInt &APIVal) {
|
||||
return numBits <= APIVal.getBitWidth() &&
|
||||
APIVal == APInt::getLowBitsSet(APIVal.getBitWidth(), numBits);
|
||||
}
|
||||
|
||||
/// \returns true if the argument is a non-empty sequence of ones starting at
|
||||
/// the least significant bit with the remainder zero (32 bit version).
|
||||
/// Ex. isMask(0x0000FFFFU) == true.
|
||||
inline bool isMask(const APInt &Value) {
|
||||
return (Value != 0) && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// \brief Return true if the argument APInt value contains a sequence of ones
|
||||
/// with the remainder zero.
|
||||
inline bool isShiftedMask(unsigned numBits, const APInt &APIVal) {
|
||||
return isMask(numBits, (APIVal - APInt(numBits, 1)) | APIVal);
|
||||
}
|
||||
|
||||
/// \brief Returns a byte-swapped representation of the specified APInt Value.
|
||||
inline APInt byteSwap(const APInt &APIVal) { return APIVal.byteSwap(); }
|
||||
|
||||
/// \brief Returns the floor log base 2 of the specified APInt value.
|
||||
inline unsigned logBase2(const APInt &APIVal) { return APIVal.logBase2(); }
|
||||
|
||||
/// \brief Compute GCD of two APInt values.
|
||||
/// \brief Compute GCD of two unsigned APInt values.
|
||||
///
|
||||
/// This function returns the greatest common divisor of the two APInt values
|
||||
/// using Euclid's algorithm.
|
||||
///
|
||||
/// \returns the greatest common divisor of Val1 and Val2
|
||||
APInt GreatestCommonDivisor(const APInt &Val1, const APInt &Val2);
|
||||
/// \returns the greatest common divisor of A and B.
|
||||
APInt GreatestCommonDivisor(APInt A, APInt B);
|
||||
|
||||
/// \brief Converts the given APInt to a double value.
|
||||
///
|
||||
@ -1879,83 +2002,6 @@ inline APInt RoundFloatToAPInt(float Float, unsigned width) {
|
||||
return RoundDoubleToAPInt(double(Float), width);
|
||||
}
|
||||
|
||||
/// \brief Arithmetic right-shift function.
|
||||
///
|
||||
/// Arithmetic right-shift the APInt by shiftAmt.
|
||||
inline APInt ashr(const APInt &LHS, unsigned shiftAmt) {
|
||||
return LHS.ashr(shiftAmt);
|
||||
}
|
||||
|
||||
/// \brief Logical right-shift function.
|
||||
///
|
||||
/// Logical right-shift the APInt by shiftAmt.
|
||||
inline APInt lshr(const APInt &LHS, unsigned shiftAmt) {
|
||||
return LHS.lshr(shiftAmt);
|
||||
}
|
||||
|
||||
/// \brief Left-shift function.
|
||||
///
|
||||
/// Left-shift the APInt by shiftAmt.
|
||||
inline APInt shl(const APInt &LHS, unsigned shiftAmt) {
|
||||
return LHS.shl(shiftAmt);
|
||||
}
|
||||
|
||||
/// \brief Signed division function for APInt.
|
||||
///
|
||||
/// Signed divide APInt LHS by APInt RHS.
|
||||
inline APInt sdiv(const APInt &LHS, const APInt &RHS) { return LHS.sdiv(RHS); }
|
||||
|
||||
/// \brief Unsigned division function for APInt.
|
||||
///
|
||||
/// Unsigned divide APInt LHS by APInt RHS.
|
||||
inline APInt udiv(const APInt &LHS, const APInt &RHS) { return LHS.udiv(RHS); }
|
||||
|
||||
/// \brief Function for signed remainder operation.
|
||||
///
|
||||
/// Signed remainder operation on APInt.
|
||||
inline APInt srem(const APInt &LHS, const APInt &RHS) { return LHS.srem(RHS); }
|
||||
|
||||
/// \brief Function for unsigned remainder operation.
|
||||
///
|
||||
/// Unsigned remainder operation on APInt.
|
||||
inline APInt urem(const APInt &LHS, const APInt &RHS) { return LHS.urem(RHS); }
|
||||
|
||||
/// \brief Function for multiplication operation.
|
||||
///
|
||||
/// Performs multiplication on APInt values.
|
||||
inline APInt mul(const APInt &LHS, const APInt &RHS) { return LHS * RHS; }
|
||||
|
||||
/// \brief Function for addition operation.
|
||||
///
|
||||
/// Performs addition on APInt values.
|
||||
inline APInt add(const APInt &LHS, const APInt &RHS) { return LHS + RHS; }
|
||||
|
||||
/// \brief Function for subtraction operation.
|
||||
///
|
||||
/// Performs subtraction on APInt values.
|
||||
inline APInt sub(const APInt &LHS, const APInt &RHS) { return LHS - RHS; }
|
||||
|
||||
/// \brief Bitwise AND function for APInt.
|
||||
///
|
||||
/// Performs bitwise AND operation on APInt LHS and
|
||||
/// APInt RHS.
|
||||
inline APInt And(const APInt &LHS, const APInt &RHS) { return LHS & RHS; }
|
||||
|
||||
/// \brief Bitwise OR function for APInt.
|
||||
///
|
||||
/// Performs bitwise OR operation on APInt LHS and APInt RHS.
|
||||
inline APInt Or(const APInt &LHS, const APInt &RHS) { return LHS | RHS; }
|
||||
|
||||
/// \brief Bitwise XOR function for APInt.
|
||||
///
|
||||
/// Performs bitwise XOR operation on APInt.
|
||||
inline APInt Xor(const APInt &LHS, const APInt &RHS) { return LHS ^ RHS; }
|
||||
|
||||
/// \brief Bitwise complement function.
|
||||
///
|
||||
/// Performs a bitwise complement operation on APInt.
|
||||
inline APInt Not(const APInt &APIVal) { return ~APIVal; }
|
||||
|
||||
} // End of APIntOps namespace
|
||||
|
||||
// See friend declaration above. This additional declaration is required in
|
||||
|
@ -235,19 +235,16 @@ class LLVM_NODISCARD APSInt : public APInt {
|
||||
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
|
||||
return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned);
|
||||
}
|
||||
APSInt And(const APSInt &RHS) const { return this->operator&(RHS); }
|
||||
|
||||
APSInt operator|(const APSInt& RHS) const {
|
||||
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
|
||||
return APSInt(static_cast<const APInt&>(*this) | RHS, IsUnsigned);
|
||||
}
|
||||
APSInt Or(const APSInt &RHS) const { return this->operator|(RHS); }
|
||||
|
||||
APSInt operator^(const APSInt &RHS) const {
|
||||
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
|
||||
return APSInt(static_cast<const APInt&>(*this) ^ RHS, IsUnsigned);
|
||||
}
|
||||
APSInt Xor(const APSInt &RHS) const { return this->operator^(RHS); }
|
||||
|
||||
APSInt operator*(const APSInt& RHS) const {
|
||||
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
|
||||
|
@ -487,6 +487,18 @@ namespace llvm {
|
||||
return ArrayRef<T>(Arr);
|
||||
}
|
||||
|
||||
/// Construct a MutableArrayRef from a single element.
|
||||
template<typename T>
|
||||
MutableArrayRef<T> makeMutableArrayRef(T &OneElt) {
|
||||
return OneElt;
|
||||
}
|
||||
|
||||
/// Construct a MutableArrayRef from a pointer and length.
|
||||
template<typename T>
|
||||
MutableArrayRef<T> makeMutableArrayRef(T *data, size_t length) {
|
||||
return MutableArrayRef<T>(data, length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name ArrayRef Comparison Operators
|
||||
/// @{
|
||||
|
@ -161,6 +161,17 @@ class BitVector {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// find_first_unset - Returns the index of the first unset bit, -1 if all
|
||||
/// of the bits are set.
|
||||
int find_first_unset() const {
|
||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
||||
if (Bits[i] != ~0UL) {
|
||||
unsigned Result = i * BITWORD_SIZE + countTrailingOnes(Bits[i]);
|
||||
return Result < size() ? Result : -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// find_next - Returns the index of the next set bit following the
|
||||
/// "Prev" bit. Returns -1 if the next set bit is not found.
|
||||
int find_next(unsigned Prev) const {
|
||||
@ -184,6 +195,30 @@ class BitVector {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// find_next_unset - Returns the index of the next usnet bit following the
|
||||
/// "Prev" bit. Returns -1 if all remaining bits are set.
|
||||
int find_next_unset(unsigned Prev) const {
|
||||
++Prev;
|
||||
if (Prev >= Size)
|
||||
return -1;
|
||||
|
||||
unsigned WordPos = Prev / BITWORD_SIZE;
|
||||
unsigned BitPos = Prev % BITWORD_SIZE;
|
||||
BitWord Copy = Bits[WordPos];
|
||||
// Mask in previous bits.
|
||||
BitWord Mask = (1 << BitPos) - 1;
|
||||
Copy |= Mask;
|
||||
|
||||
if (Copy != ~0UL)
|
||||
return next_unset_in_word(WordPos, Copy);
|
||||
|
||||
// Check subsequent words.
|
||||
for (unsigned i = WordPos + 1; i < NumBitWords(size()); ++i)
|
||||
if (Bits[i] != ~0UL)
|
||||
return next_unset_in_word(i, Bits[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// clear - Clear all bits.
|
||||
void clear() {
|
||||
Size = 0;
|
||||
@ -503,6 +538,11 @@ class BitVector {
|
||||
}
|
||||
|
||||
private:
|
||||
int next_unset_in_word(int WordIndex, BitWord Word) const {
|
||||
unsigned Result = WordIndex * BITWORD_SIZE + countTrailingOnes(Word);
|
||||
return Result < size() ? Result : -1;
|
||||
}
|
||||
|
||||
unsigned NumBitWords(unsigned S) const {
|
||||
return (S + BITWORD_SIZE-1) / BITWORD_SIZE;
|
||||
}
|
||||
@ -539,7 +579,8 @@ class BitVector {
|
||||
}
|
||||
|
||||
void init_words(BitWord *B, unsigned NumWords, bool t) {
|
||||
memset(B, 0 - (int)t, NumWords*sizeof(BitWord));
|
||||
if (NumWords > 0)
|
||||
memset(B, 0 - (int)t, NumWords*sizeof(BitWord));
|
||||
}
|
||||
|
||||
template<bool AddBits, bool InvertMask>
|
||||
|
164
contrib/llvm/include/llvm/ADT/BreadthFirstIterator.h
Normal file
164
contrib/llvm/include/llvm/ADT/BreadthFirstIterator.h
Normal file
@ -0,0 +1,164 @@
|
||||
//===- llvm/ADT/BreadthFirstIterator.h - Breadth First iterator -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file builds on the ADT/GraphTraits.h file to build a generic breadth
|
||||
// first graph iterator. This file exposes the following functions/types:
|
||||
//
|
||||
// bf_begin/bf_end/bf_iterator
|
||||
// * Normal breadth-first iteration - visit a graph level-by-level.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_BREADTHFIRSTITERATOR_H
|
||||
#define LLVM_ADT_BREADTHFIRSTITERATOR_H
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include <iterator>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// bf_iterator_storage - A private class which is used to figure out where to
|
||||
// store the visited set. We only provide a non-external variant for now.
|
||||
template <class SetType> class bf_iterator_storage {
|
||||
public:
|
||||
SetType Visited;
|
||||
};
|
||||
|
||||
// The visited state for the iteration is a simple set.
|
||||
template <typename NodeRef, unsigned SmallSize = 8>
|
||||
using bf_iterator_default_set = SmallPtrSet<NodeRef, SmallSize>;
|
||||
|
||||
// Generic Breadth first search iterator.
|
||||
template <class GraphT,
|
||||
class SetType =
|
||||
bf_iterator_default_set<typename GraphTraits<GraphT>::NodeRef>,
|
||||
class GT = GraphTraits<GraphT>>
|
||||
class bf_iterator
|
||||
: public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>,
|
||||
public bf_iterator_storage<SetType> {
|
||||
typedef std::iterator<std::forward_iterator_tag, typename GT::NodeRef> super;
|
||||
|
||||
typedef typename GT::NodeRef NodeRef;
|
||||
typedef typename GT::ChildIteratorType ChildItTy;
|
||||
|
||||
// First element is the node reference, second is the next child to visit.
|
||||
typedef std::pair<NodeRef, Optional<ChildItTy>> QueueElement;
|
||||
|
||||
// Visit queue - used to maintain BFS ordering.
|
||||
// Optional<> because we need markers for levels.
|
||||
std::queue<Optional<QueueElement>> VisitQueue;
|
||||
|
||||
// Current level.
|
||||
unsigned Level;
|
||||
|
||||
private:
|
||||
inline bf_iterator(NodeRef Node) {
|
||||
this->Visited.insert(Node);
|
||||
Level = 0;
|
||||
|
||||
// Also, insert a dummy node as marker.
|
||||
VisitQueue.push(QueueElement(Node, None));
|
||||
VisitQueue.push(None);
|
||||
}
|
||||
|
||||
inline bf_iterator() = default;
|
||||
|
||||
inline void toNext() {
|
||||
Optional<QueueElement> Head = VisitQueue.front();
|
||||
QueueElement H = Head.getValue();
|
||||
NodeRef Node = H.first;
|
||||
Optional<ChildItTy> &ChildIt = H.second;
|
||||
|
||||
if (!ChildIt)
|
||||
ChildIt.emplace(GT::child_begin(Node));
|
||||
while (*ChildIt != GT::child_end(Node)) {
|
||||
NodeRef Next = *(*ChildIt)++;
|
||||
|
||||
// Already visited?
|
||||
if (this->Visited.insert(Next).second)
|
||||
VisitQueue.push(QueueElement(Next, None));
|
||||
}
|
||||
VisitQueue.pop();
|
||||
|
||||
// Go to the next element skipping markers if needed.
|
||||
if (!VisitQueue.empty()) {
|
||||
Head = VisitQueue.front();
|
||||
if (Head != None)
|
||||
return;
|
||||
Level += 1;
|
||||
VisitQueue.pop();
|
||||
|
||||
// Don't push another marker if this is the last
|
||||
// element.
|
||||
if (!VisitQueue.empty())
|
||||
VisitQueue.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
typedef typename super::pointer pointer;
|
||||
|
||||
// Provide static begin and end methods as our public "constructors"
|
||||
static bf_iterator begin(const GraphT &G) {
|
||||
return bf_iterator(GT::getEntryNode(G));
|
||||
}
|
||||
|
||||
static bf_iterator end(const GraphT &G) { return bf_iterator(); }
|
||||
|
||||
bool operator==(const bf_iterator &RHS) const {
|
||||
return VisitQueue == RHS.VisitQueue;
|
||||
}
|
||||
|
||||
bool operator!=(const bf_iterator &RHS) const { return !(*this == RHS); }
|
||||
|
||||
const NodeRef &operator*() const { return VisitQueue.front()->first; }
|
||||
|
||||
// This is a nonstandard operator-> that dereferenfces the pointer an extra
|
||||
// time so that you can actually call methods on the node, because the
|
||||
// contained type is a pointer.
|
||||
NodeRef operator->() const { return **this; }
|
||||
|
||||
bf_iterator &operator++() { // Pre-increment
|
||||
toNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bf_iterator operator++(int) { // Post-increment
|
||||
bf_iterator ItCopy = *this;
|
||||
++*this;
|
||||
return ItCopy;
|
||||
}
|
||||
|
||||
unsigned getLevel() const { return Level; }
|
||||
};
|
||||
|
||||
// Provide global constructors that automatically figure out correct types.
|
||||
template <class T> bf_iterator<T> bf_begin(const T &G) {
|
||||
return bf_iterator<T>::begin(G);
|
||||
}
|
||||
|
||||
template <class T> bf_iterator<T> bf_end(const T &G) {
|
||||
return bf_iterator<T>::end(G);
|
||||
}
|
||||
|
||||
// Provide an accessor method to use them in range-based patterns.
|
||||
template <class T> iterator_range<bf_iterator<T>> breadth_first(const T &G) {
|
||||
return make_range(bf_begin(G), bf_end(G));
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_BREADTHFIRSTITERATOR_H
|
@ -53,6 +53,9 @@ class DenseMapIterator;
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
class DenseMapBase : public DebugEpochBase {
|
||||
template <typename T>
|
||||
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
typedef KeyT key_type;
|
||||
@ -119,18 +122,18 @@ class DenseMapBase : public DebugEpochBase {
|
||||
}
|
||||
|
||||
/// Return 1 if the specified key is in the map, 0 otherwise.
|
||||
size_type count(const KeyT &Val) const {
|
||||
size_type count(const_arg_type_t<KeyT> Val) const {
|
||||
const BucketT *TheBucket;
|
||||
return LookupBucketFor(Val, TheBucket) ? 1 : 0;
|
||||
}
|
||||
|
||||
iterator find(const KeyT &Val) {
|
||||
iterator find(const_arg_type_t<KeyT> Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
const_iterator find(const KeyT &Val) const {
|
||||
const_iterator find(const_arg_type_t<KeyT> Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
@ -159,7 +162,7 @@ class DenseMapBase : public DebugEpochBase {
|
||||
|
||||
/// lookup - Return the entry for the specified key, or a default
|
||||
/// constructed value if no such entry exists.
|
||||
ValueT lookup(const KeyT &Val) const {
|
||||
ValueT lookup(const_arg_type_t<KeyT> Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return TheBucket->getSecond();
|
||||
@ -389,6 +392,8 @@ class DenseMapBase : public DebugEpochBase {
|
||||
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() {
|
||||
|
@ -60,6 +60,16 @@ template<> struct DenseMapInfo<char> {
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned shorts.
|
||||
template <> struct DenseMapInfo<unsigned short> {
|
||||
static inline unsigned short getEmptyKey() { return 0xFFFF; }
|
||||
static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
|
||||
static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
|
||||
static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned ints.
|
||||
template<> struct DenseMapInfo<unsigned> {
|
||||
static inline unsigned getEmptyKey() { return ~0U; }
|
||||
@ -95,6 +105,14 @@ template<> struct DenseMapInfo<unsigned long long> {
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for shorts.
|
||||
template <> struct DenseMapInfo<short> {
|
||||
static inline short getEmptyKey() { return 0x7FFF; }
|
||||
static inline short getTombstoneKey() { return -0x7FFF - 1; }
|
||||
static unsigned getHashValue(const short &Val) { return Val * 37U; }
|
||||
static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for ints.
|
||||
template<> struct DenseMapInfo<int> {
|
||||
static inline int getEmptyKey() { return 0x7fffffff; }
|
||||
|
@ -48,6 +48,8 @@ class DenseSetImpl {
|
||||
static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT),
|
||||
"DenseMap buckets unexpectedly large!");
|
||||
MapTy TheMap;
|
||||
template <typename T>
|
||||
using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
|
||||
|
||||
public:
|
||||
typedef ValueT key_type;
|
||||
@ -78,7 +80,7 @@ class DenseSetImpl {
|
||||
}
|
||||
|
||||
/// Return 1 if the specified key is in the set, 0 otherwise.
|
||||
size_type count(const ValueT &V) const {
|
||||
size_type count(const_arg_type_t<ValueT> V) const {
|
||||
return TheMap.count(V);
|
||||
}
|
||||
|
||||
@ -90,9 +92,12 @@ class DenseSetImpl {
|
||||
|
||||
// Iterators.
|
||||
|
||||
class ConstIterator;
|
||||
|
||||
class Iterator {
|
||||
typename MapTy::iterator I;
|
||||
friend class DenseSetImpl;
|
||||
friend class ConstIterator;
|
||||
|
||||
public:
|
||||
typedef typename MapTy::iterator::difference_type difference_type;
|
||||
@ -101,20 +106,24 @@ class DenseSetImpl {
|
||||
typedef value_type &reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
Iterator() = default;
|
||||
Iterator(const typename MapTy::iterator &i) : I(i) {}
|
||||
|
||||
ValueT &operator*() { return I->getFirst(); }
|
||||
const ValueT &operator*() const { return I->getFirst(); }
|
||||
ValueT *operator->() { return &I->getFirst(); }
|
||||
const ValueT *operator->() const { return &I->getFirst(); }
|
||||
|
||||
Iterator& operator++() { ++I; return *this; }
|
||||
Iterator operator++(int) { auto T = *this; ++I; return T; }
|
||||
bool operator==(const Iterator& X) const { return I == X.I; }
|
||||
bool operator!=(const Iterator& X) const { return I != X.I; }
|
||||
bool operator==(const ConstIterator& X) const { return I == X.I; }
|
||||
bool operator!=(const ConstIterator& X) const { return I != X.I; }
|
||||
};
|
||||
|
||||
class ConstIterator {
|
||||
typename MapTy::const_iterator I;
|
||||
friend class DenseSet;
|
||||
friend class Iterator;
|
||||
|
||||
public:
|
||||
typedef typename MapTy::const_iterator::difference_type difference_type;
|
||||
@ -123,10 +132,14 @@ class DenseSetImpl {
|
||||
typedef value_type &reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
ConstIterator(const Iterator &B) : I(B.I) {}
|
||||
|
||||
ConstIterator() = default;
|
||||
|
||||
ConstIterator(const typename MapTy::const_iterator &i) : I(i) {}
|
||||
|
||||
const ValueT &operator*() { return I->getFirst(); }
|
||||
const ValueT *operator->() { return &I->getFirst(); }
|
||||
const ValueT &operator*() const { return I->getFirst(); }
|
||||
const ValueT *operator->() const { return &I->getFirst(); }
|
||||
|
||||
ConstIterator& operator++() { ++I; return *this; }
|
||||
ConstIterator operator++(int) { auto T = *this; ++I; return T; }
|
||||
@ -143,8 +156,8 @@ class DenseSetImpl {
|
||||
const_iterator begin() const { return ConstIterator(TheMap.begin()); }
|
||||
const_iterator end() const { return ConstIterator(TheMap.end()); }
|
||||
|
||||
iterator find(const ValueT &V) { return Iterator(TheMap.find(V)); }
|
||||
const_iterator find(const ValueT &V) const {
|
||||
iterator find(const_arg_type_t<ValueT> V) { return Iterator(TheMap.find(V)); }
|
||||
const_iterator find(const_arg_type_t<ValueT> V) const {
|
||||
return ConstIterator(TheMap.find(V));
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ class df_iterator
|
||||
}
|
||||
}
|
||||
this->Visited.completed(Node);
|
||||
|
||||
|
||||
// Oops, ran out of successors... go up a level on the stack.
|
||||
VisitStack.pop_back();
|
||||
} while (!VisitStack.empty());
|
||||
|
@ -18,6 +18,8 @@
|
||||
#ifndef LLVM_ADT_GRAPHTRAITS_H
|
||||
#define LLVM_ADT_GRAPHTRAITS_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// GraphTraits - This class should be specialized by different graph types...
|
||||
@ -86,6 +88,33 @@ struct Inverse {
|
||||
// inverse falls back to the original graph.
|
||||
template <class T> struct GraphTraits<Inverse<Inverse<T>>> : GraphTraits<T> {};
|
||||
|
||||
// Provide iterator ranges for the graph traits nodes and children
|
||||
template <class GraphType>
|
||||
iterator_range<typename GraphTraits<GraphType>::nodes_iterator>
|
||||
nodes(const GraphType &G) {
|
||||
return make_range(GraphTraits<GraphType>::nodes_begin(G),
|
||||
GraphTraits<GraphType>::nodes_end(G));
|
||||
}
|
||||
template <class GraphType>
|
||||
iterator_range<typename GraphTraits<Inverse<GraphType>>::nodes_iterator>
|
||||
inverse_nodes(const GraphType &G) {
|
||||
return make_range(GraphTraits<Inverse<GraphType>>::nodes_begin(G),
|
||||
GraphTraits<Inverse<GraphType>>::nodes_end(G));
|
||||
}
|
||||
|
||||
template <class GraphType>
|
||||
iterator_range<typename GraphTraits<GraphType>::ChildIteratorType>
|
||||
children(const typename GraphTraits<GraphType>::NodeRef &G) {
|
||||
return make_range(GraphTraits<GraphType>::child_begin(G),
|
||||
GraphTraits<GraphType>::child_end(G));
|
||||
}
|
||||
|
||||
template <class GraphType>
|
||||
iterator_range<typename GraphTraits<Inverse<GraphType>>::ChildIteratorType>
|
||||
inverse_children(const typename GraphTraits<GraphType>::NodeRef &G) {
|
||||
return make_range(GraphTraits<Inverse<GraphType>>::child_begin(G),
|
||||
GraphTraits<Inverse<GraphType>>::child_end(G));
|
||||
}
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -19,8 +19,9 @@
|
||||
namespace llvm {
|
||||
/// \brief A simple null object to allow implicit construction of Optional<T>
|
||||
/// and similar types without having to spell out the specialization's name.
|
||||
enum class NoneType { None };
|
||||
const NoneType None = None;
|
||||
// (constant value 1 in an attempt to workaround MSVC build issue... )
|
||||
enum class NoneType { None = 1 };
|
||||
const NoneType None = NoneType::None;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -31,7 +31,7 @@ template <typename T> struct PointerUnionTypeSelectorReturn {
|
||||
/// Get a type based on whether two types are the same or not.
|
||||
///
|
||||
/// For:
|
||||
///
|
||||
///
|
||||
/// \code
|
||||
/// typedef typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return Ret;
|
||||
/// \endcode
|
||||
@ -190,17 +190,17 @@ template <typename PT1, typename PT2> class PointerUnion {
|
||||
};
|
||||
|
||||
template <typename PT1, typename PT2>
|
||||
static bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
|
||||
bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
|
||||
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template <typename PT1, typename PT2>
|
||||
static bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
|
||||
bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
|
||||
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template <typename PT1, typename PT2>
|
||||
static bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
|
||||
bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
|
||||
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
|
@ -268,6 +268,10 @@ inverse_post_order_ext(const T &G, SetType &S) {
|
||||
// with a postorder iterator to build the data structures). The moral of this
|
||||
// story is: Don't create more ReversePostOrderTraversal classes than necessary.
|
||||
//
|
||||
// Because it does the traversal in its constructor, it won't invalidate when
|
||||
// BasicBlocks are removed, *but* it may contain erased blocks. Some places
|
||||
// rely on this behavior (i.e. GVN).
|
||||
//
|
||||
// This class should be used like this:
|
||||
// {
|
||||
// ReversePostOrderTraversal<Function*> RPOT(FuncPtr); // Expensive to create
|
||||
|
@ -23,11 +23,13 @@
|
||||
#include <cstdlib> // for qsort
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
@ -44,6 +46,10 @@ namespace detail {
|
||||
template <typename RangeT>
|
||||
using IterOfRange = decltype(std::begin(std::declval<RangeT &>()));
|
||||
|
||||
template <typename RangeT>
|
||||
using ValueOfRange = typename std::remove_reference<decltype(
|
||||
*std::begin(std::declval<RangeT &>()))>::type;
|
||||
|
||||
} // End detail namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -123,7 +129,7 @@ inline void deleter(T *Ptr) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// mapped_iterator - This is a simple iterator adapter that causes a function to
|
||||
// be dereferenced whenever operator* is invoked on the iterator.
|
||||
// be applied whenever operator* is invoked on the iterator.
|
||||
//
|
||||
template <class RootIt, class UnaryFunc>
|
||||
class mapped_iterator {
|
||||
@ -134,9 +140,8 @@ class mapped_iterator {
|
||||
iterator_category;
|
||||
typedef typename std::iterator_traits<RootIt>::difference_type
|
||||
difference_type;
|
||||
typedef typename std::result_of<
|
||||
UnaryFunc(decltype(*std::declval<RootIt>()))>
|
||||
::type value_type;
|
||||
typedef decltype(std::declval<UnaryFunc>()(*std::declval<RootIt>()))
|
||||
value_type;
|
||||
|
||||
typedef void pointer;
|
||||
//typedef typename UnaryFunc::result_type *pointer;
|
||||
@ -356,65 +361,126 @@ template <size_t... I> struct index_sequence;
|
||||
template <class... Ts> struct index_sequence_for;
|
||||
|
||||
namespace detail {
|
||||
template <typename... Iters> class zip_first {
|
||||
public:
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef std::tuple<decltype(*std::declval<Iters>())...> value_type;
|
||||
using std::declval;
|
||||
|
||||
// We have to alias this since inlining the actual type at the usage site
|
||||
// in the parameter list of iterator_facade_base<> below ICEs MSVC 2017.
|
||||
template<typename... Iters> struct ZipTupleType {
|
||||
typedef std::tuple<decltype(*declval<Iters>())...> type;
|
||||
};
|
||||
|
||||
template <typename ZipType, typename... Iters>
|
||||
using zip_traits = iterator_facade_base<
|
||||
ZipType, typename std::common_type<std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<
|
||||
Iters>::iterator_category...>::type,
|
||||
// ^ TODO: Implement random access methods.
|
||||
typename ZipTupleType<Iters...>::type,
|
||||
typename std::iterator_traits<typename std::tuple_element<
|
||||
0, std::tuple<Iters...>>::type>::difference_type,
|
||||
// ^ FIXME: This follows boost::make_zip_iterator's assumption that all
|
||||
// inner iterators have the same difference_type. It would fail if, for
|
||||
// instance, the second field's difference_type were non-numeric while the
|
||||
// first is.
|
||||
typename ZipTupleType<Iters...>::type *,
|
||||
typename ZipTupleType<Iters...>::type>;
|
||||
|
||||
template <typename ZipType, typename... Iters>
|
||||
struct zip_common : public zip_traits<ZipType, Iters...> {
|
||||
using Base = zip_traits<ZipType, Iters...>;
|
||||
using value_type = typename Base::value_type;
|
||||
|
||||
std::tuple<Iters...> iterators;
|
||||
|
||||
private:
|
||||
template <size_t... Ns> value_type deres(index_sequence<Ns...>) {
|
||||
protected:
|
||||
template <size_t... Ns> value_type deref(index_sequence<Ns...>) const {
|
||||
return value_type(*std::get<Ns>(iterators)...);
|
||||
}
|
||||
|
||||
template <size_t... Ns> decltype(iterators) tup_inc(index_sequence<Ns...>) {
|
||||
template <size_t... Ns>
|
||||
decltype(iterators) tup_inc(index_sequence<Ns...>) const {
|
||||
return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...);
|
||||
}
|
||||
|
||||
public:
|
||||
value_type operator*() { return deres(index_sequence_for<Iters...>{}); }
|
||||
|
||||
void operator++() { iterators = tup_inc(index_sequence_for<Iters...>{}); }
|
||||
|
||||
bool operator!=(const zip_first<Iters...> &other) const {
|
||||
return std::get<0>(iterators) != std::get<0>(other.iterators);
|
||||
template <size_t... Ns>
|
||||
decltype(iterators) tup_dec(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(index_sequence_for<Iters...>{}); }
|
||||
|
||||
const value_type operator*() const {
|
||||
return deref(index_sequence_for<Iters...>{});
|
||||
}
|
||||
|
||||
ZipType &operator++() {
|
||||
iterators = tup_inc(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(index_sequence_for<Iters...>{});
|
||||
return *reinterpret_cast<ZipType *>(this);
|
||||
}
|
||||
zip_first(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
|
||||
};
|
||||
|
||||
template <typename... Iters> class zip_shortest : public zip_first<Iters...> {
|
||||
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_first<Iters...> &other, index_sequence<Ns...>) const {
|
||||
bool test(const zip_shortest<Iters...> &other, index_sequence<Ns...>) const {
|
||||
return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
|
||||
std::get<Ns>(other.iterators)...},
|
||||
identity<bool>{});
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator!=(const zip_first<Iters...> &other) const {
|
||||
return test(other, index_sequence_for<Iters...>{});
|
||||
using Base = zip_common<zip_shortest<Iters...>, Iters...>;
|
||||
|
||||
bool operator==(const zip_shortest<Iters...> &other) const {
|
||||
return !test(other, index_sequence_for<Iters...>{});
|
||||
}
|
||||
zip_shortest(Iters &&... ts)
|
||||
: zip_first<Iters...>(std::forward<Iters>(ts)...) {}
|
||||
|
||||
zip_shortest(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {}
|
||||
};
|
||||
|
||||
template <template <typename...> class ItType, typename... Args> class zippy {
|
||||
public:
|
||||
typedef ItType<decltype(std::begin(std::declval<Args>()))...> iterator;
|
||||
using iterator = ItType<decltype(std::begin(std::declval<Args>()))...>;
|
||||
using iterator_category = typename iterator::iterator_category;
|
||||
using value_type = typename iterator::value_type;
|
||||
using difference_type = typename iterator::difference_type;
|
||||
using pointer = typename iterator::pointer;
|
||||
using reference = typename iterator::reference;
|
||||
|
||||
private:
|
||||
std::tuple<Args...> ts;
|
||||
|
||||
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
|
||||
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) const {
|
||||
return iterator(std::begin(std::get<Ns>(ts))...);
|
||||
}
|
||||
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
|
||||
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) const {
|
||||
return iterator(std::end(std::get<Ns>(ts))...);
|
||||
}
|
||||
|
||||
public:
|
||||
iterator begin() { return begin_impl(index_sequence_for<Args...>{}); }
|
||||
iterator end() { return end_impl(index_sequence_for<Args...>{}); }
|
||||
iterator begin() const { return begin_impl(index_sequence_for<Args...>{}); }
|
||||
iterator end() const { return end_impl(index_sequence_for<Args...>{}); }
|
||||
zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
|
||||
};
|
||||
} // End detail namespace
|
||||
@ -777,6 +843,13 @@ auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
|
||||
return std::remove_if(std::begin(Range), std::end(Range), P);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::copy_if which take ranges instead of having to
|
||||
/// pass begin/end explicitly.
|
||||
template <typename R, typename OutputIt, typename UnaryPredicate>
|
||||
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) {
|
||||
return std::copy_if(std::begin(Range), std::end(Range), Out, P);
|
||||
}
|
||||
|
||||
/// Wrapper function around std::find to detect if an element exists
|
||||
/// in a container.
|
||||
template <typename R, typename E>
|
||||
@ -815,6 +888,15 @@ auto partition(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
|
||||
return std::partition(std::begin(Range), std::end(Range), P);
|
||||
}
|
||||
|
||||
/// \brief Given a range of type R, iterate the entire range and return a
|
||||
/// SmallVector with elements of the vector. This is useful, for example,
|
||||
/// when you want to iterate a range and then sort the results.
|
||||
template <unsigned Size, typename R>
|
||||
SmallVector<typename std::remove_const<detail::ValueOfRange<R>>::type, Size>
|
||||
to_vector(R &&Range) {
|
||||
return {std::begin(Range), std::end(Range)};
|
||||
}
|
||||
|
||||
/// Provide a container algorithm similar to C++ Library Fundamentals v2's
|
||||
/// `erase_if` which is equivalent to:
|
||||
///
|
||||
@ -909,47 +991,85 @@ template <typename T> struct deref {
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename R> class enumerator_impl {
|
||||
public:
|
||||
template <typename X> struct result_pair {
|
||||
result_pair(std::size_t Index, X Value) : Index(Index), Value(Value) {}
|
||||
template <typename R> class enumerator_iter;
|
||||
|
||||
const std::size_t Index;
|
||||
X Value;
|
||||
};
|
||||
template <typename R> struct result_pair {
|
||||
friend class enumerator_iter<R>;
|
||||
|
||||
class iterator {
|
||||
typedef
|
||||
typename std::iterator_traits<IterOfRange<R>>::reference iter_reference;
|
||||
typedef result_pair<iter_reference> result_type;
|
||||
result_pair() : Index(-1) {}
|
||||
result_pair(std::size_t Index, IterOfRange<R> Iter)
|
||||
: Index(Index), Iter(Iter) {}
|
||||
|
||||
public:
|
||||
iterator(IterOfRange<R> &&Iter, std::size_t Index)
|
||||
: Iter(Iter), Index(Index) {}
|
||||
result_pair<R> &operator=(const result_pair<R> &Other) {
|
||||
Index = Other.Index;
|
||||
Iter = Other.Iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
result_type operator*() const { return result_type(Index, *Iter); }
|
||||
|
||||
iterator &operator++() {
|
||||
++Iter;
|
||||
++Index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &RHS) const { return Iter != RHS.Iter; }
|
||||
|
||||
private:
|
||||
IterOfRange<R> Iter;
|
||||
std::size_t Index;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit enumerator_impl(R &&Range) : Range(std::forward<R>(Range)) {}
|
||||
|
||||
iterator begin() { return iterator(std::begin(Range), 0); }
|
||||
iterator end() { return iterator(std::end(Range), std::size_t(-1)); }
|
||||
std::size_t index() const { return Index; }
|
||||
const ValueOfRange<R> &value() const { return *Iter; }
|
||||
ValueOfRange<R> &value() { return *Iter; }
|
||||
|
||||
private:
|
||||
R Range;
|
||||
std::size_t Index;
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
@ -968,8 +1088,8 @@ template <typename R> class enumerator_impl {
|
||||
/// Item 2 - C
|
||||
/// Item 3 - D
|
||||
///
|
||||
template <typename R> detail::enumerator_impl<R> enumerate(R &&Range) {
|
||||
return detail::enumerator_impl<R>(std::forward<R>(Range));
|
||||
template <typename R> detail::enumerator<R> enumerate(R &&TheRange) {
|
||||
return detail::enumerator<R>(std::forward<R>(TheRange));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
@ -182,8 +182,8 @@ class ScopedHashTable {
|
||||
return TopLevelMap.count(Key);
|
||||
}
|
||||
|
||||
V lookup(const K &Key) {
|
||||
typename DenseMap<K, ValTy*, KInfo>::iterator I = TopLevelMap.find(Key);
|
||||
V lookup(const K &Key) const {
|
||||
auto I = TopLevelMap.find(Key);
|
||||
if (I != TopLevelMap.end())
|
||||
return I->second->getValue();
|
||||
|
||||
|
@ -119,6 +119,12 @@ class SetVector {
|
||||
return vector_.rend();
|
||||
}
|
||||
|
||||
/// \brief Return the first element of the SetVector.
|
||||
const T &front() const {
|
||||
assert(!empty() && "Cannot call front() on empty SetVector!");
|
||||
return vector_.front();
|
||||
}
|
||||
|
||||
/// \brief Return the last element of the SetVector.
|
||||
const T &back() const {
|
||||
assert(!empty() && "Cannot call back() on empty SetVector!");
|
||||
@ -232,7 +238,7 @@ class SetVector {
|
||||
bool operator!=(const SetVector &that) const {
|
||||
return vector_ != that.vector_;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compute This := This u S, return whether 'This' changed.
|
||||
/// TODO: We should be able to use set_union from SetOperations.h, but
|
||||
/// SetVector interface is inconsistent with DenseSet.
|
||||
|
@ -216,6 +216,18 @@ class SmallBitVector {
|
||||
return getPointer()->find_first();
|
||||
}
|
||||
|
||||
/// Returns the index of the first unset bit, -1 if all of the bits are set.
|
||||
int find_first_unset() const {
|
||||
if (isSmall()) {
|
||||
if (count() == getSmallSize())
|
||||
return -1;
|
||||
|
||||
uintptr_t Bits = getSmallBits();
|
||||
return countTrailingOnes(Bits);
|
||||
}
|
||||
return getPointer()->find_first_unset();
|
||||
}
|
||||
|
||||
/// Returns the index of the next set bit following the "Prev" bit.
|
||||
/// Returns -1 if the next set bit is not found.
|
||||
int find_next(unsigned Prev) const {
|
||||
@ -230,6 +242,23 @@ class SmallBitVector {
|
||||
return getPointer()->find_next(Prev);
|
||||
}
|
||||
|
||||
/// Returns the index of the next unset bit following the "Prev" bit.
|
||||
/// Returns -1 if the next unset bit is not found.
|
||||
int find_next_unset(unsigned Prev) const {
|
||||
if (isSmall()) {
|
||||
++Prev;
|
||||
uintptr_t Bits = getSmallBits();
|
||||
// Mask in previous bits.
|
||||
uintptr_t Mask = (1 << Prev) - 1;
|
||||
Bits |= Mask;
|
||||
|
||||
if (Bits == ~uintptr_t(0) || Prev + 1 >= getSmallSize())
|
||||
return -1;
|
||||
return countTrailingOnes(Bits);
|
||||
}
|
||||
return getPointer()->find_next_unset(Prev);
|
||||
}
|
||||
|
||||
/// Clear all bits.
|
||||
void clear() {
|
||||
if (!isSmall())
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/Config/abi-breaking.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
@ -166,8 +167,8 @@ class SmallPtrSetImplBase {
|
||||
const void *const *P = find_imp(Ptr);
|
||||
if (P == EndPointer())
|
||||
return false;
|
||||
|
||||
const void ** Loc = const_cast<const void **>(P);
|
||||
|
||||
const void **Loc = const_cast<const void **>(P);
|
||||
assert(*Loc == Ptr && "broken find!");
|
||||
*Loc = getTombstoneMarker();
|
||||
NumTombstones++;
|
||||
@ -193,7 +194,7 @@ class SmallPtrSetImplBase {
|
||||
return Bucket;
|
||||
return EndPointer();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool isSmall() const { return CurArray == SmallArray; }
|
||||
|
||||
@ -259,11 +260,10 @@ class SmallPtrSetIteratorImpl {
|
||||
}
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
void RetreatIfNotValid() {
|
||||
--Bucket;
|
||||
assert(Bucket <= End);
|
||||
assert(Bucket >= End);
|
||||
while (Bucket != End &&
|
||||
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker())) {
|
||||
(Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
|
||||
--Bucket;
|
||||
}
|
||||
}
|
||||
@ -288,6 +288,12 @@ class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
||||
// Most methods provided by baseclass.
|
||||
|
||||
const PtrTy operator*() const {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
if (ReverseIterate<bool>::value) {
|
||||
assert(Bucket > End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
|
||||
}
|
||||
#endif
|
||||
assert(Bucket < End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
|
||||
}
|
||||
@ -295,6 +301,7 @@ class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
||||
inline SmallPtrSetIterator& operator++() { // Preincrement
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
if (ReverseIterate<bool>::value) {
|
||||
--Bucket;
|
||||
RetreatIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
@ -343,7 +350,9 @@ struct RoundUpToPowerOfTwo {
|
||||
/// to avoid encoding a particular small size in the interface boundary.
|
||||
template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
|
||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
||||
typedef PointerLikeTypeTraits<ConstPtrType> ConstPtrTraits;
|
||||
|
||||
protected:
|
||||
// Constructors that forward to the base.
|
||||
@ -367,7 +376,7 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
/// the element equal to Ptr.
|
||||
std::pair<iterator, bool> insert(PtrType Ptr) {
|
||||
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return std::make_pair(iterator(p.first, EndPointer()), p.second);
|
||||
return std::make_pair(makeIterator(p.first), p.second);
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
@ -375,14 +384,10 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
bool erase(PtrType Ptr) {
|
||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
}
|
||||
|
||||
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||
size_type count(PtrType Ptr) const {
|
||||
return find(Ptr) != endPtr() ? 1 : 0;
|
||||
}
|
||||
iterator find(PtrType Ptr) const {
|
||||
auto *P = find_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return iterator(P, EndPointer());
|
||||
size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
|
||||
iterator find(ConstPtrType Ptr) const {
|
||||
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
@ -395,25 +400,23 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
insert(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
inline iterator begin() const {
|
||||
iterator begin() const {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
if (ReverseIterate<bool>::value)
|
||||
return endPtr();
|
||||
return makeIterator(EndPointer() - 1);
|
||||
#endif
|
||||
return iterator(CurArray, EndPointer());
|
||||
}
|
||||
inline iterator end() const {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
if (ReverseIterate<bool>::value)
|
||||
return iterator(CurArray, CurArray);
|
||||
#endif
|
||||
return endPtr();
|
||||
return makeIterator(CurArray);
|
||||
}
|
||||
iterator end() const { return makeIterator(EndPointer()); }
|
||||
|
||||
private:
|
||||
inline iterator endPtr() const {
|
||||
const void *const *End = EndPointer();
|
||||
return iterator(End, End);
|
||||
/// Create an iterator that dereferences to same place as the given pointer.
|
||||
iterator makeIterator(const void *const *P) const {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
if (ReverseIterate<bool>::value)
|
||||
return iterator(P == EndPointer() ? CurArray : P + 1, CurArray);
|
||||
#endif
|
||||
return iterator(P, EndPointer());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -132,6 +132,17 @@ template <unsigned ElementSize = 128> struct SparseBitVectorElement {
|
||||
llvm_unreachable("Illegal empty element");
|
||||
}
|
||||
|
||||
/// find_last - Returns the index of the last set bit.
|
||||
int find_last() const {
|
||||
for (unsigned I = 0; I < BITWORDS_PER_ELEMENT; ++I) {
|
||||
unsigned Idx = BITWORDS_PER_ELEMENT - I - 1;
|
||||
if (Bits[Idx] != 0)
|
||||
return Idx * BITWORD_SIZE + BITWORD_SIZE -
|
||||
countLeadingZeros(Bits[Idx]) - 1;
|
||||
}
|
||||
llvm_unreachable("Illegal empty element");
|
||||
}
|
||||
|
||||
/// find_next - Returns the index of the next set bit starting from the
|
||||
/// "Curr" bit. Returns -1 if the next set bit is not found.
|
||||
int find_next(unsigned Curr) const {
|
||||
@ -768,6 +779,14 @@ class SparseBitVector {
|
||||
return (First.index() * ElementSize) + First.find_first();
|
||||
}
|
||||
|
||||
// Return the last set bit in the bitmap. Return -1 if no bits are set.
|
||||
int find_last() const {
|
||||
if (Elements.empty())
|
||||
return -1;
|
||||
const SparseBitVectorElement<ElementSize> &Last = *(Elements.rbegin());
|
||||
return (Last.index() * ElementSize) + Last.find_last();
|
||||
}
|
||||
|
||||
// Return true if the SparseBitVector is empty
|
||||
bool empty() const {
|
||||
return Elements.empty();
|
||||
|
@ -234,6 +234,13 @@ inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
|
||||
return detail::join_impl(Begin, End, Separator, tag());
|
||||
}
|
||||
|
||||
/// Joins the strings in the range [R.begin(), R.end()), adding Separator
|
||||
/// between the elements.
|
||||
template <typename Range>
|
||||
inline std::string join(Range &&R, StringRef Separator) {
|
||||
return join(R.begin(), R.end(), Separator);
|
||||
}
|
||||
|
||||
/// Joins the strings in the parameter pack \p Items, adding \p Separator
|
||||
/// between the elements. All arguments must be implicitly convertible to
|
||||
/// std::string, or there should be an overload of std::string::operator+=()
|
||||
|
@ -15,13 +15,13 @@
|
||||
#define LLVM_ADT_STRINGMAP_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <initializer_list>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
@ -32,6 +32,7 @@ namespace llvm {
|
||||
class StringMapConstIterator;
|
||||
template<typename ValueT>
|
||||
class StringMapIterator;
|
||||
template <typename ValueT> class StringMapKeyIterator;
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry;
|
||||
|
||||
@ -312,6 +313,11 @@ class StringMap : public StringMapImpl {
|
||||
return const_iterator(TheTable+NumBuckets, true);
|
||||
}
|
||||
|
||||
llvm::iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
||||
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
||||
StringMapKeyIterator<ValueTy>(end()));
|
||||
}
|
||||
|
||||
iterator find(StringRef Key) {
|
||||
int Bucket = FindKey(Key);
|
||||
if (Bucket == -1) return end();
|
||||
@ -444,42 +450,39 @@ class StringMap : public StringMapImpl {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy> class StringMapConstIterator {
|
||||
template <typename DerivedTy, typename ValueTy>
|
||||
class StringMapIterBase
|
||||
: public iterator_facade_base<DerivedTy, std::forward_iterator_tag,
|
||||
ValueTy> {
|
||||
protected:
|
||||
StringMapEntryBase **Ptr = nullptr;
|
||||
|
||||
public:
|
||||
typedef StringMapEntry<ValueTy> value_type;
|
||||
StringMapIterBase() = default;
|
||||
|
||||
StringMapConstIterator() = default;
|
||||
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
explicit StringMapIterBase(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: Ptr(Bucket) {
|
||||
if (!NoAdvance) AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
const value_type &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy>*>(*Ptr);
|
||||
}
|
||||
const value_type *operator->() const {
|
||||
return static_cast<StringMapEntry<ValueTy>*>(*Ptr);
|
||||
DerivedTy &operator=(const DerivedTy &Other) {
|
||||
Ptr = Other.Ptr;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
|
||||
bool operator==(const StringMapConstIterator &RHS) const {
|
||||
return Ptr == RHS.Ptr;
|
||||
}
|
||||
bool operator!=(const StringMapConstIterator &RHS) const {
|
||||
return Ptr != RHS.Ptr;
|
||||
}
|
||||
bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
|
||||
|
||||
inline StringMapConstIterator& operator++() { // Preincrement
|
||||
DerivedTy &operator++() { // Preincrement
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return *this;
|
||||
return static_cast<DerivedTy &>(*this);
|
||||
}
|
||||
StringMapConstIterator operator++(int) { // Postincrement
|
||||
StringMapConstIterator tmp = *this; ++*this; return tmp;
|
||||
|
||||
DerivedTy operator++(int) { // Post-increment
|
||||
DerivedTy Tmp(Ptr);
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -489,24 +492,69 @@ template <typename ValueTy> class StringMapConstIterator {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ValueTy>
|
||||
class StringMapIterator : public StringMapConstIterator<ValueTy> {
|
||||
template <typename ValueTy>
|
||||
class StringMapConstIterator
|
||||
: public StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>> {
|
||||
using base = StringMapIterBase<StringMapConstIterator<ValueTy>,
|
||||
const StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapConstIterator() = default;
|
||||
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
const StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueTy>
|
||||
class StringMapIterator : public StringMapIterBase<StringMapIterator<ValueTy>,
|
||||
StringMapEntry<ValueTy>> {
|
||||
using base =
|
||||
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
|
||||
|
||||
public:
|
||||
StringMapIterator() = default;
|
||||
|
||||
explicit StringMapIterator(StringMapEntryBase **Bucket,
|
||||
bool NoAdvance = false)
|
||||
: StringMapConstIterator<ValueTy>(Bucket, NoAdvance) {
|
||||
}
|
||||
: base(Bucket, NoAdvance) {}
|
||||
|
||||
StringMapEntry<ValueTy> &operator*() const {
|
||||
return *static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
|
||||
return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
|
||||
}
|
||||
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
|
||||
|
@ -557,6 +557,14 @@ namespace llvm {
|
||||
/// string is well-formed in the given radix.
|
||||
bool getAsInteger(unsigned Radix, APInt &Result) const;
|
||||
|
||||
/// Parse the current string as an IEEE double-precision floating
|
||||
/// point value. The string must be a well-formed double.
|
||||
///
|
||||
/// If \p AllowInexact is false, the function will fail if the string
|
||||
/// cannot be represented exactly. Otherwise, the function only fails
|
||||
/// in case of an overflow or underflow.
|
||||
bool getAsDouble(double &Result, bool AllowInexact = true) const;
|
||||
|
||||
/// @}
|
||||
/// @name String Operations
|
||||
/// @{
|
||||
@ -600,7 +608,7 @@ namespace llvm {
|
||||
return drop_back(size() - N);
|
||||
}
|
||||
|
||||
/// Return a StringRef equal to 'this' but with only the first \p N
|
||||
/// Return a StringRef equal to 'this' but with only the last \p N
|
||||
/// elements remaining. If \p N is greater than the length of the
|
||||
/// string, the entire string is returned.
|
||||
LLVM_NODISCARD
|
||||
|
@ -110,6 +110,7 @@ class Triple {
|
||||
ARMSubArch_v7m,
|
||||
ARMSubArch_v7s,
|
||||
ARMSubArch_v7k,
|
||||
ARMSubArch_v7ve,
|
||||
ARMSubArch_v6,
|
||||
ARMSubArch_v6m,
|
||||
ARMSubArch_v6k,
|
||||
@ -206,6 +207,7 @@ class Triple {
|
||||
COFF,
|
||||
ELF,
|
||||
MachO,
|
||||
Wasm,
|
||||
};
|
||||
|
||||
private:
|
||||
@ -558,7 +560,8 @@ class Triple {
|
||||
|
||||
/// Tests whether the OS uses glibc.
|
||||
bool isOSGlibc() const {
|
||||
return getOS() == Triple::Linux || getOS() == Triple::KFreeBSD;
|
||||
return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD) &&
|
||||
!isAndroid();
|
||||
}
|
||||
|
||||
/// Tests whether the OS uses the ELF binary format.
|
||||
@ -576,6 +579,11 @@ class Triple {
|
||||
return getObjectFormat() == Triple::MachO;
|
||||
}
|
||||
|
||||
/// Tests whether the OS uses the Wasm binary format.
|
||||
bool isOSBinFormatWasm() const {
|
||||
return getObjectFormat() == Triple::Wasm;
|
||||
}
|
||||
|
||||
/// Tests whether the target is the PS4 CPU
|
||||
bool isPS4CPU() const {
|
||||
return getArch() == Triple::x86_64 &&
|
||||
@ -592,6 +600,19 @@ class Triple {
|
||||
/// 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 ||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_ADT_ITERATOR_H
|
||||
#define LLVM_ADT_ITERATOR_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
@ -91,6 +92,8 @@ class iterator_facade_base
|
||||
|
||||
public:
|
||||
DerivedT operator+(DifferenceTypeT n) const {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
static_assert(
|
||||
IsRandomAccess,
|
||||
"The '+' operator is only defined for random access iterators.");
|
||||
@ -114,6 +117,8 @@ class iterator_facade_base
|
||||
}
|
||||
|
||||
DerivedT &operator++() {
|
||||
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
return static_cast<DerivedT *>(this)->operator+=(1);
|
||||
}
|
||||
DerivedT operator++(int) {
|
||||
@ -160,9 +165,15 @@ class iterator_facade_base
|
||||
return !static_cast<const DerivedT *>(this)->operator<(RHS);
|
||||
}
|
||||
|
||||
PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
|
||||
PointerT operator->() const {
|
||||
return &static_cast<const DerivedT *>(this)->operator*();
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
|
||||
}
|
||||
ReferenceProxy operator[](DifferenceTypeT n) const {
|
||||
static_assert(IsRandomAccess,
|
||||
"Subscripting is only defined for random access iterators.");
|
||||
@ -202,7 +213,10 @@ class iterator_adaptor_base
|
||||
|
||||
iterator_adaptor_base() = default;
|
||||
|
||||
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {}
|
||||
explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {
|
||||
static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
}
|
||||
|
||||
const WrappedIteratorT &wrapped() const { return I; }
|
||||
|
||||
@ -283,6 +297,15 @@ struct pointee_iterator
|
||||
T &operator*() const { return **this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointee_iterator<WrappedIteratorT>>
|
||||
make_pointee_range(RangeT &&Range) {
|
||||
using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
|
||||
return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
template <typename WrappedIteratorT,
|
||||
typename T = decltype(&*std::declval<WrappedIteratorT>())>
|
||||
class pointer_iterator
|
||||
@ -300,6 +323,15 @@ class pointer_iterator
|
||||
const T &operator*() const { return Ptr = &*this->I; }
|
||||
};
|
||||
|
||||
template <typename RangeT, typename WrappedIteratorT =
|
||||
decltype(std::begin(std::declval<RangeT>()))>
|
||||
iterator_range<pointer_iterator<WrappedIteratorT>>
|
||||
make_pointer_range(RangeT &&Range) {
|
||||
using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
|
||||
return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
|
||||
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_ITERATOR_H
|
||||
|
@ -443,11 +443,7 @@ class AAResults {
|
||||
|
||||
/// getModRefInfo (for fences) - Return information about whether
|
||||
/// a particular store modifies or reads the specified memory location.
|
||||
ModRefInfo getModRefInfo(const FenceInst *S, const MemoryLocation &Loc) {
|
||||
// Conservatively correct. (We could possibly be a bit smarter if
|
||||
// Loc is a alloca that doesn't escape.)
|
||||
return MRI_ModRef;
|
||||
}
|
||||
ModRefInfo getModRefInfo(const FenceInst *S, const MemoryLocation &Loc);
|
||||
|
||||
/// getModRefInfo (for fences) - A convenience wrapper.
|
||||
ModRefInfo getModRefInfo(const FenceInst *S, const Value *P, uint64_t Size) {
|
||||
@ -528,6 +524,14 @@ class AAResults {
|
||||
/// Check whether or not an instruction may read or write the specified
|
||||
/// memory location.
|
||||
///
|
||||
/// Note explicitly that getModRefInfo considers the effects of reading and
|
||||
/// writing the memory location, and not the effect of ordering relative to
|
||||
/// other instructions. Thus, a volatile load is considered to be Ref,
|
||||
/// because it does not actually write memory, it just can't be reordered
|
||||
/// relative to other volatiles (or removed). Atomic ordered loads/stores are
|
||||
/// considered ModRef ATM because conservatively, the visible effect appears
|
||||
/// as if memory was written, not just an ordering constraint.
|
||||
///
|
||||
/// An instruction that doesn't read or write memory may be trivially LICM'd
|
||||
/// for example.
|
||||
///
|
||||
|
@ -121,7 +121,10 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
AliasSet *Forward;
|
||||
|
||||
/// All instructions without a specific address in this alias set.
|
||||
std::vector<AssertingVH<Instruction> > UnknownInsts;
|
||||
/// In rare cases this vector can have a null'ed out WeakVH
|
||||
/// instances (can happen if some other loop pass deletes an
|
||||
/// instruction in this list).
|
||||
std::vector<WeakVH> UnknownInsts;
|
||||
|
||||
/// Number of nodes pointing to this AliasSet plus the number of AliasSets
|
||||
/// forwarding to it.
|
||||
@ -171,7 +174,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
|
||||
Instruction *getUnknownInst(unsigned i) const {
|
||||
assert(i < UnknownInsts.size());
|
||||
return UnknownInsts[i];
|
||||
return cast_or_null<Instruction>(UnknownInsts[i]);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -31,11 +31,10 @@ namespace llvm {
|
||||
/// \brief A cache of @llvm.assume calls within a function.
|
||||
///
|
||||
/// This cache provides fast lookup of assumptions within a function by caching
|
||||
/// them and amortizing the cost of scanning for them across all queries. The
|
||||
/// cache is also conservatively self-updating so that it will never return
|
||||
/// incorrect results about a function even as the function is being mutated.
|
||||
/// However, flushing the cache and rebuilding it (or explicitly updating it)
|
||||
/// may allow it to discover new assumptions.
|
||||
/// them and amortizing the cost of scanning for them across all queries. Passes
|
||||
/// that create new assumptions are required to call registerAssumption() to
|
||||
/// register any new @llvm.assume calls that they create. Deletions of
|
||||
/// @llvm.assume calls do not require special handling.
|
||||
class AssumptionCache {
|
||||
/// \brief The function for which this cache is handling assumptions.
|
||||
///
|
||||
@ -87,6 +86,13 @@ class AssumptionCache {
|
||||
/// its instructions.
|
||||
AssumptionCache(Function &F) : F(F), Scanned(false) {}
|
||||
|
||||
/// This cache is designed to be self-updating and so it should never be
|
||||
/// invalidated.
|
||||
bool invalidate(Function &, const PreservedAnalyses &,
|
||||
FunctionAnalysisManager::Invalidator &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Add an @llvm.assume intrinsic to this function's cache.
|
||||
///
|
||||
/// The call passed in must be an instruction within this function and must
|
||||
@ -196,7 +202,10 @@ class AssumptionCacheTracker : public ImmutablePass {
|
||||
AssumptionCacheTracker();
|
||||
~AssumptionCacheTracker() override;
|
||||
|
||||
void releaseMemory() override { AssumptionCaches.shrink_and_clear(); }
|
||||
void releaseMemory() override {
|
||||
verifyAnalysis();
|
||||
AssumptionCaches.shrink_and_clear();
|
||||
}
|
||||
|
||||
void verifyAnalysis() const override;
|
||||
bool doFinalization(Module &) override {
|
||||
|
@ -233,6 +233,24 @@ FunctionPass *createBasicAAWrapperPass();
|
||||
/// populated to the best of our ability for a particular function when inside
|
||||
/// of a \c ModulePass or a \c CallGraphSCCPass.
|
||||
BasicAAResult createLegacyPMBasicAAResult(Pass &P, Function &F);
|
||||
|
||||
/// This class is a functor to be used in legacy module or SCC passes for
|
||||
/// computing AA results for a function. We store the results in fields so that
|
||||
/// they live long enough to be queried, but we re-use them each time.
|
||||
class LegacyAARGetter {
|
||||
Pass &P;
|
||||
Optional<BasicAAResult> BAR;
|
||||
Optional<AAResults> AAR;
|
||||
|
||||
public:
|
||||
LegacyAARGetter(Pass &P) : P(P) {}
|
||||
AAResults &operator()(Function &F) {
|
||||
BAR.emplace(createLegacyPMBasicAAResult(P, F));
|
||||
AAR.emplace(createLegacyPMAAResults(P, F, *BAR));
|
||||
return *AAR;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -45,6 +45,10 @@ class BlockFrequencyInfo {
|
||||
|
||||
~BlockFrequencyInfo();
|
||||
|
||||
/// Handle invalidation explicitly.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &);
|
||||
|
||||
const Function *getFunction() const;
|
||||
const BranchProbabilityInfo *getBPI() const;
|
||||
void view() const;
|
||||
@ -69,6 +73,12 @@ class BlockFrequencyInfo {
|
||||
// Set the frequency of the given basic block.
|
||||
void setBlockFreq(const BasicBlock *BB, uint64_t Freq);
|
||||
|
||||
/// Set the frequency of \p ReferenceBB to \p Freq and scale the frequencies
|
||||
/// of the blocks in \p BlocksToScale such that their frequencies relative
|
||||
/// to \p ReferenceBB remain unchanged.
|
||||
void setBlockFreqAndScale(const BasicBlock *ReferenceBB, uint64_t Freq,
|
||||
SmallPtrSetImpl<BasicBlock *> &BlocksToScale);
|
||||
|
||||
/// calculate - compute block frequency info for the given function.
|
||||
void calculate(const Function &F, const BranchProbabilityInfo &BPI,
|
||||
const LoopInfo &LI);
|
||||
|
@ -1291,11 +1291,14 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
|
||||
}
|
||||
|
||||
std::string getNodeLabel(NodeRef Node, const BlockFrequencyInfoT *Graph,
|
||||
GVDAGType GType) {
|
||||
GVDAGType GType, int layout_order = -1) {
|
||||
std::string Result;
|
||||
raw_string_ostream OS(Result);
|
||||
|
||||
OS << Node->getName().str() << " : ";
|
||||
if (layout_order != -1)
|
||||
OS << Node->getName() << "[" << layout_order << "] : ";
|
||||
else
|
||||
OS << Node->getName() << " : ";
|
||||
switch (GType) {
|
||||
case GVDT_Fraction:
|
||||
Graph->printBlockFreq(OS, Node);
|
||||
|
@ -164,6 +164,8 @@ class BranchProbabilityInfo {
|
||||
/// \brief Track the set of blocks that always lead to a cold call.
|
||||
SmallPtrSet<const BasicBlock *, 16> PostDominatedByColdCall;
|
||||
|
||||
void updatePostDominatedByUnreachable(const BasicBlock *BB);
|
||||
void updatePostDominatedByColdCall(const BasicBlock *BB);
|
||||
bool calcUnreachableHeuristics(const BasicBlock *BB);
|
||||
bool calcMetadataWeights(const BasicBlock *BB);
|
||||
bool calcColdCallHeuristics(const BasicBlock *BB);
|
||||
|
@ -140,8 +140,7 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
|
||||
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
SwitchInst::ConstCaseIt Case =
|
||||
SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo);
|
||||
auto Case = *SwitchInst::ConstCaseIt::fromSuccessorIndex(SI, SuccNo);
|
||||
OS << Case.getCaseValue()->getValue();
|
||||
return OS.str();
|
||||
}
|
||||
|
@ -334,6 +334,7 @@ class ModuleToPostOrderCGSCCPassAdaptor
|
||||
InvalidSCCSet, nullptr, nullptr};
|
||||
|
||||
PreservedAnalyses PA = PreservedAnalyses::all();
|
||||
CG.buildRefSCCs();
|
||||
for (auto RCI = CG.postorder_ref_scc_begin(),
|
||||
RCE = CG.postorder_ref_scc_end();
|
||||
RCI != RCE;) {
|
||||
|
@ -272,7 +272,7 @@ class CallGraphNode {
|
||||
private:
|
||||
friend class CallGraph;
|
||||
|
||||
AssertingVH<Function> F;
|
||||
Function *F;
|
||||
|
||||
std::vector<CallRecord> CalledFunctions;
|
||||
|
||||
|
@ -100,6 +100,12 @@ Constant *ConstantFoldExtractValueInstruction(Constant *Agg,
|
||||
/// successful; if not, null is returned.
|
||||
Constant *ConstantFoldExtractElementInstruction(Constant *Val, Constant *Idx);
|
||||
|
||||
/// \brief Attempt to constant fold a shufflevector instruction with the
|
||||
/// specified operands and indices. The constant result is returned if
|
||||
/// successful; if not, null is returned.
|
||||
Constant *ConstantFoldShuffleVectorInstruction(Constant *V1, Constant *V2,
|
||||
Constant *Mask);
|
||||
|
||||
/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would
|
||||
/// produce if it is constant and determinable. If this is not determinable,
|
||||
/// return null.
|
||||
|
@ -141,6 +141,10 @@ class DominanceFrontier : public ForwardDominanceFrontierBase<BasicBlock> {
|
||||
typedef DominanceFrontierBase<BasicBlock>::DomSetType DomSetType;
|
||||
typedef DominanceFrontierBase<BasicBlock>::iterator iterator;
|
||||
typedef DominanceFrontierBase<BasicBlock>::const_iterator const_iterator;
|
||||
|
||||
/// Handle invalidation explicitly.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &);
|
||||
};
|
||||
|
||||
class DominanceFrontierWrapperPass : public FunctionPass {
|
||||
|
@ -21,16 +21,8 @@ struct PGOIndirectCallSiteVisitor
|
||||
PGOIndirectCallSiteVisitor() {}
|
||||
|
||||
void visitCallSite(CallSite CS) {
|
||||
if (CS.getCalledFunction() || !CS.getCalledValue())
|
||||
return;
|
||||
Instruction *I = CS.getInstruction();
|
||||
if (CallInst *CI = dyn_cast<CallInst>(I)) {
|
||||
if (CI->isInlineAsm())
|
||||
return;
|
||||
}
|
||||
if (isa<Constant>(CS.getCalledValue()))
|
||||
return;
|
||||
IndirectCallInsts.push_back(I);
|
||||
if (CS.isIndirectCall())
|
||||
IndirectCallInsts.push_back(CS.getInstruction());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class AssumptionCacheTracker;
|
||||
class BlockFrequencyInfo;
|
||||
class CallSite;
|
||||
class DataLayout;
|
||||
class Function;
|
||||
@ -137,6 +138,9 @@ struct InlineParams {
|
||||
|
||||
/// Threshold to use when the callsite is considered hot.
|
||||
Optional<int> HotCallSiteThreshold;
|
||||
|
||||
/// Threshold to use when the callsite is considered cold.
|
||||
Optional<int> ColdCallSiteThreshold;
|
||||
};
|
||||
|
||||
/// Generate the parameters to tune the inline cost analysis based only on the
|
||||
@ -171,6 +175,7 @@ InlineCost
|
||||
getInlineCost(CallSite CS, const InlineParams &Params,
|
||||
TargetTransformInfo &CalleeTTI,
|
||||
std::function<AssumptionCache &(Function &)> &GetAssumptionCache,
|
||||
Optional<function_ref<BlockFrequencyInfo &(Function &)>> GetBFI,
|
||||
ProfileSummaryInfo *PSI);
|
||||
|
||||
/// \brief Get an InlineCost with the callee explicitly specified.
|
||||
@ -182,6 +187,7 @@ InlineCost
|
||||
getInlineCost(CallSite CS, Function *Callee, const InlineParams &Params,
|
||||
TargetTransformInfo &CalleeTTI,
|
||||
std::function<AssumptionCache &(Function &)> &GetAssumptionCache,
|
||||
Optional<function_ref<BlockFrequencyInfo &(Function &)>> GetBFI,
|
||||
ProfileSummaryInfo *PSI);
|
||||
|
||||
/// \brief Minimal filter to detect invalid constructs for inlining.
|
||||
|
@ -42,6 +42,7 @@ namespace llvm {
|
||||
class Instruction;
|
||||
class DataLayout;
|
||||
class FastMathFlags;
|
||||
class OptimizationRemarkEmitter;
|
||||
class TargetLibraryInfo;
|
||||
class Type;
|
||||
class Value;
|
||||
@ -246,6 +247,14 @@ namespace llvm {
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a ShuffleVectorInst, fold the result or return null.
|
||||
Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
||||
Type *RetTy, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
//=== Helper functions for higher up the class hierarchy.
|
||||
|
||||
|
||||
@ -296,7 +305,8 @@ namespace llvm {
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
AssumptionCache *AC = nullptr,
|
||||
OptimizationRemarkEmitter *ORE = nullptr);
|
||||
|
||||
/// Replace all uses of 'I' with 'SimpleV' and simplify the uses recursively.
|
||||
///
|
||||
|
@ -9,7 +9,7 @@
|
||||
//
|
||||
// This is an alternative analysis pass to BlockFrequencyInfoWrapperPass. The
|
||||
// difference is that with this pass the block frequencies are not computed when
|
||||
// the analysis pass is executed but rather when the BFI results is explicitly
|
||||
// the analysis pass is executed but rather when the BFI result is explicitly
|
||||
// requested by the analysis client.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -27,10 +27,58 @@ class BranchProbabilityInfo;
|
||||
class Function;
|
||||
class LoopInfo;
|
||||
|
||||
/// Wraps a BFI to allow lazy computation of the block frequencies.
|
||||
///
|
||||
/// A pass that only conditionally uses BFI can uncondtionally require the
|
||||
/// analysis without paying for the overhead if BFI doesn't end up being used.
|
||||
template <typename FunctionT, typename BranchProbabilityInfoPassT,
|
||||
typename LoopInfoT, typename BlockFrequencyInfoT>
|
||||
class LazyBlockFrequencyInfo {
|
||||
public:
|
||||
LazyBlockFrequencyInfo()
|
||||
: Calculated(false), F(nullptr), BPIPass(nullptr), LI(nullptr) {}
|
||||
|
||||
/// Set up the per-function input.
|
||||
void setAnalysis(const FunctionT *F, BranchProbabilityInfoPassT *BPIPass,
|
||||
const LoopInfoT *LI) {
|
||||
this->F = F;
|
||||
this->BPIPass = BPIPass;
|
||||
this->LI = LI;
|
||||
}
|
||||
|
||||
/// Retrieve the BFI with the block frequencies computed.
|
||||
BlockFrequencyInfoT &getCalculated() {
|
||||
if (!Calculated) {
|
||||
assert(F && BPIPass && LI && "call setAnalysis");
|
||||
BFI.calculate(
|
||||
*F, BPIPassTrait<BranchProbabilityInfoPassT>::getBPI(BPIPass), *LI);
|
||||
Calculated = true;
|
||||
}
|
||||
return BFI;
|
||||
}
|
||||
|
||||
const BlockFrequencyInfoT &getCalculated() const {
|
||||
return const_cast<LazyBlockFrequencyInfo *>(this)->getCalculated();
|
||||
}
|
||||
|
||||
void releaseMemory() {
|
||||
BFI.releaseMemory();
|
||||
Calculated = false;
|
||||
setAnalysis(nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
BlockFrequencyInfoT BFI;
|
||||
bool Calculated;
|
||||
const FunctionT *F;
|
||||
BranchProbabilityInfoPassT *BPIPass;
|
||||
const LoopInfoT *LI;
|
||||
};
|
||||
|
||||
/// \brief This is an alternative analysis pass to
|
||||
/// BlockFrequencyInfoWrapperPass. The difference is that with this pass the
|
||||
/// block frequencies are not computed when the analysis pass is executed but
|
||||
/// rather when the BFI results is explicitly requested by the analysis client.
|
||||
/// rather when the BFI result is explicitly requested by the analysis client.
|
||||
///
|
||||
/// There are some additional requirements for any client pass that wants to use
|
||||
/// the analysis:
|
||||
@ -49,54 +97,12 @@ class LoopInfo;
|
||||
///
|
||||
/// Note that it is expected that we wouldn't need this functionality for the
|
||||
/// new PM since with the new PM, analyses are executed on demand.
|
||||
|
||||
class LazyBlockFrequencyInfoPass : public FunctionPass {
|
||||
|
||||
/// Wraps a BFI to allow lazy computation of the block frequencies.
|
||||
///
|
||||
/// A pass that only conditionally uses BFI can uncondtionally require the
|
||||
/// analysis without paying for the overhead if BFI doesn't end up being used.
|
||||
class LazyBlockFrequencyInfo {
|
||||
public:
|
||||
LazyBlockFrequencyInfo()
|
||||
: Calculated(false), F(nullptr), BPIPass(nullptr), LI(nullptr) {}
|
||||
|
||||
/// Set up the per-function input.
|
||||
void setAnalysis(const Function *F, LazyBranchProbabilityInfoPass *BPIPass,
|
||||
const LoopInfo *LI) {
|
||||
this->F = F;
|
||||
this->BPIPass = BPIPass;
|
||||
this->LI = LI;
|
||||
}
|
||||
|
||||
/// Retrieve the BFI with the block frequencies computed.
|
||||
BlockFrequencyInfo &getCalculated() {
|
||||
if (!Calculated) {
|
||||
assert(F && BPIPass && LI && "call setAnalysis");
|
||||
BFI.calculate(*F, BPIPass->getBPI(), *LI);
|
||||
Calculated = true;
|
||||
}
|
||||
return BFI;
|
||||
}
|
||||
|
||||
const BlockFrequencyInfo &getCalculated() const {
|
||||
return const_cast<LazyBlockFrequencyInfo *>(this)->getCalculated();
|
||||
}
|
||||
|
||||
void releaseMemory() {
|
||||
BFI.releaseMemory();
|
||||
Calculated = false;
|
||||
setAnalysis(nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
BlockFrequencyInfo BFI;
|
||||
bool Calculated;
|
||||
const Function *F;
|
||||
LazyBranchProbabilityInfoPass *BPIPass;
|
||||
const LoopInfo *LI;
|
||||
};
|
||||
|
||||
LazyBlockFrequencyInfo LBFI;
|
||||
private:
|
||||
LazyBlockFrequencyInfo<Function, LazyBranchProbabilityInfoPass, LoopInfo,
|
||||
BlockFrequencyInfo>
|
||||
LBFI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
@ -105,5 +105,17 @@ class LazyBranchProbabilityInfoPass : public FunctionPass {
|
||||
|
||||
/// \brief Helper for client passes to initialize dependent passes for LBPI.
|
||||
void initializeLazyBPIPassPass(PassRegistry &Registry);
|
||||
|
||||
/// \brief Simple trait class that provides a mapping between BPI passes and the
|
||||
/// corresponding BPInfo.
|
||||
template <typename PassT> struct BPIPassTrait {
|
||||
static PassT &getBPI(PassT *P) { return *P; }
|
||||
};
|
||||
|
||||
template <> struct BPIPassTrait<LazyBranchProbabilityInfoPass> {
|
||||
static BranchProbabilityInfo &getBPI(LazyBranchProbabilityInfoPass *P) {
|
||||
return P->getBPI();
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -106,6 +106,7 @@ class raw_ostream;
|
||||
class LazyCallGraph {
|
||||
public:
|
||||
class Node;
|
||||
class EdgeSequence;
|
||||
class SCC;
|
||||
class RefSCC;
|
||||
class edge_iterator;
|
||||
@ -121,16 +122,6 @@ class LazyCallGraph {
|
||||
/// inherently reference edges, and so the reference graph forms a superset
|
||||
/// of the formal call graph.
|
||||
///
|
||||
/// Furthermore, edges also may point to raw \c Function objects when those
|
||||
/// functions have not been scanned and incorporated into the graph (yet).
|
||||
/// This is one of the primary ways in which the graph can be lazy. When
|
||||
/// functions are scanned and fully incorporated into the graph, all of the
|
||||
/// edges referencing them are updated to point to the graph \c Node objects
|
||||
/// instead of to the raw \c Function objects. This class even provides
|
||||
/// methods to trigger this scan on-demand by attempting to get the target
|
||||
/// node of the graph and providing a reference back to the graph in order to
|
||||
/// lazily build it if necessary.
|
||||
///
|
||||
/// All of these forms of edges are fundamentally represented as outgoing
|
||||
/// edges. The edges are stored in the source node and point at the target
|
||||
/// node. This allows the edge structure itself to be a very compact data
|
||||
@ -141,7 +132,6 @@ class LazyCallGraph {
|
||||
enum Kind : bool { Ref = false, Call = true };
|
||||
|
||||
Edge();
|
||||
explicit Edge(Function &F, Kind K);
|
||||
explicit Edge(Node &N, Kind K);
|
||||
|
||||
/// Test whether the edge is null.
|
||||
@ -158,51 +148,218 @@ class LazyCallGraph {
|
||||
/// This requires that the edge is not null.
|
||||
bool isCall() const;
|
||||
|
||||
/// Get the call graph node referenced by this edge.
|
||||
///
|
||||
/// This requires that the edge is not null.
|
||||
Node &getNode() const;
|
||||
|
||||
/// Get the function referenced by this edge.
|
||||
///
|
||||
/// This requires that the edge is not null, but will succeed whether we
|
||||
/// have built a graph node for the function yet or not.
|
||||
/// This requires that the edge is not null.
|
||||
Function &getFunction() const;
|
||||
|
||||
/// Get the call graph node referenced by this edge if one exists.
|
||||
///
|
||||
/// This requires that the edge is not null. If we have built a graph node
|
||||
/// for the function this edge points to, this will return that node,
|
||||
/// otherwise it will return null.
|
||||
Node *getNode() const;
|
||||
|
||||
/// Get the call graph node for this edge, building it if necessary.
|
||||
///
|
||||
/// This requires that the edge is not null. If we have not yet built
|
||||
/// a graph node for the function this edge points to, this will first ask
|
||||
/// the graph to build that node, inserting it into all the relevant
|
||||
/// structures.
|
||||
Node &getNode(LazyCallGraph &G);
|
||||
|
||||
private:
|
||||
friend class LazyCallGraph::Node;
|
||||
friend class LazyCallGraph::EdgeSequence;
|
||||
friend class LazyCallGraph::RefSCC;
|
||||
|
||||
PointerIntPair<PointerUnion<Function *, Node *>, 1, Kind> Value;
|
||||
PointerIntPair<Node *, 1, Kind> Value;
|
||||
|
||||
void setKind(Kind K) { Value.setInt(K); }
|
||||
};
|
||||
|
||||
typedef SmallVector<Edge, 4> EdgeVectorT;
|
||||
typedef SmallVectorImpl<Edge> EdgeVectorImplT;
|
||||
/// The edge sequence object.
|
||||
///
|
||||
/// This typically exists entirely within the node but is exposed as
|
||||
/// a separate type because a node doesn't initially have edges. An explicit
|
||||
/// population step is required to produce this sequence at first and it is
|
||||
/// then cached in the node. It is also used to represent edges entering the
|
||||
/// graph from outside the module to model the graph's roots.
|
||||
///
|
||||
/// The sequence itself both iterable and indexable. The indexes remain
|
||||
/// stable even as the sequence mutates (including removal).
|
||||
class EdgeSequence {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
friend class LazyCallGraph::RefSCC;
|
||||
|
||||
typedef SmallVector<Edge, 4> VectorT;
|
||||
typedef SmallVectorImpl<Edge> VectorImplT;
|
||||
|
||||
public:
|
||||
/// An iterator used for the edges to both entry nodes and child nodes.
|
||||
class iterator
|
||||
: public iterator_adaptor_base<iterator, VectorImplT::iterator,
|
||||
std::forward_iterator_tag> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
VectorImplT::iterator E;
|
||||
|
||||
// Build the iterator for a specific position in the edge list.
|
||||
iterator(VectorImplT::iterator BaseI, VectorImplT::iterator E)
|
||||
: iterator_adaptor_base(BaseI), E(E) {
|
||||
while (I != E && !*I)
|
||||
++I;
|
||||
}
|
||||
|
||||
public:
|
||||
iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
iterator &operator++() {
|
||||
do {
|
||||
++I;
|
||||
} while (I != E && !*I);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// An iterator over specifically call edges.
|
||||
///
|
||||
/// This has the same iteration properties as the \c iterator, but
|
||||
/// restricts itself to edges which represent actual calls.
|
||||
class call_iterator
|
||||
: public iterator_adaptor_base<call_iterator, VectorImplT::iterator,
|
||||
std::forward_iterator_tag> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
VectorImplT::iterator E;
|
||||
|
||||
/// Advance the iterator to the next valid, call edge.
|
||||
void advanceToNextEdge() {
|
||||
while (I != E && (!*I || !I->isCall()))
|
||||
++I;
|
||||
}
|
||||
|
||||
// Build the iterator for a specific position in the edge list.
|
||||
call_iterator(VectorImplT::iterator BaseI, VectorImplT::iterator E)
|
||||
: iterator_adaptor_base(BaseI), E(E) {
|
||||
advanceToNextEdge();
|
||||
}
|
||||
|
||||
public:
|
||||
call_iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
call_iterator &operator++() {
|
||||
++I;
|
||||
advanceToNextEdge();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(Edges.begin(), Edges.end()); }
|
||||
iterator end() { return iterator(Edges.end(), Edges.end()); }
|
||||
|
||||
Edge &operator[](int i) { return Edges[i]; }
|
||||
Edge &operator[](Node &N) {
|
||||
assert(EdgeIndexMap.find(&N) != EdgeIndexMap.end() && "No such edge!");
|
||||
return Edges[EdgeIndexMap.find(&N)->second];
|
||||
}
|
||||
Edge *lookup(Node &N) {
|
||||
auto EI = EdgeIndexMap.find(&N);
|
||||
return EI != EdgeIndexMap.end() ? &Edges[EI->second] : nullptr;
|
||||
}
|
||||
|
||||
call_iterator call_begin() {
|
||||
return call_iterator(Edges.begin(), Edges.end());
|
||||
}
|
||||
call_iterator call_end() { return call_iterator(Edges.end(), Edges.end()); }
|
||||
|
||||
iterator_range<call_iterator> calls() {
|
||||
return make_range(call_begin(), call_end());
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
for (auto &E : Edges)
|
||||
if (E)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
VectorT Edges;
|
||||
DenseMap<Node *, int> EdgeIndexMap;
|
||||
|
||||
EdgeSequence() = default;
|
||||
|
||||
/// Internal helper to insert an edge to a node.
|
||||
void insertEdgeInternal(Node &ChildN, Edge::Kind EK);
|
||||
|
||||
/// Internal helper to change an edge kind.
|
||||
void setEdgeKind(Node &ChildN, Edge::Kind EK);
|
||||
|
||||
/// Internal helper to remove the edge to the given function.
|
||||
bool removeEdgeInternal(Node &ChildN);
|
||||
|
||||
/// Internal helper to replace an edge key with a new one.
|
||||
///
|
||||
/// This should be used when the function for a particular node in the
|
||||
/// graph gets replaced and we are updating all of the edges to that node
|
||||
/// to use the new function as the key.
|
||||
void replaceEdgeKey(Function &OldTarget, Function &NewTarget);
|
||||
};
|
||||
|
||||
/// A node in the call graph.
|
||||
///
|
||||
/// This represents a single node. It's primary roles are to cache the list of
|
||||
/// callees, de-duplicate and provide fast testing of whether a function is
|
||||
/// a callee, and facilitate iteration of child nodes in the graph.
|
||||
///
|
||||
/// The node works much like an optional in order to lazily populate the
|
||||
/// edges of each node. Until populated, there are no edges. Once populated,
|
||||
/// you can access the edges by dereferencing the node or using the `->`
|
||||
/// operator as if the node was an `Optional<EdgeSequence>`.
|
||||
class Node {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::SCC;
|
||||
friend class LazyCallGraph::RefSCC;
|
||||
|
||||
public:
|
||||
LazyCallGraph &getGraph() const { return *G; }
|
||||
|
||||
Function &getFunction() const { return *F; }
|
||||
|
||||
StringRef getName() const { return F->getName(); }
|
||||
|
||||
/// Equality is defined as address equality.
|
||||
bool operator==(const Node &N) const { return this == &N; }
|
||||
bool operator!=(const Node &N) const { return !operator==(N); }
|
||||
|
||||
/// Tests whether the node has been populated with edges.
|
||||
operator bool() const { return Edges.hasValue(); }
|
||||
|
||||
// We allow accessing the edges by dereferencing or using the arrow
|
||||
// operator, essentially wrapping the internal optional.
|
||||
EdgeSequence &operator*() const {
|
||||
// Rip const off because the node itself isn't changing here.
|
||||
return const_cast<EdgeSequence &>(*Edges);
|
||||
}
|
||||
EdgeSequence *operator->() const { return &**this; }
|
||||
|
||||
/// Populate the edges of this node if necessary.
|
||||
///
|
||||
/// The first time this is called it will populate the edges for this node
|
||||
/// in the graph. It does this by scanning the underlying function, so once
|
||||
/// this is done, any changes to that function must be explicitly reflected
|
||||
/// in updates to the graph.
|
||||
///
|
||||
/// \returns the populated \c EdgeSequence to simplify walking it.
|
||||
///
|
||||
/// This will not update or re-scan anything if called repeatedly. Instead,
|
||||
/// the edge sequence is cached and returned immediately on subsequent
|
||||
/// calls.
|
||||
EdgeSequence &populate() {
|
||||
if (Edges)
|
||||
return *Edges;
|
||||
|
||||
return populateSlow();
|
||||
}
|
||||
|
||||
private:
|
||||
LazyCallGraph *G;
|
||||
Function &F;
|
||||
Function *F;
|
||||
|
||||
// We provide for the DFS numbering and Tarjan walk lowlink numbers to be
|
||||
// stored directly within the node. These are both '-1' when nodes are part
|
||||
@ -210,145 +367,32 @@ class LazyCallGraph {
|
||||
int DFSNumber;
|
||||
int LowLink;
|
||||
|
||||
mutable EdgeVectorT Edges;
|
||||
DenseMap<Function *, int> EdgeIndexMap;
|
||||
Optional<EdgeSequence> Edges;
|
||||
|
||||
/// Basic constructor implements the scanning of F into Edges and
|
||||
/// EdgeIndexMap.
|
||||
Node(LazyCallGraph &G, Function &F);
|
||||
Node(LazyCallGraph &G, Function &F)
|
||||
: G(&G), F(&F), DFSNumber(0), LowLink(0) {}
|
||||
|
||||
/// Internal helper to insert an edge to a function.
|
||||
void insertEdgeInternal(Function &ChildF, Edge::Kind EK);
|
||||
/// Implementation of the scan when populating.
|
||||
EdgeSequence &populateSlow();
|
||||
|
||||
/// Internal helper to insert an edge to a node.
|
||||
void insertEdgeInternal(Node &ChildN, Edge::Kind EK);
|
||||
/// Internal helper to directly replace the function with a new one.
|
||||
///
|
||||
/// This is used to facilitate tranfsormations which need to replace the
|
||||
/// formal Function object but directly move the body and users from one to
|
||||
/// the other.
|
||||
void replaceFunction(Function &NewF);
|
||||
|
||||
/// Internal helper to change an edge kind.
|
||||
void setEdgeKind(Function &ChildF, Edge::Kind EK);
|
||||
|
||||
/// Internal helper to remove the edge to the given function.
|
||||
void removeEdgeInternal(Function &ChildF);
|
||||
|
||||
void clear() {
|
||||
Edges.clear();
|
||||
EdgeIndexMap.clear();
|
||||
}
|
||||
void clear() { Edges.reset(); }
|
||||
|
||||
/// Print the name of this node's function.
|
||||
friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) {
|
||||
return OS << N.F.getName();
|
||||
return OS << N.F->getName();
|
||||
}
|
||||
|
||||
/// Dump the name of this node's function to stderr.
|
||||
void dump() const;
|
||||
|
||||
public:
|
||||
LazyCallGraph &getGraph() const { return *G; }
|
||||
|
||||
Function &getFunction() const { return F; }
|
||||
|
||||
edge_iterator begin() const {
|
||||
return edge_iterator(Edges.begin(), Edges.end());
|
||||
}
|
||||
edge_iterator end() const { return edge_iterator(Edges.end(), Edges.end()); }
|
||||
|
||||
const Edge &operator[](int i) const { return Edges[i]; }
|
||||
const Edge &operator[](Function &F) const {
|
||||
assert(EdgeIndexMap.find(&F) != EdgeIndexMap.end() && "No such edge!");
|
||||
return Edges[EdgeIndexMap.find(&F)->second];
|
||||
}
|
||||
const Edge &operator[](Node &N) const { return (*this)[N.getFunction()]; }
|
||||
|
||||
const Edge *lookup(Function &F) const {
|
||||
auto EI = EdgeIndexMap.find(&F);
|
||||
return EI != EdgeIndexMap.end() ? &Edges[EI->second] : nullptr;
|
||||
}
|
||||
|
||||
call_edge_iterator call_begin() const {
|
||||
return call_edge_iterator(Edges.begin(), Edges.end());
|
||||
}
|
||||
call_edge_iterator call_end() const {
|
||||
return call_edge_iterator(Edges.end(), Edges.end());
|
||||
}
|
||||
|
||||
iterator_range<call_edge_iterator> calls() const {
|
||||
return make_range(call_begin(), call_end());
|
||||
}
|
||||
|
||||
/// Equality is defined as address equality.
|
||||
bool operator==(const Node &N) const { return this == &N; }
|
||||
bool operator!=(const Node &N) const { return !operator==(N); }
|
||||
};
|
||||
|
||||
/// A lazy iterator used for both the entry nodes and child nodes.
|
||||
///
|
||||
/// When this iterator is dereferenced, if not yet available, a function will
|
||||
/// be scanned for "calls" or uses of functions and its child information
|
||||
/// will be constructed. All of these results are accumulated and cached in
|
||||
/// the graph.
|
||||
class edge_iterator
|
||||
: public iterator_adaptor_base<edge_iterator, EdgeVectorImplT::iterator,
|
||||
std::forward_iterator_tag> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
EdgeVectorImplT::iterator E;
|
||||
|
||||
// Build the iterator for a specific position in the edge list.
|
||||
edge_iterator(EdgeVectorImplT::iterator BaseI,
|
||||
EdgeVectorImplT::iterator E)
|
||||
: iterator_adaptor_base(BaseI), E(E) {
|
||||
while (I != E && !*I)
|
||||
++I;
|
||||
}
|
||||
|
||||
public:
|
||||
edge_iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
edge_iterator &operator++() {
|
||||
do {
|
||||
++I;
|
||||
} while (I != E && !*I);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// A lazy iterator over specifically call edges.
|
||||
///
|
||||
/// This has the same iteration properties as the \c edge_iterator, but
|
||||
/// restricts itself to edges which represent actual calls.
|
||||
class call_edge_iterator
|
||||
: public iterator_adaptor_base<call_edge_iterator,
|
||||
EdgeVectorImplT::iterator,
|
||||
std::forward_iterator_tag> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
EdgeVectorImplT::iterator E;
|
||||
|
||||
/// Advance the iterator to the next valid, call edge.
|
||||
void advanceToNextEdge() {
|
||||
while (I != E && (!*I || !I->isCall()))
|
||||
++I;
|
||||
}
|
||||
|
||||
// Build the iterator for a specific position in the edge list.
|
||||
call_edge_iterator(EdgeVectorImplT::iterator BaseI,
|
||||
EdgeVectorImplT::iterator E)
|
||||
: iterator_adaptor_base(BaseI), E(E) {
|
||||
advanceToNextEdge();
|
||||
}
|
||||
|
||||
public:
|
||||
call_edge_iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
call_edge_iterator &operator++() {
|
||||
++I;
|
||||
advanceToNextEdge();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// An SCC of the call graph.
|
||||
@ -789,19 +833,26 @@ class LazyCallGraph {
|
||||
/// already existing edges.
|
||||
void insertTrivialRefEdge(Node &SourceN, Node &TargetN);
|
||||
|
||||
/// Directly replace a node's function with a new function.
|
||||
///
|
||||
/// This should be used when moving the body and users of a function to
|
||||
/// a new formal function object but not otherwise changing the call graph
|
||||
/// structure in any way.
|
||||
///
|
||||
/// It requires that the old function in the provided node have zero uses
|
||||
/// and the new function must have calls and references to it establishing
|
||||
/// an equivalent graph.
|
||||
void replaceNodeFunction(Node &N, Function &NewF);
|
||||
|
||||
///@}
|
||||
};
|
||||
|
||||
/// A post-order depth-first RefSCC iterator over the call graph.
|
||||
///
|
||||
/// This iterator triggers the Tarjan DFS-based formation of the RefSCC (and
|
||||
/// SCC) DAG for the call graph, walking it lazily in depth-first post-order.
|
||||
/// That is, it always visits RefSCCs for the target of a reference edge
|
||||
/// prior to visiting the RefSCC for a source of the edge (when they are in
|
||||
/// different RefSCCs).
|
||||
///
|
||||
/// When forming each RefSCC, the call edges within it are used to form SCCs
|
||||
/// within it, so iterating this also controls the lazy formation of SCCs.
|
||||
/// This iterator walks the cached post-order sequence of RefSCCs. However,
|
||||
/// it trades stability for flexibility. It is restricted to a forward
|
||||
/// iterator but will survive mutations which insert new RefSCCs and continue
|
||||
/// to point to the same RefSCC even if it moves in the post-order sequence.
|
||||
class postorder_ref_scc_iterator
|
||||
: public iterator_facade_base<postorder_ref_scc_iterator,
|
||||
std::forward_iterator_tag, RefSCC> {
|
||||
@ -825,12 +876,9 @@ class LazyCallGraph {
|
||||
/// populating it if necessary.
|
||||
static RefSCC *getRC(LazyCallGraph &G, int Index) {
|
||||
if (Index == (int)G.PostOrderRefSCCs.size())
|
||||
if (!G.buildNextRefSCCInPostOrder())
|
||||
// We're at the end.
|
||||
return nullptr;
|
||||
// We're at the end.
|
||||
return nullptr;
|
||||
|
||||
assert(Index < (int)G.PostOrderRefSCCs.size() &&
|
||||
"Built the next post-order RefSCC without growing list!");
|
||||
return G.PostOrderRefSCCs[Index];
|
||||
}
|
||||
|
||||
@ -859,17 +907,21 @@ class LazyCallGraph {
|
||||
LazyCallGraph(LazyCallGraph &&G);
|
||||
LazyCallGraph &operator=(LazyCallGraph &&RHS);
|
||||
|
||||
edge_iterator begin() {
|
||||
return edge_iterator(EntryEdges.begin(), EntryEdges.end());
|
||||
}
|
||||
edge_iterator end() {
|
||||
return edge_iterator(EntryEdges.end(), EntryEdges.end());
|
||||
}
|
||||
EdgeSequence::iterator begin() { return EntryEdges.begin(); }
|
||||
EdgeSequence::iterator end() { return EntryEdges.end(); }
|
||||
|
||||
void buildRefSCCs();
|
||||
|
||||
postorder_ref_scc_iterator postorder_ref_scc_begin() {
|
||||
if (!EntryEdges.empty())
|
||||
assert(!PostOrderRefSCCs.empty() &&
|
||||
"Must form RefSCCs before iterating them!");
|
||||
return postorder_ref_scc_iterator(*this);
|
||||
}
|
||||
postorder_ref_scc_iterator postorder_ref_scc_end() {
|
||||
if (!EntryEdges.empty())
|
||||
assert(!PostOrderRefSCCs.empty() &&
|
||||
"Must form RefSCCs before iterating them!");
|
||||
return postorder_ref_scc_iterator(*this,
|
||||
postorder_ref_scc_iterator::IsAtEndT());
|
||||
}
|
||||
@ -920,19 +972,19 @@ class LazyCallGraph {
|
||||
/// below.
|
||||
|
||||
/// Update the call graph after inserting a new edge.
|
||||
void insertEdge(Node &Caller, Function &Callee, Edge::Kind EK);
|
||||
void insertEdge(Node &SourceN, Node &TargetN, Edge::Kind EK);
|
||||
|
||||
/// Update the call graph after inserting a new edge.
|
||||
void insertEdge(Function &Caller, Function &Callee, Edge::Kind EK) {
|
||||
return insertEdge(get(Caller), Callee, EK);
|
||||
void insertEdge(Function &Source, Function &Target, Edge::Kind EK) {
|
||||
return insertEdge(get(Source), get(Target), EK);
|
||||
}
|
||||
|
||||
/// Update the call graph after deleting an edge.
|
||||
void removeEdge(Node &Caller, Function &Callee);
|
||||
void removeEdge(Node &SourceN, Node &TargetN);
|
||||
|
||||
/// Update the call graph after deleting an edge.
|
||||
void removeEdge(Function &Caller, Function &Callee) {
|
||||
return removeEdge(get(Caller), Callee);
|
||||
void removeEdge(Function &Source, Function &Target) {
|
||||
return removeEdge(get(Source), get(Target));
|
||||
}
|
||||
|
||||
///@}
|
||||
@ -1013,14 +1065,11 @@ class LazyCallGraph {
|
||||
/// Maps function->node for fast lookup.
|
||||
DenseMap<const Function *, Node *> NodeMap;
|
||||
|
||||
/// The entry nodes to the graph.
|
||||
/// The entry edges into the graph.
|
||||
///
|
||||
/// These nodes are reachable through "external" means. Put another way, they
|
||||
/// These edges are from "external" sources. Put another way, they
|
||||
/// escape at the module scope.
|
||||
EdgeVectorT EntryEdges;
|
||||
|
||||
/// Map of the entry nodes in the graph to their indices in \c EntryEdges.
|
||||
DenseMap<Function *, int> EntryIndexMap;
|
||||
EdgeSequence EntryEdges;
|
||||
|
||||
/// Allocator that holds all the call graph SCCs.
|
||||
SpecificBumpPtrAllocator<SCC> SCCBPA;
|
||||
@ -1045,18 +1094,6 @@ class LazyCallGraph {
|
||||
/// These are all of the RefSCCs which have no children.
|
||||
SmallVector<RefSCC *, 4> LeafRefSCCs;
|
||||
|
||||
/// Stack of nodes in the DFS walk.
|
||||
SmallVector<std::pair<Node *, edge_iterator>, 4> DFSStack;
|
||||
|
||||
/// Set of entry nodes not-yet-processed into RefSCCs.
|
||||
SmallVector<Function *, 4> RefSCCEntryNodes;
|
||||
|
||||
/// Stack of nodes the DFS has walked but not yet put into a RefSCC.
|
||||
SmallVector<Node *, 4> PendingRefSCCStack;
|
||||
|
||||
/// Counter for the next DFS number to assign.
|
||||
int NextDFSNumber;
|
||||
|
||||
/// Helper to insert a new function, with an already looked-up entry in
|
||||
/// the NodeMap.
|
||||
Node &insertInto(Function &F, Node *&MappedN);
|
||||
@ -1078,6 +1115,23 @@ class LazyCallGraph {
|
||||
return new (RefSCCBPA.Allocate()) RefSCC(std::forward<Ts>(Args)...);
|
||||
}
|
||||
|
||||
/// Common logic for building SCCs from a sequence of roots.
|
||||
///
|
||||
/// This is a very generic implementation of the depth-first walk and SCC
|
||||
/// formation algorithm. It uses a generic sequence of roots and generic
|
||||
/// callbacks for each step. This is designed to be used to implement both
|
||||
/// the RefSCC formation and SCC formation with shared logic.
|
||||
///
|
||||
/// Currently this is a relatively naive implementation of Tarjan's DFS
|
||||
/// algorithm to form the SCCs.
|
||||
///
|
||||
/// FIXME: We should consider newer variants such as Nuutila.
|
||||
template <typename RootsT, typename GetBeginT, typename GetEndT,
|
||||
typename GetNodeT, typename FormSCCCallbackT>
|
||||
static void buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,
|
||||
GetEndT &&GetEnd, GetNodeT &&GetNode,
|
||||
FormSCCCallbackT &&FormSCC);
|
||||
|
||||
/// Build the SCCs for a RefSCC out of a list of nodes.
|
||||
void buildSCCs(RefSCC &RC, node_stack_range Nodes);
|
||||
|
||||
@ -1098,22 +1152,12 @@ class LazyCallGraph {
|
||||
"Index does not point back at RC!");
|
||||
return IndexIt->second;
|
||||
}
|
||||
|
||||
/// Builds the next node in the post-order RefSCC walk of the call graph and
|
||||
/// appends it to the \c PostOrderRefSCCs vector.
|
||||
///
|
||||
/// Returns true if a new RefSCC was successfully constructed, and false if
|
||||
/// there are no more RefSCCs to build in the graph.
|
||||
bool buildNextRefSCCInPostOrder();
|
||||
};
|
||||
|
||||
inline LazyCallGraph::Edge::Edge() : Value() {}
|
||||
inline LazyCallGraph::Edge::Edge(Function &F, Kind K) : Value(&F, K) {}
|
||||
inline LazyCallGraph::Edge::Edge(Node &N, Kind K) : Value(&N, K) {}
|
||||
|
||||
inline LazyCallGraph::Edge::operator bool() const {
|
||||
return !Value.getPointer().isNull();
|
||||
}
|
||||
inline LazyCallGraph::Edge::operator bool() const { return Value.getPointer(); }
|
||||
|
||||
inline LazyCallGraph::Edge::Kind LazyCallGraph::Edge::getKind() const {
|
||||
assert(*this && "Queried a null edge!");
|
||||
@ -1125,51 +1169,32 @@ inline bool LazyCallGraph::Edge::isCall() const {
|
||||
return getKind() == Call;
|
||||
}
|
||||
|
||||
inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode() const {
|
||||
assert(*this && "Queried a null edge!");
|
||||
return *Value.getPointer();
|
||||
}
|
||||
|
||||
inline Function &LazyCallGraph::Edge::getFunction() const {
|
||||
assert(*this && "Queried a null edge!");
|
||||
auto P = Value.getPointer();
|
||||
if (auto *F = P.dyn_cast<Function *>())
|
||||
return *F;
|
||||
|
||||
return P.get<Node *>()->getFunction();
|
||||
}
|
||||
|
||||
inline LazyCallGraph::Node *LazyCallGraph::Edge::getNode() const {
|
||||
assert(*this && "Queried a null edge!");
|
||||
auto P = Value.getPointer();
|
||||
if (auto *N = P.dyn_cast<Node *>())
|
||||
return N;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode(LazyCallGraph &G) {
|
||||
assert(*this && "Queried a null edge!");
|
||||
auto P = Value.getPointer();
|
||||
if (auto *N = P.dyn_cast<Node *>())
|
||||
return *N;
|
||||
|
||||
Node &N = G.get(*P.get<Function *>());
|
||||
Value.setPointer(&N);
|
||||
return N;
|
||||
return getNode().getFunction();
|
||||
}
|
||||
|
||||
// Provide GraphTraits specializations for call graphs.
|
||||
template <> struct GraphTraits<LazyCallGraph::Node *> {
|
||||
typedef LazyCallGraph::Node *NodeRef;
|
||||
typedef LazyCallGraph::edge_iterator ChildIteratorType;
|
||||
typedef LazyCallGraph::EdgeSequence::iterator ChildIteratorType;
|
||||
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return (*N)->begin(); }
|
||||
static ChildIteratorType child_end(NodeRef N) { return (*N)->end(); }
|
||||
};
|
||||
template <> struct GraphTraits<LazyCallGraph *> {
|
||||
typedef LazyCallGraph::Node *NodeRef;
|
||||
typedef LazyCallGraph::edge_iterator ChildIteratorType;
|
||||
typedef LazyCallGraph::EdgeSequence::iterator ChildIteratorType;
|
||||
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
|
||||
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
|
||||
static ChildIteratorType child_begin(NodeRef N) { return (*N)->begin(); }
|
||||
static ChildIteratorType child_end(NodeRef N) { return (*N)->end(); }
|
||||
};
|
||||
|
||||
/// An analysis pass which computes the call graph for a module.
|
||||
|
@ -32,6 +32,7 @@ namespace llvm {
|
||||
class LazyValueInfo {
|
||||
friend class LazyValueInfoWrapperPass;
|
||||
AssumptionCache *AC = nullptr;
|
||||
const DataLayout *DL = nullptr;
|
||||
class TargetLibraryInfo *TLI = nullptr;
|
||||
DominatorTree *DT = nullptr;
|
||||
void *PImpl = nullptr;
|
||||
@ -40,16 +41,17 @@ class LazyValueInfo {
|
||||
public:
|
||||
~LazyValueInfo();
|
||||
LazyValueInfo() {}
|
||||
LazyValueInfo(AssumptionCache *AC_, TargetLibraryInfo *TLI_,
|
||||
LazyValueInfo(AssumptionCache *AC_, const DataLayout *DL_, TargetLibraryInfo *TLI_,
|
||||
DominatorTree *DT_)
|
||||
: AC(AC_), TLI(TLI_), DT(DT_) {}
|
||||
: AC(AC_), DL(DL_), TLI(TLI_), DT(DT_) {}
|
||||
LazyValueInfo(LazyValueInfo &&Arg)
|
||||
: AC(Arg.AC), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) {
|
||||
: AC(Arg.AC), DL(Arg.DL), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) {
|
||||
Arg.PImpl = nullptr;
|
||||
}
|
||||
LazyValueInfo &operator=(LazyValueInfo &&Arg) {
|
||||
releaseMemory();
|
||||
AC = Arg.AC;
|
||||
DL = Arg.DL;
|
||||
TLI = Arg.TLI;
|
||||
DT = Arg.DT;
|
||||
PImpl = Arg.PImpl;
|
||||
@ -98,8 +100,15 @@ class LazyValueInfo {
|
||||
/// Inform the analysis cache that we have erased a block.
|
||||
void eraseBlock(BasicBlock *BB);
|
||||
|
||||
/// Print the \LazyValueInfoCache.
|
||||
void printCache(Function &F, raw_ostream &OS);
|
||||
|
||||
// For old PM pass. Delete once LazyValueInfoWrapperPass is gone.
|
||||
void releaseMemory();
|
||||
|
||||
/// Handle invalidation events in the new pass manager.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &Inv);
|
||||
};
|
||||
|
||||
/// \brief Analysis to compute lazy value information.
|
||||
|
@ -85,8 +85,37 @@ Value *FindAvailableLoadedValue(LoadInst *Load,
|
||||
BasicBlock::iterator &ScanFrom,
|
||||
unsigned MaxInstsToScan = DefMaxInstsToScan,
|
||||
AliasAnalysis *AA = nullptr,
|
||||
bool *IsLoadCSE = nullptr);
|
||||
bool *IsLoadCSE = nullptr,
|
||||
unsigned *NumScanedInst = nullptr);
|
||||
|
||||
/// Scan backwards to see if we have the value of the given pointer available
|
||||
/// locally within a small number of instructions.
|
||||
///
|
||||
/// You can use this function to scan across multiple blocks: after you call
|
||||
/// this function, if ScanFrom points at the beginning of the block, it's safe
|
||||
/// to continue scanning the predecessors.
|
||||
///
|
||||
/// \param Ptr The pointer we want the load and store to originate from.
|
||||
/// \param AccessTy The access type of the pointer.
|
||||
/// \param AtLeastAtomic Are we looking for at-least an atomic load/store ? In
|
||||
/// case it is false, we can return an atomic or non-atomic load or store. In
|
||||
/// case it is true, we need to return an atomic load or store.
|
||||
/// \param ScanBB The basic block to scan.
|
||||
/// \param [in,out] ScanFrom The location to start scanning from. When this
|
||||
/// function returns, it points at the last instruction scanned.
|
||||
/// \param MaxInstsToScan The maximum number of instructions to scan. If this
|
||||
/// is zero, the whole block will be scanned.
|
||||
/// \param AA Optional pointer to alias analysis, to make the scan more
|
||||
/// precise.
|
||||
/// \param [out] IsLoad Whether the returned value is a load from the same
|
||||
/// location in memory, as opposed to the value operand of a store.
|
||||
///
|
||||
/// \returns The found value, or nullptr if no value is found.
|
||||
Value *FindAvailablePtrLoadStore(Value *Ptr, Type *AccessTy, bool AtLeastAtomic,
|
||||
BasicBlock *ScanBB,
|
||||
BasicBlock::iterator &ScanFrom,
|
||||
unsigned MaxInstsToScan, AliasAnalysis *AA,
|
||||
bool *IsLoad, unsigned *NumScanedInst);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -38,39 +38,6 @@ class SCEVUnionPredicate;
|
||||
class LoopAccessInfo;
|
||||
class OptimizationRemarkEmitter;
|
||||
|
||||
/// Optimization analysis message produced during vectorization. Messages inform
|
||||
/// the user why vectorization did not occur.
|
||||
class LoopAccessReport {
|
||||
std::string Message;
|
||||
const Instruction *Instr;
|
||||
|
||||
protected:
|
||||
LoopAccessReport(const Twine &Message, const Instruction *I)
|
||||
: Message(Message.str()), Instr(I) {}
|
||||
|
||||
public:
|
||||
LoopAccessReport(const Instruction *I = nullptr) : Instr(I) {}
|
||||
|
||||
template <typename A> LoopAccessReport &operator<<(const A &Value) {
|
||||
raw_string_ostream Out(Message);
|
||||
Out << Value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Instruction *getInstr() const { return Instr; }
|
||||
|
||||
std::string &str() { return Message; }
|
||||
const std::string &str() const { return Message; }
|
||||
operator Twine() { return Message; }
|
||||
|
||||
/// \brief Emit an analysis note for \p PassName with the debug location from
|
||||
/// the instruction in \p Message if available. Otherwise use the location of
|
||||
/// \p TheLoop.
|
||||
static void emitAnalysis(const LoopAccessReport &Message, const Loop *TheLoop,
|
||||
const char *PassName,
|
||||
OptimizationRemarkEmitter &ORE);
|
||||
};
|
||||
|
||||
/// \brief Collection of parameters shared beetween the Loop Vectorizer and the
|
||||
/// Loop Access Analysis.
|
||||
struct VectorizerParams {
|
||||
@ -126,7 +93,7 @@ struct VectorizerParams {
|
||||
class MemoryDepChecker {
|
||||
public:
|
||||
typedef PointerIntPair<Value *, 1, bool> MemAccessInfo;
|
||||
typedef SmallPtrSet<MemAccessInfo, 8> MemAccessInfoSet;
|
||||
typedef SmallVector<MemAccessInfo, 8> MemAccessInfoList;
|
||||
/// \brief Set of potential dependent memory accesses.
|
||||
typedef EquivalenceClasses<MemAccessInfo> DepCandidates;
|
||||
|
||||
@ -221,7 +188,7 @@ class MemoryDepChecker {
|
||||
/// \brief Check whether the dependencies between the accesses are safe.
|
||||
///
|
||||
/// Only checks sets with elements in \p CheckDeps.
|
||||
bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoSet &CheckDeps,
|
||||
bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoList &CheckDeps,
|
||||
const ValueToValueMap &Strides);
|
||||
|
||||
/// \brief No memory dependence was encountered that would inhibit
|
||||
|
@ -26,7 +26,7 @@
|
||||
// * etc...
|
||||
//
|
||||
// Note that this analysis specifically identifies *Loops* not cycles or SCCs
|
||||
// in the CFG. There can be strongly connected compontents in the CFG which
|
||||
// in the CFG. There can be strongly connected components in the CFG which
|
||||
// this analysis will not recognize and that will not be represented by a Loop
|
||||
// instance. In particular, a Loop might be inside such a non-loop SCC, or a
|
||||
// non-loop SCC might contain a sub-SCC which is a Loop.
|
||||
@ -364,7 +364,7 @@ extern template class LoopBase<BasicBlock, Loop>;
|
||||
|
||||
|
||||
/// Represents a single loop in the control flow graph. Note that not all SCCs
|
||||
/// in the CFG are neccessarily loops.
|
||||
/// in the CFG are necessarily loops.
|
||||
class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
public:
|
||||
/// \brief A range representing the start and end location of a loop.
|
||||
@ -469,7 +469,7 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
/// the loop that branches to the loop header.
|
||||
///
|
||||
/// The LoopID metadata node should have one or more operands and the first
|
||||
/// operand should should be the node itself.
|
||||
/// operand should be the node itself.
|
||||
void setLoopID(MDNode *LoopID) const;
|
||||
|
||||
/// Return true if no exit block for the loop has a predecessor that is
|
||||
@ -478,7 +478,8 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
|
||||
/// Return all unique successor blocks of this loop.
|
||||
/// These are the blocks _outside of the current loop_ which are branched to.
|
||||
/// This assumes that loop exits are in canonical form.
|
||||
/// This assumes that loop exits are in canonical form, i.e. all exits are
|
||||
/// dedicated exits.
|
||||
void getUniqueExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const;
|
||||
|
||||
/// If getUniqueExitBlocks would return exactly one block, return that block.
|
||||
@ -570,6 +571,23 @@ class LoopInfoBase {
|
||||
reverse_iterator rend() const { return TopLevelLoops.rend(); }
|
||||
bool empty() const { return TopLevelLoops.empty(); }
|
||||
|
||||
/// Return all of the loops in the function in preorder across the loop
|
||||
/// nests, with siblings in forward program order.
|
||||
///
|
||||
/// Note that because loops form a forest of trees, preorder is equivalent to
|
||||
/// reverse postorder.
|
||||
SmallVector<LoopT *, 4> getLoopsInPreorder();
|
||||
|
||||
/// Return all of the loops in the function in preorder across the loop
|
||||
/// nests, with siblings in *reverse* program order.
|
||||
///
|
||||
/// Note that because loops form a forest of trees, preorder is equivalent to
|
||||
/// reverse postorder.
|
||||
///
|
||||
/// Also note that this is *not* a reverse preorder. Only the siblings are in
|
||||
/// reverse program order.
|
||||
SmallVector<LoopT *, 4> getLoopsInReverseSiblingPreorder();
|
||||
|
||||
/// Return the inner most loop that BB lives in. If a basic block is in no
|
||||
/// loop (for example the entry node), null is returned.
|
||||
LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); }
|
||||
@ -682,6 +700,10 @@ class LoopInfo : public LoopInfoBase<BasicBlock, Loop> {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Handle invalidation explicitly.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &);
|
||||
|
||||
// Most of the public interface is provided via LoopInfoBase.
|
||||
|
||||
/// Update LoopInfo after removing the last backedge from a loop. This updates
|
||||
|
@ -507,6 +507,55 @@ analyze(const DominatorTreeBase<BlockT> &DomTree) {
|
||||
DFS.traverse(DomRoot->getBlock());
|
||||
}
|
||||
|
||||
template <class BlockT, class LoopT>
|
||||
SmallVector<LoopT *, 4> LoopInfoBase<BlockT, LoopT>::getLoopsInPreorder() {
|
||||
SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist;
|
||||
// The outer-most loop actually goes into the result in the same relative
|
||||
// order as we walk it. But LoopInfo stores the top level loops in reverse
|
||||
// program order so for here we reverse it to get forward program order.
|
||||
// FIXME: If we change the order of LoopInfo we will want to remove the
|
||||
// reverse here.
|
||||
for (LoopT *RootL : reverse(*this)) {
|
||||
assert(PreOrderWorklist.empty() &&
|
||||
"Must start with an empty preorder walk worklist.");
|
||||
PreOrderWorklist.push_back(RootL);
|
||||
do {
|
||||
LoopT *L = PreOrderWorklist.pop_back_val();
|
||||
// Sub-loops are stored in forward program order, but will process the
|
||||
// worklist backwards so append them in reverse order.
|
||||
PreOrderWorklist.append(L->rbegin(), L->rend());
|
||||
PreOrderLoops.push_back(L);
|
||||
} while (!PreOrderWorklist.empty());
|
||||
}
|
||||
|
||||
return PreOrderLoops;
|
||||
}
|
||||
|
||||
template <class BlockT, class LoopT>
|
||||
SmallVector<LoopT *, 4>
|
||||
LoopInfoBase<BlockT, LoopT>::getLoopsInReverseSiblingPreorder() {
|
||||
SmallVector<LoopT *, 4> PreOrderLoops, PreOrderWorklist;
|
||||
// The outer-most loop actually goes into the result in the same relative
|
||||
// order as we walk it. LoopInfo stores the top level loops in reverse
|
||||
// program order so we walk in order here.
|
||||
// FIXME: If we change the order of LoopInfo we will want to add a reverse
|
||||
// here.
|
||||
for (LoopT *RootL : *this) {
|
||||
assert(PreOrderWorklist.empty() &&
|
||||
"Must start with an empty preorder walk worklist.");
|
||||
PreOrderWorklist.push_back(RootL);
|
||||
do {
|
||||
LoopT *L = PreOrderWorklist.pop_back_val();
|
||||
// Sub-loops are stored in forward program order, but will process the
|
||||
// worklist backwards so we can just append them in order.
|
||||
PreOrderWorklist.append(L->begin(), L->end());
|
||||
PreOrderLoops.push_back(L);
|
||||
} while (!PreOrderWorklist.empty());
|
||||
}
|
||||
|
||||
return PreOrderLoops;
|
||||
}
|
||||
|
||||
// Debugging
|
||||
template<class BlockT, class LoopT>
|
||||
void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
|
||||
@ -528,15 +577,48 @@ bool compareVectors(std::vector<T> &BB1, std::vector<T> &BB2) {
|
||||
}
|
||||
|
||||
template <class BlockT, class LoopT>
|
||||
static void
|
||||
addInnerLoopsToHeadersMap(DenseMap<BlockT *, const LoopT *> &LoopHeaders,
|
||||
const LoopInfoBase<BlockT, LoopT> &LI,
|
||||
const LoopT &L) {
|
||||
void addInnerLoopsToHeadersMap(DenseMap<BlockT *, const LoopT *> &LoopHeaders,
|
||||
const LoopInfoBase<BlockT, LoopT> &LI,
|
||||
const LoopT &L) {
|
||||
LoopHeaders[L.getHeader()] = &L;
|
||||
for (LoopT *SL : L)
|
||||
addInnerLoopsToHeadersMap(LoopHeaders, LI, *SL);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template <class BlockT, class LoopT>
|
||||
static void compareLoops(const LoopT *L, const LoopT *OtherL,
|
||||
DenseMap<BlockT *, const LoopT *> &OtherLoopHeaders) {
|
||||
BlockT *H = L->getHeader();
|
||||
BlockT *OtherH = OtherL->getHeader();
|
||||
assert(H == OtherH &&
|
||||
"Mismatched headers even though found in the same map entry!");
|
||||
|
||||
assert(L->getLoopDepth() == OtherL->getLoopDepth() &&
|
||||
"Mismatched loop depth!");
|
||||
const LoopT *ParentL = L, *OtherParentL = OtherL;
|
||||
do {
|
||||
assert(ParentL->getHeader() == OtherParentL->getHeader() &&
|
||||
"Mismatched parent loop headers!");
|
||||
ParentL = ParentL->getParentLoop();
|
||||
OtherParentL = OtherParentL->getParentLoop();
|
||||
} while (ParentL);
|
||||
|
||||
for (const LoopT *SubL : *L) {
|
||||
BlockT *SubH = SubL->getHeader();
|
||||
const LoopT *OtherSubL = OtherLoopHeaders.lookup(SubH);
|
||||
assert(OtherSubL && "Inner loop is missing in computed loop info!");
|
||||
OtherLoopHeaders.erase(SubH);
|
||||
compareLoops(SubL, OtherSubL, OtherLoopHeaders);
|
||||
}
|
||||
|
||||
std::vector<BlockT *> BBs = L->getBlocks();
|
||||
std::vector<BlockT *> OtherBBs = OtherL->getBlocks();
|
||||
assert(compareVectors(BBs, OtherBBs) &&
|
||||
"Mismatched basic blocks in the loops!");
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class BlockT, class LoopT>
|
||||
void LoopInfoBase<BlockT, LoopT>::verify(
|
||||
const DominatorTreeBase<BlockT> &DomTree) const {
|
||||
@ -559,42 +641,32 @@ void LoopInfoBase<BlockT, LoopT>::verify(
|
||||
LoopInfoBase<BlockT, LoopT> OtherLI;
|
||||
OtherLI.analyze(DomTree);
|
||||
|
||||
DenseMap<BlockT *, const LoopT *> LoopHeaders1;
|
||||
DenseMap<BlockT *, const LoopT *> LoopHeaders2;
|
||||
|
||||
for (LoopT *L : *this)
|
||||
addInnerLoopsToHeadersMap(LoopHeaders1, *this, *L);
|
||||
// Build a map we can use to move from our LI to the computed one. This
|
||||
// allows us to ignore the particular order in any layer of the loop forest
|
||||
// while still comparing the structure.
|
||||
DenseMap<BlockT *, const LoopT *> OtherLoopHeaders;
|
||||
for (LoopT *L : OtherLI)
|
||||
addInnerLoopsToHeadersMap(LoopHeaders2, OtherLI, *L);
|
||||
assert(LoopHeaders1.size() == LoopHeaders2.size() &&
|
||||
"LoopInfo is incorrect.");
|
||||
addInnerLoopsToHeadersMap(OtherLoopHeaders, OtherLI, *L);
|
||||
|
||||
auto compareLoops = [&](const LoopT *L1, const LoopT *L2) {
|
||||
BlockT *H1 = L1->getHeader();
|
||||
BlockT *H2 = L2->getHeader();
|
||||
if (H1 != H2)
|
||||
return false;
|
||||
std::vector<BlockT *> BB1 = L1->getBlocks();
|
||||
std::vector<BlockT *> BB2 = L2->getBlocks();
|
||||
if (!compareVectors(BB1, BB2))
|
||||
return false;
|
||||
// Walk the top level loops and ensure there is a corresponding top-level
|
||||
// loop in the computed version and then recursively compare those loop
|
||||
// nests.
|
||||
for (LoopT *L : *this) {
|
||||
BlockT *Header = L->getHeader();
|
||||
const LoopT *OtherL = OtherLoopHeaders.lookup(Header);
|
||||
assert(OtherL && "Top level loop is missing in computed loop info!");
|
||||
// Now that we've matched this loop, erase its header from the map.
|
||||
OtherLoopHeaders.erase(Header);
|
||||
// And recursively compare these loops.
|
||||
compareLoops(L, OtherL, OtherLoopHeaders);
|
||||
}
|
||||
|
||||
std::vector<BlockT *> SubLoopHeaders1;
|
||||
std::vector<BlockT *> SubLoopHeaders2;
|
||||
for (LoopT *L : *L1)
|
||||
SubLoopHeaders1.push_back(L->getHeader());
|
||||
for (LoopT *L : *L2)
|
||||
SubLoopHeaders2.push_back(L->getHeader());
|
||||
|
||||
if (!compareVectors(SubLoopHeaders1, SubLoopHeaders2))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
for (auto &I : LoopHeaders1) {
|
||||
BlockT *H = I.first;
|
||||
bool LoopsMatch = compareLoops(LoopHeaders1[H], LoopHeaders2[H]);
|
||||
assert(LoopsMatch && "LoopInfo is incorrect.");
|
||||
// Any remaining entries in the map are loops which were found when computing
|
||||
// a fresh LoopInfo but not present in the current one.
|
||||
if (!OtherLoopHeaders.empty()) {
|
||||
for (const auto &HeaderAndLoop : OtherLoopHeaders)
|
||||
dbgs() << "Found new loop: " << *HeaderAndLoop.second << "\n";
|
||||
llvm_unreachable("Found new loops when recomputing LoopInfo!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -32,12 +32,6 @@ class TargetLibraryInfo;
|
||||
class Type;
|
||||
class Value;
|
||||
|
||||
enum class ObjSizeMode {
|
||||
Exact = 0,
|
||||
Min = 1,
|
||||
Max = 2
|
||||
};
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates or reallocates memory (either malloc, calloc, realloc, or strdup
|
||||
/// like).
|
||||
@ -129,17 +123,36 @@ static inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
|
||||
// Utility functions to compute size of objects.
|
||||
//
|
||||
|
||||
/// Various options to control the behavior of getObjectSize.
|
||||
struct ObjectSizeOpts {
|
||||
/// Controls how we handle conditional statements with unknown conditions.
|
||||
enum class Mode : uint8_t {
|
||||
/// Fail to evaluate an unknown condition.
|
||||
Exact,
|
||||
/// Evaluate all branches of an unknown condition. If all evaluations
|
||||
/// succeed, pick the minimum size.
|
||||
Min,
|
||||
/// Same as Min, except we pick the maximum size of all of the branches.
|
||||
Max
|
||||
};
|
||||
|
||||
/// How we want to evaluate this object's size.
|
||||
Mode EvalMode = Mode::Exact;
|
||||
/// Whether to round the result up to the alignment of allocas, byval
|
||||
/// arguments, and global variables.
|
||||
bool RoundToAlign = false;
|
||||
/// If this is true, null pointers in address space 0 will be treated as
|
||||
/// though they can't be evaluated. Otherwise, null is always considered to
|
||||
/// point to a 0 byte region of memory.
|
||||
bool NullIsUnknownSize = false;
|
||||
};
|
||||
|
||||
/// \brief Compute the size of the object pointed by Ptr. Returns true and the
|
||||
/// object size in Size if successful, and false otherwise. In this context, by
|
||||
/// object we mean the region of memory starting at Ptr to the end of the
|
||||
/// underlying object pointed to by Ptr.
|
||||
/// If RoundToAlign is true, then Size is rounded up to the aligment of allocas,
|
||||
/// byval arguments, and global variables.
|
||||
/// If Mode is Min or Max the size will be evaluated even if it depends on
|
||||
/// a condition and corresponding value will be returned (min or max).
|
||||
bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI, bool RoundToAlign = false,
|
||||
ObjSizeMode Mode = ObjSizeMode::Exact);
|
||||
const TargetLibraryInfo *TLI, ObjectSizeOpts Opts = {});
|
||||
|
||||
/// Try to turn a call to @llvm.objectsize into an integer value of the given
|
||||
/// Type. Returns null on failure.
|
||||
@ -160,8 +173,7 @@ class ObjectSizeOffsetVisitor
|
||||
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
bool RoundToAlign;
|
||||
ObjSizeMode Mode;
|
||||
ObjectSizeOpts Options;
|
||||
unsigned IntTyBits;
|
||||
APInt Zero;
|
||||
SmallPtrSet<Instruction *, 8> SeenInsts;
|
||||
@ -174,8 +186,7 @@ class ObjectSizeOffsetVisitor
|
||||
|
||||
public:
|
||||
ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
LLVMContext &Context, bool RoundToAlign = false,
|
||||
ObjSizeMode Mode = ObjSizeMode::Exact);
|
||||
LLVMContext &Context, ObjectSizeOpts Options = {});
|
||||
|
||||
SizeOffsetType compute(Value *V);
|
||||
|
||||
|
@ -6,71 +6,71 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file
|
||||
// \brief This file exposes an interface to building/using memory SSA to
|
||||
// walk memory instructions using a use/def graph.
|
||||
//
|
||||
// Memory SSA class builds an SSA form that links together memory access
|
||||
// instructions such as loads, stores, atomics, and calls. Additionally, it does
|
||||
// a trivial form of "heap versioning" Every time the memory state changes in
|
||||
// the program, we generate a new heap version. It generates MemoryDef/Uses/Phis
|
||||
// that are overlayed on top of the existing instructions.
|
||||
//
|
||||
// As a trivial example,
|
||||
// define i32 @main() #0 {
|
||||
// entry:
|
||||
// %call = call noalias i8* @_Znwm(i64 4) #2
|
||||
// %0 = bitcast i8* %call to i32*
|
||||
// %call1 = call noalias i8* @_Znwm(i64 4) #2
|
||||
// %1 = bitcast i8* %call1 to i32*
|
||||
// store i32 5, i32* %0, align 4
|
||||
// store i32 7, i32* %1, align 4
|
||||
// %2 = load i32* %0, align 4
|
||||
// %3 = load i32* %1, align 4
|
||||
// %add = add nsw i32 %2, %3
|
||||
// ret i32 %add
|
||||
// }
|
||||
//
|
||||
// Will become
|
||||
// define i32 @main() #0 {
|
||||
// entry:
|
||||
// ; 1 = MemoryDef(0)
|
||||
// %call = call noalias i8* @_Znwm(i64 4) #3
|
||||
// %2 = bitcast i8* %call to i32*
|
||||
// ; 2 = MemoryDef(1)
|
||||
// %call1 = call noalias i8* @_Znwm(i64 4) #3
|
||||
// %4 = bitcast i8* %call1 to i32*
|
||||
// ; 3 = MemoryDef(2)
|
||||
// store i32 5, i32* %2, align 4
|
||||
// ; 4 = MemoryDef(3)
|
||||
// store i32 7, i32* %4, align 4
|
||||
// ; MemoryUse(3)
|
||||
// %7 = load i32* %2, align 4
|
||||
// ; MemoryUse(4)
|
||||
// %8 = load i32* %4, align 4
|
||||
// %add = add nsw i32 %7, %8
|
||||
// ret i32 %add
|
||||
// }
|
||||
//
|
||||
// Given this form, all the stores that could ever effect the load at %8 can be
|
||||
// gotten by using the MemoryUse associated with it, and walking from use to def
|
||||
// until you hit the top of the function.
|
||||
//
|
||||
// Each def also has a list of users associated with it, so you can walk from
|
||||
// both def to users, and users to defs. Note that we disambiguate MemoryUses,
|
||||
// but not the RHS of MemoryDefs. You can see this above at %7, which would
|
||||
// otherwise be a MemoryUse(4). Being disambiguated means that for a given
|
||||
// store, all the MemoryUses on its use lists are may-aliases of that store (but
|
||||
// the MemoryDefs on its use list may not be).
|
||||
//
|
||||
// MemoryDefs are not disambiguated because it would require multiple reaching
|
||||
// definitions, which would require multiple phis, and multiple memoryaccesses
|
||||
// per instruction.
|
||||
///
|
||||
/// \file
|
||||
/// \brief This file exposes an interface to building/using memory SSA to
|
||||
/// walk memory instructions using a use/def graph.
|
||||
///
|
||||
/// Memory SSA class builds an SSA form that links together memory access
|
||||
/// instructions such as loads, stores, atomics, and calls. Additionally, it
|
||||
/// does a trivial form of "heap versioning" Every time the memory state changes
|
||||
/// in the program, we generate a new heap version. It generates
|
||||
/// MemoryDef/Uses/Phis that are overlayed on top of the existing instructions.
|
||||
///
|
||||
/// As a trivial example,
|
||||
/// define i32 @main() #0 {
|
||||
/// entry:
|
||||
/// %call = call noalias i8* @_Znwm(i64 4) #2
|
||||
/// %0 = bitcast i8* %call to i32*
|
||||
/// %call1 = call noalias i8* @_Znwm(i64 4) #2
|
||||
/// %1 = bitcast i8* %call1 to i32*
|
||||
/// store i32 5, i32* %0, align 4
|
||||
/// store i32 7, i32* %1, align 4
|
||||
/// %2 = load i32* %0, align 4
|
||||
/// %3 = load i32* %1, align 4
|
||||
/// %add = add nsw i32 %2, %3
|
||||
/// ret i32 %add
|
||||
/// }
|
||||
///
|
||||
/// Will become
|
||||
/// define i32 @main() #0 {
|
||||
/// entry:
|
||||
/// ; 1 = MemoryDef(0)
|
||||
/// %call = call noalias i8* @_Znwm(i64 4) #3
|
||||
/// %2 = bitcast i8* %call to i32*
|
||||
/// ; 2 = MemoryDef(1)
|
||||
/// %call1 = call noalias i8* @_Znwm(i64 4) #3
|
||||
/// %4 = bitcast i8* %call1 to i32*
|
||||
/// ; 3 = MemoryDef(2)
|
||||
/// store i32 5, i32* %2, align 4
|
||||
/// ; 4 = MemoryDef(3)
|
||||
/// store i32 7, i32* %4, align 4
|
||||
/// ; MemoryUse(3)
|
||||
/// %7 = load i32* %2, align 4
|
||||
/// ; MemoryUse(4)
|
||||
/// %8 = load i32* %4, align 4
|
||||
/// %add = add nsw i32 %7, %8
|
||||
/// ret i32 %add
|
||||
/// }
|
||||
///
|
||||
/// Given this form, all the stores that could ever effect the load at %8 can be
|
||||
/// gotten by using the MemoryUse associated with it, and walking from use to
|
||||
/// def until you hit the top of the function.
|
||||
///
|
||||
/// Each def also has a list of users associated with it, so you can walk from
|
||||
/// both def to users, and users to defs. Note that we disambiguate MemoryUses,
|
||||
/// but not the RHS of MemoryDefs. You can see this above at %7, which would
|
||||
/// otherwise be a MemoryUse(4). Being disambiguated means that for a given
|
||||
/// store, all the MemoryUses on its use lists are may-aliases of that store
|
||||
/// (but the MemoryDefs on its use list may not be).
|
||||
///
|
||||
/// MemoryDefs are not disambiguated because it would require multiple reaching
|
||||
/// definitions, which would require multiple phis, and multiple memoryaccesses
|
||||
/// per instruction.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_MEMORYSSA_H
|
||||
#define LLVM_TRANSFORMS_UTILS_MEMORYSSA_H
|
||||
#ifndef LLVM_ANALYSIS_MEMORYSSA_H
|
||||
#define LLVM_ANALYSIS_MEMORYSSA_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
@ -79,6 +79,7 @@
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/ilist_node.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/MemoryLocation.h"
|
||||
#include "llvm/Analysis/PHITransAddr.h"
|
||||
@ -91,9 +92,7 @@
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/PassAnalysisSupport.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@ -104,12 +103,16 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DominatorTree;
|
||||
class Function;
|
||||
class Instruction;
|
||||
class MemoryAccess;
|
||||
class LLVMContext;
|
||||
class raw_ostream;
|
||||
namespace MSSAHelpers {
|
||||
struct AllAccessTag {};
|
||||
struct DefsOnlyTag {};
|
||||
}
|
||||
|
||||
enum {
|
||||
// Used to signify what the default invalid ID is for MemoryAccess's
|
||||
// getID()
|
||||
@ -123,21 +126,30 @@ using const_memoryaccess_def_iterator =
|
||||
|
||||
// \brief The base for all memory accesses. All memory accesses in a block are
|
||||
// linked together using an intrusive list.
|
||||
class MemoryAccess : public User, public ilist_node<MemoryAccess> {
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
void *operator new(size_t) = delete;
|
||||
|
||||
class MemoryAccess
|
||||
: public User,
|
||||
public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>,
|
||||
public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>> {
|
||||
public:
|
||||
using AllAccessType =
|
||||
ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>;
|
||||
using DefsOnlyType =
|
||||
ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>>;
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and
|
||||
// dyn_cast
|
||||
static inline bool classof(const MemoryAccess *) { return true; }
|
||||
static inline bool classof(const Value *V) {
|
||||
unsigned ID = V->getValueID();
|
||||
return ID == MemoryUseVal || ID == MemoryPhiVal || ID == MemoryDefVal;
|
||||
}
|
||||
|
||||
MemoryAccess(const MemoryAccess &) = delete;
|
||||
MemoryAccess &operator=(const MemoryAccess &) = delete;
|
||||
~MemoryAccess() override;
|
||||
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
void *operator new(size_t) = delete;
|
||||
|
||||
BasicBlock *getBlock() const { return Block; }
|
||||
|
||||
virtual void print(raw_ostream &OS) const = 0;
|
||||
@ -155,6 +167,33 @@ class MemoryAccess : public User, public ilist_node<MemoryAccess> {
|
||||
memoryaccess_def_iterator defs_end();
|
||||
const_memoryaccess_def_iterator defs_end() const;
|
||||
|
||||
/// \brief Get the iterators for the all access list and the defs only list
|
||||
/// We default to the all access list.
|
||||
AllAccessType::self_iterator getIterator() {
|
||||
return this->AllAccessType::getIterator();
|
||||
}
|
||||
AllAccessType::const_self_iterator getIterator() const {
|
||||
return this->AllAccessType::getIterator();
|
||||
}
|
||||
AllAccessType::reverse_self_iterator getReverseIterator() {
|
||||
return this->AllAccessType::getReverseIterator();
|
||||
}
|
||||
AllAccessType::const_reverse_self_iterator getReverseIterator() const {
|
||||
return this->AllAccessType::getReverseIterator();
|
||||
}
|
||||
DefsOnlyType::self_iterator getDefsIterator() {
|
||||
return this->DefsOnlyType::getIterator();
|
||||
}
|
||||
DefsOnlyType::const_self_iterator getDefsIterator() const {
|
||||
return this->DefsOnlyType::getIterator();
|
||||
}
|
||||
DefsOnlyType::reverse_self_iterator getReverseDefsIterator() {
|
||||
return this->DefsOnlyType::getReverseIterator();
|
||||
}
|
||||
DefsOnlyType::const_reverse_self_iterator getReverseDefsIterator() const {
|
||||
return this->DefsOnlyType::getReverseIterator();
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class MemorySSA;
|
||||
friend class MemoryUseOrDef;
|
||||
@ -162,6 +201,10 @@ class MemoryAccess : public User, public ilist_node<MemoryAccess> {
|
||||
friend class MemoryDef;
|
||||
friend class MemoryPhi;
|
||||
|
||||
/// \brief Used by MemorySSA to change the block of a MemoryAccess when it is
|
||||
/// moved.
|
||||
void setBlock(BasicBlock *BB) { Block = BB; }
|
||||
|
||||
/// \brief Used for debugging and tracking things about MemoryAccesses.
|
||||
/// Guaranteed unique among MemoryAccesses, no guarantees otherwise.
|
||||
virtual unsigned getID() const = 0;
|
||||
@ -171,8 +214,6 @@ class MemoryAccess : public User, public ilist_node<MemoryAccess> {
|
||||
: User(Type::getVoidTy(C), Vty, nullptr, NumOperands), Block(BB) {}
|
||||
|
||||
private:
|
||||
MemoryAccess(const MemoryAccess &);
|
||||
void operator=(const MemoryAccess &);
|
||||
BasicBlock *Block;
|
||||
};
|
||||
|
||||
@ -189,10 +230,10 @@ inline raw_ostream &operator<<(raw_ostream &OS, const MemoryAccess &MA) {
|
||||
/// This class should never be instantiated directly; make a MemoryUse or
|
||||
/// MemoryDef instead.
|
||||
class MemoryUseOrDef : public MemoryAccess {
|
||||
public:
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
void *operator new(size_t) = delete;
|
||||
|
||||
public:
|
||||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
|
||||
|
||||
/// \brief Get the instruction that this MemoryUse represents.
|
||||
@ -201,21 +242,36 @@ class MemoryUseOrDef : public MemoryAccess {
|
||||
/// \brief Get the access that produces the memory state used by this Use.
|
||||
MemoryAccess *getDefiningAccess() const { return getOperand(0); }
|
||||
|
||||
static inline bool classof(const MemoryUseOrDef *) { return true; }
|
||||
static inline bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryUseVal || MA->getValueID() == MemoryDefVal;
|
||||
}
|
||||
|
||||
// Sadly, these have to be public because they are needed in some of the
|
||||
// iterators.
|
||||
virtual bool isOptimized() const = 0;
|
||||
virtual MemoryAccess *getOptimized() const = 0;
|
||||
virtual void setOptimized(MemoryAccess *) = 0;
|
||||
|
||||
/// \brief Reset the ID of what this MemoryUse was optimized to, causing it to
|
||||
/// be rewalked by the walker if necessary.
|
||||
/// This really should only be called by tests.
|
||||
virtual void resetOptimized() = 0;
|
||||
|
||||
protected:
|
||||
friend class MemorySSA;
|
||||
|
||||
friend class MemorySSAUpdater;
|
||||
MemoryUseOrDef(LLVMContext &C, MemoryAccess *DMA, unsigned Vty,
|
||||
Instruction *MI, BasicBlock *BB)
|
||||
: MemoryAccess(C, Vty, BB, 1), MemoryInst(MI) {
|
||||
setDefiningAccess(DMA);
|
||||
}
|
||||
|
||||
void setDefiningAccess(MemoryAccess *DMA) { setOperand(0, DMA); }
|
||||
void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) {
|
||||
if (!Optimized) {
|
||||
setOperand(0, DMA);
|
||||
return;
|
||||
}
|
||||
setOptimized(DMA);
|
||||
}
|
||||
|
||||
private:
|
||||
Instruction *MemoryInst;
|
||||
@ -232,35 +288,37 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUseOrDef, MemoryAccess)
|
||||
/// MemoryUse's is exactly the set of Instructions for which
|
||||
/// AliasAnalysis::getModRefInfo returns "Ref".
|
||||
class MemoryUse final : public MemoryUseOrDef {
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
|
||||
public:
|
||||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
|
||||
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
|
||||
MemoryUse(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB)
|
||||
: MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB), OptimizedID(0) {}
|
||||
|
||||
static inline bool classof(const MemoryUse *) { return true; }
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
|
||||
static inline bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryUseVal;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const override;
|
||||
void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) {
|
||||
if (Optimized)
|
||||
OptimizedID = DMA->getID();
|
||||
MemoryUseOrDef::setDefiningAccess(DMA);
|
||||
|
||||
virtual void setOptimized(MemoryAccess *DMA) override {
|
||||
OptimizedID = DMA->getID();
|
||||
setOperand(0, DMA);
|
||||
}
|
||||
bool isOptimized() const {
|
||||
|
||||
virtual bool isOptimized() const override {
|
||||
return getDefiningAccess() && OptimizedID == getDefiningAccess()->getID();
|
||||
}
|
||||
/// \brief Reset the ID of what this MemoryUse was optimized to, causing it to
|
||||
/// be rewalked by the walker if necessary.
|
||||
/// This really should only be called by tests.
|
||||
void resetOptimized() { OptimizedID = INVALID_MEMORYACCESS_ID; }
|
||||
|
||||
virtual MemoryAccess *getOptimized() const override {
|
||||
return getDefiningAccess();
|
||||
}
|
||||
virtual void resetOptimized() override {
|
||||
OptimizedID = INVALID_MEMORYACCESS_ID;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class MemorySSA;
|
||||
@ -287,23 +345,35 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryUse, MemoryAccess)
|
||||
/// associated with them. This use points to the nearest reaching
|
||||
/// MemoryDef/MemoryPhi.
|
||||
class MemoryDef final : public MemoryUseOrDef {
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
|
||||
public:
|
||||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
|
||||
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
|
||||
MemoryDef(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB,
|
||||
unsigned Ver)
|
||||
: MemoryUseOrDef(C, DMA, MemoryDefVal, MI, BB), ID(Ver) {}
|
||||
: MemoryUseOrDef(C, DMA, MemoryDefVal, MI, BB), ID(Ver),
|
||||
Optimized(nullptr), OptimizedID(INVALID_MEMORYACCESS_ID) {}
|
||||
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
|
||||
static inline bool classof(const MemoryDef *) { return true; }
|
||||
static inline bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryDefVal;
|
||||
}
|
||||
|
||||
virtual void setOptimized(MemoryAccess *MA) override {
|
||||
Optimized = MA;
|
||||
OptimizedID = getDefiningAccess()->getID();
|
||||
}
|
||||
virtual MemoryAccess *getOptimized() const override { return Optimized; }
|
||||
virtual bool isOptimized() const override {
|
||||
return getOptimized() && getDefiningAccess() &&
|
||||
OptimizedID == getDefiningAccess()->getID();
|
||||
}
|
||||
virtual void resetOptimized() override {
|
||||
OptimizedID = INVALID_MEMORYACCESS_ID;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const override;
|
||||
|
||||
protected:
|
||||
@ -313,6 +383,8 @@ class MemoryDef final : public MemoryUseOrDef {
|
||||
|
||||
private:
|
||||
const unsigned ID;
|
||||
MemoryAccess *Optimized;
|
||||
unsigned int OptimizedID;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -352,7 +424,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryDef, MemoryAccess)
|
||||
/// Because MemoryUse's do not generate new definitions, they do not have this
|
||||
/// issue.
|
||||
class MemoryPhi final : public MemoryAccess {
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
// allocate space for exactly zero operands
|
||||
void *operator new(size_t s) { return User::operator new(s); }
|
||||
|
||||
@ -365,6 +436,8 @@ class MemoryPhi final : public MemoryAccess {
|
||||
allocHungoffUses(ReservedSpace);
|
||||
}
|
||||
|
||||
void *operator new(size_t, unsigned) = delete;
|
||||
|
||||
// Block iterator interface. This provides access to the list of incoming
|
||||
// basic blocks, which parallels the list of incoming values.
|
||||
typedef BasicBlock **block_iterator;
|
||||
@ -457,7 +530,6 @@ class MemoryPhi final : public MemoryAccess {
|
||||
return getIncomingValue(Idx);
|
||||
}
|
||||
|
||||
static inline bool classof(const MemoryPhi *) { return true; }
|
||||
static inline bool classof(const Value *V) {
|
||||
return V->getValueID() == MemoryPhiVal;
|
||||
}
|
||||
@ -466,6 +538,7 @@ class MemoryPhi final : public MemoryAccess {
|
||||
|
||||
protected:
|
||||
friend class MemorySSA;
|
||||
|
||||
/// \brief this is more complicated than the generic
|
||||
/// User::allocHungoffUses, because we have to allocate Uses for the incoming
|
||||
/// values and pointers to the incoming blocks, all in one allocation.
|
||||
@ -529,7 +602,14 @@ class MemorySSA {
|
||||
return LiveOnEntryDef.get();
|
||||
}
|
||||
|
||||
using AccessList = iplist<MemoryAccess>;
|
||||
// Sadly, iplists, by default, owns and deletes pointers added to the
|
||||
// list. It's not currently possible to have two iplists for the same type,
|
||||
// where one owns the pointers, and one does not. This is because the traits
|
||||
// are per-type, not per-tag. If this ever changes, we should make the
|
||||
// DefList an iplist.
|
||||
using AccessList = iplist<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>;
|
||||
using DefsList =
|
||||
simple_ilist<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>>;
|
||||
|
||||
/// \brief Return the list of MemoryAccess's for a given basic block.
|
||||
///
|
||||
@ -538,62 +618,13 @@ class MemorySSA {
|
||||
return getWritableBlockAccesses(BB);
|
||||
}
|
||||
|
||||
/// \brief Create an empty MemoryPhi in MemorySSA for a given basic block.
|
||||
/// Only one MemoryPhi for a block exists at a time, so this function will
|
||||
/// assert if you try to create one where it already exists.
|
||||
MemoryPhi *createMemoryPhi(BasicBlock *BB);
|
||||
|
||||
enum InsertionPlace { Beginning, End };
|
||||
|
||||
/// \brief Create a MemoryAccess in MemorySSA at a specified point in a block,
|
||||
/// with a specified clobbering definition.
|
||||
/// \brief Return the list of MemoryDef's and MemoryPhi's for a given basic
|
||||
/// block.
|
||||
///
|
||||
/// Returns the new MemoryAccess.
|
||||
/// This should be called when a memory instruction is created that is being
|
||||
/// used to replace an existing memory instruction. It will *not* create PHI
|
||||
/// nodes, or verify the clobbering definition. The insertion place is used
|
||||
/// solely to determine where in the memoryssa access lists the instruction
|
||||
/// will be placed. The caller is expected to keep ordering the same as
|
||||
/// instructions.
|
||||
/// It will return the new MemoryAccess.
|
||||
/// Note: If a MemoryAccess already exists for I, this function will make it
|
||||
/// inaccessible and it *must* have removeMemoryAccess called on it.
|
||||
MemoryAccess *createMemoryAccessInBB(Instruction *I, MemoryAccess *Definition,
|
||||
const BasicBlock *BB,
|
||||
InsertionPlace Point);
|
||||
/// \brief Create a MemoryAccess in MemorySSA before or after an existing
|
||||
/// MemoryAccess.
|
||||
///
|
||||
/// Returns the new MemoryAccess.
|
||||
/// This should be called when a memory instruction is created that is being
|
||||
/// used to replace an existing memory instruction. It will *not* create PHI
|
||||
/// nodes, or verify the clobbering definition. The clobbering definition
|
||||
/// must be non-null.
|
||||
/// Note: If a MemoryAccess already exists for I, this function will make it
|
||||
/// inaccessible and it *must* have removeMemoryAccess called on it.
|
||||
MemoryUseOrDef *createMemoryAccessBefore(Instruction *I,
|
||||
MemoryAccess *Definition,
|
||||
MemoryUseOrDef *InsertPt);
|
||||
MemoryUseOrDef *createMemoryAccessAfter(Instruction *I,
|
||||
MemoryAccess *Definition,
|
||||
MemoryAccess *InsertPt);
|
||||
|
||||
// \brief Splice \p What to just before \p Where.
|
||||
//
|
||||
// In order to be efficient, the following conditions must be met:
|
||||
// - \p Where dominates \p What,
|
||||
// - All memory accesses in [\p Where, \p What) are no-alias with \p What.
|
||||
//
|
||||
// TODO: relax the MemoryDef requirement on Where.
|
||||
void spliceMemoryAccessAbove(MemoryDef *Where, MemoryUseOrDef *What);
|
||||
|
||||
/// \brief Remove a MemoryAccess from MemorySSA, including updating all
|
||||
/// definitions and uses.
|
||||
/// This should be called when a memory instruction that has a MemoryAccess
|
||||
/// associated with it is erased from the program. For example, if a store or
|
||||
/// load is simply erased (not replaced), removeMemoryAccess should be called
|
||||
/// on the MemoryAccess for that store/load.
|
||||
void removeMemoryAccess(MemoryAccess *);
|
||||
/// This list is not modifiable by the user.
|
||||
const DefsList *getBlockDefs(const BasicBlock *BB) const {
|
||||
return getWritableBlockDefs(BB);
|
||||
}
|
||||
|
||||
/// \brief Given two memory accesses in the same basic block, determine
|
||||
/// whether MemoryAccess \p A dominates MemoryAccess \p B.
|
||||
@ -611,20 +642,51 @@ class MemorySSA {
|
||||
/// all uses, uses appear in the right places). This is used by unit tests.
|
||||
void verifyMemorySSA() const;
|
||||
|
||||
/// Used in various insertion functions to specify whether we are talking
|
||||
/// about the beginning or end of a block.
|
||||
enum InsertionPlace { Beginning, End };
|
||||
|
||||
protected:
|
||||
// Used by Memory SSA annotater, dumpers, and wrapper pass
|
||||
friend class MemorySSAAnnotatedWriter;
|
||||
friend class MemorySSAPrinterLegacyPass;
|
||||
friend class MemorySSAUpdater;
|
||||
|
||||
void verifyDefUses(Function &F) const;
|
||||
void verifyDomination(Function &F) const;
|
||||
void verifyOrdering(Function &F) const;
|
||||
|
||||
// This is used by the use optimizer class
|
||||
// This is used by the use optimizer and updater.
|
||||
AccessList *getWritableBlockAccesses(const BasicBlock *BB) const {
|
||||
auto It = PerBlockAccesses.find(BB);
|
||||
return It == PerBlockAccesses.end() ? nullptr : It->second.get();
|
||||
}
|
||||
|
||||
// This is used by the use optimizer and updater.
|
||||
DefsList *getWritableBlockDefs(const BasicBlock *BB) const {
|
||||
auto It = PerBlockDefs.find(BB);
|
||||
return It == PerBlockDefs.end() ? nullptr : It->second.get();
|
||||
}
|
||||
|
||||
// These is used by the updater to perform various internal MemorySSA
|
||||
// machinsations. They do not always leave the IR in a correct state, and
|
||||
// relies on the updater to fixup what it breaks, so it is not public.
|
||||
|
||||
void moveTo(MemoryUseOrDef *What, BasicBlock *BB, AccessList::iterator Where);
|
||||
void moveTo(MemoryUseOrDef *What, BasicBlock *BB, InsertionPlace Point);
|
||||
// Rename the dominator tree branch rooted at BB.
|
||||
void renamePass(BasicBlock *BB, MemoryAccess *IncomingVal,
|
||||
SmallPtrSetImpl<BasicBlock *> &Visited) {
|
||||
renamePass(DT->getNode(BB), IncomingVal, Visited, true, true);
|
||||
}
|
||||
void removeFromLookups(MemoryAccess *);
|
||||
void removeFromLists(MemoryAccess *, bool ShouldDelete = true);
|
||||
void insertIntoListsForBlock(MemoryAccess *, const BasicBlock *,
|
||||
InsertionPlace);
|
||||
void insertIntoListsBefore(MemoryAccess *, const BasicBlock *,
|
||||
AccessList::iterator);
|
||||
MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *);
|
||||
|
||||
private:
|
||||
class CachingWalker;
|
||||
class OptimizeUses;
|
||||
@ -635,32 +697,39 @@ class MemorySSA {
|
||||
|
||||
void verifyUseInDefs(MemoryAccess *, MemoryAccess *) const;
|
||||
using AccessMap = DenseMap<const BasicBlock *, std::unique_ptr<AccessList>>;
|
||||
using DefsMap = DenseMap<const BasicBlock *, std::unique_ptr<DefsList>>;
|
||||
|
||||
void
|
||||
determineInsertionPoint(const SmallPtrSetImpl<BasicBlock *> &DefiningBlocks);
|
||||
void computeDomLevels(DenseMap<DomTreeNode *, unsigned> &DomLevels);
|
||||
void markUnreachableAsLiveOnEntry(BasicBlock *BB);
|
||||
bool dominatesUse(const MemoryAccess *, const MemoryAccess *) const;
|
||||
MemoryPhi *createMemoryPhi(BasicBlock *BB);
|
||||
MemoryUseOrDef *createNewAccess(Instruction *);
|
||||
MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *);
|
||||
MemoryAccess *findDominatingDef(BasicBlock *, enum InsertionPlace);
|
||||
void removeFromLookups(MemoryAccess *);
|
||||
|
||||
void placePHINodes(const SmallPtrSetImpl<BasicBlock *> &,
|
||||
const DenseMap<const BasicBlock *, unsigned int> &);
|
||||
MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *);
|
||||
MemoryAccess *renameBlock(BasicBlock *, MemoryAccess *, bool);
|
||||
void renameSuccessorPhis(BasicBlock *, MemoryAccess *, bool);
|
||||
void renamePass(DomTreeNode *, MemoryAccess *IncomingVal,
|
||||
SmallPtrSet<BasicBlock *, 16> &Visited);
|
||||
SmallPtrSetImpl<BasicBlock *> &Visited,
|
||||
bool SkipVisited = false, bool RenameAllUses = false);
|
||||
AccessList *getOrCreateAccessList(const BasicBlock *);
|
||||
DefsList *getOrCreateDefsList(const BasicBlock *);
|
||||
void renumberBlock(const BasicBlock *) const;
|
||||
|
||||
AliasAnalysis *AA;
|
||||
DominatorTree *DT;
|
||||
Function &F;
|
||||
|
||||
// Memory SSA mappings
|
||||
DenseMap<const Value *, MemoryAccess *> ValueToMemoryAccess;
|
||||
// These two mappings contain the main block to access/def mappings for
|
||||
// MemorySSA. The list contained in PerBlockAccesses really owns all the
|
||||
// MemoryAccesses.
|
||||
// Both maps maintain the invariant that if a block is found in them, the
|
||||
// corresponding list is not empty, and if a block is not found in them, the
|
||||
// corresponding list is empty.
|
||||
AccessMap PerBlockAccesses;
|
||||
DefsMap PerBlockDefs;
|
||||
std::unique_ptr<MemoryAccess> LiveOnEntryDef;
|
||||
|
||||
// Domination mappings
|
||||
@ -674,21 +743,33 @@ class MemorySSA {
|
||||
unsigned NextID;
|
||||
};
|
||||
|
||||
// Internal MemorySSA utils, for use by MemorySSA classes and walkers
|
||||
class MemorySSAUtil {
|
||||
protected:
|
||||
friend class MemorySSAWalker;
|
||||
friend class GVNHoist;
|
||||
// This function should not be used by new passes.
|
||||
static bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU,
|
||||
AliasAnalysis &AA);
|
||||
};
|
||||
|
||||
// This pass does eager building and then printing of MemorySSA. It is used by
|
||||
// the tests to be able to build, dump, and verify Memory SSA.
|
||||
class MemorySSAPrinterLegacyPass : public FunctionPass {
|
||||
public:
|
||||
MemorySSAPrinterLegacyPass();
|
||||
|
||||
static char ID;
|
||||
bool runOnFunction(Function &) override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
static char ID;
|
||||
};
|
||||
|
||||
/// An analysis that produces \c MemorySSA for a function.
|
||||
///
|
||||
class MemorySSAAnalysis : public AnalysisInfoMixin<MemorySSAAnalysis> {
|
||||
friend AnalysisInfoMixin<MemorySSAAnalysis>;
|
||||
|
||||
static AnalysisKey Key;
|
||||
|
||||
public:
|
||||
@ -711,6 +792,7 @@ class MemorySSAPrinterPass : public PassInfoMixin<MemorySSAPrinterPass> {
|
||||
|
||||
public:
|
||||
explicit MemorySSAPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
@ -725,6 +807,7 @@ class MemorySSAWrapperPass : public FunctionPass {
|
||||
MemorySSAWrapperPass();
|
||||
|
||||
static char ID;
|
||||
|
||||
bool runOnFunction(Function &) override;
|
||||
void releaseMemory() override;
|
||||
MemorySSA &getMSSA() { return *MSSA; }
|
||||
@ -753,7 +836,7 @@ class MemorySSAWrapperPass : public FunctionPass {
|
||||
class MemorySSAWalker {
|
||||
public:
|
||||
MemorySSAWalker(MemorySSA *);
|
||||
virtual ~MemorySSAWalker() {}
|
||||
virtual ~MemorySSAWalker() = default;
|
||||
|
||||
using MemoryAccessSet = SmallVector<MemoryAccess *, 8>;
|
||||
|
||||
@ -825,6 +908,7 @@ class DoNothingMemorySSAWalker final : public MemorySSAWalker {
|
||||
// Keep the overrides below from hiding the Instruction overload of
|
||||
// getClobberingMemoryAccess.
|
||||
using MemorySSAWalker::getClobberingMemoryAccess;
|
||||
|
||||
MemoryAccess *getClobberingMemoryAccess(MemoryAccess *) override;
|
||||
MemoryAccess *getClobberingMemoryAccess(MemoryAccess *,
|
||||
const MemoryLocation &) override;
|
||||
@ -843,8 +927,9 @@ class memoryaccess_def_iterator_base
|
||||
using BaseT = typename memoryaccess_def_iterator_base::iterator_facade_base;
|
||||
|
||||
public:
|
||||
memoryaccess_def_iterator_base(T *Start) : Access(Start), ArgNo(0) {}
|
||||
memoryaccess_def_iterator_base() : Access(nullptr), ArgNo(0) {}
|
||||
memoryaccess_def_iterator_base(T *Start) : Access(Start) {}
|
||||
memoryaccess_def_iterator_base() = default;
|
||||
|
||||
bool operator==(const memoryaccess_def_iterator_base &Other) const {
|
||||
return Access == Other.Access && (!Access || ArgNo == Other.ArgNo);
|
||||
}
|
||||
@ -883,8 +968,8 @@ class memoryaccess_def_iterator_base
|
||||
}
|
||||
|
||||
private:
|
||||
T *Access;
|
||||
unsigned ArgNo;
|
||||
T *Access = nullptr;
|
||||
unsigned ArgNo = 0;
|
||||
};
|
||||
|
||||
inline memoryaccess_def_iterator MemoryAccess::defs_begin() {
|
||||
@ -947,10 +1032,7 @@ class upward_defs_iterator
|
||||
fillInCurrentPair();
|
||||
}
|
||||
|
||||
upward_defs_iterator()
|
||||
: DefIterator(), Location(), OriginalAccess(), WalkingPhi(false) {
|
||||
CurrentPair.first = nullptr;
|
||||
}
|
||||
upward_defs_iterator() { CurrentPair.first = nullptr; }
|
||||
|
||||
bool operator==(const upward_defs_iterator &Other) const {
|
||||
return DefIterator == Other.DefIterator;
|
||||
@ -995,8 +1077,8 @@ class upward_defs_iterator
|
||||
MemoryAccessPair CurrentPair;
|
||||
memoryaccess_def_iterator DefIterator;
|
||||
MemoryLocation Location;
|
||||
MemoryAccess *OriginalAccess;
|
||||
bool WalkingPhi;
|
||||
MemoryAccess *OriginalAccess = nullptr;
|
||||
bool WalkingPhi = false;
|
||||
};
|
||||
|
||||
inline upward_defs_iterator upward_defs_begin(const MemoryAccessPair &Pair) {
|
||||
@ -1005,10 +1087,69 @@ inline upward_defs_iterator upward_defs_begin(const MemoryAccessPair &Pair) {
|
||||
|
||||
inline upward_defs_iterator upward_defs_end() { return upward_defs_iterator(); }
|
||||
|
||||
// Return true when MD may alias MU, return false otherwise.
|
||||
bool defClobbersUseOrDef(MemoryDef *MD, const MemoryUseOrDef *MU,
|
||||
AliasAnalysis &AA);
|
||||
inline iterator_range<upward_defs_iterator>
|
||||
upward_defs(const MemoryAccessPair &Pair) {
|
||||
return make_range(upward_defs_begin(Pair), upward_defs_end());
|
||||
}
|
||||
|
||||
/// Walks the defining accesses of MemoryDefs. Stops after we hit something that
|
||||
/// has no defining use (e.g. a MemoryPhi or liveOnEntry). Note that, when
|
||||
/// comparing against a null def_chain_iterator, this will compare equal only
|
||||
/// after walking said Phi/liveOnEntry.
|
||||
///
|
||||
/// The UseOptimizedChain flag specifies whether to walk the clobbering
|
||||
/// access chain, or all the accesses.
|
||||
///
|
||||
/// Normally, MemoryDef are all just def/use linked together, so a def_chain on
|
||||
/// a MemoryDef will walk all MemoryDefs above it in the program until it hits
|
||||
/// a phi node. The optimized chain walks the clobbering access of a store.
|
||||
/// So if you are just trying to find, given a store, what the next
|
||||
/// thing that would clobber the same memory is, you want the optimized chain.
|
||||
template <class T, bool UseOptimizedChain = false>
|
||||
struct def_chain_iterator
|
||||
: public iterator_facade_base<def_chain_iterator<T, UseOptimizedChain>,
|
||||
std::forward_iterator_tag, MemoryAccess *> {
|
||||
def_chain_iterator() : MA(nullptr) {}
|
||||
def_chain_iterator(T MA) : MA(MA) {}
|
||||
|
||||
T operator*() const { return MA; }
|
||||
|
||||
def_chain_iterator &operator++() {
|
||||
// N.B. liveOnEntry has a null defining access.
|
||||
if (auto *MUD = dyn_cast<MemoryUseOrDef>(MA)) {
|
||||
if (UseOptimizedChain && MUD->isOptimized())
|
||||
MA = MUD->getOptimized();
|
||||
else
|
||||
MA = MUD->getDefiningAccess();
|
||||
} else {
|
||||
MA = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const def_chain_iterator &O) const { return MA == O.MA; }
|
||||
|
||||
private:
|
||||
T MA;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline iterator_range<def_chain_iterator<T>>
|
||||
def_chain(T MA, MemoryAccess *UpTo = nullptr) {
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
assert((!UpTo || find(def_chain(MA), UpTo) != def_chain_iterator<T>()) &&
|
||||
"UpTo isn't in the def chain!");
|
||||
#endif
|
||||
return make_range(def_chain_iterator<T>(MA), def_chain_iterator<T>(UpTo));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline iterator_range<def_chain_iterator<T, true>> optimized_def_chain(T MA) {
|
||||
return make_range(def_chain_iterator<T, true>(MA),
|
||||
def_chain_iterator<T, true>(nullptr));
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_UTILS_MEMORYSSA_H
|
||||
#endif // LLVM_ANALYSIS_MEMORYSSA_H
|
153
contrib/llvm/include/llvm/Analysis/MemorySSAUpdater.h
Normal file
153
contrib/llvm/include/llvm/Analysis/MemorySSAUpdater.h
Normal file
@ -0,0 +1,153 @@
|
||||
//===- MemorySSAUpdater.h - Memory SSA Updater-------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file
|
||||
// \brief An automatic updater for MemorySSA that handles arbitrary insertion,
|
||||
// deletion, and moves. It performs phi insertion where necessary, and
|
||||
// automatically updates the MemorySSA IR to be correct.
|
||||
// While updating loads or removing instructions is often easy enough to not
|
||||
// need this, updating stores should generally not be attemped outside this
|
||||
// API.
|
||||
//
|
||||
// Basic API usage:
|
||||
// Create the memory access you want for the instruction (this is mainly so
|
||||
// we know where it is, without having to duplicate the entire set of create
|
||||
// functions MemorySSA supports).
|
||||
// Call insertDef or insertUse depending on whether it's a MemoryUse or a
|
||||
// MemoryDef.
|
||||
// That's it.
|
||||
//
|
||||
// For moving, first, move the instruction itself using the normal SSA
|
||||
// instruction moving API, then just call moveBefore, moveAfter,or moveTo with
|
||||
// the right arguments.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_MEMORYSSAUPDATER_H
|
||||
#define LLVM_ANALYSIS_MEMORYSSAUPDATER_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/OperandTraits.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Use.h"
|
||||
#include "llvm/IR/User.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Analysis/MemorySSA.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
class Instruction;
|
||||
class MemoryAccess;
|
||||
class LLVMContext;
|
||||
class raw_ostream;
|
||||
|
||||
class MemorySSAUpdater {
|
||||
private:
|
||||
MemorySSA *MSSA;
|
||||
SmallVector<MemoryPhi *, 8> InsertedPHIs;
|
||||
SmallPtrSet<BasicBlock *, 8> VisitedBlocks;
|
||||
|
||||
public:
|
||||
MemorySSAUpdater(MemorySSA *MSSA) : MSSA(MSSA) {}
|
||||
/// Insert a definition into the MemorySSA IR. RenameUses will rename any use
|
||||
/// below the new def block (and any inserted phis). RenameUses should be set
|
||||
/// to true if the definition may cause new aliases for loads below it. This
|
||||
/// is not the case for hoisting or sinking or other forms of code *movement*.
|
||||
/// It *is* the case for straight code insertion.
|
||||
/// For example:
|
||||
/// store a
|
||||
/// if (foo) { }
|
||||
/// load a
|
||||
///
|
||||
/// Moving the store into the if block, and calling insertDef, does not
|
||||
/// require RenameUses.
|
||||
/// However, changing it to:
|
||||
/// store a
|
||||
/// if (foo) { store b }
|
||||
/// load a
|
||||
/// Where a mayalias b, *does* require RenameUses be set to true.
|
||||
void insertDef(MemoryDef *Def, bool RenameUses = false);
|
||||
void insertUse(MemoryUse *Use);
|
||||
void moveBefore(MemoryUseOrDef *What, MemoryUseOrDef *Where);
|
||||
void moveAfter(MemoryUseOrDef *What, MemoryUseOrDef *Where);
|
||||
void moveToPlace(MemoryUseOrDef *What, BasicBlock *BB,
|
||||
MemorySSA::InsertionPlace Where);
|
||||
|
||||
// The below are utility functions. Other than creation of accesses to pass
|
||||
// to insertDef, and removeAccess to remove accesses, you should generally
|
||||
// not attempt to update memoryssa yourself. It is very non-trivial to get
|
||||
// the edge cases right, and the above calls already operate in near-optimal
|
||||
// time bounds.
|
||||
|
||||
/// \brief Create a MemoryAccess in MemorySSA at a specified point in a block,
|
||||
/// with a specified clobbering definition.
|
||||
///
|
||||
/// Returns the new MemoryAccess.
|
||||
/// This should be called when a memory instruction is created that is being
|
||||
/// used to replace an existing memory instruction. It will *not* create PHI
|
||||
/// nodes, or verify the clobbering definition. The insertion place is used
|
||||
/// solely to determine where in the memoryssa access lists the instruction
|
||||
/// will be placed. The caller is expected to keep ordering the same as
|
||||
/// instructions.
|
||||
/// It will return the new MemoryAccess.
|
||||
/// Note: If a MemoryAccess already exists for I, this function will make it
|
||||
/// inaccessible and it *must* have removeMemoryAccess called on it.
|
||||
MemoryAccess *createMemoryAccessInBB(Instruction *I, MemoryAccess *Definition,
|
||||
const BasicBlock *BB,
|
||||
MemorySSA::InsertionPlace Point);
|
||||
|
||||
/// \brief Create a MemoryAccess in MemorySSA before or after an existing
|
||||
/// MemoryAccess.
|
||||
///
|
||||
/// Returns the new MemoryAccess.
|
||||
/// This should be called when a memory instruction is created that is being
|
||||
/// used to replace an existing memory instruction. It will *not* create PHI
|
||||
/// nodes, or verify the clobbering definition.
|
||||
///
|
||||
/// Note: If a MemoryAccess already exists for I, this function will make it
|
||||
/// inaccessible and it *must* have removeMemoryAccess called on it.
|
||||
MemoryUseOrDef *createMemoryAccessBefore(Instruction *I,
|
||||
MemoryAccess *Definition,
|
||||
MemoryUseOrDef *InsertPt);
|
||||
MemoryUseOrDef *createMemoryAccessAfter(Instruction *I,
|
||||
MemoryAccess *Definition,
|
||||
MemoryAccess *InsertPt);
|
||||
|
||||
/// \brief Remove a MemoryAccess from MemorySSA, including updating all
|
||||
/// definitions and uses.
|
||||
/// This should be called when a memory instruction that has a MemoryAccess
|
||||
/// associated with it is erased from the program. For example, if a store or
|
||||
/// load is simply erased (not replaced), removeMemoryAccess should be called
|
||||
/// on the MemoryAccess for that store/load.
|
||||
void removeMemoryAccess(MemoryAccess *);
|
||||
|
||||
private:
|
||||
// Move What before Where in the MemorySSA IR.
|
||||
template <class WhereType>
|
||||
void moveTo(MemoryUseOrDef *What, BasicBlock *BB, WhereType Where);
|
||||
MemoryAccess *getPreviousDef(MemoryAccess *);
|
||||
MemoryAccess *getPreviousDefInBlock(MemoryAccess *);
|
||||
MemoryAccess *getPreviousDefFromEnd(BasicBlock *);
|
||||
MemoryAccess *getPreviousDefRecursive(BasicBlock *);
|
||||
MemoryAccess *recursePhi(MemoryAccess *Phi);
|
||||
template <class RangeType>
|
||||
MemoryAccess *tryRemoveTrivialPhi(MemoryPhi *Phi, RangeType &Operands);
|
||||
void fixupDefs(const SmallVectorImpl<MemoryAccess *> &);
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_MEMORYSSAUPDATER_H
|
42
contrib/llvm/include/llvm/Analysis/ObjectUtils.h
Normal file
42
contrib/llvm/include/llvm/Analysis/ObjectUtils.h
Normal file
@ -0,0 +1,42 @@
|
||||
//===- Analysis/ObjectUtils.h - analysis utils for object files -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_OBJECT_UTILS_H
|
||||
#define LLVM_ANALYSIS_OBJECT_UTILS_H
|
||||
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// True if GV can be left out of the object symbol table. This is the case
|
||||
/// for linkonce_odr values whose address is not significant. While legal, it is
|
||||
/// not normally profitable to omit them from the .o symbol table. Using this
|
||||
/// analysis makes sense when the information can be passed down to the linker
|
||||
/// or we are in LTO.
|
||||
inline bool canBeOmittedFromSymbolTable(const GlobalValue *GV) {
|
||||
if (!GV->hasLinkOnceODRLinkage())
|
||||
return false;
|
||||
|
||||
// We assume that anyone who sets global unnamed_addr on a non-constant knows
|
||||
// what they're doing.
|
||||
if (GV->hasGlobalUnnamedAddr())
|
||||
return true;
|
||||
|
||||
// If it is a non constant variable, it needs to be uniqued across shared
|
||||
// objects.
|
||||
if (auto *Var = dyn_cast<GlobalVariable>(GV))
|
||||
if (!Var->isConstant())
|
||||
return false;
|
||||
|
||||
return GV->hasAtLeastLocalUnnamedAddr();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -38,7 +38,7 @@ class Value;
|
||||
/// enabled in the LLVM context.
|
||||
class OptimizationRemarkEmitter {
|
||||
public:
|
||||
OptimizationRemarkEmitter(Function *F, BlockFrequencyInfo *BFI)
|
||||
OptimizationRemarkEmitter(const Function *F, BlockFrequencyInfo *BFI)
|
||||
: F(F), BFI(BFI) {}
|
||||
|
||||
/// \brief This variant can be used to generate ORE on demand (without the
|
||||
@ -52,7 +52,7 @@ class OptimizationRemarkEmitter {
|
||||
/// operation since BFI and all its required analyses are computed. This is
|
||||
/// for example useful for CGSCC passes that can't use function analyses
|
||||
/// passes in the old PM.
|
||||
OptimizationRemarkEmitter(Function *F);
|
||||
OptimizationRemarkEmitter(const Function *F);
|
||||
|
||||
OptimizationRemarkEmitter(OptimizationRemarkEmitter &&Arg)
|
||||
: F(Arg.F), BFI(Arg.BFI) {}
|
||||
@ -63,137 +63,17 @@ class OptimizationRemarkEmitter {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// The new interface to emit remarks.
|
||||
/// Handle invalidation events in the new pass manager.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &Inv);
|
||||
|
||||
/// \brief Output the remark via the diagnostic handler and to the
|
||||
/// optimization record file.
|
||||
///
|
||||
/// This is the new interface that should be now used rather than the legacy
|
||||
/// emit* APIs.
|
||||
void emit(DiagnosticInfoOptimizationBase &OptDiag);
|
||||
|
||||
/// Emit an optimization-applied message.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If -Rpass= is
|
||||
/// given and \p PassName matches the regular expression in -Rpass, then the
|
||||
/// remark will be emitted. \p Fn is the function triggering the remark, \p
|
||||
/// DLoc is the debug location where the diagnostic is generated. \p V is the
|
||||
/// IR Value that identifies the code region. \p Msg is the message string to
|
||||
/// use.
|
||||
void emitOptimizationRemark(const char *PassName, const DebugLoc &DLoc,
|
||||
const Value *V, const Twine &Msg);
|
||||
|
||||
/// \brief Same as above but derives the IR Value for the code region and the
|
||||
/// debug location from the Loop parameter \p L.
|
||||
void emitOptimizationRemark(const char *PassName, Loop *L, const Twine &Msg);
|
||||
|
||||
/// \brief Same as above but derives the debug location and the code region
|
||||
/// from the debug location and the basic block of \p Inst, respectively.
|
||||
void emitOptimizationRemark(const char *PassName, Instruction *Inst,
|
||||
const Twine &Msg) {
|
||||
emitOptimizationRemark(PassName, Inst->getDebugLoc(), Inst->getParent(),
|
||||
Msg);
|
||||
}
|
||||
|
||||
/// Emit an optimization-missed message.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If
|
||||
/// -Rpass-missed= is given and the name matches the regular expression in
|
||||
/// -Rpass, then the remark will be emitted. \p DLoc is the debug location
|
||||
/// where the diagnostic is generated. \p V is the IR Value that identifies
|
||||
/// the code region. \p Msg is the message string to use. If \p IsVerbose is
|
||||
/// true, the message is considered verbose and will only be emitted when
|
||||
/// verbose output is turned on.
|
||||
void emitOptimizationRemarkMissed(const char *PassName, const DebugLoc &DLoc,
|
||||
const Value *V, const Twine &Msg,
|
||||
bool IsVerbose = false);
|
||||
|
||||
/// \brief Same as above but derives the IR Value for the code region and the
|
||||
/// debug location from the Loop parameter \p L.
|
||||
void emitOptimizationRemarkMissed(const char *PassName, Loop *L,
|
||||
const Twine &Msg, bool IsVerbose = false);
|
||||
|
||||
/// \brief Same as above but derives the debug location and the code region
|
||||
/// from the debug location and the basic block of \p Inst, respectively.
|
||||
void emitOptimizationRemarkMissed(const char *PassName, Instruction *Inst,
|
||||
const Twine &Msg, bool IsVerbose = false) {
|
||||
emitOptimizationRemarkMissed(PassName, Inst->getDebugLoc(),
|
||||
Inst->getParent(), Msg, IsVerbose);
|
||||
}
|
||||
|
||||
/// Emit an optimization analysis remark message.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If
|
||||
/// -Rpass-analysis= is given and \p PassName matches the regular expression
|
||||
/// in -Rpass, then the remark will be emitted. \p DLoc is the debug location
|
||||
/// where the diagnostic is generated. \p V is the IR Value that identifies
|
||||
/// the code region. \p Msg is the message string to use. If \p IsVerbose is
|
||||
/// true, the message is considered verbose and will only be emitted when
|
||||
/// verbose output is turned on.
|
||||
void emitOptimizationRemarkAnalysis(const char *PassName,
|
||||
const DebugLoc &DLoc, const Value *V,
|
||||
const Twine &Msg, bool IsVerbose = false);
|
||||
|
||||
/// \brief Same as above but derives the IR Value for the code region and the
|
||||
/// debug location from the Loop parameter \p L.
|
||||
void emitOptimizationRemarkAnalysis(const char *PassName, Loop *L,
|
||||
const Twine &Msg, bool IsVerbose = false);
|
||||
|
||||
/// \brief Same as above but derives the debug location and the code region
|
||||
/// from the debug location and the basic block of \p Inst, respectively.
|
||||
void emitOptimizationRemarkAnalysis(const char *PassName, Instruction *Inst,
|
||||
const Twine &Msg,
|
||||
bool IsVerbose = false) {
|
||||
emitOptimizationRemarkAnalysis(PassName, Inst->getDebugLoc(),
|
||||
Inst->getParent(), Msg, IsVerbose);
|
||||
}
|
||||
|
||||
/// \brief This variant allows specifying what should be emitted for missed
|
||||
/// and analysis remarks in one call.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If
|
||||
/// -Rpass-missed= is given and \p PassName matches the regular expression, \p
|
||||
/// MsgForMissedRemark is emitted.
|
||||
///
|
||||
/// If -Rpass-analysis= is given and \p PassName matches the regular
|
||||
/// expression, \p MsgForAnalysisRemark is emitted.
|
||||
///
|
||||
/// The debug location and the code region is derived from \p Inst. If \p
|
||||
/// IsVerbose is true, the message is considered verbose and will only be
|
||||
/// emitted when verbose output is turned on.
|
||||
void emitOptimizationRemarkMissedAndAnalysis(
|
||||
const char *PassName, Instruction *Inst, const Twine &MsgForMissedRemark,
|
||||
const Twine &MsgForAnalysisRemark, bool IsVerbose = false) {
|
||||
emitOptimizationRemarkAnalysis(PassName, Inst, MsgForAnalysisRemark,
|
||||
IsVerbose);
|
||||
emitOptimizationRemarkMissed(PassName, Inst, MsgForMissedRemark, IsVerbose);
|
||||
}
|
||||
|
||||
/// \brief Emit an optimization analysis remark related to floating-point
|
||||
/// non-commutativity.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If
|
||||
/// -Rpass-analysis= is given and \p PassName matches the regular expression
|
||||
/// in -Rpass, then the remark will be emitted. \p Fn is the function
|
||||
/// triggering the remark, \p DLoc is the debug location where the diagnostic
|
||||
/// is generated.\p V is the IR Value that identifies the code region. \p Msg
|
||||
/// is the message string to use.
|
||||
void emitOptimizationRemarkAnalysisFPCommute(const char *PassName,
|
||||
const DebugLoc &DLoc,
|
||||
const Value *V,
|
||||
const Twine &Msg);
|
||||
|
||||
/// \brief Emit an optimization analysis remark related to pointer aliasing.
|
||||
///
|
||||
/// \p PassName is the name of the pass emitting the message. If
|
||||
/// -Rpass-analysis= is given and \p PassName matches the regular expression
|
||||
/// in -Rpass, then the remark will be emitted. \p Fn is the function
|
||||
/// triggering the remark, \p DLoc is the debug location where the diagnostic
|
||||
/// is generated.\p V is the IR Value that identifies the code region. \p Msg
|
||||
/// is the message string to use.
|
||||
void emitOptimizationRemarkAnalysisAliasing(const char *PassName,
|
||||
const DebugLoc &DLoc,
|
||||
const Value *V, const Twine &Msg);
|
||||
|
||||
/// \brief Same as above but derives the IR Value for the code region and the
|
||||
/// debug location from the Loop parameter \p L.
|
||||
void emitOptimizationRemarkAnalysisAliasing(const char *PassName, Loop *L,
|
||||
const Twine &Msg);
|
||||
|
||||
/// \brief Whether we allow for extra compile-time budget to perform more
|
||||
/// analysis to produce fewer false positives.
|
||||
///
|
||||
@ -208,7 +88,7 @@ class OptimizationRemarkEmitter {
|
||||
}
|
||||
|
||||
private:
|
||||
Function *F;
|
||||
const Function *F;
|
||||
|
||||
BlockFrequencyInfo *BFI;
|
||||
|
||||
@ -220,7 +100,7 @@ class OptimizationRemarkEmitter {
|
||||
Optional<uint64_t> computeHotness(const Value *V);
|
||||
|
||||
/// Similar but use value from \p OptDiag and update hotness there.
|
||||
void computeHotness(DiagnosticInfoOptimizationBase &OptDiag);
|
||||
void computeHotness(DiagnosticInfoIROptimization &OptDiag);
|
||||
|
||||
/// \brief Only allow verbose messages if we know we're filtering by hotness
|
||||
/// (BFI is only set in this case).
|
||||
@ -274,5 +154,11 @@ class OptimizationRemarkEmitterAnalysis
|
||||
/// \brief Run the analysis pass over a function and produce BFI.
|
||||
Result run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
namespace yaml {
|
||||
template <> struct MappingTraits<DiagnosticInfoOptimizationBase *> {
|
||||
static void mapping(IO &io, DiagnosticInfoOptimizationBase *&OptDiag);
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif // LLVM_IR_OPTIMIZATIONDIAGNOSTICINFO_H
|
||||
|
@ -26,6 +26,10 @@ struct PostDominatorTree : public DominatorTreeBase<BasicBlock> {
|
||||
typedef DominatorTreeBase<BasicBlock> Base;
|
||||
|
||||
PostDominatorTree() : DominatorTreeBase<BasicBlock>(true) {}
|
||||
|
||||
/// Handle invalidation explicitly.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &);
|
||||
};
|
||||
|
||||
/// \brief Analysis pass which computes a \c PostDominatorTree.
|
||||
|
@ -29,6 +29,7 @@
|
||||
namespace llvm {
|
||||
class BasicBlock;
|
||||
class BlockFrequencyInfo;
|
||||
class CallSite;
|
||||
class ProfileSummary;
|
||||
/// \brief Analysis providing profile information.
|
||||
///
|
||||
@ -44,7 +45,7 @@ class ProfileSummaryInfo {
|
||||
private:
|
||||
Module &M;
|
||||
std::unique_ptr<ProfileSummary> Summary;
|
||||
void computeSummary();
|
||||
bool computeSummary();
|
||||
void computeThresholds();
|
||||
// Count thresholds to answer isHotCount and isColdCount queries.
|
||||
Optional<uint64_t> HotCountThreshold, ColdCountThreshold;
|
||||
@ -53,16 +54,29 @@ class ProfileSummaryInfo {
|
||||
ProfileSummaryInfo(Module &M) : M(M) {}
|
||||
ProfileSummaryInfo(ProfileSummaryInfo &&Arg)
|
||||
: M(Arg.M), Summary(std::move(Arg.Summary)) {}
|
||||
/// Returns the profile count for \p CallInst.
|
||||
static Optional<uint64_t> getProfileCount(const Instruction *CallInst,
|
||||
BlockFrequencyInfo *BFI);
|
||||
/// \brief Returns true if \p F has hot function entry.
|
||||
bool isFunctionEntryHot(const Function *F);
|
||||
/// Returns true if \p F has hot function entry or hot call edge.
|
||||
bool isFunctionHotInCallGraph(const Function *F);
|
||||
/// \brief Returns true if \p F has cold function entry.
|
||||
bool isFunctionEntryCold(const Function *F);
|
||||
/// Returns true if \p F has cold function entry or cold call edge.
|
||||
bool isFunctionColdInCallGraph(const Function *F);
|
||||
/// \brief Returns true if \p F is a hot function.
|
||||
bool isHotCount(uint64_t C);
|
||||
/// \brief Returns true if count \p C is considered cold.
|
||||
bool isColdCount(uint64_t C);
|
||||
/// \brief Returns true if BasicBlock \p B is considered hot.
|
||||
bool isHotBB(const BasicBlock *B, BlockFrequencyInfo *BFI);
|
||||
/// \brief Returns true if BasicBlock \p B is considered cold.
|
||||
bool isColdBB(const BasicBlock *B, BlockFrequencyInfo *BFI);
|
||||
/// \brief Returns true if CallSite \p CS is considered hot.
|
||||
bool isHotCallSite(const CallSite &CS, BlockFrequencyInfo *BFI);
|
||||
/// \brief Returns true if Callsite \p CS is considered cold.
|
||||
bool isColdCallSite(const CallSite &CS, BlockFrequencyInfo *BFI);
|
||||
};
|
||||
|
||||
/// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo.
|
||||
|
@ -196,7 +196,10 @@ class PtrUseVisitor : protected InstVisitor<DerivedT>,
|
||||
typedef InstVisitor<DerivedT> Base;
|
||||
|
||||
public:
|
||||
PtrUseVisitor(const DataLayout &DL) : PtrUseVisitorBase(DL) {}
|
||||
PtrUseVisitor(const DataLayout &DL) : PtrUseVisitorBase(DL) {
|
||||
static_assert(std::is_base_of<PtrUseVisitor, DerivedT>::value,
|
||||
"Must pass the derived type to this template!");
|
||||
}
|
||||
|
||||
/// \brief Recursively visit the uses of the given pointer.
|
||||
/// \returns An info struct about the pointer. See \c PtrInfo for details.
|
||||
|
@ -886,6 +886,10 @@ class RegionInfo : public RegionInfoBase<RegionTraits<Function>> {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Handle invalidation explicitly.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &);
|
||||
|
||||
// updateStatistics - Update statistic about created regions.
|
||||
void updateStatistics(Region *R) final;
|
||||
|
||||
|
@ -543,6 +543,12 @@ class ScalarEvolution {
|
||||
/// predicate by splitting it into a set of independent predicates.
|
||||
bool ProvingSplitPredicate;
|
||||
|
||||
/// Memoized values for the GetMinTrailingZeros
|
||||
DenseMap<const SCEV *, uint32_t> MinTrailingZerosCache;
|
||||
|
||||
/// Private helper method for the GetMinTrailingZeros method
|
||||
uint32_t GetMinTrailingZerosImpl(const SCEV *S);
|
||||
|
||||
/// Information about the number of loop iterations for which a loop exit's
|
||||
/// branch condition evaluates to the not-taken path. This is a temporary
|
||||
/// pair of exact and max expressions that are eventually summarized in
|
||||
@ -600,14 +606,14 @@ class ScalarEvolution {
|
||||
/// Information about the number of times a particular loop exit may be
|
||||
/// reached before exiting the loop.
|
||||
struct ExitNotTakenInfo {
|
||||
AssertingVH<BasicBlock> ExitingBlock;
|
||||
PoisoningVH<BasicBlock> ExitingBlock;
|
||||
const SCEV *ExactNotTaken;
|
||||
std::unique_ptr<SCEVUnionPredicate> Predicate;
|
||||
bool hasAlwaysTruePredicate() const {
|
||||
return !Predicate || Predicate->isAlwaysTrue();
|
||||
}
|
||||
|
||||
explicit ExitNotTakenInfo(AssertingVH<BasicBlock> ExitingBlock,
|
||||
explicit ExitNotTakenInfo(PoisoningVH<BasicBlock> ExitingBlock,
|
||||
const SCEV *ExactNotTaken,
|
||||
std::unique_ptr<SCEVUnionPredicate> Predicate)
|
||||
: ExitingBlock(ExitingBlock), ExactNotTaken(ExactNotTaken),
|
||||
@ -970,6 +976,20 @@ class ScalarEvolution {
|
||||
const SCEV *RHS, const SCEV *FoundLHS,
|
||||
const SCEV *FoundRHS);
|
||||
|
||||
/// Test whether the condition described by Pred, LHS, and RHS is true
|
||||
/// whenever the condition described by Pred, FoundLHS, and FoundRHS is
|
||||
/// true. Here LHS is an operation that includes FoundLHS as one of its
|
||||
/// arguments.
|
||||
bool isImpliedViaOperations(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS,
|
||||
const SCEV *FoundLHS, const SCEV *FoundRHS,
|
||||
unsigned Depth = 0);
|
||||
|
||||
/// Test whether the condition described by Pred, LHS, and RHS is true.
|
||||
/// Use only simple non-recursive types of checks, such as range analysis etc.
|
||||
bool isKnownViaSimpleReasoning(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS);
|
||||
|
||||
/// Test whether the condition described by Pred, LHS, and RHS is true
|
||||
/// whenever the condition described by Pred, FoundLHS, and FoundRHS is
|
||||
/// true.
|
||||
@ -1065,18 +1085,6 @@ class ScalarEvolution {
|
||||
bool isMonotonicPredicateImpl(const SCEVAddRecExpr *LHS,
|
||||
ICmpInst::Predicate Pred, bool &Increasing);
|
||||
|
||||
/// Return true if, for all loop invariant X, the predicate "LHS `Pred` X"
|
||||
/// is monotonically increasing or decreasing. In the former case set
|
||||
/// `Increasing` to true and in the latter case set `Increasing` to false.
|
||||
///
|
||||
/// A predicate is said to be monotonically increasing if may go from being
|
||||
/// false to being true as the loop iterates, but never the other way
|
||||
/// around. A predicate is said to be monotonically decreasing if may go
|
||||
/// from being true to being false as the loop iterates, but never the other
|
||||
/// way around.
|
||||
bool isMonotonicPredicate(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred,
|
||||
bool &Increasing);
|
||||
|
||||
/// Return SCEV no-wrap flags that can be proven based on reasoning about
|
||||
/// how poison produced from no-wrap flags on this value (e.g. a nuw add)
|
||||
/// would trigger undefined behavior on overflow.
|
||||
@ -1129,6 +1137,9 @@ class ScalarEvolution {
|
||||
/// return true. For pointer types, this is the pointer-sized integer type.
|
||||
Type *getEffectiveSCEVType(Type *Ty) const;
|
||||
|
||||
// Returns a wider type among {Ty1, Ty2}.
|
||||
Type *getWiderType(Type *Ty1, Type *Ty2) const;
|
||||
|
||||
/// Return true if the SCEV is a scAddRecExpr or it contains
|
||||
/// scAddRecExpr. The result will be cached in HasRecMap.
|
||||
///
|
||||
@ -1152,7 +1163,8 @@ class ScalarEvolution {
|
||||
const SCEV *getSignExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getAnyExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
|
||||
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap);
|
||||
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap,
|
||||
unsigned Depth = 0);
|
||||
const SCEV *getAddExpr(const SCEV *LHS, const SCEV *RHS,
|
||||
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap) {
|
||||
SmallVector<const SCEV *, 2> Ops = {LHS, RHS};
|
||||
@ -1301,7 +1313,7 @@ class ScalarEvolution {
|
||||
///
|
||||
/// Implemented in terms of the \c getSmallConstantTripCount overload with
|
||||
/// the single exiting block passed to it. See that routine for details.
|
||||
unsigned getSmallConstantTripCount(Loop *L);
|
||||
unsigned getSmallConstantTripCount(const Loop *L);
|
||||
|
||||
/// Returns the maximum trip count of this loop as a normal unsigned
|
||||
/// value. Returns 0 if the trip count is unknown or not constant. This
|
||||
@ -1310,12 +1322,12 @@ class ScalarEvolution {
|
||||
/// before taking the branch. For loops with multiple exits, it may not be
|
||||
/// the number times that the loop header executes if the loop exits
|
||||
/// prematurely via another branch.
|
||||
unsigned getSmallConstantTripCount(Loop *L, BasicBlock *ExitingBlock);
|
||||
unsigned getSmallConstantTripCount(const Loop *L, BasicBlock *ExitingBlock);
|
||||
|
||||
/// Returns the upper bound of the loop trip count as a normal unsigned
|
||||
/// value.
|
||||
/// Returns 0 if the trip count is unknown or not constant.
|
||||
unsigned getSmallConstantMaxTripCount(Loop *L);
|
||||
unsigned getSmallConstantMaxTripCount(const Loop *L);
|
||||
|
||||
/// Returns the largest constant divisor of the trip count of the
|
||||
/// loop if it is a single-exit loop and we can compute a small maximum for
|
||||
@ -1323,7 +1335,7 @@ class ScalarEvolution {
|
||||
///
|
||||
/// Implemented in terms of the \c getSmallConstantTripMultiple overload with
|
||||
/// the single exiting block passed to it. See that routine for details.
|
||||
unsigned getSmallConstantTripMultiple(Loop *L);
|
||||
unsigned getSmallConstantTripMultiple(const Loop *L);
|
||||
|
||||
/// Returns the largest constant divisor of the trip count of this loop as a
|
||||
/// normal unsigned value, if possible. This means that the actual trip
|
||||
@ -1331,12 +1343,13 @@ class ScalarEvolution {
|
||||
/// count could very well be zero as well!). As explained in the comments
|
||||
/// for getSmallConstantTripCount, this assumes that control exits the loop
|
||||
/// via ExitingBlock.
|
||||
unsigned getSmallConstantTripMultiple(Loop *L, BasicBlock *ExitingBlock);
|
||||
unsigned getSmallConstantTripMultiple(const Loop *L,
|
||||
BasicBlock *ExitingBlock);
|
||||
|
||||
/// Get the expression for the number of loop iterations for which this loop
|
||||
/// is guaranteed not to exit via ExitingBlock. Otherwise return
|
||||
/// SCEVCouldNotCompute.
|
||||
const SCEV *getExitCount(Loop *L, BasicBlock *ExitingBlock);
|
||||
const SCEV *getExitCount(const Loop *L, BasicBlock *ExitingBlock);
|
||||
|
||||
/// If the specified loop has a predictable backedge-taken count, return it,
|
||||
/// otherwise return a SCEVCouldNotCompute object. The backedge-taken count
|
||||
@ -1432,6 +1445,18 @@ class ScalarEvolution {
|
||||
bool isKnownPredicate(ICmpInst::Predicate Pred, const SCEV *LHS,
|
||||
const SCEV *RHS);
|
||||
|
||||
/// Return true if, for all loop invariant X, the predicate "LHS `Pred` X"
|
||||
/// is monotonically increasing or decreasing. In the former case set
|
||||
/// `Increasing` to true and in the latter case set `Increasing` to false.
|
||||
///
|
||||
/// A predicate is said to be monotonically increasing if may go from being
|
||||
/// false to being true as the loop iterates, but never the other way
|
||||
/// around. A predicate is said to be monotonically decreasing if may go
|
||||
/// from being true to being false as the loop iterates, but never the other
|
||||
/// way around.
|
||||
bool isMonotonicPredicate(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred,
|
||||
bool &Increasing);
|
||||
|
||||
/// Return true if the result of the predicate LHS `Pred` RHS is loop
|
||||
/// invariant with respect to L. Set InvariantPred, InvariantLHS and
|
||||
/// InvariantLHS so that InvariantLHS `InvariantPred` InvariantRHS is the
|
||||
@ -1613,6 +1638,10 @@ class ScalarEvolution {
|
||||
bool doesIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride, bool IsSigned,
|
||||
bool NoWrap);
|
||||
|
||||
/// Get add expr already created or create a new one
|
||||
const SCEV *getOrCreateAddExpr(SmallVectorImpl<const SCEV *> &Ops,
|
||||
SCEV::NoWrapFlags Flags);
|
||||
|
||||
private:
|
||||
FoldingSet<SCEV> UniqueSCEVs;
|
||||
FoldingSet<SCEVPredicate> UniquePreds;
|
||||
|
@ -595,58 +595,82 @@ namespace llvm {
|
||||
|
||||
const SCEV *visitTruncateExpr(const SCEVTruncateExpr *Expr) {
|
||||
const SCEV *Operand = ((SC*)this)->visit(Expr->getOperand());
|
||||
return SE.getTruncateExpr(Operand, Expr->getType());
|
||||
return Operand == Expr->getOperand()
|
||||
? Expr
|
||||
: SE.getTruncateExpr(Operand, Expr->getType());
|
||||
}
|
||||
|
||||
const SCEV *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
|
||||
const SCEV *Operand = ((SC*)this)->visit(Expr->getOperand());
|
||||
return SE.getZeroExtendExpr(Operand, Expr->getType());
|
||||
return Operand == Expr->getOperand()
|
||||
? Expr
|
||||
: SE.getZeroExtendExpr(Operand, Expr->getType());
|
||||
}
|
||||
|
||||
const SCEV *visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
|
||||
const SCEV *Operand = ((SC*)this)->visit(Expr->getOperand());
|
||||
return SE.getSignExtendExpr(Operand, Expr->getType());
|
||||
return Operand == Expr->getOperand()
|
||||
? Expr
|
||||
: SE.getSignExtendExpr(Operand, Expr->getType());
|
||||
}
|
||||
|
||||
const SCEV *visitAddExpr(const SCEVAddExpr *Expr) {
|
||||
SmallVector<const SCEV *, 2> Operands;
|
||||
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
||||
Operands.push_back(((SC*)this)->visit(Expr->getOperand(i)));
|
||||
return SE.getAddExpr(Operands);
|
||||
bool Changed = false;
|
||||
for (auto *Op : Expr->operands()) {
|
||||
Operands.push_back(((SC*)this)->visit(Op));
|
||||
Changed |= Op != Operands.back();
|
||||
}
|
||||
return !Changed ? Expr : SE.getAddExpr(Operands);
|
||||
}
|
||||
|
||||
const SCEV *visitMulExpr(const SCEVMulExpr *Expr) {
|
||||
SmallVector<const SCEV *, 2> Operands;
|
||||
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
||||
Operands.push_back(((SC*)this)->visit(Expr->getOperand(i)));
|
||||
return SE.getMulExpr(Operands);
|
||||
bool Changed = false;
|
||||
for (auto *Op : Expr->operands()) {
|
||||
Operands.push_back(((SC*)this)->visit(Op));
|
||||
Changed |= Op != Operands.back();
|
||||
}
|
||||
return !Changed ? Expr : SE.getMulExpr(Operands);
|
||||
}
|
||||
|
||||
const SCEV *visitUDivExpr(const SCEVUDivExpr *Expr) {
|
||||
return SE.getUDivExpr(((SC*)this)->visit(Expr->getLHS()),
|
||||
((SC*)this)->visit(Expr->getRHS()));
|
||||
auto *LHS = ((SC *)this)->visit(Expr->getLHS());
|
||||
auto *RHS = ((SC *)this)->visit(Expr->getRHS());
|
||||
bool Changed = LHS != Expr->getLHS() || RHS != Expr->getRHS();
|
||||
return !Changed ? Expr : SE.getUDivExpr(LHS, RHS);
|
||||
}
|
||||
|
||||
const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr) {
|
||||
SmallVector<const SCEV *, 2> Operands;
|
||||
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
||||
Operands.push_back(((SC*)this)->visit(Expr->getOperand(i)));
|
||||
return SE.getAddRecExpr(Operands, Expr->getLoop(),
|
||||
Expr->getNoWrapFlags());
|
||||
bool Changed = false;
|
||||
for (auto *Op : Expr->operands()) {
|
||||
Operands.push_back(((SC*)this)->visit(Op));
|
||||
Changed |= Op != Operands.back();
|
||||
}
|
||||
return !Changed ? Expr
|
||||
: SE.getAddRecExpr(Operands, Expr->getLoop(),
|
||||
Expr->getNoWrapFlags());
|
||||
}
|
||||
|
||||
const SCEV *visitSMaxExpr(const SCEVSMaxExpr *Expr) {
|
||||
SmallVector<const SCEV *, 2> Operands;
|
||||
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
||||
Operands.push_back(((SC*)this)->visit(Expr->getOperand(i)));
|
||||
return SE.getSMaxExpr(Operands);
|
||||
bool Changed = false;
|
||||
for (auto *Op : Expr->operands()) {
|
||||
Operands.push_back(((SC *)this)->visit(Op));
|
||||
Changed |= Op != Operands.back();
|
||||
}
|
||||
return !Changed ? Expr : SE.getSMaxExpr(Operands);
|
||||
}
|
||||
|
||||
const SCEV *visitUMaxExpr(const SCEVUMaxExpr *Expr) {
|
||||
SmallVector<const SCEV *, 2> Operands;
|
||||
for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
|
||||
Operands.push_back(((SC*)this)->visit(Expr->getOperand(i)));
|
||||
return SE.getUMaxExpr(Operands);
|
||||
bool Changed = false;
|
||||
for (auto *Op : Expr->operands()) {
|
||||
Operands.push_back(((SC*)this)->visit(Op));
|
||||
Changed |= Op != Operands.back();
|
||||
}
|
||||
return !Changed ? Expr : SE.getUMaxExpr(Operands);
|
||||
}
|
||||
|
||||
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
|
||||
|
@ -37,42 +37,33 @@
|
||||
#define LLVM_ANALYSIS_SCALAREVOLUTIONNORMALIZATION_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Instruction;
|
||||
class DominatorTree;
|
||||
class Loop;
|
||||
class ScalarEvolution;
|
||||
class SCEV;
|
||||
class Value;
|
||||
|
||||
/// TransformKind - Different types of transformations that
|
||||
/// TransformForPostIncUse can do.
|
||||
enum TransformKind {
|
||||
/// Normalize - Normalize according to the given loops.
|
||||
Normalize,
|
||||
/// NormalizeAutodetect - Detect post-inc opportunities on new expressions,
|
||||
/// update the given loop set, and normalize.
|
||||
NormalizeAutodetect,
|
||||
/// Denormalize - Perform the inverse transform on the expression with the
|
||||
/// given loop set.
|
||||
Denormalize
|
||||
};
|
||||
|
||||
/// PostIncLoopSet - A set of loops.
|
||||
typedef SmallPtrSet<const Loop *, 2> PostIncLoopSet;
|
||||
|
||||
/// TransformForPostIncUse - Transform the given expression according to the
|
||||
/// given transformation kind.
|
||||
const SCEV *TransformForPostIncUse(TransformKind Kind,
|
||||
const SCEV *S,
|
||||
Instruction *User,
|
||||
Value *OperandValToReplace,
|
||||
PostIncLoopSet &Loops,
|
||||
ScalarEvolution &SE,
|
||||
DominatorTree &DT);
|
||||
typedef function_ref<bool(const SCEVAddRecExpr *)> NormalizePredTy;
|
||||
|
||||
}
|
||||
/// Normalize \p S to be post-increment for all loops present in \p
|
||||
/// Loops.
|
||||
const SCEV *normalizeForPostIncUse(const SCEV *S, const PostIncLoopSet &Loops,
|
||||
ScalarEvolution &SE);
|
||||
|
||||
/// Normalize \p S for all add recurrence sub-expressions for which \p
|
||||
/// Pred returns true.
|
||||
const SCEV *normalizeForPostIncUseIf(const SCEV *S, NormalizePredTy Pred,
|
||||
ScalarEvolution &SE);
|
||||
|
||||
/// Denormalize \p S to be post-increment for all loops present in \p
|
||||
/// Loops.
|
||||
const SCEV *denormalizeForPostIncUse(const SCEV *S, const PostIncLoopSet &Loops,
|
||||
ScalarEvolution &SE);
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
// One of TLI_DEFINE_ENUM/STRING are defined.
|
||||
|
||||
#if defined(TLI_DEFINE_ENUM)
|
||||
#define TLI_DEFINE_ENUM_INTERNAL(enum_variant) enum_variant,
|
||||
#define TLI_DEFINE_ENUM_INTERNAL(enum_variant) LibFunc_##enum_variant,
|
||||
#define TLI_DEFINE_STRING_INTERNAL(string_repr)
|
||||
#else
|
||||
#define TLI_DEFINE_ENUM_INTERNAL(enum_variant)
|
||||
|
@ -30,14 +30,12 @@ struct VecDesc {
|
||||
unsigned VectorizationFactor;
|
||||
};
|
||||
|
||||
namespace LibFunc {
|
||||
enum Func {
|
||||
enum LibFunc {
|
||||
#define TLI_DEFINE_ENUM
|
||||
#include "llvm/Analysis/TargetLibraryInfo.def"
|
||||
|
||||
NumLibFuncs
|
||||
};
|
||||
}
|
||||
NumLibFuncs
|
||||
};
|
||||
|
||||
/// Implementation of the target library information.
|
||||
///
|
||||
@ -48,9 +46,9 @@ struct VecDesc {
|
||||
class TargetLibraryInfoImpl {
|
||||
friend class TargetLibraryInfo;
|
||||
|
||||
unsigned char AvailableArray[(LibFunc::NumLibFuncs+3)/4];
|
||||
unsigned char AvailableArray[(NumLibFuncs+3)/4];
|
||||
llvm::DenseMap<unsigned, std::string> CustomNames;
|
||||
static StringRef const StandardNames[LibFunc::NumLibFuncs];
|
||||
static StringRef const StandardNames[NumLibFuncs];
|
||||
bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param;
|
||||
|
||||
enum AvailabilityState {
|
||||
@ -58,11 +56,11 @@ class TargetLibraryInfoImpl {
|
||||
CustomName = 1,
|
||||
Unavailable = 0 // (memset to all zeros)
|
||||
};
|
||||
void setState(LibFunc::Func F, AvailabilityState State) {
|
||||
void setState(LibFunc F, AvailabilityState State) {
|
||||
AvailableArray[F/4] &= ~(3 << 2*(F&3));
|
||||
AvailableArray[F/4] |= State << 2*(F&3);
|
||||
}
|
||||
AvailabilityState getState(LibFunc::Func F) const {
|
||||
AvailabilityState getState(LibFunc F) const {
|
||||
return static_cast<AvailabilityState>((AvailableArray[F/4] >> 2*(F&3)) & 3);
|
||||
}
|
||||
|
||||
@ -74,7 +72,7 @@ class TargetLibraryInfoImpl {
|
||||
|
||||
/// Return true if the function type FTy is valid for the library function
|
||||
/// F, regardless of whether the function is available.
|
||||
bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc::Func F,
|
||||
bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F,
|
||||
const DataLayout *DL) const;
|
||||
|
||||
public:
|
||||
@ -104,28 +102,28 @@ class TargetLibraryInfoImpl {
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(StringRef funcName, LibFunc::Func &F) const;
|
||||
bool getLibFunc(StringRef funcName, LibFunc &F) const;
|
||||
|
||||
/// Searches for a particular function name, also checking that its type is
|
||||
/// valid for the library function matching that name.
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const;
|
||||
bool getLibFunc(const Function &FDecl, LibFunc &F) const;
|
||||
|
||||
/// Forces a function to be marked as unavailable.
|
||||
void setUnavailable(LibFunc::Func F) {
|
||||
void setUnavailable(LibFunc F) {
|
||||
setState(F, Unavailable);
|
||||
}
|
||||
|
||||
/// Forces a function to be marked as available.
|
||||
void setAvailable(LibFunc::Func F) {
|
||||
void setAvailable(LibFunc F) {
|
||||
setState(F, StandardName);
|
||||
}
|
||||
|
||||
/// Forces a function to be marked as available and provide an alternate name
|
||||
/// that must be used.
|
||||
void setAvailableWithName(LibFunc::Func F, StringRef Name) {
|
||||
void setAvailableWithName(LibFunc F, StringRef Name) {
|
||||
if (StandardNames[F] != Name) {
|
||||
setState(F, CustomName);
|
||||
CustomNames[F] = Name;
|
||||
@ -225,16 +223,16 @@ class TargetLibraryInfo {
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(StringRef funcName, LibFunc::Func &F) const {
|
||||
bool getLibFunc(StringRef funcName, LibFunc &F) const {
|
||||
return Impl->getLibFunc(funcName, F);
|
||||
}
|
||||
|
||||
bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const {
|
||||
bool getLibFunc(const Function &FDecl, LibFunc &F) const {
|
||||
return Impl->getLibFunc(FDecl, F);
|
||||
}
|
||||
|
||||
/// Tests whether a library function is available.
|
||||
bool has(LibFunc::Func F) const {
|
||||
bool has(LibFunc F) const {
|
||||
return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable;
|
||||
}
|
||||
bool isFunctionVectorizable(StringRef F, unsigned VF) const {
|
||||
@ -249,37 +247,37 @@ class TargetLibraryInfo {
|
||||
|
||||
/// Tests if the function is both available and a candidate for optimized code
|
||||
/// generation.
|
||||
bool hasOptimizedCodeGen(LibFunc::Func F) const {
|
||||
bool hasOptimizedCodeGen(LibFunc F) const {
|
||||
if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable)
|
||||
return false;
|
||||
switch (F) {
|
||||
default: break;
|
||||
case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl:
|
||||
case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl:
|
||||
case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl:
|
||||
case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl:
|
||||
case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl:
|
||||
case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite:
|
||||
case LibFunc::sqrtl_finite:
|
||||
case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl:
|
||||
case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl:
|
||||
case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl:
|
||||
case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl:
|
||||
case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill:
|
||||
case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl:
|
||||
case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl:
|
||||
case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl:
|
||||
case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l:
|
||||
case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l:
|
||||
case LibFunc::memcmp: case LibFunc::strcmp: case LibFunc::strcpy:
|
||||
case LibFunc::stpcpy: case LibFunc::strlen: case LibFunc::strnlen:
|
||||
case LibFunc::memchr: case LibFunc::mempcpy:
|
||||
case LibFunc_copysign: case LibFunc_copysignf: case LibFunc_copysignl:
|
||||
case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl:
|
||||
case LibFunc_sin: case LibFunc_sinf: case LibFunc_sinl:
|
||||
case LibFunc_cos: case LibFunc_cosf: case LibFunc_cosl:
|
||||
case LibFunc_sqrt: case LibFunc_sqrtf: case LibFunc_sqrtl:
|
||||
case LibFunc_sqrt_finite: case LibFunc_sqrtf_finite:
|
||||
case LibFunc_sqrtl_finite:
|
||||
case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl:
|
||||
case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl:
|
||||
case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl:
|
||||
case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl:
|
||||
case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill:
|
||||
case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl:
|
||||
case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl:
|
||||
case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl:
|
||||
case LibFunc_log2: case LibFunc_log2f: case LibFunc_log2l:
|
||||
case LibFunc_exp2: case LibFunc_exp2f: case LibFunc_exp2l:
|
||||
case LibFunc_memcmp: case LibFunc_strcmp: case LibFunc_strcpy:
|
||||
case LibFunc_stpcpy: case LibFunc_strlen: case LibFunc_strnlen:
|
||||
case LibFunc_memchr: case LibFunc_mempcpy:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
StringRef getName(LibFunc::Func F) const {
|
||||
StringRef getName(LibFunc F) const {
|
||||
auto State = Impl->getState(F);
|
||||
if (State == TargetLibraryInfoImpl::Unavailable)
|
||||
return StringRef();
|
||||
|
@ -44,23 +44,26 @@ class Value;
|
||||
|
||||
/// \brief Information about a load/store intrinsic defined by the target.
|
||||
struct MemIntrinsicInfo {
|
||||
MemIntrinsicInfo()
|
||||
: ReadMem(false), WriteMem(false), IsSimple(false), MatchingId(0),
|
||||
NumMemRefs(0), PtrVal(nullptr) {}
|
||||
bool ReadMem;
|
||||
bool WriteMem;
|
||||
/// True only if this memory operation is non-volatile, non-atomic, and
|
||||
/// unordered. (See LoadInst/StoreInst for details on each)
|
||||
bool IsSimple;
|
||||
// Same Id is set by the target for corresponding load/store intrinsics.
|
||||
unsigned short MatchingId;
|
||||
int NumMemRefs;
|
||||
|
||||
/// This is the pointer that the intrinsic is loading from or storing to.
|
||||
/// If this is non-null, then analysis/optimization passes can assume that
|
||||
/// this intrinsic is functionally equivalent to a load/store from this
|
||||
/// pointer.
|
||||
Value *PtrVal;
|
||||
Value *PtrVal = nullptr;
|
||||
|
||||
// Ordering for atomic operations.
|
||||
AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
|
||||
|
||||
// Same Id is set by the target for corresponding load/store intrinsics.
|
||||
unsigned short MatchingId = 0;
|
||||
|
||||
bool ReadMem = false;
|
||||
bool WriteMem = false;
|
||||
bool IsVolatile = false;
|
||||
|
||||
bool isUnordered() const {
|
||||
return (Ordering == AtomicOrdering::NotAtomic ||
|
||||
Ordering == AtomicOrdering::Unordered) && !IsVolatile;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This pass provides access to the codegen interfaces that are needed
|
||||
@ -226,6 +229,24 @@ class TargetTransformInfo {
|
||||
/// starting with the sources of divergence.
|
||||
bool isSourceOfDivergence(const Value *V) const;
|
||||
|
||||
/// Returns the address space ID for a target's 'flat' address space. Note
|
||||
/// this is not necessarily the same as addrspace(0), which LLVM sometimes
|
||||
/// refers to as the generic address space. The flat address space is a
|
||||
/// generic address space that can be used access multiple segments of memory
|
||||
/// with different address spaces. Access of a memory location through a
|
||||
/// pointer with this address space is expected to be legal but slower
|
||||
/// compared to the same memory location accessed through a pointer with a
|
||||
/// different address space.
|
||||
//
|
||||
/// This is for for targets with different pointer representations which can
|
||||
/// be converted with the addrspacecast instruction. If a pointer is converted
|
||||
/// to this address space, optimizations should attempt to replace the access
|
||||
/// with the source address space.
|
||||
///
|
||||
/// \returns ~0u if the target does not have such a flat address space to
|
||||
/// optimize away.
|
||||
unsigned getFlatAddressSpace() const;
|
||||
|
||||
/// \brief Test whether calls to a function lower to actual program function
|
||||
/// calls.
|
||||
///
|
||||
@ -411,6 +432,16 @@ class TargetTransformInfo {
|
||||
/// containing this constant value for the target.
|
||||
bool shouldBuildLookupTablesForConstant(Constant *C) const;
|
||||
|
||||
unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) const;
|
||||
|
||||
unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args,
|
||||
unsigned VF) const;
|
||||
|
||||
/// If target has efficient vector element load/store instructions, it can
|
||||
/// return true here so that insertion/extraction costs are not added to
|
||||
/// the scalarization cost of a load/store.
|
||||
bool supportsEfficientVectorElementLoadStore() const;
|
||||
|
||||
/// \brief Don't restrict interleaved unrolling to small loops.
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) const;
|
||||
|
||||
@ -500,6 +531,12 @@ class TargetTransformInfo {
|
||||
/// \return The width of the largest scalar or vector register type.
|
||||
unsigned getRegisterBitWidth(bool Vector) const;
|
||||
|
||||
/// \return True if it should be considered for address type promotion.
|
||||
/// \p AllowPromotionWithoutCommonHeader Set true if promoting \p I is
|
||||
/// profitable without finding other extensions fed by the same input.
|
||||
bool shouldConsiderAddressTypePromotion(
|
||||
const Instruction &I, bool &AllowPromotionWithoutCommonHeader) const;
|
||||
|
||||
/// \return The size of a cache line in bytes.
|
||||
unsigned getCacheLineSize() const;
|
||||
|
||||
@ -540,8 +577,10 @@ class TargetTransformInfo {
|
||||
Type *SubTp = nullptr) const;
|
||||
|
||||
/// \return The expected cost of cast instructions, such as bitcast, trunc,
|
||||
/// zext, etc.
|
||||
int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) const;
|
||||
/// zext, etc. If there is an existing instruction that holds Opcode, it
|
||||
/// may be passed in the 'I' parameter.
|
||||
int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
|
||||
const Instruction *I = nullptr) const;
|
||||
|
||||
/// \return The expected cost of a sign- or zero-extended vector extract. Use
|
||||
/// -1 to indicate that there is no information about the index value.
|
||||
@ -552,9 +591,11 @@ class TargetTransformInfo {
|
||||
/// Phi, Ret, Br.
|
||||
int getCFInstrCost(unsigned Opcode) const;
|
||||
|
||||
/// \returns The expected cost of compare and select instructions.
|
||||
/// \returns The expected cost of compare and select instructions. If there
|
||||
/// is an existing instruction that holds Opcode, it may be passed in the
|
||||
/// 'I' parameter.
|
||||
int getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
|
||||
Type *CondTy = nullptr) const;
|
||||
Type *CondTy = nullptr, const Instruction *I = nullptr) const;
|
||||
|
||||
/// \return The expected cost of vector Insert and Extract.
|
||||
/// Use -1 to indicate that there is no information on the index value.
|
||||
@ -562,7 +603,7 @@ class TargetTransformInfo {
|
||||
|
||||
/// \return The cost of Load and Store instructions.
|
||||
int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) const;
|
||||
unsigned AddressSpace, const Instruction *I = nullptr) const;
|
||||
|
||||
/// \return The cost of masked Load and Store instructions.
|
||||
int getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
@ -605,13 +646,19 @@ class TargetTransformInfo {
|
||||
/// ((v0+v2), (v1+v3), undef, undef)
|
||||
int getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwiseForm) const;
|
||||
|
||||
/// \returns The cost of Intrinsic instructions. Types analysis only.
|
||||
int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF) const;
|
||||
|
||||
/// \returns The cost of Intrinsic instructions. Analyses the real arguments.
|
||||
/// Three cases are handled: 1. scalar instruction 2. vector instruction
|
||||
/// 3. scalar instruction which is to be vectorized with VF.
|
||||
int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF) const;
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF,
|
||||
unsigned VF = 1) const;
|
||||
|
||||
/// \returns The cost of Intrinsic instructions. Types analysis only.
|
||||
/// If ScalarizationCostPassed is UINT_MAX, the cost of scalarizing the
|
||||
/// arguments and the return value will be computed based on types.
|
||||
int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF,
|
||||
unsigned ScalarizationCostPassed = UINT_MAX) const;
|
||||
|
||||
/// \returns The cost of Call instructions.
|
||||
int getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) const;
|
||||
@ -720,6 +767,7 @@ class TargetTransformInfo::Concept {
|
||||
virtual int getUserCost(const User *U) = 0;
|
||||
virtual bool hasBranchDivergence() = 0;
|
||||
virtual bool isSourceOfDivergence(const Value *V) = 0;
|
||||
virtual unsigned getFlatAddressSpace() = 0;
|
||||
virtual bool isLoweredToCall(const Function *F) = 0;
|
||||
virtual void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) = 0;
|
||||
virtual bool isLegalAddImmediate(int64_t Imm) = 0;
|
||||
@ -743,6 +791,11 @@ class TargetTransformInfo::Concept {
|
||||
virtual unsigned getJumpBufSize() = 0;
|
||||
virtual bool shouldBuildLookupTables() = 0;
|
||||
virtual bool shouldBuildLookupTablesForConstant(Constant *C) = 0;
|
||||
virtual unsigned
|
||||
getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) = 0;
|
||||
virtual unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args,
|
||||
unsigned VF) = 0;
|
||||
virtual bool supportsEfficientVectorElementLoadStore() = 0;
|
||||
virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0;
|
||||
virtual bool enableInterleavedAccessVectorization() = 0;
|
||||
virtual bool isFPVectorizationPotentiallyUnsafe() = 0;
|
||||
@ -763,6 +816,8 @@ class TargetTransformInfo::Concept {
|
||||
Type *Ty) = 0;
|
||||
virtual unsigned getNumberOfRegisters(bool Vector) = 0;
|
||||
virtual unsigned getRegisterBitWidth(bool Vector) = 0;
|
||||
virtual bool shouldConsiderAddressTypePromotion(
|
||||
const Instruction &I, bool &AllowPromotionWithoutCommonHeader) = 0;
|
||||
virtual unsigned getCacheLineSize() = 0;
|
||||
virtual unsigned getPrefetchDistance() = 0;
|
||||
virtual unsigned getMinPrefetchStride() = 0;
|
||||
@ -776,16 +831,17 @@ class TargetTransformInfo::Concept {
|
||||
ArrayRef<const Value *> Args) = 0;
|
||||
virtual int getShuffleCost(ShuffleKind Kind, Type *Tp, int Index,
|
||||
Type *SubTp) = 0;
|
||||
virtual int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) = 0;
|
||||
virtual int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
|
||||
const Instruction *I) = 0;
|
||||
virtual int getExtractWithExtendCost(unsigned Opcode, Type *Dst,
|
||||
VectorType *VecTy, unsigned Index) = 0;
|
||||
virtual int getCFInstrCost(unsigned Opcode) = 0;
|
||||
virtual int getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
|
||||
Type *CondTy) = 0;
|
||||
Type *CondTy, const Instruction *I) = 0;
|
||||
virtual int getVectorInstrCost(unsigned Opcode, Type *Val,
|
||||
unsigned Index) = 0;
|
||||
virtual int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) = 0;
|
||||
unsigned AddressSpace, const Instruction *I) = 0;
|
||||
virtual int getMaskedMemoryOpCost(unsigned Opcode, Type *Src,
|
||||
unsigned Alignment,
|
||||
unsigned AddressSpace) = 0;
|
||||
@ -800,11 +856,10 @@ class TargetTransformInfo::Concept {
|
||||
virtual int getReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) = 0;
|
||||
virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys,
|
||||
FastMathFlags FMF) = 0;
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF,
|
||||
unsigned ScalarizationCostPassed) = 0;
|
||||
virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Value *> Args,
|
||||
FastMathFlags FMF) = 0;
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF, unsigned VF) = 0;
|
||||
virtual int getCallInstrCost(Function *F, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) = 0;
|
||||
virtual unsigned getNumberOfParts(Type *Tp) = 0;
|
||||
@ -879,6 +934,11 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
bool isSourceOfDivergence(const Value *V) override {
|
||||
return Impl.isSourceOfDivergence(V);
|
||||
}
|
||||
|
||||
unsigned getFlatAddressSpace() override {
|
||||
return Impl.getFlatAddressSpace();
|
||||
}
|
||||
|
||||
bool isLoweredToCall(const Function *F) override {
|
||||
return Impl.isLoweredToCall(F);
|
||||
}
|
||||
@ -933,6 +993,19 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
bool shouldBuildLookupTablesForConstant(Constant *C) override {
|
||||
return Impl.shouldBuildLookupTablesForConstant(C);
|
||||
}
|
||||
unsigned getScalarizationOverhead(Type *Ty, bool Insert,
|
||||
bool Extract) override {
|
||||
return Impl.getScalarizationOverhead(Ty, Insert, Extract);
|
||||
}
|
||||
unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args,
|
||||
unsigned VF) override {
|
||||
return Impl.getOperandsScalarizationOverhead(Args, VF);
|
||||
}
|
||||
|
||||
bool supportsEfficientVectorElementLoadStore() override {
|
||||
return Impl.supportsEfficientVectorElementLoadStore();
|
||||
}
|
||||
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) override {
|
||||
return Impl.enableAggressiveInterleaving(LoopHasReductions);
|
||||
}
|
||||
@ -976,7 +1049,11 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
unsigned getRegisterBitWidth(bool Vector) override {
|
||||
return Impl.getRegisterBitWidth(Vector);
|
||||
}
|
||||
|
||||
bool shouldConsiderAddressTypePromotion(
|
||||
const Instruction &I, bool &AllowPromotionWithoutCommonHeader) override {
|
||||
return Impl.shouldConsiderAddressTypePromotion(
|
||||
I, AllowPromotionWithoutCommonHeader);
|
||||
}
|
||||
unsigned getCacheLineSize() override {
|
||||
return Impl.getCacheLineSize();
|
||||
}
|
||||
@ -1003,8 +1080,9 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
Type *SubTp) override {
|
||||
return Impl.getShuffleCost(Kind, Tp, Index, SubTp);
|
||||
}
|
||||
int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) override {
|
||||
return Impl.getCastInstrCost(Opcode, Dst, Src);
|
||||
int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
|
||||
const Instruction *I) override {
|
||||
return Impl.getCastInstrCost(Opcode, Dst, Src, I);
|
||||
}
|
||||
int getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy,
|
||||
unsigned Index) override {
|
||||
@ -1013,15 +1091,16 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
int getCFInstrCost(unsigned Opcode) override {
|
||||
return Impl.getCFInstrCost(Opcode);
|
||||
}
|
||||
int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) override {
|
||||
return Impl.getCmpSelInstrCost(Opcode, ValTy, CondTy);
|
||||
int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy,
|
||||
const Instruction *I) override {
|
||||
return Impl.getCmpSelInstrCost(Opcode, ValTy, CondTy, I);
|
||||
}
|
||||
int getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) override {
|
||||
return Impl.getVectorInstrCost(Opcode, Val, Index);
|
||||
}
|
||||
int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) override {
|
||||
return Impl.getMemoryOpCost(Opcode, Src, Alignment, AddressSpace);
|
||||
unsigned AddressSpace, const Instruction *I) override {
|
||||
return Impl.getMemoryOpCost(Opcode, Src, Alignment, AddressSpace, I);
|
||||
}
|
||||
int getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) override {
|
||||
@ -1044,13 +1123,13 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
return Impl.getReductionCost(Opcode, Ty, IsPairwiseForm);
|
||||
}
|
||||
int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, ArrayRef<Type *> Tys,
|
||||
FastMathFlags FMF) override {
|
||||
return Impl.getIntrinsicInstrCost(ID, RetTy, Tys, FMF);
|
||||
FastMathFlags FMF, unsigned ScalarizationCostPassed) override {
|
||||
return Impl.getIntrinsicInstrCost(ID, RetTy, Tys, FMF,
|
||||
ScalarizationCostPassed);
|
||||
}
|
||||
int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Value *> Args,
|
||||
FastMathFlags FMF) override {
|
||||
return Impl.getIntrinsicInstrCost(ID, RetTy, Args, FMF);
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF, unsigned VF) override {
|
||||
return Impl.getIntrinsicInstrCost(ID, RetTy, Args, FMF, VF);
|
||||
}
|
||||
int getCallInstrCost(Function *F, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) override {
|
||||
|
@ -171,6 +171,10 @@ class TargetTransformInfoImplBase {
|
||||
|
||||
bool isSourceOfDivergence(const Value *V) { return false; }
|
||||
|
||||
unsigned getFlatAddressSpace () {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool isLoweredToCall(const Function *F) {
|
||||
// FIXME: These should almost certainly not be handled here, and instead
|
||||
// handled with the help of TLI or the target itself. This was largely
|
||||
@ -251,6 +255,15 @@ class TargetTransformInfoImplBase {
|
||||
bool shouldBuildLookupTables() { return true; }
|
||||
bool shouldBuildLookupTablesForConstant(Constant *C) { return true; }
|
||||
|
||||
unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args,
|
||||
unsigned VF) { return 0; }
|
||||
|
||||
bool supportsEfficientVectorElementLoadStore() { return false; }
|
||||
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) { return false; }
|
||||
|
||||
bool enableInterleavedAccessVectorization() { return false; }
|
||||
@ -292,6 +305,13 @@ class TargetTransformInfoImplBase {
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) { return 32; }
|
||||
|
||||
bool
|
||||
shouldConsiderAddressTypePromotion(const Instruction &I,
|
||||
bool &AllowPromotionWithoutCommonHeader) {
|
||||
AllowPromotionWithoutCommonHeader = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned getCacheLineSize() { return 0; }
|
||||
|
||||
unsigned getPrefetchDistance() { return 0; }
|
||||
@ -316,7 +336,8 @@ class TargetTransformInfoImplBase {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { return 1; }
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
|
||||
const Instruction *I) { return 1; }
|
||||
|
||||
unsigned getExtractWithExtendCost(unsigned Opcode, Type *Dst,
|
||||
VectorType *VecTy, unsigned Index) {
|
||||
@ -325,7 +346,8 @@ class TargetTransformInfoImplBase {
|
||||
|
||||
unsigned getCFInstrCost(unsigned Opcode) { return 1; }
|
||||
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) {
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy,
|
||||
const Instruction *I) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -334,7 +356,7 @@ class TargetTransformInfoImplBase {
|
||||
}
|
||||
|
||||
unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) {
|
||||
unsigned AddressSpace, const Instruction *I) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -358,11 +380,12 @@ class TargetTransformInfoImplBase {
|
||||
}
|
||||
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF) {
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF,
|
||||
unsigned ScalarizationCostPassed) {
|
||||
return 1;
|
||||
}
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF) {
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF, unsigned VF) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -32,14 +32,15 @@ struct DevirtCallSite {
|
||||
/// call sites based on the call and return them in DevirtCalls.
|
||||
void findDevirtualizableCallsForTypeTest(
|
||||
SmallVectorImpl<DevirtCallSite> &DevirtCalls,
|
||||
SmallVectorImpl<CallInst *> &Assumes, CallInst *CI);
|
||||
SmallVectorImpl<CallInst *> &Assumes, const CallInst *CI);
|
||||
|
||||
/// Given a call to the intrinsic @llvm.type.checked.load, find all
|
||||
/// devirtualizable call sites based on the call and return them in DevirtCalls.
|
||||
void findDevirtualizableCallsForTypeCheckedLoad(
|
||||
SmallVectorImpl<DevirtCallSite> &DevirtCalls,
|
||||
SmallVectorImpl<Instruction *> &LoadedPtrs,
|
||||
SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses, CallInst *CI);
|
||||
SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses,
|
||||
const CallInst *CI);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@ template <typename T> class ArrayRef;
|
||||
class Instruction;
|
||||
class Loop;
|
||||
class LoopInfo;
|
||||
class OptimizationRemarkEmitter;
|
||||
class MDNode;
|
||||
class StringRef;
|
||||
class TargetLibraryInfo;
|
||||
@ -52,7 +53,8 @@ template <typename T> class ArrayRef;
|
||||
const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
const DominatorTree *DT = nullptr,
|
||||
OptimizationRemarkEmitter *ORE = nullptr);
|
||||
/// Compute known bits from the range metadata.
|
||||
/// \p KnownZero the set of bits that are known to be zero
|
||||
/// \p KnownOne the set of bits that are known to be one
|
||||
@ -86,8 +88,10 @@ template <typename T> class ArrayRef;
|
||||
|
||||
/// Return true if the given value is known to be non-zero when defined. For
|
||||
/// vectors, return true if every element is known to be non-zero when
|
||||
/// defined. Supports values with integer or pointer type and vectors of
|
||||
/// integers.
|
||||
/// defined. For pointers, if the context instruction and dominator tree are
|
||||
/// specified, perform context-sensitive analysis and return true if the
|
||||
/// pointer couldn't possibly be null at the specified instruction.
|
||||
/// Supports values with integer or pointer type and vectors of integers.
|
||||
bool isKnownNonZero(const Value *V, const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
@ -167,13 +171,25 @@ template <typename T> class ArrayRef;
|
||||
bool CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI,
|
||||
unsigned Depth = 0);
|
||||
|
||||
/// Return true if we can prove that the specified FP value is either a NaN or
|
||||
/// never less than 0.0.
|
||||
/// If \p IncludeNeg0 is false, -0.0 is considered less than 0.0.
|
||||
/// Return true if we can prove that the specified FP value is either NaN or
|
||||
/// never less than -0.0.
|
||||
///
|
||||
/// NaN --> true
|
||||
/// +0 --> true
|
||||
/// -0 --> true
|
||||
/// x > +0 --> true
|
||||
/// x < -0 --> false
|
||||
///
|
||||
bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// \returns true if we can prove that the specified FP value has a 0 sign
|
||||
/// bit.
|
||||
/// Return true if we can prove that the specified FP value's sign bit is 0.
|
||||
///
|
||||
/// NaN --> true/false (depending on the NaN's sign bit)
|
||||
/// +0 --> true
|
||||
/// -0 --> false
|
||||
/// x > +0 --> true
|
||||
/// x < -0 --> false
|
||||
///
|
||||
bool SignBitMustBeZero(const Value *V, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// If the specified value can be set by repeating the same byte in memory,
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- llvm/Transforms/Utils/VectorUtils.h - Vector utilities -*- C++ -*-=====//
|
||||
//===- llvm/Analysis/VectorUtils.h - Vector utilities -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -11,11 +11,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_UTILS_VECTORUTILS_H
|
||||
#define LLVM_TRANSFORMS_UTILS_VECTORUTILS_H
|
||||
#ifndef LLVM_ANALYSIS_VECTORUTILS_H
|
||||
#define LLVM_ANALYSIS_VECTORUTILS_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -123,6 +124,58 @@ computeMinimumValueSizes(ArrayRef<BasicBlock*> Blocks,
|
||||
/// This function always sets a (possibly null) value for each K in Kinds.
|
||||
Instruction *propagateMetadata(Instruction *I, ArrayRef<Value *> VL);
|
||||
|
||||
/// \brief Create an interleave shuffle mask.
|
||||
///
|
||||
/// This function creates a shuffle mask for interleaving \p NumVecs vectors of
|
||||
/// vectorization factor \p VF into a single wide vector. The mask is of the
|
||||
/// form:
|
||||
///
|
||||
/// <0, VF, VF * 2, ..., VF * (NumVecs - 1), 1, VF + 1, VF * 2 + 1, ...>
|
||||
///
|
||||
/// For example, the mask for VF = 4 and NumVecs = 2 is:
|
||||
///
|
||||
/// <0, 4, 1, 5, 2, 6, 3, 7>.
|
||||
Constant *createInterleaveMask(IRBuilder<> &Builder, unsigned VF,
|
||||
unsigned NumVecs);
|
||||
|
||||
/// \brief Create a stride shuffle mask.
|
||||
///
|
||||
/// This function creates a shuffle mask whose elements begin at \p Start and
|
||||
/// are incremented by \p Stride. The mask can be used to deinterleave an
|
||||
/// interleaved vector into separate vectors of vectorization factor \p VF. The
|
||||
/// mask is of the form:
|
||||
///
|
||||
/// <Start, Start + Stride, ..., Start + Stride * (VF - 1)>
|
||||
///
|
||||
/// For example, the mask for Start = 0, Stride = 2, and VF = 4 is:
|
||||
///
|
||||
/// <0, 2, 4, 6>
|
||||
Constant *createStrideMask(IRBuilder<> &Builder, unsigned Start,
|
||||
unsigned Stride, unsigned VF);
|
||||
|
||||
/// \brief Create a sequential shuffle mask.
|
||||
///
|
||||
/// This function creates shuffle mask whose elements are sequential and begin
|
||||
/// at \p Start. The mask contains \p NumInts integers and is padded with \p
|
||||
/// NumUndefs undef values. The mask is of the form:
|
||||
///
|
||||
/// <Start, Start + 1, ... Start + NumInts - 1, undef_1, ... undef_NumUndefs>
|
||||
///
|
||||
/// For example, the mask for Start = 0, NumInsts = 4, and NumUndefs = 4 is:
|
||||
///
|
||||
/// <0, 1, 2, 3, undef, undef, undef, undef>
|
||||
Constant *createSequentialMask(IRBuilder<> &Builder, unsigned Start,
|
||||
unsigned NumInts, unsigned NumUndefs);
|
||||
|
||||
/// \brief Concatenate a list of vectors.
|
||||
///
|
||||
/// This function generates code that concatenate the vectors in \p Vecs into a
|
||||
/// single large vector. The number of vectors should be greater than one, and
|
||||
/// their element types should be the same. The number of elements in the
|
||||
/// vectors should also be the same; however, if the last vector has fewer
|
||||
/// elements, it will be padded with undefs.
|
||||
Value *concatenateVectors(IRBuilder<> &Builder, ArrayRef<Value *> Vecs);
|
||||
|
||||
} // llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -43,9 +43,16 @@ namespace llvm {
|
||||
///
|
||||
/// \p GenerateHash enables hashing the Module and including the hash in the
|
||||
/// bitcode (currently for use in ThinLTO incremental build).
|
||||
///
|
||||
/// If \p ModHash is non-null, when GenerateHash is true, the resulting
|
||||
/// hash is written into ModHash. When GenerateHash is false, that value
|
||||
/// is used as the hash instead of computing from the generated bitcode.
|
||||
/// Can be used to produce the same module hash for a minimized bitcode
|
||||
/// used just for the thin link as in the regular full bitcode that will
|
||||
/// be used in the backend.
|
||||
void writeModule(const Module *M, bool ShouldPreserveUseListOrder = false,
|
||||
const ModuleSummaryIndex *Index = nullptr,
|
||||
bool GenerateHash = false);
|
||||
bool GenerateHash = false, ModuleHash *ModHash = nullptr);
|
||||
};
|
||||
|
||||
/// \brief Write the specified module to the specified raw output stream.
|
||||
@ -62,10 +69,18 @@ namespace llvm {
|
||||
///
|
||||
/// \p GenerateHash enables hashing the Module and including the hash in the
|
||||
/// bitcode (currently for use in ThinLTO incremental build).
|
||||
///
|
||||
/// If \p ModHash is non-null, when GenerateHash is true, the resulting
|
||||
/// hash is written into ModHash. When GenerateHash is false, that value
|
||||
/// is used as the hash instead of computing from the generated bitcode.
|
||||
/// Can be used to produce the same module hash for a minimized bitcode
|
||||
/// used just for the thin link as in the regular full bitcode that will
|
||||
/// be used in the backend.
|
||||
void WriteBitcodeToFile(const Module *M, raw_ostream &Out,
|
||||
bool ShouldPreserveUseListOrder = false,
|
||||
const ModuleSummaryIndex *Index = nullptr,
|
||||
bool GenerateHash = false);
|
||||
bool GenerateHash = false,
|
||||
ModuleHash *ModHash = nullptr);
|
||||
|
||||
/// Write the specified module summary index to the given raw output stream,
|
||||
/// where it will be written in a new bitcode block. This is used when
|
||||
|
@ -92,9 +92,6 @@ enum ModuleCodes {
|
||||
// ALIAS: [alias type, aliasee val#, linkage, visibility]
|
||||
MODULE_CODE_ALIAS_OLD = 9,
|
||||
|
||||
// MODULE_CODE_PURGEVALS: [numvals]
|
||||
MODULE_CODE_PURGEVALS = 10,
|
||||
|
||||
MODULE_CODE_GCNAME = 11, // GCNAME: [strchr x N]
|
||||
MODULE_CODE_COMDAT = 12, // COMDAT: [selection_kind, name]
|
||||
|
||||
@ -213,8 +210,28 @@ enum GlobalValueSummarySymtabCodes {
|
||||
FS_COMBINED_ORIGINAL_NAME = 9,
|
||||
// VERSION of the summary, bumped when adding flags for instance.
|
||||
FS_VERSION = 10,
|
||||
// The list of llvm.type.test type identifiers used by the following function.
|
||||
// The list of llvm.type.test type identifiers used by the following function
|
||||
// that are used other than by an llvm.assume.
|
||||
// [n x typeid]
|
||||
FS_TYPE_TESTS = 11,
|
||||
// The list of virtual calls made by this function using
|
||||
// llvm.assume(llvm.type.test) intrinsics that do not have all constant
|
||||
// integer arguments.
|
||||
// [n x (typeid, offset)]
|
||||
FS_TYPE_TEST_ASSUME_VCALLS = 12,
|
||||
// The list of virtual calls made by this function using
|
||||
// llvm.type.checked.load intrinsics that do not have all constant integer
|
||||
// arguments.
|
||||
// [n x (typeid, offset)]
|
||||
FS_TYPE_CHECKED_LOAD_VCALLS = 13,
|
||||
// Identifies a virtual call made by this function using an
|
||||
// llvm.assume(llvm.type.test) intrinsic with all constant integer arguments.
|
||||
// [typeid, offset, n x arg]
|
||||
FS_TYPE_TEST_ASSUME_CONST_VCALL = 14,
|
||||
// Identifies a virtual call made by this function using an
|
||||
// llvm.type.checked.load intrinsic with all constant integer arguments.
|
||||
// [typeid, offset, n x arg]
|
||||
FS_TYPE_CHECKED_LOAD_CONST_VCALL = 15,
|
||||
};
|
||||
|
||||
enum MetadataCodes {
|
||||
|
@ -123,13 +123,6 @@ bool returnTypeIsEligibleForTailCall(const Function *F, const Instruction *I,
|
||||
const ReturnInst *Ret,
|
||||
const TargetLoweringBase &TLI);
|
||||
|
||||
// True if GV can be left out of the object symbol table. This is the case
|
||||
// for linkonce_odr values whose address is not significant. While legal, it is
|
||||
// not normally profitable to omit them from the .o symbol table. Using this
|
||||
// analysis makes sense when the information can be passed down to the linker
|
||||
// or we are in LTO.
|
||||
bool canBeOmittedFromSymbolTable(const GlobalValue *GV);
|
||||
|
||||
DenseMap<const MachineBasicBlock *, int>
|
||||
getFuncletMembership(const MachineFunction &MF);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework --------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -17,35 +17,43 @@
|
||||
#define LLVM_CODEGEN_ASMPRINTER_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinterHandler;
|
||||
class BlockAddress;
|
||||
class ByteStreamer;
|
||||
class GCStrategy;
|
||||
class Constant;
|
||||
class ConstantArray;
|
||||
class DataLayout;
|
||||
class DIE;
|
||||
class DIEAbbrev;
|
||||
class DwarfDebug;
|
||||
class GCMetadataPrinter;
|
||||
class GlobalIndirectSymbol;
|
||||
class GlobalValue;
|
||||
class GlobalVariable;
|
||||
class GCStrategy;
|
||||
class MachineBasicBlock;
|
||||
class MachineConstantPoolValue;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineLocation;
|
||||
class MachineLoopInfo;
|
||||
class MachineLoop;
|
||||
class MachineConstantPoolValue;
|
||||
class MachineJumpTableInfo;
|
||||
class MachineLoopInfo;
|
||||
class MachineModuleInfo;
|
||||
class MachineOptimizationRemarkEmitter;
|
||||
class MCAsmInfo;
|
||||
class MCCFIInstruction;
|
||||
class MCContext;
|
||||
@ -57,10 +65,7 @@ class MCSubtargetInfo;
|
||||
class MCSymbol;
|
||||
class MCTargetOptions;
|
||||
class MDNode;
|
||||
class DwarfDebug;
|
||||
class Mangler;
|
||||
class TargetLoweringObjectFile;
|
||||
class DataLayout;
|
||||
class TargetMachine;
|
||||
|
||||
/// This class is intended to be used as a driving class for all asm writers.
|
||||
@ -84,33 +89,39 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
std::unique_ptr<MCStreamer> OutStreamer;
|
||||
|
||||
/// The current machine function.
|
||||
const MachineFunction *MF;
|
||||
const MachineFunction *MF = nullptr;
|
||||
|
||||
/// This is a pointer to the current MachineModuleInfo.
|
||||
MachineModuleInfo *MMI;
|
||||
MachineModuleInfo *MMI = nullptr;
|
||||
|
||||
/// Optimization remark emitter.
|
||||
MachineOptimizationRemarkEmitter *ORE;
|
||||
|
||||
/// The symbol for the current function. This is recalculated at the beginning
|
||||
/// of each call to runOnMachineFunction().
|
||||
///
|
||||
MCSymbol *CurrentFnSym;
|
||||
MCSymbol *CurrentFnSym = nullptr;
|
||||
|
||||
/// The symbol used to represent the start of the current function for the
|
||||
/// purpose of calculating its size (e.g. using the .size directive). By
|
||||
/// default, this is equal to CurrentFnSym.
|
||||
MCSymbol *CurrentFnSymForSize;
|
||||
MCSymbol *CurrentFnSymForSize = nullptr;
|
||||
|
||||
/// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of
|
||||
/// its number of uses by other globals.
|
||||
typedef std::pair<const GlobalVariable *, unsigned> GOTEquivUsePair;
|
||||
MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs;
|
||||
|
||||
/// Enable print [latency:throughput] in output
|
||||
bool EnablePrintSchedInfo = false;
|
||||
|
||||
private:
|
||||
MCSymbol *CurrentFnBegin;
|
||||
MCSymbol *CurrentFnEnd;
|
||||
MCSymbol *CurExceptionSym;
|
||||
MCSymbol *CurrentFnBegin = nullptr;
|
||||
MCSymbol *CurrentFnEnd = nullptr;
|
||||
MCSymbol *CurExceptionSym = nullptr;
|
||||
|
||||
// The garbage collection metadata printer table.
|
||||
void *GCMetadataPrinters; // Really a DenseMap.
|
||||
void *GCMetadataPrinters = nullptr; // Really a DenseMap.
|
||||
|
||||
/// Emit comments in assembly output if this is true.
|
||||
///
|
||||
@ -118,7 +129,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
static char ID;
|
||||
|
||||
/// If VerboseAsm is set, a pointer to the loop info for this function.
|
||||
MachineLoopInfo *LI;
|
||||
MachineLoopInfo *LI = nullptr;
|
||||
|
||||
struct HandlerInfo {
|
||||
AsmPrinterHandler *Handler;
|
||||
@ -126,6 +137,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
const char *TimerDescription;
|
||||
const char *TimerGroupName;
|
||||
const char *TimerGroupDescription;
|
||||
|
||||
HandlerInfo(AsmPrinterHandler *Handler, const char *TimerName,
|
||||
const char *TimerDescription, const char *TimerGroupName,
|
||||
const char *TimerGroupDescription)
|
||||
@ -137,11 +149,24 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// maintains ownership of the emitters.
|
||||
SmallVector<HandlerInfo, 1> Handlers;
|
||||
|
||||
public:
|
||||
struct SrcMgrDiagInfo {
|
||||
SourceMgr SrcMgr;
|
||||
std::vector<const MDNode *> LocInfos;
|
||||
LLVMContext::InlineAsmDiagHandlerTy DiagHandler;
|
||||
void *DiagContext;
|
||||
};
|
||||
|
||||
private:
|
||||
/// Structure for generating diagnostics for inline assembly. Only initialised
|
||||
/// when necessary.
|
||||
mutable std::unique_ptr<SrcMgrDiagInfo> DiagInfo;
|
||||
|
||||
/// If the target supports dwarf debug info, this pointer is non-null.
|
||||
DwarfDebug *DD;
|
||||
DwarfDebug *DD = nullptr;
|
||||
|
||||
/// If the current module uses dwarf CFI annotations strictly for debugging.
|
||||
bool isCFIMoveForDebugging;
|
||||
bool isCFIMoveForDebugging = false;
|
||||
|
||||
protected:
|
||||
explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
|
||||
@ -200,6 +225,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
FUNCTION_ENTER = 0,
|
||||
FUNCTION_EXIT = 1,
|
||||
TAIL_CALL = 2,
|
||||
LOG_ARGS_ENTER = 3,
|
||||
};
|
||||
|
||||
// The table will contain these structs that point to the sled, the function
|
||||
@ -381,7 +407,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
//===------------------------------------------------------------------===//
|
||||
// Symbol Lowering Routines.
|
||||
//===------------------------------------------------------------------===//
|
||||
public:
|
||||
|
||||
MCSymbol *createTempSymbol(const Twine &Name) const;
|
||||
|
||||
/// Return the MCSymbol for a private symbol with global value name as its
|
||||
@ -407,7 +433,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
//===------------------------------------------------------------------===//
|
||||
// Emission Helper Routines.
|
||||
//===------------------------------------------------------------------===//
|
||||
public:
|
||||
|
||||
/// This is just convenient handler for printing offsets.
|
||||
void printOffset(int64_t Offset, raw_ostream &OS) const;
|
||||
|
||||
@ -484,7 +510,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
///
|
||||
/// \p Value - The value to emit.
|
||||
/// \p Size - The size of the integer (in bytes) to emit.
|
||||
virtual void EmitDebugValue(const MCExpr *Value, unsigned Size) const;
|
||||
virtual void EmitDebugThreadLocal(const MCExpr *Value, unsigned Size) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Dwarf Lowering Routines
|
||||
@ -511,7 +537,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
//===------------------------------------------------------------------===//
|
||||
// Inline Asm Support
|
||||
//===------------------------------------------------------------------===//
|
||||
public:
|
||||
|
||||
// These are hooks that targets can override to implement inline asm
|
||||
// support. These should probably be moved out of AsmPrinter someday.
|
||||
|
||||
@ -555,9 +581,9 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
private:
|
||||
/// Private state for PrintSpecial()
|
||||
// Assign a unique ID to this machine instruction.
|
||||
mutable const MachineInstr *LastMI;
|
||||
mutable unsigned LastFn;
|
||||
mutable unsigned Counter;
|
||||
mutable const MachineInstr *LastMI = nullptr;
|
||||
mutable unsigned LastFn = 0;
|
||||
mutable unsigned Counter = ~0U;
|
||||
|
||||
/// This method emits the header for the current function.
|
||||
virtual void EmitFunctionHeader();
|
||||
@ -596,6 +622,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
void emitGlobalIndirectSymbol(Module &M,
|
||||
const GlobalIndirectSymbol& GIS);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_ASMPRINTER_H
|
||||
|
@ -42,24 +42,6 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
typedef TargetTransformInfoImplCRTPBase<T> BaseT;
|
||||
typedef TargetTransformInfo TTI;
|
||||
|
||||
/// Estimate the overhead of scalarizing an instruction. Insert and Extract
|
||||
/// are set if the result needs to be inserted and/or extracted from vectors.
|
||||
unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) {
|
||||
assert(Ty->isVectorTy() && "Can only scalarize vectors");
|
||||
unsigned Cost = 0;
|
||||
|
||||
for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) {
|
||||
if (Insert)
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::InsertElement, Ty, i);
|
||||
if (Extract)
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::ExtractElement, Ty, i);
|
||||
}
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
/// Estimate a cost of shuffle as a sequence of extract and insert
|
||||
/// operations.
|
||||
unsigned getPermuteShuffleOverhead(Type *Ty) {
|
||||
@ -111,6 +93,11 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
|
||||
bool isSourceOfDivergence(const Value *V) { return false; }
|
||||
|
||||
unsigned getFlatAddressSpace() {
|
||||
// Return an invalid address space.
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool isLegalAddImmediate(int64_t imm) {
|
||||
return getTLI()->isLegalAddImmediate(imm);
|
||||
}
|
||||
@ -301,6 +288,67 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) { return 32; }
|
||||
|
||||
/// Estimate the overhead of scalarizing an instruction. Insert and Extract
|
||||
/// are set if the result needs to be inserted and/or extracted from vectors.
|
||||
unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) {
|
||||
assert(Ty->isVectorTy() && "Can only scalarize vectors");
|
||||
unsigned Cost = 0;
|
||||
|
||||
for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) {
|
||||
if (Insert)
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::InsertElement, Ty, i);
|
||||
if (Extract)
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::ExtractElement, Ty, i);
|
||||
}
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
/// Estimate the overhead of scalarizing an instructions unique
|
||||
/// non-constant operands. The types of the arguments are ordinarily
|
||||
/// scalar, in which case the costs are multiplied with VF.
|
||||
unsigned getOperandsScalarizationOverhead(ArrayRef<const Value *> Args,
|
||||
unsigned VF) {
|
||||
unsigned Cost = 0;
|
||||
SmallPtrSet<const Value*, 4> UniqueOperands;
|
||||
for (const Value *A : Args) {
|
||||
if (!isa<Constant>(A) && UniqueOperands.insert(A).second) {
|
||||
Type *VecTy = nullptr;
|
||||
if (A->getType()->isVectorTy()) {
|
||||
VecTy = A->getType();
|
||||
// If A is a vector operand, VF should be 1 or correspond to A.
|
||||
assert ((VF == 1 || VF == VecTy->getVectorNumElements()) &&
|
||||
"Vector argument does not match VF");
|
||||
}
|
||||
else
|
||||
VecTy = VectorType::get(A->getType(), VF);
|
||||
|
||||
Cost += getScalarizationOverhead(VecTy, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
unsigned getScalarizationOverhead(Type *VecTy, ArrayRef<const Value *> Args) {
|
||||
assert (VecTy->isVectorTy());
|
||||
|
||||
unsigned Cost = 0;
|
||||
|
||||
Cost += getScalarizationOverhead(VecTy, true, false);
|
||||
if (!Args.empty())
|
||||
Cost += getOperandsScalarizationOverhead(Args,
|
||||
VecTy->getVectorNumElements());
|
||||
else
|
||||
// When no information on arguments is provided, we add the cost
|
||||
// associated with one argument as a heuristic.
|
||||
Cost += getScalarizationOverhead(VecTy, false, true);
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) { return 1; }
|
||||
|
||||
unsigned getArithmeticInstrCost(
|
||||
@ -341,10 +389,9 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
unsigned Num = Ty->getVectorNumElements();
|
||||
unsigned Cost = static_cast<T *>(this)
|
||||
->getArithmeticInstrCost(Opcode, Ty->getScalarType());
|
||||
// return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting
|
||||
// and extracting the values.
|
||||
return getScalarizationOverhead(Ty, true, true) + Num * Cost;
|
||||
// Return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting and extracting the values.
|
||||
return getScalarizationOverhead(Ty, Args) + Num * Cost;
|
||||
}
|
||||
|
||||
// We don't know anything about this scalar instruction.
|
||||
@ -360,7 +407,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) {
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
|
||||
const Instruction *I = nullptr) {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
int ISD = TLI->InstructionOpcodeToISD(Opcode);
|
||||
assert(ISD && "Invalid opcode");
|
||||
@ -389,6 +437,18 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
Dst->getPointerAddressSpace()))
|
||||
return 0;
|
||||
|
||||
// If this is a zext/sext of a load, return 0 if the corresponding
|
||||
// extending load exists on target.
|
||||
if ((Opcode == Instruction::ZExt || Opcode == Instruction::SExt) &&
|
||||
I && isa<LoadInst>(I->getOperand(0))) {
|
||||
EVT ExtVT = EVT::getEVT(Dst);
|
||||
EVT LoadVT = EVT::getEVT(Src);
|
||||
unsigned LType =
|
||||
((Opcode == Instruction::ZExt) ? ISD::ZEXTLOAD : ISD::SEXTLOAD);
|
||||
if (TLI->isLoadExtLegal(LType, ExtVT, LoadVT))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the cast is marked as legal (or promote) then assume low cost.
|
||||
if (SrcLT.first == DstLT.first &&
|
||||
TLI->isOperationLegalOrPromote(ISD, DstLT.second))
|
||||
@ -446,14 +506,14 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
Src->getVectorNumElements() / 2);
|
||||
T *TTI = static_cast<T *>(this);
|
||||
return TTI->getVectorSplitCost() +
|
||||
(2 * TTI->getCastInstrCost(Opcode, SplitDst, SplitSrc));
|
||||
(2 * TTI->getCastInstrCost(Opcode, SplitDst, SplitSrc, I));
|
||||
}
|
||||
|
||||
// In other cases where the source or destination are illegal, assume
|
||||
// the operation will get scalarized.
|
||||
unsigned Num = Dst->getVectorNumElements();
|
||||
unsigned Cost = static_cast<T *>(this)->getCastInstrCost(
|
||||
Opcode, Dst->getScalarType(), Src->getScalarType());
|
||||
Opcode, Dst->getScalarType(), Src->getScalarType(), I);
|
||||
|
||||
// Return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting and extracting the values.
|
||||
@ -487,7 +547,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) {
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy,
|
||||
const Instruction *I) {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
int ISD = TLI->InstructionOpcodeToISD(Opcode);
|
||||
assert(ISD && "Invalid opcode");
|
||||
@ -515,7 +576,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
if (CondTy)
|
||||
CondTy = CondTy->getScalarType();
|
||||
unsigned Cost = static_cast<T *>(this)->getCmpSelInstrCost(
|
||||
Opcode, ValTy->getScalarType(), CondTy);
|
||||
Opcode, ValTy->getScalarType(), CondTy, I);
|
||||
|
||||
// Return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting and extracting the values.
|
||||
@ -534,7 +595,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
}
|
||||
|
||||
unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) {
|
||||
unsigned AddressSpace, const Instruction *I = nullptr) {
|
||||
assert(!Src->isVoidTy() && "Invalid type");
|
||||
std::pair<unsigned, MVT> LT = getTLI()->getTypeLegalizationCost(DL, Src);
|
||||
|
||||
@ -680,18 +741,42 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return Cost;
|
||||
}
|
||||
|
||||
/// Get intrinsic cost based on arguments
|
||||
/// Get intrinsic cost based on arguments.
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF) {
|
||||
ArrayRef<Value *> Args, FastMathFlags FMF,
|
||||
unsigned VF = 1) {
|
||||
unsigned RetVF = (RetTy->isVectorTy() ? RetTy->getVectorNumElements() : 1);
|
||||
assert ((RetVF == 1 || VF == 1) && "VF > 1 and RetVF is a vector type");
|
||||
|
||||
switch (IID) {
|
||||
default: {
|
||||
// Assume that we need to scalarize this intrinsic.
|
||||
SmallVector<Type *, 4> Types;
|
||||
for (Value *Op : Args)
|
||||
Types.push_back(Op->getType());
|
||||
return static_cast<T *>(this)->getIntrinsicInstrCost(IID, RetTy, Types,
|
||||
FMF);
|
||||
for (Value *Op : Args) {
|
||||
Type *OpTy = Op->getType();
|
||||
assert (VF == 1 || !OpTy->isVectorTy());
|
||||
Types.push_back(VF == 1 ? OpTy : VectorType::get(OpTy, VF));
|
||||
}
|
||||
|
||||
if (VF > 1 && !RetTy->isVoidTy())
|
||||
RetTy = VectorType::get(RetTy, VF);
|
||||
|
||||
// Compute the scalarization overhead based on Args for a vector
|
||||
// intrinsic. A vectorizer will pass a scalar RetTy and VF > 1, while
|
||||
// CostModel will pass a vector RetTy and VF is 1.
|
||||
unsigned ScalarizationCost = UINT_MAX;
|
||||
if (RetVF > 1 || VF > 1) {
|
||||
ScalarizationCost = 0;
|
||||
if (!RetTy->isVoidTy())
|
||||
ScalarizationCost += getScalarizationOverhead(RetTy, true, false);
|
||||
ScalarizationCost += getOperandsScalarizationOverhead(Args, VF);
|
||||
}
|
||||
|
||||
return static_cast<T *>(this)->
|
||||
getIntrinsicInstrCost(IID, RetTy, Types, FMF, ScalarizationCost);
|
||||
}
|
||||
case Intrinsic::masked_scatter: {
|
||||
assert (VF == 1 && "Can't vectorize types here.");
|
||||
Value *Mask = Args[3];
|
||||
bool VarMask = !isa<Constant>(Mask);
|
||||
unsigned Alignment = cast<ConstantInt>(Args[2])->getZExtValue();
|
||||
@ -702,6 +787,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
Alignment);
|
||||
}
|
||||
case Intrinsic::masked_gather: {
|
||||
assert (VF == 1 && "Can't vectorize types here.");
|
||||
Value *Mask = Args[2];
|
||||
bool VarMask = !isa<Constant>(Mask);
|
||||
unsigned Alignment = cast<ConstantInt>(Args[1])->getZExtValue();
|
||||
@ -713,19 +799,23 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get intrinsic cost based on argument types
|
||||
/// Get intrinsic cost based on argument types.
|
||||
/// If ScalarizationCostPassed is UINT_MAX, the cost of scalarizing the
|
||||
/// arguments and the return value will be computed based on types.
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF) {
|
||||
ArrayRef<Type *> Tys, FastMathFlags FMF,
|
||||
unsigned ScalarizationCostPassed = UINT_MAX) {
|
||||
SmallVector<unsigned, 2> ISDs;
|
||||
unsigned SingleCallCost = 10; // Library call cost. Make it expensive.
|
||||
switch (IID) {
|
||||
default: {
|
||||
// Assume that we need to scalarize this intrinsic.
|
||||
unsigned ScalarizationCost = 0;
|
||||
unsigned ScalarizationCost = ScalarizationCostPassed;
|
||||
unsigned ScalarCalls = 1;
|
||||
Type *ScalarRetTy = RetTy;
|
||||
if (RetTy->isVectorTy()) {
|
||||
ScalarizationCost = getScalarizationOverhead(RetTy, true, false);
|
||||
if (ScalarizationCostPassed == UINT_MAX)
|
||||
ScalarizationCost = getScalarizationOverhead(RetTy, true, false);
|
||||
ScalarCalls = std::max(ScalarCalls, RetTy->getVectorNumElements());
|
||||
ScalarRetTy = RetTy->getScalarType();
|
||||
}
|
||||
@ -733,7 +823,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) {
|
||||
Type *Ty = Tys[i];
|
||||
if (Ty->isVectorTy()) {
|
||||
ScalarizationCost += getScalarizationOverhead(Ty, false, true);
|
||||
if (ScalarizationCostPassed == UINT_MAX)
|
||||
ScalarizationCost += getScalarizationOverhead(Ty, false, true);
|
||||
ScalarCalls = std::max(ScalarCalls, Ty->getVectorNumElements());
|
||||
Ty = Ty->getScalarType();
|
||||
}
|
||||
@ -881,7 +972,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
// this will emit a costly libcall, adding call overhead and spills. Make it
|
||||
// very expensive.
|
||||
if (RetTy->isVectorTy()) {
|
||||
unsigned ScalarizationCost = getScalarizationOverhead(RetTy, true, false);
|
||||
unsigned ScalarizationCost = ((ScalarizationCostPassed != UINT_MAX) ?
|
||||
ScalarizationCostPassed : getScalarizationOverhead(RetTy, true, false));
|
||||
unsigned ScalarCalls = RetTy->getVectorNumElements();
|
||||
SmallVector<Type *, 4> ScalarTys;
|
||||
for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) {
|
||||
@ -894,7 +986,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
IID, RetTy->getScalarType(), ScalarTys, FMF);
|
||||
for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) {
|
||||
if (Tys[i]->isVectorTy()) {
|
||||
ScalarizationCost += getScalarizationOverhead(Tys[i], false, true);
|
||||
if (ScalarizationCostPassed == UINT_MAX)
|
||||
ScalarizationCost += getScalarizationOverhead(Tys[i], false, true);
|
||||
ScalarCalls = std::max(ScalarCalls, Tys[i]->getVectorNumElements());
|
||||
}
|
||||
}
|
||||
|
@ -183,11 +183,6 @@ typedef bool CCCustomFn(unsigned &ValNo, MVT &ValVT,
|
||||
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
||||
ISD::ArgFlagsTy &ArgFlags, CCState &State);
|
||||
|
||||
/// ParmContext - This enum tracks whether calling convention lowering is in
|
||||
/// the context of prologue or call generation. Not all backends make use of
|
||||
/// this information.
|
||||
typedef enum { Unknown, Prologue, Call } ParmContext;
|
||||
|
||||
/// CCState - This class holds information needed while lowering arguments and
|
||||
/// return values. It captures which registers are already assigned and which
|
||||
/// stack slots are used. It provides accessors to allocate these values.
|
||||
@ -256,9 +251,6 @@ class CCState {
|
||||
// during argument analysis.
|
||||
unsigned InRegsParamsProcessed;
|
||||
|
||||
protected:
|
||||
ParmContext CallOrPrologue;
|
||||
|
||||
public:
|
||||
CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
|
||||
SmallVectorImpl<CCValAssign> &locs, LLVMContext &C);
|
||||
@ -510,8 +502,6 @@ class CCState {
|
||||
InRegsParamsProcessed = 0;
|
||||
}
|
||||
|
||||
ParmContext getCallOrPrologue() const { return CallOrPrologue; }
|
||||
|
||||
// Get list of pending assignments
|
||||
SmallVectorImpl<llvm::CCValAssign> &getPendingLocs() {
|
||||
return PendingLocs;
|
||||
|
@ -118,11 +118,6 @@ FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile),
|
||||
clEnumValN(TargetMachine::CGFT_Null, "null",
|
||||
"Emit nothing, for performance testing")));
|
||||
|
||||
cl::opt<bool>
|
||||
EnableFPMAD("enable-fp-mad",
|
||||
cl::desc("Enable less precise MAD instructions to be generated"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool>
|
||||
DisableFPElim("disable-fp-elim",
|
||||
cl::desc("Disable frame pointer elimination optimization"),
|
||||
@ -143,6 +138,12 @@ EnableNoNaNsFPMath("enable-no-nans-fp-math",
|
||||
cl::desc("Enable FP math optimizations that assume no NaNs"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool>
|
||||
EnableNoSignedZerosFPMath("enable-no-signed-zeros-fp-math",
|
||||
cl::desc("Enable FP math optimizations that assume "
|
||||
"the sign of 0 is insignificant"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool>
|
||||
EnableNoTrappingFPMath("enable-no-trapping-fp-math",
|
||||
cl::desc("Enable setting the FP exceptions build "
|
||||
@ -277,11 +278,11 @@ DebuggerTuningOpt("debugger-tune",
|
||||
// a TargetOptions object with CodeGen flags and returns it.
|
||||
static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||
TargetOptions Options;
|
||||
Options.LessPreciseFPMADOption = EnableFPMAD;
|
||||
Options.AllowFPOpFusion = FuseFPOps;
|
||||
Options.UnsafeFPMath = EnableUnsafeFPMath;
|
||||
Options.NoInfsFPMath = EnableNoInfsFPMath;
|
||||
Options.NoNaNsFPMath = EnableNoNaNsFPMath;
|
||||
Options.NoSignedZerosFPMath = EnableNoSignedZerosFPMath;
|
||||
Options.NoTrappingFPMath = EnableNoTrappingFPMath;
|
||||
Options.FPDenormalMode = DenormalMode;
|
||||
Options.HonorSignDependentRoundingFPMathOption =
|
||||
@ -345,28 +346,28 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features,
|
||||
Module &M) {
|
||||
for (auto &F : M) {
|
||||
auto &Ctx = F.getContext();
|
||||
AttributeSet Attrs = F.getAttributes(), NewAttrs;
|
||||
AttributeList Attrs = F.getAttributes(), NewAttrs;
|
||||
|
||||
if (!CPU.empty())
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"target-cpu", CPU);
|
||||
|
||||
if (!Features.empty())
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"target-features", Features);
|
||||
|
||||
if (DisableFPElim.getNumOccurrences() > 0)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"no-frame-pointer-elim",
|
||||
DisableFPElim ? "true" : "false");
|
||||
|
||||
if (DisableTailCalls.getNumOccurrences() > 0)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"disable-tail-calls",
|
||||
toStringRef(DisableTailCalls));
|
||||
|
||||
if (StackRealign)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"stackrealign");
|
||||
|
||||
if (TrapFuncName.getNumOccurrences() > 0)
|
||||
@ -376,12 +377,12 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features,
|
||||
if (const auto *F = Call->getCalledFunction())
|
||||
if (F->getIntrinsicID() == Intrinsic::debugtrap ||
|
||||
F->getIntrinsicID() == Intrinsic::trap)
|
||||
Call->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
Attribute::get(Ctx, "trap-func-name",
|
||||
TrapFuncName));
|
||||
Call->addAttribute(
|
||||
llvm::AttributeList::FunctionIndex,
|
||||
Attribute::get(Ctx, "trap-func-name", TrapFuncName));
|
||||
|
||||
// Let NewAttrs override Attrs.
|
||||
NewAttrs = Attrs.addAttributes(Ctx, AttributeSet::FunctionIndex, NewAttrs);
|
||||
NewAttrs = Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs);
|
||||
F.setAttributes(NewAttrs);
|
||||
}
|
||||
}
|
||||
|
220
contrib/llvm/include/llvm/CodeGen/ExecutionDepsFix.h
Normal file
220
contrib/llvm/include/llvm/CodeGen/ExecutionDepsFix.h
Normal file
@ -0,0 +1,220 @@
|
||||
//===- llvm/CodeGen/ExecutionDepsFix.h - Execution Dependency Fix -*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file Execution Dependency Fix pass.
|
||||
///
|
||||
/// Some X86 SSE instructions like mov, and, or, xor are available in different
|
||||
/// variants for different operand types. These variant instructions are
|
||||
/// equivalent, but on Nehalem and newer cpus there is extra latency
|
||||
/// transferring data between integer and floating point domains. ARM cores
|
||||
/// have similar issues when they are configured with both VFP and NEON
|
||||
/// pipelines.
|
||||
///
|
||||
/// This pass changes the variant instructions to minimize domain crossings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CODEGEN_EXECUTIONDEPSFIX_H
|
||||
#define LLVM_CODEGEN_EXECUTIONDEPSFIX_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LivePhysRegs.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/RegisterClassInfo.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A DomainValue is a bit like LiveIntervals' ValNo, but it also keeps track
|
||||
/// of execution domains.
|
||||
///
|
||||
/// An open DomainValue represents a set of instructions that can still switch
|
||||
/// execution domain. Multiple registers may refer to the same open
|
||||
/// DomainValue - they will eventually be collapsed to the same execution
|
||||
/// domain.
|
||||
///
|
||||
/// A collapsed DomainValue represents a single register that has been forced
|
||||
/// into one of more execution domains. There is a separate collapsed
|
||||
/// DomainValue for each register, but it may contain multiple execution
|
||||
/// domains. A register value is initially created in a single execution
|
||||
/// domain, but if we were forced to pay the penalty of a domain crossing, we
|
||||
/// keep track of the fact that the register is now available in multiple
|
||||
/// domains.
|
||||
struct DomainValue {
|
||||
// Basic reference counting.
|
||||
unsigned Refs;
|
||||
|
||||
// Bitmask of available domains. For an open DomainValue, it is the still
|
||||
// possible domains for collapsing. For a collapsed DomainValue it is the
|
||||
// domains where the register is available for free.
|
||||
unsigned AvailableDomains;
|
||||
|
||||
// Pointer to the next DomainValue in a chain. When two DomainValues are
|
||||
// merged, Victim.Next is set to point to Victor, so old DomainValue
|
||||
// references can be updated by following the chain.
|
||||
DomainValue *Next;
|
||||
|
||||
// Twiddleable instructions using or defining these registers.
|
||||
SmallVector<MachineInstr*, 8> Instrs;
|
||||
|
||||
// A collapsed DomainValue has no instructions to twiddle - it simply keeps
|
||||
// track of the domains where the registers are already available.
|
||||
bool isCollapsed() const { return Instrs.empty(); }
|
||||
|
||||
// Is domain available?
|
||||
bool hasDomain(unsigned domain) const {
|
||||
assert(domain <
|
||||
static_cast<unsigned>(std::numeric_limits<unsigned>::digits) &&
|
||||
"undefined behavior");
|
||||
return AvailableDomains & (1u << domain);
|
||||
}
|
||||
|
||||
// Mark domain as available.
|
||||
void addDomain(unsigned domain) {
|
||||
AvailableDomains |= 1u << domain;
|
||||
}
|
||||
|
||||
// Restrict to a single domain available.
|
||||
void setSingleDomain(unsigned domain) {
|
||||
AvailableDomains = 1u << domain;
|
||||
}
|
||||
|
||||
// Return bitmask of domains that are available and in mask.
|
||||
unsigned getCommonDomains(unsigned mask) const {
|
||||
return AvailableDomains & mask;
|
||||
}
|
||||
|
||||
// First domain available.
|
||||
unsigned getFirstDomain() const {
|
||||
return countTrailingZeros(AvailableDomains);
|
||||
}
|
||||
|
||||
DomainValue() : Refs(0) { clear(); }
|
||||
|
||||
// Clear this DomainValue and point to next which has all its data.
|
||||
void clear() {
|
||||
AvailableDomains = 0;
|
||||
Next = nullptr;
|
||||
Instrs.clear();
|
||||
}
|
||||
};
|
||||
|
||||
/// Information about a live register.
|
||||
struct LiveReg {
|
||||
/// Value currently in this register, or NULL when no value is being tracked.
|
||||
/// This counts as a DomainValue reference.
|
||||
DomainValue *Value;
|
||||
|
||||
/// Instruction that defined this register, relative to the beginning of the
|
||||
/// current basic block. When a LiveReg is used to represent a live-out
|
||||
/// register, this value is relative to the end of the basic block, so it
|
||||
/// will be a negative number.
|
||||
int Def;
|
||||
};
|
||||
|
||||
class ExecutionDepsFix : public MachineFunctionPass {
|
||||
SpecificBumpPtrAllocator<DomainValue> Allocator;
|
||||
SmallVector<DomainValue*,16> Avail;
|
||||
|
||||
const TargetRegisterClass *const RC;
|
||||
MachineFunction *MF;
|
||||
const TargetInstrInfo *TII;
|
||||
const TargetRegisterInfo *TRI;
|
||||
RegisterClassInfo RegClassInfo;
|
||||
std::vector<SmallVector<int, 1>> AliasMap;
|
||||
const unsigned NumRegs;
|
||||
LiveReg *LiveRegs;
|
||||
struct MBBInfo {
|
||||
// Keeps clearance and domain information for all registers. Note that this
|
||||
// is different from the usual definition notion of liveness. The CPU
|
||||
// doesn't care whether or not we consider a register killed.
|
||||
LiveReg *OutRegs;
|
||||
|
||||
// Whether we have gotten to this block in primary processing yet.
|
||||
bool PrimaryCompleted;
|
||||
|
||||
// The number of predecessors for which primary processing has completed
|
||||
unsigned IncomingProcessed;
|
||||
|
||||
// The value of `IncomingProcessed` at the start of primary processing
|
||||
unsigned PrimaryIncoming;
|
||||
|
||||
// The number of predecessors for which all processing steps are done.
|
||||
unsigned IncomingCompleted;
|
||||
|
||||
MBBInfo()
|
||||
: OutRegs(nullptr), PrimaryCompleted(false), IncomingProcessed(0),
|
||||
PrimaryIncoming(0), IncomingCompleted(0) {}
|
||||
};
|
||||
typedef DenseMap<MachineBasicBlock *, MBBInfo> MBBInfoMap;
|
||||
MBBInfoMap MBBInfos;
|
||||
|
||||
/// List of undefined register reads in this block in forward order.
|
||||
std::vector<std::pair<MachineInstr*, unsigned> > UndefReads;
|
||||
|
||||
/// Storage for register unit liveness.
|
||||
LivePhysRegs LiveRegSet;
|
||||
|
||||
/// Current instruction number.
|
||||
/// The first instruction in each basic block is 0.
|
||||
int CurInstr;
|
||||
public:
|
||||
ExecutionDepsFix(char &PassID, const TargetRegisterClass &RC)
|
||||
: MachineFunctionPass(PassID), RC(&RC), NumRegs(RC.getNumRegs()) {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
||||
private:
|
||||
iterator_range<SmallVectorImpl<int>::const_iterator>
|
||||
regIndices(unsigned Reg) const;
|
||||
// DomainValue allocation.
|
||||
DomainValue *alloc(int domain = -1);
|
||||
DomainValue *retain(DomainValue *DV) {
|
||||
if (DV) ++DV->Refs;
|
||||
return DV;
|
||||
}
|
||||
void release(DomainValue*);
|
||||
DomainValue *resolve(DomainValue*&);
|
||||
|
||||
// LiveRegs manipulations.
|
||||
void setLiveReg(int rx, DomainValue *DV);
|
||||
void kill(int rx);
|
||||
void force(int rx, unsigned domain);
|
||||
void collapse(DomainValue *dv, unsigned domain);
|
||||
bool merge(DomainValue *A, DomainValue *B);
|
||||
|
||||
void enterBasicBlock(MachineBasicBlock*);
|
||||
void leaveBasicBlock(MachineBasicBlock*);
|
||||
bool isBlockDone(MachineBasicBlock *);
|
||||
void processBasicBlock(MachineBasicBlock *MBB, bool PrimaryPass);
|
||||
bool visitInstr(MachineInstr *);
|
||||
void processDefs(MachineInstr *, bool breakDependency, bool Kill);
|
||||
void visitSoftInstr(MachineInstr*, unsigned mask);
|
||||
void visitHardInstr(MachineInstr*, unsigned domain);
|
||||
bool pickBestRegisterForUndef(MachineInstr *MI, unsigned OpIdx,
|
||||
unsigned Pref);
|
||||
bool shouldBreakDependence(MachineInstr*, unsigned OpIdx, unsigned Pref);
|
||||
void processUndefReads(MachineBasicBlock*);
|
||||
};
|
||||
|
||||
} // end namepsace llvm
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===-- FastISel.h - Definition of the FastISel class ---*- C++ -*---------===//
|
||||
//===- FastISel.h - Definition of the FastISel class ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -16,10 +16,21 @@
|
||||
#define LLVM_CODEGEN_FASTISEL_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineValueType.h"
|
||||
#include "llvm/IR/Attributes.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -30,57 +41,31 @@ class MachineConstantPool;
|
||||
/// quickly.
|
||||
class FastISel {
|
||||
public:
|
||||
struct ArgListEntry {
|
||||
Value *Val;
|
||||
Type *Ty;
|
||||
bool IsSExt : 1;
|
||||
bool IsZExt : 1;
|
||||
bool IsInReg : 1;
|
||||
bool IsSRet : 1;
|
||||
bool IsNest : 1;
|
||||
bool IsByVal : 1;
|
||||
bool IsInAlloca : 1;
|
||||
bool IsReturned : 1;
|
||||
bool IsSwiftSelf : 1;
|
||||
bool IsSwiftError : 1;
|
||||
uint16_t Alignment;
|
||||
|
||||
ArgListEntry()
|
||||
: Val(nullptr), Ty(nullptr), IsSExt(false), IsZExt(false),
|
||||
IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false),
|
||||
IsInAlloca(false), IsReturned(false), IsSwiftSelf(false),
|
||||
IsSwiftError(false), Alignment(0) {}
|
||||
|
||||
/// \brief Set CallLoweringInfo attribute flags based on a call instruction
|
||||
/// and called function attributes.
|
||||
void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx);
|
||||
};
|
||||
typedef std::vector<ArgListEntry> ArgListTy;
|
||||
|
||||
typedef TargetLoweringBase::ArgListEntry ArgListEntry;
|
||||
typedef TargetLoweringBase::ArgListTy ArgListTy;
|
||||
struct CallLoweringInfo {
|
||||
Type *RetTy;
|
||||
Type *RetTy = nullptr;
|
||||
bool RetSExt : 1;
|
||||
bool RetZExt : 1;
|
||||
bool IsVarArg : 1;
|
||||
bool IsInReg : 1;
|
||||
bool DoesNotReturn : 1;
|
||||
bool IsReturnValueUsed : 1;
|
||||
bool IsPatchPoint : 1;
|
||||
|
||||
// \brief IsTailCall Should be modified by implementations of FastLowerCall
|
||||
// that perform tail call conversions.
|
||||
bool IsTailCall;
|
||||
bool IsTailCall = false;
|
||||
|
||||
unsigned NumFixedArgs;
|
||||
CallingConv::ID CallConv;
|
||||
const Value *Callee;
|
||||
MCSymbol *Symbol;
|
||||
unsigned NumFixedArgs = -1;
|
||||
CallingConv::ID CallConv = CallingConv::C;
|
||||
const Value *Callee = nullptr;
|
||||
MCSymbol *Symbol = nullptr;
|
||||
ArgListTy Args;
|
||||
ImmutableCallSite *CS;
|
||||
MachineInstr *Call;
|
||||
unsigned ResultReg;
|
||||
unsigned NumResultRegs;
|
||||
|
||||
bool IsPatchPoint;
|
||||
ImmutableCallSite *CS = nullptr;
|
||||
MachineInstr *Call = nullptr;
|
||||
unsigned ResultReg = 0;
|
||||
unsigned NumResultRegs = 0;
|
||||
|
||||
SmallVector<Value *, 16> OutVals;
|
||||
SmallVector<ISD::ArgFlagsTy, 16> OutFlags;
|
||||
@ -89,11 +74,8 @@ class FastISel {
|
||||
SmallVector<unsigned, 4> InRegs;
|
||||
|
||||
CallLoweringInfo()
|
||||
: RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false),
|
||||
IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true),
|
||||
IsTailCall(false), NumFixedArgs(-1), CallConv(CallingConv::C),
|
||||
Callee(nullptr), Symbol(nullptr), CS(nullptr), Call(nullptr),
|
||||
ResultReg(0), NumResultRegs(0), IsPatchPoint(false) {}
|
||||
: RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false),
|
||||
DoesNotReturn(false), IsReturnValueUsed(true), IsPatchPoint(false) {}
|
||||
|
||||
CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
|
||||
const Value *Target, ArgListTy &&ArgsList,
|
||||
@ -101,12 +83,12 @@ class FastISel {
|
||||
RetTy = ResultTy;
|
||||
Callee = Target;
|
||||
|
||||
IsInReg = Call.paramHasAttr(0, Attribute::InReg);
|
||||
IsInReg = Call.hasRetAttr(Attribute::InReg);
|
||||
DoesNotReturn = Call.doesNotReturn();
|
||||
IsVarArg = FuncTy->isVarArg();
|
||||
IsReturnValueUsed = !Call.getInstruction()->use_empty();
|
||||
RetSExt = Call.paramHasAttr(0, Attribute::SExt);
|
||||
RetZExt = Call.paramHasAttr(0, Attribute::ZExt);
|
||||
RetSExt = Call.hasRetAttr(Attribute::SExt);
|
||||
RetZExt = Call.hasRetAttr(Attribute::ZExt);
|
||||
|
||||
CallConv = Call.getCallingConv();
|
||||
Args = std::move(ArgsList);
|
||||
@ -125,12 +107,12 @@ class FastISel {
|
||||
Callee = Call.getCalledValue();
|
||||
Symbol = Target;
|
||||
|
||||
IsInReg = Call.paramHasAttr(0, Attribute::InReg);
|
||||
IsInReg = Call.hasRetAttr(Attribute::InReg);
|
||||
DoesNotReturn = Call.doesNotReturn();
|
||||
IsVarArg = FuncTy->isVarArg();
|
||||
IsReturnValueUsed = !Call.getInstruction()->use_empty();
|
||||
RetSExt = Call.paramHasAttr(0, Attribute::SExt);
|
||||
RetZExt = Call.paramHasAttr(0, Attribute::ZExt);
|
||||
RetSExt = Call.hasRetAttr(Attribute::SExt);
|
||||
RetZExt = Call.hasRetAttr(Attribute::ZExt);
|
||||
|
||||
CallConv = Call.getCallingConv();
|
||||
Args = std::move(ArgsList);
|
||||
@ -510,7 +492,6 @@ class FastISel {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool lowerCall(const CallInst *I);
|
||||
/// \brief Select and emit code for a binary operator instruction, which has
|
||||
/// an opcode which directly corresponds to the given ISD opcode.
|
||||
@ -567,4 +548,4 @@ class FastISel {
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_FASTISEL_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===------------------- FaultMaps.h - The "FaultMaps" section --*- C++ -*-===//
|
||||
//===- FaultMaps.h - The "FaultMaps" section --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -12,26 +12,31 @@
|
||||
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class MCExpr;
|
||||
class MCSymbol;
|
||||
class MCStreamer;
|
||||
class raw_ostream;
|
||||
|
||||
class FaultMaps {
|
||||
public:
|
||||
enum FaultKind { FaultingLoad = 1, FaultKindMax };
|
||||
|
||||
static const char *faultTypeToString(FaultKind);
|
||||
enum FaultKind {
|
||||
FaultingLoad = 1,
|
||||
FaultingLoadStore,
|
||||
FaultingStore,
|
||||
FaultKindMax
|
||||
};
|
||||
|
||||
explicit FaultMaps(AsmPrinter &AP);
|
||||
|
||||
static const char *faultTypeToString(FaultKind);
|
||||
|
||||
void recordFaultingOp(FaultKind FaultTy, const MCSymbol *HandlerLabel);
|
||||
void serializeToFaultMapSection();
|
||||
|
||||
@ -39,13 +44,11 @@ class FaultMaps {
|
||||
static const char *WFMP;
|
||||
|
||||
struct FaultInfo {
|
||||
FaultKind Kind;
|
||||
const MCExpr *FaultingOffsetExpr;
|
||||
const MCExpr *HandlerOffsetExpr;
|
||||
FaultKind Kind = FaultKindMax;
|
||||
const MCExpr *FaultingOffsetExpr = nullptr;
|
||||
const MCExpr *HandlerOffsetExpr = nullptr;
|
||||
|
||||
FaultInfo()
|
||||
: Kind(FaultKindMax), FaultingOffsetExpr(nullptr),
|
||||
HandlerOffsetExpr(nullptr) {}
|
||||
FaultInfo() = default;
|
||||
|
||||
explicit FaultInfo(FaultMaps::FaultKind Kind, const MCExpr *FaultingOffset,
|
||||
const MCExpr *HandlerOffset)
|
||||
@ -153,11 +156,11 @@ class FaultMapParser {
|
||||
|
||||
static const size_t FunctionInfoHeaderSize = FunctionFaultInfosOffset;
|
||||
|
||||
const uint8_t *P;
|
||||
const uint8_t *E;
|
||||
const uint8_t *P = nullptr;
|
||||
const uint8_t *E = nullptr;
|
||||
|
||||
public:
|
||||
FunctionInfoAccessor() : P(nullptr), E(nullptr) {}
|
||||
FunctionInfoAccessor() = default;
|
||||
|
||||
explicit FunctionInfoAccessor(const uint8_t *P, const uint8_t *E)
|
||||
: P(P), E(E) {}
|
||||
@ -214,6 +217,6 @@ raw_ostream &operator<<(raw_ostream &OS,
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const FaultMapParser &);
|
||||
|
||||
} // namespace llvm
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_FAULTMAPS_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/GCStrategy.h - Garbage collection ----------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/GCStrategy.h - Garbage collection -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -47,19 +47,20 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_IR_GCSTRATEGY_H
|
||||
#define LLVM_IR_GCSTRATEGY_H
|
||||
#ifndef LLVM_CODEGEN_GCSTRATEGY_H
|
||||
#define LLVM_CODEGEN_GCSTRATEGY_H
|
||||
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Registry.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Type;
|
||||
|
||||
namespace GC {
|
||||
|
||||
/// PointKind - Used to indicate whether the address of the call instruction
|
||||
/// or the address after the call instruction is listed in the stackmap. For
|
||||
/// most runtimes, PostCall safepoints are appropriate.
|
||||
@ -68,7 +69,8 @@ enum PointKind {
|
||||
PreCall, ///< Instr is a call instruction.
|
||||
PostCall ///< Instr is the return address of a call.
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace GC
|
||||
|
||||
/// GCStrategy describes a garbage collector algorithm's code generation
|
||||
/// requirements, and provides overridable hooks for those needs which cannot
|
||||
@ -77,24 +79,25 @@ enum PointKind {
|
||||
/// be immutable.
|
||||
class GCStrategy {
|
||||
private:
|
||||
std::string Name;
|
||||
friend class GCModuleInfo;
|
||||
|
||||
protected:
|
||||
bool UseStatepoints; /// Uses gc.statepoints as opposed to gc.roots,
|
||||
/// if set, none of the other options can be
|
||||
/// anything but their default values.
|
||||
std::string Name;
|
||||
|
||||
unsigned NeededSafePoints; ///< Bitmask of required safe points.
|
||||
bool CustomReadBarriers; ///< Default is to insert loads.
|
||||
bool CustomWriteBarriers; ///< Default is to insert stores.
|
||||
bool CustomRoots; ///< Default is to pass through to backend.
|
||||
bool InitRoots; ///< If set, roots are nulled during lowering.
|
||||
bool UsesMetadata; ///< If set, backend must emit metadata tables.
|
||||
protected:
|
||||
bool UseStatepoints = false; /// Uses gc.statepoints as opposed to gc.roots,
|
||||
/// if set, none of the other options can be
|
||||
/// anything but their default values.
|
||||
|
||||
unsigned NeededSafePoints = 0; ///< Bitmask of required safe points.
|
||||
bool CustomReadBarriers = false; ///< Default is to insert loads.
|
||||
bool CustomWriteBarriers = false; ///< Default is to insert stores.
|
||||
bool CustomRoots = false; ///< Default is to pass through to backend.
|
||||
bool InitRoots= true; ///< If set, roots are nulled during lowering.
|
||||
bool UsesMetadata = false; ///< If set, backend must emit metadata tables.
|
||||
|
||||
public:
|
||||
GCStrategy();
|
||||
virtual ~GCStrategy() {}
|
||||
virtual ~GCStrategy() = default;
|
||||
|
||||
/// Return the name of the GC strategy. This is the value of the collector
|
||||
/// name string specified on functions which use this strategy.
|
||||
@ -172,6 +175,7 @@ class GCStrategy {
|
||||
/// register your GCMetadataPrinter subclass with the
|
||||
/// GCMetadataPrinterRegistery as well.
|
||||
typedef Registry<GCStrategy> GCRegistry;
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GCSTRATEGY_H
|
||||
|
@ -35,9 +35,11 @@ class CallLowering {
|
||||
unsigned Reg;
|
||||
Type *Ty;
|
||||
ISD::ArgFlagsTy Flags;
|
||||
bool IsFixed;
|
||||
|
||||
ArgInfo(unsigned Reg, Type *Ty, ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy{})
|
||||
: Reg(Reg), Ty(Ty), Flags(Flags) {}
|
||||
ArgInfo(unsigned Reg, Type *Ty, ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy{},
|
||||
bool IsFixed = true)
|
||||
: Reg(Reg), Ty(Ty), Flags(Flags), IsFixed(IsFixed) {}
|
||||
};
|
||||
|
||||
/// Argument handling is mostly uniform between the four places that
|
||||
@ -68,15 +70,34 @@ class CallLowering {
|
||||
uint64_t Size, MachinePointerInfo &MPO,
|
||||
CCValAssign &VA) = 0;
|
||||
|
||||
/// Handle custom values, which may be passed into one or more of \p VAs.
|
||||
/// \return The number of \p VAs that have been assigned after the first
|
||||
/// one, and which should therefore be skipped from further
|
||||
/// processing.
|
||||
virtual unsigned assignCustomValue(const ArgInfo &Arg,
|
||||
ArrayRef<CCValAssign> VAs) {
|
||||
// This is not a pure virtual method because not all targets need to worry
|
||||
// about custom values.
|
||||
llvm_unreachable("Custom values not supported");
|
||||
}
|
||||
|
||||
unsigned extendRegister(unsigned ValReg, CCValAssign &VA);
|
||||
|
||||
ValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
|
||||
: MIRBuilder(MIRBuilder), MRI(MRI) {}
|
||||
virtual bool assignArg(unsigned ValNo, MVT ValVT, MVT LocVT,
|
||||
CCValAssign::LocInfo LocInfo, const ArgInfo &Info,
|
||||
CCState &State) {
|
||||
return AssignFn(ValNo, ValVT, LocVT, LocInfo, Info.Flags, State);
|
||||
}
|
||||
|
||||
ValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
|
||||
CCAssignFn *AssignFn)
|
||||
: MIRBuilder(MIRBuilder), MRI(MRI), AssignFn(AssignFn) {}
|
||||
|
||||
virtual ~ValueHandler() {}
|
||||
|
||||
MachineIRBuilder &MIRBuilder;
|
||||
MachineRegisterInfo &MRI;
|
||||
CCAssignFn *AssignFn;
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -96,12 +117,12 @@ class CallLowering {
|
||||
void setArgFlags(ArgInfo &Arg, unsigned OpNum, const DataLayout &DL,
|
||||
const FuncInfoTy &FuncInfo) const;
|
||||
|
||||
/// Invoke the \p AssignFn on each of the given \p Args and then use
|
||||
/// Invoke Handler::assignArg on each of the given \p Args and then use
|
||||
/// \p Callback to move them to the assigned locations.
|
||||
///
|
||||
/// \return True if everything has succeeded, false otherwise.
|
||||
bool handleAssignments(MachineIRBuilder &MIRBuilder, CCAssignFn *AssignFn,
|
||||
ArrayRef<ArgInfo> Args, ValueHandler &Callback) const;
|
||||
bool handleAssignments(MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args,
|
||||
ValueHandler &Callback) const;
|
||||
|
||||
public:
|
||||
CallLowering(const TargetLowering *TLI) : TLI(TLI) {}
|
||||
@ -135,6 +156,8 @@ class CallLowering {
|
||||
/// This hook must be implemented to lower the given call instruction,
|
||||
/// including argument and return value marshalling.
|
||||
///
|
||||
/// \p CallConv is the calling convention to be used for the call.
|
||||
///
|
||||
/// \p Callee is the destination of the call. It should be either a register,
|
||||
/// globaladdress, or externalsymbol.
|
||||
///
|
||||
@ -150,14 +173,16 @@ class CallLowering {
|
||||
/// needs to be passed.
|
||||
///
|
||||
/// \return true if the lowering succeeded, false otherwise.
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder,
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
|
||||
const MachineOperand &Callee, const ArgInfo &OrigRet,
|
||||
ArrayRef<ArgInfo> OrigArgs) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This hook must be implemented to lower the given call instruction,
|
||||
/// including argument and return value marshalling.
|
||||
/// Lower the given call instruction, including argument and return value
|
||||
/// marshalling.
|
||||
///
|
||||
/// \p CI is the call/invoke instruction.
|
||||
///
|
||||
/// \p ResReg is a register where the call's return value should be stored (or
|
||||
/// 0 if there is no return value).
|
||||
@ -171,9 +196,9 @@ class CallLowering {
|
||||
/// range of an immediate jump.
|
||||
///
|
||||
/// \return true if the lowering succeeded, false otherwise.
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder, const CallInst &CI,
|
||||
unsigned ResReg, ArrayRef<unsigned> ArgRegs,
|
||||
std::function<unsigned()> GetCalleeReg) const;
|
||||
bool lowerCall(MachineIRBuilder &MIRBuilder, ImmutableCallSite CS,
|
||||
unsigned ResReg, ArrayRef<unsigned> ArgRegs,
|
||||
std::function<unsigned()> GetCalleeReg) const;
|
||||
};
|
||||
} // End namespace llvm.
|
||||
|
||||
|
@ -34,6 +34,7 @@ class Instruction;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class OptimizationRemarkEmitter;
|
||||
class MachineRegisterInfo;
|
||||
class TargetPassConfig;
|
||||
|
||||
@ -55,21 +56,20 @@ class IRTranslator : public MachineFunctionPass {
|
||||
/// Mapping of the values of the current LLVM IR function
|
||||
/// to the related virtual registers.
|
||||
ValueToVReg ValToVReg;
|
||||
// Constants are special because when we encounter one,
|
||||
// we do not know at first where to insert the definition since
|
||||
// this depends on all its uses.
|
||||
// Thus, we will insert the sequences to materialize them when
|
||||
// we know all their users.
|
||||
// In the meantime, just keep it in a set.
|
||||
// Note: Constants that end up as immediate in the related instructions,
|
||||
// do not appear in that map.
|
||||
SmallSetVector<const Constant *, 8> Constants;
|
||||
|
||||
// N.b. it's not completely obvious that this will be sufficient for every
|
||||
// LLVM IR construct (with "invoke" being the obvious candidate to mess up our
|
||||
// lives.
|
||||
DenseMap<const BasicBlock *, MachineBasicBlock *> BBToMBB;
|
||||
|
||||
// One BasicBlock can be translated to multiple MachineBasicBlocks. For such
|
||||
// BasicBlocks translated to multiple MachineBasicBlocks, MachinePreds retains
|
||||
// a mapping between the edges arriving at the BasicBlock to the corresponding
|
||||
// created MachineBasicBlocks. Some BasicBlocks that get translated to a
|
||||
// single MachineBasicBlock may also end up in this Map.
|
||||
typedef std::pair<const BasicBlock *, const BasicBlock *> CFGEdge;
|
||||
DenseMap<CFGEdge, SmallVector<MachineBasicBlock *, 1>> MachinePreds;
|
||||
|
||||
// List of stubbed PHI instructions, for values and basic blocks to be filled
|
||||
// in once all MachineBasicBlocks have been created.
|
||||
SmallVector<std::pair<const PHINode *, MachineInstr *>, 4> PendingPHIs;
|
||||
@ -122,7 +122,9 @@ class IRTranslator : public MachineFunctionPass {
|
||||
/// Translate an LLVM store instruction into generic IR.
|
||||
bool translateStore(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateMemcpy(const CallInst &CI, MachineIRBuilder &MIRBuilder);
|
||||
/// Translate an LLVM string intrinsic (memcpy, memset, ...).
|
||||
bool translateMemfunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
|
||||
unsigned Intrinsic);
|
||||
|
||||
void getStackGuard(unsigned DstReg, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
@ -132,6 +134,8 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateInlineAsm(const CallInst &CI, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate call instruction.
|
||||
/// \pre \p U is a call instruction.
|
||||
bool translateCall(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
@ -145,11 +149,6 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool translateCast(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate static alloca instruction (i.e. one of constant size and in the
|
||||
/// first basic block).
|
||||
bool translateStaticAlloca(const AllocaInst &Inst,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate a phi instruction.
|
||||
bool translatePHI(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
@ -182,6 +181,8 @@ class IRTranslator : public MachineFunctionPass {
|
||||
|
||||
bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
@ -190,12 +191,16 @@ class IRTranslator : public MachineFunctionPass {
|
||||
|
||||
bool translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate return (ret) instruction.
|
||||
/// The target needs to implement CallLowering::lowerReturn for
|
||||
/// this to succeed.
|
||||
/// \pre \p U is a return instruction.
|
||||
bool translateRet(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder);
|
||||
}
|
||||
@ -227,9 +232,6 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder);
|
||||
}
|
||||
bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateStaticAlloca(cast<AllocaInst>(U), MIRBuilder);
|
||||
}
|
||||
bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder);
|
||||
}
|
||||
@ -281,9 +283,6 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool translateFAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FADD, U, MIRBuilder);
|
||||
}
|
||||
bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder);
|
||||
}
|
||||
bool translateFMul(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FMUL, U, MIRBuilder);
|
||||
}
|
||||
@ -294,11 +293,16 @@ class IRTranslator : public MachineFunctionPass {
|
||||
return translateBinaryOp(TargetOpcode::G_FREM, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
// Stubs to keep the compiler happy while we implement the rest of the
|
||||
// translation.
|
||||
bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
@ -335,18 +339,6 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
@ -371,6 +363,9 @@ class IRTranslator : public MachineFunctionPass {
|
||||
/// Current target configuration. Controls how the pass handles errors.
|
||||
const TargetPassConfig *TPC;
|
||||
|
||||
/// Current optimization remark emitter. Used to report failures.
|
||||
std::unique_ptr<OptimizationRemarkEmitter> ORE;
|
||||
|
||||
// * Insert all the code needed to materialize the constants
|
||||
// at the proper place. E.g., Entry block or dominator block
|
||||
// of each constant depending on how fancy we want to be.
|
||||
@ -390,10 +385,27 @@ class IRTranslator : public MachineFunctionPass {
|
||||
/// the type being accessed (according to the Module's DataLayout).
|
||||
unsigned getMemOpAlignment(const Instruction &I);
|
||||
|
||||
/// Get the MachineBasicBlock that represents \p BB.
|
||||
/// If such basic block does not exist, it is created.
|
||||
MachineBasicBlock &getOrCreateBB(const BasicBlock &BB);
|
||||
/// Get the MachineBasicBlock that represents \p BB. Specifically, the block
|
||||
/// returned will be the head of the translated block (suitable for branch
|
||||
/// destinations).
|
||||
MachineBasicBlock &getMBB(const BasicBlock &BB);
|
||||
|
||||
/// Record \p NewPred as a Machine predecessor to `Edge.second`, corresponding
|
||||
/// to `Edge.first` at the IR level. This is used when IRTranslation creates
|
||||
/// multiple MachineBasicBlocks for a given IR block and the CFG is no longer
|
||||
/// represented simply by the IR-level CFG.
|
||||
void addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred);
|
||||
|
||||
/// Returns the Machine IR predecessors for the given IR CFG edge. Usually
|
||||
/// this is just the single MachineBasicBlock corresponding to the predecessor
|
||||
/// in the IR. More complex lowering can result in multiple MachineBasicBlocks
|
||||
/// preceding the original though (e.g. switch instructions).
|
||||
SmallVector<MachineBasicBlock *, 1> getMachinePredBBs(CFGEdge Edge) {
|
||||
auto RemappedEdge = MachinePreds.find(Edge);
|
||||
if (RemappedEdge != MachinePreds.end())
|
||||
return RemappedEdge->second;
|
||||
return SmallVector<MachineBasicBlock *, 4>(1, &getMBB(*Edge.first));
|
||||
}
|
||||
|
||||
public:
|
||||
// Ctor, nothing fancy.
|
||||
@ -407,13 +419,13 @@ class IRTranslator : public MachineFunctionPass {
|
||||
// CallLowering = MF.subtarget.getCallLowering()
|
||||
// F = MF.getParent()
|
||||
// MIRBuilder.reset(MF)
|
||||
// MIRBuilder.getOrCreateBB(F.getEntryBB())
|
||||
// getMBB(F.getEntryBB())
|
||||
// CallLowering->translateArguments(MIRBuilder, F, ValToVReg)
|
||||
// for each bb in F
|
||||
// MIRBuilder.getOrCreateBB(bb)
|
||||
// getMBB(bb)
|
||||
// for each inst in bb
|
||||
// if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence))
|
||||
// report_fatal_error(“Don’t know how to translate input");
|
||||
// report_fatal_error("Don't know how to translate input");
|
||||
// finalize()
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
@ -16,8 +16,13 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
class MachineInstr;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class RegisterBankInfo;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterInfo;
|
||||
@ -56,6 +61,14 @@ class InstructionSelector {
|
||||
const TargetInstrInfo &TII,
|
||||
const TargetRegisterInfo &TRI,
|
||||
const RegisterBankInfo &RBI) const;
|
||||
|
||||
Optional<int64_t> getConstantVRegVal(unsigned VReg,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
bool isObviouslySafeToFold(MachineInstr &MI) const;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
|
@ -58,6 +58,9 @@ class Legalizer : public MachineFunctionPass {
|
||||
bool combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI,
|
||||
const TargetInstrInfo &TII);
|
||||
|
||||
bool combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI,
|
||||
const TargetInstrInfo &TII);
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
} // End namespace llvm.
|
||||
|
@ -55,11 +55,7 @@ class LegalizerHelper {
|
||||
///
|
||||
/// Considered as an opaque blob, the legal code will use and define the same
|
||||
/// registers as \p MI.
|
||||
LegalizeResult legalizeInstrStep(MachineInstr &MI,
|
||||
const LegalizerInfo &LegalizerInfo);
|
||||
|
||||
LegalizeResult legalizeInstr(MachineInstr &MI,
|
||||
const LegalizerInfo &LegalizerInfo);
|
||||
LegalizeResult legalizeInstrStep(MachineInstr &MI);
|
||||
|
||||
/// Legalize an instruction by emiting a runtime library call instead.
|
||||
LegalizeResult libcall(MachineInstr &MI);
|
||||
@ -87,6 +83,10 @@ class LegalizerHelper {
|
||||
LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT WideTy);
|
||||
|
||||
/// Expose MIRBuilder so clients can set their own RecordInsertInstruction
|
||||
/// functions
|
||||
MachineIRBuilder MIRBuilder;
|
||||
|
||||
private:
|
||||
|
||||
/// Helper function to split a wide generic register into bitwise blocks with
|
||||
@ -95,8 +95,8 @@ class LegalizerHelper {
|
||||
void extractParts(unsigned Reg, LLT Ty, int NumParts,
|
||||
SmallVectorImpl<unsigned> &Ops);
|
||||
|
||||
MachineIRBuilder MIRBuilder;
|
||||
MachineRegisterInfo &MRI;
|
||||
const LegalizerInfo &LI;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
|
@ -25,6 +25,7 @@
|
||||
namespace llvm {
|
||||
class LLVMContext;
|
||||
class MachineInstr;
|
||||
class MachineIRBuilder;
|
||||
class MachineRegisterInfo;
|
||||
class Type;
|
||||
class VectorType;
|
||||
@ -96,6 +97,7 @@ class LegalizerInfo {
|
||||
};
|
||||
|
||||
LegalizerInfo();
|
||||
virtual ~LegalizerInfo() = default;
|
||||
|
||||
/// Compute any ancillary tables needed to quickly decide how an operation
|
||||
/// should be handled. This must be called after all "set*Action"methods but
|
||||
@ -144,7 +146,7 @@ class LegalizerInfo {
|
||||
/// Iterate the given function (typically something like doubling the width)
|
||||
/// on Ty until we find a legal type for this operation.
|
||||
LLT findLegalType(const InstrAspect &Aspect,
|
||||
std::function<LLT(LLT)> NextType) const {
|
||||
function_ref<LLT(LLT)> NextType) const {
|
||||
LegalizeAction Action;
|
||||
const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx];
|
||||
LLT Ty = Aspect.Type;
|
||||
@ -186,6 +188,10 @@ class LegalizerInfo {
|
||||
|
||||
bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const;
|
||||
|
||||
virtual bool legalizeCustom(MachineInstr &MI,
|
||||
MachineRegisterInfo &MRI,
|
||||
MachineIRBuilder &MIRBuilder) const;
|
||||
|
||||
private:
|
||||
static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
|
||||
static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
|
||||
|
@ -108,6 +108,9 @@ class MachineIRBuilder {
|
||||
/// Set the debug location to \p DL for all the next build instructions.
|
||||
void setDebugLoc(const DebugLoc &DL) { this->DL = DL; }
|
||||
|
||||
/// Get the current instruction's debug location.
|
||||
DebugLoc getDebugLoc() { return DL; }
|
||||
|
||||
/// Build and insert <empty> = \p Opcode <empty>.
|
||||
/// The insertion point is the one set by the last call of either
|
||||
/// setBasicBlock or setMI.
|
||||
@ -127,6 +130,29 @@ class MachineIRBuilder {
|
||||
/// Insert an existing instruction at the insertion point.
|
||||
MachineInstrBuilder insertInstr(MachineInstrBuilder MIB);
|
||||
|
||||
/// Build and insert a DBG_VALUE instruction expressing the fact that the
|
||||
/// associated \p Variable lives in \p Reg (suitably modified by \p Expr).
|
||||
MachineInstrBuilder buildDirectDbgValue(unsigned Reg, const MDNode *Variable,
|
||||
const MDNode *Expr);
|
||||
|
||||
/// Build and insert a DBG_VALUE instruction expressing the fact that the
|
||||
/// associated \p Variable lives in memory at \p Reg + \p Offset (suitably
|
||||
/// modified by \p Expr).
|
||||
MachineInstrBuilder buildIndirectDbgValue(unsigned Reg, unsigned Offset,
|
||||
const MDNode *Variable,
|
||||
const MDNode *Expr);
|
||||
/// Build and insert a DBG_VALUE instruction expressing the fact that the
|
||||
/// associated \p Variable lives in the stack slot specified by \p FI
|
||||
/// (suitably modified by \p Expr).
|
||||
MachineInstrBuilder buildFIDbgValue(int FI, const MDNode *Variable,
|
||||
const MDNode *Expr);
|
||||
|
||||
/// Build and insert a DBG_VALUE instructions specifying that \p Variable is
|
||||
/// given by \p C (suitably modified by \p Expr).
|
||||
MachineInstrBuilder buildConstDbgValue(const Constant &C, unsigned Offset,
|
||||
const MDNode *Variable,
|
||||
const MDNode *Expr);
|
||||
|
||||
/// Build and insert \p Res<def> = G_FRAME_INDEX \p Idx
|
||||
///
|
||||
/// G_FRAME_INDEX materializes the address of an alloca value or other
|
||||
@ -203,6 +229,22 @@ class MachineIRBuilder {
|
||||
MachineInstrBuilder buildGEP(unsigned Res, unsigned Op0,
|
||||
unsigned Op1);
|
||||
|
||||
/// Build and insert \p Res<def> = G_PTR_MASK \p Op0, \p NumBits
|
||||
///
|
||||
/// G_PTR_MASK clears the low bits of a pointer operand without destroying its
|
||||
/// pointer properties. This has the effect of rounding the address *down* to
|
||||
/// a specified alignment in bits.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res and \p Op0 must be generic virtual registers with pointer
|
||||
/// type.
|
||||
/// \pre \p NumBits must be an integer representing the number of low bits to
|
||||
/// be cleared in \p Op0.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildPtrMask(unsigned Res, unsigned Op0,
|
||||
uint32_t NumBits);
|
||||
|
||||
/// Build and insert \p Res<def>, \p CarryOut<def> = G_UADDE \p Op0,
|
||||
/// \p Op1, \p CarryIn
|
||||
///
|
||||
@ -220,6 +262,19 @@ class MachineIRBuilder {
|
||||
MachineInstrBuilder buildUAdde(unsigned Res, unsigned CarryOut, unsigned Op0,
|
||||
unsigned Op1, unsigned CarryIn);
|
||||
|
||||
/// Build and insert \p Res<def> = G_AND \p Op0, \p Op1
|
||||
///
|
||||
/// G_AND sets \p Res to the bitwise and of integer parameters \p Op0 and \p
|
||||
/// Op1.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers
|
||||
/// with the same (scalar or vector) type).
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildAnd(unsigned Res, unsigned Op0,
|
||||
unsigned Op1);
|
||||
|
||||
/// Build and insert \p Res<def> = G_ANYEXT \p Op0
|
||||
///
|
||||
/// G_ANYEXT produces a register of the specified width, with bits 0 to
|
||||
@ -273,6 +328,19 @@ class MachineIRBuilder {
|
||||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildSExtOrTrunc(unsigned Res, unsigned Op);
|
||||
|
||||
/// Build and insert \p Res<def> = G_ZEXT \p Op, \p Res = G_TRUNC \p Op, or
|
||||
/// \p Res = COPY \p Op depending on the differing sizes of \p Res and \p Op.
|
||||
/// ///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res must be a generic virtual register with scalar or vector type.
|
||||
/// \pre \p Op must be a generic virtual register with scalar or vector type.
|
||||
///
|
||||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildZExtOrTrunc(unsigned Res, unsigned Op);
|
||||
|
||||
/// Build and insert an appropriate cast between two registers of equal size.
|
||||
MachineInstrBuilder buildCast(unsigned Dst, unsigned Src);
|
||||
|
||||
/// Build and insert G_BR \p Dest
|
||||
///
|
||||
/// G_BR is an unconditional branch to \p Dest.
|
||||
@ -296,6 +364,16 @@ class MachineIRBuilder {
|
||||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildBrCond(unsigned Tst, MachineBasicBlock &BB);
|
||||
|
||||
/// Build and insert G_BRINDIRECT \p Tgt
|
||||
///
|
||||
/// G_BRINDIRECT is an indirect branch to \p Tgt.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Tgt must be a generic virtual register with pointer type.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildBrIndirect(unsigned Tgt);
|
||||
|
||||
/// Build and insert \p Res = G_CONSTANT \p Val
|
||||
///
|
||||
/// G_CONSTANT is an integer constant with the specified size and value. \p
|
||||
@ -362,19 +440,16 @@ class MachineIRBuilder {
|
||||
MachineInstrBuilder buildStore(unsigned Val, unsigned Addr,
|
||||
MachineMemOperand &MMO);
|
||||
|
||||
/// Build and insert `Res0<def>, ... = G_EXTRACT Src, Idx0, ...`.
|
||||
///
|
||||
/// If \p Res[i] has size N bits, G_EXTRACT sets \p Res[i] to bits `[Idxs[i],
|
||||
/// Idxs[i] + N)` of \p Src.
|
||||
/// Build and insert `Res0<def>, ... = G_EXTRACT Src, Idx0`.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre Indices must be in ascending order of bit position.
|
||||
/// \pre Each member of \p Results and \p Src must be a generic
|
||||
/// virtual register.
|
||||
/// \pre \p Res and \p Src must be generic virtual registers.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildExtract(ArrayRef<unsigned> Results,
|
||||
ArrayRef<uint64_t> Indices, unsigned Src);
|
||||
MachineInstrBuilder buildExtract(unsigned Res, unsigned Src, uint64_t Index);
|
||||
|
||||
/// Build and insert \p Res = IMPLICIT_DEF.
|
||||
MachineInstrBuilder buildUndef(unsigned Dst);
|
||||
|
||||
/// Build and insert \p Res<def> = G_SEQUENCE \p Op0, \p Idx0...
|
||||
///
|
||||
@ -393,6 +468,31 @@ class MachineIRBuilder {
|
||||
ArrayRef<unsigned> Ops,
|
||||
ArrayRef<uint64_t> Indices);
|
||||
|
||||
/// Build and insert \p Res<def> = G_MERGE_VALUES \p Op0, ...
|
||||
///
|
||||
/// G_MERGE_VALUES combines the input elements contiguously into a larger
|
||||
/// register.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre The entire register \p Res (and no more) must be covered by the input
|
||||
/// registers.
|
||||
/// \pre The type of all \p Ops registers must be identical.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildMerge(unsigned Res, ArrayRef<unsigned> Ops);
|
||||
|
||||
/// Build and insert \p Res0<def>, ... = G_UNMERGE_VALUES \p Op
|
||||
///
|
||||
/// G_UNMERGE_VALUES splits contiguous bits of the input into multiple
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre The entire register \p Res (and no more) must be covered by the input
|
||||
/// registers.
|
||||
/// \pre The type of all \p Res registers must be identical.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildUnmerge(ArrayRef<unsigned> Res, unsigned Op);
|
||||
|
||||
void addUsesWithIndices(MachineInstrBuilder MIB) {}
|
||||
|
||||
template <typename... ArgTys>
|
||||
@ -411,14 +511,8 @@ class MachineIRBuilder {
|
||||
return MIB;
|
||||
}
|
||||
|
||||
template <typename... ArgTys>
|
||||
MachineInstrBuilder buildInsert(unsigned Res, unsigned Src,
|
||||
unsigned Op, unsigned Index, ArgTys... Args) {
|
||||
MachineInstrBuilder MIB =
|
||||
buildInstr(TargetOpcode::G_INSERT).addDef(Res).addUse(Src);
|
||||
addUsesWithIndices(MIB, Op, Index, Args...);
|
||||
return MIB;
|
||||
}
|
||||
unsigned Op, unsigned Index);
|
||||
|
||||
/// Build and insert either a G_INTRINSIC (if \p HasSideEffects is false) or
|
||||
/// G_INTRINSIC_W_SIDE_EFFECTS instruction. Its first operand will be the
|
||||
@ -500,6 +594,30 @@ class MachineIRBuilder {
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst,
|
||||
unsigned Op0, unsigned Op1);
|
||||
|
||||
/// Build and insert \p Res<def> = G_INSERT_VECTOR_ELT \p Val,
|
||||
/// \p Elt, \p Idx
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res and \p Val must be a generic virtual register
|
||||
// with the same vector type.
|
||||
/// \pre \p Elt and \p Idx must be a generic virtual register
|
||||
/// with scalar type.
|
||||
///
|
||||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildInsertVectorElement(unsigned Res, unsigned Val,
|
||||
unsigned Elt, unsigned Idx);
|
||||
|
||||
/// Build and insert \p Res<def> = G_EXTRACT_VECTOR_ELT \p Val, \p Idx
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res must be a generic virtual register with scalar type.
|
||||
/// \pre \p Val must be a generic virtual register with vector type.
|
||||
/// \pre \p Idx must be a generic virtual register with scalar type.
|
||||
///
|
||||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildExtractVectorElement(unsigned Res, unsigned Val,
|
||||
unsigned Idx);
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
@ -484,6 +485,9 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
/// This is required for non-fast mode.
|
||||
MachineBranchProbabilityInfo *MBPI;
|
||||
|
||||
/// Current optimization remark emitter. Used to report failures.
|
||||
std::unique_ptr<MachineOptimizationRemarkEmitter> MORE;
|
||||
|
||||
/// Helper class used for every code morphing.
|
||||
MachineIRBuilder MIRBuilder;
|
||||
|
||||
|
@ -42,7 +42,7 @@ class RegisterBank {
|
||||
|
||||
public:
|
||||
RegisterBank(unsigned ID, const char *Name, unsigned Size,
|
||||
const uint32_t *ContainedRegClasses);
|
||||
const uint32_t *ContainedRegClasses, unsigned NumRegClasses);
|
||||
|
||||
/// Get the identifier of this register bank.
|
||||
unsigned getID() const { return ID; }
|
||||
|
@ -317,12 +317,18 @@ class RegisterBankInfo {
|
||||
|
||||
/// The final mapping of the instruction.
|
||||
const InstructionMapping &getInstrMapping() const { return InstrMapping; }
|
||||
|
||||
/// The MachineRegisterInfo we used to realize the mapping.
|
||||
MachineRegisterInfo &getMRI() const { return MRI; }
|
||||
/// @}
|
||||
|
||||
/// Create as many new virtual registers as needed for the mapping of the \p
|
||||
/// OpIdx-th operand.
|
||||
/// The number of registers is determined by the number of breakdown for the
|
||||
/// related operand in the instruction mapping.
|
||||
/// The type of the new registers is a plain scalar of the right size.
|
||||
/// The proper type is expected to be set when the mapping is applied to
|
||||
/// the instruction(s) that realizes the mapping.
|
||||
///
|
||||
/// \pre getMI().getOperand(OpIdx).isReg()
|
||||
///
|
||||
@ -372,15 +378,15 @@ class RegisterBankInfo {
|
||||
|
||||
/// Keep dynamically allocated PartialMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, const PartialMapping *> MapOfPartialMappings;
|
||||
mutable DenseMap<unsigned, std::unique_ptr<const PartialMapping>> MapOfPartialMappings;
|
||||
|
||||
/// Keep dynamically allocated ValueMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, const ValueMapping *> MapOfValueMappings;
|
||||
mutable DenseMap<unsigned, std::unique_ptr<const ValueMapping> > MapOfValueMappings;
|
||||
|
||||
/// Keep dynamically allocated array of ValueMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, ValueMapping *> MapOfOperandsMappings;
|
||||
mutable DenseMap<unsigned, std::unique_ptr<ValueMapping[]>> MapOfOperandsMappings;
|
||||
|
||||
/// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks
|
||||
/// RegisterBank instances.
|
||||
@ -487,6 +493,12 @@ class RegisterBankInfo {
|
||||
/// Basically, that means that \p OpdMapper.getMI() is left untouched
|
||||
/// aside from the reassignment of the register operand that have been
|
||||
/// remapped.
|
||||
///
|
||||
/// The type of all the new registers that have been created by the
|
||||
/// mapper are properly remapped to the type of the original registers
|
||||
/// they replace. In other words, the semantic of the instruction does
|
||||
/// not change, only the register banks.
|
||||
///
|
||||
/// If the mapping of one of the operand spans several registers, this
|
||||
/// method will abort as this is not like a default mapping anymore.
|
||||
///
|
||||
@ -500,7 +512,7 @@ class RegisterBankInfo {
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~RegisterBankInfo();
|
||||
virtual ~RegisterBankInfo() = default;
|
||||
|
||||
/// Get the register bank identified by \p ID.
|
||||
const RegisterBank &getRegBank(unsigned ID) const {
|
||||
|
@ -15,15 +15,21 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_UTILS_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_UTILS_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineOptimizationRemarkEmitter;
|
||||
class MachineOptimizationRemarkMissed;
|
||||
class MachineRegisterInfo;
|
||||
class MCInstrDesc;
|
||||
class RegisterBankInfo;
|
||||
class TargetInstrInfo;
|
||||
class TargetPassConfig;
|
||||
class TargetRegisterInfo;
|
||||
class Twine;
|
||||
|
||||
/// Try to constrain Reg so that it is usable by argument OpIdx of the
|
||||
/// provided MCInstrDesc \p II. If this fails, create a new virtual
|
||||
@ -39,5 +45,20 @@ unsigned constrainOperandRegClass(const MachineFunction &MF,
|
||||
MachineInstr &InsertPt, const MCInstrDesc &II,
|
||||
unsigned Reg, unsigned OpIdx);
|
||||
|
||||
/// Check whether an instruction \p MI is dead: it only defines dead virtual
|
||||
/// registers, and doesn't have other side effects.
|
||||
bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Report an ISel error as a missed optimization remark to the LLVMContext's
|
||||
/// diagnostic stream. Set the FailedISel MachineFunction property.
|
||||
void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
MachineOptimizationRemarkEmitter &MORE,
|
||||
MachineOptimizationRemarkMissed &R);
|
||||
|
||||
void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
MachineOptimizationRemarkEmitter &MORE,
|
||||
const char *PassName, StringRef Msg,
|
||||
const MachineInstr &MI);
|
||||
|
||||
} // End namespace llvm.
|
||||
#endif
|
||||
|
@ -245,6 +245,12 @@ namespace ISD {
|
||||
/// Simple binary floating point operators.
|
||||
FADD, FSUB, FMUL, FDIV, FREM,
|
||||
|
||||
/// Constrained versions of the binary floating point operators.
|
||||
/// These will be lowered to the simple operators before final selection.
|
||||
/// They are used to limit optimizations while the DAG is being
|
||||
/// optimized.
|
||||
STRICT_FADD, STRICT_FSUB, STRICT_FMUL, STRICT_FDIV, STRICT_FREM,
|
||||
|
||||
/// FMA - Perform a * b + c with no intermediate rounding step.
|
||||
FMA,
|
||||
|
||||
@ -281,7 +287,8 @@ namespace ISD {
|
||||
/// EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR
|
||||
/// identified by the (potentially variable) element number IDX. If the
|
||||
/// return type is an integer type larger than the element type of the
|
||||
/// vector, the result is extended to the width of the return type.
|
||||
/// vector, the result is extended to the width of the return type. In
|
||||
/// that case, the high bits are undefined.
|
||||
EXTRACT_VECTOR_ELT,
|
||||
|
||||
/// CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of
|
||||
@ -332,6 +339,12 @@ namespace ISD {
|
||||
/// Bitwise operators - logical and, logical or, logical xor.
|
||||
AND, OR, XOR,
|
||||
|
||||
/// ABS - Determine the unsigned absolute value of a signed integer value of
|
||||
/// the same bitwidth.
|
||||
/// Note: A value of INT_MIN will return INT_MIN, no saturation or overflow
|
||||
/// is performed.
|
||||
ABS,
|
||||
|
||||
/// Shift and rotation operations. After legalization, the type of the
|
||||
/// shift amount is known to be TLI.getShiftAmountTy(). Before legalization
|
||||
/// the shift amount can be any type, but care must be taken to ensure it is
|
||||
@ -801,10 +814,11 @@ namespace ISD {
|
||||
PRE_INC,
|
||||
PRE_DEC,
|
||||
POST_INC,
|
||||
POST_DEC,
|
||||
LAST_INDEXED_MODE
|
||||
POST_DEC
|
||||
};
|
||||
|
||||
static const int LAST_INDEXED_MODE = POST_DEC + 1;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// LoadExtType enum - This enum defines the three variants of LOADEXT
|
||||
/// (load with extension).
|
||||
@ -819,10 +833,11 @@ namespace ISD {
|
||||
NON_EXTLOAD = 0,
|
||||
EXTLOAD,
|
||||
SEXTLOAD,
|
||||
ZEXTLOAD,
|
||||
LAST_LOADEXT_TYPE
|
||||
ZEXTLOAD
|
||||
};
|
||||
|
||||
static const int LAST_LOADEXT_TYPE = ZEXTLOAD + 1;
|
||||
|
||||
NodeType getExtForLoadExtType(bool IsFP, LoadExtType);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -0,0 +1,76 @@
|
||||
///===- LazyMachineBlockFrequencyInfo.h - Lazy Block Frequency -*- C++ -*--===//
|
||||
///
|
||||
/// The LLVM Compiler Infrastructure
|
||||
///
|
||||
/// This file is distributed under the University of Illinois Open Source
|
||||
/// License. See LICENSE.TXT for details.
|
||||
///
|
||||
///===---------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This is an alternative analysis pass to MachineBlockFrequencyInfo. The
|
||||
/// difference is that with this pass the block frequencies are not computed
|
||||
/// when the analysis pass is executed but rather when the BFI result is
|
||||
/// explicitly requested by the analysis client.
|
||||
///
|
||||
///===---------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LAZYMACHINEBLOCKFREQUENCYINFO_H
|
||||
#define LLVM_ANALYSIS_LAZYMACHINEBLOCKFREQUENCYINFO_H
|
||||
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
/// \brief This is an alternative analysis pass to MachineBlockFrequencyInfo.
|
||||
/// The difference is that with this pass, the block frequencies are not
|
||||
/// computed when the analysis pass is executed but rather when the BFI result
|
||||
/// is explicitly requested by the analysis client.
|
||||
///
|
||||
/// This works by checking querying if MBFI is available and otherwise
|
||||
/// generating MBFI on the fly. In this case the passes required for (LI, DT)
|
||||
/// are also queried before being computed on the fly.
|
||||
///
|
||||
/// Note that it is expected that we wouldn't need this functionality for the
|
||||
/// new PM since with the new PM, analyses are executed on demand.
|
||||
|
||||
class LazyMachineBlockFrequencyInfoPass : public MachineFunctionPass {
|
||||
private:
|
||||
/// If generated on the fly this own the instance.
|
||||
mutable std::unique_ptr<MachineBlockFrequencyInfo> OwnedMBFI;
|
||||
|
||||
/// If generated on the fly this own the instance.
|
||||
mutable std::unique_ptr<MachineLoopInfo> OwnedMLI;
|
||||
|
||||
/// If generated on the fly this own the instance.
|
||||
mutable std::unique_ptr<MachineDominatorTree> OwnedMDT;
|
||||
|
||||
/// The function.
|
||||
MachineFunction *MF = nullptr;
|
||||
|
||||
/// \brief Calculate MBFI and all other analyses that's not available and
|
||||
/// required by BFI.
|
||||
MachineBlockFrequencyInfo &calculateIfNotAvailable() const;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LazyMachineBlockFrequencyInfoPass();
|
||||
|
||||
/// \brief Compute and return the block frequencies.
|
||||
MachineBlockFrequencyInfo &getBFI() { return calculateIfNotAvailable(); }
|
||||
|
||||
/// \brief Compute and return the block frequencies.
|
||||
const MachineBlockFrequencyInfo &getBFI() const {
|
||||
return calculateIfNotAvailable();
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
void releaseMemory() override;
|
||||
void print(raw_ostream &OS, const Module *M) const override;
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===- LexicalScopes.cpp - Collecting lexical scope info -*- C++ -*--------===//
|
||||
//===- LexicalScopes.cpp - Collecting lexical scope info --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -19,19 +19,18 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// InsnRange - This is used to track range of instructions with identical
|
||||
@ -43,13 +42,15 @@ typedef std::pair<const MachineInstr *, const MachineInstr *> InsnRange;
|
||||
/// LexicalScope - This class is used to track scope information.
|
||||
///
|
||||
class LexicalScope {
|
||||
|
||||
public:
|
||||
LexicalScope(LexicalScope *P, const DILocalScope *D, const DILocation *I,
|
||||
bool A)
|
||||
: Parent(P), Desc(D), InlinedAtLocation(I), AbstractScope(A),
|
||||
LastInsn(nullptr), FirstInsn(nullptr), DFSIn(0), DFSOut(0) {
|
||||
assert((!D || D->isResolved()) && "Expected resolved node");
|
||||
: Parent(P), Desc(D), InlinedAtLocation(I), AbstractScope(A) {
|
||||
assert(D);
|
||||
assert(D->getSubprogram()->getUnit()->getEmissionKind() !=
|
||||
DICompileUnit::NoDebug &&
|
||||
"Don't build lexical scopes for non-debug locations");
|
||||
assert(D->isResolved() && "Expected resolved node");
|
||||
assert((!I || I->isResolved()) && "Expected resolved node");
|
||||
if (Parent)
|
||||
Parent->addChild(this);
|
||||
@ -127,10 +128,10 @@ class LexicalScope {
|
||||
// Contents not owned.
|
||||
SmallVector<InsnRange, 4> Ranges;
|
||||
|
||||
const MachineInstr *LastInsn; // Last instruction of this scope.
|
||||
const MachineInstr *FirstInsn; // First instruction of this scope.
|
||||
unsigned DFSIn, DFSOut; // In & Out Depth use to determine
|
||||
// scope nesting.
|
||||
const MachineInstr *LastInsn = nullptr; // Last instruction of this scope.
|
||||
const MachineInstr *FirstInsn = nullptr; // First instruction of this scope.
|
||||
unsigned DFSIn = 0; // In & Out Depth use to determine scope nesting.
|
||||
unsigned DFSOut = 0;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -139,7 +140,7 @@ class LexicalScope {
|
||||
///
|
||||
class LexicalScopes {
|
||||
public:
|
||||
LexicalScopes() : MF(nullptr), CurrentFnLexicalScope(nullptr) {}
|
||||
LexicalScopes() = default;
|
||||
|
||||
/// initialize - Scan machine function and constuct lexical scope nest, resets
|
||||
/// the instance if necessary.
|
||||
@ -225,8 +226,7 @@ class LexicalScopes {
|
||||
assignInstructionRanges(SmallVectorImpl<InsnRange> &MIRanges,
|
||||
DenseMap<const MachineInstr *, LexicalScope *> &M);
|
||||
|
||||
private:
|
||||
const MachineFunction *MF;
|
||||
const MachineFunction *MF = nullptr;
|
||||
|
||||
/// LexicalScopeMap - Tracks the scopes in the current function.
|
||||
// Use an unordered_map to ensure value pointer validity over insertion.
|
||||
@ -249,9 +249,9 @@ class LexicalScopes {
|
||||
|
||||
/// CurrentFnLexicalScope - Top level scope for the current function.
|
||||
///
|
||||
LexicalScope *CurrentFnLexicalScope;
|
||||
LexicalScope *CurrentFnLexicalScope = nullptr;
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_LEXICALSCOPES_H
|
||||
|
@ -227,15 +227,22 @@ namespace llvm {
|
||||
LiveRange(const LiveRange &Other, BumpPtrAllocator &Allocator) {
|
||||
assert(Other.segmentSet == nullptr &&
|
||||
"Copying of LiveRanges with active SegmentSets is not supported");
|
||||
assign(Other, Allocator);
|
||||
}
|
||||
|
||||
/// Copies values numbers and live segments from \p Other into this range.
|
||||
void assign(const LiveRange &Other, BumpPtrAllocator &Allocator) {
|
||||
if (this == &Other)
|
||||
return;
|
||||
|
||||
assert(Other.segmentSet == nullptr &&
|
||||
"Copying of LiveRanges with active SegmentSets is not supported");
|
||||
// Duplicate valnos.
|
||||
for (const VNInfo *VNI : Other.valnos) {
|
||||
for (const VNInfo *VNI : Other.valnos)
|
||||
createValueCopy(VNI, Allocator);
|
||||
}
|
||||
// Now we can copy segments and remap their valnos.
|
||||
for (const Segment &S : Other.segments) {
|
||||
for (const Segment &S : Other.segments)
|
||||
segments.push_back(Segment(S.start, S.end, valnos[S.valno->id]));
|
||||
}
|
||||
}
|
||||
|
||||
/// advanceTo - Advance the specified iterator to point to the Segment
|
||||
@ -767,6 +774,19 @@ namespace llvm {
|
||||
const MachineRegisterInfo &MRI,
|
||||
const SlotIndexes &Indexes) const;
|
||||
|
||||
/// Refines the subranges to support \p LaneMask. This may only be called
|
||||
/// for LI.hasSubrange()==true. Subregister ranges are split or created
|
||||
/// until \p LaneMask can be matched exactly. \p Mod is executed on the
|
||||
/// matching subranges.
|
||||
///
|
||||
/// Example:
|
||||
/// Given an interval with subranges with lanemasks L0F00, L00F0 and
|
||||
/// L000F, refining for mask L0018. Will split the L00F0 lane into
|
||||
/// L00E0 and L0010 and the L000F lane into L0007 and L0008. The Mod
|
||||
/// function will be applied to the L0010 and L0008 subranges.
|
||||
void refineSubRanges(BumpPtrAllocator &Allocator, LaneBitmask LaneMask,
|
||||
std::function<void(LiveInterval::SubRange&)> Mod);
|
||||
|
||||
bool operator<(const LiveInterval& other) const {
|
||||
const SlotIndex &thisIndex = beginIndex();
|
||||
const SlotIndex &otherIndex = other.beginIndex();
|
||||
|
@ -7,13 +7,13 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the LiveInterval analysis pass. Given some numbering of
|
||||
// each the machine instructions (in this implemention depth-first order) an
|
||||
// interval [i, j) is said to be a live interval for register v if there is no
|
||||
// instruction with number j' > j such that v is live at j' and there is no
|
||||
// instruction with number i' < i such that v is live at i'. In this
|
||||
// implementation intervals can have holes, i.e. an interval might look like
|
||||
// [1,20), [50,65), [1000,1001).
|
||||
/// \file This file implements the LiveInterval analysis pass. Given some
|
||||
/// numbering of each the machine instructions (in this implemention depth-first
|
||||
/// order) an interval [i, j) is said to be a live interval for register v if
|
||||
/// there is no instruction with number j' > j such that v is live at j' and
|
||||
/// there is no instruction with number i' < i such that v is live at i'. In
|
||||
/// this implementation intervals can have holes, i.e. an interval might look
|
||||
/// like [1,20), [50,65), [1000,1001).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -60,20 +60,17 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
LiveRangeCalc *LRCalc;
|
||||
|
||||
/// Special pool allocator for VNInfo's (LiveInterval val#).
|
||||
///
|
||||
VNInfo::Allocator VNInfoAllocator;
|
||||
|
||||
/// Live interval pointers for all the virtual registers.
|
||||
IndexedMap<LiveInterval*, VirtReg2IndexFunctor> VirtRegIntervals;
|
||||
|
||||
/// RegMaskSlots - Sorted list of instructions with register mask operands.
|
||||
/// Always use the 'r' slot, RegMasks are normal clobbers, not early
|
||||
/// clobbers.
|
||||
/// Sorted list of instructions with register mask operands. Always use the
|
||||
/// 'r' slot, RegMasks are normal clobbers, not early clobbers.
|
||||
SmallVector<SlotIndex, 8> RegMaskSlots;
|
||||
|
||||
/// RegMaskBits - This vector is parallel to RegMaskSlots, it holds a
|
||||
/// pointer to the corresponding register mask. This pointer can be
|
||||
/// recomputed as:
|
||||
/// This vector is parallel to RegMaskSlots, it holds a pointer to the
|
||||
/// corresponding register mask. This pointer can be recomputed as:
|
||||
///
|
||||
/// MI = Indexes->getInstructionFromIndex(RegMaskSlot[N]);
|
||||
/// unsigned OpNum = findRegMaskOperand(MI);
|
||||
@ -97,11 +94,11 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
SmallVector<LiveRange*, 0> RegUnitRanges;
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
static char ID;
|
||||
LiveIntervals();
|
||||
~LiveIntervals() override;
|
||||
|
||||
// Calculate the spill weight to assign to a single instruction.
|
||||
/// Calculate the spill weight to assign to a single instruction.
|
||||
static float getSpillWeight(bool isDef, bool isUse,
|
||||
const MachineBlockFrequencyInfo *MBFI,
|
||||
const MachineInstr &Instr);
|
||||
@ -121,7 +118,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
return VirtRegIntervals.inBounds(Reg) && VirtRegIntervals[Reg];
|
||||
}
|
||||
|
||||
// Interval creation.
|
||||
/// Interval creation.
|
||||
LiveInterval &createEmptyInterval(unsigned Reg) {
|
||||
assert(!hasInterval(Reg) && "Interval already exists!");
|
||||
VirtRegIntervals.grow(Reg);
|
||||
@ -135,7 +132,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
return LI;
|
||||
}
|
||||
|
||||
// Interval removal.
|
||||
/// Interval removal.
|
||||
void removeInterval(unsigned Reg) {
|
||||
delete VirtRegIntervals[Reg];
|
||||
VirtRegIntervals[Reg] = nullptr;
|
||||
@ -163,16 +160,16 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
/// LiveInterval::removeEmptySubranges() afterwards.
|
||||
void shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg);
|
||||
|
||||
/// Extend the live range @p LR to reach all points in @p Indices. The
|
||||
/// points in the @p Indices array must be jointly dominated by the union
|
||||
/// of the existing defs in @p LR and points in @p Undefs.
|
||||
/// Extend the live range \p LR to reach all points in \p Indices. The
|
||||
/// points in the \p Indices array must be jointly dominated by the union
|
||||
/// of the existing defs in \p LR and points in \p Undefs.
|
||||
///
|
||||
/// PHI-defs are added as needed to maintain SSA form.
|
||||
///
|
||||
/// If a SlotIndex in @p Indices is the end index of a basic block, @p LR
|
||||
/// If a SlotIndex in \p Indices is the end index of a basic block, \p LR
|
||||
/// will be extended to be live out of the basic block.
|
||||
/// If a SlotIndex in @p Indices is jointy dominated only by points in
|
||||
/// @p Undefs, the live range will not be extended to that point.
|
||||
/// If a SlotIndex in \p Indices is jointy dominated only by points in
|
||||
/// \p Undefs, the live range will not be extended to that point.
|
||||
///
|
||||
/// See also LiveRangeCalc::extend().
|
||||
void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices,
|
||||
@ -182,7 +179,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
extendToIndices(LR, Indices, /*Undefs=*/{});
|
||||
}
|
||||
|
||||
/// If @p LR has a live value at @p Kill, prune its live range by removing
|
||||
/// If \p LR has a live value at \p Kill, prune its live range by removing
|
||||
/// any liveness reachable from Kill. Add live range end points to
|
||||
/// EndPoints such that extendToIndices(LI, EndPoints) will reconstruct the
|
||||
/// value's live range.
|
||||
@ -192,6 +189,16 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
void pruneValue(LiveRange &LR, SlotIndex Kill,
|
||||
SmallVectorImpl<SlotIndex> *EndPoints);
|
||||
|
||||
/// This function should be used. Its intend is to tell you that
|
||||
/// you are doing something wrong if you call pruveValue directly on a
|
||||
/// LiveInterval. Indeed, you are supposed to call pruneValue on the main
|
||||
/// LiveRange and all the LiveRange of the subranges if any.
|
||||
LLVM_ATTRIBUTE_UNUSED void pruneValue(LiveInterval &, SlotIndex,
|
||||
SmallVectorImpl<SlotIndex> *) {
|
||||
llvm_unreachable(
|
||||
"Use pruneValue on the main LiveRange and on each subrange");
|
||||
}
|
||||
|
||||
SlotIndexes *getSlotIndexes() const {
|
||||
return Indexes;
|
||||
}
|
||||
@ -200,8 +207,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
return AA;
|
||||
}
|
||||
|
||||
/// isNotInMIMap - returns true if the specified machine instr has been
|
||||
/// removed or was never entered in the map.
|
||||
/// Returns true if the specified machine instr has been removed or was
|
||||
/// never entered in the map.
|
||||
bool isNotInMIMap(const MachineInstr &Instr) const {
|
||||
return !Indexes->hasIndex(Instr);
|
||||
}
|
||||
@ -270,35 +277,32 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
void releaseMemory() override;
|
||||
|
||||
/// runOnMachineFunction - pass entry point
|
||||
/// Pass entry point; Calculates LiveIntervals.
|
||||
bool runOnMachineFunction(MachineFunction&) override;
|
||||
|
||||
/// print - Implement the dump method.
|
||||
/// Implement the dump method.
|
||||
void print(raw_ostream &O, const Module* = nullptr) const override;
|
||||
|
||||
/// intervalIsInOneMBB - If LI is confined to a single basic block, return
|
||||
/// a pointer to that block. If LI is live in to or out of any block,
|
||||
/// return NULL.
|
||||
/// If LI is confined to a single basic block, return a pointer to that
|
||||
/// block. If LI is live in to or out of any block, return NULL.
|
||||
MachineBasicBlock *intervalIsInOneMBB(const LiveInterval &LI) const;
|
||||
|
||||
/// Returns true if VNI is killed by any PHI-def values in LI.
|
||||
/// This may conservatively return true to avoid expensive computations.
|
||||
bool hasPHIKill(const LiveInterval &LI, const VNInfo *VNI) const;
|
||||
|
||||
/// addKillFlags - Add kill flags to any instruction that kills a virtual
|
||||
/// register.
|
||||
/// Add kill flags to any instruction that kills a virtual register.
|
||||
void addKillFlags(const VirtRegMap*);
|
||||
|
||||
/// handleMove - call this method to notify LiveIntervals that
|
||||
/// instruction 'mi' has been moved within a basic block. This will update
|
||||
/// the live intervals for all operands of mi. Moves between basic blocks
|
||||
/// are not supported.
|
||||
/// Call this method to notify LiveIntervals that instruction \p MI has been
|
||||
/// moved within a basic block. This will update the live intervals for all
|
||||
/// operands of \p MI. Moves between basic blocks are not supported.
|
||||
///
|
||||
/// \param UpdateFlags Update live intervals for nonallocatable physregs.
|
||||
void handleMove(MachineInstr &MI, bool UpdateFlags = false);
|
||||
|
||||
/// moveIntoBundle - Update intervals for operands of MI so that they
|
||||
/// begin/end on the SlotIndex for BundleStart.
|
||||
/// Update intervals for operands of \p MI so that they begin/end on the
|
||||
/// SlotIndex for \p BundleStart.
|
||||
///
|
||||
/// \param UpdateFlags Update live intervals for nonallocatable physregs.
|
||||
///
|
||||
@ -308,10 +312,9 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
void handleMoveIntoBundle(MachineInstr &MI, MachineInstr &BundleStart,
|
||||
bool UpdateFlags = false);
|
||||
|
||||
/// repairIntervalsInRange - Update live intervals for instructions in a
|
||||
/// range of iterators. It is intended for use after target hooks that may
|
||||
/// insert or remove instructions, and is only efficient for a small number
|
||||
/// of instructions.
|
||||
/// Update live intervals for instructions in a range of iterators. It is
|
||||
/// intended for use after target hooks that may insert or remove
|
||||
/// instructions, and is only efficient for a small number of instructions.
|
||||
///
|
||||
/// OrigRegs is a vector of registers that were originally used by the
|
||||
/// instructions in the range between the two iterators.
|
||||
@ -334,34 +337,33 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
// LiveIntervalAnalysis maintains a sorted list of instructions with
|
||||
// register mask operands.
|
||||
|
||||
/// getRegMaskSlots - Returns a sorted array of slot indices of all
|
||||
/// instructions with register mask operands.
|
||||
/// Returns a sorted array of slot indices of all instructions with
|
||||
/// register mask operands.
|
||||
ArrayRef<SlotIndex> getRegMaskSlots() const { return RegMaskSlots; }
|
||||
|
||||
/// getRegMaskSlotsInBlock - Returns a sorted array of slot indices of all
|
||||
/// instructions with register mask operands in the basic block numbered
|
||||
/// MBBNum.
|
||||
/// Returns a sorted array of slot indices of all instructions with register
|
||||
/// mask operands in the basic block numbered \p MBBNum.
|
||||
ArrayRef<SlotIndex> getRegMaskSlotsInBlock(unsigned MBBNum) const {
|
||||
std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum];
|
||||
return getRegMaskSlots().slice(P.first, P.second);
|
||||
}
|
||||
|
||||
/// getRegMaskBits() - Returns an array of register mask pointers
|
||||
/// corresponding to getRegMaskSlots().
|
||||
/// Returns an array of register mask pointers corresponding to
|
||||
/// getRegMaskSlots().
|
||||
ArrayRef<const uint32_t*> getRegMaskBits() const { return RegMaskBits; }
|
||||
|
||||
/// getRegMaskBitsInBlock - Returns an array of mask pointers corresponding
|
||||
/// to getRegMaskSlotsInBlock(MBBNum).
|
||||
/// Returns an array of mask pointers corresponding to
|
||||
/// getRegMaskSlotsInBlock(MBBNum).
|
||||
ArrayRef<const uint32_t*> getRegMaskBitsInBlock(unsigned MBBNum) const {
|
||||
std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum];
|
||||
return getRegMaskBits().slice(P.first, P.second);
|
||||
}
|
||||
|
||||
/// checkRegMaskInterference - Test if LI is live across any register mask
|
||||
/// instructions, and compute a bit mask of physical registers that are not
|
||||
/// clobbered by any of them.
|
||||
/// Test if \p LI is live across any register mask instructions, and
|
||||
/// compute a bit mask of physical registers that are not clobbered by any
|
||||
/// of them.
|
||||
///
|
||||
/// Returns false if LI doesn't cross any register mask instructions. In
|
||||
/// Returns false if \p LI doesn't cross any register mask instructions. In
|
||||
/// that case, the bit vector is not filled in.
|
||||
bool checkRegMaskInterference(LiveInterval &LI,
|
||||
BitVector &UsableRegs);
|
||||
@ -377,8 +379,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
// track liveness per register unit to handle aliasing registers more
|
||||
// efficiently.
|
||||
|
||||
/// getRegUnit - Return the live range for Unit.
|
||||
/// It will be computed if it doesn't exist.
|
||||
/// Return the live range for register unit \p Unit. It will be computed if
|
||||
/// it doesn't exist.
|
||||
LiveRange &getRegUnit(unsigned Unit) {
|
||||
LiveRange *LR = RegUnitRanges[Unit];
|
||||
if (!LR) {
|
||||
@ -390,8 +392,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
return *LR;
|
||||
}
|
||||
|
||||
/// getCachedRegUnit - Return the live range for Unit if it has already
|
||||
/// been computed, or NULL if it hasn't been computed yet.
|
||||
/// Return the live range for register unit \p Unit if it has already been
|
||||
/// computed, or nullptr if it hasn't been computed yet.
|
||||
LiveRange *getCachedRegUnit(unsigned Unit) {
|
||||
return RegUnitRanges[Unit];
|
||||
}
|
||||
@ -400,7 +402,7 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
return RegUnitRanges[Unit];
|
||||
}
|
||||
|
||||
/// removeRegUnit - Remove computed live range for Unit. Subsequent uses
|
||||
/// Remove computed live range for register unit \p Unit. Subsequent uses
|
||||
/// should rely on on-demand recomputation.
|
||||
void removeRegUnit(unsigned Unit) {
|
||||
delete RegUnitRanges[Unit];
|
||||
@ -408,12 +410,12 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
}
|
||||
|
||||
/// Remove value numbers and related live segments starting at position
|
||||
/// @p Pos that are part of any liverange of physical register @p Reg or one
|
||||
/// \p Pos that are part of any liverange of physical register \p Reg or one
|
||||
/// of its subregisters.
|
||||
void removePhysRegDefAt(unsigned Reg, SlotIndex Pos);
|
||||
|
||||
/// Remove value number and related live segments of @p LI and its subranges
|
||||
/// that start at position @p Pos.
|
||||
/// Remove value number and related live segments of \p LI and its subranges
|
||||
/// that start at position \p Pos.
|
||||
void removeVRegDefAt(LiveInterval &LI, SlotIndex Pos);
|
||||
|
||||
/// Split separate components in LiveInterval \p LI into separate intervals.
|
||||
@ -432,10 +434,10 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
/// Compute RegMaskSlots and RegMaskBits.
|
||||
void computeRegMasks();
|
||||
|
||||
/// Walk the values in @p LI and check for dead values:
|
||||
/// Walk the values in \p LI and check for dead values:
|
||||
/// - Dead PHIDef values are marked as unused.
|
||||
/// - Dead operands are marked as such.
|
||||
/// - Completely dead machine instructions are added to the @p dead vector
|
||||
/// - Completely dead machine instructions are added to the \p dead vector
|
||||
/// if it is not nullptr.
|
||||
/// Returns true if any PHI value numbers have been removed which may
|
||||
/// have separated the interval into multiple connected components.
|
||||
@ -453,8 +455,8 @@ extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
|
||||
|
||||
/// Helper function for repairIntervalsInRange(), walks backwards and
|
||||
/// creates/modifies live segments in @p LR to match the operands found.
|
||||
/// Only full operands or operands with subregisters matching @p LaneMask
|
||||
/// creates/modifies live segments in \p LR to match the operands found.
|
||||
/// Only full operands or operands with subregisters matching \p LaneMask
|
||||
/// are considered.
|
||||
void repairOldRegInRange(MachineBasicBlock::iterator Begin,
|
||||
MachineBasicBlock::iterator End,
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- LiveIntervalUnion.h - Live interval union data struct --*- C++ -*--===//
|
||||
//===- LiveIntervalUnion.h - Live interval union data struct ---*- C++ -*--===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -18,7 +18,11 @@
|
||||
#define LLVM_CODEGEN_LIVEINTERVALUNION_H
|
||||
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -30,13 +34,6 @@ template <unsigned Element> class SparseBitVector;
|
||||
typedef SparseBitVector<128> LiveVirtRegBitSet;
|
||||
#endif
|
||||
|
||||
/// Compare a live virtual register segment to a LiveIntervalUnion segment.
|
||||
inline bool
|
||||
overlap(const LiveInterval::Segment &VRSeg,
|
||||
const IntervalMap<SlotIndex, LiveInterval*>::const_iterator &LUSeg) {
|
||||
return VRSeg.start < LUSeg.stop() && LUSeg.start() < VRSeg.end;
|
||||
}
|
||||
|
||||
/// Union of live intervals that are strong candidates for coalescing into a
|
||||
/// single register (either physical or virtual depending on the context). We
|
||||
/// expect the constituent live intervals to be disjoint, although we may
|
||||
@ -53,29 +50,34 @@ class LiveIntervalUnion {
|
||||
// to reach the current segment's containing virtual register.
|
||||
typedef LiveSegments::iterator SegmentIter;
|
||||
|
||||
/// Const version of SegmentIter.
|
||||
typedef LiveSegments::const_iterator ConstSegmentIter;
|
||||
|
||||
// LiveIntervalUnions share an external allocator.
|
||||
typedef LiveSegments::Allocator Allocator;
|
||||
|
||||
class Query;
|
||||
|
||||
private:
|
||||
unsigned Tag; // unique tag for current contents.
|
||||
unsigned Tag = 0; // unique tag for current contents.
|
||||
LiveSegments Segments; // union of virtual reg segments
|
||||
|
||||
public:
|
||||
explicit LiveIntervalUnion(Allocator &a) : Tag(0), Segments(a) {}
|
||||
explicit LiveIntervalUnion(Allocator &a) : Segments(a) {}
|
||||
|
||||
// Iterate over all segments in the union of live virtual registers ordered
|
||||
// by their starting position.
|
||||
SegmentIter begin() { return Segments.begin(); }
|
||||
SegmentIter end() { return Segments.end(); }
|
||||
SegmentIter find(SlotIndex x) { return Segments.find(x); }
|
||||
ConstSegmentIter begin() const { return Segments.begin(); }
|
||||
ConstSegmentIter end() const { return Segments.end(); }
|
||||
ConstSegmentIter find(SlotIndex x) const { return Segments.find(x); }
|
||||
|
||||
bool empty() const { return Segments.empty(); }
|
||||
SlotIndex startIndex() const { return Segments.start(); }
|
||||
|
||||
// Provide public access to the underlying map to allow overlap iteration.
|
||||
typedef LiveSegments Map;
|
||||
const Map &getMap() { return Segments; }
|
||||
const Map &getMap() const { return Segments; }
|
||||
|
||||
/// getTag - Return an opaque tag representing the current state of the union.
|
||||
unsigned getTag() const { return Tag; }
|
||||
@ -85,15 +87,9 @@ class LiveIntervalUnion {
|
||||
|
||||
// Add a live virtual register to this union and merge its segments.
|
||||
void unify(LiveInterval &VirtReg, const LiveRange &Range);
|
||||
void unify(LiveInterval &VirtReg) {
|
||||
unify(VirtReg, VirtReg);
|
||||
}
|
||||
|
||||
// Remove a live virtual register's segments from this union.
|
||||
void extract(LiveInterval &VirtReg, const LiveRange &Range);
|
||||
void extract(LiveInterval &VirtReg) {
|
||||
extract(VirtReg, VirtReg);
|
||||
}
|
||||
|
||||
// Remove all inserted virtual registers.
|
||||
void clear() { Segments.clear(); ++Tag; }
|
||||
@ -109,52 +105,42 @@ class LiveIntervalUnion {
|
||||
/// Query interferences between a single live virtual register and a live
|
||||
/// interval union.
|
||||
class Query {
|
||||
LiveIntervalUnion *LiveUnion;
|
||||
LiveInterval *VirtReg;
|
||||
LiveInterval::iterator VirtRegI; // current position in VirtReg
|
||||
SegmentIter LiveUnionI; // current position in LiveUnion
|
||||
const LiveIntervalUnion *LiveUnion = nullptr;
|
||||
const LiveRange *LR = nullptr;
|
||||
LiveRange::const_iterator LRI; ///< current position in LR
|
||||
ConstSegmentIter LiveUnionI; ///< current position in LiveUnion
|
||||
SmallVector<LiveInterval*,4> InterferingVRegs;
|
||||
bool CheckedFirstInterference;
|
||||
bool SeenAllInterferences;
|
||||
bool SeenUnspillableVReg;
|
||||
unsigned Tag, UserTag;
|
||||
bool CheckedFirstInterference = false;
|
||||
bool SeenAllInterferences = false;
|
||||
unsigned Tag = 0;
|
||||
unsigned UserTag = 0;
|
||||
|
||||
public:
|
||||
Query(): LiveUnion(), VirtReg(), Tag(0), UserTag(0) {}
|
||||
|
||||
Query(LiveInterval *VReg, LiveIntervalUnion *LIU):
|
||||
LiveUnion(LIU), VirtReg(VReg), CheckedFirstInterference(false),
|
||||
SeenAllInterferences(false), SeenUnspillableVReg(false)
|
||||
{}
|
||||
|
||||
void clear() {
|
||||
LiveUnion = nullptr;
|
||||
VirtReg = nullptr;
|
||||
void reset(unsigned NewUserTag, const LiveRange &NewLR,
|
||||
const LiveIntervalUnion &NewLiveUnion) {
|
||||
LiveUnion = &NewLiveUnion;
|
||||
LR = &NewLR;
|
||||
InterferingVRegs.clear();
|
||||
CheckedFirstInterference = false;
|
||||
SeenAllInterferences = false;
|
||||
SeenUnspillableVReg = false;
|
||||
Tag = 0;
|
||||
UserTag = 0;
|
||||
Tag = NewLiveUnion.getTag();
|
||||
UserTag = NewUserTag;
|
||||
}
|
||||
|
||||
void init(unsigned UTag, LiveInterval *VReg, LiveIntervalUnion *LIU) {
|
||||
assert(VReg && LIU && "Invalid arguments");
|
||||
if (UserTag == UTag && VirtReg == VReg &&
|
||||
LiveUnion == LIU && !LIU->changedSince(Tag)) {
|
||||
public:
|
||||
Query() = default;
|
||||
Query(const LiveRange &LR, const LiveIntervalUnion &LIU):
|
||||
LiveUnion(&LIU), LR(&LR) {}
|
||||
Query(const Query &) = delete;
|
||||
Query &operator=(const Query &) = delete;
|
||||
|
||||
void init(unsigned NewUserTag, const LiveRange &NewLR,
|
||||
const LiveIntervalUnion &NewLiveUnion) {
|
||||
if (UserTag == NewUserTag && LR == &NewLR && LiveUnion == &NewLiveUnion &&
|
||||
!NewLiveUnion.changedSince(Tag)) {
|
||||
// Retain cached results, e.g. firstInterference.
|
||||
return;
|
||||
}
|
||||
clear();
|
||||
LiveUnion = LIU;
|
||||
VirtReg = VReg;
|
||||
Tag = LIU->getTag();
|
||||
UserTag = UTag;
|
||||
}
|
||||
|
||||
LiveInterval &virtReg() const {
|
||||
assert(VirtReg && "uninitialized");
|
||||
return *VirtReg;
|
||||
reset(NewUserTag, NewLR, NewLiveUnion);
|
||||
}
|
||||
|
||||
// Does this live virtual register interfere with the union?
|
||||
@ -162,7 +148,8 @@ class LiveIntervalUnion {
|
||||
|
||||
// Count the virtual registers in this union that interfere with this
|
||||
// query's live virtual register, up to maxInterferingRegs.
|
||||
unsigned collectInterferingVRegs(unsigned MaxInterferingRegs = UINT_MAX);
|
||||
unsigned collectInterferingVRegs(
|
||||
unsigned MaxInterferingRegs = std::numeric_limits<unsigned>::max());
|
||||
|
||||
// Was this virtual register visited during collectInterferingVRegs?
|
||||
bool isSeenInterference(LiveInterval *VReg) const;
|
||||
@ -170,25 +157,19 @@ class LiveIntervalUnion {
|
||||
// Did collectInterferingVRegs collect all interferences?
|
||||
bool seenAllInterferences() const { return SeenAllInterferences; }
|
||||
|
||||
// Did collectInterferingVRegs encounter an unspillable vreg?
|
||||
bool seenUnspillableVReg() const { return SeenUnspillableVReg; }
|
||||
|
||||
// Vector generated by collectInterferingVRegs.
|
||||
const SmallVectorImpl<LiveInterval*> &interferingVRegs() const {
|
||||
return InterferingVRegs;
|
||||
}
|
||||
|
||||
private:
|
||||
Query(const Query&) = delete;
|
||||
void operator=(const Query&) = delete;
|
||||
};
|
||||
|
||||
// Array of LiveIntervalUnions.
|
||||
class Array {
|
||||
unsigned Size;
|
||||
LiveIntervalUnion *LIUs;
|
||||
unsigned Size = 0;
|
||||
LiveIntervalUnion *LIUs = nullptr;
|
||||
|
||||
public:
|
||||
Array() : Size(0), LIUs(nullptr) {}
|
||||
Array() = default;
|
||||
~Array() { clear(); }
|
||||
|
||||
// Initialize the array to have Size entries.
|
||||
@ -213,4 +194,4 @@ class LiveIntervalUnion {
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // !defined(LLVM_CODEGEN_LIVEINTERVALUNION_H)
|
||||
#endif // LLVM_CODEGEN_LIVEINTERVALUNION_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- LiveRegMatrix.h - Track register interference ---------*- C++ -*---===//
|
||||
//===- LiveRegMatrix.h - Track register interference ----------*- C++ -*---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -27,11 +27,14 @@
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/CodeGen/LiveIntervalUnion.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AnalysisUsage;
|
||||
class LiveInterval;
|
||||
class LiveIntervalAnalysis;
|
||||
class LiveIntervals;
|
||||
class MachineFunction;
|
||||
class TargetRegisterInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
@ -41,7 +44,7 @@ class LiveRegMatrix : public MachineFunctionPass {
|
||||
VirtRegMap *VRM;
|
||||
|
||||
// UserTag changes whenever virtual registers have been modified.
|
||||
unsigned UserTag;
|
||||
unsigned UserTag = 0;
|
||||
|
||||
// The matrix is represented as a LiveIntervalUnion per register unit.
|
||||
LiveIntervalUnion::Allocator LIUAlloc;
|
||||
@ -51,16 +54,18 @@ class LiveRegMatrix : public MachineFunctionPass {
|
||||
std::unique_ptr<LiveIntervalUnion::Query[]> Queries;
|
||||
|
||||
// Cached register mask interference info.
|
||||
unsigned RegMaskTag;
|
||||
unsigned RegMaskVirtReg;
|
||||
unsigned RegMaskTag = 0;
|
||||
unsigned RegMaskVirtReg = 0;
|
||||
BitVector RegMaskUsable;
|
||||
|
||||
// MachineFunctionPass boilerplate.
|
||||
void getAnalysisUsage(AnalysisUsage&) const override;
|
||||
bool runOnMachineFunction(MachineFunction&) override;
|
||||
void getAnalysisUsage(AnalysisUsage &) const override;
|
||||
bool runOnMachineFunction(MachineFunction &) override;
|
||||
void releaseMemory() override;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LiveRegMatrix();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -136,7 +141,7 @@ class LiveRegMatrix : public MachineFunctionPass {
|
||||
/// Use MCRegUnitIterator to enumerate all regunits in the desired PhysReg.
|
||||
/// This returns a reference to an internal Query data structure that is only
|
||||
/// valid until the next query() call.
|
||||
LiveIntervalUnion::Query &query(LiveInterval &VirtReg, unsigned RegUnit);
|
||||
LiveIntervalUnion::Query &query(const LiveRange &LR, unsigned RegUnit);
|
||||
|
||||
/// Directly access the live interval unions per regunit.
|
||||
/// This returns an array indexed by the regunit number.
|
||||
|
128
contrib/llvm/include/llvm/CodeGen/LiveRegUnits.h
Normal file
128
contrib/llvm/include/llvm/CodeGen/LiveRegUnits.h
Normal file
@ -0,0 +1,128 @@
|
||||
//===- llvm/CodeGen/LiveRegUnits.h - Register Unit Set ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// A set of register units. It is intended for register liveness tracking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEREGUNITS_H
|
||||
#define LLVM_CODEGEN_LIVEREGUNITS_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/MC/LaneBitmask.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineBasicBlock;
|
||||
|
||||
/// A set of register units used to track register liveness.
|
||||
class LiveRegUnits {
|
||||
const TargetRegisterInfo *TRI = nullptr;
|
||||
BitVector Units;
|
||||
|
||||
public:
|
||||
/// Constructs a new empty LiveRegUnits set.
|
||||
LiveRegUnits() = default;
|
||||
|
||||
/// Constructs and initialize an empty LiveRegUnits set.
|
||||
LiveRegUnits(const TargetRegisterInfo &TRI) {
|
||||
init(TRI);
|
||||
}
|
||||
|
||||
/// Initialize and clear the set.
|
||||
void init(const TargetRegisterInfo &TRI) {
|
||||
this->TRI = &TRI;
|
||||
Units.reset();
|
||||
Units.resize(TRI.getNumRegUnits());
|
||||
}
|
||||
|
||||
/// Clears the set.
|
||||
void clear() { Units.reset(); }
|
||||
|
||||
/// Returns true if the set is empty.
|
||||
bool empty() const { return Units.empty(); }
|
||||
|
||||
/// Adds register units covered by physical register \p Reg.
|
||||
void addReg(unsigned Reg) {
|
||||
for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit)
|
||||
Units.set(*Unit);
|
||||
}
|
||||
|
||||
/// \brief Adds register units covered by physical register \p Reg that are
|
||||
/// part of the lanemask \p Mask.
|
||||
void addRegMasked(unsigned Reg, LaneBitmask Mask) {
|
||||
for (MCRegUnitMaskIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) {
|
||||
LaneBitmask UnitMask = (*Unit).second;
|
||||
if (UnitMask.none() || (UnitMask & Mask).any())
|
||||
Units.set((*Unit).first);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all register units covered by physical register \p Reg.
|
||||
void removeReg(unsigned Reg) {
|
||||
for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit)
|
||||
Units.reset(*Unit);
|
||||
}
|
||||
|
||||
/// Removes register units not preserved by the regmask \p RegMask.
|
||||
/// The regmask has the same format as the one in the RegMask machine operand.
|
||||
void removeRegsNotPreserved(const uint32_t *RegMask);
|
||||
|
||||
/// Adds register units not preserved by the regmask \p RegMask.
|
||||
/// The regmask has the same format as the one in the RegMask machine operand.
|
||||
void addRegsInMask(const uint32_t *RegMask);
|
||||
|
||||
/// Returns true if no part of physical register \p Reg is live.
|
||||
bool available(unsigned Reg) const {
|
||||
for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) {
|
||||
if (Units.test(*Unit))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Updates liveness when stepping backwards over the instruction \p MI.
|
||||
void stepBackward(const MachineInstr &MI);
|
||||
|
||||
/// Mark all register units live during instruction \p MI.
|
||||
/// This can be used to accumulate live/unoccupied registers over a range of
|
||||
/// instructions.
|
||||
void accumulateBackward(const MachineInstr &MI);
|
||||
|
||||
/// Adds registers living out of block \p MBB.
|
||||
/// Live out registers are the union of the live-in registers of the successor
|
||||
/// blocks and pristine registers. Live out registers of the end block are the
|
||||
/// callee saved registers.
|
||||
void addLiveOuts(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds registers living into block \p MBB.
|
||||
void addLiveIns(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds all register units marked in the bitvector \p RegUnits.
|
||||
void addUnits(const BitVector &RegUnits) {
|
||||
Units |= RegUnits;
|
||||
}
|
||||
/// Removes all register units marked in the bitvector \p RegUnits.
|
||||
void removeUnits(const BitVector &RegUnits) {
|
||||
Units.reset(RegUnits);
|
||||
}
|
||||
/// Return the internal bitvector representation of the set.
|
||||
const BitVector &getBitVector() const {
|
||||
return Units;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVEREGUNITS_H
|
@ -1,4 +1,4 @@
|
||||
//== llvm/CodeGen/GlobalISel/LowLevelType.h -------------------- -*- C++ -*-==//
|
||||
//== llvm/CodeGen/LowLevelType.h ------------------------------- -*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -10,197 +10,23 @@
|
||||
/// Implement a low-level type suitable for MachineInstr level instruction
|
||||
/// selection.
|
||||
///
|
||||
/// For a type attached to a MachineInstr, we only care about 2 details: total
|
||||
/// size and the number of vector lanes (if any). Accordingly, there are 4
|
||||
/// possible valid type-kinds:
|
||||
///
|
||||
/// * `sN` for scalars and aggregates
|
||||
/// * `<N x sM>` for vectors, which must have at least 2 elements.
|
||||
/// * `pN` for pointers
|
||||
///
|
||||
/// Other information required for correct selection is expected to be carried
|
||||
/// by the opcode, or non-type flags. For example the distinction between G_ADD
|
||||
/// and G_FADD for int/float or fast-math flags.
|
||||
/// This provides the CodeGen aspects of LowLevelType, such as Type conversion.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LOWLEVELTYPE_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LOWLEVELTYPE_H
|
||||
#ifndef LLVM_CODEGEN_LOWLEVELTYPE_H
|
||||
#define LLVM_CODEGEN_LOWLEVELTYPE_H
|
||||
|
||||
#include <cassert>
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DataLayout;
|
||||
class LLVMContext;
|
||||
class Type;
|
||||
class raw_ostream;
|
||||
|
||||
class LLT {
|
||||
public:
|
||||
enum TypeKind : uint16_t {
|
||||
Invalid,
|
||||
Scalar,
|
||||
Pointer,
|
||||
Vector,
|
||||
};
|
||||
|
||||
/// Get a low-level scalar or aggregate "bag of bits".
|
||||
static LLT scalar(unsigned SizeInBits) {
|
||||
assert(SizeInBits > 0 && "invalid scalar size");
|
||||
return LLT{Scalar, 1, SizeInBits};
|
||||
}
|
||||
|
||||
/// Get a low-level pointer in the given address space (defaulting to 0).
|
||||
static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) {
|
||||
return LLT{Pointer, AddressSpace, SizeInBits};
|
||||
}
|
||||
|
||||
/// Get a low-level vector of some number of elements and element width.
|
||||
/// \p NumElements must be at least 2.
|
||||
static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) {
|
||||
assert(NumElements > 1 && "invalid number of vector elements");
|
||||
return LLT{Vector, NumElements, ScalarSizeInBits};
|
||||
}
|
||||
|
||||
/// Get a low-level vector of some number of elements and element type.
|
||||
static LLT vector(uint16_t NumElements, LLT ScalarTy) {
|
||||
assert(NumElements > 1 && "invalid number of vector elements");
|
||||
assert(ScalarTy.isScalar() && "invalid vector element type");
|
||||
return LLT{Vector, NumElements, ScalarTy.getSizeInBits()};
|
||||
}
|
||||
|
||||
explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits)
|
||||
: SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) {
|
||||
assert((Kind != Vector || ElementsOrAddrSpace > 1) &&
|
||||
"invalid number of vector elements");
|
||||
}
|
||||
|
||||
explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {}
|
||||
|
||||
/// Construct a low-level type based on an LLVM type.
|
||||
explicit LLT(Type &Ty, const DataLayout &DL);
|
||||
|
||||
explicit LLT(MVT VT);
|
||||
|
||||
bool isValid() const { return Kind != Invalid; }
|
||||
|
||||
bool isScalar() const { return Kind == Scalar; }
|
||||
|
||||
bool isPointer() const { return Kind == Pointer; }
|
||||
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
|
||||
/// Returns the number of elements in a vector LLT. Must only be called on
|
||||
/// vector types.
|
||||
uint16_t getNumElements() const {
|
||||
assert(isVector() && "cannot get number of elements on scalar/aggregate");
|
||||
return ElementsOrAddrSpace;
|
||||
}
|
||||
|
||||
/// Returns the total size of the type. Must only be called on sized types.
|
||||
unsigned getSizeInBits() const {
|
||||
if (isPointer() || isScalar())
|
||||
return SizeInBits;
|
||||
return SizeInBits * ElementsOrAddrSpace;
|
||||
}
|
||||
|
||||
unsigned getScalarSizeInBits() const {
|
||||
return SizeInBits;
|
||||
}
|
||||
|
||||
unsigned getAddressSpace() const {
|
||||
assert(isPointer() && "cannot get address space of non-pointer type");
|
||||
return ElementsOrAddrSpace;
|
||||
}
|
||||
|
||||
/// Returns the vector's element type. Only valid for vector types.
|
||||
LLT getElementType() const {
|
||||
assert(isVector() && "cannot get element type of scalar/aggregate");
|
||||
return scalar(SizeInBits);
|
||||
}
|
||||
|
||||
/// Get a low-level type with half the size of the original, by halving the
|
||||
/// size of the scalar type involved. For example `s32` will become `s16`,
|
||||
/// `<2 x s32>` will become `<2 x s16>`.
|
||||
LLT halfScalarSize() const {
|
||||
assert(!isPointer() && getScalarSizeInBits() > 1 &&
|
||||
getScalarSizeInBits() % 2 == 0 && "cannot half size of this type");
|
||||
return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2};
|
||||
}
|
||||
|
||||
/// Get a low-level type with twice the size of the original, by doubling the
|
||||
/// size of the scalar type involved. For example `s32` will become `s64`,
|
||||
/// `<2 x s32>` will become `<2 x s64>`.
|
||||
LLT doubleScalarSize() const {
|
||||
assert(!isPointer() && "cannot change size of this type");
|
||||
return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2};
|
||||
}
|
||||
|
||||
/// Get a low-level type with half the size of the original, by halving the
|
||||
/// number of vector elements of the scalar type involved. The source must be
|
||||
/// a vector type with an even number of elements. For example `<4 x s32>`
|
||||
/// will become `<2 x s32>`, `<2 x s32>` will become `s32`.
|
||||
LLT halfElements() const {
|
||||
assert(isVector() && ElementsOrAddrSpace % 2 == 0 &&
|
||||
"cannot half odd vector");
|
||||
if (ElementsOrAddrSpace == 2)
|
||||
return scalar(SizeInBits);
|
||||
|
||||
return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2),
|
||||
SizeInBits};
|
||||
}
|
||||
|
||||
/// Get a low-level type with twice the size of the original, by doubling the
|
||||
/// number of vector elements of the scalar type involved. The source must be
|
||||
/// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling
|
||||
/// the number of elements in sN produces <2 x sN>.
|
||||
LLT doubleElements() const {
|
||||
assert(!isPointer() && "cannot double elements in pointer");
|
||||
return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2),
|
||||
SizeInBits};
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
bool operator==(const LLT &RHS) const {
|
||||
return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits &&
|
||||
ElementsOrAddrSpace == RHS.ElementsOrAddrSpace;
|
||||
}
|
||||
|
||||
bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
|
||||
|
||||
friend struct DenseMapInfo<LLT>;
|
||||
private:
|
||||
unsigned SizeInBits;
|
||||
uint16_t ElementsOrAddrSpace;
|
||||
TypeKind Kind;
|
||||
};
|
||||
|
||||
inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
|
||||
Ty.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
template<> struct DenseMapInfo<LLT> {
|
||||
static inline LLT getEmptyKey() {
|
||||
return LLT{LLT::Invalid, 0, -1u};
|
||||
}
|
||||
static inline LLT getTombstoneKey() {
|
||||
return LLT{LLT::Invalid, 0, -2u};
|
||||
}
|
||||
static inline unsigned getHashValue(const LLT &Ty) {
|
||||
uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) |
|
||||
((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind;
|
||||
return DenseMapInfo<uint64_t>::getHashValue(Val);
|
||||
}
|
||||
static bool isEqual(const LLT &LHS, const LLT &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
/// Construct a low-level type based on an LLVM type.
|
||||
LLT getLLTForType(Type &Ty, const DataLayout &DL);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_LOWLEVELTYPE_H
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user