1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-01 08:27:59 +00:00

Update llvm to trunk r290819 and resolve conflicts.

This commit is contained in:
Dimitry Andric 2017-01-02 21:25:48 +00:00
commit d88c1a5a57
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang400-import/; revision=311142
2400 changed files with 224635 additions and 102682 deletions

View File

@ -54,51 +54,6 @@ extern "C" {
* @{
*/
typedef enum {
LLVMZExtAttribute = 1<<0,
LLVMSExtAttribute = 1<<1,
LLVMNoReturnAttribute = 1<<2,
LLVMInRegAttribute = 1<<3,
LLVMStructRetAttribute = 1<<4,
LLVMNoUnwindAttribute = 1<<5,
LLVMNoAliasAttribute = 1<<6,
LLVMByValAttribute = 1<<7,
LLVMNestAttribute = 1<<8,
LLVMReadNoneAttribute = 1<<9,
LLVMReadOnlyAttribute = 1<<10,
LLVMNoInlineAttribute = 1<<11,
LLVMAlwaysInlineAttribute = 1<<12,
LLVMOptimizeForSizeAttribute = 1<<13,
LLVMStackProtectAttribute = 1<<14,
LLVMStackProtectReqAttribute = 1<<15,
LLVMAlignment = 31<<16,
LLVMNoCaptureAttribute = 1<<21,
LLVMNoRedZoneAttribute = 1<<22,
LLVMNoImplicitFloatAttribute = 1<<23,
LLVMNakedAttribute = 1<<24,
LLVMInlineHintAttribute = 1<<25,
LLVMStackAlignment = 7<<26,
LLVMReturnsTwice = 1 << 29,
LLVMUWTable = 1 << 30,
LLVMNonLazyBind = 1 << 31
/* FIXME: These attributes are currently not included in the C API as
a temporary measure until the API/ABI impact to the C API is understood
and the path forward agreed upon.
LLVMSanitizeAddressAttribute = 1ULL << 32,
LLVMStackProtectStrongAttribute = 1ULL<<35,
LLVMColdAttribute = 1ULL << 40,
LLVMOptimizeNoneAttribute = 1ULL << 42,
LLVMInAllocaAttribute = 1ULL << 43,
LLVMNonNullAttribute = 1ULL << 44,
LLVMJumpTableAttribute = 1ULL << 45,
LLVMConvergentAttribute = 1ULL << 46,
LLVMSafeStackAttribute = 1ULL << 47,
LLVMSwiftSelfAttribute = 1ULL << 48,
LLVMSwiftErrorAttribute = 1ULL << 49,
*/
} LLVMAttribute;
typedef enum {
/* Terminator Instructions */
LLVMRet = 1,
@ -1752,6 +1707,7 @@ LLVMValueRef LLVMConstNSWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant)
LLVMValueRef LLVMConstNUWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstFMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstUDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstExactUDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstSDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstExactSDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
LLVMValueRef LLVMConstFDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant);
@ -2010,8 +1966,6 @@ void LLVMSetGC(LLVMValueRef Fn, const char *Name);
*
* @see llvm::Function::addAttribute()
*/
void LLVMAddFunctionAttr(LLVMValueRef Fn, LLVMAttribute PA);
void LLVMAddAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
LLVMAttributeRef A);
unsigned LLVMGetAttributeCountAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx);
@ -2035,18 +1989,6 @@ void LLVMRemoveStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
void LLVMAddTargetDependentFunctionAttr(LLVMValueRef Fn, const char *A,
const char *V);
/**
* Obtain an attribute from a function.
*
* @see llvm::Function::getAttributes()
*/
LLVMAttribute LLVMGetFunctionAttr(LLVMValueRef Fn);
/**
* Remove an attribute from a function.
*/
void LLVMRemoveFunctionAttr(LLVMValueRef Fn, LLVMAttribute PA);
/**
* @defgroup LLVMCCoreValueFunctionParameters Function Parameters
*
@ -2128,25 +2070,6 @@ LLVMValueRef LLVMGetNextParam(LLVMValueRef Arg);
*/
LLVMValueRef LLVMGetPreviousParam(LLVMValueRef Arg);
/**
* Add an attribute to a function argument.
*
* @see llvm::Argument::addAttr()
*/
void LLVMAddAttribute(LLVMValueRef Arg, LLVMAttribute PA);
/**
* Remove an attribute from a function argument.
*
* @see llvm::Argument::removeAttr()
*/
void LLVMRemoveAttribute(LLVMValueRef Arg, LLVMAttribute PA);
/**
* Get an attribute from a function argument.
*/
LLVMAttribute LLVMGetAttribute(LLVMValueRef Arg);
/**
* Set the alignment for a function parameter.
*
@ -2595,9 +2518,6 @@ void LLVMSetInstructionCallConv(LLVMValueRef Instr, unsigned CC);
*/
unsigned LLVMGetInstructionCallConv(LLVMValueRef Instr);
void LLVMAddInstrAttribute(LLVMValueRef Instr, unsigned index, LLVMAttribute);
void LLVMRemoveInstrAttribute(LLVMValueRef Instr, unsigned index,
LLVMAttribute);
void LLVMSetInstrParamAlignment(LLVMValueRef Instr, unsigned index,
unsigned Align);
@ -2962,6 +2882,8 @@ LLVMValueRef LLVMBuildFMul(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS,
const char *Name);
LLVMValueRef LLVMBuildUDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS,
const char *Name);
LLVMValueRef LLVMBuildExactUDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS,
const char *Name);
LLVMValueRef LLVMBuildSDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS,
const char *Name);
LLVMValueRef LLVMBuildExactSDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS,

View File

@ -56,6 +56,9 @@ void LLVMAddMergedLoadStoreMotionPass(LLVMPassManagerRef PM);
/** See llvm::createGVNPass function. */
void LLVMAddGVNPass(LLVMPassManagerRef PM);
/** See llvm::createGVNPass function. */
void LLVMAddNewGVNPass(LLVMPassManagerRef PM);
/** See llvm::createIndVarSimplifyPass function. */
void LLVMAddIndVarSimplifyPass(LLVMPassManagerRef PM);
@ -135,6 +138,9 @@ void LLVMAddCorrelatedValuePropagationPass(LLVMPassManagerRef PM);
/** See llvm::createEarlyCSEPass function */
void LLVMAddEarlyCSEPass(LLVMPassManagerRef PM);
/** See llvm::createEarlyCSEPass function */
void LLVMAddEarlyCSEMemSSAPass(LLVMPassManagerRef PM);
/** See llvm::createLowerExpectIntrinsicPass function */
void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM);

View File

@ -44,7 +44,7 @@ typedef bool lto_bool_t;
* @{
*/
#define LTO_API_VERSION 20
#define LTO_API_VERSION 21
/**
* \since prior to LTO_API_VERSION=3
@ -145,10 +145,10 @@ extern lto_bool_t
lto_module_has_objc_category(const void *mem, size_t length);
/**
* Checks if a buffer is a loadable object file.
*
* \since prior to LTO_API_VERSION=3
*/
* Checks if a buffer is a loadable object file.
*
* \since prior to LTO_API_VERSION=3
*/
extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem,
size_t length);
@ -636,6 +636,29 @@ extern unsigned int thinlto_module_get_num_objects(thinlto_code_gen_t cg);
extern LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg,
unsigned int index);
/**
* Returns the number of object files produced by the ThinLTO CodeGenerator.
*
* It usually matches the number of input files, but this is not a guarantee of
* the API and may change in future implementation, so the client should not
* assume it.
*
* \since LTO_API_VERSION=21
*/
unsigned int thinlto_module_get_num_object_files(thinlto_code_gen_t cg);
/**
* Returns the path to the ith object file produced by the ThinLTO
* CodeGenerator.
*
* Client should use \p thinlto_module_get_num_object_files() to get the number
* of available objects.
*
* \since LTO_API_VERSION=21
*/
const char *thinlto_module_get_object_file(thinlto_code_gen_t cg,
unsigned int index);
/**
* Sets which PIC code model to generate.
* Returns true on error (check lto_get_error_message() for details).
@ -724,6 +747,17 @@ extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg,
extern void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg,
const char *save_temps_dir);
/**
* Set the path to a directory where to save generated object files. This
* path can be used by a linker to request on-disk files instead of in-memory
* buffers. When set, results are available through
* thinlto_module_get_object_file() instead of thinlto_module_get_object().
*
* \since LTO_API_VERSION=21
*/
void thinlto_set_generated_objects_dir(thinlto_code_gen_t cg,
const char *save_temps_dir);
/**
* Sets the cpu to generate code for.
*

View File

@ -18,12 +18,16 @@
#define LLVM_ADT_APFLOAT_H
#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
#include <memory>
namespace llvm {
struct fltSemantics;
class APSInt;
class StringRef;
class APFloat;
class raw_ostream;
template <typename T> class SmallVectorImpl;
@ -121,33 +125,30 @@ enum lostFraction { // Example of truncated bits:
///
/// New operations: sqrt, IEEE remainder, C90 fmod, nexttoward.
///
class APFloat {
public:
// This is the common type definitions shared by APFloat and its internal
// implementation classes. This struct should not define any non-static data
// members.
struct APFloatBase {
/// 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();
static const fltSemantics &IEEEsingle();
static const fltSemantics &IEEEdouble();
static const fltSemantics &IEEEquad();
static const fltSemantics &PPCDoubleDouble();
static const fltSemantics &x87DoubleExtended();
/// A Pseudo fltsemantic used to construct APFloats that cannot conflict with
/// anything real.
static const fltSemantics Bogus;
static const fltSemantics &Bogus();
/// @}
static unsigned int semanticsPrecision(const fltSemantics &);
static ExponentType semanticsMinExponent(const fltSemantics &);
static ExponentType semanticsMaxExponent(const fltSemantics &);
static unsigned int semanticsSizeInBits(const fltSemantics &);
/// IEEE-754R 5.11: Floating Point Comparison Relations.
enum cmpResult {
cmpLessThan,
@ -190,19 +191,39 @@ class APFloat {
uninitialized
};
/// \brief Enumeration of \c ilogb error results.
enum IlogbErrorKinds {
IEK_Zero = INT_MIN + 1,
IEK_NaN = INT_MIN,
IEK_Inf = INT_MAX
};
static unsigned int semanticsPrecision(const fltSemantics &);
static ExponentType semanticsMinExponent(const fltSemantics &);
static ExponentType semanticsMaxExponent(const fltSemantics &);
static unsigned int semanticsSizeInBits(const fltSemantics &);
/// Returns the size of the floating point number (in bits) in the given
/// semantics.
static unsigned getSizeInBits(const fltSemantics &Sem);
};
namespace detail {
class IEEEFloat final : public APFloatBase {
public:
/// \name Constructors
/// @{
APFloat(const fltSemantics &); // Default construct to 0.0
APFloat(const fltSemantics &, StringRef);
APFloat(const fltSemantics &, integerPart);
APFloat(const fltSemantics &, uninitializedTag);
APFloat(const fltSemantics &, const APInt &);
explicit APFloat(double d);
explicit APFloat(float f);
APFloat(const APFloat &);
APFloat(APFloat &&);
~APFloat();
IEEEFloat(const fltSemantics &); // Default construct to 0.0
IEEEFloat(const fltSemantics &, integerPart);
IEEEFloat(const fltSemantics &, uninitializedTag);
IEEEFloat(const fltSemantics &, const APInt &);
explicit IEEEFloat(double d);
explicit IEEEFloat(float f);
IEEEFloat(const IEEEFloat &);
IEEEFloat(IEEEFloat &&);
~IEEEFloat();
/// @}
@ -212,79 +233,6 @@ class APFloat {
/// \name Convenience "constructors"
/// @{
/// Factory for Positive and Negative Zero.
///
/// \param Negative True iff the number should be negative.
static APFloat getZero(const fltSemantics &Sem, bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeZero(Negative);
return Val;
}
/// Factory for Positive and Negative Infinity.
///
/// \param Negative True iff the number should be negative.
static APFloat getInf(const fltSemantics &Sem, bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeInf(Negative);
return Val;
}
/// Factory for QNaN values.
///
/// \param Negative - True iff the NaN generated should be negative.
/// \param type - The unspecified fill bits for creating the NaN, 0 by
/// default. The value is truncated as necessary.
static APFloat getNaN(const fltSemantics &Sem, bool Negative = false,
unsigned type = 0) {
if (type) {
APInt fill(64, type);
return getQNaN(Sem, Negative, &fill);
} else {
return getQNaN(Sem, Negative, nullptr);
}
}
/// Factory for QNaN values.
static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
const APInt *payload = nullptr) {
return makeNaN(Sem, false, Negative, payload);
}
/// Factory for SNaN values.
static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
const APInt *payload = nullptr) {
return makeNaN(Sem, true, Negative, payload);
}
/// Returns the largest finite number in the given semantics.
///
/// \param Negative - True iff the number should be negative
static APFloat getLargest(const fltSemantics &Sem, bool Negative = false);
/// Returns the smallest (by magnitude) finite number in the given semantics.
/// Might be denormalized, which implies a relative loss of precision.
///
/// \param Negative - True iff the number should be negative
static APFloat getSmallest(const fltSemantics &Sem, bool Negative = false);
/// Returns the smallest (by magnitude) normalized finite number in the given
/// semantics.
///
/// \param Negative - True iff the number should be negative
static APFloat getSmallestNormalized(const fltSemantics &Sem,
bool Negative = false);
/// Returns a float which is bitcasted from an all one value int.
///
/// \param BitWidth - Select float type
/// \param isIEEE - If 128 bit number, select between PPC and IEEE
static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
/// Returns the size of the floating point number (in bits) in the given
/// semantics.
static unsigned getSizeInBits(const fltSemantics &Sem);
/// @}
/// Used to insert APFloat objects, or objects that contain APFloat objects,
@ -294,47 +242,47 @@ class APFloat {
/// \name Arithmetic
/// @{
opStatus add(const APFloat &, roundingMode);
opStatus subtract(const APFloat &, roundingMode);
opStatus multiply(const APFloat &, roundingMode);
opStatus divide(const APFloat &, roundingMode);
opStatus add(const IEEEFloat &, roundingMode);
opStatus subtract(const IEEEFloat &, roundingMode);
opStatus multiply(const IEEEFloat &, roundingMode);
opStatus divide(const IEEEFloat &, roundingMode);
/// IEEE remainder.
opStatus remainder(const APFloat &);
opStatus remainder(const IEEEFloat &);
/// C fmod, or llvm frem.
opStatus mod(const APFloat &);
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
opStatus mod(const IEEEFloat &);
opStatus fusedMultiplyAdd(const IEEEFloat &, const IEEEFloat &, roundingMode);
opStatus roundToIntegral(roundingMode);
/// IEEE-754R 5.3.1: nextUp/nextDown.
opStatus next(bool nextDown);
/// \brief Operator+ overload which provides the default
/// \c nmNearestTiesToEven rounding mode and *no* error checking.
APFloat operator+(const APFloat &RHS) const {
APFloat Result = *this;
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.
APFloat operator-(const APFloat &RHS) const {
APFloat Result = *this;
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.
APFloat operator*(const APFloat &RHS) const {
APFloat Result = *this;
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.
APFloat operator/(const APFloat &RHS) const {
APFloat Result = *this;
IEEEFloat operator/(const IEEEFloat &RHS) const {
IEEEFloat Result = *this;
Result.divide(RHS, rmNearestTiesToEven);
return Result;
}
@ -346,11 +294,11 @@ class APFloat {
void changeSign();
void clearSign();
void copySign(const APFloat &);
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 APFloat copySign(APFloat Value, const APFloat &Sign) {
static IEEEFloat copySign(IEEEFloat Value, const IEEEFloat &Sign) {
Value.copySign(Sign);
return Value;
}
@ -379,14 +327,14 @@ class APFloat {
/// The definition of equality is not straightforward for floating point, so
/// we won't use operator==. Use one of the following, or write whatever it
/// is you really mean.
bool operator==(const APFloat &) const = delete;
bool operator==(const IEEEFloat &) const = delete;
/// IEEE comparison with another floating point number (NaNs compare
/// unordered, 0==-0).
cmpResult compare(const APFloat &) const;
cmpResult compare(const IEEEFloat &) const;
/// Bitwise comparison for equality (QNaNs compare equal, 0!=-0).
bool bitwiseIsEqual(const APFloat &) const;
bool bitwiseIsEqual(const IEEEFloat &) const;
/// Write out a hexadecimal representation of the floating point value to DST,
/// which must be of sufficient size, in the C99 form [-]0xh.hhhhp[+-]d.
@ -456,8 +404,8 @@ class APFloat {
/// @}
APFloat &operator=(const APFloat &);
APFloat &operator=(APFloat &&);
IEEEFloat &operator=(const IEEEFloat &);
IEEEFloat &operator=(IEEEFloat &&);
/// \brief Overload to compute a hash code for an APFloat value.
///
@ -468,7 +416,7 @@ class APFloat {
/// emphasizes producing different codes for different inputs in order to
/// be used in canonicalization and memoization. As such, equality is
/// bitwiseIsEqual, and 0 != -0.
friend hash_code hash_value(const APFloat &Arg);
friend hash_code hash_value(const IEEEFloat &Arg);
/// Converts this value into a decimal string.
///
@ -495,14 +443,7 @@ class APFloat {
/// If this value has an exact multiplicative inverse, store it in inv and
/// return true.
bool getExactInverse(APFloat *inv) const;
/// \brief Enumeration of \c ilogb error results.
enum IlogbErrorKinds {
IEK_Zero = INT_MIN+1,
IEK_NaN = INT_MIN,
IEK_Inf = INT_MAX
};
bool getExactInverse(IEEEFloat *inv) const;
/// \brief Returns the exponent of the internal representation of the APFloat.
///
@ -513,15 +454,35 @@ class APFloat {
/// 0 -> \c IEK_Zero
/// Inf -> \c IEK_Inf
///
friend int ilogb(const APFloat &Arg);
friend int ilogb(const IEEEFloat &Arg);
/// \brief Returns: X * 2^Exp for integral exponents.
friend APFloat scalbn(APFloat X, int Exp, roundingMode);
friend IEEEFloat scalbn(IEEEFloat X, int Exp, roundingMode);
friend APFloat frexp(const APFloat &X, int &Exp, roundingMode);
friend IEEEFloat frexp(const IEEEFloat &X, int &Exp, roundingMode);
/// \name Special value setters.
/// @{
void makeLargest(bool Neg = false);
void makeSmallest(bool Neg = false);
void makeNaN(bool SNaN = false, bool Neg = false,
const APInt *fill = nullptr);
void makeInf(bool Neg = false);
void makeZero(bool Neg = false);
void makeQuiet();
/// Returns the smallest (by magnitude) normalized finite number in the given
/// semantics.
///
/// \param Negative - True iff the number should be negative
void makeSmallestNormalized(bool Negative = false);
/// @}
cmpResult compareAbsoluteValue(const IEEEFloat &) const;
private:
/// \name Simple Queries
/// @{
@ -534,11 +495,11 @@ class APFloat {
/// \name Significand operations.
/// @{
integerPart addSignificand(const APFloat &);
integerPart subtractSignificand(const APFloat &, integerPart);
lostFraction addOrSubtractSignificand(const APFloat &, bool subtract);
lostFraction multiplySignificand(const APFloat &, const APFloat *);
lostFraction divideSignificand(const APFloat &);
integerPart addSignificand(const IEEEFloat &);
integerPart subtractSignificand(const IEEEFloat &, integerPart);
lostFraction addOrSubtractSignificand(const IEEEFloat &, bool subtract);
lostFraction multiplySignificand(const IEEEFloat &, const IEEEFloat *);
lostFraction divideSignificand(const IEEEFloat &);
void incrementSignificand();
void initialize(const fltSemantics *);
void shiftSignificandLeft(unsigned int);
@ -556,25 +517,10 @@ class APFloat {
/// \name Arithmetic on special values.
/// @{
opStatus addOrSubtractSpecials(const APFloat &, bool subtract);
opStatus divideSpecials(const APFloat &);
opStatus multiplySpecials(const APFloat &);
opStatus modSpecials(const APFloat &);
/// @}
/// \name Special value setters.
/// @{
void makeLargest(bool Neg = false);
void makeSmallest(bool Neg = false);
void makeNaN(bool SNaN = false, bool Neg = false,
const APInt *fill = nullptr);
static APFloat makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative,
const APInt *fill);
void makeInf(bool Neg = false);
void makeZero(bool Neg = false);
void makeQuiet();
opStatus addOrSubtractSpecials(const IEEEFloat &, bool subtract);
opStatus divideSpecials(const IEEEFloat &);
opStatus multiplySpecials(const IEEEFloat &);
opStatus modSpecials(const IEEEFloat &);
/// @}
@ -583,8 +529,7 @@ class APFloat {
bool convertFromStringSpecials(StringRef str);
opStatus normalize(roundingMode, lostFraction);
opStatus addOrSubtract(const APFloat &, roundingMode, bool subtract);
cmpResult compareAbsoluteValue(const APFloat &) const;
opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract);
opStatus handleOverflow(roundingMode);
bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const;
opStatus convertToSignExtendedInteger(integerPart *, unsigned int, bool,
@ -614,10 +559,11 @@ class APFloat {
void initFromF80LongDoubleAPInt(const APInt &api);
void initFromPPCDoubleDoubleAPInt(const APInt &api);
void assign(const APFloat &);
void copySignificand(const APFloat &);
void assign(const IEEEFloat &);
void copySignificand(const IEEEFloat &);
void freeSignificand();
/// Note: this must be the first data member.
/// The semantics that this value obeys.
const fltSemantics *semantics;
@ -642,20 +588,513 @@ class APFloat {
unsigned int sign : 1;
};
hash_code hash_value(const IEEEFloat &Arg);
int ilogb(const IEEEFloat &Arg);
IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode);
IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM);
// This mode implements more precise float in terms of two APFloats.
// The interface and layout is designed for arbitray underlying semantics,
// though currently only PPCDoubleDouble semantics are supported, whose
// corresponding underlying semantics are IEEEdouble.
class DoubleAPFloat final : public APFloatBase {
// Note: this must be the first data member.
const fltSemantics *Semantics;
std::unique_ptr<APFloat[]> Floats;
opStatus addImpl(const APFloat &a, const APFloat &aa, const APFloat &c,
const APFloat &cc, roundingMode RM);
opStatus addWithSpecial(const DoubleAPFloat &LHS, const DoubleAPFloat &RHS,
DoubleAPFloat &Out, roundingMode RM);
public:
DoubleAPFloat(const fltSemantics &S);
DoubleAPFloat(const fltSemantics &S, uninitializedTag);
DoubleAPFloat(const fltSemantics &S, integerPart);
DoubleAPFloat(const fltSemantics &S, const APInt &I);
DoubleAPFloat(const fltSemantics &S, APFloat &&First, APFloat &&Second);
DoubleAPFloat(const DoubleAPFloat &RHS);
DoubleAPFloat(DoubleAPFloat &&RHS);
DoubleAPFloat &operator=(const DoubleAPFloat &RHS);
DoubleAPFloat &operator=(DoubleAPFloat &&RHS) {
if (this != &RHS) {
this->~DoubleAPFloat();
new (this) DoubleAPFloat(std::move(RHS));
}
return *this;
}
bool needsCleanup() const { return Floats != nullptr; }
APFloat &getFirst() { return Floats[0]; }
const APFloat &getFirst() const { return Floats[0]; }
APFloat &getSecond() { return Floats[1]; }
const APFloat &getSecond() const { return Floats[1]; }
opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
void changeSign();
cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
fltCategory getCategory() const;
bool isNegative() const;
void makeInf(bool Neg);
void makeNaN(bool SNaN, bool Neg, const APInt *fill);
};
} // End detail namespace
// This is a interface class that is currently forwarding functionalities from
// detail::IEEEFloat.
class APFloat : public APFloatBase {
typedef detail::IEEEFloat IEEEFloat;
typedef detail::DoubleAPFloat DoubleAPFloat;
static_assert(std::is_standard_layout<IEEEFloat>::value, "");
union Storage {
const fltSemantics *semantics;
IEEEFloat IEEE;
DoubleAPFloat Double;
explicit Storage(IEEEFloat F, const fltSemantics &S);
explicit Storage(DoubleAPFloat F, const fltSemantics &S)
: Double(std::move(F)) {
assert(&S == &PPCDoubleDouble());
}
template <typename... ArgTypes>
Storage(const fltSemantics &Semantics, ArgTypes &&... Args) {
if (usesLayout<IEEEFloat>(Semantics)) {
new (&IEEE) IEEEFloat(Semantics, std::forward<ArgTypes>(Args)...);
return;
}
if (usesLayout<DoubleAPFloat>(Semantics)) {
new (&Double) DoubleAPFloat(Semantics, std::forward<ArgTypes>(Args)...);
return;
}
llvm_unreachable("Unexpected semantics");
}
~Storage() {
if (usesLayout<IEEEFloat>(*semantics)) {
IEEE.~IEEEFloat();
return;
}
if (usesLayout<DoubleAPFloat>(*semantics)) {
Double.~DoubleAPFloat();
return;
}
llvm_unreachable("Unexpected semantics");
}
Storage(const Storage &RHS) {
if (usesLayout<IEEEFloat>(*RHS.semantics)) {
new (this) IEEEFloat(RHS.IEEE);
return;
}
if (usesLayout<DoubleAPFloat>(*RHS.semantics)) {
new (this) DoubleAPFloat(RHS.Double);
return;
}
llvm_unreachable("Unexpected semantics");
}
Storage(Storage &&RHS) {
if (usesLayout<IEEEFloat>(*RHS.semantics)) {
new (this) IEEEFloat(std::move(RHS.IEEE));
return;
}
if (usesLayout<DoubleAPFloat>(*RHS.semantics)) {
new (this) DoubleAPFloat(std::move(RHS.Double));
return;
}
llvm_unreachable("Unexpected semantics");
}
Storage &operator=(const Storage &RHS) {
if (usesLayout<IEEEFloat>(*semantics) &&
usesLayout<IEEEFloat>(*RHS.semantics)) {
IEEE = RHS.IEEE;
} else if (usesLayout<DoubleAPFloat>(*semantics) &&
usesLayout<DoubleAPFloat>(*RHS.semantics)) {
Double = RHS.Double;
} else if (this != &RHS) {
this->~Storage();
new (this) Storage(RHS);
}
return *this;
}
Storage &operator=(Storage &&RHS) {
if (usesLayout<IEEEFloat>(*semantics) &&
usesLayout<IEEEFloat>(*RHS.semantics)) {
IEEE = std::move(RHS.IEEE);
} else if (usesLayout<DoubleAPFloat>(*semantics) &&
usesLayout<DoubleAPFloat>(*RHS.semantics)) {
Double = std::move(RHS.Double);
} else if (this != &RHS) {
this->~Storage();
new (this) Storage(std::move(RHS));
}
return *this;
}
} U;
template <typename T> static bool usesLayout(const fltSemantics &Semantics) {
static_assert(std::is_same<T, IEEEFloat>::value ||
std::is_same<T, DoubleAPFloat>::value, "");
if (std::is_same<T, DoubleAPFloat>::value) {
return &Semantics == &PPCDoubleDouble();
}
return &Semantics != &PPCDoubleDouble();
}
IEEEFloat &getIEEE() {
if (usesLayout<IEEEFloat>(*U.semantics))
return U.IEEE;
if (usesLayout<DoubleAPFloat>(*U.semantics))
return U.Double.getFirst().U.IEEE;
llvm_unreachable("Unexpected semantics");
}
const IEEEFloat &getIEEE() const {
if (usesLayout<IEEEFloat>(*U.semantics))
return U.IEEE;
if (usesLayout<DoubleAPFloat>(*U.semantics))
return U.Double.getFirst().U.IEEE;
llvm_unreachable("Unexpected semantics");
}
void makeZero(bool Neg) { getIEEE().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 makeNaN(bool SNaN, bool Neg, const APInt *fill) {
getIEEE().makeNaN(SNaN, Neg, fill);
}
void makeLargest(bool Neg) { getIEEE().makeLargest(Neg); }
void makeSmallest(bool Neg) { getIEEE().makeSmallest(Neg); }
void makeSmallestNormalized(bool Neg) {
getIEEE().makeSmallestNormalized(Neg);
}
// FIXME: This is due to clang 3.3 (or older version) always checks for the
// default constructor in an array aggregate initialization, even if no
// elements in the array is default initialized.
APFloat() : U(IEEEdouble()) {
llvm_unreachable("This is a workaround for old clang.");
}
explicit APFloat(IEEEFloat F, const fltSemantics &S) : U(std::move(F), S) {}
explicit APFloat(DoubleAPFloat F, const fltSemantics &S)
: U(std::move(F), S) {}
cmpResult compareAbsoluteValue(const APFloat &RHS) const {
assert(&getSemantics() == &RHS.getSemantics());
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.compareAbsoluteValue(RHS.U.IEEE);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.compareAbsoluteValue(RHS.U.Double);
llvm_unreachable("Unexpected semantics");
}
public:
APFloat(const fltSemantics &Semantics) : U(Semantics) {}
APFloat(const fltSemantics &Semantics, StringRef S);
APFloat(const fltSemantics &Semantics, integerPart I) : U(Semantics, I) {}
// TODO: Remove this constructor. This isn't faster than the first one.
APFloat(const fltSemantics &Semantics, uninitializedTag)
: U(Semantics, uninitialized) {}
APFloat(const fltSemantics &Semantics, const APInt &I) : U(Semantics, I) {}
explicit APFloat(double d) : U(IEEEFloat(d), IEEEdouble()) {}
explicit APFloat(float f) : U(IEEEFloat(f), IEEEsingle()) {}
APFloat(const APFloat &RHS) = default;
APFloat(APFloat &&RHS) = default;
~APFloat() = default;
bool needsCleanup() const {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.needsCleanup();
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.needsCleanup();
llvm_unreachable("Unexpected semantics");
}
/// Factory for Positive and Negative Zero.
///
/// \param Negative True iff the number should be negative.
static APFloat getZero(const fltSemantics &Sem, bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeZero(Negative);
return Val;
}
/// Factory for Positive and Negative Infinity.
///
/// \param Negative True iff the number should be negative.
static APFloat getInf(const fltSemantics &Sem, bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeInf(Negative);
return Val;
}
/// Factory for NaN values.
///
/// \param Negative - True iff the NaN generated should be negative.
/// \param type - The unspecified fill bits for creating the NaN, 0 by
/// default. The value is truncated as necessary.
static APFloat getNaN(const fltSemantics &Sem, bool Negative = false,
unsigned type = 0) {
if (type) {
APInt fill(64, type);
return getQNaN(Sem, Negative, &fill);
} else {
return getQNaN(Sem, Negative, nullptr);
}
}
/// Factory for QNaN values.
static APFloat getQNaN(const fltSemantics &Sem, bool Negative = false,
const APInt *payload = nullptr) {
APFloat Val(Sem, uninitialized);
Val.makeNaN(false, Negative, payload);
return Val;
}
/// Factory for SNaN values.
static APFloat getSNaN(const fltSemantics &Sem, bool Negative = false,
const APInt *payload = nullptr) {
APFloat Val(Sem, uninitialized);
Val.makeNaN(true, Negative, payload);
return Val;
}
/// Returns the largest finite number in the given semantics.
///
/// \param Negative - True iff the number should be negative
static APFloat getLargest(const fltSemantics &Sem, bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeLargest(Negative);
return Val;
}
/// Returns the smallest (by magnitude) finite number in the given semantics.
/// Might be denormalized, which implies a relative loss of precision.
///
/// \param Negative - True iff the number should be negative
static APFloat getSmallest(const fltSemantics &Sem, bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeSmallest(Negative);
return Val;
}
/// Returns the smallest (by magnitude) normalized finite number in the given
/// semantics.
///
/// \param Negative - True iff the number should be negative
static APFloat getSmallestNormalized(const fltSemantics &Sem,
bool Negative = false) {
APFloat Val(Sem, uninitialized);
Val.makeSmallestNormalized(Negative);
return Val;
}
/// Returns a float which is bitcasted from an all one value int.
///
/// \param BitWidth - Select float type
/// \param isIEEE - If 128 bit number, select between PPC and IEEE
static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false);
void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
opStatus add(const APFloat &RHS, roundingMode RM) {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.add(RHS.U.IEEE, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.add(RHS.U.Double, RM);
llvm_unreachable("Unexpected semantics");
}
opStatus subtract(const APFloat &RHS, roundingMode RM) {
if (usesLayout<IEEEFloat>(getSemantics()))
return U.IEEE.subtract(RHS.U.IEEE, RM);
if (usesLayout<DoubleAPFloat>(getSemantics()))
return U.Double.subtract(RHS.U.Double, RM);
llvm_unreachable("Unexpected semantics");
}
opStatus multiply(const APFloat &RHS, roundingMode RM) {
return getIEEE().multiply(RHS.getIEEE(), RM);
}
opStatus divide(const APFloat &RHS, roundingMode RM) {
return getIEEE().divide(RHS.getIEEE(), RM);
}
opStatus remainder(const APFloat &RHS) {
return getIEEE().remainder(RHS.getIEEE());
}
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);
}
opStatus roundToIntegral(roundingMode RM) {
return getIEEE().roundToIntegral(RM);
}
opStatus next(bool nextDown) { return getIEEE().next(nextDown); }
APFloat operator+(const APFloat &RHS) const {
return APFloat(getIEEE() + RHS.getIEEE(), getSemantics());
}
APFloat operator-(const APFloat &RHS) const {
return APFloat(getIEEE() - RHS.getIEEE(), getSemantics());
}
APFloat operator*(const APFloat &RHS) const {
return APFloat(getIEEE() * RHS.getIEEE(), getSemantics());
}
APFloat operator/(const APFloat &RHS) const {
return APFloat(getIEEE() / RHS.getIEEE(), getSemantics());
}
void changeSign() { getIEEE().changeSign(); }
void clearSign() { getIEEE().clearSign(); }
void copySign(const APFloat &RHS) { getIEEE().copySign(RHS.getIEEE()); }
static APFloat copySign(APFloat Value, const APFloat &Sign) {
return APFloat(IEEEFloat::copySign(Value.getIEEE(), Sign.getIEEE()),
Value.getSemantics());
}
opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
bool *losesInfo);
opStatus convertToInteger(integerPart *Input, unsigned int Width,
bool IsSigned, roundingMode RM,
bool *IsExact) const {
return getIEEE().convertToInteger(Input, Width, IsSigned, RM, IsExact);
}
opStatus convertToInteger(APSInt &Result, roundingMode RM,
bool *IsExact) const {
return getIEEE().convertToInteger(Result, RM, IsExact);
}
opStatus convertFromAPInt(const APInt &Input, bool IsSigned,
roundingMode RM) {
return getIEEE().convertFromAPInt(Input, IsSigned, RM);
}
opStatus convertFromSignExtendedInteger(const integerPart *Input,
unsigned int InputSize, bool IsSigned,
roundingMode RM) {
return getIEEE().convertFromSignExtendedInteger(Input, InputSize, IsSigned,
RM);
}
opStatus convertFromZeroExtendedInteger(const integerPart *Input,
unsigned int InputSize, bool IsSigned,
roundingMode RM) {
return getIEEE().convertFromZeroExtendedInteger(Input, InputSize, IsSigned,
RM);
}
opStatus convertFromString(StringRef, roundingMode);
APInt bitcastToAPInt() const { return getIEEE().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());
}
bool bitwiseIsEqual(const APFloat &RHS) const {
return getIEEE().bitwiseIsEqual(RHS.getIEEE());
}
unsigned int convertToHexString(char *DST, unsigned int HexDigits,
bool UpperCase, roundingMode RM) const {
return getIEEE().convertToHexString(DST, HexDigits, UpperCase, RM);
}
bool isZero() const { return getCategory() == fcZero; }
bool isInfinity() const { return getCategory() == fcInfinity; }
bool isNaN() const { return getCategory() == fcNaN; }
bool isNegative() const { return getIEEE().isNegative(); }
bool isDenormal() const { return getIEEE().isDenormal(); }
bool isSignaling() const { return getIEEE().isSignaling(); }
bool isNormal() const { return !isDenormal() && isFiniteNonZero(); }
bool isFinite() const { return !isNaN() && !isInfinity(); }
fltCategory getCategory() const { return getIEEE().getCategory(); }
const fltSemantics &getSemantics() const { return *U.semantics; }
bool isNonZero() const { return !isZero(); }
bool isFiniteNonZero() const { return isFinite() && !isZero(); }
bool isPosZero() const { return isZero() && !isNegative(); }
bool isNegZero() const { return isZero() && isNegative(); }
bool isSmallest() const { return getIEEE().isSmallest(); }
bool isLargest() const { return getIEEE().isLargest(); }
bool isInteger() const { return getIEEE().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);
}
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();
}
friend hash_code hash_value(const APFloat &Arg);
friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
friend IEEEFloat;
friend DoubleAPFloat;
};
/// See friend declarations above.
///
/// These additional declarations are required in order to compile LLVM with IBM
/// xlC compiler.
hash_code hash_value(const APFloat &Arg);
int ilogb(const APFloat &Arg);
APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode);
inline APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM) {
return APFloat(scalbn(X.getIEEE(), Exp, RM), X.getSemantics());
}
/// \brief Equivalent of C standard library function.
///
/// While the C standard says Exp is an unspecified value for infinity and nan,
/// this returns INT_MAX for infinities, and INT_MIN for NaNs.
APFloat frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM);
inline APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM) {
return APFloat(frexp(X.getIEEE(), Exp, RM), X.getSemantics());
}
/// \brief Returns the absolute value of the argument.
inline APFloat abs(APFloat X) {
X.clearSign();

View File

@ -40,6 +40,10 @@ 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);
//===----------------------------------------------------------------------===//
// APInt Class
//===----------------------------------------------------------------------===//
@ -70,7 +74,7 @@ const unsigned int integerPartWidth =
/// * In general, the class tries to follow the style of computation that LLVM
/// uses in its IR. This simplifies its use for LLVM.
///
class APInt {
class LLVM_NODISCARD APInt {
unsigned BitWidth; ///< The number of bits in this APInt.
/// This union is used to store the integer value. When the
@ -620,18 +624,6 @@ class APInt {
return Result;
}
/// \brief Unary negation operator
///
/// Negates *this using two's complement logic.
///
/// \returns An APInt value representing the negation of *this.
APInt operator-() const {
APInt Result(*this);
Result.flipAllBits();
++Result;
return Result;
}
/// \brief Logical negation operator.
///
/// Performs logical negation operation on this APInt.
@ -750,6 +742,7 @@ class APInt {
///
/// \returns *this
APInt &operator+=(const APInt &RHS);
APInt &operator+=(uint64_t RHS);
/// \brief Subtraction assignment operator.
///
@ -757,6 +750,7 @@ class APInt {
///
/// \returns *this
APInt &operator-=(const APInt &RHS);
APInt &operator-=(uint64_t RHS);
/// \brief Left-shift assignment function.
///
@ -783,9 +777,7 @@ class APInt {
return APInt(getBitWidth(), VAL & RHS.VAL);
return AndSlowCase(RHS);
}
APInt LLVM_ATTRIBUTE_UNUSED_RESULT And(const APInt &RHS) const {
return this->operator&(RHS);
}
APInt And(const APInt &RHS) const { return this->operator&(RHS); }
/// \brief Bitwise OR operator.
///
@ -805,9 +797,7 @@ class APInt {
/// calling operator|.
///
/// \returns An APInt value representing the bitwise OR of *this and RHS.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT Or(const APInt &RHS) const {
return this->operator|(RHS);
}
APInt Or(const APInt &RHS) const { return this->operator|(RHS); }
/// \brief Bitwise XOR operator.
///
@ -827,27 +817,13 @@ class APInt {
/// through the usage of operator^.
///
/// \returns An APInt value representing the bitwise XOR of *this and RHS.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT Xor(const APInt &RHS) const {
return this->operator^(RHS);
}
APInt Xor(const APInt &RHS) const { return this->operator^(RHS); }
/// \brief Multiplication operator.
///
/// Multiplies this APInt by RHS and returns the result.
APInt operator*(const APInt &RHS) const;
/// \brief Addition operator.
///
/// Adds RHS to this APInt and returns the result.
APInt operator+(const APInt &RHS) const;
APInt operator+(uint64_t RHS) const;
/// \brief Subtraction operator.
///
/// Subtracts RHS from this APInt and returns the result.
APInt operator-(const APInt &RHS) const;
APInt operator-(uint64_t RHS) const;
/// \brief Left logical shift operator.
///
/// Shifts this APInt left by \p Bits and returns the result.
@ -861,17 +837,17 @@ class APInt {
/// \brief Arithmetic right-shift function.
///
/// Arithmetic right-shift this APInt by shiftAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT ashr(unsigned shiftAmt) const;
APInt ashr(unsigned shiftAmt) const;
/// \brief Logical right-shift function.
///
/// Logical right-shift this APInt by shiftAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT lshr(unsigned shiftAmt) const;
APInt lshr(unsigned shiftAmt) const;
/// \brief Left-shift function.
///
/// Left-shift this APInt by shiftAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT shl(unsigned shiftAmt) const {
APInt shl(unsigned shiftAmt) const {
assert(shiftAmt <= BitWidth && "Invalid shift amount");
if (isSingleWord()) {
if (shiftAmt >= BitWidth)
@ -882,31 +858,31 @@ class APInt {
}
/// \brief Rotate left by rotateAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT rotl(unsigned rotateAmt) const;
APInt rotl(unsigned rotateAmt) const;
/// \brief Rotate right by rotateAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT rotr(unsigned rotateAmt) const;
APInt rotr(unsigned rotateAmt) const;
/// \brief Arithmetic right-shift function.
///
/// Arithmetic right-shift this APInt by shiftAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT ashr(const APInt &shiftAmt) const;
APInt ashr(const APInt &shiftAmt) const;
/// \brief Logical right-shift function.
///
/// Logical right-shift this APInt by shiftAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT lshr(const APInt &shiftAmt) const;
APInt lshr(const APInt &shiftAmt) const;
/// \brief Left-shift function.
///
/// Left-shift this APInt by shiftAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT shl(const APInt &shiftAmt) const;
APInt shl(const APInt &shiftAmt) const;
/// \brief Rotate left by rotateAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT rotl(const APInt &rotateAmt) const;
APInt rotl(const APInt &rotateAmt) const;
/// \brief Rotate right by rotateAmt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT rotr(const APInt &rotateAmt) const;
APInt rotr(const APInt &rotateAmt) const;
/// \brief Unsigned division operation.
///
@ -914,12 +890,12 @@ class APInt {
/// RHS are treated as unsigned quantities for purposes of this division.
///
/// \returns a new APInt value containing the division result
APInt LLVM_ATTRIBUTE_UNUSED_RESULT udiv(const APInt &RHS) const;
APInt udiv(const APInt &RHS) const;
/// \brief Signed division function for APInt.
///
/// Signed divide this APInt by APInt RHS.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT sdiv(const APInt &RHS) const;
APInt sdiv(const APInt &RHS) const;
/// \brief Unsigned remainder operation.
///
@ -930,12 +906,12 @@ class APInt {
/// is *this.
///
/// \returns a new APInt value containing the remainder result
APInt LLVM_ATTRIBUTE_UNUSED_RESULT urem(const APInt &RHS) const;
APInt urem(const APInt &RHS) const;
/// \brief Function for signed remainder operation.
///
/// Signed remainder operation on APInt.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT srem(const APInt &RHS) const;
APInt srem(const APInt &RHS) const;
/// \brief Dual division/remainder interface.
///
@ -1178,7 +1154,7 @@ class APInt {
///
/// Truncate the APInt to a specified width. It is an error to specify a width
/// that is greater than or equal to the current width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT trunc(unsigned width) const;
APInt trunc(unsigned width) const;
/// \brief Sign extend to a new width.
///
@ -1186,38 +1162,38 @@ class APInt {
/// bit is set, the fill on the left will be done with 1 bits, otherwise zero.
/// It is an error to specify a width that is less than or equal to the
/// current width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT sext(unsigned width) const;
APInt sext(unsigned width) const;
/// \brief Zero extend to a new width.
///
/// This operation zero extends the APInt to a new width. The high order bits
/// are filled with 0 bits. It is an error to specify a width that is less
/// than or equal to the current width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT zext(unsigned width) const;
APInt zext(unsigned width) const;
/// \brief Sign extend or truncate to width
///
/// Make this APInt have the bit width given by \p width. The value is sign
/// extended, truncated, or left alone to make it that width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT sextOrTrunc(unsigned width) const;
APInt sextOrTrunc(unsigned width) const;
/// \brief Zero extend or truncate to width
///
/// Make this APInt have the bit width given by \p width. The value is zero
/// extended, truncated, or left alone to make it that width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT zextOrTrunc(unsigned width) const;
APInt zextOrTrunc(unsigned width) const;
/// \brief Sign extend or truncate to width
///
/// Make this APInt have the bit width given by \p width. The value is sign
/// extended, or left alone to make it that width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT sextOrSelf(unsigned width) const;
APInt sextOrSelf(unsigned width) const;
/// \brief Zero extend or truncate to width
///
/// Make this APInt have the bit width given by \p width. The value is zero
/// extended, or left alone to make it that width.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT zextOrSelf(unsigned width) const;
APInt zextOrSelf(unsigned width) const;
/// @}
/// \name Bit Manipulation Operators
@ -1454,11 +1430,11 @@ class APInt {
std::string toString(unsigned Radix, bool Signed) const;
/// \returns a byte-swapped representation of this APInt Value.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT byteSwap() const;
APInt byteSwap() const;
/// \returns the value with the bit representation reversed of this APInt
/// Value.
APInt LLVM_ATTRIBUTE_UNUSED_RESULT reverseBits() const;
APInt reverseBits() const;
/// \brief Converts this APInt to a double value.
double roundToDouble(bool isSigned) const;
@ -1501,7 +1477,7 @@ class APInt {
///
/// The conversion does not do a translation from double to integer, it just
/// re-interprets the bits of the double.
static APInt LLVM_ATTRIBUTE_UNUSED_RESULT doubleToBits(double V) {
static APInt doubleToBits(double V) {
union {
uint64_t I;
double D;
@ -1514,7 +1490,7 @@ class APInt {
///
/// The conversion does not do a translation from float to integer, it just
/// re-interprets the bits of the float.
static APInt LLVM_ATTRIBUTE_UNUSED_RESULT floatToBits(float V) {
static APInt floatToBits(float V) {
union {
unsigned I;
float F;
@ -1532,7 +1508,9 @@ class APInt {
/// \returns the ceil log base 2 of this APInt.
unsigned ceilLogBase2() const {
return BitWidth - (*this - 1).countLeadingZeros();
APInt temp(*this);
--temp;
return BitWidth - temp.countLeadingZeros();
}
/// \returns the nearest log base 2 of this APInt. Ties round up.
@ -1573,12 +1551,12 @@ class APInt {
}
/// \brief Compute the square root
APInt LLVM_ATTRIBUTE_UNUSED_RESULT sqrt() const;
APInt sqrt() const;
/// \brief Get the absolute value;
///
/// If *this is < 0 then return -(*this), otherwise *this;
APInt LLVM_ATTRIBUTE_UNUSED_RESULT abs() const {
APInt abs() const {
if (isNegative())
return -(*this);
return *this;
@ -1750,6 +1728,55 @@ inline raw_ostream &operator<<(raw_ostream &OS, const APInt &I) {
return OS;
}
inline APInt operator-(APInt v) {
v.flipAllBits();
++v;
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 = -std::move(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 = -std::move(b);
b += LHS;
return b;
}
namespace APIntOps {
/// \brief Determine the smaller of two APInts considered to be signed.

View File

@ -19,7 +19,7 @@
namespace llvm {
class APSInt : public APInt {
class LLVM_NODISCARD APSInt : public APInt {
bool IsUnsigned;
public:
@ -78,22 +78,22 @@ class APSInt : public APInt {
return isSigned() ? getSExtValue() : getZExtValue();
}
APSInt LLVM_ATTRIBUTE_UNUSED_RESULT trunc(uint32_t width) const {
APSInt trunc(uint32_t width) const {
return APSInt(APInt::trunc(width), IsUnsigned);
}
APSInt LLVM_ATTRIBUTE_UNUSED_RESULT extend(uint32_t width) const {
APSInt extend(uint32_t width) const {
if (IsUnsigned)
return APSInt(zext(width), IsUnsigned);
else
return APSInt(sext(width), IsUnsigned);
}
APSInt LLVM_ATTRIBUTE_UNUSED_RESULT extOrTrunc(uint32_t width) const {
if (IsUnsigned)
return APSInt(zextOrTrunc(width), IsUnsigned);
else
return APSInt(sextOrTrunc(width), IsUnsigned);
APSInt extOrTrunc(uint32_t width) const {
if (IsUnsigned)
return APSInt(zextOrTrunc(width), IsUnsigned);
else
return APSInt(sextOrTrunc(width), IsUnsigned);
}
const APSInt &operator%=(const APSInt &RHS) {
@ -235,25 +235,19 @@ class APSInt : public APInt {
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
return APSInt(static_cast<const APInt&>(*this) & RHS, IsUnsigned);
}
APSInt LLVM_ATTRIBUTE_UNUSED_RESULT And(const APSInt& RHS) const {
return this->operator&(RHS);
}
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 LLVM_ATTRIBUTE_UNUSED_RESULT Or(const APSInt& RHS) const {
return this->operator|(RHS);
}
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 LLVM_ATTRIBUTE_UNUSED_RESULT Xor(const APSInt& RHS) const {
return this->operator^(RHS);
}
APSInt Xor(const APSInt &RHS) const { return this->operator^(RHS); }
APSInt operator*(const APSInt& RHS) const {
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");

View File

@ -0,0 +1,226 @@
//===- llvm/ADT/AllocatorList.h - Custom allocator list ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ALLOCATORLIST_H
#define LLVM_ADT_ALLOCATORLIST_H
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/simple_ilist.h"
#include "llvm/Support/Allocator.h"
#include <type_traits>
namespace llvm {
/// A linked-list with a custom, local allocator.
///
/// Expose a std::list-like interface that owns and uses a custom LLVM-style
/// allocator (e.g., BumpPtrAllocator), leveraging \a simple_ilist for the
/// implementation details.
///
/// Because this list owns the allocator, calling \a splice() with a different
/// list isn't generally safe. As such, \a splice has been left out of the
/// interface entirely.
template <class T, class AllocatorT> class AllocatorList : AllocatorT {
struct Node : ilist_node<Node> {
Node(Node &&) = delete;
Node(const Node &) = delete;
Node &operator=(Node &&) = delete;
Node &operator=(const Node &) = delete;
Node(T &&V) : V(std::move(V)) {}
Node(const T &V) : V(V) {}
template <class... Ts> Node(Ts &&... Vs) : V(std::forward<Ts>(Vs)...) {}
T V;
};
typedef simple_ilist<Node> list_type;
list_type List;
AllocatorT &getAlloc() { return *this; }
const AllocatorT &getAlloc() const { return *this; }
template <class... ArgTs> Node *create(ArgTs &&... Args) {
return new (getAlloc()) Node(std::forward<ArgTs>(Args)...);
}
struct Cloner {
AllocatorList &AL;
Cloner(AllocatorList &AL) : AL(AL) {}
Node *operator()(const Node &N) const { return AL.create(N.V); }
};
struct Disposer {
AllocatorList &AL;
Disposer(AllocatorList &AL) : AL(AL) {}
void operator()(Node *N) const {
N->~Node();
AL.getAlloc().Deallocate(N);
}
};
public:
typedef T value_type;
typedef T *pointer;
typedef T &reference;
typedef const T *const_pointer;
typedef const T &const_reference;
typedef typename list_type::size_type size_type;
typedef typename list_type::difference_type difference_type;
private:
template <class ValueT, class IteratorBase>
class IteratorImpl
: public iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>,
IteratorBase,
std::bidirectional_iterator_tag, ValueT> {
template <class OtherValueT, class OtherIteratorBase>
friend class IteratorImpl;
friend AllocatorList;
typedef iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>,
IteratorBase, std::bidirectional_iterator_tag,
ValueT>
base_type;
public:
typedef ValueT value_type;
typedef ValueT *pointer;
typedef ValueT &reference;
IteratorImpl() = default;
IteratorImpl(const IteratorImpl &) = default;
IteratorImpl &operator=(const IteratorImpl &) = default;
~IteratorImpl() = default;
explicit IteratorImpl(const IteratorBase &I) : base_type(I) {}
template <class OtherValueT, class OtherIteratorBase>
IteratorImpl(const IteratorImpl<OtherValueT, OtherIteratorBase> &X,
typename std::enable_if<std::is_convertible<
OtherIteratorBase, IteratorBase>::value>::type * = nullptr)
: base_type(X.wrapped()) {}
reference operator*() const { return base_type::wrapped()->V; }
pointer operator->() const { return &operator*(); }
friend bool operator==(const IteratorImpl &L, const IteratorImpl &R) {
return L.wrapped() == R.wrapped();
}
friend bool operator!=(const IteratorImpl &L, const IteratorImpl &R) {
return !(L == R);
}
};
public:
typedef IteratorImpl<T, typename list_type::iterator> iterator;
typedef IteratorImpl<T, typename list_type::reverse_iterator>
reverse_iterator;
typedef IteratorImpl<const T, typename list_type::const_iterator>
const_iterator;
typedef IteratorImpl<const T, typename list_type::const_reverse_iterator>
const_reverse_iterator;
AllocatorList() = default;
AllocatorList(AllocatorList &&X)
: AllocatorT(std::move(X.getAlloc())), List(std::move(X.List)) {}
AllocatorList(const AllocatorList &X) {
List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
}
AllocatorList &operator=(AllocatorList &&X) {
clear(); // Dispose of current nodes explicitly.
List = std::move(X.List);
getAlloc() = std::move(X.getAlloc());
return *this;
}
AllocatorList &operator=(const AllocatorList &X) {
List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
return *this;
}
~AllocatorList() { clear(); }
void swap(AllocatorList &RHS) {
List.swap(RHS.List);
std::swap(getAlloc(), RHS.getAlloc());
}
bool empty() { return List.empty(); }
size_t size() { return List.size(); }
iterator begin() { return iterator(List.begin()); }
iterator end() { return iterator(List.end()); }
const_iterator begin() const { return const_iterator(List.begin()); }
const_iterator end() const { return const_iterator(List.end()); }
reverse_iterator rbegin() { return reverse_iterator(List.rbegin()); }
reverse_iterator rend() { return reverse_iterator(List.rend()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(List.rbegin());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(List.rend());
}
T &back() { return List.back().V; }
T &front() { return List.front().V; }
const T &back() const { return List.back().V; }
const T &front() const { return List.front().V; }
template <class... Ts> iterator emplace(iterator I, Ts &&... Vs) {
return iterator(List.insert(I.wrapped(), *create(std::forward<Ts>(Vs)...)));
}
iterator insert(iterator I, T &&V) {
return iterator(List.insert(I.wrapped(), *create(std::move(V))));
}
iterator insert(iterator I, const T &V) {
return iterator(List.insert(I.wrapped(), *create(V)));
}
template <class Iterator>
void insert(iterator I, Iterator First, Iterator Last) {
for (; First != Last; ++First)
List.insert(I.wrapped(), *create(*First));
}
iterator erase(iterator I) {
return iterator(List.eraseAndDispose(I.wrapped(), Disposer(*this)));
}
iterator erase(iterator First, iterator Last) {
return iterator(
List.eraseAndDispose(First.wrapped(), Last.wrapped(), Disposer(*this)));
}
void clear() { List.clearAndDispose(Disposer(*this)); }
void pop_back() { List.eraseAndDispose(--List.end(), Disposer(*this)); }
void pop_front() { List.eraseAndDispose(List.begin(), Disposer(*this)); }
void push_back(T &&V) { insert(end(), std::move(V)); }
void push_front(T &&V) { insert(begin(), std::move(V)); }
void push_back(const T &V) { insert(end(), V); }
void push_front(const T &V) { insert(begin(), V); }
template <class... Ts> void emplace_back(Ts &&... Vs) {
emplace(end(), std::forward<Ts>(Vs)...);
}
template <class... Ts> void emplace_front(Ts &&... Vs) {
emplace(begin(), std::forward<Ts>(Vs)...);
}
/// Reset the underlying allocator.
///
/// \pre \c empty()
void resetAlloc() {
assert(empty() && "Cannot reset allocator if not empty");
getAlloc().Reset();
}
};
template <class T> using BumpPtrList = AllocatorList<T, BumpPtrAllocator>;
} // end namespace llvm
#endif // LLVM_ADT_ALLOCATORLIST_H

View File

@ -12,7 +12,9 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <array>
#include <vector>
namespace llvm {
@ -28,7 +30,7 @@ namespace llvm {
/// This is intended to be trivially copyable, so it should be passed by
/// value.
template<typename T>
class ArrayRef {
class LLVM_NODISCARD ArrayRef {
public:
typedef const T *iterator;
typedef const T *const_iterator;
@ -78,10 +80,14 @@ namespace llvm {
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
: Data(Vec.data()), Length(Vec.size()) {}
/// Construct an ArrayRef from a std::array
template <size_t N>
/*implicit*/ constexpr ArrayRef(const std::array<T, N> &Arr)
: Data(Arr.data()), Length(N) {}
/// Construct an ArrayRef from a C array.
template <size_t N>
/*implicit*/ LLVM_CONSTEXPR ArrayRef(const T (&Arr)[N])
: Data(Arr), Length(N) {}
/*implicit*/ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {}
/// Construct an ArrayRef from a std::initializer_list.
/*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
@ -160,12 +166,6 @@ namespace llvm {
return std::equal(begin(), end(), RHS.begin());
}
/// slice(n) - Chop off the first N elements of the array.
ArrayRef<T> slice(size_t N) const {
assert(N <= size() && "Invalid specifier");
return ArrayRef<T>(data()+N, size()-N);
}
/// slice(n, m) - Chop off the first N elements of the array, and keep M
/// elements in the array.
ArrayRef<T> slice(size_t N, size_t M) const {
@ -173,6 +173,9 @@ namespace llvm {
return ArrayRef<T>(data()+N, M);
}
/// slice(n) - Chop off the first N elements of the array.
ArrayRef<T> slice(size_t N) const { return slice(N, size() - N); }
/// \brief Drop the first \p N elements of the array.
ArrayRef<T> drop_front(size_t N = 1) const {
assert(size() >= N && "Dropping more elements than exist");
@ -185,6 +188,44 @@ namespace llvm {
return slice(0, size() - N);
}
/// \brief Return a copy of *this with the first N elements satisfying the
/// given predicate removed.
template <class PredicateT> ArrayRef<T> drop_while(PredicateT Pred) const {
return ArrayRef<T>(find_if_not(*this, Pred), end());
}
/// \brief Return a copy of *this with the first N elements not satisfying
/// the given predicate removed.
template <class PredicateT> ArrayRef<T> drop_until(PredicateT Pred) const {
return ArrayRef<T>(find_if(*this, Pred), end());
}
/// \brief Return a copy of *this with only the first \p N elements.
ArrayRef<T> take_front(size_t N = 1) const {
if (N >= size())
return *this;
return drop_back(size() - N);
}
/// \brief Return a copy of *this with only the last \p N elements.
ArrayRef<T> take_back(size_t N = 1) const {
if (N >= size())
return *this;
return drop_front(size() - N);
}
/// \brief Return the first N elements of this Array that satisfy the given
/// predicate.
template <class PredicateT> ArrayRef<T> take_while(PredicateT Pred) const {
return ArrayRef<T>(begin(), find_if_not(*this, Pred));
}
/// \brief Return the first N elements of this Array that don't satisfy the
/// given predicate.
template <class PredicateT> ArrayRef<T> take_until(PredicateT Pred) const {
return ArrayRef<T>(begin(), find_if(*this, Pred));
}
/// @}
/// @name Operator Overloads
/// @{
@ -193,6 +234,22 @@ namespace llvm {
return Data[Index];
}
/// Disallow accidental assignment from a temporary.
///
/// The declaration here is extra complicated so that "arrayRef = {}"
/// continues to select the move assignment operator.
template <typename U>
typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
operator=(U &&Temporary) = delete;
/// Disallow accidental assignment from a temporary.
///
/// The declaration here is extra complicated so that "arrayRef = {}"
/// continues to select the move assignment operator.
template <typename U>
typename std::enable_if<std::is_same<U, T>::value, ArrayRef<T>>::type &
operator=(std::initializer_list<U>) = delete;
/// @}
/// @name Expensive Operations
/// @{
@ -223,7 +280,7 @@ namespace llvm {
/// This is intended to be trivially copyable, so it should be passed by
/// value.
template<typename T>
class MutableArrayRef : public ArrayRef<T> {
class LLVM_NODISCARD MutableArrayRef : public ArrayRef<T> {
public:
typedef T *iterator;
@ -253,10 +310,14 @@ namespace llvm {
/*implicit*/ MutableArrayRef(std::vector<T> &Vec)
: ArrayRef<T>(Vec) {}
/// Construct an ArrayRef from a std::array
template <size_t N>
/*implicit*/ constexpr MutableArrayRef(std::array<T, N> &Arr)
: ArrayRef<T>(Arr) {}
/// Construct an MutableArrayRef from a C array.
template <size_t N>
/*implicit*/ LLVM_CONSTEXPR MutableArrayRef(T (&Arr)[N])
: ArrayRef<T>(Arr) {}
/*implicit*/ constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {}
T *data() const { return const_cast<T*>(ArrayRef<T>::data()); }
@ -278,17 +339,16 @@ namespace llvm {
return data()[this->size()-1];
}
/// slice(n) - Chop off the first N elements of the array.
MutableArrayRef<T> slice(size_t N) const {
assert(N <= this->size() && "Invalid specifier");
return MutableArrayRef<T>(data()+N, this->size()-N);
}
/// slice(n, m) - Chop off the first N elements of the array, and keep M
/// elements in the array.
MutableArrayRef<T> slice(size_t N, size_t M) const {
assert(N+M <= this->size() && "Invalid specifier");
return MutableArrayRef<T>(data()+N, M);
assert(N + M <= this->size() && "Invalid specifier");
return MutableArrayRef<T>(this->data() + N, M);
}
/// slice(n) - Chop off the first N elements of the array.
MutableArrayRef<T> slice(size_t N) const {
return slice(N, this->size() - N);
}
/// \brief Drop the first \p N elements of the array.
@ -302,6 +362,48 @@ namespace llvm {
return slice(0, this->size() - N);
}
/// \brief Return a copy of *this with the first N elements satisfying the
/// given predicate removed.
template <class PredicateT>
MutableArrayRef<T> drop_while(PredicateT Pred) const {
return MutableArrayRef<T>(find_if_not(*this, Pred), end());
}
/// \brief Return a copy of *this with the first N elements not satisfying
/// the given predicate removed.
template <class PredicateT>
MutableArrayRef<T> drop_until(PredicateT Pred) const {
return MutableArrayRef<T>(find_if(*this, Pred), end());
}
/// \brief Return a copy of *this with only the first \p N elements.
MutableArrayRef<T> take_front(size_t N = 1) const {
if (N >= this->size())
return *this;
return drop_back(this->size() - N);
}
/// \brief Return a copy of *this with only the last \p N elements.
MutableArrayRef<T> take_back(size_t N = 1) const {
if (N >= this->size())
return *this;
return drop_front(this->size() - N);
}
/// \brief Return the first N elements of this Array that satisfy the given
/// predicate.
template <class PredicateT>
MutableArrayRef<T> take_while(PredicateT Pred) const {
return MutableArrayRef<T>(begin(), find_if_not(*this, Pred));
}
/// \brief Return the first N elements of this Array that don't satisfy the
/// given predicate.
template <class PredicateT>
MutableArrayRef<T> take_until(PredicateT Pred) const {
return MutableArrayRef<T>(begin(), find_if(*this, Pred));
}
/// @}
/// @name Operator Overloads
/// @{
@ -311,6 +413,25 @@ namespace llvm {
}
};
/// This is a MutableArrayRef that owns its array.
template <typename T> class OwningArrayRef : public MutableArrayRef<T> {
public:
OwningArrayRef() {}
OwningArrayRef(size_t Size) : MutableArrayRef<T>(new T[Size], Size) {}
OwningArrayRef(ArrayRef<T> Data)
: MutableArrayRef<T>(new T[Data.size()], Data.size()) {
std::copy(Data.begin(), Data.end(), this->begin());
}
OwningArrayRef(OwningArrayRef &&Other) { *this = Other; }
OwningArrayRef &operator=(OwningArrayRef &&Other) {
delete[] this->data();
this->MutableArrayRef<T>::operator=(Other);
Other.MutableArrayRef<T>::operator=(MutableArrayRef<T>());
return *this;
}
~OwningArrayRef() { delete[] this->data(); }
};
/// @name ArrayRef Convenience constructors
/// @{

View File

@ -21,6 +21,7 @@
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <utility>
namespace llvm {
@ -45,14 +46,13 @@ class BitVector {
BitWord *WordRef;
unsigned BitPos;
reference(); // Undefined
public:
reference(BitVector &b, unsigned Idx) {
WordRef = &b.Bits[Idx / BITWORD_SIZE];
BitPos = Idx % BITWORD_SIZE;
}
reference() = delete;
reference(const reference&) = default;
reference &operator=(reference t) {

View File

@ -0,0 +1,184 @@
//===- llvm/ADT/CachedHashString.h - Prehashed string/StringRef -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines CachedHashString and CachedHashStringRef. These are owning
// and not-owning string types that store their hash in addition to their string
// data.
//
// Unlike std::string, CachedHashString can be used in DenseSet/DenseMap
// (because, unlike std::string, CachedHashString lets us have empty and
// tombstone values).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_CACHED_HASH_STRING_H
#define LLVM_ADT_CACHED_HASH_STRING_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
/// A container which contains a StringRef plus a precomputed hash.
class CachedHashStringRef {
const char *P;
uint32_t Size;
uint32_t Hash;
public:
// Explicit because hashing a string isn't free.
explicit CachedHashStringRef(StringRef S)
: CachedHashStringRef(S, DenseMapInfo<StringRef>::getHashValue(S)) {}
CachedHashStringRef(StringRef S, uint32_t Hash)
: P(S.data()), Size(S.size()), Hash(Hash) {
assert(S.size() <= std::numeric_limits<uint32_t>::max());
}
StringRef val() const { return StringRef(P, Size); }
uint32_t size() const { return Size; }
uint32_t hash() const { return Hash; }
};
template <> struct DenseMapInfo<CachedHashStringRef> {
static CachedHashStringRef getEmptyKey() {
return CachedHashStringRef(DenseMapInfo<StringRef>::getEmptyKey(), 0);
}
static CachedHashStringRef getTombstoneKey() {
return CachedHashStringRef(DenseMapInfo<StringRef>::getTombstoneKey(), 1);
}
static unsigned getHashValue(const CachedHashStringRef &S) {
assert(!isEqual(S, getEmptyKey()) && "Cannot hash the empty key!");
assert(!isEqual(S, getTombstoneKey()) && "Cannot hash the tombstone key!");
return S.hash();
}
static bool isEqual(const CachedHashStringRef &LHS,
const CachedHashStringRef &RHS) {
return LHS.hash() == RHS.hash() &&
DenseMapInfo<StringRef>::isEqual(LHS.val(), RHS.val());
}
};
/// A container which contains a string, which it owns, plus a precomputed hash.
///
/// We do not null-terminate the string.
class CachedHashString {
friend struct DenseMapInfo<CachedHashString>;
char *P;
uint32_t Size;
uint32_t Hash;
static char *getEmptyKeyPtr() { return DenseMapInfo<char *>::getEmptyKey(); }
static char *getTombstoneKeyPtr() {
return DenseMapInfo<char *>::getTombstoneKey();
}
bool isEmptyOrTombstone() const {
return P == getEmptyKeyPtr() || P == getTombstoneKeyPtr();
}
struct ConstructEmptyOrTombstoneTy {};
CachedHashString(ConstructEmptyOrTombstoneTy, char *EmptyOrTombstonePtr)
: P(EmptyOrTombstonePtr), Size(0), Hash(0) {
assert(isEmptyOrTombstone());
}
// TODO: Use small-string optimization to avoid allocating.
public:
explicit CachedHashString(const char *S) : CachedHashString(StringRef(S)) {}
// Explicit because copying and hashing a string isn't free.
explicit CachedHashString(StringRef S)
: CachedHashString(S, DenseMapInfo<StringRef>::getHashValue(S)) {}
CachedHashString(StringRef S, uint32_t Hash)
: P(new char[S.size()]), Size(S.size()), Hash(Hash) {
memcpy(P, S.data(), S.size());
}
// Ideally this class would not be copyable. But SetVector requires copyable
// keys, and we want this to be usable there.
CachedHashString(const CachedHashString &Other)
: Size(Other.Size), Hash(Other.Hash) {
if (Other.isEmptyOrTombstone()) {
P = Other.P;
} else {
P = new char[Size];
memcpy(P, Other.P, Size);
}
}
CachedHashString &operator=(CachedHashString Other) {
swap(*this, Other);
return *this;
}
CachedHashString(CachedHashString &&Other) noexcept
: P(Other.P), Size(Other.Size), Hash(Other.Hash) {
Other.P = getEmptyKeyPtr();
}
~CachedHashString() {
if (!isEmptyOrTombstone())
delete[] P;
}
StringRef val() const { return StringRef(P, Size); }
uint32_t size() const { return Size; }
uint32_t hash() const { return Hash; }
operator StringRef() const { return val(); }
operator CachedHashStringRef() const {
return CachedHashStringRef(val(), Hash);
}
friend void swap(CachedHashString &LHS, CachedHashString &RHS) {
using std::swap;
swap(LHS.P, RHS.P);
swap(LHS.Size, RHS.Size);
swap(LHS.Hash, RHS.Hash);
}
};
template <> struct DenseMapInfo<CachedHashString> {
static CachedHashString getEmptyKey() {
return CachedHashString(CachedHashString::ConstructEmptyOrTombstoneTy(),
CachedHashString::getEmptyKeyPtr());
}
static CachedHashString getTombstoneKey() {
return CachedHashString(CachedHashString::ConstructEmptyOrTombstoneTy(),
CachedHashString::getTombstoneKeyPtr());
}
static unsigned getHashValue(const CachedHashString &S) {
assert(!isEqual(S, getEmptyKey()) && "Cannot hash the empty key!");
assert(!isEqual(S, getTombstoneKey()) && "Cannot hash the tombstone key!");
return S.hash();
}
static bool isEqual(const CachedHashString &LHS,
const CachedHashString &RHS) {
if (LHS.hash() != RHS.hash())
return false;
if (LHS.P == CachedHashString::getEmptyKeyPtr())
return RHS.P == CachedHashString::getEmptyKeyPtr();
if (LHS.P == CachedHashString::getTombstoneKeyPtr())
return RHS.P == CachedHashString::getTombstoneKeyPtr();
// This is safe because if RHS.P is the empty or tombstone key, it will have
// length 0, so we'll never dereference its pointer.
return LHS.val() == RHS.val();
}
};
} // namespace llvm
#endif

View File

@ -10,6 +10,7 @@
#define LLVM_ADT_DAGDELTAALGORITHM_H
#include <set>
#include <utility>
#include <vector>
namespace llvm {
@ -37,6 +38,7 @@ namespace llvm {
/// should satisfy.
class DAGDeltaAlgorithm {
virtual void anchor();
public:
typedef unsigned change_ty;
typedef std::pair<change_ty, change_ty> edge_ty;
@ -46,7 +48,7 @@ class DAGDeltaAlgorithm {
typedef std::vector<changeset_ty> changesetlist_ty;
public:
virtual ~DAGDeltaAlgorithm() {}
virtual ~DAGDeltaAlgorithm() = default;
/// Run - Minimize the DAG formed by the \p Changes vertices and the
/// \p Dependencies edges by executing \see ExecuteOneTest() on subsets of
@ -74,4 +76,4 @@ class DAGDeltaAlgorithm {
} // end namespace llvm
#endif
#endif // LLVM_ADT_DAGDELTAALGORITHM_H

View File

@ -19,20 +19,20 @@
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/type_traits.h"
#include <algorithm>
#include <cassert>
#include <climits>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <limits>
#include <new>
#include <utility>
namespace llvm {
namespace detail {
// We extend a pair to allow users to override the bucket type with their own
// implementation without requiring two members.
template <typename KeyT, typename ValueT>
@ -42,7 +42,8 @@ struct DenseMapPair : public std::pair<KeyT, ValueT> {
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
};
}
} // end namespace detail
template <
typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo<KeyT>,
@ -76,7 +77,7 @@ class DenseMapBase : public DebugEpochBase {
return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
}
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
LLVM_NODISCARD bool empty() const {
return getNumEntries() == 0;
}
unsigned size() const { return getNumEntries(); }
@ -169,30 +170,45 @@ class DenseMapBase : public DebugEpochBase {
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
return try_emplace(KV.first, KV.second);
}
// Inserts key,value pair into the map if the key isn't already in the map.
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
return try_emplace(std::move(KV.first), std::move(KV.second));
}
// Inserts key,value pair into the map if the key isn't already in the map.
// The value is constructed in-place if the key is not in the map, otherwise
// it is not moved.
template <typename... Ts>
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(std::move(KV.first),
std::move(KV.second),
TheBucket);
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
// Inserts key,value pair into the map if the key isn't already in the map.
// The value is constructed in-place if the key is not in the map, otherwise
// it is not moved.
template <typename... Ts>
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
@ -211,8 +227,8 @@ class DenseMapBase : public DebugEpochBase {
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(std::move(KV.first), std::move(KV.second), Val,
TheBucket);
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
@ -224,7 +240,6 @@ class DenseMapBase : public DebugEpochBase {
insert(*I);
}
bool erase(const KeyT &Val) {
BucketT *TheBucket;
if (!LookupBucketFor(Val, TheBucket))
@ -249,7 +264,7 @@ class DenseMapBase : public DebugEpochBase {
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;
return *InsertIntoBucket(Key, ValueT(), TheBucket);
return *InsertIntoBucket(TheBucket, Key);
}
ValueT &operator[](const KeyT &Key) {
@ -261,7 +276,7 @@ class DenseMapBase : public DebugEpochBase {
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;
return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
return *InsertIntoBucket(TheBucket, std::move(Key));
}
ValueT &operator[](KeyT &&Key) {
@ -429,36 +444,19 @@ class DenseMapBase : public DebugEpochBase {
static_cast<DerivedT *>(this)->shrink_and_clear();
}
BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
BucketT *TheBucket) {
template <typename KeyArg, typename... ValueArgs>
BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
ValueArgs &&... Values) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = Key;
::new (&TheBucket->getSecond()) ValueT(Value);
return TheBucket;
}
BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = Key;
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
return TheBucket;
}
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
TheBucket->getFirst() = std::move(Key);
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
TheBucket->getFirst() = std::forward<KeyArg>(Key);
::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
return TheBucket;
}
template <typename LookupKeyT>
BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, LookupKeyT &Lookup,
BucketT *TheBucket) {
BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
ValueT &&Value, LookupKeyT &Lookup) {
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
TheBucket->getFirst() = std::move(Key);
@ -530,7 +528,7 @@ class DenseMapBase : public DebugEpochBase {
unsigned BucketNo = getHashValue(Val) & (NumBuckets-1);
unsigned ProbeAmt = 1;
while (1) {
while (true) {
const BucketT *ThisBucket = BucketsPtr + BucketNo;
// Found Val's bucket? If so, return it.
if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
@ -744,6 +742,8 @@ class SmallDenseMap
// simplicity of referring to them.
typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT> BaseT;
friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
static_assert(isPowerOf2_64(InlineBuckets),
"InlineBuckets must be a power of 2.");
unsigned Small : 1;
unsigned NumEntries : 31;
@ -968,7 +968,8 @@ class SmallDenseMap
return NumEntries;
}
void setNumEntries(unsigned Num) {
assert(Num < INT_MAX && "Cannot support more than INT_MAX entries");
// NumEntries is hardcoded to be 31 bits wide.
assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries");
NumEntries = Num;
}
@ -1042,8 +1043,10 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
typedef value_type *pointer;
typedef value_type &reference;
typedef std::forward_iterator_tag iterator_category;
private:
pointer Ptr, End;
public:
DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
@ -1117,4 +1120,4 @@ capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
} // end namespace llvm
#endif
#endif // LLVM_ADT_DENSEMAP_H

View File

@ -30,36 +30,6 @@ struct DenseMapInfo {
//static bool isEqual(const T &LHS, const T &RHS);
};
template <typename T> struct CachedHash {
CachedHash(T Val) : Val(std::move(Val)) {
Hash = DenseMapInfo<T>::getHashValue(Val);
}
CachedHash(T Val, unsigned Hash) : Val(std::move(Val)), Hash(Hash) {}
T Val;
unsigned Hash;
};
// Provide DenseMapInfo for all CachedHash<T>.
template <typename T> struct DenseMapInfo<CachedHash<T>> {
static CachedHash<T> getEmptyKey() {
T N = DenseMapInfo<T>::getEmptyKey();
return {N, 0};
}
static CachedHash<T> getTombstoneKey() {
T N = DenseMapInfo<T>::getTombstoneKey();
return {N, 0};
}
static unsigned getHashValue(CachedHash<T> Val) {
assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!");
assert(!isEqual(Val, getTombstoneKey()) &&
"Cannot hash the tombstone key!");
return Val.Hash;
}
static bool isEqual(CachedHash<T> A, CachedHash<T> B) {
return DenseMapInfo<T>::isEqual(A.Val, B.Val);
}
};
// Provide DenseMapInfo for all pointers.
template<typename T>
struct DenseMapInfo<T*> {

View File

@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines the DenseSet class.
// This file defines the DenseSet and SmallDenseSet classes.
//
//===----------------------------------------------------------------------===//
@ -15,6 +15,7 @@
#define LLVM_ADT_DENSESET_H
#include "llvm/ADT/DenseMap.h"
#include <initializer_list>
namespace llvm {
@ -32,13 +33,18 @@ template <typename KeyT> class DenseSetPair : public DenseSetEmpty {
DenseSetEmpty &getSecond() { return *this; }
const DenseSetEmpty &getSecond() const { return *this; }
};
}
/// DenseSet - This implements a dense probed hash-table based set.
template<typename ValueT, typename ValueInfoT = DenseMapInfo<ValueT> >
class DenseSet {
typedef DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
detail::DenseSetPair<ValueT>> MapTy;
/// Base class for DenseSet and DenseSmallSet.
///
/// MapTy should be either
///
/// DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
/// detail::DenseSetPair<ValueT>>
///
/// or the equivalent SmallDenseMap type. ValueInfoT must implement the
/// DenseMapInfo "concept".
template <typename ValueT, typename MapTy, typename ValueInfoT>
class DenseSetImpl {
static_assert(sizeof(typename MapTy::value_type) == sizeof(ValueT),
"DenseMap buckets unexpectedly large!");
MapTy TheMap;
@ -48,7 +54,12 @@ class DenseSet {
typedef ValueT value_type;
typedef unsigned size_type;
explicit DenseSet(unsigned NumInitBuckets = 0) : TheMap(NumInitBuckets) {}
explicit DenseSetImpl(unsigned InitialReserve = 0) : TheMap(InitialReserve) {}
DenseSetImpl(std::initializer_list<ValueT> Elems)
: DenseSetImpl(Elems.size()) {
insert(Elems.begin(), Elems.end());
}
bool empty() const { return TheMap.empty(); }
size_type size() const { return TheMap.size(); }
@ -58,6 +69,10 @@ class DenseSet {
/// the Size of the set.
void resize(size_t Size) { TheMap.resize(Size); }
/// Grow the DenseSet so that it can contain at least \p NumEntries items
/// before resizing again.
void reserve(size_t Size) { TheMap.reserve(Size); }
void clear() {
TheMap.clear();
}
@ -71,15 +86,13 @@ class DenseSet {
return TheMap.erase(V);
}
void swap(DenseSet& RHS) {
TheMap.swap(RHS.TheMap);
}
void swap(DenseSetImpl &RHS) { TheMap.swap(RHS.TheMap); }
// Iterators.
class Iterator {
typename MapTy::iterator I;
friend class DenseSet;
friend class DenseSetImpl;
public:
typedef typename MapTy::iterator::difference_type difference_type;
@ -131,6 +144,9 @@ class DenseSet {
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 {
return ConstIterator(TheMap.find(V));
}
/// Alternative version of find() which allows a different, and possibly less
/// expensive, key type.
@ -151,7 +167,12 @@ class DenseSet {
std::pair<iterator, bool> insert(const ValueT &V) {
detail::DenseSetEmpty Empty;
return TheMap.insert(std::make_pair(V, Empty));
return TheMap.try_emplace(V, Empty);
}
std::pair<iterator, bool> insert(ValueT &&V) {
detail::DenseSetEmpty Empty;
return TheMap.try_emplace(std::move(V), Empty);
}
/// Alternative version of insert that uses a different (and possibly less
@ -159,12 +180,11 @@ class DenseSet {
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(const ValueT &V,
const LookupKeyT &LookupKey) {
return insert_as(ValueT(V), LookupKey);
return TheMap.insert_as({V, detail::DenseSetEmpty()}, LookupKey);
}
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(ValueT &&V, const LookupKeyT &LookupKey) {
detail::DenseSetEmpty Empty;
return TheMap.insert_as(std::make_pair(std::move(V), Empty), LookupKey);
return TheMap.insert_as({std::move(V), detail::DenseSetEmpty()}, LookupKey);
}
// Range insertion of values.
@ -175,6 +195,42 @@ class DenseSet {
}
};
} // namespace detail
/// Implements a dense probed hash-table based set.
template <typename ValueT, typename ValueInfoT = DenseMapInfo<ValueT>>
class DenseSet : public detail::DenseSetImpl<
ValueT, DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
detail::DenseSetPair<ValueT>>,
ValueInfoT> {
using BaseT =
detail::DenseSetImpl<ValueT,
DenseMap<ValueT, detail::DenseSetEmpty, ValueInfoT,
detail::DenseSetPair<ValueT>>,
ValueInfoT>;
public:
using BaseT::BaseT;
};
/// Implements a dense probed hash-table based set with some number of buckets
/// stored inline.
template <typename ValueT, unsigned InlineBuckets = 4,
typename ValueInfoT = DenseMapInfo<ValueT>>
class SmallDenseSet
: public detail::DenseSetImpl<
ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets,
ValueInfoT, detail::DenseSetPair<ValueT>>,
ValueInfoT> {
using BaseT = detail::DenseSetImpl<
ValueT, SmallDenseMap<ValueT, detail::DenseSetEmpty, InlineBuckets,
ValueInfoT, detail::DenseSetPair<ValueT>>,
ValueInfoT>;
public:
using BaseT::BaseT;
};
} // end namespace llvm
#endif

View File

@ -34,10 +34,13 @@
#define LLVM_ADT_DEPTHFIRSTITERATOR_H
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/PointerIntPair.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 <set>
#include <utility>
#include <vector>
namespace llvm {
@ -55,44 +58,56 @@ class df_iterator_storage<SetType, true> {
public:
df_iterator_storage(SetType &VSet) : Visited(VSet) {}
df_iterator_storage(const df_iterator_storage &S) : Visited(S.Visited) {}
SetType &Visited;
};
// Generic Depth First Iterator
template<class GraphT,
class SetType = llvm::SmallPtrSet<typename GraphTraits<GraphT>::NodeType*, 8>,
bool ExtStorage = false, class GT = GraphTraits<GraphT> >
class df_iterator : public std::iterator<std::forward_iterator_tag,
typename GT::NodeType, ptrdiff_t>,
public df_iterator_storage<SetType, ExtStorage> {
typedef std::iterator<std::forward_iterator_tag,
typename GT::NodeType, ptrdiff_t> super;
// The visited stated for the iteration is a simple set augmented with
// one more method, completed, which is invoked when all children of a
// node have been processed. It is intended to distinguish of back and
// cross edges in the spanning tree but is not used in the common case.
template <typename NodeRef, unsigned SmallSize=8>
struct df_iterator_default_set : public SmallPtrSet<NodeRef, SmallSize> {
typedef SmallPtrSet<NodeRef, SmallSize> BaseSet;
typedef typename BaseSet::iterator iterator;
std::pair<iterator,bool> insert(NodeRef N) { return BaseSet::insert(N) ; }
template <typename IterT>
void insert(IterT Begin, IterT End) { BaseSet::insert(Begin,End); }
typedef typename GT::NodeType NodeType;
void completed(NodeRef) { }
};
// Generic Depth First Iterator
template <class GraphT,
class SetType =
df_iterator_default_set<typename GraphTraits<GraphT>::NodeRef>,
bool ExtStorage = false, class GT = GraphTraits<GraphT>>
class df_iterator
: public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>,
public df_iterator_storage<SetType, ExtStorage> {
typedef std::iterator<std::forward_iterator_tag, typename GT::NodeRef> super;
typedef typename GT::NodeRef NodeRef;
typedef typename GT::ChildIteratorType ChildItTy;
typedef PointerIntPair<NodeType*, 1> PointerIntTy;
// First element is node reference, second is the 'next child' to visit.
// The second child is initialized lazily to pick up graph changes during the
// DFS.
typedef std::pair<NodeRef, Optional<ChildItTy>> StackElement;
// VisitStack - Used to maintain the ordering. Top = current block
// First element is node pointer, second is the 'next child' to visit
// if the int in PointerIntTy is 0, the 'next child' to visit is invalid
std::vector<std::pair<PointerIntTy, ChildItTy>> VisitStack;
std::vector<StackElement> VisitStack;
private:
inline df_iterator(NodeType *Node) {
inline df_iterator(NodeRef Node) {
this->Visited.insert(Node);
VisitStack.push_back(
std::make_pair(PointerIntTy(Node, 0), GT::child_begin(Node)));
VisitStack.push_back(StackElement(Node, None));
}
inline df_iterator() {
// End is when stack is empty
}
inline df_iterator(NodeType *Node, SetType &S)
: df_iterator_storage<SetType, ExtStorage>(S) {
if (!S.count(Node)) {
VisitStack.push_back(
std::make_pair(PointerIntTy(Node, 0), GT::child_begin(Node)));
this->Visited.insert(Node);
}
inline df_iterator() = default; // End is when stack is empty
inline df_iterator(NodeRef Node, SetType &S)
: df_iterator_storage<SetType, ExtStorage>(S) {
if (this->Visited.insert(Node).second)
VisitStack.push_back(StackElement(Node, None));
}
inline df_iterator(SetType &S)
: df_iterator_storage<SetType, ExtStorage>(S) {
@ -101,26 +116,26 @@ class df_iterator : public std::iterator<std::forward_iterator_tag,
inline void toNext() {
do {
std::pair<PointerIntTy, ChildItTy> &Top = VisitStack.back();
NodeType *Node = Top.first.getPointer();
ChildItTy &It = Top.second;
if (!Top.first.getInt()) {
// now retrieve the real begin of the children before we dive in
It = GT::child_begin(Node);
Top.first.setInt(1);
}
NodeRef Node = VisitStack.back().first;
Optional<ChildItTy> &Opt = VisitStack.back().second;
while (It != GT::child_end(Node)) {
NodeType *Next = *It++;
if (!Opt)
Opt.emplace(GT::child_begin(Node));
// Notice that we directly mutate *Opt here, so that
// VisitStack.back().second actually gets updated as the iterator
// increases.
while (*Opt != GT::child_end(Node)) {
NodeRef Next = *(*Opt)++;
// Has our next sibling been visited?
if (Next && this->Visited.insert(Next).second) {
if (this->Visited.insert(Next).second) {
// No, do it now.
VisitStack.push_back(
std::make_pair(PointerIntTy(Next, 0), GT::child_begin(Next)));
VisitStack.push_back(StackElement(Next, None));
return;
}
}
this->Visited.completed(Node);
// Oops, ran out of successors... go up a level on the stack.
VisitStack.pop_back();
} while (!VisitStack.empty());
@ -146,13 +161,13 @@ class df_iterator : public std::iterator<std::forward_iterator_tag,
}
bool operator!=(const df_iterator &x) const { return !(*this == x); }
pointer operator*() const { return VisitStack.back().first.getPointer(); }
const NodeRef &operator*() const { return VisitStack.back().first; }
// This is a nonstandard operator-> that dereferences the pointer an extra
// time... so that you can actually call methods ON the Node, because
// the contained type is a pointer. This allows BBIt->getTerminator() f.e.
//
NodeType *operator->() const { return **this; }
NodeRef operator->() const { return **this; }
df_iterator &operator++() { // Preincrement
toNext();
@ -180,7 +195,7 @@ class df_iterator : public std::iterator<std::forward_iterator_tag,
// specified node. This is public, and will probably be used to iterate over
// nodes that a depth first iteration did not find: ie unreachable nodes.
//
bool nodeVisited(NodeType *Node) const {
bool nodeVisited(NodeRef Node) const {
return this->Visited.count(Node) != 0;
}
@ -190,9 +205,7 @@ class df_iterator : public std::iterator<std::forward_iterator_tag,
/// getPath - Return the n'th node in the path from the entry node to the
/// current node.
NodeType *getPath(unsigned n) const {
return VisitStack[n].first.getPointer();
}
NodeRef getPath(unsigned n) const { return VisitStack[n].first; }
};
// Provide global constructors that automatically figure out correct types...
@ -214,7 +227,7 @@ iterator_range<df_iterator<T>> depth_first(const T& G) {
}
// Provide global definitions of external depth first iterators...
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeRef>>
struct df_ext_iterator : public df_iterator<T, SetTy, true> {
df_ext_iterator(const df_iterator<T, SetTy, true> &V)
: df_iterator<T, SetTy, true>(V) {}
@ -238,7 +251,8 @@ iterator_range<df_ext_iterator<T, SetTy>> depth_first_ext(const T& G,
// Provide global definitions of inverse depth first iterators...
template <class T,
class SetTy = llvm::SmallPtrSet<typename GraphTraits<T>::NodeType*, 8>,
class SetTy =
df_iterator_default_set<typename GraphTraits<T>::NodeRef>,
bool External = false>
struct idf_iterator : public df_iterator<Inverse<T>, SetTy, External> {
idf_iterator(const df_iterator<Inverse<T>, SetTy, External> &V)
@ -262,7 +276,7 @@ iterator_range<idf_iterator<T>> inverse_depth_first(const T& G) {
}
// Provide global definitions of external inverse depth first iterators...
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeType*> >
template <class T, class SetTy = std::set<typename GraphTraits<T>::NodeRef>>
struct idf_ext_iterator : public idf_iterator<T, SetTy, true> {
idf_ext_iterator(const idf_iterator<T, SetTy, true> &V)
: idf_iterator<T, SetTy, true>(V) {}
@ -286,6 +300,6 @@ iterator_range<idf_ext_iterator<T, SetTy>> inverse_depth_first_ext(const T& G,
return make_range(idf_ext_begin(G, S), idf_ext_end(G, S));
}
} // End llvm namespace
} // end namespace llvm
#endif
#endif // LLVM_ADT_DEPTHFIRSTITERATOR_H

View File

@ -16,28 +16,14 @@
#ifndef LLVM_ADT_EPOCH_TRACKER_H
#define LLVM_ADT_EPOCH_TRACKER_H
#include "llvm/Config/abi-breaking.h"
#include "llvm/Config/llvm-config.h"
#include <cstdint>
namespace llvm {
#ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
class DebugEpochBase {
public:
void incrementEpoch() {}
class HandleBase {
public:
HandleBase() = default;
explicit HandleBase(const DebugEpochBase *) {}
bool isHandleInSync() const { return true; }
const void *getEpochAddress() const { return nullptr; }
};
};
#else
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
/// \brief A base class for data structure classes wishing to make iterators
/// ("handles") pointing into themselves fail-fast. When building without
@ -92,6 +78,21 @@ class DebugEpochBase {
};
};
#else
class DebugEpochBase {
public:
void incrementEpoch() {}
class HandleBase {
public:
HandleBase() = default;
explicit HandleBase(const DebugEpochBase *) {}
bool isHandleInSync() const { return true; }
const void *getEpochAddress() const { return nullptr; }
};
};
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
} // namespace llvm

View File

@ -15,9 +15,10 @@
#ifndef LLVM_ADT_EQUIVALENCECLASSES_H
#define LLVM_ADT_EQUIVALENCECLASSES_H
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <set>
namespace llvm {
@ -70,6 +71,7 @@ class EquivalenceClasses {
friend class EquivalenceClasses;
mutable const ECValue *Leader, *Next;
ElemTy Data;
// ECValue ctor - Start out with EndOfList pointing to this node, Next is
// Null, isLeader = true.
ECValue(const ElemTy &Elt)
@ -81,6 +83,7 @@ class EquivalenceClasses {
// Path compression.
return Leader = Leader->getLeader();
}
const ECValue *getEndOfList() const {
assert(isLeader() && "Cannot get the end of a list for a non-leader!");
return Leader;
@ -90,6 +93,7 @@ class EquivalenceClasses {
assert(getNext() == nullptr && "Already has a next pointer!");
Next = (const ECValue*)((intptr_t)NewNext | (intptr_t)isLeader());
}
public:
ECValue(const ECValue &RHS) : Leader(this), Next((ECValue*)(intptr_t)1),
Data(RHS.Data) {
@ -115,7 +119,7 @@ class EquivalenceClasses {
std::set<ECValue> TheMapping;
public:
EquivalenceClasses() {}
EquivalenceClasses() = default;
EquivalenceClasses(const EquivalenceClasses &RHS) {
operator=(RHS);
}
@ -187,7 +191,6 @@ class EquivalenceClasses {
return NC;
}
//===--------------------------------------------------------------------===//
// Mutation methods
@ -210,7 +213,6 @@ class EquivalenceClasses {
return findLeader(TheMapping.find(V));
}
/// union - Merge the two equivalence sets for the specified values, inserting
/// them if they do not already exist in the equivalence set.
member_iterator unionSets(const ElemTy &V1, const ElemTy &V2) {
@ -243,12 +245,13 @@ class EquivalenceClasses {
const ElemTy, ptrdiff_t> super;
const ECValue *Node;
friend class EquivalenceClasses;
public:
typedef size_t size_type;
typedef typename super::pointer pointer;
typedef typename super::reference reference;
explicit member_iterator() {}
explicit member_iterator() = default;
explicit member_iterator(const ECValue *N) : Node(N) {}
reference operator*() const {
@ -278,6 +281,6 @@ class EquivalenceClasses {
};
};
} // End llvm namespace
} // end namespace llvm
#endif
#endif // LLVM_ADT_EQUIVALENCECLASSES_H

View File

@ -19,8 +19,13 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/Allocator.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <utility>
namespace llvm {
/// This folding set used for two purposes:
/// 1. Given information about a node we want to create, look up the unique
/// instance of the node in the set. If the node already exists, return
@ -184,6 +189,7 @@ class FoldingSetImpl {
/// EltCount-th node won't cause a rebucket operation. reserve is permitted
/// to allocate more space than requested by EltCount.
void reserve(unsigned EltCount);
/// capacity - Returns the number of nodes permitted in the folding set
/// before a rebucket operation is performed.
unsigned capacity() {
@ -200,14 +206,17 @@ class FoldingSetImpl {
/// NewBucketCount must be a power of two, and must be greater than the old
/// bucket count.
void GrowBucketCount(unsigned NewBucketCount);
protected:
/// GetNodeProfile - Instantiations of the FoldingSet template implement
/// this function to gather data bits for the given node.
virtual void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const = 0;
/// NodeEquals - Instantiations of the FoldingSet template implement
/// this function to compare the given node with the given ID.
virtual bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
FoldingSetNodeID &TempID) const=0;
/// ComputeNodeHash - Instantiations of the FoldingSet template implement
/// this function to compute a hash value for the given node.
virtual unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const = 0;
@ -215,8 +224,6 @@ class FoldingSetImpl {
//===----------------------------------------------------------------------===//
template<typename T> struct FoldingSetTrait;
/// DefaultFoldingSetTrait - This class provides default implementations
/// for FoldingSetTrait implementations.
///
@ -252,8 +259,6 @@ template<typename T> struct DefaultFoldingSetTrait {
template<typename T> struct FoldingSetTrait
: public DefaultFoldingSetTrait<T> {};
template<typename T, typename Ctx> struct ContextualFoldingSetTrait;
/// DefaultContextualFoldingSetTrait - Like DefaultFoldingSetTrait, but
/// for ContextualFoldingSets.
template<typename T, typename Ctx>
@ -261,6 +266,7 @@ struct DefaultContextualFoldingSetTrait {
static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) {
X.Profile(ID, Context);
}
static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
FoldingSetNodeID &TempID, Ctx Context);
static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID,
@ -279,11 +285,11 @@ template<typename T, typename Ctx> struct ContextualFoldingSetTrait
/// is often much larger than necessary, and the possibility of heap
/// allocation means it requires a non-trivial destructor call.
class FoldingSetNodeIDRef {
const unsigned *Data;
size_t Size;
const unsigned *Data = nullptr;
size_t Size = 0;
public:
FoldingSetNodeIDRef() : Data(nullptr), Size(0) {}
FoldingSetNodeIDRef() = default;
FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
/// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef,
@ -313,7 +319,7 @@ class FoldingSetNodeID {
SmallVector<unsigned, 32> Bits;
public:
FoldingSetNodeID() {}
FoldingSetNodeID() = default;
FoldingSetNodeID(FoldingSetNodeIDRef Ref)
: Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
@ -418,6 +424,7 @@ template <class T> class FoldingSet final : public FoldingSetImpl {
T *TN = static_cast<T *>(N);
FoldingSetTrait<T>::Profile(*TN, ID);
}
/// NodeEquals - Instantiations may optionally provide a way to compare a
/// node with a specified ID.
bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,
@ -425,6 +432,7 @@ template <class T> class FoldingSet final : public FoldingSetImpl {
T *TN = static_cast<T *>(N);
return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
}
/// ComputeNodeHash - Instantiations may optionally provide a way to compute a
/// hash value directly from a node.
unsigned ComputeNodeHash(Node *N, FoldingSetNodeID &TempID) const override {
@ -483,7 +491,7 @@ template <class T> class FoldingSet final : public FoldingSetImpl {
///
/// T must be a subclass of FoldingSetNode and implement a Profile
/// function with signature
/// void Profile(llvm::FoldingSetNodeID &, Ctx);
/// void Profile(FoldingSetNodeID &, Ctx);
template <class T, class Ctx>
class ContextualFoldingSet final : public FoldingSetImpl {
// Unfortunately, this can't derive from FoldingSet<T> because the
@ -501,12 +509,14 @@ class ContextualFoldingSet final : public FoldingSetImpl {
T *TN = static_cast<T *>(N);
ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, Context);
}
bool NodeEquals(FoldingSetImpl::Node *N, const FoldingSetNodeID &ID,
unsigned IDHash, FoldingSetNodeID &TempID) const override {
T *TN = static_cast<T *>(N);
return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
Context);
}
unsigned ComputeNodeHash(FoldingSetImpl::Node *N,
FoldingSetNodeID &TempID) const override {
T *TN = static_cast<T *>(N);
@ -558,7 +568,7 @@ class ContextualFoldingSet final : public FoldingSetImpl {
/// to provide the interface of FoldingSet but with deterministic iteration
/// order based on the insertion order. T must be a subclass of FoldingSetNode
/// and implement a Profile function.
template <class T, class VectorT = SmallVector<T*, 8> >
template <class T, class VectorT = SmallVector<T*, 8>>
class FoldingSetVector {
FoldingSet<T> Set;
VectorT Vector;
@ -623,7 +633,9 @@ class FoldingSetVector {
class FoldingSetIteratorImpl {
protected:
FoldingSetNode *NodePtr;
FoldingSetIteratorImpl(void **Bucket);
void advance();
public:
@ -754,11 +766,12 @@ template<typename T> struct FoldingSetTrait<T*> {
template <typename T1, typename T2>
struct FoldingSetTrait<std::pair<T1, T2>> {
static inline void Profile(const std::pair<T1, T2> &P,
llvm::FoldingSetNodeID &ID) {
FoldingSetNodeID &ID) {
ID.Add(P.first);
ID.Add(P.second);
}
};
} // End of namespace llvm.
#endif
} // end namespace llvm
#endif // LLVM_ADT_FOLDINGSET_H

View File

@ -27,14 +27,10 @@ template<class GraphType>
struct GraphTraits {
// Elements to provide:
// NOTICE: We are in a transition from migration interfaces that require
// NodeType *, to NodeRef. NodeRef is required to be cheap to copy, but does
// not have to be a raw pointer. In the transition, user should define
// NodeType, and NodeRef = NodeType *.
//
// typedef NodeType - Type of Node in the graph
// typedef NodeRef - NodeType *
// typedef ChildIteratorType - Type used to iterate over children in graph
// typedef NodeRef - Type of Node token in the graph, which should
// be cheap to copy.
// typedef ChildIteratorType - Type used to iterate over children in graph,
// dereference to a NodeRef.
// static NodeRef getEntryNode(const GraphType &)
// Return the entry node of the graph
@ -45,7 +41,7 @@ struct GraphTraits {
// node list for the specified node.
//
// typedef ...iterator nodes_iterator;
// typedef ...iterator nodes_iterator; - dereference to a NodeRef
// static nodes_iterator nodes_begin(GraphType *G)
// static nodes_iterator nodes_end (GraphType *G)
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
@ -88,23 +84,7 @@ struct Inverse {
// Provide a partial specialization of GraphTraits so that the inverse of an
// inverse falls back to the original graph.
template<class T>
struct GraphTraits<Inverse<Inverse<T> > > {
typedef typename GraphTraits<T>::NodeType NodeType;
typedef typename GraphTraits<T>::ChildIteratorType ChildIteratorType;
static NodeType *getEntryNode(Inverse<Inverse<T> > *G) {
return GraphTraits<T>::getEntryNode(G->Graph.Graph);
}
static ChildIteratorType child_begin(NodeType* N) {
return GraphTraits<T>::child_begin(N);
}
static ChildIteratorType child_end(NodeType* N) {
return GraphTraits<T>::child_end(N);
}
};
template <class T> struct GraphTraits<Inverse<Inverse<T>>> : GraphTraits<T> {};
} // End llvm namespace

View File

@ -16,8 +16,9 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <cstdint>
#include <new>
namespace llvm {
@ -25,18 +26,18 @@ template <typename T> class ImmutableListFactory;
template <typename T>
class ImmutableListImpl : public FoldingSetNode {
friend class ImmutableListFactory<T>;
T Head;
const ImmutableListImpl* Tail;
ImmutableListImpl(const T& head, const ImmutableListImpl* tail = nullptr)
: Head(head), Tail(tail) {}
friend class ImmutableListFactory<T>;
void operator=(const ImmutableListImpl&) = delete;
ImmutableListImpl(const ImmutableListImpl&) = delete;
public:
ImmutableListImpl(const ImmutableListImpl &) = delete;
ImmutableListImpl &operator=(const ImmutableListImpl &) = delete;
const T& getHead() const { return Head; }
const ImmutableListImpl* getTail() const { return Tail; }
@ -79,15 +80,17 @@ class ImmutableList {
}
class iterator {
const ImmutableListImpl<T>* L;
const ImmutableListImpl<T>* L = nullptr;
public:
iterator() : L(nullptr) {}
iterator() = default;
iterator(ImmutableList l) : L(l.getInternalPointer()) {}
iterator& operator++() { L = L->getTail(); return *this; }
bool operator==(const iterator& I) const { return L == I.L; }
bool operator!=(const iterator& I) const { return L != I.L; }
const value_type& operator*() const { return L->getHead(); }
ImmutableList getList() const { return L; }
};
@ -121,7 +124,7 @@ class ImmutableList {
/// getHead - Returns the head of the list.
const T& getHead() {
assert (!isEmpty() && "Cannot get the head of an empty list.");
assert(!isEmpty() && "Cannot get the head of an empty list.");
return X->getHead();
}
@ -145,7 +148,7 @@ class ImmutableListFactory {
uintptr_t Allocator;
bool ownsAllocator() const {
return Allocator & 0x1 ? false : true;
return (Allocator & 0x1) == 0;
}
BumpPtrAllocator& getAllocator() const {
@ -203,18 +206,21 @@ class ImmutableListFactory {
//===----------------------------------------------------------------------===//
template<typename T> struct DenseMapInfo;
template<typename T> struct DenseMapInfo<ImmutableList<T> > {
template<typename T> struct DenseMapInfo<ImmutableList<T>> {
static inline ImmutableList<T> getEmptyKey() {
return reinterpret_cast<ImmutableListImpl<T>*>(-1);
}
static inline ImmutableList<T> getTombstoneKey() {
return reinterpret_cast<ImmutableListImpl<T>*>(-2);
}
static unsigned getHashValue(ImmutableList<T> X) {
uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer());
return (unsigned((uintptr_t)PtrVal) >> 4) ^
(unsigned((uintptr_t)PtrVal) >> 9);
}
static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) {
return X1 == X2;
}
@ -222,8 +228,8 @@ template<typename T> struct DenseMapInfo<ImmutableList<T> > {
template <typename T> struct isPodLike;
template <typename T>
struct isPodLike<ImmutableList<T> > { static const bool value = true; };
struct isPodLike<ImmutableList<T>> { static const bool value = true; };
} // end llvm namespace
} // end namespace llvm
#endif // LLVM_ADT_IMMUTABLELIST_H

View File

@ -14,7 +14,10 @@
#ifndef LLVM_ADT_IMMUTABLEMAP_H
#define LLVM_ADT_IMMUTABLEMAP_H
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
#include "llvm/Support/Allocator.h"
#include <utility>
namespace llvm {
@ -56,7 +59,7 @@ struct ImutKeyValueInfo {
};
template <typename KeyT, typename ValT,
typename ValInfo = ImutKeyValueInfo<KeyT,ValT> >
typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
class ImmutableMap {
public:
typedef typename ValInfo::value_type value_type;
@ -106,6 +109,9 @@ class ImmutableMap {
Factory(BumpPtrAllocator &Alloc, bool canonicalize = true)
: F(Alloc), Canonicalize(canonicalize) {}
Factory(const Factory &) = delete;
Factory &operator=(const Factory &) = delete;
ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); }
ImmutableMap add(ImmutableMap Old, key_type_ref K, data_type_ref D) {
@ -121,10 +127,6 @@ class ImmutableMap {
typename TreeTy::Factory *getTreeFactory() const {
return const_cast<typename TreeTy::Factory *>(&F);
}
private:
Factory(const Factory& RHS) = delete;
void operator=(const Factory& RHS) = delete;
};
bool contains(key_type_ref K) const {
@ -203,9 +205,10 @@ class ImmutableMap {
//===--------------------------------------------------===//
class iterator : public ImutAVLValueIterator<ImmutableMap> {
friend class ImmutableMap;
iterator() = default;
explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
friend class ImmutableMap;
public:
key_type_ref getKey() const { return (*this)->first; }
@ -248,7 +251,7 @@ class ImmutableMap {
// NOTE: This will possibly become the new implementation of ImmutableMap some day.
template <typename KeyT, typename ValT,
typename ValInfo = ImutKeyValueInfo<KeyT,ValT> >
typename ValInfo = ImutKeyValueInfo<KeyT,ValT>>
class ImmutableMapRef {
public:
typedef typename ValInfo::value_type value_type;
@ -362,9 +365,10 @@ class ImmutableMapRef {
//===--------------------------------------------------===//
class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
friend class ImmutableMapRef;
iterator() = default;
explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
friend class ImmutableMapRef;
public:
key_type_ref getKey() const { return (*this)->first; }

View File

@ -16,12 +16,16 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <functional>
#include <vector>
#include <cstdint>
#include <iterator>
#include <new>
namespace llvm {
@ -329,11 +333,13 @@ class ImutAVLTree {
public:
void retain() { ++refCount; }
void release() {
assert(refCount > 0);
if (--refCount == 0)
destroy();
}
void destroy() {
if (left)
left->release();
@ -375,7 +381,7 @@ class ImutAVLFactory {
std::vector<TreeTy*> freeNodes;
bool ownsAllocator() const {
return Allocator & 0x1 ? false : true;
return (Allocator & 0x1) == 0;
}
BumpPtrAllocator& getAllocator() const {
@ -414,7 +420,6 @@ class ImutAVLFactory {
TreeTy* getEmptyTree() const { return nullptr; }
protected:
//===--------------------------------------------------===//
// A bunch of quick helper functions used for reasoning
// about the properties of trees and their children.
@ -649,13 +654,14 @@ class ImutAVLTreeGenericIterator
: public std::iterator<std::bidirectional_iterator_tag,
ImutAVLTree<ImutInfo>> {
SmallVector<uintptr_t,20> stack;
public:
enum VisitFlag { VisitedNone=0x0, VisitedLeft=0x1, VisitedRight=0x3,
Flags=0x3 };
typedef ImutAVLTree<ImutInfo> TreeTy;
ImutAVLTreeGenericIterator() {}
ImutAVLTreeGenericIterator() = default;
ImutAVLTreeGenericIterator(const TreeTy *Root) {
if (Root) stack.push_back(reinterpret_cast<uintptr_t>(Root));
}
@ -671,7 +677,6 @@ class ImutAVLTreeGenericIterator
return stack.back() & Flags;
}
bool atEnd() const { return stack.empty(); }
bool atBeginning() const {
@ -881,7 +886,6 @@ struct ImutProfileInfo<bool> {
}
};
/// Generic profile trait for pointer types. We treat pointers as
/// references to unique objects.
template <typename T>
@ -901,7 +905,6 @@ struct ImutProfileInfo<T*> {
// for element profiling.
//===----------------------------------------------------------------------===//
/// ImutContainerInfo - Generic definition of comparison operations for
/// elements of immutable containers that defaults to using
/// std::equal_to<> and std::less<> to perform comparison of elements.
@ -954,7 +957,7 @@ struct ImutContainerInfo<T*> : public ImutProfileInfo<T*> {
// Immutable Set
//===----------------------------------------------------------------------===//
template <typename ValT, typename ValInfo = ImutContainerInfo<ValT> >
template <typename ValT, typename ValInfo = ImutContainerInfo<ValT>>
class ImmutableSet {
public:
typedef typename ValInfo::value_type value_type;
@ -972,9 +975,11 @@ class ImmutableSet {
explicit ImmutableSet(TreeTy* R) : Root(R) {
if (Root) { Root->retain(); }
}
ImmutableSet(const ImmutableSet &X) : Root(X.Root) {
if (Root) { Root->retain(); }
}
ImmutableSet &operator=(const ImmutableSet &X) {
if (Root != X.Root) {
if (X.Root) { X.Root->retain(); }
@ -983,6 +988,7 @@ class ImmutableSet {
}
return *this;
}
~ImmutableSet() {
if (Root) { Root->release(); }
}
@ -998,6 +1004,9 @@ class ImmutableSet {
Factory(BumpPtrAllocator& Alloc, bool canonicalize = true)
: F(Alloc), Canonicalize(canonicalize) {}
Factory(const Factory& RHS) = delete;
void operator=(const Factory& RHS) = delete;
/// getEmptySet - Returns an immutable set that contains no elements.
ImmutableSet getEmptySet() {
return ImmutableSet(F.getEmptyTree());
@ -1032,10 +1041,6 @@ class ImmutableSet {
typename TreeTy::Factory *getTreeFactory() const {
return const_cast<typename TreeTy::Factory *>(&F);
}
private:
Factory(const Factory& RHS) = delete;
void operator=(const Factory& RHS) = delete;
};
friend class Factory;
@ -1104,7 +1109,7 @@ class ImmutableSet {
};
// NOTE: This may some day replace the current ImmutableSet.
template <typename ValT, typename ValInfo = ImutContainerInfo<ValT> >
template <typename ValT, typename ValInfo = ImutContainerInfo<ValT>>
class ImmutableSetRef {
public:
typedef typename ValInfo::value_type value_type;
@ -1126,11 +1131,13 @@ class ImmutableSetRef {
Factory(F) {
if (Root) { Root->retain(); }
}
ImmutableSetRef(const ImmutableSetRef &X)
: Root(X.Root),
Factory(X.Factory) {
if (Root) { Root->retain(); }
}
ImmutableSetRef &operator=(const ImmutableSetRef &X) {
if (Root != X.Root) {
if (X.Root) { X.Root->retain(); }
@ -1215,4 +1222,4 @@ class ImmutableSetRef {
} // end namespace llvm
#endif
#endif // LLVM_ADT_IMMUTABLESET_H

View File

@ -104,11 +104,14 @@
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/RecyclingAllocator.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <new>
#include <utility>
namespace llvm {
//===----------------------------------------------------------------------===//
//--- Key traits ---//
//===----------------------------------------------------------------------===//
@ -131,7 +134,6 @@ namespace llvm {
template <typename T>
struct IntervalMapInfo {
/// startLess - Return true if x is not in [a;b].
/// This is x < a both for closed intervals and for [a;b) half-open intervals.
static inline bool startLess(const T &x, const T &a) {
@ -150,11 +152,15 @@ struct IntervalMapInfo {
return a+1 == b;
}
/// nonEmpty - Return true if [a;b] is non-empty.
/// This is a <= b for a closed interval, a < b for [a;b) half-open intervals.
static inline bool nonEmpty(const T &a, const T &b) {
return a <= b;
}
};
template <typename T>
struct IntervalMapHalfOpenInfo {
/// startLess - Return true if x is not in [a;b).
static inline bool startLess(const T &x, const T &a) {
return x < a;
@ -170,19 +176,18 @@ struct IntervalMapHalfOpenInfo {
return a == b;
}
/// nonEmpty - Return true if [a;b) is non-empty.
static inline bool nonEmpty(const T &a, const T &b) {
return a < b;
}
};
/// IntervalMapImpl - Namespace used for IntervalMap implementation details.
/// It should be considered private to the implementation.
namespace IntervalMapImpl {
// Forward declarations.
template <typename, typename, unsigned, typename> class LeafNode;
template <typename, typename, unsigned, typename> class BranchNode;
typedef std::pair<unsigned,unsigned> IdxPair;
//===----------------------------------------------------------------------===//
//--- IntervalMapImpl::NodeBase ---//
//===----------------------------------------------------------------------===//
@ -406,7 +411,6 @@ IdxPair distribute(unsigned Nodes, unsigned Elements, unsigned Capacity,
const unsigned *CurSize, unsigned NewSize[],
unsigned Position, bool Grow);
//===----------------------------------------------------------------------===//
//--- IntervalMapImpl::NodeSizer ---//
//===----------------------------------------------------------------------===//
@ -459,10 +463,8 @@ struct NodeSizer {
/// different kinds of maps.
typedef RecyclingAllocator<BumpPtrAllocator, char,
AllocBytes, CacheLineBytes> Allocator;
};
//===----------------------------------------------------------------------===//
//--- IntervalMapImpl::NodeRef ---//
//===----------------------------------------------------------------------===//
@ -494,7 +496,7 @@ class NodeRef {
public:
/// NodeRef - Create a null ref.
NodeRef() {}
NodeRef() = default;
/// operator bool - Detect a null ref.
explicit operator bool() const { return pip.getOpaqueValue(); }
@ -674,7 +676,6 @@ insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y) {
return Size + 1;
}
//===----------------------------------------------------------------------===//
//--- IntervalMapImpl::BranchNode ---//
//===----------------------------------------------------------------------===//
@ -919,8 +920,7 @@ class Path {
}
};
} // namespace IntervalMapImpl
} // end namespace IntervalMapImpl
//===----------------------------------------------------------------------===//
//--- IntervalMap ----//
@ -928,7 +928,7 @@ class Path {
template <typename KeyT, typename ValT,
unsigned N = IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize,
typename Traits = IntervalMapInfo<KeyT> >
typename Traits = IntervalMapInfo<KeyT>>
class IntervalMap {
typedef IntervalMapImpl::NodeSizer<KeyT, ValT> Sizer;
typedef IntervalMapImpl::LeafNode<KeyT, ValT, Sizer::LeafSize, Traits> Leaf;
@ -995,6 +995,7 @@ class IntervalMap {
assert(!branched() && "Cannot acces leaf data in branched root");
return dataAs<RootLeaf>();
}
RootBranchData &rootBranchData() const {
assert(branched() && "Cannot access branch data in non-branched root");
return dataAs<RootBranchData>();
@ -1003,6 +1004,7 @@ class IntervalMap {
assert(branched() && "Cannot access branch data in non-branched root");
return dataAs<RootBranchData>();
}
const RootBranch &rootBranch() const { return rootBranchData().node; }
RootBranch &rootBranch() { return rootBranchData().node; }
KeyT rootBranchStart() const { return rootBranchData().start; }
@ -1041,7 +1043,7 @@ class IntervalMap {
public:
explicit IntervalMap(Allocator &a) : height(0), rootSize(0), allocator(a) {
assert((uintptr_t(data.buffer) & (alignOf<RootLeaf>() - 1)) == 0 &&
assert((uintptr_t(data.buffer) & (alignof(RootLeaf) - 1)) == 0 &&
"Insufficient alignment");
new(&rootLeaf()) RootLeaf();
}
@ -1149,7 +1151,6 @@ treeSafeLookup(KeyT x, ValT NotFound) const {
return NR.get<Leaf>().safeLookup(x, NotFound);
}
// branchRoot - Switch from a leaf root to a branched root.
// Return the new (root offset, node offset) corresponding to Position.
template <typename KeyT, typename ValT, unsigned N, typename Traits>
@ -1284,6 +1285,7 @@ clear() {
template <typename KeyT, typename ValT, unsigned N, typename Traits>
class IntervalMap<KeyT, ValT, N, Traits>::const_iterator :
public std::iterator<std::bidirectional_iterator_tag, ValT> {
protected:
friend class IntervalMap;
@ -1436,7 +1438,6 @@ class IntervalMap<KeyT, ValT, N, Traits>::const_iterator :
path.leafOffset() =
map->rootLeaf().findFrom(path.leafOffset(), map->rootSize, x);
}
};
/// pathFillFind - Complete path by searching for x.
@ -1523,7 +1524,7 @@ class IntervalMap<KeyT, ValT, N, Traits>::iterator : public const_iterator {
public:
/// iterator - Create null iterator.
iterator() {}
iterator() = default;
/// setStart - Move the start of the current interval.
/// This may cause coalescing with the previous interval.
@ -1589,7 +1590,6 @@ class IntervalMap<KeyT, ValT, N, Traits>::iterator : public const_iterator {
operator--();
return tmp;
}
};
/// canCoalesceLeft - Can the current interval coalesce to the left after
@ -1669,7 +1669,7 @@ iterator::setNodeStop(unsigned Level, KeyT Stop) {
template <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
iterator::setStart(KeyT a) {
assert(Traits::stopLess(a, this->stop()) && "Cannot move start beyond stop");
assert(Traits::nonEmpty(a, this->stop()) && "Cannot move start beyond stop");
KeyT &CurStart = this->unsafeStart();
if (!Traits::startLess(a, CurStart) || !canCoalesceLeft(a, this->value())) {
CurStart = a;
@ -1685,7 +1685,7 @@ iterator::setStart(KeyT a) {
template <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
iterator::setStop(KeyT b) {
assert(Traits::stopLess(this->start(), b) && "Cannot move stop beyond start");
assert(Traits::nonEmpty(this->start(), b) && "Cannot move stop beyond start");
if (Traits::startLess(b, this->stop()) ||
!canCoalesceRight(b, this->value())) {
setStopUnchecked(b);
@ -1790,7 +1790,6 @@ iterator::insert(KeyT a, KeyT b, ValT y) {
treeInsert(a, b, y);
}
template <typename KeyT, typename ValT, unsigned N, typename Traits>
void IntervalMap<KeyT, ValT, N, Traits>::
iterator::treeInsert(KeyT a, KeyT b, ValT y) {
@ -2151,6 +2150,6 @@ class IntervalMapOverlaps {
}
};
} // namespace llvm
} // end namespace llvm
#endif
#endif // LLVM_ADT_INTERVALMAP_H

View File

@ -7,14 +7,49 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines IntrusiveRefCntPtr, a template class that
// implements a "smart" pointer for objects that maintain their own
// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
// generic base classes for objects that wish to have their lifetimes
// managed using reference counting.
// This file defines the RefCountedBase, ThreadSafeRefCountedBase, and
// IntrusiveRefCntPtr classes.
//
// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
// LLVM-style casting.
// IntrusiveRefCntPtr is a smart pointer to an object which maintains a
// reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a
// refcount member variable and methods for updating the refcount. An object
// that inherits from (ThreadSafe)RefCountedBase deletes itself when its
// refcount hits zero.
//
// For example:
//
// class MyClass : public RefCountedBase<MyClass> {};
//
// void foo() {
// // Objects that inherit from RefCountedBase should always be instantiated
// // on the heap, never on the stack.
// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass());
//
// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1.
// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1);
//
// // Constructing an IntrusiveRefCntPtr has no effect on the object's
// // refcount. After a move, the moved-from pointer is null.
// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1));
// assert(Ptr1 == nullptr);
//
// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1.
// Ptr2.reset();
//
// // The object deletes itself when we return from the function, because
// // Ptr3's destructor decrements its refcount to 0.
// }
//
// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.:
//
// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass());
// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required
//
// IntrusiveRefCntPtr works with any class that
//
// - inherits from (ThreadSafe)RefCountedBase,
// - has Retain() and Release() methods, or
// - specializes IntrusiveRefCntPtrInfo.
//
//===----------------------------------------------------------------------===//
@ -27,261 +62,207 @@
namespace llvm {
template <class T>
class IntrusiveRefCntPtr;
//===----------------------------------------------------------------------===//
/// RefCountedBase - A generic base class for objects that wish to
/// have their lifetimes managed using reference counts. Classes
/// subclass RefCountedBase to obtain such functionality, and are
/// typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
/// which automatically handle the management of reference counts.
/// Objects that subclass RefCountedBase should not be allocated on
/// the stack, as invoking "delete" (which is called when the
/// reference count hits 0) on such objects is an error.
//===----------------------------------------------------------------------===//
template <class Derived>
class RefCountedBase {
mutable unsigned ref_cnt;
public:
RefCountedBase() : ref_cnt(0) {}
RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
void Retain() const { ++ref_cnt; }
void Release() const {
assert (ref_cnt > 0 && "Reference count is already zero.");
if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
}
};
//===----------------------------------------------------------------------===//
/// RefCountedBaseVPTR - A class that has the same function as
/// RefCountedBase, but with a virtual destructor. Should be used
/// instead of RefCountedBase for classes that already have virtual
/// methods to enforce dynamic allocation via 'new'. Classes that
/// inherit from RefCountedBaseVPTR can't be allocated on stack -
/// attempting to do this will produce a compile error.
//===----------------------------------------------------------------------===//
class RefCountedBaseVPTR {
mutable unsigned ref_cnt;
virtual void anchor();
protected:
RefCountedBaseVPTR() : ref_cnt(0) {}
RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
virtual ~RefCountedBaseVPTR() {}
void Retain() const { ++ref_cnt; }
void Release() const {
assert (ref_cnt > 0 && "Reference count is already zero.");
if (--ref_cnt == 0) delete this;
}
template <typename T>
friend struct IntrusiveRefCntPtrInfo;
};
template <typename T> struct IntrusiveRefCntPtrInfo {
static void retain(T *obj) { obj->Retain(); }
static void release(T *obj) { obj->Release(); }
};
/// \brief A thread-safe version of \c llvm::RefCountedBase.
/// A CRTP mixin class that adds reference counting to a type.
///
/// A generic base class for objects that wish to have their lifetimes managed
/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
/// obtain such functionality, and are typically handled with
/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
/// management of reference counts.
template <class Derived>
class ThreadSafeRefCountedBase {
/// The lifetime of an object which inherits from RefCountedBase is managed by
/// calls to Release() and Retain(), which increment and decrement the object's
/// refcount, respectively. When a Release() call decrements the refcount to 0,
/// the object deletes itself.
///
/// Objects that inherit from RefCountedBase should always be allocated with
/// operator new.
template <class Derived> class RefCountedBase {
mutable unsigned RefCount = 0;
public:
RefCountedBase() = default;
RefCountedBase(const RefCountedBase &) : RefCount(0) {}
void Retain() const { ++RefCount; }
void Release() const {
assert(RefCount > 0 && "Reference count is already zero.");
if (--RefCount == 0)
delete static_cast<const Derived *>(this);
}
};
/// A thread-safe version of \c RefCountedBase.
template <class Derived> class ThreadSafeRefCountedBase {
mutable std::atomic<int> RefCount;
protected:
ThreadSafeRefCountedBase() : RefCount(0) {}
public:
void Retain() const { ++RefCount; }
void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
void Release() const {
int NewRefCount = --RefCount;
int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
assert(NewRefCount >= 0 && "Reference count was already zero.");
if (NewRefCount == 0)
delete static_cast<const Derived*>(this);
delete static_cast<const Derived *>(this);
}
};
//===----------------------------------------------------------------------===//
/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
/// that assumes the wrapped object has a reference count associated
/// with it that can be managed via calls to
/// IntrusivePtrAddRef/IntrusivePtrRelease. The smart pointers
/// manage reference counts via the RAII idiom: upon creation of
/// smart pointer the reference count of the wrapped object is
/// incremented and upon destruction of the smart pointer the
/// reference count is decremented. This class also safely handles
/// wrapping NULL pointers.
/// Class you can specialize to provide custom retain/release functionality for
/// a type.
///
/// Reference counting is implemented via calls to
/// Obj->Retain()/Obj->Release(). Release() is required to destroy
/// the object when the reference count reaches zero. Inheriting from
/// RefCountedBase/RefCountedBaseVPTR takes care of this
/// automatically.
//===----------------------------------------------------------------------===//
template <typename T>
class IntrusiveRefCntPtr {
T* Obj;
/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr
/// works with any type which defines Retain() and Release() functions -- you
/// can define those functions yourself if RefCountedBase doesn't work for you.
///
/// One case when you might want to specialize this type is if you have
/// - Foo.h defines type Foo and includes Bar.h, and
/// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions.
///
/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in
/// the declaration of Foo. Without the declaration of Foo, normally Bar.h
/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call
/// T::Retain and T::Release.
///
/// To resolve this, Bar.h could include a third header, FooFwd.h, which
/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then
/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
/// functions on Foo itself, because Foo would be an incomplete type.
template <typename T> struct IntrusiveRefCntPtrInfo {
static void retain(T *obj) { obj->Retain(); }
static void release(T *obj) { obj->Release(); }
};
public:
typedef T element_type;
/// A smart pointer to a reference-counted object that inherits from
/// RefCountedBase or ThreadSafeRefCountedBase.
///
/// This class increments its pointee's reference count when it is created, and
/// decrements its refcount when it's destroyed (or is changed to point to a
/// different object).
template <typename T> class IntrusiveRefCntPtr {
T *Obj = nullptr;
explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
public:
typedef T element_type;
IntrusiveRefCntPtr(T* obj) : Obj(obj) {
retain();
}
explicit IntrusiveRefCntPtr() = default;
IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); }
IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
retain();
}
IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
S.Obj = nullptr;
}
template <class X>
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
S.Obj = nullptr;
}
template <class X>
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
: Obj(S.get()) {
retain();
}
IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
swap(S);
return *this;
}
~IntrusiveRefCntPtr() { release(); }
T& operator*() const { return *Obj; }
T* operator->() const { return Obj; }
T* get() const { return Obj; }
explicit operator bool() const { return Obj; }
void swap(IntrusiveRefCntPtr& other) {
T* tmp = other.Obj;
other.Obj = Obj;
Obj = tmp;
}
void reset() {
release();
Obj = nullptr;
}
void resetWithoutRelease() {
Obj = nullptr;
}
private:
void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
template <typename X>
friend class IntrusiveRefCntPtr;
};
template<class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
const IntrusiveRefCntPtr<U>& B)
{
return A.get() == B.get();
template <class X>
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) {
S.Obj = nullptr;
}
template<class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
const IntrusiveRefCntPtr<U>& B)
{
return A.get() != B.get();
template <class X>
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) {
retain();
}
template<class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T>& A,
U* B)
{
return A.get() == B;
IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
swap(S);
return *this;
}
template<class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
U* B)
{
return A.get() != B;
~IntrusiveRefCntPtr() { release(); }
T &operator*() const { return *Obj; }
T *operator->() const { return Obj; }
T *get() const { return Obj; }
explicit operator bool() const { return Obj; }
void swap(IntrusiveRefCntPtr &other) {
T *tmp = other.Obj;
other.Obj = Obj;
Obj = tmp;
}
template<class T, class U>
inline bool operator==(T* A,
const IntrusiveRefCntPtr<U>& B)
{
return A == B.get();
void reset() {
release();
Obj = nullptr;
}
template<class T, class U>
inline bool operator!=(T* A,
const IntrusiveRefCntPtr<U>& B)
{
return A != B.get();
void resetWithoutRelease() { Obj = nullptr; }
private:
void retain() {
if (Obj)
IntrusiveRefCntPtrInfo<T>::retain(Obj);
}
void release() {
if (Obj)
IntrusiveRefCntPtrInfo<T>::release(Obj);
}
template <class T>
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !B;
template <typename X> friend class IntrusiveRefCntPtr;
};
template <class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T> &A,
const IntrusiveRefCntPtr<U> &B) {
return A.get() == B.get();
}
template <class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
const IntrusiveRefCntPtr<U> &B) {
return A.get() != B.get();
}
template <class T, class U>
inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
return A.get() == B;
}
template <class T, class U>
inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
return A.get() != B;
}
template <class T, class U>
inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
return A == B.get();
}
template <class T, class U>
inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
return A != B.get();
}
template <class T>
bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !B;
}
template <class T>
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return B == A;
}
template <class T>
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !(A == B);
}
template <class T>
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return !(A == B);
}
// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from
// Casting.h.
template <typename From> struct simplify_type;
template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
typedef T *SimpleType;
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) {
return Val.get();
}
};
template <class T>
bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return B == A;
template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
typedef /*const*/ T *SimpleType;
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) {
return Val.get();
}
template <class T>
bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
return !(A == B);
}
template <class T>
bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
return !(A == B);
}
//===----------------------------------------------------------------------===//
// LLVM-style downcasting support for IntrusiveRefCntPtr objects
//===----------------------------------------------------------------------===//
template <typename From> struct simplify_type;
template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
typedef T* SimpleType;
static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
return Val.get();
}
};
template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
typedef /*const*/ T* SimpleType;
static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
return Val.get();
}
};
};
} // end namespace llvm

View File

@ -30,6 +30,7 @@ template<typename KeyT, typename ValueT,
typename MapType = llvm::DenseMap<KeyT, unsigned>,
typename VectorType = std::vector<std::pair<KeyT, ValueT> > >
class MapVector {
typedef typename VectorType::value_type value_type;
typedef typename VectorType::size_type size_type;
MapType Map;
@ -41,6 +42,12 @@ class MapVector {
typedef typename VectorType::reverse_iterator reverse_iterator;
typedef typename VectorType::const_reverse_iterator const_reverse_iterator;
/// Clear the MapVector and return the underlying vector.
VectorType takeVector() {
Map.clear();
return std::move(Vector);
}
size_type size() const { return Vector.size(); }
iterator begin() { return Vector.begin(); }
@ -83,7 +90,10 @@ class MapVector {
return Vector[I].second;
}
// Returns a copy of the value. Only allowed if ValueT is copyable.
ValueT lookup(const KeyT &Key) const {
static_assert(std::is_copy_constructible<ValueT>::value,
"Cannot call lookup() if ValueT is not copyable.");
typename MapType::const_iterator Pos = Map.find(Key);
return Pos == Map.end()? ValueT() : Vector[Pos->second].second;
}
@ -100,6 +110,19 @@ class MapVector {
return std::make_pair(begin() + I, false);
}
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
// Copy KV.first into the map, then move it into the vector.
std::pair<KeyT, unsigned> Pair = std::make_pair(KV.first, 0);
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
unsigned &I = Result.first->second;
if (Result.second) {
Vector.push_back(std::move(KV));
I = Vector.size() - 1;
return std::make_pair(std::prev(end()), true);
}
return std::make_pair(begin() + I, false);
}
size_type count(const KeyT &Key) const {
typename MapType::const_iterator Pos = Map.find(Key);
return Pos == Map.end()? 0 : 1;

View File

@ -129,7 +129,7 @@ class Optional {
T& operator*() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
template <typename U>
LLVM_CONSTEXPR T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
return hasValue() ? getValue() : std::forward<U>(value);
}
@ -150,18 +150,43 @@ template <typename T> struct isPodLike<Optional<T> > {
static const bool value = isPodLike<T>::value;
};
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator==(const Optional<T> &X, const Optional<U> &Y);
template <typename T, typename U>
bool operator==(const Optional<T> &X, const Optional<U> &Y) {
if (X && Y)
return *X == *Y;
return X.hasValue() == Y.hasValue();
}
template <typename T, typename U>
bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
return !(X == Y);
}
template <typename T, typename U>
bool operator<(const Optional<T> &X, const Optional<U> &Y) {
if (X && Y)
return *X < *Y;
return X.hasValue() < Y.hasValue();
}
template <typename T, typename U>
bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
return !(Y < X);
}
template <typename T, typename U>
bool operator>(const Optional<T> &X, const Optional<U> &Y) {
return Y < X;
}
template <typename T, typename U>
bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
return !(X < Y);
}
template<typename T>
bool operator==(const Optional<T> &X, NoneType) {
return !X.hasValue();
return !X;
}
template<typename T>
@ -178,50 +203,86 @@ template<typename T>
bool operator!=(NoneType, const Optional<T> &X) {
return X != None;
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator!=(const Optional<T> &X, const Optional<U> &Y);
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator<(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<(const Optional<T> &X, NoneType) {
return false;
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator<=(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<(NoneType, const Optional<T> &X) {
return X.hasValue();
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator>=(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
return !(None < X);
}
/// \brief Poison comparison between two \c Optional objects. Clients needs to
/// explicitly compare the underlying values and account for empty \c Optional
/// objects.
///
/// This routine will never be defined. It returns \c void to help diagnose
/// errors at compile time.
template<typename T, typename U>
void operator>(const Optional<T> &X, const Optional<U> &Y);
template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
return !(X < None);
}
template <typename T> bool operator>(const Optional<T> &X, NoneType) {
return None < X;
}
template <typename T> bool operator>(NoneType, const Optional<T> &X) {
return X < None;
}
template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
return None <= X;
}
template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
return X <= None;
}
template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
return X && *X == Y;
}
template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
return Y && X == *Y;
}
template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
return !(X == Y);
}
template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
return !(X == Y);
}
template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
return !X || *X < Y;
}
template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
return Y && X < *Y;
}
template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
return !(Y < X);
}
template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
return !(Y < X);
}
template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
return Y < X;
}
template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
return Y < X;
}
template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
return !(X < Y);
}
template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
return !(X < Y);
}
} // end llvm namespace

View File

@ -15,6 +15,7 @@
#define LLVM_ADT_PACKEDVECTOR_H
#include "llvm/ADT/BitVector.h"
#include <cassert>
#include <limits>
namespace llvm {
@ -83,14 +84,15 @@ class PackedVector : public PackedVectorBase<T, BitNum, BitVectorTy,
PackedVector &Vec;
const unsigned Idx;
reference(); // Undefined
public:
reference() = delete;
reference(PackedVector &vec, unsigned idx) : Vec(vec), Idx(idx) {}
reference &operator=(T val) {
Vec.setValue(Vec.Bits, Idx, val);
return *this;
}
operator T() const {
return Vec.getValue(Vec.Bits, Idx);
}
@ -144,6 +146,6 @@ class PackedVector : public PackedVectorBase<T, BitNum, BitVectorTy,
// Leave BitNum=0 undefined.
template <typename T> class PackedVector<T, 0>;
} // end llvm namespace
} // end namespace llvm
#endif
#endif // LLVM_ADT_PACKEDVECTOR_H

View File

@ -54,7 +54,7 @@ struct PointerSumTypeHelper;
///
/// It also default constructs to a zero tag with a null pointer, whatever that
/// would be. This means that the zero value for the tag type is significant
/// and may be desireable to set to a state that is particularly desirable to
/// and may be desirable to set to a state that is particularly desirable to
/// default construct.
///
/// There is no support for constructing or accessing with a dynamic tag as

View File

@ -17,7 +17,10 @@
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <cstdint>
#include <cstddef>
namespace llvm {
@ -57,6 +60,7 @@ template <typename PT1, typename PT2> class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
enum {
PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
@ -97,7 +101,7 @@ template <typename PT1, typename PT2> class PointerUnion {
template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
public:
PointerUnion() {}
PointerUnion() = default;
PointerUnion(PT1 V)
: Val(const_cast<void *>(
@ -208,6 +212,7 @@ class PointerLikeTypeTraits<PointerUnion<PT1, PT2>> {
static inline void *getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion<PT1, PT2> getFromVoidPointer(void *P) {
return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
}
@ -249,7 +254,7 @@ template <typename PT1, typename PT2, typename PT3> class PointerUnion3 {
};
public:
PointerUnion3() {}
PointerUnion3() = default;
PointerUnion3(PT1 V) { Val = InnerUnion(V); }
PointerUnion3(PT2 V) { Val = InnerUnion(V); }
@ -328,6 +333,7 @@ class PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3>> {
static inline void *getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion3<PT1, PT2, PT3> getFromVoidPointer(void *P) {
return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
}
@ -352,7 +358,7 @@ class PointerUnion4 {
ValTy Val;
public:
PointerUnion4() {}
PointerUnion4() = default;
PointerUnion4(PT1 V) { Val = InnerUnion1(V); }
PointerUnion4(PT2 V) { Val = InnerUnion1(V); }
@ -435,6 +441,7 @@ class PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4>> {
getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion4<PT1, PT2, PT3, PT4> getFromVoidPointer(void *P) {
return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
}
@ -469,6 +476,6 @@ template <typename T, typename U> struct DenseMapInfo<PointerUnion<T, U>> {
}
};
}
} // end namespace llvm
#endif
#endif // LLVM_ADT_POINTERUNION_H

View File

@ -17,9 +17,12 @@
#define LLVM_ADT_POSTORDERITERATOR_H
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallPtrSet.h"
#include <iterator>
#include <set>
#include <utility>
#include <vector>
namespace llvm {
@ -54,22 +57,23 @@ namespace llvm {
template<class SetType, bool External>
class po_iterator_storage {
SetType Visited;
public:
// Return true if edge destination should be visited.
template<typename NodeType>
bool insertEdge(NodeType *From, NodeType *To) {
template <typename NodeRef>
bool insertEdge(Optional<NodeRef> From, NodeRef To) {
return Visited.insert(To).second;
}
// Called after all children of BB have been visited.
template<typename NodeType>
void finishPostorder(NodeType *BB) {}
template <typename NodeRef> void finishPostorder(NodeRef BB) {}
};
/// Specialization of po_iterator_storage that references an external set.
template<class SetType>
class po_iterator_storage<SetType, true> {
SetType &Visited;
public:
po_iterator_storage(SetType &VSet) : Visited(VSet) {}
po_iterator_storage(const po_iterator_storage &S) : Visited(S.Visited) {}
@ -77,51 +81,50 @@ class po_iterator_storage<SetType, true> {
// Return true if edge destination should be visited, called with From = 0 for
// the root node.
// Graph edges can be pruned by specializing this function.
template <class NodeType> bool insertEdge(NodeType *From, NodeType *To) {
template <class NodeRef> bool insertEdge(Optional<NodeRef> From, NodeRef To) {
return Visited.insert(To).second;
}
// Called after all children of BB have been visited.
template<class NodeType>
void finishPostorder(NodeType *BB) {}
template <class NodeRef> void finishPostorder(NodeRef BB) {}
};
template<class GraphT,
class SetType = llvm::SmallPtrSet<typename GraphTraits<GraphT>::NodeType*, 8>,
bool ExtStorage = false,
class GT = GraphTraits<GraphT> >
class po_iterator : public std::iterator<std::forward_iterator_tag,
typename GT::NodeType, ptrdiff_t>,
public po_iterator_storage<SetType, ExtStorage> {
typedef std::iterator<std::forward_iterator_tag,
typename GT::NodeType, ptrdiff_t> super;
typedef typename GT::NodeType NodeType;
template <class GraphT,
class SetType =
SmallPtrSet<typename GraphTraits<GraphT>::NodeRef, 8>,
bool ExtStorage = false, class GT = GraphTraits<GraphT>>
class po_iterator
: public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>,
public po_iterator_storage<SetType, ExtStorage> {
typedef std::iterator<std::forward_iterator_tag, typename GT::NodeRef> super;
typedef typename GT::NodeRef NodeRef;
typedef typename GT::ChildIteratorType ChildItTy;
// VisitStack - Used to maintain the ordering. Top = current block
// First element is basic block pointer, second is the 'next child' to visit
std::vector<std::pair<NodeType *, ChildItTy> > VisitStack;
std::vector<std::pair<NodeRef, ChildItTy>> VisitStack;
void traverseChild() {
while (VisitStack.back().second != GT::child_end(VisitStack.back().first)) {
NodeType *BB = *VisitStack.back().second++;
if (this->insertEdge(VisitStack.back().first, BB)) {
NodeRef BB = *VisitStack.back().second++;
if (this->insertEdge(Optional<NodeRef>(VisitStack.back().first), BB)) {
// If the block is not visited...
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
}
}
}
po_iterator(NodeType *BB) {
this->insertEdge((NodeType*)nullptr, BB);
po_iterator(NodeRef BB) {
this->insertEdge(Optional<NodeRef>(), BB);
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
traverseChild();
}
po_iterator() {} // End is when stack is empty.
po_iterator(NodeType *BB, SetType &S)
po_iterator() = default; // End is when stack is empty.
po_iterator(NodeRef BB, SetType &S)
: po_iterator_storage<SetType, ExtStorage>(S) {
if (this->insertEdge((NodeType*)nullptr, BB)) {
if (this->insertEdge(Optional<NodeRef>(), BB)) {
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
traverseChild();
}
@ -130,6 +133,7 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
po_iterator(SetType &S)
: po_iterator_storage<SetType, ExtStorage>(S) {
} // End is when stack is empty.
public:
typedef typename super::pointer pointer;
@ -149,13 +153,13 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
}
bool operator!=(const po_iterator &x) const { return !(*this == x); }
pointer operator*() const { return VisitStack.back().first; }
const NodeRef &operator*() const { return VisitStack.back().first; }
// This is a nonstandard operator-> that dereferences the pointer an extra
// time... so that you can actually call methods ON the BasicBlock, because
// the contained type is a pointer. This allows BBIt->getTerminator() f.e.
//
NodeType *operator->() const { return **this; }
NodeRef operator->() const { return **this; }
po_iterator &operator++() { // Preincrement
this->finishPostorder(VisitStack.back().first);
@ -184,7 +188,7 @@ template <class T> iterator_range<po_iterator<T>> post_order(const T &G) {
}
// Provide global definitions of external postorder iterators...
template<class T, class SetType=std::set<typename GraphTraits<T>::NodeType*> >
template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
struct po_ext_iterator : public po_iterator<T, SetType, true> {
po_ext_iterator(const po_iterator<T, SetType, true> &V) :
po_iterator<T, SetType, true>(V) {}
@ -206,10 +210,9 @@ iterator_range<po_ext_iterator<T, SetType>> post_order_ext(const T &G, SetType &
}
// Provide global definitions of inverse post order iterators...
template <class T,
class SetType = std::set<typename GraphTraits<T>::NodeType*>,
template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>,
bool External = false>
struct ipo_iterator : public po_iterator<Inverse<T>, SetType, External > {
struct ipo_iterator : public po_iterator<Inverse<T>, SetType, External> {
ipo_iterator(const po_iterator<Inverse<T>, SetType, External> &V) :
po_iterator<Inverse<T>, SetType, External> (V) {}
};
@ -230,8 +233,7 @@ iterator_range<ipo_iterator<T>> inverse_post_order(const T &G) {
}
// Provide global definitions of external inverse postorder iterators...
template <class T,
class SetType = std::set<typename GraphTraits<T>::NodeType*> >
template <class T, class SetType = std::set<typename GraphTraits<T>::NodeRef>>
struct ipo_ext_iterator : public ipo_iterator<T, SetType, true> {
ipo_ext_iterator(const ipo_iterator<T, SetType, true> &V) :
ipo_iterator<T, SetType, true>(V) {}
@ -278,15 +280,17 @@ inverse_post_order_ext(const T &G, SetType &S) {
// }
//
template<class GraphT, class GT = GraphTraits<GraphT> >
template<class GraphT, class GT = GraphTraits<GraphT>>
class ReversePostOrderTraversal {
typedef typename GT::NodeType NodeType;
std::vector<NodeType*> Blocks; // Block list in normal PO order
void Initialize(NodeType *BB) {
typedef typename GT::NodeRef NodeRef;
std::vector<NodeRef> Blocks; // Block list in normal PO order
void Initialize(NodeRef BB) {
std::copy(po_begin(BB), po_end(BB), std::back_inserter(Blocks));
}
public:
typedef typename std::vector<NodeType*>::reverse_iterator rpo_iterator;
typedef typename std::vector<NodeRef>::reverse_iterator rpo_iterator;
ReversePostOrderTraversal(GraphT G) { Initialize(GT::getEntryNode(G)); }
@ -295,6 +299,6 @@ class ReversePostOrderTraversal {
rpo_iterator end() { return Blocks.rend(); }
};
} // End llvm namespace
} // end namespace llvm
#endif
#endif // LLVM_ADT_POSTORDERITERATOR_H

View File

@ -46,8 +46,7 @@ class PriorityQueue : public std::priority_queue<T, Sequence, Compare> {
///
void erase_one(const T &t) {
// Linear-search to find the element.
typename Sequence::size_type i =
std::find(this->c.begin(), this->c.end(), t) - this->c.begin();
typename Sequence::size_type i = find(this->c, t) - this->c.begin();
// Logarithmic-time heap bubble-up.
while (i != 0) {

View File

@ -17,10 +17,12 @@
#define LLVM_ADT_PRIORITYWORKLIST_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <cassert>
#include <utility>
#include <cstddef>
#include <vector>
namespace llvm {
@ -59,7 +61,7 @@ class PriorityWorklist {
typedef typename MapT::size_type size_type;
/// Construct an empty PriorityWorklist
PriorityWorklist() {}
PriorityWorklist() = default;
/// Determine if the PriorityWorklist is empty or not.
bool empty() const {
@ -115,7 +117,7 @@ class PriorityWorklist {
} while (!V.empty() && V.back() == T());
}
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
LLVM_NODISCARD T pop_back_val() {
T Ret = back();
pop_back();
return Ret;
@ -147,7 +149,7 @@ class PriorityWorklist {
/// write it:
///
/// \code
/// V.erase(std::remove_if(V.begin(), V.end(), P), V.end());
/// V.erase(remove_if(V, P), V.end());
/// \endcode
///
/// However, PriorityWorklist doesn't expose non-const iterators, making any
@ -156,8 +158,8 @@ class PriorityWorklist {
/// \returns true if any element is removed.
template <typename UnaryPredicate>
bool erase_if(UnaryPredicate P) {
typename VectorT::iterator E = std::remove_if(
V.begin(), V.end(), TestAndEraseFromMap<UnaryPredicate>(P, M));
typename VectorT::iterator E =
remove_if(V, TestAndEraseFromMap<UnaryPredicate>(P, M));
if (E == V.end())
return false;
for (auto I = V.begin(); I != E; ++I)
@ -216,9 +218,9 @@ class SmallPriorityWorklist
: public PriorityWorklist<T, SmallVector<T, N>,
SmallDenseMap<T, ptrdiff_t>> {
public:
SmallPriorityWorklist() {}
SmallPriorityWorklist() = default;
};
}
} // end namespace llvm
#endif
#endif // LLVM_ADT_PRIORITYWORKLIST_H

View File

@ -26,6 +26,9 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/iterator.h"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <vector>
namespace llvm {
@ -93,7 +96,7 @@ class scc_iterator : public iterator_facade_base<
}
/// End is when the DFS stack is empty.
scc_iterator() {}
scc_iterator() = default;
public:
static scc_iterator begin(const GraphT &G) {
@ -230,15 +233,15 @@ template <class T> scc_iterator<T> scc_end(const T &G) {
}
/// \brief Construct the begin iterator for a deduced graph type T's Inverse<T>.
template <class T> scc_iterator<Inverse<T> > scc_begin(const Inverse<T> &G) {
return scc_iterator<Inverse<T> >::begin(G);
template <class T> scc_iterator<Inverse<T>> scc_begin(const Inverse<T> &G) {
return scc_iterator<Inverse<T>>::begin(G);
}
/// \brief Construct the end iterator for a deduced graph type T's Inverse<T>.
template <class T> scc_iterator<Inverse<T> > scc_end(const Inverse<T> &G) {
return scc_iterator<Inverse<T> >::end(G);
template <class T> scc_iterator<Inverse<T>> scc_end(const Inverse<T> &G) {
return scc_iterator<Inverse<T>>::end(G);
}
} // End llvm namespace
} // end namespace llvm
#endif
#endif // LLVM_ADT_SCCITERATOR_H

View File

@ -24,18 +24,25 @@
#include <functional>
#include <iterator>
#include <memory>
#include <tuple>
#include <utility> // for std::pair
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
namespace llvm {
// Only used by compiler if both template types are the same. Useful when
// using SFINAE to test for the existence of member functions.
template <typename T, T> struct SameType;
namespace detail {
template <typename RangeT>
using IterOfRange = decltype(std::begin(std::declval<RangeT>()));
using IterOfRange = decltype(std::begin(std::declval<RangeT &>()));
} // End detail namespace
@ -208,11 +215,24 @@ inline mapped_iterator<ItTy, FuncTy> map_iterator(const ItTy &I, FuncTy F) {
return mapped_iterator<ItTy, FuncTy>(I, F);
}
/// \brief Metafunction to determine if type T has a member called rbegin().
template <typename T> struct has_rbegin {
template <typename U> static char(&f(const U &, decltype(&U::rbegin)))[1];
static char(&f(...))[2];
const static bool value = sizeof(f(std::declval<T>(), nullptr)) == 1;
/// Helper to determine if type T has a member called rbegin().
template <typename Ty> class has_rbegin_impl {
typedef char yes[1];
typedef char no[2];
template <typename Inner>
static yes& test(Inner *I, decltype(I->rbegin()) * = nullptr);
template <typename>
static no& test(...);
public:
static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes);
};
/// Metafunction to determine if T& or T has a member called rbegin().
template <typename Ty>
struct has_rbegin : has_rbegin_impl<typename std::remove_reference<Ty>::type> {
};
// Returns an iterator_range over the given container which iterates in reverse.
@ -327,6 +347,240 @@ make_filter_range(RangeT &&Range, PredicateT Pred) {
FilterIteratorT(std::end(std::forward<RangeT>(Range))));
}
// forward declarations required by zip_shortest/zip_first
template <typename R, typename UnaryPredicate>
bool all_of(R &&range, UnaryPredicate P);
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;
std::tuple<Iters...> iterators;
private:
template <size_t... Ns> value_type deres(index_sequence<Ns...>) {
return value_type(*std::get<Ns>(iterators)...);
}
template <size_t... Ns> decltype(iterators) tup_inc(index_sequence<Ns...>) {
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);
}
zip_first(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
};
template <typename... Iters> class zip_shortest : public zip_first<Iters...> {
template <size_t... Ns>
bool test(const zip_first<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...>{});
}
zip_shortest(Iters &&... ts)
: zip_first<Iters...>(std::forward<Iters>(ts)...) {}
};
template <template <typename...> class ItType, typename... Args> class zippy {
public:
typedef ItType<decltype(std::begin(std::declval<Args>()))...> iterator;
private:
std::tuple<Args...> ts;
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
return iterator(std::begin(std::get<Ns>(ts))...);
}
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
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...>{}); }
zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
};
} // End detail namespace
/// zip iterator for two or more iteratable types.
template <typename T, typename U, typename... Args>
detail::zippy<detail::zip_shortest, T, U, Args...> zip(T &&t, U &&u,
Args &&... args) {
return detail::zippy<detail::zip_shortest, T, U, Args...>(
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
}
/// zip iterator that, for the sake of efficiency, assumes the first iteratee to
/// be the shortest.
template <typename T, typename U, typename... Args>
detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u,
Args &&... args) {
return detail::zippy<detail::zip_first, T, U, Args...>(
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
}
/// Iterator wrapper that concatenates sequences together.
///
/// This can concatenate different iterators, even with different types, into
/// a single iterator provided the value types of all the concatenated
/// iterators expose `reference` and `pointer` types that can be converted to
/// `ValueT &` and `ValueT *` respectively. It doesn't support more
/// interesting/customized pointer or reference types.
///
/// Currently this only supports forward or higher iterator categories as
/// inputs and always exposes a forward iterator interface.
template <typename ValueT, typename... IterTs>
class concat_iterator
: public iterator_facade_base<concat_iterator<ValueT, IterTs...>,
std::forward_iterator_tag, ValueT> {
typedef typename concat_iterator::iterator_facade_base BaseT;
/// We store both the current and end iterators for each concatenated
/// sequence in a tuple of pairs.
///
/// Note that something like iterator_range seems nice at first here, but the
/// range properties are of little benefit and end up getting in the way
/// because we need to do mutation on the current iterators.
std::tuple<std::pair<IterTs, IterTs>...> IterPairs;
/// Attempts to increment a specific iterator.
///
/// Returns true if it was able to increment the iterator. Returns false if
/// the iterator is already at the end iterator.
template <size_t Index> bool incrementHelper() {
auto &IterPair = std::get<Index>(IterPairs);
if (IterPair.first == IterPair.second)
return false;
++IterPair.first;
return true;
}
/// Increments the first non-end iterator.
///
/// It is an error to call this with all iterators at the end.
template <size_t... Ns> void increment(index_sequence<Ns...>) {
// Build a sequence of functions to increment each iterator if possible.
bool (concat_iterator::*IncrementHelperFns[])() = {
&concat_iterator::incrementHelper<Ns>...};
// Loop over them, and stop as soon as we succeed at incrementing one.
for (auto &IncrementHelperFn : IncrementHelperFns)
if ((this->*IncrementHelperFn)())
return;
llvm_unreachable("Attempted to increment an end concat iterator!");
}
/// Returns null if the specified iterator is at the end. Otherwise,
/// dereferences the iterator and returns the address of the resulting
/// reference.
template <size_t Index> ValueT *getHelper() const {
auto &IterPair = std::get<Index>(IterPairs);
if (IterPair.first == IterPair.second)
return nullptr;
return &*IterPair.first;
}
/// Finds the first non-end iterator, dereferences, and returns the resulting
/// reference.
///
/// It is an error to call this with all iterators at the end.
template <size_t... Ns> ValueT &get(index_sequence<Ns...>) const {
// Build a sequence of functions to get from iterator if possible.
ValueT *(concat_iterator::*GetHelperFns[])() const = {
&concat_iterator::getHelper<Ns>...};
// Loop over them, and return the first result we find.
for (auto &GetHelperFn : GetHelperFns)
if (ValueT *P = (this->*GetHelperFn)())
return *P;
llvm_unreachable("Attempted to get a pointer from an end concat iterator!");
}
public:
/// Constructs an iterator from a squence of ranges.
///
/// We need the full range to know how to switch between each of the
/// iterators.
template <typename... RangeTs>
explicit concat_iterator(RangeTs &&... Ranges)
: IterPairs({std::begin(Ranges), std::end(Ranges)}...) {}
using BaseT::operator++;
concat_iterator &operator++() {
increment(index_sequence_for<IterTs...>());
return *this;
}
ValueT &operator*() const { return get(index_sequence_for<IterTs...>()); }
bool operator==(const concat_iterator &RHS) const {
return IterPairs == RHS.IterPairs;
}
};
namespace detail {
/// Helper to store a sequence of ranges being concatenated and access them.
///
/// This is designed to facilitate providing actual storage when temporaries
/// are passed into the constructor such that we can use it as part of range
/// based for loops.
template <typename ValueT, typename... RangeTs> class concat_range {
public:
typedef concat_iterator<ValueT,
decltype(std::begin(std::declval<RangeTs &>()))...>
iterator;
private:
std::tuple<RangeTs...> Ranges;
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
return iterator(std::get<Ns>(Ranges)...);
}
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
return iterator(make_range(std::end(std::get<Ns>(Ranges)),
std::end(std::get<Ns>(Ranges)))...);
}
public:
iterator begin() { return begin_impl(index_sequence_for<RangeTs...>{}); }
iterator end() { return end_impl(index_sequence_for<RangeTs...>{}); }
concat_range(RangeTs &&... Ranges)
: Ranges(std::forward<RangeTs>(Ranges)...) {}
};
}
/// Concatenated range across two or more ranges.
///
/// The desired value type must be explicitly specified.
template <typename ValueT, typename... RangeTs>
detail::concat_range<ValueT, RangeTs...> concat(RangeTs &&... Ranges) {
static_assert(sizeof...(RangeTs) > 1,
"Need more than one range to concatenate!");
return detail::concat_range<ValueT, RangeTs...>(
std::forward<RangeTs>(Ranges)...);
}
//===----------------------------------------------------------------------===//
// Extra additions to <utility>
//===----------------------------------------------------------------------===//
@ -353,7 +607,7 @@ struct less_second {
template <class T, T... I> struct integer_sequence {
typedef T value_type;
static LLVM_CONSTEXPR size_t size() { return sizeof...(I); }
static constexpr size_t size() { return sizeof...(I); }
};
/// \brief Alias for the common case of a sequence of size_ts.
@ -369,13 +623,30 @@ struct build_index_impl<0, I...> : index_sequence<I...> {};
template <class... Ts>
struct index_sequence_for : build_index_impl<sizeof...(Ts)> {};
/// Utility type to build an inheritance chain that makes it easy to rank
/// overload candidates.
template <int N> struct rank : rank<N - 1> {};
template <> struct rank<0> {};
/// \brief traits class for checking whether type T is one of any of the given
/// types in the variadic list.
template <typename T, typename... Ts> struct is_one_of {
static const bool value = false;
};
template <typename T, typename U, typename... Ts>
struct is_one_of<T, U, Ts...> {
static const bool value =
std::is_same<T, U>::value || is_one_of<T, Ts...>::value;
};
//===----------------------------------------------------------------------===//
// Extra additions for arrays
//===----------------------------------------------------------------------===//
/// Find the length of an array.
template <class T, std::size_t N>
LLVM_CONSTEXPR inline size_t array_lengthof(T (&)[N]) {
constexpr inline size_t array_lengthof(T (&)[N]) {
return N;
}
@ -445,8 +716,8 @@ inline void array_pod_sort(
/// container.
template<typename Container>
void DeleteContainerPointers(Container &C) {
for (typename Container::iterator I = C.begin(), E = C.end(); I != E; ++I)
delete *I;
for (auto V : C)
delete V;
C.clear();
}
@ -454,77 +725,106 @@ void DeleteContainerPointers(Container &C) {
/// deletes the second elements and then clears the container.
template<typename Container>
void DeleteContainerSeconds(Container &C) {
for (typename Container::iterator I = C.begin(), E = C.end(); I != E; ++I)
delete I->second;
for (auto &V : C)
delete V.second;
C.clear();
}
/// Provide wrappers to std::all_of which take ranges instead of having to pass
/// begin/end explicitly.
template<typename R, class UnaryPredicate>
bool all_of(R &&Range, UnaryPredicate &&P) {
return std::all_of(Range.begin(), Range.end(),
std::forward<UnaryPredicate>(P));
template <typename R, typename UnaryPredicate>
bool all_of(R &&Range, UnaryPredicate P) {
return std::all_of(std::begin(Range), std::end(Range), P);
}
/// Provide wrappers to std::any_of which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, class UnaryPredicate>
bool any_of(R &&Range, UnaryPredicate &&P) {
return std::any_of(Range.begin(), Range.end(),
std::forward<UnaryPredicate>(P));
template <typename R, typename UnaryPredicate>
bool any_of(R &&Range, UnaryPredicate P) {
return std::any_of(std::begin(Range), std::end(Range), P);
}
/// Provide wrappers to std::none_of which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, class UnaryPredicate>
bool none_of(R &&Range, UnaryPredicate &&P) {
return std::none_of(Range.begin(), Range.end(),
std::forward<UnaryPredicate>(P));
template <typename R, typename UnaryPredicate>
bool none_of(R &&Range, UnaryPredicate P) {
return std::none_of(std::begin(Range), std::end(Range), P);
}
/// Provide wrappers to std::find which take ranges instead of having to pass
/// begin/end explicitly.
template<typename R, class T>
auto find(R &&Range, const T &val) -> decltype(Range.begin()) {
return std::find(Range.begin(), Range.end(), val);
template <typename R, typename T>
auto find(R &&Range, const T &Val) -> decltype(std::begin(Range)) {
return std::find(std::begin(Range), std::end(Range), Val);
}
/// Provide wrappers to std::find_if which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, class T>
auto find_if(R &&Range, const T &Pred) -> decltype(Range.begin()) {
return std::find_if(Range.begin(), Range.end(), Pred);
template <typename R, typename UnaryPredicate>
auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
return std::find_if(std::begin(Range), std::end(Range), P);
}
template <typename R, typename UnaryPredicate>
auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
return std::find_if_not(std::begin(Range), std::end(Range), P);
}
/// Provide wrappers to std::remove_if which take ranges instead of having to
/// pass begin/end explicitly.
template<typename R, class UnaryPredicate>
auto remove_if(R &&Range, UnaryPredicate &&P) -> decltype(Range.begin()) {
return std::remove_if(Range.begin(), Range.end(), P);
template <typename R, typename UnaryPredicate>
auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
return std::remove_if(std::begin(Range), std::end(Range), P);
}
/// Wrapper function around std::find to detect if an element exists
/// in a container.
template <typename R, typename E>
bool is_contained(R &&Range, const E &Element) {
return std::find(Range.begin(), Range.end(), Element) != Range.end();
return std::find(std::begin(Range), std::end(Range), Element) !=
std::end(Range);
}
/// Wrapper function around std::count to count the number of times an element
/// \p Element occurs in the given range \p Range.
template <typename R, typename E>
auto count(R &&Range, const E &Element) -> typename std::iterator_traits<
decltype(std::begin(Range))>::difference_type {
return std::count(std::begin(Range), std::end(Range), Element);
}
/// Wrapper function around std::count_if to count the number of times an
/// element satisfying a given predicate occurs in a range.
template <typename R, typename UnaryPredicate>
auto count_if(R &&Range, UnaryPredicate &&P)
-> typename std::iterator_traits<decltype(Range.begin())>::difference_type {
return std::count_if(Range.begin(), Range.end(), P);
auto count_if(R &&Range, UnaryPredicate P) -> typename std::iterator_traits<
decltype(std::begin(Range))>::difference_type {
return std::count_if(std::begin(Range), std::end(Range), P);
}
/// Wrapper function around std::transform to apply a function to a range and
/// store the result elsewhere.
template <typename R, class OutputIt, typename UnaryPredicate>
OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate &&P) {
return std::transform(Range.begin(), Range.end(), d_first,
std::forward<UnaryPredicate>(P));
template <typename R, typename OutputIt, typename UnaryPredicate>
OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P) {
return std::transform(std::begin(Range), std::end(Range), d_first, P);
}
/// Provide wrappers to std::partition which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename UnaryPredicate>
auto partition(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
return std::partition(std::begin(Range), std::end(Range), P);
}
/// Provide a container algorithm similar to C++ Library Fundamentals v2's
/// `erase_if` which is equivalent to:
///
/// C.erase(remove_if(C, pred), C.end());
///
/// This version works for any container with an erase method call accepting
/// two iterators.
template <typename Container, typename UnaryPredicate>
void erase_if(Container &C, UnaryPredicate P) {
C.erase(remove_if(C, P), C.end());
}
//===----------------------------------------------------------------------===//
@ -608,6 +908,92 @@ 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) {}
const std::size_t Index;
X Value;
};
class iterator {
typedef
typename std::iterator_traits<IterOfRange<R>>::reference iter_reference;
typedef result_pair<iter_reference> result_type;
public:
iterator(IterOfRange<R> &&Iter, std::size_t Index)
: Iter(Iter), Index(Index) {}
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)); }
private:
R Range;
};
}
/// Given an input range, returns a new range whose values are are pair (A,B)
/// such that A is the 0-based index of the item in the sequence, and B is
/// the value from the original sequence. Example:
///
/// std::vector<char> Items = {'A', 'B', 'C', 'D'};
/// for (auto X : enumerate(Items)) {
/// printf("Item %d - %c\n", X.Index, X.Value);
/// }
///
/// Output:
/// Item 0 - A
/// Item 1 - B
/// Item 2 - C
/// Item 3 - D
///
template <typename R> detail::enumerator_impl<R> enumerate(R &&Range) {
return detail::enumerator_impl<R>(std::forward<R>(Range));
}
namespace detail {
template <typename F, typename Tuple, std::size_t... I>
auto apply_tuple_impl(F &&f, Tuple &&t, index_sequence<I...>)
-> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...)) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
}
/// Given an input tuple (a1, a2, ..., an), pass the arguments of the
/// tuple variadically to f as if by calling f(a1, a2, ..., an) and
/// return the result.
template <typename F, typename Tuple>
auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(
std::forward<F>(f), std::forward<Tuple>(t),
build_index_impl<
std::tuple_size<typename std::decay<Tuple>::type>::value>{})) {
using Indices = build_index_impl<
std::tuple_size<typename std::decay<Tuple>::type>::value>;
return detail::apply_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t),
Indices{});
}
} // End llvm namespace
#endif

View File

@ -0,0 +1,54 @@
//===- llvm/ADT/ScopeExit.h - Execute code at scope exit --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the make_scope_exit function, which executes user-defined
// cleanup logic at scope exit.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SCOPE_EXIT_H
#define LLVM_ADT_SCOPE_EXIT_H
#include "llvm/Support/Compiler.h"
#include <type_traits>
#include <utility>
namespace llvm {
namespace detail {
template <typename Callable> class scope_exit {
Callable ExitFunction;
public:
template <typename Fp>
explicit scope_exit(Fp &&F) : ExitFunction(std::forward<Fp>(F)) {}
scope_exit(scope_exit &&Rhs) : ExitFunction(std::move(Rhs.ExitFunction)) {}
~scope_exit() { ExitFunction(); }
};
} // end namespace detail
// Keeps the callable object that is passed in, and execute it at the
// destruction of the returned object (usually at the scope exit where the
// returned object is kept).
//
// Interface is specified by p0052r2.
template <typename Callable>
LLVM_NODISCARD detail::scope_exit<typename std::decay<Callable>::type>
make_scope_exit(Callable &&F) {
return detail::scope_exit<typename std::decay<Callable>::type>(
std::forward<Callable>(F));
}
} // end namespace llvm
#endif

View File

@ -32,7 +32,10 @@
#define LLVM_ADT_SCOPEDHASHTABLE_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/Allocator.h"
#include <cassert>
#include <new>
namespace llvm {
@ -46,6 +49,7 @@ class ScopedHashTableVal {
ScopedHashTableVal *NextForKey;
K Key;
V Val;
ScopedHashTableVal(const K &key, const V &val) : Key(key), Val(val) {}
public:
@ -89,11 +93,11 @@ class ScopedHashTableScope {
/// LastValInScope - This is the last value that was inserted for this scope
/// or null if none have been inserted yet.
ScopedHashTableVal<K, V> *LastValInScope;
void operator=(ScopedHashTableScope &) = delete;
ScopedHashTableScope(ScopedHashTableScope &) = delete;
public:
ScopedHashTableScope(ScopedHashTable<K, V, KInfo, AllocatorTy> &HT);
ScopedHashTableScope(ScopedHashTableScope &) = delete;
ScopedHashTableScope &operator=(ScopedHashTableScope &) = delete;
~ScopedHashTableScope();
ScopedHashTableScope *getParentScope() { return PrevScope; }
@ -101,6 +105,7 @@ class ScopedHashTableScope {
private:
friend class ScopedHashTable<K, V, KInfo, AllocatorTy>;
ScopedHashTableVal<K, V> *getLastValInScope() {
return LastValInScope;
}
@ -150,19 +155,20 @@ class ScopedHashTable {
typedef unsigned size_type;
private:
friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
typedef ScopedHashTableVal<K, V> ValTy;
DenseMap<K, ValTy*, KInfo> TopLevelMap;
ScopeTy *CurScope;
ScopeTy *CurScope = nullptr;
AllocatorTy Allocator;
ScopedHashTable(const ScopedHashTable &); // NOT YET IMPLEMENTED
void operator=(const ScopedHashTable &); // NOT YET IMPLEMENTED
friend class ScopedHashTableScope<K, V, KInfo, AllocatorTy>;
public:
ScopedHashTable() : CurScope(nullptr) {}
ScopedHashTable() = default;
ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {}
ScopedHashTable(const ScopedHashTable &) = delete;
ScopedHashTable &operator=(const ScopedHashTable &) = delete;
~ScopedHashTable() {
assert(!CurScope && TopLevelMap.empty() && "Scope imbalance!");
}
@ -253,4 +259,4 @@ ScopedHashTableScope<K, V, KInfo, Allocator>::~ScopedHashTableScope() {
} // end namespace llvm
#endif
#endif // LLVM_ADT_SCOPEDHASHTABLE_H

View File

@ -20,11 +20,13 @@
#ifndef LLVM_ADT_SETVECTOR_H
#define LLVM_ADT_SETVECTOR_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <cassert>
#include <utility>
#include <iterator>
#include <vector>
namespace llvm {
@ -51,7 +53,7 @@ class SetVector {
typedef typename vector_type::size_type size_type;
/// \brief Construct an empty SetVector
SetVector() {}
SetVector() = default;
/// \brief Initialize a SetVector with a range of elements
template<typename It>
@ -61,6 +63,12 @@ class SetVector {
ArrayRef<T> getArrayRef() const { return vector_; }
/// Clear the SetVector and return the underlying vector.
Vector takeVector() {
set_.clear();
return std::move(vector_);
}
/// \brief Determine if the SetVector is empty or not.
bool empty() const {
return vector_.empty();
@ -143,8 +151,7 @@ class SetVector {
/// \brief Remove an item from the set vector.
bool remove(const value_type& X) {
if (set_.erase(X)) {
typename vector_type::iterator I =
std::find(vector_.begin(), vector_.end(), X);
typename vector_type::iterator I = find(vector_, X);
assert(I != vector_.end() && "Corrupted SetVector instances!");
vector_.erase(I);
return true;
@ -176,7 +183,7 @@ class SetVector {
/// write it:
///
/// \code
/// V.erase(std::remove_if(V.begin(), V.end(), P), V.end());
/// V.erase(remove_if(V, P), V.end());
/// \endcode
///
/// However, SetVector doesn't expose non-const iterators, making any
@ -185,9 +192,8 @@ class SetVector {
/// \returns true if any element is removed.
template <typename UnaryPredicate>
bool remove_if(UnaryPredicate P) {
typename vector_type::iterator I
= std::remove_if(vector_.begin(), vector_.end(),
TestAndEraseFromSet<UnaryPredicate>(P, set_));
typename vector_type::iterator I =
llvm::remove_if(vector_, TestAndEraseFromSet<UnaryPredicate>(P, set_));
if (I == vector_.end())
return false;
vector_.erase(I, vector_.end());
@ -213,7 +219,7 @@ class SetVector {
vector_.pop_back();
}
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
LLVM_NODISCARD T pop_back_val() {
T Ret = back();
pop_back();
return Ret;
@ -283,9 +289,10 @@ class SetVector {
/// \brief A SetVector that performs no allocations if smaller than
/// a certain size.
template <typename T, unsigned N>
class SmallSetVector : public SetVector<T, SmallVector<T, N>, SmallSet<T, N> > {
class SmallSetVector
: public SetVector<T, SmallVector<T, N>, SmallDenseSet<T, N>> {
public:
SmallSetVector() {}
SmallSetVector() = default;
/// \brief Initialize a SmallSetVector with a range of elements
template<typename It>
@ -294,7 +301,6 @@ class SmallSetVector : public SetVector<T, SmallVector<T, N>, SmallSet<T, N> > {
}
};
} // End llvm namespace
} // end namespace llvm
// vim: sw=2 ai
#endif
#endif // LLVM_ADT_SETVECTOR_H

View File

@ -15,19 +15,25 @@
#ifndef LLVM_ADT_SMALLPTRSET_H
#define LLVM_ADT_SMALLPTRSET_H
#include "llvm/Config/abi-breaking.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <cstddef>
#include <cstring>
#include <cstdlib>
#include <initializer_list>
#include <iterator>
#include <utility>
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
namespace llvm {
template <class T = void> struct ReverseIterate { static bool value; };
template <class T> bool ReverseIterate<T>::value = false;
}
#endif
class SmallPtrSetIteratorImpl;
namespace llvm {
/// SmallPtrSetImplBase - This is the common code shared among all the
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
@ -71,12 +77,14 @@ class SmallPtrSetImplBase {
const SmallPtrSetImplBase &that);
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
SmallPtrSetImplBase &&that);
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
: SmallArray(SmallStorage), CurArray(SmallStorage),
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
"Initial size must be a power of two!");
}
~SmallPtrSetImplBase() {
if (!isSmall())
free(CurArray);
@ -84,7 +92,10 @@ class SmallPtrSetImplBase {
public:
typedef unsigned size_type;
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
LLVM_NODISCARD bool empty() const { return size() == 0; }
size_type size() const { return NumNonEmpty - NumTombstones; }
void clear() {
@ -103,6 +114,7 @@ class SmallPtrSetImplBase {
protected:
static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
static void *getEmptyMarker() {
// Note that -1 is chosen to make clear() efficiently implementable with
// memset and because it's not a valid pointer value.
@ -150,22 +162,38 @@ class SmallPtrSetImplBase {
/// return true, otherwise return false. This is hidden from the client so
/// that the derived class can check that the right type of pointer is passed
/// in.
bool erase_imp(const void * Ptr);
bool erase_imp(const void * Ptr) {
const void *const *P = find_imp(Ptr);
if (P == EndPointer())
return false;
const void ** Loc = const_cast<const void **>(P);
assert(*Loc == Ptr && "broken find!");
*Loc = getTombstoneMarker();
NumTombstones++;
return true;
}
bool count_imp(const void * Ptr) const {
/// Returns the raw pointer needed to construct an iterator. If element not
/// found, this will be EndPointer. Otherwise, it will be a pointer to the
/// slot which stores Ptr;
const void *const * find_imp(const void * Ptr) const {
if (isSmall()) {
// Linear search for the item.
for (const void *const *APtr = SmallArray,
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
if (*APtr == Ptr)
return true;
return false;
return APtr;
return EndPointer();
}
// Big set case.
return *FindBucketFor(Ptr) == Ptr;
auto *Bucket = FindBucketFor(Ptr);
if (*Bucket == Ptr)
return Bucket;
return EndPointer();
}
private:
bool isSmall() const { return CurArray == SmallArray; }
@ -177,8 +205,6 @@ class SmallPtrSetImplBase {
/// Grow - Allocate a larger backing store for the buckets and move it over.
void Grow(unsigned NewSize);
void operator=(const SmallPtrSetImplBase &RHS) = delete;
protected:
/// swap - Swaps the elements of two sets.
/// Note: This method assumes that both sets have the same small size.
@ -204,6 +230,12 @@ class SmallPtrSetIteratorImpl {
public:
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
: Bucket(BP), End(E) {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
if (ReverseIterate<bool>::value) {
RetreatIfNotValid();
return;
}
#endif
AdvanceIfNotValid();
}
@ -225,6 +257,17 @@ class SmallPtrSetIteratorImpl {
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
++Bucket;
}
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
void RetreatIfNotValid() {
--Bucket;
assert(Bucket <= End);
while (Bucket != End &&
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker())) {
--Bucket;
}
}
#endif
};
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
@ -250,13 +293,21 @@ class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
}
inline SmallPtrSetIterator& operator++() { // Preincrement
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
if (ReverseIterate<bool>::value) {
RetreatIfNotValid();
return *this;
}
#endif
++Bucket;
AdvanceIfNotValid();
return *this;
}
SmallPtrSetIterator operator++(int) { // Postincrement
SmallPtrSetIterator tmp = *this; ++*this; return tmp;
SmallPtrSetIterator tmp = *this;
++*this;
return tmp;
}
};
@ -294,8 +345,6 @@ template <typename PtrType>
class SmallPtrSetImpl : public SmallPtrSetImplBase {
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
protected:
// Constructors that forward to the base.
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
@ -310,6 +359,8 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
typedef SmallPtrSetIterator<PtrType> iterator;
typedef SmallPtrSetIterator<PtrType> const_iterator;
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
/// Inserts Ptr if and only if there is no element in the container equal to
/// Ptr. The bool component of the returned pair is true if and only if the
/// insertion takes place, and the iterator component of the pair points to
@ -327,7 +378,11 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
size_type count(PtrType Ptr) const {
return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0;
return find(Ptr) != endPtr() ? 1 : 0;
}
iterator find(PtrType Ptr) const {
auto *P = find_imp(PtrTraits::getAsVoidPointer(Ptr));
return iterator(P, EndPointer());
}
template <typename IterT>
@ -336,10 +391,27 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
insert(*I);
}
void insert(std::initializer_list<PtrType> IL) {
insert(IL.begin(), IL.end());
}
inline iterator begin() const {
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
if (ReverseIterate<bool>::value)
return endPtr();
#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();
}
private:
inline iterator endPtr() const {
const void *const *End = EndPointer();
return iterator(End, End);
}
@ -374,6 +446,11 @@ class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
this->insert(I, E);
}
SmallPtrSet(std::initializer_list<PtrType> IL)
: BaseT(SmallStorage, SmallSizePowTwo) {
this->insert(IL.begin(), IL.end());
}
SmallPtrSet<PtrType, SmallSize> &
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
if (&RHS != this)
@ -381,26 +458,36 @@ class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
return *this;
}
SmallPtrSet<PtrType, SmallSize>&
SmallPtrSet<PtrType, SmallSize> &
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
if (&RHS != this)
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
return *this;
}
SmallPtrSet<PtrType, SmallSize> &
operator=(std::initializer_list<PtrType> IL) {
this->clear();
this->insert(IL.begin(), IL.end());
return *this;
}
/// swap - Swaps the elements of two sets.
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
SmallPtrSetImplBase::swap(RHS);
}
};
}
} // end namespace llvm
namespace std {
/// Implement std::swap in terms of SmallPtrSet swap.
template<class T, unsigned N>
inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
LHS.swap(RHS);
}
}
#endif
} // end namespace std
#endif // LLVM_ADT_SMALLPTRSET_H

View File

@ -17,7 +17,11 @@
#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include <cstddef>
#include <functional>
#include <set>
#include <utility>
namespace llvm {
@ -28,7 +32,7 @@ namespace llvm {
///
/// Note that this set does not provide a way to iterate over members in the
/// set.
template <typename T, unsigned N, typename C = std::less<T> >
template <typename T, unsigned N, typename C = std::less<T>>
class SmallSet {
/// Use a SmallVector to hold the elements here (even though it will never
/// reach its 'large' stage) to avoid calling the default ctors of elements
@ -45,9 +49,10 @@ class SmallSet {
public:
typedef size_t size_type;
SmallSet() {}
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
SmallSet() = default;
LLVM_NODISCARD bool empty() const {
return Vector.empty() && Set.empty();
}
@ -133,4 +138,4 @@ class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
} // end namespace llvm
#endif
#endif // LLVM_ADT_SMALLSET_H

View File

@ -16,6 +16,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <cstddef>
namespace llvm {
@ -25,7 +26,7 @@ template<unsigned InternalLen>
class SmallString : public SmallVector<char, InternalLen> {
public:
/// Default ctor - Initialize to empty.
SmallString() {}
SmallString() = default;
/// Initialize from a StringRef.
SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
@ -79,7 +80,6 @@ class SmallString : public SmallVector<char, InternalLen> {
SmallVectorImpl<char>::append(NumInputs, Elt);
}
/// Append from a StringRef.
void append(StringRef RHS) {
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
@ -292,6 +292,6 @@ class SmallString : public SmallVector<char, InternalLen> {
}
};
}
} // end namespace llvm
#endif
#endif // LLVM_ADT_SMALLSTRING_H

View File

@ -27,6 +27,9 @@
#include <initializer_list>
#include <iterator>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
namespace llvm {
@ -54,11 +57,9 @@ class SmallVectorBase {
return size_t((char*)CapacityX - (char*)BeginX);
}
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return BeginX == EndX; }
LLVM_NODISCARD bool empty() const { return BeginX == EndX; }
};
template <typename T, unsigned N> struct SmallVectorStorage;
/// This is the part of SmallVectorTemplateBase which does not depend on whether
/// the type T is a POD. The extra dummy template argument is used by ArrayRef
/// to avoid unnecessarily requiring T to be complete.
@ -70,7 +71,7 @@ class SmallVectorTemplateCommon : public SmallVectorBase {
// Allocate raw space for N elements of type T. If T has a ctor or dtor, we
// don't want it to be automatically run, so we need to represent the space as
// something else. Use an array of char of sufficient alignment.
typedef llvm::AlignedCharArrayUnion<T> U;
typedef AlignedCharArrayUnion<T> U;
U FirstEl;
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
@ -93,6 +94,7 @@ class SmallVectorTemplateCommon : public SmallVectorBase {
}
void setEnd(T *P) { this->EndX = P; }
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
@ -117,11 +119,12 @@ class SmallVectorTemplateCommon : public SmallVectorBase {
iterator end() { return (iterator)this->EndX; }
LLVM_ATTRIBUTE_ALWAYS_INLINE
const_iterator end() const { return (const_iterator)this->EndX; }
protected:
iterator capacity_ptr() { return (iterator)this->CapacityX; }
const_iterator capacity_ptr() const { return (const_iterator)this->CapacityX;}
public:
public:
// reverse iterator creation methods.
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
@ -298,6 +301,7 @@ class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
void grow(size_t MinSize = 0) {
this->grow_pod(MinSize*sizeof(T), sizeof(T));
}
public:
void push_back(const T &Elt) {
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
@ -311,14 +315,12 @@ class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
}
};
/// This class consists of common code factored out of the SmallVector class to
/// reduce code duplication based on the SmallVector 'N' template parameter.
template <typename T>
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
SmallVectorImpl(const SmallVectorImpl&) = delete;
public:
typedef typename SuperClass::iterator iterator;
typedef typename SuperClass::const_iterator const_iterator;
@ -331,6 +333,8 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
}
public:
SmallVectorImpl(const SmallVectorImpl &) = delete;
~SmallVectorImpl() {
// Destroy the constructed elements in the vector.
this->destroy_range(this->begin(), this->end());
@ -340,7 +344,6 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
free(this->begin());
}
void clear() {
this->destroy_range(this->begin(), this->end());
this->EndX = this->BeginX;
@ -376,7 +379,7 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
this->grow(N);
}
T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
LLVM_NODISCARD T pop_back_val() {
T Result = ::std::move(this->back());
this->pop_back();
return Result;
@ -668,7 +671,6 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
}
};
template <typename T>
void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
if (this == &RHS) return;
@ -841,6 +843,7 @@ template <typename T, unsigned N>
class SmallVector : public SmallVectorImpl<T> {
/// Inline space for elements which aren't stored in the base class.
SmallVectorStorage<T, N> Storage;
public:
SmallVector() : SmallVectorImpl<T>(N) {
}
@ -856,7 +859,7 @@ class SmallVector : public SmallVectorImpl<T> {
}
template <typename RangeTy>
explicit SmallVector(const llvm::iterator_range<RangeTy> R)
explicit SmallVector(const iterator_range<RangeTy> &R)
: SmallVectorImpl<T>(N) {
this->append(R.begin(), R.end());
}
@ -906,9 +909,10 @@ static inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
return X.capacity_in_bytes();
}
} // End llvm namespace
} // end namespace llvm
namespace std {
/// Implement std::swap in terms of SmallVector swap.
template<typename T>
inline void
@ -922,6 +926,7 @@ namespace std {
swap(llvm::SmallVector<T, N> &LHS, llvm::SmallVector<T, N> &RHS) {
LHS.swap(RHS);
}
}
#endif
} // end namespace std
#endif // LLVM_ADT_SMALLVECTOR_H

View File

@ -15,14 +15,14 @@
#ifndef LLVM_ADT_SPARSEBITVECTOR_H
#define LLVM_ADT_SPARSEBITVECTOR_H
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <climits>
#include <cstring>
#include <iterator>
#include <list>
namespace llvm {
@ -39,9 +39,7 @@ namespace llvm {
/// etc) do not perform as well in practice as a linked list with this iterator
/// kept up to date. They are also significantly more memory intensive.
template <unsigned ElementSize = 128>
struct SparseBitVectorElement
: public ilist_node<SparseBitVectorElement<ElementSize> > {
template <unsigned ElementSize = 128> struct SparseBitVectorElement {
public:
typedef unsigned long BitWord;
typedef unsigned size_type;
@ -55,8 +53,7 @@ struct SparseBitVectorElement
// Index of Element in terms of where first bit starts.
unsigned ElementIndex;
BitWord Bits[BITWORDS_PER_ELEMENT];
// Needed for sentinels
friend struct ilist_sentinel_traits<SparseBitVectorElement>;
SparseBitVectorElement() {
ElementIndex = ~0U;
memset(&Bits[0], 0, sizeof (BitWord) * BITWORDS_PER_ELEMENT);
@ -84,7 +81,7 @@ struct SparseBitVectorElement
// Return the bits that make up word Idx in our element.
BitWord word(unsigned Idx) const {
assert (Idx < BITWORDS_PER_ELEMENT);
assert(Idx < BITWORDS_PER_ELEMENT);
return Bits[Idx];
}
@ -144,8 +141,8 @@ struct SparseBitVectorElement
unsigned WordPos = Curr / BITWORD_SIZE;
unsigned BitPos = Curr % BITWORD_SIZE;
BitWord Copy = Bits[WordPos];
assert (WordPos <= BITWORDS_PER_ELEMENT
&& "Word Position outside of element");
assert(WordPos <= BITWORDS_PER_ELEMENT
&& "Word Position outside of element");
// Mask off previous bits.
Copy &= ~0UL << BitPos;
@ -244,25 +241,9 @@ struct SparseBitVectorElement
}
};
template <unsigned ElementSize>
struct ilist_traits<SparseBitVectorElement<ElementSize> >
: public ilist_default_traits<SparseBitVectorElement<ElementSize> > {
typedef SparseBitVectorElement<ElementSize> Element;
Element *createSentinel() const { return static_cast<Element *>(&Sentinel); }
static void destroySentinel(Element *) {}
Element *provideInitialHead() const { return createSentinel(); }
Element *ensureHead(Element *) const { return createSentinel(); }
static void noteHead(Element *, Element *) {}
private:
mutable ilist_half_node<Element> Sentinel;
};
template <unsigned ElementSize = 128>
class SparseBitVector {
typedef ilist<SparseBitVectorElement<ElementSize> > ElementList;
typedef std::list<SparseBitVectorElement<ElementSize>> ElementList;
typedef typename ElementList::iterator ElementListIter;
typedef typename ElementList::const_iterator ElementListConstIter;
enum {
@ -310,7 +291,7 @@ class SparseBitVector {
private:
bool AtEnd;
const SparseBitVector<ElementSize> *BitVector;
const SparseBitVector<ElementSize> *BitVector = nullptr;
// Current element inside of bitmap.
ElementListConstIter Iter;
@ -380,7 +361,20 @@ class SparseBitVector {
}
}
}
public:
SparseBitVectorIterator() = default;
SparseBitVectorIterator(const SparseBitVector<ElementSize> *RHS,
bool end = false):BitVector(RHS) {
Iter = BitVector->Elements.begin();
BitNumber = 0;
Bits = 0;
WordNumber = ~0;
AtEnd = end;
AdvanceToFirstNonZero();
}
// Preincrement.
inline SparseBitVectorIterator& operator++() {
++BitNumber;
@ -413,29 +407,16 @@ class SparseBitVector {
bool operator!=(const SparseBitVectorIterator &RHS) const {
return !(*this == RHS);
}
SparseBitVectorIterator(): BitVector(nullptr) {
}
SparseBitVectorIterator(const SparseBitVector<ElementSize> *RHS,
bool end = false):BitVector(RHS) {
Iter = BitVector->Elements.begin();
BitNumber = 0;
Bits = 0;
WordNumber = ~0;
AtEnd = end;
AdvanceToFirstNonZero();
}
};
public:
typedef SparseBitVectorIterator iterator;
SparseBitVector () {
CurrElementIter = Elements.begin ();
SparseBitVector() {
CurrElementIter = Elements.begin();
}
~SparseBitVector() {
}
~SparseBitVector() = default;
// SparseBitVector copy ctor.
SparseBitVector(const SparseBitVector &RHS) {
@ -510,26 +491,21 @@ class SparseBitVector {
void set(unsigned Idx) {
unsigned ElementIndex = Idx / ElementSize;
SparseBitVectorElement<ElementSize> *Element;
ElementListIter ElementIter;
if (Elements.empty()) {
Element = new SparseBitVectorElement<ElementSize>(ElementIndex);
ElementIter = Elements.insert(Elements.end(), Element);
ElementIter = Elements.emplace(Elements.end(), ElementIndex);
} else {
ElementIter = FindLowerBound(ElementIndex);
if (ElementIter == Elements.end() ||
ElementIter->index() != ElementIndex) {
Element = new SparseBitVectorElement<ElementSize>(ElementIndex);
// We may have hit the beginning of our SparseBitVector, in which case,
// we may need to insert right after this element, which requires moving
// the current iterator forward one, because insert does insert before.
if (ElementIter != Elements.end() &&
ElementIter->index() < ElementIndex)
ElementIter = Elements.insert(++ElementIter, Element);
else
ElementIter = Elements.insert(ElementIter, Element);
++ElementIter;
ElementIter = Elements.emplace(ElementIter, ElementIndex);
}
}
CurrElementIter = ElementIter;
@ -537,7 +513,7 @@ class SparseBitVector {
ElementIter->set(Idx % ElementSize);
}
bool test_and_set (unsigned Idx) {
bool test_and_set(unsigned Idx) {
bool old = test(Idx);
if (!old) {
set(Idx);
@ -577,8 +553,7 @@ class SparseBitVector {
while (Iter2 != RHS.Elements.end()) {
if (Iter1 == Elements.end() || Iter1->index() > Iter2->index()) {
Elements.insert(Iter1,
new SparseBitVectorElement<ElementSize>(*Iter2));
Elements.insert(Iter1, *Iter2);
++Iter2;
changed = true;
} else if (Iter1->index() == Iter2->index()) {
@ -725,31 +700,19 @@ class SparseBitVector {
++Iter2;
} else if (Iter1->index() == Iter2->index()) {
bool BecameZero = false;
SparseBitVectorElement<ElementSize> *NewElement =
new SparseBitVectorElement<ElementSize>(Iter1->index());
NewElement->intersectWithComplement(*Iter1, *Iter2, BecameZero);
if (!BecameZero) {
Elements.push_back(NewElement);
}
else
delete NewElement;
Elements.emplace_back(Iter1->index());
Elements.back().intersectWithComplement(*Iter1, *Iter2, BecameZero);
if (BecameZero)
Elements.pop_back();
++Iter1;
++Iter2;
} else {
SparseBitVectorElement<ElementSize> *NewElement =
new SparseBitVectorElement<ElementSize>(*Iter1);
Elements.push_back(NewElement);
++Iter1;
Elements.push_back(*Iter1++);
}
}
// copy the remaining elements
while (Iter1 != RHS1.Elements.end()) {
SparseBitVectorElement<ElementSize> *NewElement =
new SparseBitVectorElement<ElementSize>(*Iter1);
Elements.push_back(NewElement);
++Iter1;
}
std::copy(Iter1, RHS1.Elements.end(), std::back_inserter(Elements));
}
void intersectWithComplement(const SparseBitVector<ElementSize> *RHS1,
@ -819,6 +782,7 @@ class SparseBitVector {
return BitCount;
}
iterator begin() const {
return iterator(this);
}
@ -899,6 +863,7 @@ void dump(const SparseBitVector<ElementSize> &LHS, raw_ostream &out) {
}
out << "]\n";
}
} // end namespace llvm
#endif // LLVM_ADT_SPARSEBITVECTOR_H

View File

@ -21,7 +21,15 @@
#ifndef LLVM_ADT_SPARSEMULTISET_H
#define LLVM_ADT_SPARSEMULTISET_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseSet.h"
#include "llvm/ADT/STLExtras.h"
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <limits>
#include <utility>
namespace llvm {
@ -73,7 +81,7 @@ namespace llvm {
/// @tparam SparseT An unsigned integer type. See above.
///
template<typename ValueT,
typename KeyFunctorT = llvm::identity<unsigned>,
typename KeyFunctorT = identity<unsigned>,
typename SparseT = uint8_t>
class SparseMultiSet {
static_assert(std::numeric_limits<SparseT>::is_integer &&
@ -113,16 +121,16 @@ class SparseMultiSet {
typedef typename KeyFunctorT::argument_type KeyT;
typedef SmallVector<SMSNode, 8> DenseT;
DenseT Dense;
SparseT *Sparse;
unsigned Universe;
SparseT *Sparse = nullptr;
unsigned Universe = 0;
KeyFunctorT KeyIndexOf;
SparseSetValFunctor<KeyT, ValueT, KeyFunctorT> ValIndexOf;
/// We have a built-in recycler for reusing tombstone slots. This recycler
/// puts a singly-linked free list into tombstone slots, allowing us quick
/// erasure, iterator preservation, and dense size.
unsigned FreelistIdx;
unsigned NumFree;
unsigned FreelistIdx = SMSNode::INVALID;
unsigned NumFree = 0;
unsigned sparseIndex(const ValueT &Val) const {
assert(ValIndexOf(Val) < Universe &&
@ -131,11 +139,6 @@ class SparseMultiSet {
}
unsigned sparseIndex(const SMSNode &N) const { return sparseIndex(N.Data); }
// Disable copy construction and assignment.
// This data structure is not meant to be used that way.
SparseMultiSet(const SparseMultiSet&) = delete;
SparseMultiSet &operator=(const SparseMultiSet&) = delete;
/// Whether the given entry is the head of the list. List heads's previous
/// pointers are to the tail of the list, allowing for efficient access to the
/// list tail. D must be a valid entry node.
@ -187,9 +190,9 @@ class SparseMultiSet {
typedef const ValueT *const_pointer;
typedef unsigned size_type;
SparseMultiSet()
: Sparse(nullptr), Universe(0), FreelistIdx(SMSNode::INVALID), NumFree(0) {}
SparseMultiSet() = default;
SparseMultiSet(const SparseMultiSet &) = delete;
SparseMultiSet &operator=(const SparseMultiSet &) = delete;
~SparseMultiSet() { free(Sparse); }
/// Set the universe size which determines the largest key the set can hold.
@ -218,6 +221,7 @@ class SparseMultiSet {
class iterator_base : public std::iterator<std::bidirectional_iterator_tag,
ValueT> {
friend class SparseMultiSet;
SMSPtrTy SMS;
unsigned Idx;
unsigned SparseIdx;
@ -515,4 +519,4 @@ class SparseMultiSet {
} // end namespace llvm
#endif
#endif // LLVM_ADT_SPARSEMULTISET_H

View File

@ -22,8 +22,11 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <utility>
namespace llvm {
@ -115,7 +118,7 @@ struct SparseSetValFunctor<KeyT, KeyT, KeyFunctorT> {
/// @tparam SparseT An unsigned integer type. See above.
///
template<typename ValueT,
typename KeyFunctorT = llvm::identity<unsigned>,
typename KeyFunctorT = identity<unsigned>,
typename SparseT = uint8_t>
class SparseSet {
static_assert(std::numeric_limits<SparseT>::is_integer &&
@ -126,16 +129,11 @@ class SparseSet {
typedef SmallVector<ValueT, 8> DenseT;
typedef unsigned size_type;
DenseT Dense;
SparseT *Sparse;
unsigned Universe;
SparseT *Sparse = nullptr;
unsigned Universe = 0;
KeyFunctorT KeyIndexOf;
SparseSetValFunctor<KeyT, ValueT, KeyFunctorT> ValIndexOf;
// Disable copy construction and assignment.
// This data structure is not meant to be used that way.
SparseSet(const SparseSet&) = delete;
SparseSet &operator=(const SparseSet&) = delete;
public:
typedef ValueT value_type;
typedef ValueT &reference;
@ -143,7 +141,9 @@ class SparseSet {
typedef ValueT *pointer;
typedef const ValueT *const_pointer;
SparseSet() : Sparse(nullptr), Universe(0) {}
SparseSet() = default;
SparseSet(const SparseSet &) = delete;
SparseSet &operator=(const SparseSet &) = delete;
~SparseSet() { free(Sparse); }
/// setUniverse - Set the universe size which determines the largest key the
@ -308,9 +308,8 @@ class SparseSet {
erase(I);
return true;
}
};
} // end namespace llvm
#endif
#endif // LLVM_ADT_SPARSESET_H

View File

@ -32,6 +32,7 @@
#include <memory>
namespace llvm {
class raw_ostream;
class raw_fd_ostream;
@ -140,16 +141,17 @@ class Statistic {
TsanHappensAfter(this);
return *this;
}
void RegisterStatistic();
};
// STATISTIC - A macro to make definition of statistics really simple. This
// automatically passes the DEBUG_TYPE of the file into the statistic.
#define STATISTIC(VARNAME, DESC) \
static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, 0}
static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, false}
/// \brief Enable the collection and printing of statistics.
void EnableStatistics();
void EnableStatistics(bool PrintOnExit = true);
/// \brief Check if statistics are enabled.
bool AreStatisticsEnabled();
@ -163,9 +165,12 @@ void PrintStatistics();
/// \brief Print statistics to the given output stream.
void PrintStatistics(raw_ostream &OS);
/// Print statistics in JSON format.
/// Print statistics in JSON format. This does include all global timers (\see
/// Timer, TimerGroup). Note that the timers are cleared after printing and will
/// not be printed in human readable form or in a second call of
/// PrintStatisticsJSON().
void PrintStatisticsJSON(raw_ostream &OS);
} // end llvm namespace
} // end namespace llvm
#endif // LLVM_ADT_STATISTIC_H

View File

@ -19,6 +19,7 @@
#include <iterator>
namespace llvm {
class raw_ostream;
template<typename T> class SmallVectorImpl;
/// hexdigit - Return the hexadecimal character for the
@ -150,6 +151,12 @@ static inline StringRef getOrdinalSuffix(unsigned Val) {
}
}
/// PrintEscapedString - Print each character of the specified string, escaping
/// it if it is not printable or if it is an escape char.
void PrintEscapedString(StringRef Name, raw_ostream &Out);
namespace detail {
template <typename IteratorT>
inline std::string join_impl(IteratorT Begin, IteratorT End,
StringRef Separator, std::input_iterator_tag) {
@ -184,12 +191,64 @@ inline std::string join_impl(IteratorT Begin, IteratorT End,
return S;
}
template <typename Sep>
inline void join_items_impl(std::string &Result, Sep Separator) {}
template <typename Sep, typename Arg>
inline void join_items_impl(std::string &Result, Sep Separator,
const Arg &Item) {
Result += Item;
}
template <typename Sep, typename Arg1, typename... Args>
inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
Args &&... Items) {
Result += A1;
Result += Separator;
join_items_impl(Result, Separator, std::forward<Args>(Items)...);
}
inline size_t join_one_item_size(char C) { return 1; }
inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
template <typename T> inline size_t join_one_item_size(const T &Str) {
return Str.size();
}
inline size_t join_items_size() { return 0; }
template <typename A1> inline size_t join_items_size(const A1 &A) {
return join_one_item_size(A);
}
template <typename A1, typename... Args>
inline size_t join_items_size(const A1 &A, Args &&... Items) {
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
}
}
/// Joins the strings in the range [Begin, End), adding Separator between
/// the elements.
template <typename IteratorT>
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
typedef typename std::iterator_traits<IteratorT>::iterator_category tag;
return join_impl(Begin, End, Separator, tag());
return detail::join_impl(Begin, End, Separator, tag());
}
/// Joins the strings in the parameter pack \p Items, adding \p Separator
/// between the elements. All arguments must be implicitly convertible to
/// std::string, or there should be an overload of std::string::operator+=()
/// that accepts the argument explicitly.
template <typename Sep, typename... Args>
inline std::string join_items(Sep Separator, Args &&... Items) {
std::string Result;
if (sizeof...(Items) == 0)
return Result;
size_t NS = detail::join_one_item_size(Separator);
size_t NI = detail::join_items_size(std::forward<Args>(Items)...);
Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1);
detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...);
return Result;
}
} // End llvm namespace

View File

@ -17,10 +17,17 @@
#include "llvm/ADT/StringRef.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>
namespace llvm {
template<typename ValueT>
class StringMapConstIterator;
template<typename ValueT>
@ -119,8 +126,6 @@ class StringMapImpl {
/// and data.
template<typename ValueTy>
class StringMapEntry : public StringMapEntryBase {
StringMapEntry(StringMapEntry &E) = delete;
public:
ValueTy second;
@ -129,6 +134,7 @@ class StringMapEntry : public StringMapEntryBase {
template <typename... InitTy>
StringMapEntry(unsigned strLen, InitTy &&... InitVals)
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
StringMapEntry(StringMapEntry &E) = delete;
StringRef getKey() const {
return StringRef(getKeyData(), getKeyLength());
@ -157,7 +163,7 @@ class StringMapEntry : public StringMapEntryBase {
// terminator.
unsigned AllocSize = static_cast<unsigned>(sizeof(StringMapEntry))+
KeyLength+1;
unsigned Alignment = alignOf<StringMapEntry>();
unsigned Alignment = alignof(StringMapEntry);
StringMapEntry *NewItem =
static_cast<StringMapEntry*>(Allocator.Allocate(AllocSize,Alignment));
@ -329,9 +335,7 @@ class StringMap : public StringMapImpl {
/// Lookup the ValueTy for the \p Key, or create a default constructed value
/// if the key is not in the map.
ValueTy &operator[](StringRef Key) {
return emplace_second(Key).first->second;
}
ValueTy &operator[](StringRef Key) { return try_emplace(Key).first->second; }
/// count - Return 1 if the element is in the map, 0 otherwise.
size_type count(StringRef Key) const {
@ -362,7 +366,7 @@ class StringMap : public StringMapImpl {
/// if and only if the insertion takes place, and the iterator component of
/// the pair points to the element with key equivalent to the key of the pair.
std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {
return emplace_second(KV.first, std::move(KV.second));
return try_emplace(KV.first, std::move(KV.second));
}
/// Emplace a new element for the specified key into the map if the key isn't
@ -370,7 +374,7 @@ class StringMap : public StringMapImpl {
/// if and only if the insertion takes place, and the iterator component of
/// the pair points to the element with key equivalent to the key of the pair.
template <typename... ArgsTy>
std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {
std::pair<iterator, bool> try_emplace(StringRef Key, ArgsTy &&... Args) {
unsigned BucketNo = LookupBucketFor(Key);
StringMapEntryBase *&Bucket = TheTable[BucketNo];
if (Bucket && Bucket != getTombstoneVal())
@ -442,12 +446,12 @@ class StringMap : public StringMapImpl {
template <typename ValueTy> class StringMapConstIterator {
protected:
StringMapEntryBase **Ptr;
StringMapEntryBase **Ptr = nullptr;
public:
typedef StringMapEntry<ValueTy> value_type;
StringMapConstIterator() : Ptr(nullptr) { }
StringMapConstIterator() = default;
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
@ -488,11 +492,13 @@ template <typename ValueTy> class StringMapConstIterator {
template<typename ValueTy>
class StringMapIterator : public StringMapConstIterator<ValueTy> {
public:
StringMapIterator() {}
StringMapIterator() = default;
explicit StringMapIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: StringMapConstIterator<ValueTy>(Bucket, NoAdvance) {
}
StringMapEntry<ValueTy> &operator*() const {
return *static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
}
@ -500,6 +506,7 @@ class StringMapIterator : public StringMapConstIterator<ValueTy> {
return static_cast<StringMapEntry<ValueTy>*>(*this->Ptr);
}
};
}
#endif
} // end namespace llvm
#endif // LLVM_ADT_STRINGMAP_H

View File

@ -10,6 +10,7 @@
#ifndef LLVM_ADT_STRINGREF_H
#define LLVM_ADT_STRINGREF_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
@ -32,6 +33,10 @@ namespace llvm {
bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result);
bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
unsigned long long &Result);
bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result);
/// StringRef - Represent a constant reference to a string, i.e. a character
/// array and a length, which need not be null terminated.
///
@ -48,10 +53,10 @@ namespace llvm {
private:
/// The start of the string, in an external buffer.
const char *Data;
const char *Data = nullptr;
/// The length of the string.
size_t Length;
size_t Length = 0;
// Workaround memcmp issue with null pointers (undefined behavior)
// by providing a specialized version
@ -66,28 +71,31 @@ namespace llvm {
/// @{
/// Construct an empty string ref.
/*implicit*/ StringRef() : Data(nullptr), Length(0) {}
/*implicit*/ StringRef() = default;
/// Disable conversion from nullptr. This prevents things like
/// if (S == nullptr)
StringRef(std::nullptr_t) = delete;
/// Construct a string ref from a cstring.
LLVM_ATTRIBUTE_ALWAYS_INLINE
/*implicit*/ StringRef(const char *Str)
: Data(Str) {
assert(Str && "StringRef cannot be built from a NULL argument");
Length = ::strlen(Str); // invoking strlen(NULL) is undefined behavior
}
: Data(Str), Length(Str ? ::strlen(Str) : 0) {}
/// Construct a string ref from a pointer and length.
LLVM_ATTRIBUTE_ALWAYS_INLINE
/*implicit*/ StringRef(const char *data, size_t length)
: Data(data), Length(length) {
assert((data || length == 0) &&
"StringRef cannot be built from a NULL argument with non-null length");
}
/*implicit*/ constexpr StringRef(const char *data, size_t length)
: Data(data), Length(length) {}
/// Construct a string ref from an std::string.
LLVM_ATTRIBUTE_ALWAYS_INLINE
/*implicit*/ StringRef(const std::string &Str)
: Data(Str.data()), Length(Str.length()) {}
static StringRef withNullAsEmpty(const char *data) {
return StringRef(data ? data : "");
}
/// @}
/// @name Iterators
/// @{
@ -112,31 +120,37 @@ namespace llvm {
/// data - Get a pointer to the start of the string (which may not be null
/// terminated).
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
const char *data() const { return Data; }
/// empty - Check if the string is empty.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool empty() const { return Length == 0; }
/// size - Get the string size.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t size() const { return Length; }
/// front - Get the first character in the string.
LLVM_NODISCARD
char front() const {
assert(!empty());
return Data[0];
}
/// back - Get the last character in the string.
LLVM_NODISCARD
char back() const {
assert(!empty());
return Data[Length-1];
}
// copy - Allocate copy in Allocator and return StringRef to it.
template <typename Allocator> StringRef copy(Allocator &A) const {
template <typename Allocator>
LLVM_NODISCARD StringRef copy(Allocator &A) const {
// Don't request a length 0 copy from the allocator.
if (empty())
return StringRef();
@ -147,6 +161,7 @@ namespace llvm {
/// equals - Check for string equality, this is more efficient than
/// compare() when the relative ordering of inequal strings isn't needed.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool equals(StringRef RHS) const {
return (Length == RHS.Length &&
@ -154,12 +169,14 @@ namespace llvm {
}
/// equals_lower - Check for string equality, ignoring case.
LLVM_NODISCARD
bool equals_lower(StringRef RHS) const {
return Length == RHS.Length && compare_lower(RHS) == 0;
}
/// compare - Compare two strings; the result is -1, 0, or 1 if this string
/// is lexicographically less than, equal to, or greater than the \p RHS.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
int compare(StringRef RHS) const {
// Check the prefix for a mismatch.
@ -173,10 +190,12 @@ namespace llvm {
}
/// compare_lower - Compare two strings, ignoring case.
LLVM_NODISCARD
int compare_lower(StringRef RHS) const;
/// compare_numeric - Compare two strings, treating sequences of digits as
/// numbers.
LLVM_NODISCARD
int compare_numeric(StringRef RHS) const;
/// \brief Determine the edit distance between this string and another
@ -197,10 +216,12 @@ namespace llvm {
/// or (if \p AllowReplacements is \c true) replacements needed to
/// transform one of the given strings into the other. If zero,
/// the strings are identical.
LLVM_NODISCARD
unsigned edit_distance(StringRef Other, bool AllowReplacements = true,
unsigned MaxEditDistance = 0) const;
/// str - Get the contents as an std::string.
LLVM_NODISCARD
std::string str() const {
if (!Data) return std::string();
return std::string(Data, Length);
@ -210,11 +231,21 @@ namespace llvm {
/// @name Operator Overloads
/// @{
LLVM_NODISCARD
char operator[](size_t Index) const {
assert(Index < Length && "Invalid index!");
return Data[Index];
}
/// Disallow accidental assignment from a temporary std::string.
///
/// The declaration here is extra complicated so that `stringRef = {}`
/// and `stringRef = "abc"` continue to select the move assignment operator.
template <typename T>
typename std::enable_if<std::is_same<T, std::string>::value,
StringRef>::type &
operator=(T &&Str) = delete;
/// @}
/// @name Type Conversions
/// @{
@ -228,6 +259,7 @@ namespace llvm {
/// @{
/// Check if this string starts with the given \p Prefix.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool startswith(StringRef Prefix) const {
return Length >= Prefix.Length &&
@ -235,9 +267,11 @@ namespace llvm {
}
/// Check if this string starts with the given \p Prefix, ignoring case.
LLVM_NODISCARD
bool startswith_lower(StringRef Prefix) const;
/// Check if this string ends with the given \p Suffix.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool endswith(StringRef Suffix) const {
return Length >= Suffix.Length &&
@ -245,6 +279,7 @@ namespace llvm {
}
/// Check if this string ends with the given \p Suffix, ignoring case.
LLVM_NODISCARD
bool endswith_lower(StringRef Suffix) const;
/// @}
@ -255,6 +290,7 @@ namespace llvm {
///
/// \returns The index of the first occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, Length);
@ -266,16 +302,58 @@ namespace llvm {
return npos;
}
/// Search for the first character \p C in the string, ignoring case.
///
/// \returns The index of the first occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t find_lower(char C, size_t From = 0) const;
/// Search for the first character satisfying the predicate \p F
///
/// \returns The index of the first character satisfying \p F starting from
/// \p From, or npos if not found.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t find_if(function_ref<bool(char)> F, size_t From = 0) const {
StringRef S = drop_front(From);
while (!S.empty()) {
if (F(S.front()))
return size() - S.size();
S = S.drop_front();
}
return npos;
}
/// Search for the first character not satisfying the predicate \p F
///
/// \returns The index of the first character not satisfying \p F starting
/// from \p From, or npos if not found.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const {
return find_if([F](char c) { return !F(c); }, From);
}
/// Search for the first string \p Str in the string.
///
/// \returns The index of the first occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t find(StringRef Str, size_t From = 0) const;
/// Search for the first string \p Str in the string, ignoring case.
///
/// \returns The index of the first occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t find_lower(StringRef Str, size_t From = 0) const;
/// Search for the last character \p C in the string.
///
/// \returns The index of the last occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind(char C, size_t From = npos) const {
From = std::min(From, Length);
size_t i = From;
@ -287,14 +365,30 @@ namespace llvm {
return npos;
}
/// Search for the last character \p C in the string, ignoring case.
///
/// \returns The index of the last occurrence of \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind_lower(char C, size_t From = npos) const;
/// Search for the last string \p Str in the string.
///
/// \returns The index of the last occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind(StringRef Str) const;
/// Search for the last string \p Str in the string, ignoring case.
///
/// \returns The index of the last occurrence of \p Str, or npos if not
/// found.
LLVM_NODISCARD
size_t rfind_lower(StringRef Str) const;
/// Find the first character in the string that is \p C, or npos if not
/// found. Same as find.
LLVM_NODISCARD
size_t find_first_of(char C, size_t From = 0) const {
return find(C, From);
}
@ -303,20 +397,24 @@ namespace llvm {
/// not found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_first_of(StringRef Chars, size_t From = 0) const;
/// Find the first character in the string that is not \p C or npos if not
/// found.
LLVM_NODISCARD
size_t find_first_not_of(char C, size_t From = 0) const;
/// Find the first character in the string that is not in the string
/// \p Chars, or npos if not found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_first_not_of(StringRef Chars, size_t From = 0) const;
/// Find the last character in the string that is \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t find_last_of(char C, size_t From = npos) const {
return rfind(C, From);
}
@ -325,23 +423,53 @@ namespace llvm {
/// found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_last_of(StringRef Chars, size_t From = npos) const;
/// Find the last character in the string that is not \p C, or npos if not
/// found.
LLVM_NODISCARD
size_t find_last_not_of(char C, size_t From = npos) const;
/// Find the last character in the string that is not in \p Chars, or
/// npos if not found.
///
/// Complexity: O(size() + Chars.size())
LLVM_NODISCARD
size_t find_last_not_of(StringRef Chars, size_t From = npos) const;
/// Return true if the given string is a substring of *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains(StringRef Other) const { return find(Other) != npos; }
/// Return true if the given character is contained in *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains(char C) const { return find_first_of(C) != npos; }
/// Return true if the given string is a substring of *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains_lower(StringRef Other) const {
return find_lower(Other) != npos;
}
/// Return true if the given character is contained in *this, and false
/// otherwise.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool contains_lower(char C) const { return find_lower(C) != npos; }
/// @}
/// @name Helpful Algorithms
/// @{
/// Return the number of occurrences of \p C in the string.
LLVM_NODISCARD
size_t count(char C) const {
size_t Count = 0;
for (size_t i = 0, e = Length; i != e; ++i)
@ -386,6 +514,37 @@ namespace llvm {
return false;
}
/// Parse the current string as an integer of the specified radix. If
/// \p Radix is specified as zero, this does radix autosensing using
/// extended C rules: 0 is octal, 0x is hex, 0b is binary.
///
/// If the string does not begin with a number of the specified radix,
/// this returns true to signify the error. The string is considered
/// erroneous if empty or if it overflows T.
/// The portion of the string representing the discovered numeric value
/// is removed from the beginning of the string.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
consumeInteger(unsigned Radix, T &Result) {
long long LLVal;
if (consumeSignedInteger(*this, Radix, LLVal) ||
static_cast<long long>(static_cast<T>(LLVal)) != LLVal)
return true;
Result = LLVal;
return false;
}
template <typename T>
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
consumeInteger(unsigned Radix, T &Result) {
unsigned long long ULLVal;
if (consumeUnsignedInteger(*this, Radix, ULLVal) ||
static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
return true;
Result = ULLVal;
return false;
}
/// Parse the current string as an integer of the specified \p Radix, or of
/// an autosensed radix if the \p Radix given is 0. The current value in
/// \p Result is discarded, and the storage is changed to be wide enough to
@ -403,9 +562,11 @@ namespace llvm {
/// @{
// Convert the given ASCII string to lowercase.
LLVM_NODISCARD
std::string lower() const;
/// Convert the given ASCII string to uppercase.
LLVM_NODISCARD
std::string upper() const;
/// @}
@ -421,14 +582,54 @@ namespace llvm {
/// \param N The number of characters to included in the substring. If N
/// exceeds the number of characters remaining in the string, the string
/// suffix (starting with \p Start) will be returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef substr(size_t Start, size_t N = npos) const {
Start = std::min(Start, Length);
return StringRef(Data + Start, std::min(N, Length - Start));
}
/// Return a StringRef equal to 'this' but with only the first \p N
/// elements remaining. If \p N is greater than the length of the
/// string, the entire string is returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_front(size_t N = 1) const {
if (N >= size())
return *this;
return drop_back(size() - N);
}
/// Return a StringRef equal to 'this' but with only the first \p N
/// elements remaining. If \p N is greater than the length of the
/// string, the entire string is returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_back(size_t N = 1) const {
if (N >= size())
return *this;
return drop_front(size() - N);
}
/// Return the longest prefix of 'this' such that every character
/// in the prefix satisfies the given predicate.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_while(function_ref<bool(char)> F) const {
return substr(0, find_if_not(F));
}
/// Return the longest prefix of 'this' such that no character in
/// the prefix satisfies the given predicate.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef take_until(function_ref<bool(char)> F) const {
return substr(0, find_if(F));
}
/// Return a StringRef equal to 'this' but with the first \p N elements
/// dropped.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_front(size_t N = 1) const {
assert(size() >= N && "Dropping more elements than exist");
@ -437,12 +638,51 @@ namespace llvm {
/// Return a StringRef equal to 'this' but with the last \p N elements
/// dropped.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_back(size_t N = 1) const {
assert(size() >= N && "Dropping more elements than exist");
return substr(0, size()-N);
}
/// Return a StringRef equal to 'this', but with all characters satisfying
/// the given predicate dropped from the beginning of the string.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_while(function_ref<bool(char)> F) const {
return substr(find_if_not(F));
}
/// Return a StringRef equal to 'this', but with all characters not
/// satisfying the given predicate dropped from the beginning of the string.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef drop_until(function_ref<bool(char)> F) const {
return substr(find_if(F));
}
/// Returns true if this StringRef has the given prefix and removes that
/// prefix.
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool consume_front(StringRef Prefix) {
if (!startswith(Prefix))
return false;
*this = drop_front(Prefix.size());
return true;
}
/// Returns true if this StringRef has the given suffix and removes that
/// suffix.
LLVM_ATTRIBUTE_ALWAYS_INLINE
bool consume_back(StringRef Suffix) {
if (!endswith(Suffix))
return false;
*this = drop_back(Suffix.size());
return true;
}
/// Return a reference to the substring from [Start, End).
///
/// \param Start The index of the starting character in the substring; if
@ -454,6 +694,7 @@ namespace llvm {
/// remaining in the string, the string suffix (starting with \p Start)
/// will be returned. If this is less than \p Start, an empty string will
/// be returned.
LLVM_NODISCARD
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringRef slice(size_t Start, size_t End) const {
Start = std::min(Start, Length);
@ -471,6 +712,7 @@ namespace llvm {
///
/// \param Separator The character to split on.
/// \returns The split substrings.
LLVM_NODISCARD
std::pair<StringRef, StringRef> split(char Separator) const {
size_t Idx = find(Separator);
if (Idx == npos)
@ -488,6 +730,7 @@ namespace llvm {
///
/// \param Separator - The string to split on.
/// \return - The split substrings.
LLVM_NODISCARD
std::pair<StringRef, StringRef> split(StringRef Separator) const {
size_t Idx = find(Separator);
if (Idx == npos)
@ -540,6 +783,7 @@ namespace llvm {
///
/// \param Separator - The character to split on.
/// \return - The split substrings.
LLVM_NODISCARD
std::pair<StringRef, StringRef> rsplit(char Separator) const {
size_t Idx = rfind(Separator);
if (Idx == npos)
@ -549,36 +793,42 @@ namespace llvm {
/// Return string with consecutive \p Char characters starting from the
/// the left removed.
LLVM_NODISCARD
StringRef ltrim(char Char) const {
return drop_front(std::min(Length, find_first_not_of(Char)));
}
/// Return string with consecutive characters in \p Chars starting from
/// the left removed.
LLVM_NODISCARD
StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const {
return drop_front(std::min(Length, find_first_not_of(Chars)));
}
/// Return string with consecutive \p Char characters starting from the
/// right removed.
LLVM_NODISCARD
StringRef rtrim(char Char) const {
return drop_back(Length - std::min(Length, find_last_not_of(Char) + 1));
}
/// Return string with consecutive characters in \p Chars starting from
/// the right removed.
LLVM_NODISCARD
StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const {
return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1));
}
/// Return string with consecutive \p Char characters starting from the
/// left and right removed.
LLVM_NODISCARD
StringRef trim(char Char) const {
return ltrim(Char).rtrim(Char);
}
/// Return string with consecutive characters in \p Chars starting from
/// the left and right removed.
LLVM_NODISCARD
StringRef trim(StringRef Chars = " \t\n\v\f\r") const {
return ltrim(Chars).rtrim(Chars);
}
@ -586,6 +836,28 @@ namespace llvm {
/// @}
};
/// A wrapper around a string literal that serves as a proxy for constructing
/// global tables of StringRefs with the length computed at compile time.
/// In order to avoid the invocation of a global constructor, StringLiteral
/// should *only* be used in a constexpr context, as such:
///
/// constexpr StringLiteral S("test");
///
class StringLiteral : public StringRef {
public:
template <size_t N>
constexpr StringLiteral(const char (&Str)[N])
#if defined(__clang__) && __has_attribute(enable_if)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
__attribute((enable_if(__builtin_strlen(Str) == N - 1,
"invalid string literal")))
#pragma clang diagnostic pop
#endif
: StringRef(Str, N - 1) {
}
};
/// @name StringRef Comparison Operators
/// @{
@ -595,9 +867,7 @@ namespace llvm {
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
inline bool operator!=(StringRef LHS, StringRef RHS) {
return !(LHS == RHS);
}
inline bool operator!=(StringRef LHS, StringRef RHS) { return !(LHS == RHS); }
inline bool operator<(StringRef LHS, StringRef RHS) {
return LHS.compare(RHS) == -1;
@ -622,6 +892,7 @@ namespace llvm {
/// @}
/// \brief Compute a hash_code for a StringRef.
LLVM_NODISCARD
hash_code hash_value(StringRef S);
// StringRefs can be treated like a POD type.

View File

@ -53,104 +53,197 @@ class StringSwitch {
explicit StringSwitch(StringRef S)
: Str(S), Result(nullptr) { }
// StringSwitch is not copyable.
StringSwitch(const StringSwitch &) = delete;
void operator=(const StringSwitch &) = delete;
StringSwitch(StringSwitch &&other) {
*this = std::move(other);
}
StringSwitch &operator=(StringSwitch &&other) {
Str = other.Str;
Result = other.Result;
return *this;
}
~StringSwitch() = default;
// Case-sensitive case matchers
template<unsigned N>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& Case(const char (&S)[N], const T& Value) {
assert(N);
if (!Result && N-1 == Str.size() &&
(std::memcmp(S, Str.data(), N-1) == 0)) {
(N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
Result = &Value;
}
return *this;
}
template<unsigned N>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
assert(N);
if (!Result && Str.size() >= N-1 &&
std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0) {
(N == 1 || std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0)) {
Result = &Value;
}
return *this;
}
template<unsigned N>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
assert(N);
if (!Result && Str.size() >= N-1 &&
std::memcmp(S, Str.data(), N-1) == 0) {
(N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
Result = &Value;
}
return *this;
}
template<unsigned N0, unsigned N1>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const T& Value) {
if (!Result && (
(N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
(N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0))) {
Result = &Value;
}
return *this;
return Case(S0, Value).Case(S1, Value);
}
template<unsigned N0, unsigned N1, unsigned N2>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const T& Value) {
if (!Result && (
(N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
(N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) ||
(N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0))) {
Result = &Value;
}
return *this;
return Case(S0, Value).Cases(S1, S2, Value);
}
template<unsigned N0, unsigned N1, unsigned N2, unsigned N3>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const T& Value) {
if (!Result && (
(N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
(N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) ||
(N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0) ||
(N3-1 == Str.size() && std::memcmp(S3, Str.data(), N3-1) == 0))) {
Result = &Value;
}
return *this;
return Case(S0, Value).Cases(S1, S2, S3, Value);
}
template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch& Cases(const char (&S0)[N0], const char (&S1)[N1],
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const char (&S4)[N4], const T& Value) {
if (!Result && (
(N0-1 == Str.size() && std::memcmp(S0, Str.data(), N0-1) == 0) ||
(N1-1 == Str.size() && std::memcmp(S1, Str.data(), N1-1) == 0) ||
(N2-1 == Str.size() && std::memcmp(S2, Str.data(), N2-1) == 0) ||
(N3-1 == Str.size() && std::memcmp(S3, Str.data(), N3-1) == 0) ||
(N4-1 == Str.size() && std::memcmp(S4, Str.data(), N4-1) == 0))) {
return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
unsigned N5>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const char (&S4)[N4], const char (&S5)[N5],
const T &Value) {
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
unsigned N5, unsigned N6>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const char (&S4)[N4], const char (&S5)[N5],
const char (&S6)[N6], const T &Value) {
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
unsigned N5, unsigned N6, unsigned N7>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const char (&S4)[N4], const char (&S5)[N5],
const char (&S6)[N6], const char (&S7)[N7],
const T &Value) {
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
unsigned N5, unsigned N6, unsigned N7, unsigned N8>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const char (&S4)[N4], const char (&S5)[N5],
const char (&S6)[N6], const char (&S7)[N7],
const char (&S8)[N8], const T &Value) {
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
unsigned N5, unsigned N6, unsigned N7, unsigned N8, unsigned N9>
LLVM_ATTRIBUTE_ALWAYS_INLINE
StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
const char (&S2)[N2], const char (&S3)[N3],
const char (&S4)[N4], const char (&S5)[N5],
const char (&S6)[N6], const char (&S7)[N7],
const char (&S8)[N8], const char (&S9)[N9],
const T &Value) {
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
}
// Case-insensitive case matchers.
template <unsigned N>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &CaseLower(const char (&S)[N],
const T &Value) {
if (!Result && Str.equals_lower(StringRef(S, N - 1)))
Result = &Value;
}
return *this;
}
template <unsigned N>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &EndsWithLower(const char (&S)[N],
const T &Value) {
if (!Result && Str.endswith_lower(StringRef(S, N - 1)))
Result = &Value;
return *this;
}
template <unsigned N>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &StartsWithLower(const char (&S)[N],
const T &Value) {
if (!Result && Str.startswith_lower(StringRef(S, N - 1)))
Result = &Value;
return *this;
}
template <unsigned N0, unsigned N1>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const T &Value) {
return CaseLower(S0, Value).CaseLower(S1, Value);
}
template <unsigned N0, unsigned N1, unsigned N2>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
const T &Value) {
return CaseLower(S0, Value).CasesLower(S1, S2, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
const char (&S3)[N3], const T &Value) {
return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
}
template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
const char (&S3)[N3], const char (&S4)[N4], const T &Value) {
return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
R Default(const T& Value) const {
R Default(const T &Value) const {
if (Result)
return *Result;
return Value;
}

View File

@ -11,8 +11,13 @@
#define LLVM_ADT_TINYPTRVECTOR_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace llvm {
@ -25,15 +30,16 @@ namespace llvm {
template <typename EltTy>
class TinyPtrVector {
public:
typedef llvm::SmallVector<EltTy, 4> VecTy;
typedef SmallVector<EltTy, 4> VecTy;
typedef typename VecTy::value_type value_type;
typedef llvm::PointerUnion<EltTy, VecTy *> PtrUnion;
typedef PointerUnion<EltTy, VecTy *> PtrUnion;
private:
PtrUnion Val;
public:
TinyPtrVector() {}
TinyPtrVector() = default;
~TinyPtrVector() {
if (VecTy *V = Val.template dyn_cast<VecTy*>())
delete V;
@ -43,6 +49,7 @@ class TinyPtrVector {
if (VecTy *V = Val.template dyn_cast<VecTy*>())
Val = new VecTy(*V);
}
TinyPtrVector &operator=(const TinyPtrVector &RHS) {
if (this == &RHS)
return *this;
@ -74,6 +81,7 @@ class TinyPtrVector {
TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
RHS.Val = (EltTy)nullptr;
}
TinyPtrVector &operator=(TinyPtrVector &&RHS) {
if (this == &RHS)
return *this;
@ -170,6 +178,7 @@ class TinyPtrVector {
return Val.template get<VecTy *>()->begin();
}
iterator end() {
if (Val.template is<EltTy>())
return begin() + (Val.isNull() ? 0 : 1);
@ -187,9 +196,11 @@ class TinyPtrVector {
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
@ -329,6 +340,7 @@ class TinyPtrVector {
return Val.template get<VecTy*>()->insert(begin() + Offset, From, To);
}
};
} // end namespace llvm
#endif
#endif // LLVM_ADT_TINYPTRVECTOR_H

View File

@ -64,11 +64,14 @@ class Triple {
ppc64le, // PPC64LE: powerpc64le
r600, // R600: AMD GPUs HD2XXX - HD6XXX
amdgcn, // AMDGCN: AMD GCN GPUs
riscv32, // RISC-V (32-bit): riscv32
riscv64, // RISC-V (64-bit): riscv64
sparc, // Sparc: sparc
sparcv9, // Sparcv9: Sparcv9
sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
systemz, // SystemZ: s390x
tce, // TCE (http://tce.cs.tut.fi/): tce
tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele
thumb, // Thumb (little endian): thumb, thumbv.*
thumbeb, // Thumb (big endian): thumbeb
x86, // X86: i[3-9]86
@ -99,6 +102,7 @@ class Triple {
ARMSubArch_v8_2a,
ARMSubArch_v8_1a,
ARMSubArch_v8,
ARMSubArch_v8r,
ARMSubArch_v8m_baseline,
ARMSubArch_v8m_mainline,
ARMSubArch_v7,
@ -144,6 +148,7 @@ class Triple {
Darwin,
DragonFly,
FreeBSD,
Fuchsia,
IOS,
KFreeBSD,
Linux,
@ -168,7 +173,8 @@ class Triple {
TvOS, // Apple tvOS
WatchOS, // Apple watchOS
Mesa3D,
LastOSType = Mesa3D
Contiki,
LastOSType = Contiki
};
enum EnvironmentType {
UnknownEnvironment,
@ -191,7 +197,8 @@ class Triple {
Cygnus,
AMDOpenCL,
CoreCLR,
LastEnvironmentType = CoreCLR
OpenCL,
LastEnvironmentType = OpenCL
};
enum ObjectFormatType {
UnknownObjectFormat,
@ -461,6 +468,10 @@ class Triple {
return getOS() == Triple::FreeBSD;
}
bool isOSFuchsia() const {
return getOS() == Triple::Fuchsia;
}
bool isOSDragonFly() const { return getOS() == Triple::DragonFly; }
bool isOSSolaris() const {
@ -482,6 +493,10 @@ class Triple {
Env == Triple::GNUX32;
}
bool isOSContiki() const {
return getOS() == Triple::Contiki;
}
/// Checks if the environment could be MSVC.
bool isWindowsMSVCEnvironment() const {
return getOS() == Triple::Win32 &&
@ -690,7 +705,7 @@ class Triple {
/// @{
/// getArchTypeName - Get the canonical name for the \p Kind architecture.
static const char *getArchTypeName(ArchType Kind);
static StringRef getArchTypeName(ArchType Kind);
/// getArchTypePrefix - Get the "prefix" canonical name for the \p Kind
/// architecture. This is the prefix used by the architecture specific
@ -698,17 +713,17 @@ class Triple {
/// Intrinsic::getIntrinsicForGCCBuiltin().
///
/// \return - The architecture prefix, or 0 if none is defined.
static const char *getArchTypePrefix(ArchType Kind);
static StringRef getArchTypePrefix(ArchType Kind);
/// getVendorTypeName - Get the canonical name for the \p Kind vendor.
static const char *getVendorTypeName(VendorType Kind);
static StringRef getVendorTypeName(VendorType Kind);
/// getOSTypeName - Get the canonical name for the \p Kind operating system.
static const char *getOSTypeName(OSType Kind);
static StringRef getOSTypeName(OSType Kind);
/// getEnvironmentTypeName - Get the canonical name for the \p Kind
/// environment.
static const char *getEnvironmentTypeName(EnvironmentType Kind);
static StringRef getEnvironmentTypeName(EnvironmentType Kind);
/// @}
/// @name Static helpers for converting alternate architecture names.

View File

@ -12,12 +12,14 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <cstdint>
#include <string>
namespace llvm {
class formatv_object_base;
class raw_ostream;
/// Twine - A lightweight data structure for efficiently representing the
@ -101,6 +103,9 @@ namespace llvm {
/// A pointer to a SmallString instance.
SmallStringKind,
/// A pointer to a formatv_object_base instance.
FormatvObjectKind,
/// A char value, to render as a character.
CharKind,
@ -136,6 +141,7 @@ namespace llvm {
const std::string *stdString;
const StringRef *stringRef;
const SmallVectorImpl<char> *smallString;
const formatv_object_base *formatvObject;
char character;
unsigned int decUI;
int decI;
@ -146,7 +152,6 @@ namespace llvm {
const uint64_t *uHex;
};
private:
/// LHS - The prefix in the concatenation, which may be uninitialized for
/// Null or Empty kinds.
Child LHS;
@ -158,7 +163,6 @@ namespace llvm {
/// RHSKind - The NodeKind of the right hand side, \see getRHSKind().
NodeKind RHSKind;
private:
/// Construct a nullary twine; the kind must be NullKind or EmptyKind.
explicit Twine(NodeKind Kind)
: LHSKind(Kind), RHSKind(EmptyKind) {
@ -179,10 +183,6 @@ namespace llvm {
assert(isValid() && "Invalid twine!");
}
/// Since the intended use of twines is as temporary objects, assignments
/// when concatenating might cause undefined behavior or stack corruptions
Twine &operator=(const Twine &Other) = delete;
/// Check for the null twine.
bool isNull() const {
return getLHSKind() == NullKind;
@ -295,6 +295,13 @@ namespace llvm {
assert(isValid() && "Invalid twine!");
}
/// Construct from a formatv_object_base.
/*implicit*/ Twine(const formatv_object_base &Fmt)
: LHSKind(FormatvObjectKind), RHSKind(EmptyKind) {
LHS.formatvObject = &Fmt;
assert(isValid() && "Invalid twine!");
}
/// Construct from a char.
explicit Twine(char Val)
: LHSKind(CharKind), RHSKind(EmptyKind) {
@ -370,6 +377,10 @@ namespace llvm {
assert(isValid() && "Invalid twine!");
}
/// Since the intended use of twines is as temporary objects, assignments
/// when concatenating might cause undefined behavior or stack corruptions
Twine &operator=(const Twine &) = delete;
/// Create a 'null' string, which is an empty string that always
/// concatenates to form another empty string.
static Twine createNull() {
@ -535,6 +546,7 @@ namespace llvm {
}
/// @}
}
#endif
} // end namespace llvm
#endif // LLVM_ADT_TWINE_H

View File

@ -11,459 +11,270 @@
// (i.e. each node of the list must contain a next and previous field for the
// list.
//
// The ilist_traits trait class is used to gain access to the next and previous
// fields of the node type that the list is instantiated with. If it is not
// specialized, the list defaults to using the getPrev(), getNext() method calls
// to get the next and previous pointers.
// The ilist class itself should be a plug in replacement for list. This list
// replacement does not provide a constant time size() method, so be careful to
// use empty() when you really want to know if it's empty.
//
// The ilist class itself, should be a plug in replacement for list, assuming
// that the nodes contain next/prev pointers. This list replacement does not
// provide a constant time size() method, so be careful to use empty() when you
// really want to know if it's empty.
//
// The ilist class is implemented by allocating a 'tail' node when the list is
// created (using ilist_traits<>::createSentinel()). This tail node is
// absolutely required because the user must be able to compute end()-1. Because
// of this, users of the direct next/prev links will see an extra link on the
// end of the list, which should be ignored.
//
// Requirements for a user of this list:
//
// 1. The user must provide {g|s}et{Next|Prev} methods, or specialize
// ilist_traits to provide an alternate way of getting and setting next and
// prev links.
// The ilist class is implemented as a circular list. The list itself contains
// a sentinel node, whose Next points at begin() and whose Prev points at
// rbegin(). The sentinel node itself serves as end() and rend().
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ILIST_H
#define LLVM_ADT_ILIST_H
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include "llvm/ADT/simple_ilist.h"
#include <cassert>
#include <cstddef>
#include <iterator>
namespace llvm {
template<typename NodeTy, typename Traits> class iplist;
template<typename NodeTy> class ilist_iterator;
/// ilist_nextprev_traits - A fragment for template traits for intrusive list
/// that provides default next/prev implementations for common operations.
/// Use delete by default for iplist and ilist.
///
template<typename NodeTy>
struct ilist_nextprev_traits {
static NodeTy *getPrev(NodeTy *N) { return N->getPrev(); }
static NodeTy *getNext(NodeTy *N) { return N->getNext(); }
static const NodeTy *getPrev(const NodeTy *N) { return N->getPrev(); }
static const NodeTy *getNext(const NodeTy *N) { return N->getNext(); }
static void setPrev(NodeTy *N, NodeTy *Prev) { N->setPrev(Prev); }
static void setNext(NodeTy *N, NodeTy *Next) { N->setNext(Next); }
};
template<typename NodeTy>
struct ilist_traits;
/// ilist_sentinel_traits - A fragment for template traits for intrusive list
/// that provides default sentinel implementations for common operations.
/// Specialize this to get different behaviour for ownership-related API. (If
/// you really want ownership semantics, consider using std::list or building
/// something like \a BumpPtrList.)
///
/// ilist_sentinel_traits implements a lazy dynamic sentinel allocation
/// strategy. The sentinel is stored in the prev field of ilist's Head.
///
template<typename NodeTy>
struct ilist_sentinel_traits {
/// createSentinel - create the dynamic sentinel
static NodeTy *createSentinel() { return new NodeTy(); }
/// destroySentinel - deallocate the dynamic sentinel
static void destroySentinel(NodeTy *N) { delete N; }
/// provideInitialHead - when constructing an ilist, provide a starting
/// value for its Head
/// @return null node to indicate that it needs to be allocated later
static NodeTy *provideInitialHead() { return nullptr; }
/// ensureHead - make sure that Head is either already
/// initialized or assigned a fresh sentinel
/// @return the sentinel
static NodeTy *ensureHead(NodeTy *&Head) {
if (!Head) {
Head = ilist_traits<NodeTy>::createSentinel();
ilist_traits<NodeTy>::noteHead(Head, Head);
ilist_traits<NodeTy>::setNext(Head, nullptr);
return Head;
}
return ilist_traits<NodeTy>::getPrev(Head);
}
/// noteHead - stash the sentinel into its default location
static void noteHead(NodeTy *NewHead, NodeTy *Sentinel) {
ilist_traits<NodeTy>::setPrev(NewHead, Sentinel);
}
};
template <typename NodeTy> class ilist_half_node;
template <typename NodeTy> class ilist_node;
/// Traits with an embedded ilist_node as a sentinel.
///
/// FIXME: The downcast in createSentinel() is UB.
template <typename NodeTy> struct ilist_embedded_sentinel_traits {
/// Get hold of the node that marks the end of the list.
NodeTy *createSentinel() const {
// Since i(p)lists always publicly derive from their corresponding traits,
// placing a data member in this class will augment the i(p)list. But since
// the NodeTy is expected to be publicly derive from ilist_node<NodeTy>,
// there is a legal viable downcast from it to NodeTy. We use this trick to
// superimpose an i(p)list with a "ghostly" NodeTy, which becomes the
// sentinel. Dereferencing the sentinel is forbidden (save the
// ilist_node<NodeTy>), so no one will ever notice the superposition.
return static_cast<NodeTy *>(&Sentinel);
}
static void destroySentinel(NodeTy *) {}
NodeTy *provideInitialHead() const { return createSentinel(); }
NodeTy *ensureHead(NodeTy *) const { return createSentinel(); }
static void noteHead(NodeTy *, NodeTy *) {}
private:
mutable ilist_node<NodeTy> Sentinel;
};
/// Trait with an embedded ilist_half_node as a sentinel.
///
/// FIXME: The downcast in createSentinel() is UB.
template <typename NodeTy> struct ilist_half_embedded_sentinel_traits {
/// Get hold of the node that marks the end of the list.
NodeTy *createSentinel() const {
// See comment in ilist_embedded_sentinel_traits::createSentinel().
return static_cast<NodeTy *>(&Sentinel);
}
static void destroySentinel(NodeTy *) {}
NodeTy *provideInitialHead() const { return createSentinel(); }
NodeTy *ensureHead(NodeTy *) const { return createSentinel(); }
static void noteHead(NodeTy *, NodeTy *) {}
private:
mutable ilist_half_node<NodeTy> Sentinel;
};
/// ilist_node_traits - A fragment for template traits for intrusive list
/// that provides default node related operations.
///
template<typename NodeTy>
struct ilist_node_traits {
static NodeTy *createNode(const NodeTy &V) { return new NodeTy(V); }
/// \see ilist_noalloc_traits
template <typename NodeTy> struct ilist_alloc_traits {
static void deleteNode(NodeTy *V) { delete V; }
};
/// Custom traits to do nothing on deletion.
///
/// Specialize ilist_alloc_traits to inherit from this to disable the
/// non-intrusive deletion in iplist (which implies ownership).
///
/// If you want purely intrusive semantics with no callbacks, consider using \a
/// simple_ilist instead.
///
/// \code
/// template <>
/// struct ilist_alloc_traits<MyType> : ilist_noalloc_traits<MyType> {};
/// \endcode
template <typename NodeTy> struct ilist_noalloc_traits {
static void deleteNode(NodeTy *V) {}
};
/// Callbacks do nothing by default in iplist and ilist.
///
/// Specialize this for to use callbacks for when nodes change their list
/// membership.
template <typename NodeTy> struct ilist_callback_traits {
void addNodeToList(NodeTy *) {}
void removeNodeFromList(NodeTy *) {}
void transferNodesFromList(ilist_node_traits & /*SrcTraits*/,
ilist_iterator<NodeTy> /*first*/,
ilist_iterator<NodeTy> /*last*/) {}
/// Callback before transferring nodes to this list.
///
/// \pre \c this!=&OldList
template <class Iterator>
void transferNodesFromList(ilist_callback_traits &OldList, Iterator /*first*/,
Iterator /*last*/) {
(void)OldList;
}
};
/// ilist_default_traits - Default template traits for intrusive list.
/// By inheriting from this, you can easily use default implementations
/// for all common operations.
/// A fragment for template traits for intrusive list that provides default
/// node related operations.
///
template<typename NodeTy>
struct ilist_default_traits : public ilist_nextprev_traits<NodeTy>,
public ilist_sentinel_traits<NodeTy>,
public ilist_node_traits<NodeTy> {
};
/// TODO: Remove this layer of indirection. It's not necessary.
template <typename NodeTy>
struct ilist_node_traits : ilist_alloc_traits<NodeTy>,
ilist_callback_traits<NodeTy> {};
// Template traits for intrusive list. By specializing this template class, you
// can change what next/prev fields are used to store the links...
template<typename NodeTy>
/// Default template traits for intrusive list.
///
/// By inheriting from this, you can easily use default implementations for all
/// common operations.
///
/// TODO: Remove this customization point. Specializing ilist_traits is
/// already fully general.
template <typename NodeTy>
struct ilist_default_traits : public ilist_node_traits<NodeTy> {};
/// Template traits for intrusive list.
///
/// Customize callbacks and allocation semantics.
template <typename NodeTy>
struct ilist_traits : public ilist_default_traits<NodeTy> {};
// Const traits are the same as nonconst traits...
template<typename Ty>
struct ilist_traits<const Ty> : public ilist_traits<Ty> {};
/// Const traits should never be instantiated.
template <typename Ty> struct ilist_traits<const Ty> {};
namespace ilist_detail {
template <class T> T &make();
/// Type trait to check for a traits class that has a getNext member (as a
/// canary for any of the ilist_nextprev_traits API).
template <class TraitsT, class NodeT> struct HasGetNext {
typedef char Yes[1];
typedef char No[2];
template <size_t N> struct SFINAE {};
template <class U>
static Yes &test(U *I, decltype(I->getNext(&make<NodeT>())) * = 0);
template <class> static No &test(...);
public:
static const bool value = sizeof(test<TraitsT>(nullptr)) == sizeof(Yes);
};
/// Type trait to check for a traits class that has a createSentinel member (as
/// a canary for any of the ilist_sentinel_traits API).
template <class TraitsT> struct HasCreateSentinel {
typedef char Yes[1];
typedef char No[2];
template <class U>
static Yes &test(U *I, decltype(I->createSentinel()) * = 0);
template <class> static No &test(...);
public:
static const bool value = sizeof(test<TraitsT>(nullptr)) == sizeof(Yes);
};
/// Type trait to check for a traits class that has a createNode member.
/// Allocation should be managed in a wrapper class, instead of in
/// ilist_traits.
template <class TraitsT, class NodeT> struct HasCreateNode {
typedef char Yes[1];
typedef char No[2];
template <size_t N> struct SFINAE {};
template <class U>
static Yes &test(U *I, decltype(I->createNode(make<NodeT>())) * = 0);
template <class> static No &test(...);
public:
static const bool value = sizeof(test<TraitsT>(nullptr)) == sizeof(Yes);
};
template <class TraitsT, class NodeT> struct HasObsoleteCustomization {
static const bool value = HasGetNext<TraitsT, NodeT>::value ||
HasCreateSentinel<TraitsT>::value ||
HasCreateNode<TraitsT, NodeT>::value;
};
} // end namespace ilist_detail
//===----------------------------------------------------------------------===//
// Iterator for intrusive list.
//
template <typename NodeTy>
class ilist_iterator
: public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> {
public:
typedef ilist_traits<NodeTy> Traits;
typedef std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t>
super;
/// A wrapper around an intrusive list with callbacks and non-intrusive
/// ownership.
///
/// This wraps a purely intrusive list (like simple_ilist) with a configurable
/// traits class. The traits can implement callbacks and customize the
/// ownership semantics.
///
/// This is a subset of ilist functionality that can safely be used on nodes of
/// polymorphic types, i.e. a heterogeneous list with a common base class that
/// holds the next/prev pointers. The only state of the list itself is an
/// ilist_sentinel, which holds pointers to the first and last nodes in the
/// list.
template <class IntrusiveListT, class TraitsT>
class iplist_impl : public TraitsT, IntrusiveListT {
typedef IntrusiveListT base_list_type;
typedef typename super::value_type value_type;
typedef typename super::difference_type difference_type;
typedef typename super::pointer pointer;
typedef typename super::reference reference;
protected:
typedef iplist_impl iplist_impl_type;
public:
typedef typename base_list_type::pointer pointer;
typedef typename base_list_type::const_pointer const_pointer;
typedef typename base_list_type::reference reference;
typedef typename base_list_type::const_reference const_reference;
typedef typename base_list_type::value_type value_type;
typedef typename base_list_type::size_type size_type;
typedef typename base_list_type::difference_type difference_type;
typedef typename base_list_type::iterator iterator;
typedef typename base_list_type::const_iterator const_iterator;
typedef typename base_list_type::reverse_iterator reverse_iterator;
typedef
typename base_list_type::const_reverse_iterator const_reverse_iterator;
private:
pointer NodePtr;
// TODO: Drop this assertion and the transitive type traits anytime after
// v4.0 is branched (i.e,. keep them for one release to help out-of-tree code
// update).
static_assert(
!ilist_detail::HasObsoleteCustomization<TraitsT, value_type>::value,
"ilist customization points have changed!");
static bool op_less(const_reference L, const_reference R) { return L < R; }
static bool op_equal(const_reference L, const_reference R) { return L == R; }
public:
explicit ilist_iterator(pointer NP) : NodePtr(NP) {}
explicit ilist_iterator(reference NR) : NodePtr(&NR) {}
ilist_iterator() : NodePtr(nullptr) {}
iplist_impl() = default;
// This is templated so that we can allow constructing a const iterator from
// a nonconst iterator...
template <class node_ty>
ilist_iterator(const ilist_iterator<node_ty> &RHS)
: NodePtr(RHS.getNodePtrUnchecked()) {}
iplist_impl(const iplist_impl &) = delete;
iplist_impl &operator=(const iplist_impl &) = delete;
// This is templated so that we can allow assigning to a const iterator from
// a nonconst iterator...
template <class node_ty>
const ilist_iterator &operator=(const ilist_iterator<node_ty> &RHS) {
NodePtr = RHS.getNodePtrUnchecked();
iplist_impl(iplist_impl &&X)
: TraitsT(std::move(X)), IntrusiveListT(std::move(X)) {}
iplist_impl &operator=(iplist_impl &&X) {
*static_cast<TraitsT *>(this) = std::move(X);
*static_cast<IntrusiveListT *>(this) = std::move(X);
return *this;
}
void reset(pointer NP) { NodePtr = NP; }
// Accessors...
explicit operator pointer() const { return NodePtr; }
reference operator*() const { return *NodePtr; }
pointer operator->() const { return &operator*(); }
// Comparison operators
template <class Y> bool operator==(const ilist_iterator<Y> &RHS) const {
return NodePtr == RHS.getNodePtrUnchecked();
}
template <class Y> bool operator!=(const ilist_iterator<Y> &RHS) const {
return NodePtr != RHS.getNodePtrUnchecked();
}
// Increment and decrement operators...
ilist_iterator &operator--() {
NodePtr = Traits::getPrev(NodePtr);
assert(NodePtr && "--'d off the beginning of an ilist!");
return *this;
}
ilist_iterator &operator++() {
NodePtr = Traits::getNext(NodePtr);
return *this;
}
ilist_iterator operator--(int) {
ilist_iterator tmp = *this;
--*this;
return tmp;
}
ilist_iterator operator++(int) {
ilist_iterator tmp = *this;
++*this;
return tmp;
}
// Internal interface, do not use...
pointer getNodePtrUnchecked() const { return NodePtr; }
};
// Allow ilist_iterators to convert into pointers to a node automatically when
// used by the dyn_cast, cast, isa mechanisms...
template<typename From> struct simplify_type;
template<typename NodeTy> struct simplify_type<ilist_iterator<NodeTy> > {
typedef NodeTy* SimpleType;
static SimpleType getSimplifiedValue(ilist_iterator<NodeTy> &Node) {
return &*Node;
}
};
template<typename NodeTy> struct simplify_type<const ilist_iterator<NodeTy> > {
typedef /*const*/ NodeTy* SimpleType;
static SimpleType getSimplifiedValue(const ilist_iterator<NodeTy> &Node) {
return &*Node;
}
};
//===----------------------------------------------------------------------===//
//
/// iplist - The subset of list functionality that can safely be used on nodes
/// of polymorphic types, i.e. a heterogeneous list with a common base class that
/// holds the next/prev pointers. The only state of the list itself is a single
/// pointer to the head of the list.
///
/// This list can be in one of three interesting states:
/// 1. The list may be completely unconstructed. In this case, the head
/// pointer is null. When in this form, any query for an iterator (e.g.
/// begin() or end()) causes the list to transparently change to state #2.
/// 2. The list may be empty, but contain a sentinel for the end iterator. This
/// sentinel is created by the Traits::createSentinel method and is a link
/// in the list. When the list is empty, the pointer in the iplist points
/// to the sentinel. Once the sentinel is constructed, it
/// is not destroyed until the list is.
/// 3. The list may contain actual objects in it, which are stored as a doubly
/// linked list of nodes. One invariant of the list is that the predecessor
/// of the first node in the list always points to the last node in the list,
/// and the successor pointer for the sentinel (which always stays at the
/// end of the list) is always null.
///
template<typename NodeTy, typename Traits=ilist_traits<NodeTy> >
class iplist : public Traits {
mutable NodeTy *Head;
// Use the prev node pointer of 'head' as the tail pointer. This is really a
// circularly linked list where we snip the 'next' link from the sentinel node
// back to the first node in the list (to preserve assertions about going off
// the end of the list).
NodeTy *getTail() { return this->ensureHead(Head); }
const NodeTy *getTail() const { return this->ensureHead(Head); }
void setTail(NodeTy *N) const { this->noteHead(Head, N); }
/// CreateLazySentinel - This method verifies whether the sentinel for the
/// list has been created and lazily makes it if not.
void CreateLazySentinel() const {
this->ensureHead(Head);
}
static bool op_less(NodeTy &L, NodeTy &R) { return L < R; }
static bool op_equal(NodeTy &L, NodeTy &R) { return L == R; }
// No fundamental reason why iplist can't be copyable, but the default
// copy/copy-assign won't do.
iplist(const iplist &) = delete;
void operator=(const iplist &) = delete;
public:
typedef NodeTy *pointer;
typedef const NodeTy *const_pointer;
typedef NodeTy &reference;
typedef const NodeTy &const_reference;
typedef NodeTy value_type;
typedef ilist_iterator<NodeTy> iterator;
typedef ilist_iterator<const NodeTy> const_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
iplist() : Head(this->provideInitialHead()) {}
~iplist() {
if (!Head) return;
clear();
Traits::destroySentinel(getTail());
}
// Iterator creation methods.
iterator begin() {
CreateLazySentinel();
return iterator(Head);
}
const_iterator begin() const {
CreateLazySentinel();
return const_iterator(Head);
}
iterator end() {
CreateLazySentinel();
return iterator(getTail());
}
const_iterator end() const {
CreateLazySentinel();
return const_iterator(getTail());
}
// reverse iterator creation methods.
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
~iplist_impl() { clear(); }
// Miscellaneous inspection routines.
size_type max_size() const { return size_type(-1); }
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
return !Head || Head == getTail();
}
// Front and back accessor functions...
reference front() {
assert(!empty() && "Called front() on empty list!");
return *Head;
}
const_reference front() const {
assert(!empty() && "Called front() on empty list!");
return *Head;
}
reference back() {
assert(!empty() && "Called back() on empty list!");
return *this->getPrev(getTail());
}
const_reference back() const {
assert(!empty() && "Called back() on empty list!");
return *this->getPrev(getTail());
}
using base_list_type::begin;
using base_list_type::end;
using base_list_type::rbegin;
using base_list_type::rend;
using base_list_type::empty;
using base_list_type::front;
using base_list_type::back;
void swap(iplist &RHS) {
void swap(iplist_impl &RHS) {
assert(0 && "Swap does not use list traits callback correctly yet!");
std::swap(Head, RHS.Head);
base_list_type::swap(RHS);
}
iterator insert(iterator where, NodeTy *New) {
NodeTy *CurNode = where.getNodePtrUnchecked();
NodeTy *PrevNode = this->getPrev(CurNode);
this->setNext(New, CurNode);
this->setPrev(New, PrevNode);
if (CurNode != Head) // Is PrevNode off the beginning of the list?
this->setNext(PrevNode, New);
else
Head = New;
this->setPrev(CurNode, New);
this->addNodeToList(New); // Notify traits that we added a node...
return iterator(New);
iterator insert(iterator where, pointer New) {
this->addNodeToList(New); // Notify traits that we added a node...
return base_list_type::insert(where, *New);
}
iterator insert(iterator where, const NodeTy &New) {
return this->insert(where, new NodeTy(New));
iterator insert(iterator where, const_reference New) {
return this->insert(where, new value_type(New));
}
iterator insertAfter(iterator where, NodeTy *New) {
iterator insertAfter(iterator where, pointer New) {
if (empty())
return insert(begin(), New);
else
return insert(++where, New);
}
NodeTy *remove(iterator &IT) {
assert(IT != end() && "Cannot remove end of list!");
NodeTy *Node = &*IT;
NodeTy *NextNode = this->getNext(Node);
NodeTy *PrevNode = this->getPrev(Node);
/// Clone another list.
template <class Cloner> void cloneFrom(const iplist_impl &L2, Cloner clone) {
clear();
for (const_reference V : L2)
push_back(clone(V));
}
if (Node != Head) // Is PrevNode off the beginning of the list?
this->setNext(PrevNode, NextNode);
else
Head = NextNode;
this->setPrev(NextNode, PrevNode);
IT.reset(NextNode);
this->removeNodeFromList(Node); // Notify traits that we removed a node...
// Set the next/prev pointers of the current node to null. This isn't
// strictly required, but this catches errors where a node is removed from
// an ilist (and potentially deleted) with iterators still pointing at it.
// When those iterators are incremented or decremented, they will assert on
// the null next/prev pointer instead of "usually working".
this->setNext(Node, nullptr);
this->setPrev(Node, nullptr);
pointer remove(iterator &IT) {
pointer Node = &*IT++;
this->removeNodeFromList(Node); // Notify traits that we removed a node...
base_list_type::remove(*Node);
return Node;
}
NodeTy *remove(const iterator &IT) {
pointer remove(const iterator &IT) {
iterator MutIt = IT;
return remove(MutIt);
}
NodeTy *remove(NodeTy *IT) { return remove(iterator(IT)); }
NodeTy *remove(NodeTy &IT) { return remove(iterator(IT)); }
pointer remove(pointer IT) { return remove(iterator(IT)); }
pointer remove(reference IT) { return remove(iterator(IT)); }
// erase - remove a node from the controlled sequence... and delete it.
iterator erase(iterator where) {
@ -471,82 +282,36 @@ class iplist : public Traits {
return where;
}
iterator erase(NodeTy *IT) { return erase(iterator(IT)); }
iterator erase(NodeTy &IT) { return erase(iterator(IT)); }
iterator erase(pointer IT) { return erase(iterator(IT)); }
iterator erase(reference IT) { return erase(iterator(IT)); }
/// Remove all nodes from the list like clear(), but do not call
/// removeNodeFromList() or deleteNode().
///
/// This should only be used immediately before freeing nodes in bulk to
/// avoid traversing the list and bringing all the nodes into cache.
void clearAndLeakNodesUnsafely() {
if (Head) {
Head = getTail();
this->setPrev(Head, Head);
}
}
void clearAndLeakNodesUnsafely() { base_list_type::clear(); }
private:
// transfer - The heart of the splice function. Move linked list nodes from
// [first, last) into position.
//
void transfer(iterator position, iplist &L2, iterator first, iterator last) {
assert(first != last && "Should be checked by callers");
// Position cannot be contained in the range to be transferred.
// Check for the most common mistake.
assert(position != first &&
"Insertion point can't be one of the transferred nodes");
void transfer(iterator position, iplist_impl &L2, iterator first, iterator last) {
if (position == last)
return;
if (position != last) {
// Note: we have to be careful about the case when we move the first node
// in the list. This node is the list sentinel node and we can't move it.
NodeTy *ThisSentinel = getTail();
setTail(nullptr);
NodeTy *L2Sentinel = L2.getTail();
L2.setTail(nullptr);
if (this != &L2) // Notify traits we moved the nodes...
this->transferNodesFromList(L2, first, last);
// Remove [first, last) from its old position.
NodeTy *First = &*first, *Prev = this->getPrev(First);
NodeTy *Next = last.getNodePtrUnchecked(), *Last = this->getPrev(Next);
if (Prev)
this->setNext(Prev, Next);
else
L2.Head = Next;
this->setPrev(Next, Prev);
// Splice [first, last) into its new position.
NodeTy *PosNext = position.getNodePtrUnchecked();
NodeTy *PosPrev = this->getPrev(PosNext);
// Fix head of list...
if (PosPrev)
this->setNext(PosPrev, First);
else
Head = First;
this->setPrev(First, PosPrev);
// Fix end of list...
this->setNext(Last, PosNext);
this->setPrev(PosNext, Last);
this->transferNodesFromList(L2, iterator(First), iterator(PosNext));
// Now that everything is set, restore the pointers to the list sentinels.
L2.setTail(L2Sentinel);
setTail(ThisSentinel);
}
base_list_type::splice(position, L2, first, last);
}
public:
//===----------------------------------------------------------------------===
// Functionality derived from other functions defined above...
//
size_type LLVM_ATTRIBUTE_UNUSED_RESULT size() const {
if (!Head) return 0; // Don't require construction of sentinel if empty.
return std::distance(begin(), end());
}
using base_list_type::size;
iterator erase(iterator first, iterator last) {
while (first != last)
@ -554,11 +319,11 @@ class iplist : public Traits {
return last;
}
void clear() { if (Head) erase(begin(), end()); }
void clear() { erase(begin(), end()); }
// Front and back inserters...
void push_front(NodeTy *val) { insert(begin(), val); }
void push_back(NodeTy *val) { insert(end(), val); }
void push_front(pointer val) { insert(begin(), val); }
void push_back(pointer val) { insert(end(), val); }
void pop_front() {
assert(!empty() && "pop_front() on empty list!");
erase(begin());
@ -574,179 +339,96 @@ class iplist : public Traits {
}
// Splice members - defined in terms of transfer...
void splice(iterator where, iplist &L2) {
void splice(iterator where, iplist_impl &L2) {
if (!L2.empty())
transfer(where, L2, L2.begin(), L2.end());
}
void splice(iterator where, iplist &L2, iterator first) {
void splice(iterator where, iplist_impl &L2, iterator first) {
iterator last = first; ++last;
if (where == first || where == last) return; // No change
transfer(where, L2, first, last);
}
void splice(iterator where, iplist &L2, iterator first, iterator last) {
void splice(iterator where, iplist_impl &L2, iterator first, iterator last) {
if (first != last) transfer(where, L2, first, last);
}
void splice(iterator where, iplist &L2, NodeTy &N) {
void splice(iterator where, iplist_impl &L2, reference N) {
splice(where, L2, iterator(N));
}
void splice(iterator where, iplist &L2, NodeTy *N) {
void splice(iterator where, iplist_impl &L2, pointer N) {
splice(where, L2, iterator(N));
}
template <class Compare>
void merge(iplist &Right, Compare comp) {
void merge(iplist_impl &Right, Compare comp) {
if (this == &Right)
return;
iterator First1 = begin(), Last1 = end();
iterator First2 = Right.begin(), Last2 = Right.end();
while (First1 != Last1 && First2 != Last2) {
if (comp(*First2, *First1)) {
iterator Next = First2;
transfer(First1, Right, First2, ++Next);
First2 = Next;
} else {
++First1;
}
}
if (First2 != Last2)
transfer(Last1, Right, First2, Last2);
this->transferNodesFromList(Right, Right.begin(), Right.end());
base_list_type::merge(Right, comp);
}
void merge(iplist &Right) { return merge(Right, op_less); }
void merge(iplist_impl &Right) { return merge(Right, op_less); }
template <class Compare>
void sort(Compare comp) {
// The list is empty, vacuously sorted.
if (empty())
return;
// The list has a single element, vacuously sorted.
if (std::next(begin()) == end())
return;
// Find the split point for the list.
iterator Center = begin(), End = begin();
while (End != end() && std::next(End) != end()) {
Center = std::next(Center);
End = std::next(std::next(End));
}
// Split the list into two.
iplist RightHalf;
RightHalf.splice(RightHalf.begin(), *this, Center, end());
// Sort the two sublists.
sort(comp);
RightHalf.sort(comp);
// Merge the two sublists back together.
merge(RightHalf, comp);
}
void sort() { sort(op_less); }
using base_list_type::sort;
/// \brief Get the previous node, or \c nullptr for the list head.
NodeTy *getPrevNode(NodeTy &N) const {
pointer getPrevNode(reference N) const {
auto I = N.getIterator();
if (I == begin())
return nullptr;
return &*std::prev(I);
}
/// \brief Get the previous node, or \c nullptr for the list head.
const NodeTy *getPrevNode(const NodeTy &N) const {
return getPrevNode(const_cast<NodeTy &>(N));
const_pointer getPrevNode(const_reference N) const {
return getPrevNode(const_cast<reference >(N));
}
/// \brief Get the next node, or \c nullptr for the list tail.
NodeTy *getNextNode(NodeTy &N) const {
pointer getNextNode(reference N) const {
auto Next = std::next(N.getIterator());
if (Next == end())
return nullptr;
return &*Next;
}
/// \brief Get the next node, or \c nullptr for the list tail.
const NodeTy *getNextNode(const NodeTy &N) const {
return getNextNode(const_cast<NodeTy &>(N));
const_pointer getNextNode(const_reference N) const {
return getNextNode(const_cast<reference >(N));
}
};
/// An intrusive list with ownership and callbacks specified/controlled by
/// ilist_traits, only with API safe for polymorphic types.
///
/// The \p Options parameters are the same as those for \a simple_ilist. See
/// there for a description of what's available.
template <class T, class... Options>
class iplist
: public iplist_impl<simple_ilist<T, Options...>, ilist_traits<T>> {
typedef typename iplist::iplist_impl_type iplist_impl_type;
template<typename NodeTy>
struct ilist : public iplist<NodeTy> {
typedef typename iplist<NodeTy>::size_type size_type;
typedef typename iplist<NodeTy>::iterator iterator;
public:
iplist() = default;
ilist() {}
ilist(const ilist &right) : iplist<NodeTy>() {
insert(this->begin(), right.begin(), right.end());
iplist(const iplist &X) = delete;
iplist &operator=(const iplist &X) = delete;
iplist(iplist &&X) : iplist_impl_type(std::move(X)) {}
iplist &operator=(iplist &&X) {
*static_cast<iplist_impl_type *>(this) = std::move(X);
return *this;
}
explicit ilist(size_type count) {
insert(this->begin(), count, NodeTy());
}
ilist(size_type count, const NodeTy &val) {
insert(this->begin(), count, val);
}
template<class InIt> ilist(InIt first, InIt last) {
insert(this->begin(), first, last);
}
// bring hidden functions into scope
using iplist<NodeTy>::insert;
using iplist<NodeTy>::push_front;
using iplist<NodeTy>::push_back;
// Main implementation here - Insert for a node passed by value...
iterator insert(iterator where, const NodeTy &val) {
return insert(where, this->createNode(val));
}
// Front and back inserters...
void push_front(const NodeTy &val) { insert(this->begin(), val); }
void push_back(const NodeTy &val) { insert(this->end(), val); }
void insert(iterator where, size_type count, const NodeTy &val) {
for (; count != 0; --count) insert(where, val);
}
// Assign special forms...
void assign(size_type count, const NodeTy &val) {
iterator I = this->begin();
for (; I != this->end() && count != 0; ++I, --count)
*I = val;
if (count != 0)
insert(this->end(), val, val);
else
erase(I, this->end());
}
template<class InIt> void assign(InIt first1, InIt last1) {
iterator first2 = this->begin(), last2 = this->end();
for ( ; first1 != last1 && first2 != last2; ++first1, ++first2)
*first1 = *first2;
if (first2 == last2)
erase(first1, last1);
else
insert(last1, first2, last2);
}
// Resize members...
void resize(size_type newsize, NodeTy val) {
iterator i = this->begin();
size_type len = 0;
for ( ; i != this->end() && len < newsize; ++i, ++len) /* empty*/ ;
if (len == newsize)
erase(i, this->end());
else // i == end()
insert(this->end(), newsize - len, val);
}
void resize(size_type newsize) { resize(newsize, NodeTy()); }
};
} // End llvm namespace
template <class T, class... Options> using ilist = iplist<T, Options...>;
} // end namespace llvm
namespace std {
// Ensure that swap uses the fast list swap...
template<class Ty>
void swap(llvm::iplist<Ty> &Left, llvm::iplist<Ty> &Right) {
Left.swap(Right);
}
} // End 'std' extensions...
} // end namespace std
#endif // LLVM_ADT_ILIST_H

View File

@ -0,0 +1,95 @@
//===- llvm/ADT/ilist_base.h - Intrusive List Base ---------------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ILIST_BASE_H
#define LLVM_ADT_ILIST_BASE_H
#include "llvm/ADT/ilist_node_base.h"
#include <cassert>
#include <cstddef>
#include <type_traits>
namespace llvm {
/// Implementations of list algorithms using ilist_node_base.
template <bool EnableSentinelTracking> class ilist_base {
public:
typedef ilist_node_base<EnableSentinelTracking> node_base_type;
static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
node_base_type &Prev = *Next.getPrev();
N.setNext(&Next);
N.setPrev(&Prev);
Prev.setNext(&N);
Next.setPrev(&N);
}
static void removeImpl(node_base_type &N) {
node_base_type *Prev = N.getPrev();
node_base_type *Next = N.getNext();
Next->setPrev(Prev);
Prev->setNext(Next);
// Not strictly necessary, but helps catch a class of bugs.
N.setPrev(nullptr);
N.setNext(nullptr);
}
static void removeRangeImpl(node_base_type &First, node_base_type &Last) {
node_base_type *Prev = First.getPrev();
node_base_type *Final = Last.getPrev();
Last.setPrev(Prev);
Prev->setNext(&Last);
// Not strictly necessary, but helps catch a class of bugs.
First.setPrev(nullptr);
Final->setNext(nullptr);
}
static void transferBeforeImpl(node_base_type &Next, node_base_type &First,
node_base_type &Last) {
if (&Next == &Last || &First == &Last)
return;
// Position cannot be contained in the range to be transferred.
assert(&Next != &First &&
// Check for the most common mistake.
"Insertion point can't be one of the transferred nodes");
node_base_type &Final = *Last.getPrev();
// Detach from old list/position.
First.getPrev()->setNext(&Last);
Last.setPrev(First.getPrev());
// Splice [First, Final] into its new list/position.
node_base_type &Prev = *Next.getPrev();
Final.setNext(&Next);
First.setPrev(&Prev);
Prev.setNext(&First);
Next.setPrev(&Final);
}
template <class T> static void insertBefore(T &Next, T &N) {
insertBeforeImpl(Next, N);
}
template <class T> static void remove(T &N) { removeImpl(N); }
template <class T> static void removeRange(T &First, T &Last) {
removeRangeImpl(First, Last);
}
template <class T> static void transferBefore(T &Next, T &First, T &Last) {
transferBeforeImpl(Next, First, Last);
}
};
} // end namespace llvm
#endif // LLVM_ADT_ILIST_BASE_H

View File

@ -0,0 +1,185 @@
//===- llvm/ADT/ilist_iterator.h - Intrusive List Iterator -------*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ILIST_ITERATOR_H
#define LLVM_ADT_ILIST_ITERATOR_H
#include "llvm/ADT/ilist_node.h"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace llvm {
namespace ilist_detail {
/// Find const-correct node types.
template <class OptionsT, bool IsConst> struct IteratorTraits;
template <class OptionsT> struct IteratorTraits<OptionsT, false> {
typedef typename OptionsT::value_type value_type;
typedef typename OptionsT::pointer pointer;
typedef typename OptionsT::reference reference;
typedef ilist_node_impl<OptionsT> *node_pointer;
typedef ilist_node_impl<OptionsT> &node_reference;
};
template <class OptionsT> struct IteratorTraits<OptionsT, true> {
typedef const typename OptionsT::value_type value_type;
typedef typename OptionsT::const_pointer pointer;
typedef typename OptionsT::const_reference reference;
typedef const ilist_node_impl<OptionsT> *node_pointer;
typedef const ilist_node_impl<OptionsT> &node_reference;
};
template <bool IsReverse> struct IteratorHelper;
template <> struct IteratorHelper<false> : ilist_detail::NodeAccess {
typedef ilist_detail::NodeAccess Access;
template <class T> static void increment(T *&I) { I = Access::getNext(*I); }
template <class T> static void decrement(T *&I) { I = Access::getPrev(*I); }
};
template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
typedef ilist_detail::NodeAccess Access;
template <class T> static void increment(T *&I) { I = Access::getPrev(*I); }
template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
};
} // end namespace ilist_detail
/// Iterator for intrusive lists based on ilist_node.
template <class OptionsT, bool IsReverse, bool IsConst>
class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
typedef ilist_detail::IteratorTraits<OptionsT, IsConst> Traits;
typedef ilist_detail::SpecificNodeAccess<OptionsT> Access;
public:
typedef typename Traits::value_type value_type;
typedef typename Traits::pointer pointer;
typedef typename Traits::reference reference;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef typename OptionsT::const_pointer const_pointer;
typedef typename OptionsT::const_reference const_reference;
private:
typedef typename Traits::node_pointer node_pointer;
typedef typename Traits::node_reference node_reference;
node_pointer NodePtr;
public:
/// Create from an ilist_node.
explicit ilist_iterator(node_reference N) : NodePtr(&N) {}
explicit ilist_iterator(pointer NP) : NodePtr(Access::getNodePtr(NP)) {}
explicit ilist_iterator(reference NR) : NodePtr(Access::getNodePtr(&NR)) {}
ilist_iterator() : NodePtr(nullptr) {}
// This is templated so that we can allow constructing a const iterator from
// a nonconst iterator...
template <bool RHSIsConst>
ilist_iterator(
const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS,
typename std::enable_if<IsConst || !RHSIsConst, void *>::type = nullptr)
: NodePtr(RHS.NodePtr) {}
// This is templated so that we can allow assigning to a const iterator from
// a nonconst iterator...
template <bool RHSIsConst>
typename std::enable_if<IsConst || !RHSIsConst, ilist_iterator &>::type
operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) {
NodePtr = RHS.NodePtr;
return *this;
}
/// Convert from an iterator to its reverse.
///
/// TODO: Roll this into the implicit constructor once we're sure that no one
/// is relying on the std::reverse_iterator off-by-one semantics.
ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const {
if (NodePtr)
return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr);
return ilist_iterator<OptionsT, !IsReverse, IsConst>();
}
/// Const-cast.
ilist_iterator<OptionsT, IsReverse, false> getNonConst() const {
if (NodePtr)
return ilist_iterator<OptionsT, IsReverse, false>(
const_cast<typename ilist_iterator<OptionsT, IsReverse,
false>::node_reference>(*NodePtr));
return ilist_iterator<OptionsT, IsReverse, false>();
}
// Accessors...
reference operator*() const {
assert(!NodePtr->isKnownSentinel());
return *Access::getValuePtr(NodePtr);
}
pointer operator->() const { return &operator*(); }
// Comparison operators
friend bool operator==(const ilist_iterator &LHS, const ilist_iterator &RHS) {
return LHS.NodePtr == RHS.NodePtr;
}
friend bool operator!=(const ilist_iterator &LHS, const ilist_iterator &RHS) {
return LHS.NodePtr != RHS.NodePtr;
}
// Increment and decrement operators...
ilist_iterator &operator--() {
NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
return *this;
}
ilist_iterator &operator++() {
NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
return *this;
}
ilist_iterator operator--(int) {
ilist_iterator tmp = *this;
--*this;
return tmp;
}
ilist_iterator operator++(int) {
ilist_iterator tmp = *this;
++*this;
return tmp;
}
/// Get the underlying ilist_node.
node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
/// Check for end. Only valid if ilist_sentinel_tracking<true>.
bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; }
};
template <typename From> struct simplify_type;
/// Allow ilist_iterators to convert into pointers to a node automatically when
/// used by the dyn_cast, cast, isa mechanisms...
///
/// FIXME: remove this, since there is no implicit conversion to NodeTy.
template <class OptionsT, bool IsConst>
struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> {
typedef ilist_iterator<OptionsT, false, IsConst> iterator;
typedef typename iterator::pointer SimpleType;
static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
};
template <class OptionsT, bool IsConst>
struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>>
: simplify_type<ilist_iterator<OptionsT, false, IsConst>> {};
} // end namespace llvm
#endif // LLVM_ADT_ILIST_ITERATOR_H

View File

@ -15,65 +15,232 @@
#ifndef LLVM_ADT_ILIST_NODE_H
#define LLVM_ADT_ILIST_NODE_H
#include "llvm/ADT/ilist_node_base.h"
#include "llvm/ADT/ilist_node_options.h"
namespace llvm {
namespace ilist_detail {
struct NodeAccess;
} // end namespace ilist_detail
template<typename NodeTy>
struct ilist_traits;
template <typename NodeTy> struct ilist_embedded_sentinel_traits;
template <typename NodeTy> struct ilist_half_embedded_sentinel_traits;
/// ilist_half_node - Base class that provides prev services for sentinels.
template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
template <class OptionsT> class ilist_sentinel;
/// Implementation for an ilist node.
///
template<typename NodeTy>
class ilist_half_node {
friend struct ilist_traits<NodeTy>;
friend struct ilist_half_embedded_sentinel_traits<NodeTy>;
NodeTy *Prev;
protected:
NodeTy *getPrev() { return Prev; }
const NodeTy *getPrev() const { return Prev; }
void setPrev(NodeTy *P) { Prev = P; }
ilist_half_node() : Prev(nullptr) {}
};
template<typename NodeTy>
struct ilist_nextprev_traits;
template <typename NodeTy> class ilist_iterator;
/// ilist_node - Base class that provides next/prev services for nodes
/// that use ilist_nextprev_traits or ilist_default_traits.
/// Templated on an appropriate \a ilist_detail::node_options, usually computed
/// by \a ilist_detail::compute_node_options.
///
template<typename NodeTy>
class ilist_node : private ilist_half_node<NodeTy> {
friend struct ilist_nextprev_traits<NodeTy>;
friend struct ilist_traits<NodeTy>;
friend struct ilist_half_embedded_sentinel_traits<NodeTy>;
friend struct ilist_embedded_sentinel_traits<NodeTy>;
NodeTy *Next;
NodeTy *getNext() { return Next; }
const NodeTy *getNext() const { return Next; }
void setNext(NodeTy *N) { Next = N; }
/// This is a wrapper around \a ilist_node_base whose main purpose is to
/// provide type safety: you can't insert nodes of \a ilist_node_impl into the
/// wrong \a simple_ilist or \a iplist.
template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
typedef typename OptionsT::value_type value_type;
typedef typename OptionsT::node_base_type node_base_type;
typedef typename OptionsT::list_base_type list_base_type;
friend typename OptionsT::list_base_type;
friend struct ilist_detail::NodeAccess;
friend class ilist_sentinel<OptionsT>;
friend class ilist_iterator<OptionsT, false, false>;
friend class ilist_iterator<OptionsT, false, true>;
friend class ilist_iterator<OptionsT, true, false>;
friend class ilist_iterator<OptionsT, true, true>;
protected:
ilist_node() : Next(nullptr) {}
ilist_node_impl() = default;
typedef ilist_iterator<OptionsT, false, false> self_iterator;
typedef ilist_iterator<OptionsT, false, true> const_self_iterator;
typedef ilist_iterator<OptionsT, true, false> reverse_self_iterator;
typedef ilist_iterator<OptionsT, true, true> const_reverse_self_iterator;
private:
ilist_node_impl *getPrev() {
return static_cast<ilist_node_impl *>(node_base_type::getPrev());
}
ilist_node_impl *getNext() {
return static_cast<ilist_node_impl *>(node_base_type::getNext());
}
const ilist_node_impl *getPrev() const {
return static_cast<ilist_node_impl *>(node_base_type::getPrev());
}
const ilist_node_impl *getNext() const {
return static_cast<ilist_node_impl *>(node_base_type::getNext());
}
void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); }
void setNext(ilist_node_impl *N) { node_base_type::setNext(N); }
public:
ilist_iterator<NodeTy> getIterator() {
// FIXME: Stop downcasting to create the iterator (potential UB).
return ilist_iterator<NodeTy>(static_cast<NodeTy *>(this));
self_iterator getIterator() { return self_iterator(*this); }
const_self_iterator getIterator() const { return const_self_iterator(*this); }
reverse_self_iterator getReverseIterator() {
return reverse_self_iterator(*this);
}
ilist_iterator<const NodeTy> getIterator() const {
// FIXME: Stop downcasting to create the iterator (potential UB).
return ilist_iterator<const NodeTy>(static_cast<const NodeTy *>(this));
const_reverse_self_iterator getReverseIterator() const {
return const_reverse_self_iterator(*this);
}
// Under-approximation, but always available for assertions.
using node_base_type::isKnownSentinel;
/// Check whether this is the sentinel node.
///
/// This requires sentinel tracking to be explicitly enabled. Use the
/// ilist_sentinel_tracking<true> option to get this API.
bool isSentinel() const {
static_assert(OptionsT::is_sentinel_tracking_explicit,
"Use ilist_sentinel_tracking<true> to enable isSentinel()");
return node_base_type::isSentinel();
}
};
/// An intrusive list node.
///
/// A base class to enable membership in intrusive lists, including \a
/// simple_ilist, \a iplist, and \a ilist. The first template parameter is the
/// \a value_type for the list.
///
/// An ilist node can be configured with compile-time options to change
/// behaviour and/or add API.
///
/// By default, an \a ilist_node knows whether it is the list sentinel (an
/// instance of \a ilist_sentinel) if and only if
/// LLVM_ENABLE_ABI_BREAKING_CHECKS. The function \a isKnownSentinel() always
/// returns \c false tracking is off. Sentinel tracking steals a bit from the
/// "prev" link, which adds a mask operation when decrementing an iterator, but
/// enables bug-finding assertions in \a ilist_iterator.
///
/// To turn sentinel tracking on all the time, pass in the
/// ilist_sentinel_tracking<true> template parameter. This also enables the \a
/// isSentinel() function. The same option must be passed to the intrusive
/// list. (ilist_sentinel_tracking<false> turns sentinel tracking off all the
/// time.)
///
/// A type can inherit from ilist_node multiple times by passing in different
/// \a ilist_tag options. This allows a single instance to be inserted into
/// multiple lists simultaneously, where each list is given the same tag.
///
/// \example
/// struct A {};
/// struct B {};
/// struct N : ilist_node<N, ilist_tag<A>>, ilist_node<N, ilist_tag<B>> {};
///
/// void foo() {
/// simple_ilist<N, ilist_tag<A>> ListA;
/// simple_ilist<N, ilist_tag<B>> ListB;
/// N N1;
/// ListA.push_back(N1);
/// ListB.push_back(N1);
/// }
/// \endexample
///
/// See \a is_valid_option for steps on adding a new option.
template <class T, class... Options>
class ilist_node
: public ilist_node_impl<
typename ilist_detail::compute_node_options<T, Options...>::type> {
static_assert(ilist_detail::check_options<Options...>::value,
"Unrecognized node option!");
};
namespace ilist_detail {
/// An access class for ilist_node private API.
///
/// This gives access to the private parts of ilist nodes. Nodes for an ilist
/// should friend this class if they inherit privately from ilist_node.
///
/// Using this class outside of the ilist implementation is unsupported.
struct NodeAccess {
protected:
template <class OptionsT>
static ilist_node_impl<OptionsT> *getNodePtr(typename OptionsT::pointer N) {
return N;
}
template <class OptionsT>
static const ilist_node_impl<OptionsT> *
getNodePtr(typename OptionsT::const_pointer N) {
return N;
}
template <class OptionsT>
static typename OptionsT::pointer getValuePtr(ilist_node_impl<OptionsT> *N) {
return static_cast<typename OptionsT::pointer>(N);
}
template <class OptionsT>
static typename OptionsT::const_pointer
getValuePtr(const ilist_node_impl<OptionsT> *N) {
return static_cast<typename OptionsT::const_pointer>(N);
}
template <class OptionsT>
static ilist_node_impl<OptionsT> *getPrev(ilist_node_impl<OptionsT> &N) {
return N.getPrev();
}
template <class OptionsT>
static ilist_node_impl<OptionsT> *getNext(ilist_node_impl<OptionsT> &N) {
return N.getNext();
}
template <class OptionsT>
static const ilist_node_impl<OptionsT> *
getPrev(const ilist_node_impl<OptionsT> &N) {
return N.getPrev();
}
template <class OptionsT>
static const ilist_node_impl<OptionsT> *
getNext(const ilist_node_impl<OptionsT> &N) {
return N.getNext();
}
};
template <class OptionsT> struct SpecificNodeAccess : NodeAccess {
protected:
typedef typename OptionsT::pointer pointer;
typedef typename OptionsT::const_pointer const_pointer;
typedef ilist_node_impl<OptionsT> node_type;
static node_type *getNodePtr(pointer N) {
return NodeAccess::getNodePtr<OptionsT>(N);
}
static const node_type *getNodePtr(const_pointer N) {
return NodeAccess::getNodePtr<OptionsT>(N);
}
static pointer getValuePtr(node_type *N) {
return NodeAccess::getValuePtr<OptionsT>(N);
}
static const_pointer getValuePtr(const node_type *N) {
return NodeAccess::getValuePtr<OptionsT>(N);
}
};
} // end namespace ilist_detail
template <class OptionsT>
class ilist_sentinel : public ilist_node_impl<OptionsT> {
public:
ilist_sentinel() {
this->initializeSentinel();
reset();
}
void reset() {
this->setPrev(this);
this->setNext(this);
}
bool empty() const { return this == this->getPrev(); }
};
/// An ilist node that can access its parent list.
///
/// Requires \c NodeTy to have \a getParent() to find the parent node, and the
/// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
template <typename NodeTy, typename ParentTy>
class ilist_node_with_parent : public ilist_node<NodeTy> {
template <typename NodeTy, typename ParentTy, class... Options>
class ilist_node_with_parent : public ilist_node<NodeTy, Options...> {
protected:
ilist_node_with_parent() = default;

View File

@ -0,0 +1,53 @@
//===- llvm/ADT/ilist_node_base.h - Intrusive List Node Base -----*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ILIST_NODE_BASE_H
#define LLVM_ADT_ILIST_NODE_BASE_H
#include "llvm/ADT/PointerIntPair.h"
namespace llvm {
/// Base class for ilist nodes.
///
/// Optionally tracks whether this node is the sentinel.
template <bool EnableSentinelTracking> class ilist_node_base;
template <> class ilist_node_base<false> {
ilist_node_base *Prev = nullptr;
ilist_node_base *Next = nullptr;
public:
void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
void setNext(ilist_node_base *Next) { this->Next = Next; }
ilist_node_base *getPrev() const { return Prev; }
ilist_node_base *getNext() const { return Next; }
bool isKnownSentinel() const { return false; }
void initializeSentinel() {}
};
template <> class ilist_node_base<true> {
PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
ilist_node_base *Next = nullptr;
public:
void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
void setNext(ilist_node_base *Next) { this->Next = Next; }
ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
ilist_node_base *getNext() const { return Next; }
bool isSentinel() const { return PrevAndSentinel.getInt(); }
bool isKnownSentinel() const { return isSentinel(); }
void initializeSentinel() { PrevAndSentinel.setInt(true); }
};
} // end namespace llvm
#endif // LLVM_ADT_ILIST_NODE_BASE_H

View File

@ -0,0 +1,133 @@
//===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_ILIST_NODE_OPTIONS_H
#define LLVM_ADT_ILIST_NODE_OPTIONS_H
#include "llvm/Config/abi-breaking.h"
#include "llvm/Config/llvm-config.h"
#include <type_traits>
namespace llvm {
template <bool EnableSentinelTracking> class ilist_node_base;
template <bool EnableSentinelTracking> class ilist_base;
/// Option to choose whether to track sentinels.
///
/// This option affects the ABI for the nodes. When not specified explicitly,
/// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS. Specify explicitly to
/// enable \a ilist_node::isSentinel().
template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {};
/// Option to specify a tag for the node type.
///
/// This option allows a single value type to be inserted in multiple lists
/// simultaneously. See \a ilist_node for usage examples.
template <class Tag> struct ilist_tag {};
namespace ilist_detail {
/// Helper trait for recording whether an option is specified explicitly.
template <bool IsExplicit> struct explicitness {
static const bool is_explicit = IsExplicit;
};
typedef explicitness<true> is_explicit;
typedef explicitness<false> is_implicit;
/// Check whether an option is valid.
///
/// The steps for adding and enabling a new ilist option include:
/// \li define the option, ilist_foo<Bar>, above;
/// \li add new parameters for Bar to \a ilist_detail::node_options;
/// \li add an extraction meta-function, ilist_detail::extract_foo;
/// \li call extract_foo from \a ilist_detail::compute_node_options and pass it
/// into \a ilist_detail::node_options; and
/// \li specialize \c is_valid_option<ilist_foo<Bar>> to inherit from \c
/// std::true_type to get static assertions passing in \a simple_ilist and \a
/// ilist_node.
template <class Option> struct is_valid_option : std::false_type {};
/// Extract sentinel tracking option.
///
/// Look through \p Options for the \a ilist_sentinel_tracking option, with the
/// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS.
template <class... Options> struct extract_sentinel_tracking;
template <bool EnableSentinelTracking, class... Options>
struct extract_sentinel_tracking<
ilist_sentinel_tracking<EnableSentinelTracking>, Options...>
: std::integral_constant<bool, EnableSentinelTracking>, is_explicit {};
template <class Option1, class... Options>
struct extract_sentinel_tracking<Option1, Options...>
: extract_sentinel_tracking<Options...> {};
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {};
#else
template <>
struct extract_sentinel_tracking<> : std::false_type, is_implicit {};
#endif
template <bool EnableSentinelTracking>
struct is_valid_option<ilist_sentinel_tracking<EnableSentinelTracking>>
: std::true_type {};
/// Extract custom tag option.
///
/// Look through \p Options for the \a ilist_tag option, pulling out the
/// custom tag type, using void as a default.
template <class... Options> struct extract_tag;
template <class Tag, class... Options>
struct extract_tag<ilist_tag<Tag>, Options...> {
typedef Tag type;
};
template <class Option1, class... Options>
struct extract_tag<Option1, Options...> : extract_tag<Options...> {};
template <> struct extract_tag<> { typedef void type; };
template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {};
/// Check whether options are valid.
///
/// The conjunction of \a is_valid_option on each individual option.
template <class... Options> struct check_options;
template <> struct check_options<> : std::true_type {};
template <class Option1, class... Options>
struct check_options<Option1, Options...>
: std::integral_constant<bool, is_valid_option<Option1>::value &&
check_options<Options...>::value> {};
/// Traits for options for \a ilist_node.
///
/// This is usually computed via \a compute_node_options.
template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
class TagT>
struct node_options {
typedef T value_type;
typedef T *pointer;
typedef T &reference;
typedef const T *const_pointer;
typedef const T &const_reference;
static const bool enable_sentinel_tracking = EnableSentinelTracking;
static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
typedef TagT tag;
typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
typedef ilist_base<enable_sentinel_tracking> list_base_type;
};
template <class T, class... Options> struct compute_node_options {
typedef node_options<T, extract_sentinel_tracking<Options...>::value,
extract_sentinel_tracking<Options...>::is_explicit,
typename extract_tag<Options...>::type>
type;
};
} // end namespace ilist_detail
} // end namespace llvm
#endif // LLVM_ADT_ILIST_NODE_OPTIONS_H

View File

@ -12,6 +12,7 @@
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace llvm {
@ -256,6 +257,23 @@ struct pointee_iterator
T &operator*() const { return **this->I; }
};
}
template <typename WrappedIteratorT,
typename T = decltype(&*std::declval<WrappedIteratorT>())>
class pointer_iterator
: public iterator_adaptor_base<pointer_iterator<WrappedIteratorT>,
WrappedIteratorT, T> {
mutable T Ptr;
#endif
public:
pointer_iterator() = default;
explicit pointer_iterator(WrappedIteratorT u)
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
T &operator*() { return Ptr = &*this->I; }
const T &operator*() const { return Ptr = &*this->I; }
};
} // end namespace llvm
#endif // LLVM_ADT_ITERATOR_H

View File

@ -0,0 +1,310 @@
//===- llvm/ADT/simple_ilist.h - Simple Intrusive List ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_SIMPLE_ILIST_H
#define LLVM_ADT_SIMPLE_ILIST_H
#include "llvm/ADT/ilist_base.h"
#include "llvm/ADT/ilist_iterator.h"
#include "llvm/ADT/ilist_node.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
namespace llvm {
/// A simple intrusive list implementation.
///
/// This is a simple intrusive list for a \c T that inherits from \c
/// ilist_node<T>. The list never takes ownership of anything inserted in it.
///
/// Unlike \a iplist<T> and \a ilist<T>, \a simple_ilist<T> never allocates or
/// deletes values, and has no callback traits.
///
/// The API for adding nodes include \a push_front(), \a push_back(), and \a
/// insert(). These all take values by reference (not by pointer), except for
/// the range version of \a insert().
///
/// There are three sets of API for discarding nodes from the list: \a
/// remove(), which takes a reference to the node to remove, \a erase(), which
/// takes an iterator or iterator range and returns the next one, and \a
/// clear(), which empties out the container. All three are constant time
/// operations. None of these deletes any nodes; in particular, if there is a
/// single node in the list, then these have identical semantics:
/// \li \c L.remove(L.front());
/// \li \c L.erase(L.begin());
/// \li \c L.clear();
///
/// As a convenience for callers, there are parallel APIs that take a \c
/// Disposer (such as \c std::default_delete<T>): \a removeAndDispose(), \a
/// eraseAndDispose(), and \a clearAndDispose(). These have different names
/// because the extra semantic is otherwise non-obvious. They are equivalent
/// to calling \a std::for_each() on the range to be discarded.
///
/// The currently available \p Options customize the nodes in the list. The
/// same options must be specified in the \a ilist_node instantation for
/// compatibility (although the order is irrelevant).
/// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
/// list should use. This is useful if a type \p T is part of multiple,
/// independent lists simultaneously.
/// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
/// node is a sentinel. Specifying \c true enables the \a
/// ilist_node::isSentinel() API. Unlike \a ilist_node::isKnownSentinel(),
/// which is only appropriate for assertions, \a ilist_node::isSentinel() is
/// appropriate for real logic.
///
/// Here are examples of \p Options usage:
/// \li \c simple_ilist<T> gives the defaults. \li \c
/// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a
/// ilist_node::isSentinel() API.
/// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>>
/// specifies a tag of A and that tracking should be off (even when
/// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
/// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is
/// equivalent to the last.
///
/// See \a is_valid_option for steps on adding a new option.
template <typename T, class... Options>
class simple_ilist
: ilist_detail::compute_node_options<T, Options...>::type::list_base_type,
ilist_detail::SpecificNodeAccess<
typename ilist_detail::compute_node_options<T, Options...>::type> {
static_assert(ilist_detail::check_options<Options...>::value,
"Unrecognized node option!");
typedef
typename ilist_detail::compute_node_options<T, Options...>::type OptionsT;
typedef typename OptionsT::list_base_type list_base_type;
ilist_sentinel<OptionsT> Sentinel;
public:
typedef typename OptionsT::value_type value_type;
typedef typename OptionsT::pointer pointer;
typedef typename OptionsT::reference reference;
typedef typename OptionsT::const_pointer const_pointer;
typedef typename OptionsT::const_reference const_reference;
typedef ilist_iterator<OptionsT, false, false> iterator;
typedef ilist_iterator<OptionsT, false, true> const_iterator;
typedef ilist_iterator<OptionsT, true, false> reverse_iterator;
typedef ilist_iterator<OptionsT, true, true> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
simple_ilist() = default;
~simple_ilist() = default;
// No copy constructors.
simple_ilist(const simple_ilist &) = delete;
simple_ilist &operator=(const simple_ilist &) = delete;
// Move constructors.
simple_ilist(simple_ilist &&X) { splice(end(), X); }
simple_ilist &operator=(simple_ilist &&X) {
clear();
splice(end(), X);
return *this;
}
iterator begin() { return ++iterator(Sentinel); }
const_iterator begin() const { return ++const_iterator(Sentinel); }
iterator end() { return iterator(Sentinel); }
const_iterator end() const { return const_iterator(Sentinel); }
reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); }
const_reverse_iterator rbegin() const {
return ++const_reverse_iterator(Sentinel);
}
reverse_iterator rend() { return reverse_iterator(Sentinel); }
const_reverse_iterator rend() const {
return const_reverse_iterator(Sentinel);
}
/// Check if the list is empty in constant time.
LLVM_NODISCARD bool empty() const { return Sentinel.empty(); }
/// Calculate the size of the list in linear time.
LLVM_NODISCARD size_type size() const {
return std::distance(begin(), end());
}
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *rbegin(); }
const_reference back() const { return *rbegin(); }
/// Insert a node at the front; never copies.
void push_front(reference Node) { insert(begin(), Node); }
/// Insert a node at the back; never copies.
void push_back(reference Node) { insert(end(), Node); }
/// Remove the node at the front; never deletes.
void pop_front() { erase(begin()); }
/// Remove the node at the back; never deletes.
void pop_back() { erase(--end()); }
/// Swap with another list in place using std::swap.
void swap(simple_ilist &X) { std::swap(*this, X); }
/// Insert a node by reference; never copies.
iterator insert(iterator I, reference Node) {
list_base_type::insertBefore(*I.getNodePtr(), *this->getNodePtr(&Node));
return iterator(&Node);
}
/// Insert a range of nodes; never copies.
template <class Iterator>
void insert(iterator I, Iterator First, Iterator Last) {
for (; First != Last; ++First)
insert(I, *First);
}
/// Clone another list.
template <class Cloner, class Disposer>
void cloneFrom(const simple_ilist &L2, Cloner clone, Disposer dispose) {
clearAndDispose(dispose);
for (const_reference V : L2)
push_back(*clone(V));
}
/// Remove a node by reference; never deletes.
///
/// \see \a erase() for removing by iterator.
/// \see \a removeAndDispose() if the node should be deleted.
void remove(reference N) { list_base_type::remove(*this->getNodePtr(&N)); }
/// Remove a node by reference and dispose of it.
template <class Disposer>
void removeAndDispose(reference N, Disposer dispose) {
remove(N);
dispose(&N);
}
/// Remove a node by iterator; never deletes.
///
/// \see \a remove() for removing by reference.
/// \see \a eraseAndDispose() it the node should be deleted.
iterator erase(iterator I) {
assert(I != end() && "Cannot remove end of list!");
remove(*I++);
return I;
}
/// Remove a range of nodes; never deletes.
///
/// \see \a eraseAndDispose() if the nodes should be deleted.
iterator erase(iterator First, iterator Last) {
list_base_type::removeRange(*First.getNodePtr(), *Last.getNodePtr());
return Last;
}
/// Remove a node by iterator and dispose of it.
template <class Disposer>
iterator eraseAndDispose(iterator I, Disposer dispose) {
auto Next = std::next(I);
erase(I);
dispose(&*I);
return Next;
}
/// Remove a range of nodes and dispose of them.
template <class Disposer>
iterator eraseAndDispose(iterator First, iterator Last, Disposer dispose) {
while (First != Last)
First = eraseAndDispose(First, dispose);
return Last;
}
/// Clear the list; never deletes.
///
/// \see \a clearAndDispose() if the nodes should be deleted.
void clear() { Sentinel.reset(); }
/// Clear the list and dispose of the nodes.
template <class Disposer> void clearAndDispose(Disposer dispose) {
eraseAndDispose(begin(), end(), dispose);
}
/// Splice in another list.
void splice(iterator I, simple_ilist &L2) {
splice(I, L2, L2.begin(), L2.end());
}
/// Splice in a node from another list.
void splice(iterator I, simple_ilist &L2, iterator Node) {
splice(I, L2, Node, std::next(Node));
}
/// Splice in a range of nodes from another list.
void splice(iterator I, simple_ilist &, iterator First, iterator Last) {
list_base_type::transferBefore(*I.getNodePtr(), *First.getNodePtr(),
*Last.getNodePtr());
}
/// Merge in another list.
///
/// \pre \c this and \p RHS are sorted.
///@{
void merge(simple_ilist &RHS) { merge(RHS, std::less<T>()); }
template <class Compare> void merge(simple_ilist &RHS, Compare comp);
///@}
/// Sort the list.
///@{
void sort() { sort(std::less<T>()); }
template <class Compare> void sort(Compare comp);
///@}
};
template <class T, class... Options>
template <class Compare>
void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
if (this == &RHS || RHS.empty())
return;
iterator LI = begin(), LE = end();
iterator RI = RHS.begin(), RE = RHS.end();
while (LI != LE) {
if (comp(*RI, *LI)) {
// Transfer a run of at least size 1 from RHS to LHS.
iterator RunStart = RI++;
RI = std::find_if(RI, RE, [&](reference RV) { return !comp(RV, *LI); });
splice(LI, RHS, RunStart, RI);
if (RI == RE)
return;
}
++LI;
}
// Transfer the remaining RHS nodes once LHS is finished.
splice(LE, RHS, RI, RE);
}
template <class T, class... Options>
template <class Compare>
void simple_ilist<T, Options...>::sort(Compare comp) {
// Vacuously sorted.
if (empty() || std::next(begin()) == end())
return;
// Split the list in the middle.
iterator Center = begin(), End = begin();
while (End != end() && ++End != end()) {
++Center;
++End;
}
simple_ilist RHS;
RHS.splice(RHS.end(), *this, Center, end());
// Sort the sublists and merge back together.
sort(comp);
RHS.sort(comp);
merge(RHS, comp);
}
} // end namespace llvm
#endif // LLVM_ADT_SIMPLE_ILIST_H

View File

@ -112,8 +112,10 @@ enum FunctionModRefLocation {
FMRL_Nowhere = 0,
/// Access to memory via argument pointers.
FMRL_ArgumentPointees = 4,
/// Memory that is inaccessible via LLVM IR.
FMRL_InaccessibleMem = 8,
/// Access to any memory.
FMRL_Anywhere = 8 | FMRL_ArgumentPointees
FMRL_Anywhere = 16 | FMRL_InaccessibleMem | FMRL_ArgumentPointees
};
/// Summary of how a function affects memory in the program.
@ -143,6 +145,22 @@ enum FunctionModRefBehavior {
/// This property corresponds to the IntrArgMemOnly LLVM intrinsic flag.
FMRB_OnlyAccessesArgumentPointees = FMRL_ArgumentPointees | MRI_ModRef,
/// The only memory references in this function (if it has any) are
/// references of memory that is otherwise inaccessible via LLVM IR.
///
/// This property corresponds to the LLVM IR inaccessiblememonly attribute.
FMRB_OnlyAccessesInaccessibleMem = FMRL_InaccessibleMem | MRI_ModRef,
/// The function may perform non-volatile loads and stores of objects
/// pointed to by its pointer-typed arguments, with arbitrary offsets, and
/// it may also perform loads and stores of memory that is otherwise
/// inaccessible via LLVM IR.
///
/// This property corresponds to the LLVM IR
/// inaccessiblemem_or_argmemonly attribute.
FMRB_OnlyAccessesInaccessibleOrArgMem = FMRL_InaccessibleMem |
FMRL_ArgumentPointees | MRI_ModRef,
/// This function does not perform any non-local stores or volatile loads,
/// but may read from any memory location.
///
@ -179,6 +197,20 @@ class AAResults {
AAs.emplace_back(new Model<AAResultT>(AAResult, *this));
}
/// Register a function analysis ID that the results aggregation depends on.
///
/// This is used in the new pass manager to implement the invalidation logic
/// where we must invalidate the results aggregation if any of our component
/// analyses become invalid.
void addAADependencyID(AnalysisKey *ID) { AADeps.push_back(ID); }
/// Handle invalidation events in the new pass manager.
///
/// The aggregation is invalidated if any of the underlying analyses is
/// invalidated.
bool invalidate(Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv);
//===--------------------------------------------------------------------===//
/// \name Alias Queries
/// @{
@ -339,6 +371,26 @@ class AAResults {
return (MRB & MRI_ModRef) && (MRB & FMRL_ArgumentPointees);
}
/// Checks if functions with the specified behavior are known to read and
/// write at most from memory that is inaccessible from LLVM IR.
static bool onlyAccessesInaccessibleMem(FunctionModRefBehavior MRB) {
return !(MRB & FMRL_Anywhere & ~FMRL_InaccessibleMem);
}
/// Checks if functions with the specified behavior are known to potentially
/// read or write from memory that is inaccessible from LLVM IR.
static bool doesAccessInaccessibleMem(FunctionModRefBehavior MRB) {
return (MRB & MRI_ModRef) && (MRB & FMRL_InaccessibleMem);
}
/// Checks if functions with the specified behavior are known to read and
/// write at most from memory that is inaccessible from LLVM IR or objects
/// pointed to by their pointer-typed arguments (with arbitrary offsets).
static bool onlyAccessesInaccessibleOrArgMem(FunctionModRefBehavior MRB) {
return !(MRB & FMRL_Anywhere &
~(FMRL_InaccessibleMem | FMRL_ArgumentPointees));
}
/// getModRefInfo (for call sites) - Return information about whether
/// a particular call site modifies or reads the specified memory location.
ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc);
@ -571,6 +623,8 @@ class AAResults {
const TargetLibraryInfo &TLI;
std::vector<std::unique_ptr<Concept>> AAs;
std::vector<AnalysisKey *> AADeps;
};
/// Temporary typedef for legacy code that uses a generic \c AliasAnalysis
@ -854,20 +908,6 @@ class AAManager : public AnalysisInfoMixin<AAManager> {
public:
typedef AAResults Result;
// This type hase value semantics. We have to spell these out because MSVC
// won't synthesize them.
AAManager() {}
AAManager(AAManager &&Arg) : ResultGetters(std::move(Arg.ResultGetters)) {}
AAManager(const AAManager &Arg) : ResultGetters(Arg.ResultGetters) {}
AAManager &operator=(AAManager &&RHS) {
ResultGetters = std::move(RHS.ResultGetters);
return *this;
}
AAManager &operator=(const AAManager &RHS) {
ResultGetters = RHS.ResultGetters;
return *this;
}
/// Register a specific AA result.
template <typename AnalysisT> void registerFunctionAnalysis() {
ResultGetters.push_back(&getFunctionAAResultImpl<AnalysisT>);
@ -878,7 +918,7 @@ class AAManager : public AnalysisInfoMixin<AAManager> {
ResultGetters.push_back(&getModuleAAResultImpl<AnalysisT>);
}
Result run(Function &F, AnalysisManager<Function> &AM) {
Result run(Function &F, FunctionAnalysisManager &AM) {
Result R(AM.getResult<TargetLibraryAnalysis>(F));
for (auto &Getter : ResultGetters)
(*Getter)(F, AM, R);
@ -887,26 +927,30 @@ class AAManager : public AnalysisInfoMixin<AAManager> {
private:
friend AnalysisInfoMixin<AAManager>;
static char PassID;
static AnalysisKey Key;
SmallVector<void (*)(Function &F, AnalysisManager<Function> &AM,
SmallVector<void (*)(Function &F, FunctionAnalysisManager &AM,
AAResults &AAResults),
4> ResultGetters;
template <typename AnalysisT>
static void getFunctionAAResultImpl(Function &F,
AnalysisManager<Function> &AM,
FunctionAnalysisManager &AM,
AAResults &AAResults) {
AAResults.addAAResult(AM.template getResult<AnalysisT>(F));
AAResults.addAADependencyID(AnalysisT::ID());
}
template <typename AnalysisT>
static void getModuleAAResultImpl(Function &F, AnalysisManager<Function> &AM,
static void getModuleAAResultImpl(Function &F, FunctionAnalysisManager &AM,
AAResults &AAResults) {
auto &MAM =
AM.getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager();
if (auto *R = MAM.template getCachedResult<AnalysisT>(*F.getParent()))
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
auto &MAM = MAMProxy.getManager();
if (auto *R = MAM.template getCachedResult<AnalysisT>(*F.getParent())) {
AAResults.addAAResult(*R);
MAMProxy
.template registerOuterAnalysisInvalidation<AnalysisT, AAManager>();
}
}
};

View File

@ -53,7 +53,7 @@ class AAEvaluator : public PassInfoMixin<AAEvaluator> {
~AAEvaluator();
/// \brief Run the pass over the function.
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
private:
// Allow the legacy pass to run this using an internal API.

View File

@ -115,15 +115,21 @@ class AliasSet : public ilist_node<AliasSet> {
}
};
PointerRec *PtrList, **PtrListEnd; // Doubly linked list of nodes.
AliasSet *Forward; // Forwarding pointer.
// Doubly linked list of nodes.
PointerRec *PtrList, **PtrListEnd;
// Forwarding pointer.
AliasSet *Forward;
/// All instructions without a specific address in this alias set.
std::vector<AssertingVH<Instruction> > UnknownInsts;
/// Number of nodes pointing to this AliasSet plus the number of AliasSets
/// forwarding to it.
unsigned RefCount : 28;
unsigned RefCount : 27;
// Signifies that this set should be considered to alias any pointer.
// Use when the tracker holding this set is saturated.
unsigned AliasAny : 1;
/// The kinds of access this alias set models.
///
@ -153,7 +159,10 @@ class AliasSet : public ilist_node<AliasSet> {
/// True if this alias set contains volatile loads or stores.
unsigned Volatile : 1;
unsigned SetSize;
void addRef() { ++RefCount; }
void dropRef(AliasSetTracker &AST) {
assert(RefCount >= 1 && "Invalid reference count detected!");
if (--RefCount == 0)
@ -189,6 +198,10 @@ class AliasSet : public ilist_node<AliasSet> {
iterator end() const { return iterator(); }
bool empty() const { return PtrList == nullptr; }
// Unfortunately, ilist::size() is linear, so we have to add code to keep
// track of the list's exact size.
unsigned size() { return SetSize; }
void print(raw_ostream &OS) const;
void dump() const;
@ -226,13 +239,11 @@ class AliasSet : public ilist_node<AliasSet> {
};
private:
// Can only be created by AliasSetTracker. Also, ilist creates one
// to serve as a sentinel.
friend struct ilist_sentinel_traits<AliasSet>;
// Can only be created by AliasSetTracker.
AliasSet()
: PtrList(nullptr), PtrListEnd(&PtrList), Forward(nullptr), RefCount(0),
Access(NoAccess), Alias(SetMustAlias), Volatile(false) {
}
: PtrList(nullptr), PtrListEnd(&PtrList), Forward(nullptr), RefCount(0),
AliasAny(false), Access(NoAccess), Alias(SetMustAlias),
Volatile(false), SetSize(0) {}
AliasSet(const AliasSet &AS) = delete;
void operator=(const AliasSet &AS) = delete;
@ -317,7 +328,8 @@ class AliasSetTracker {
public:
/// Create an empty collection of AliasSets, and use the specified alias
/// analysis object to disambiguate load and store addresses.
explicit AliasSetTracker(AliasAnalysis &aa) : AA(aa) {}
explicit AliasSetTracker(AliasAnalysis &aa)
: AA(aa), TotalMayAliasSetSize(0), AliasAnyAS(nullptr) {}
~AliasSetTracker() { clear(); }
/// These methods are used to add different types of instructions to the alias
@ -332,27 +344,16 @@ class AliasSetTracker {
/// These methods return true if inserting the instruction resulted in the
/// addition of a new alias set (i.e., the pointer did not alias anything).
///
bool add(Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo); // Add a loc.
bool add(LoadInst *LI);
bool add(StoreInst *SI);
bool add(VAArgInst *VAAI);
bool add(MemSetInst *MSI);
bool add(Instruction *I); // Dispatch to one of the other add methods...
void add(Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo); // Add a loc.
void add(LoadInst *LI);
void add(StoreInst *SI);
void add(VAArgInst *VAAI);
void add(MemSetInst *MSI);
void add(MemTransferInst *MTI);
void add(Instruction *I); // Dispatch to one of the other add methods...
void add(BasicBlock &BB); // Add all instructions in basic block
void add(const AliasSetTracker &AST); // Add alias relations from another AST
bool addUnknown(Instruction *I);
/// These methods are used to remove all entries that might be aliased by the
/// specified instruction. These methods return true if any alias sets were
/// eliminated.
bool remove(Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo);
bool remove(LoadInst *LI);
bool remove(StoreInst *SI);
bool remove(VAArgInst *VAAI);
bool remove(MemSetInst *MSI);
bool remove(Instruction *I);
void remove(AliasSet &AS);
bool removeUnknown(Instruction *I);
void addUnknown(Instruction *I);
void clear();
@ -364,8 +365,7 @@ class AliasSetTracker {
/// set is created to contain the pointer (because the pointer didn't alias
/// anything).
AliasSet &getAliasSetForPointer(Value *P, uint64_t Size,
const AAMDNodes &AAInfo,
bool *New = nullptr);
const AAMDNodes &AAInfo);
/// Return the alias set containing the location specified if one exists,
/// otherwise return null.
@ -374,11 +374,6 @@ class AliasSetTracker {
return mergeAliasSetsForPointer(P, Size, AAInfo);
}
/// Return true if the specified location is represented by this alias set,
/// false otherwise. This does not modify the AST object or alias sets.
bool containsPointer(const Value *P, uint64_t Size,
const AAMDNodes &AAInfo) const;
/// Return true if the specified instruction "may" (or must) alias one of the
/// members in any of the sets.
bool containsUnknown(const Instruction *I) const;
@ -412,6 +407,14 @@ class AliasSetTracker {
private:
friend class AliasSet;
// The total number of pointers contained in all "may" alias sets.
unsigned TotalMayAliasSetSize;
// A non-null value signifies this AST is saturated. A saturated AST lumps
// all pointers into a single "May" set.
AliasSet *AliasAnyAS;
void removeAliasSet(AliasSet *AS);
/// Just like operator[] on the map, except that it creates an entry for the
@ -424,16 +427,14 @@ class AliasSetTracker {
}
AliasSet &addPointer(Value *P, uint64_t Size, const AAMDNodes &AAInfo,
AliasSet::AccessLattice E,
bool &NewSet) {
NewSet = false;
AliasSet &AS = getAliasSetForPointer(P, Size, AAInfo, &NewSet);
AS.Access |= E;
return AS;
}
AliasSet::AccessLattice E);
AliasSet *mergeAliasSetsForPointer(const Value *Ptr, uint64_t Size,
const AAMDNodes &AAInfo);
/// Merge all alias sets into a single set that is considered to alias any
/// pointer.
AliasSet &mergeAllAliasSets();
AliasSet *findAliasSetForUnknownInst(Instruction *Inst);
};

View File

@ -95,17 +95,11 @@ class AssumptionCache {
/// assumption caches for a given function.
class AssumptionAnalysis : public AnalysisInfoMixin<AssumptionAnalysis> {
friend AnalysisInfoMixin<AssumptionAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
typedef AssumptionCache Result;
AssumptionAnalysis() {}
AssumptionAnalysis(const AssumptionAnalysis &Arg) {}
AssumptionAnalysis(AssumptionAnalysis &&Arg) {}
AssumptionAnalysis &operator=(const AssumptionAnalysis &RHS) { return *this; }
AssumptionAnalysis &operator=(AssumptionAnalysis &&RHS) { return *this; }
AssumptionCache run(Function &F, FunctionAnalysisManager &) {
return AssumptionCache(F);
}
@ -117,7 +111,7 @@ class AssumptionPrinterPass : public PassInfoMixin<AssumptionPrinterPass> {
public:
explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief An immutable pass that tracks lazily created \c AssumptionCache

View File

@ -33,9 +33,10 @@ class LoopInfo;
/// This is the AA result object for the basic, local, and stateless alias
/// analysis. It implements the AA query interface in an entirely stateless
/// manner. As one consequence, it is never invalidated. While it does retain
/// some storage, that is used as an optimization and not to preserve
/// information from query to query.
/// manner. As one consequence, it is never invalidated due to IR changes.
/// While it does retain some storage, that is used as an optimization and not
/// to preserve information from query to query. However it does retain handles
/// to various other analyses and must be recomputed when those analyses are.
class BasicAAResult : public AAResultBase<BasicAAResult> {
friend AAResultBase<BasicAAResult>;
@ -58,10 +59,9 @@ class BasicAAResult : public AAResultBase<BasicAAResult> {
: AAResultBase(std::move(Arg)), DL(Arg.DL), TLI(Arg.TLI), AC(Arg.AC),
DT(Arg.DT), LI(Arg.LI) {}
/// Handle invalidation events from the new pass manager.
///
/// By definition, this result is stateless and so remains valid.
bool invalidate(Function &, const PreservedAnalyses &) { return false; }
/// Handle invalidation events in the new pass manager.
bool invalidate(Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv);
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB);
@ -185,25 +185,28 @@ class BasicAAResult : public AAResultBase<BasicAAResult> {
AliasResult aliasPHI(const PHINode *PN, uint64_t PNSize,
const AAMDNodes &PNAAInfo, const Value *V2,
uint64_t V2Size, const AAMDNodes &V2AAInfo);
uint64_t V2Size, const AAMDNodes &V2AAInfo,
const Value *UnderV2);
AliasResult aliasSelect(const SelectInst *SI, uint64_t SISize,
const AAMDNodes &SIAAInfo, const Value *V2,
uint64_t V2Size, const AAMDNodes &V2AAInfo);
uint64_t V2Size, const AAMDNodes &V2AAInfo,
const Value *UnderV2);
AliasResult aliasCheck(const Value *V1, uint64_t V1Size, AAMDNodes V1AATag,
const Value *V2, uint64_t V2Size, AAMDNodes V2AATag);
const Value *V2, uint64_t V2Size, AAMDNodes V2AATag,
const Value *O1 = nullptr, const Value *O2 = nullptr);
};
/// Analysis pass providing a never-invalidated alias analysis result.
class BasicAA : public AnalysisInfoMixin<BasicAA> {
friend AnalysisInfoMixin<BasicAA>;
static char PassID;
static AnalysisKey Key;
public:
typedef BasicAAResult Result;
BasicAAResult run(Function &F, AnalysisManager<Function> &AM);
BasicAAResult run(Function &F, FunctionAnalysisManager &AM);
};
/// Legacy wrapper pass to provide the BasicAAResult object.

View File

@ -61,6 +61,11 @@ class BlockFrequencyInfo {
/// the enclosing function's count (if available) and returns the value.
Optional<uint64_t> getBlockProfileCount(const BasicBlock *BB) const;
/// \brief Returns the estimated profile count of \p Freq.
/// This uses the frequency \p Freq and multiplies it by
/// the enclosing function's count (if available) and returns the value.
Optional<uint64_t> getProfileCountFromFreq(uint64_t Freq) const;
// Set the frequency of the given basic block.
void setBlockFreq(const BasicBlock *BB, uint64_t Freq);
@ -85,14 +90,14 @@ class BlockFrequencyInfo {
class BlockFrequencyAnalysis
: public AnalysisInfoMixin<BlockFrequencyAnalysis> {
friend AnalysisInfoMixin<BlockFrequencyAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
/// \brief Provide the result typedef for this analysis pass.
typedef BlockFrequencyInfo Result;
/// \brief Run the analysis pass over a function and produce BFI.
Result run(Function &F, AnalysisManager<Function> &AM);
Result run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Printer pass for the \c BlockFrequencyInfo results.
@ -102,7 +107,7 @@ class BlockFrequencyPrinterPass
public:
explicit BlockFrequencyPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Legacy analysis pass which computes \c BlockFrequencyInfo.

View File

@ -482,6 +482,8 @@ class BlockFrequencyInfoImplBase {
BlockFrequency getBlockFreq(const BlockNode &Node) const;
Optional<uint64_t> getBlockProfileCount(const Function &F,
const BlockNode &Node) const;
Optional<uint64_t> getProfileCountFromFreq(const Function &F,
uint64_t Freq) const;
void setBlockFreq(const BlockNode &Node, uint64_t Freq);
@ -925,6 +927,10 @@ template <class BT> class BlockFrequencyInfoImpl : BlockFrequencyInfoImplBase {
const BlockT *BB) const {
return BlockFrequencyInfoImplBase::getBlockProfileCount(F, getNode(BB));
}
Optional<uint64_t> getProfileCountFromFreq(const Function &F,
uint64_t Freq) const {
return BlockFrequencyInfoImplBase::getProfileCountFromFreq(F, Freq);
}
void setBlockFreq(const BlockT *BB, uint64_t Freq);
Scaled64 getFloatingBlockFreq(const BlockT *BB) const {
return BlockFrequencyInfoImplBase::getFloatingBlockFreq(getNode(BB));
@ -1245,7 +1251,7 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
: DefaultDOTGraphTraits(isSimple) {}
typedef GraphTraits<BlockFrequencyInfoT *> GTraits;
typedef typename GTraits::NodeType NodeType;
typedef typename GTraits::NodeRef NodeRef;
typedef typename GTraits::ChildIteratorType EdgeIter;
typedef typename GTraits::nodes_iterator NodeIter;
@ -1254,8 +1260,7 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
return G->getFunction()->getName();
}
std::string getNodeAttributes(const NodeType *Node,
const BlockFrequencyInfoT *Graph,
std::string getNodeAttributes(NodeRef Node, const BlockFrequencyInfoT *Graph,
unsigned HotPercentThreshold = 0) {
std::string Result;
if (!HotPercentThreshold)
@ -1266,9 +1271,9 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
for (NodeIter I = GTraits::nodes_begin(Graph),
E = GTraits::nodes_end(Graph);
I != E; ++I) {
NodeType &N = *I;
NodeRef N = *I;
MaxFrequency =
std::max(MaxFrequency, Graph->getBlockFreq(&N).getFrequency());
std::max(MaxFrequency, Graph->getBlockFreq(N).getFrequency());
}
}
BlockFrequency Freq = Graph->getBlockFreq(Node);
@ -1285,8 +1290,8 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
return Result;
}
std::string getNodeLabel(const NodeType *Node,
const BlockFrequencyInfoT *Graph, GVDAGType GType) {
std::string getNodeLabel(NodeRef Node, const BlockFrequencyInfoT *Graph,
GVDAGType GType) {
std::string Result;
raw_string_ostream OS(Result);
@ -1313,7 +1318,7 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
return Result;
}
std::string getEdgeAttributes(const NodeType *Node, EdgeIter EI,
std::string getEdgeAttributes(NodeRef Node, EdgeIter EI,
const BlockFrequencyInfoT *BFI,
const BranchProbabilityInfoT *BPI,
unsigned HotPercentThreshold = 0) {

View File

@ -178,14 +178,14 @@ class BranchProbabilityInfo {
class BranchProbabilityAnalysis
: public AnalysisInfoMixin<BranchProbabilityAnalysis> {
friend AnalysisInfoMixin<BranchProbabilityAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
/// \brief Provide the result typedef for this analysis pass.
typedef BranchProbabilityInfo Result;
/// \brief Run the analysis pass over a function and produce BPI.
BranchProbabilityInfo run(Function &F, AnalysisManager<Function> &AM);
BranchProbabilityInfo run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Printer pass for the \c BranchProbabilityAnalysis results.
@ -195,7 +195,7 @@ class BranchProbabilityPrinterPass
public:
explicit BranchProbabilityPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Legacy analysis pass which computes \c BranchProbabilityInfo.

View File

@ -7,6 +7,10 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines a 'dot-cfg' analysis pass, which emits the
// cfg.<fnname>.dot file for each function in the program, with a graph of the
// CFG for that function.
//
// This file defines external functions that can be called to explicitly
// instantiate the CFG printer.
//
@ -19,9 +23,34 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/GraphWriter.h"
namespace llvm {
class CFGViewerPass
: public PassInfoMixin<CFGViewerPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
class CFGOnlyViewerPass
: public PassInfoMixin<CFGOnlyViewerPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
class CFGPrinterPass
: public PassInfoMixin<CFGPrinterPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
class CFGOnlyPrinterPass
: public PassInfoMixin<CFGOnlyPrinterPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
template<>
struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
@ -118,13 +147,42 @@ struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
}
return "";
}
/// Display the raw branch weights from PGO.
std::string getEdgeAttributes(const BasicBlock *Node, succ_const_iterator I,
const Function *F) {
const TerminatorInst *TI = Node->getTerminator();
if (TI->getNumSuccessors() == 1)
return "";
MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof);
if (!WeightsNode)
return "";
MDString *MDName = cast<MDString>(WeightsNode->getOperand(0));
if (MDName->getString() != "branch_weights")
return "";
unsigned OpNo = I.getSuccessorIndex() + 1;
if (OpNo >= WeightsNode->getNumOperands())
return "";
ConstantInt *Weight =
mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo));
if (!Weight)
return "";
// Prepend a 'W' to indicate that this is a weight rather than the actual
// profile count (due to scaling).
Twine Attrs = "label=\"W:" + Twine(Weight->getZExtValue()) + "\"";
return Attrs.str();
}
};
} // End llvm namespace
namespace llvm {
class FunctionPass;
FunctionPass *createCFGPrinterPass ();
FunctionPass *createCFGOnlyPrinterPass ();
FunctionPass *createCFGPrinterLegacyPassPass ();
FunctionPass *createCFGOnlyPrinterLegacyPassPass ();
} // End llvm namespace
#endif

View File

@ -42,7 +42,10 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
/// Handle invalidation events from the new pass manager.
/// By definition, this result is stateless and so remains valid.
bool invalidate(Function &, const PreservedAnalyses &) { return false; }
bool invalidate(Function &, const PreservedAnalyses &,
FunctionAnalysisManager::Invalidator &) {
return false;
}
/// Evict the given function from cache
void evict(const Function &Fn);
@ -103,12 +106,12 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
/// in particular to leverage invalidation to trigger re-computation.
class CFLAndersAA : public AnalysisInfoMixin<CFLAndersAA> {
friend AnalysisInfoMixin<CFLAndersAA>;
static char PassID;
static AnalysisKey Key;
public:
typedef CFLAndersAAResult Result;
CFLAndersAAResult run(Function &F, AnalysisManager<Function> &AM);
CFLAndersAAResult run(Function &F, FunctionAnalysisManager &AM);
};
/// Legacy wrapper pass to provide the CFLAndersAAResult object.

View File

@ -45,7 +45,10 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
/// Handle invalidation events from the new pass manager.
///
/// By definition, this result is stateless and so remains valid.
bool invalidate(Function &, const PreservedAnalyses &) { return false; }
bool invalidate(Function &, const PreservedAnalyses &,
FunctionAnalysisManager::Invalidator &) {
return false;
}
/// \brief Inserts the given Function into the cache.
void scan(Function *Fn);
@ -81,16 +84,6 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
return QueryResult;
}
/// Get the location associated with a pointer argument of a callsite.
ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx);
/// Returns the behavior when calling the given call site.
FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS);
/// Returns the behavior when calling the given function. For use when the
/// call site is not known.
FunctionModRefBehavior getModRefBehavior(const Function *F);
private:
struct FunctionHandle final : public CallbackVH {
FunctionHandle(Function *Fn, CFLSteensAAResult *Result)
@ -132,12 +125,12 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
/// in particular to leverage invalidation to trigger re-computation of sets.
class CFLSteensAA : public AnalysisInfoMixin<CFLSteensAA> {
friend AnalysisInfoMixin<CFLSteensAA>;
static char PassID;
static AnalysisKey Key;
public:
typedef CFLSteensAAResult Result;
CFLSteensAAResult run(Function &F, AnalysisManager<Function> &AM);
CFLSteensAAResult run(Function &F, FunctionAnalysisManager &AM);
};
/// Legacy wrapper pass to provide the CFLSteensAAResult object.

View File

@ -11,49 +11,272 @@
/// This header provides classes for managing passes over SCCs of the call
/// graph. These passes form an important component of LLVM's interprocedural
/// optimizations. Because they operate on the SCCs of the call graph, and they
/// traverse the graph in post order, they can effectively do pair-wise
/// interprocedural optimizations for all call edges in the program. At each
/// call site edge, the callee has already been optimized as much as is
/// possible. This in turn allows very accurate analysis of it for IPO.
/// traverse the graph in post-order, they can effectively do pair-wise
/// interprocedural optimizations for all call edges in the program while
/// incrementally refining it and improving the context of these pair-wise
/// optimizations. At each call site edge, the callee has already been
/// optimized as much as is possible. This in turn allows very accurate
/// analysis of it for IPO.
///
/// A secondary more general goal is to be able to isolate optimization on
/// unrelated parts of the IR module. This is useful to ensure our
/// optimizations are principled and don't miss oportunities where refinement
/// of one part of the module influence transformations in another part of the
/// module. But this is also useful if we want to parallelize the optimizations
/// across common large module graph shapes which tend to be very wide and have
/// large regions of unrelated cliques.
///
/// To satisfy these goals, we use the LazyCallGraph which provides two graphs
/// nested inside each other (and built lazily from the bottom-up): the call
/// graph proper, and a reference graph. The reference graph is super set of
/// the call graph and is a conservative approximation of what could through
/// scalar or CGSCC transforms *become* the call graph. Using this allows us to
/// ensure we optimize functions prior to them being introduced into the call
/// graph by devirtualization or other technique, and thus ensures that
/// subsequent pair-wise interprocedural optimizations observe the optimized
/// form of these functions. The (potentially transitive) reference
/// reachability used by the reference graph is a conservative approximation
/// that still allows us to have independent regions of the graph.
///
/// FIXME: There is one major drawback of the reference graph: in its naive
/// form it is quadratic because it contains a distinct edge for each
/// (potentially indirect) reference, even if are all through some common
/// global table of function pointers. This can be fixed in a number of ways
/// that essentially preserve enough of the normalization. While it isn't
/// expected to completely preclude the usability of this, it will need to be
/// addressed.
///
///
/// All of these issues are made substantially more complex in the face of
/// mutations to the call graph while optimization passes are being run. When
/// mutations to the call graph occur we want to achieve two different things:
///
/// - We need to update the call graph in-flight and invalidate analyses
/// cached on entities in the graph. Because of the cache-based analysis
/// design of the pass manager, it is essential to have stable identities for
/// the elements of the IR that passes traverse, and to invalidate any
/// analyses cached on these elements as the mutations take place.
///
/// - We want to preserve the incremental and post-order traversal of the
/// graph even as it is refined and mutated. This means we want optimization
/// to observe the most refined form of the call graph and to do so in
/// post-order.
///
/// To address this, the CGSCC manager uses both worklists that can be expanded
/// by passes which transform the IR, and provides invalidation tests to skip
/// entries that become dead. This extra data is provided to every SCC pass so
/// that it can carefully update the manager's traversal as the call graph
/// mutates.
///
/// We also provide support for running function passes within the CGSCC walk,
/// and there we provide automatic update of the call graph including of the
/// pass manager to reflect call graph changes that fall out naturally as part
/// of scalar transformations.
///
/// The patterns used to ensure the goals of post-order visitation of the fully
/// refined graph:
///
/// 1) Sink toward the "bottom" as the graph is refined. This means that any
/// iteration continues in some valid post-order sequence after the mutation
/// has altered the structure.
///
/// 2) Enqueue in post-order, including the current entity. If the current
/// entity's shape changes, it and everything after it in post-order needs
/// to be visited to observe that shape.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H
#define LLVM_ANALYSIS_CGSCCPASSMANAGER_H
#include "llvm/ADT/PriorityWorklist.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/ValueHandle.h"
namespace llvm {
extern template class PassManager<LazyCallGraph::SCC>;
/// \brief The CGSCC pass manager.
///
/// See the documentation for the PassManager template for details. It runs
/// a sequency of SCC passes over each SCC that the manager is run over. This
/// typedef serves as a convenient way to refer to this construct.
typedef PassManager<LazyCallGraph::SCC> CGSCCPassManager;
struct CGSCCUpdateResult;
extern template class AnalysisManager<LazyCallGraph::SCC>;
/// Extern template declaration for the analysis set for this IR unit.
extern template class AllAnalysesOn<LazyCallGraph::SCC>;
extern template class AnalysisManager<LazyCallGraph::SCC, LazyCallGraph &>;
/// \brief The CGSCC analysis manager.
///
/// See the documentation for the AnalysisManager template for detail
/// documentation. This typedef serves as a convenient way to refer to this
/// construct in the adaptors and proxies used to integrate this into the larger
/// pass manager infrastructure.
typedef AnalysisManager<LazyCallGraph::SCC> CGSCCAnalysisManager;
typedef AnalysisManager<LazyCallGraph::SCC, LazyCallGraph &>
CGSCCAnalysisManager;
// Explicit specialization and instantiation declarations for the pass manager.
// See the comments on the definition of the specialization for details on how
// it differs from the primary template.
template <>
PreservedAnalyses
PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &,
CGSCCUpdateResult &>::run(LazyCallGraph::SCC &InitialC,
CGSCCAnalysisManager &AM,
LazyCallGraph &G, CGSCCUpdateResult &UR);
extern template class PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager,
LazyCallGraph &, CGSCCUpdateResult &>;
/// \brief The CGSCC pass manager.
///
/// See the documentation for the PassManager template for details. It runs
/// a sequency of SCC passes over each SCC that the manager is run over. This
/// typedef serves as a convenient way to refer to this construct.
typedef PassManager<LazyCallGraph::SCC, CGSCCAnalysisManager, LazyCallGraph &,
CGSCCUpdateResult &>
CGSCCPassManager;
/// An explicit specialization of the require analysis template pass.
template <typename AnalysisT>
struct RequireAnalysisPass<AnalysisT, LazyCallGraph::SCC, CGSCCAnalysisManager,
LazyCallGraph &, CGSCCUpdateResult &>
: PassInfoMixin<RequireAnalysisPass<AnalysisT, LazyCallGraph::SCC,
CGSCCAnalysisManager, LazyCallGraph &,
CGSCCUpdateResult &>> {
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
LazyCallGraph &CG, CGSCCUpdateResult &) {
(void)AM.template getResult<AnalysisT>(C, CG);
return PreservedAnalyses::all();
}
};
extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>;
/// A proxy from a \c CGSCCAnalysisManager to a \c Module.
typedef InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>
CGSCCAnalysisManagerModuleProxy;
extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
LazyCallGraph::SCC>;
/// We need a specialized result for the \c CGSCCAnalysisManagerModuleProxy so
/// it can have access to the call graph in order to walk all the SCCs when
/// invalidating things.
template <> class CGSCCAnalysisManagerModuleProxy::Result {
public:
explicit Result(CGSCCAnalysisManager &InnerAM, LazyCallGraph &G)
: InnerAM(&InnerAM), G(&G) {}
/// \brief Accessor for the analysis manager.
CGSCCAnalysisManager &getManager() { return *InnerAM; }
/// \brief Handler for invalidation of the Module.
///
/// If the proxy analysis itself is preserved, then we assume that the set of
/// SCCs in the Module hasn't changed. Thus any pointers to SCCs in the
/// CGSCCAnalysisManager are still valid, and we don't need to call \c clear
/// on the CGSCCAnalysisManager.
///
/// Regardless of whether this analysis is marked as preserved, all of the
/// analyses in the \c CGSCCAnalysisManager are potentially invalidated based
/// on the set of preserved analyses.
bool invalidate(Module &M, const PreservedAnalyses &PA,
ModuleAnalysisManager::Invalidator &Inv);
private:
CGSCCAnalysisManager *InnerAM;
LazyCallGraph *G;
};
/// Provide a specialized run method for the \c CGSCCAnalysisManagerModuleProxy
/// so it can pass the lazy call graph to the result.
template <>
CGSCCAnalysisManagerModuleProxy::Result
CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager &AM);
// Ensure the \c CGSCCAnalysisManagerModuleProxy is provided as an extern
// template.
extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>;
extern template class OuterAnalysisManagerProxy<
ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;
/// A proxy from a \c ModuleAnalysisManager to an \c SCC.
typedef OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC>
typedef OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC,
LazyCallGraph &>
ModuleAnalysisManagerCGSCCProxy;
/// Support structure for SCC passes to communicate updates the call graph back
/// to the CGSCC pass manager infrsatructure.
///
/// The CGSCC pass manager runs SCC passes which are allowed to update the call
/// graph and SCC structures. This means the structure the pass manager works
/// on is mutating underneath it. In order to support that, there needs to be
/// careful communication about the precise nature and ramifications of these
/// updates to the pass management infrastructure.
///
/// All SCC passes will have to accept a reference to the management layer's
/// update result struct and use it to reflect the results of any CG updates
/// performed.
///
/// Passes which do not change the call graph structure in any way can just
/// ignore this argument to their run method.
struct CGSCCUpdateResult {
/// Worklist of the RefSCCs queued for processing.
///
/// When a pass refines the graph and creates new RefSCCs or causes them to
/// have a different shape or set of component SCCs it should add the RefSCCs
/// to this worklist so that we visit them in the refined form.
///
/// This worklist is in reverse post-order, as we pop off the back in order
/// to observe RefSCCs in post-order. When adding RefSCCs, clients should add
/// them in reverse post-order.
SmallPriorityWorklist<LazyCallGraph::RefSCC *, 1> &RCWorklist;
/// Worklist of the SCCs queued for processing.
///
/// When a pass refines the graph and creates new SCCs or causes them to have
/// a different shape or set of component functions it should add the SCCs to
/// this worklist so that we visit them in the refined form.
///
/// Note that if the SCCs are part of a RefSCC that is added to the \c
/// RCWorklist, they don't need to be added here as visiting the RefSCC will
/// be sufficient to re-visit the SCCs within it.
///
/// This worklist is in reverse post-order, as we pop off the back in order
/// to observe SCCs in post-order. When adding SCCs, clients should add them
/// in reverse post-order.
SmallPriorityWorklist<LazyCallGraph::SCC *, 1> &CWorklist;
/// The set of invalidated RefSCCs which should be skipped if they are found
/// in \c RCWorklist.
///
/// This is used to quickly prune out RefSCCs when they get deleted and
/// happen to already be on the worklist. We use this primarily to avoid
/// scanning the list and removing entries from it.
SmallPtrSetImpl<LazyCallGraph::RefSCC *> &InvalidatedRefSCCs;
/// The set of invalidated SCCs which should be skipped if they are found
/// in \c CWorklist.
///
/// This is used to quickly prune out SCCs when they get deleted and happen
/// to already be on the worklist. We use this primarily to avoid scanning
/// the list and removing entries from it.
SmallPtrSetImpl<LazyCallGraph::SCC *> &InvalidatedSCCs;
/// If non-null, the updated current \c RefSCC being processed.
///
/// This is set when a graph refinement takes place an the "current" point in
/// the graph moves "down" or earlier in the post-order walk. This will often
/// cause the "current" RefSCC to be a newly created RefSCC object and the
/// old one to be added to the above worklist. When that happens, this
/// pointer is non-null and can be used to continue processing the "top" of
/// the post-order walk.
LazyCallGraph::RefSCC *UpdatedRC;
/// If non-null, the updated current \c SCC being processed.
///
/// This is set when a graph refinement takes place an the "current" point in
/// the graph moves "down" or earlier in the post-order walk. This will often
/// cause the "current" SCC to be a newly created SCC object and the old one
/// to be added to the above worklist. When that happens, this pointer is
/// non-null and can be used to continue processing the "top" of the
/// post-order walk.
LazyCallGraph::SCC *UpdatedC;
};
/// \brief The core module pass which does a post-order walk of the SCCs and
/// runs a CGSCC pass over each one.
///
@ -97,35 +320,129 @@ class ModuleToPostOrderCGSCCPassAdaptor
// Get the call graph for this module.
LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M);
// We keep worklists to allow us to push more work onto the pass manager as
// the passes are run.
SmallPriorityWorklist<LazyCallGraph::RefSCC *, 1> RCWorklist;
SmallPriorityWorklist<LazyCallGraph::SCC *, 1> CWorklist;
// Keep sets for invalidated SCCs and RefSCCs that should be skipped when
// iterating off the worklists.
SmallPtrSet<LazyCallGraph::RefSCC *, 4> InvalidRefSCCSet;
SmallPtrSet<LazyCallGraph::SCC *, 4> InvalidSCCSet;
CGSCCUpdateResult UR = {RCWorklist, CWorklist, InvalidRefSCCSet,
InvalidSCCSet, nullptr, nullptr};
PreservedAnalyses PA = PreservedAnalyses::all();
for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
if (DebugLogging)
dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n";
for (auto RCI = CG.postorder_ref_scc_begin(),
RCE = CG.postorder_ref_scc_end();
RCI != RCE;) {
assert(RCWorklist.empty() &&
"Should always start with an empty RefSCC worklist");
// The postorder_ref_sccs range we are walking is lazily constructed, so
// we only push the first one onto the worklist. The worklist allows us
// to capture *new* RefSCCs created during transformations.
//
// We really want to form RefSCCs lazily because that makes them cheaper
// to update as the program is simplified and allows us to have greater
// cache locality as forming a RefSCC touches all the parts of all the
// functions within that RefSCC.
//
// We also eagerly increment the iterator to the next position because
// the CGSCC passes below may delete the current RefSCC.
RCWorklist.insert(&*RCI++);
for (LazyCallGraph::SCC &C : RC) {
PreservedAnalyses PassPA = Pass.run(C, CGAM);
do {
LazyCallGraph::RefSCC *RC = RCWorklist.pop_back_val();
if (InvalidRefSCCSet.count(RC)) {
if (DebugLogging)
dbgs() << "Skipping an invalid RefSCC...\n";
continue;
}
// We know that the CGSCC pass couldn't have invalidated any other
// SCC's analyses (that's the contract of a CGSCC pass), so
// directly handle the CGSCC analysis manager's invalidation here. We
// also update the preserved set of analyses to reflect that invalidated
// analyses are now safe to preserve.
// FIXME: This isn't quite correct. We need to handle the case where the
// pass updated the CG, particularly some child of the current SCC, and
// invalidate its analyses.
PassPA = CGAM.invalidate(C, std::move(PassPA));
assert(CWorklist.empty() &&
"Should always start with an empty SCC worklist");
// Then intersect the preserved set so that invalidation of module
// analyses will eventually occur when the module pass completes.
PA.intersect(std::move(PassPA));
}
if (DebugLogging)
dbgs() << "Running an SCC pass across the RefSCC: " << *RC << "\n";
// Push the initial SCCs in reverse post-order as we'll pop off the the
// back and so see this in post-order.
for (LazyCallGraph::SCC &C : reverse(*RC))
CWorklist.insert(&C);
do {
LazyCallGraph::SCC *C = CWorklist.pop_back_val();
// Due to call graph mutations, we may have invalid SCCs or SCCs from
// other RefSCCs in the worklist. The invalid ones are dead and the
// other RefSCCs should be queued above, so we just need to skip both
// scenarios here.
if (InvalidSCCSet.count(C)) {
if (DebugLogging)
dbgs() << "Skipping an invalid SCC...\n";
continue;
}
if (&C->getOuterRefSCC() != RC) {
if (DebugLogging)
dbgs() << "Skipping an SCC that is now part of some other "
"RefSCC...\n";
continue;
}
do {
// Check that we didn't miss any update scenario.
assert(!InvalidSCCSet.count(C) && "Processing an invalid SCC!");
assert(C->begin() != C->end() && "Cannot have an empty SCC!");
assert(&C->getOuterRefSCC() == RC &&
"Processing an SCC in a different RefSCC!");
UR.UpdatedRC = nullptr;
UR.UpdatedC = nullptr;
PreservedAnalyses PassPA = Pass.run(*C, CGAM, CG, UR);
// We handle invalidating the CGSCC analysis manager's information
// for the (potentially updated) SCC here. Note that any other SCCs
// whose structure has changed should have been invalidated by
// whatever was updating the call graph. This SCC gets invalidated
// late as it contains the nodes that were actively being
// processed.
CGAM.invalidate(*(UR.UpdatedC ? UR.UpdatedC : C), PassPA);
// Then intersect the preserved set so that invalidation of module
// analyses will eventually occur when the module pass completes.
PA.intersect(std::move(PassPA));
// The pass may have restructured the call graph and refined the
// current SCC and/or RefSCC. We need to update our current SCC and
// RefSCC pointers to follow these. Also, when the current SCC is
// refined, re-run the SCC pass over the newly refined SCC in order
// to observe the most precise SCC model available. This inherently
// cannot cycle excessively as it only happens when we split SCCs
// apart, at most converging on a DAG of single nodes.
// FIXME: If we ever start having RefSCC passes, we'll want to
// iterate there too.
RC = UR.UpdatedRC ? UR.UpdatedRC : RC;
C = UR.UpdatedC ? UR.UpdatedC : C;
if (DebugLogging && UR.UpdatedC)
dbgs() << "Re-running SCC passes after a refinement of the "
"current SCC: "
<< *UR.UpdatedC << "\n";
// Note that both `C` and `RC` may at this point refer to deleted,
// invalid SCC and RefSCCs respectively. But we will short circuit
// the processing when we check them in the loop above.
} while (UR.UpdatedC);
} while (!CWorklist.empty());
} while (!RCWorklist.empty());
}
// By definition we preserve the proxy. This precludes *any* invalidation
// of CGSCC analyses by the proxy, but that's OK because we've taken
// care to invalidate analyses in the CGSCC analysis manager
// incrementally above.
// By definition we preserve the call garph, all SCC analyses, and the
// analysis proxies by handling them above and in any nested pass managers.
PA.preserveSet<AllAnalysesOn<LazyCallGraph::SCC>>();
PA.preserve<LazyCallGraphAnalysis>();
PA.preserve<CGSCCAnalysisManagerModuleProxy>();
PA.preserve<FunctionAnalysisManagerModuleProxy>();
return PA;
}
@ -142,17 +459,54 @@ createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = fal
return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass), DebugLogging);
}
extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
LazyCallGraph::SCC>;
/// A proxy from a \c FunctionAnalysisManager to an \c SCC.
typedef InnerAnalysisManagerProxy<FunctionAnalysisManager, LazyCallGraph::SCC>
FunctionAnalysisManagerCGSCCProxy;
///
/// When a module pass runs and triggers invalidation, both the CGSCC and
/// Function analysis manager proxies on the module get an invalidation event.
/// We don't want to fully duplicate responsibility for most of the
/// invalidation logic. Instead, this layer is only responsible for SCC-local
/// invalidation events. We work with the module's FunctionAnalysisManager to
/// invalidate function analyses.
class FunctionAnalysisManagerCGSCCProxy
: public AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy> {
public:
class Result {
public:
explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
/// \brief Accessor for the analysis manager.
FunctionAnalysisManager &getManager() { return *FAM; }
bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
CGSCCAnalysisManager::Invalidator &Inv);
private:
FunctionAnalysisManager *FAM;
};
/// Computes the \c FunctionAnalysisManager and stores it in the result proxy.
Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &);
private:
friend AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy>;
static AnalysisKey Key;
};
extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>;
/// A proxy from a \c CGSCCAnalysisManager to a \c Function.
typedef OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>
CGSCCAnalysisManagerFunctionProxy;
/// Helper to update the call graph after running a function pass.
///
/// Function passes can only mutate the call graph in specific ways. This
/// routine provides a helper that updates the call graph in those ways
/// including returning whether any changes were made and populating a CG
/// update result struct for the overall CGSCC walk.
LazyCallGraph::SCC &updateCGAndAnalysisManagerForFunctionPass(
LazyCallGraph &G, LazyCallGraph::SCC &C, LazyCallGraph::Node &N,
CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, bool DebugLogging = false);
/// \brief Adaptor that maps from a SCC to its functions.
///
/// Designed to allow composition of a FunctionPass(Manager) and
@ -185,37 +539,61 @@ class CGSCCToFunctionPassAdaptor
}
/// \brief Runs the function pass across every function in the module.
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
LazyCallGraph &CG, CGSCCUpdateResult &UR) {
// Setup the function analysis manager from its proxy.
FunctionAnalysisManager &FAM =
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
SmallVector<LazyCallGraph::Node *, 4> Nodes;
for (LazyCallGraph::Node &N : C)
Nodes.push_back(&N);
// The SCC may get split while we are optimizing functions due to deleting
// edges. If this happens, the current SCC can shift, so keep track of
// a pointer we can overwrite.
LazyCallGraph::SCC *CurrentC = &C;
if (DebugLogging)
dbgs() << "Running function passes across an SCC: " << C << "\n";
PreservedAnalyses PA = PreservedAnalyses::all();
for (LazyCallGraph::Node &N : C) {
PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM);
for (LazyCallGraph::Node *N : Nodes) {
// Skip nodes from other SCCs. These may have been split out during
// processing. We'll eventually visit those SCCs and pick up the nodes
// there.
if (CG.lookupSCC(*N) != CurrentC)
continue;
PreservedAnalyses PassPA = Pass.run(N->getFunction(), FAM);
// We know that the function pass couldn't have invalidated any other
// function's analyses (that's the contract of a function pass), so
// directly handle the function analysis manager's invalidation here.
// Also, update the preserved analyses to reflect that once invalidated
// these can again be preserved.
PassPA = FAM.invalidate(N.getFunction(), std::move(PassPA));
FAM.invalidate(N->getFunction(), PassPA);
// Then intersect the preserved set so that invalidation of module
// analyses will eventually occur when the module pass completes.
PA.intersect(std::move(PassPA));
// Update the call graph based on this function pass. This may also
// update the current SCC to point to a smaller, more refined SCC.
CurrentC = &updateCGAndAnalysisManagerForFunctionPass(
CG, *CurrentC, *N, AM, UR, DebugLogging);
assert(CG.lookupSCC(*N) == CurrentC &&
"Current SCC not updated to the SCC containing the current node!");
}
// By definition we preserve the proxy. This precludes *any* invalidation
// of function analyses by the proxy, but that's OK because we've taken
// care to invalidate analyses in the function analysis manager
// incrementally above.
// FIXME: We need to update the call graph here to account for any deleted
// edges!
// By definition we preserve the proxy. And we preserve all analyses on
// Functions. This precludes *any* invalidation of function analyses by the
// proxy, but that's OK because we've taken care to invalidate analyses in
// the function analysis manager incrementally above.
PA.preserveSet<AllAnalysesOn<Function>>();
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
// We've also ensured that we updated the call graph along the way.
PA.preserve<LazyCallGraphAnalysis>();
return PA;
}
@ -232,6 +610,185 @@ createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false)
return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass),
DebugLogging);
}
/// A helper that repeats an SCC pass each time an indirect call is refined to
/// a direct call by that pass.
///
/// While the CGSCC pass manager works to re-visit SCCs and RefSCCs as they
/// change shape, we may also want to repeat an SCC pass if it simply refines
/// an indirect call to a direct call, even if doing so does not alter the
/// shape of the graph. Note that this only pertains to direct calls to
/// functions where IPO across the SCC may be able to compute more precise
/// results. For intrinsics, we assume scalar optimizations already can fully
/// reason about them.
///
/// This repetition has the potential to be very large however, as each one
/// might refine a single call site. As a consequence, in practice we use an
/// upper bound on the number of repetitions to limit things.
template <typename PassT>
class DevirtSCCRepeatedPass
: public PassInfoMixin<DevirtSCCRepeatedPass<PassT>> {
public:
explicit DevirtSCCRepeatedPass(PassT Pass, int MaxIterations,
bool DebugLogging = false)
: Pass(std::move(Pass)), MaxIterations(MaxIterations),
DebugLogging(DebugLogging) {}
/// Runs the wrapped pass up to \c MaxIterations on the SCC, iterating
/// whenever an indirect call is refined.
PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM,
LazyCallGraph &CG, CGSCCUpdateResult &UR) {
PreservedAnalyses PA = PreservedAnalyses::all();
// The SCC may be refined while we are running passes over it, so set up
// a pointer that we can update.
LazyCallGraph::SCC *C = &InitialC;
// Collect value handles for all of the indirect call sites.
SmallVector<WeakVH, 8> CallHandles;
// Struct to track the counts of direct and indirect calls in each function
// of the SCC.
struct CallCount {
int Direct;
int Indirect;
};
// Put value handles on all of the indirect calls and return the number of
// direct calls for each function in the SCC.
auto ScanSCC = [](LazyCallGraph::SCC &C,
SmallVectorImpl<WeakVH> &CallHandles) {
assert(CallHandles.empty() && "Must start with a clear set of handles.");
SmallVector<CallCount, 4> CallCounts;
for (LazyCallGraph::Node &N : C) {
CallCounts.push_back({0, 0});
CallCount &Count = CallCounts.back();
for (Instruction &I : instructions(N.getFunction()))
if (auto CS = CallSite(&I)) {
if (CS.getCalledFunction()) {
++Count.Direct;
} else {
++Count.Indirect;
CallHandles.push_back(WeakVH(&I));
}
}
}
return CallCounts;
};
// Populate the initial call handles and get the initial call counts.
auto CallCounts = ScanSCC(*C, CallHandles);
for (int Iteration = 0;; ++Iteration) {
PreservedAnalyses PassPA = Pass.run(*C, AM, CG, UR);
// If the SCC structure has changed, bail immediately and let the outer
// CGSCC layer handle any iteration to reflect the refined structure.
if (UR.UpdatedC && UR.UpdatedC != C) {
PA.intersect(std::move(PassPA));
break;
}
// Check that we didn't miss any update scenario.
assert(!UR.InvalidatedSCCs.count(C) && "Processing an invalid SCC!");
assert(C->begin() != C->end() && "Cannot have an empty SCC!");
assert((int)CallCounts.size() == C->size() &&
"Cannot have changed the size of the SCC!");
// Check whether any of the handles were devirtualized.
auto IsDevirtualizedHandle = [&](WeakVH &CallH) {
if (!CallH)
return false;
auto CS = CallSite(CallH);
if (!CS)
return false;
// If the call is still indirect, leave it alone.
Function *F = CS.getCalledFunction();
if (!F)
return false;
if (DebugLogging)
dbgs() << "Found devirutalized call from "
<< CS.getParent()->getParent()->getName() << " to "
<< F->getName() << "\n";
// We now have a direct call where previously we had an indirect call,
// so iterate to process this devirtualization site.
return true;
};
bool Devirt = any_of(CallHandles, IsDevirtualizedHandle);
// Rescan to build up a new set of handles and count how many direct
// calls remain. If we decide to iterate, this also sets up the input to
// the next iteration.
CallHandles.clear();
auto NewCallCounts = ScanSCC(*C, CallHandles);
// If we haven't found an explicit devirtualization already see if we
// have decreased the number of indirect calls and increased the number
// of direct calls for any function in the SCC. This can be fooled by all
// manner of transformations such as DCE and other things, but seems to
// work well in practice.
if (!Devirt)
for (int i = 0, Size = C->size(); i < Size; ++i)
if (CallCounts[i].Indirect > NewCallCounts[i].Indirect &&
CallCounts[i].Direct < NewCallCounts[i].Direct) {
Devirt = true;
break;
}
if (!Devirt) {
PA.intersect(std::move(PassPA));
break;
}
// Otherwise, if we've already hit our max, we're done.
if (Iteration >= MaxIterations) {
if (DebugLogging)
dbgs() << "Found another devirtualization after hitting the max "
"number of repetitions ("
<< MaxIterations << ") on SCC: " << *C << "\n";
PA.intersect(std::move(PassPA));
break;
}
if (DebugLogging)
dbgs() << "Repeating an SCC pass after finding a devirtualization in: "
<< *C << "\n";
// Move over the new call counts in preparation for iterating.
CallCounts = std::move(NewCallCounts);
// Update the analysis manager with each run and intersect the total set
// of preserved analyses so we're ready to iterate.
AM.invalidate(*C, PassPA);
PA.intersect(std::move(PassPA));
}
// Note that we don't add any preserved entries here unlike a more normal
// "pass manager" because we only handle invalidation *between* iterations,
// not after the last iteration.
return PA;
}
private:
PassT Pass;
int MaxIterations;
bool DebugLogging;
};
/// \brief A function to deduce a function pass type and wrap it in the
/// templated adaptor.
template <typename PassT>
DevirtSCCRepeatedPass<PassT>
createDevirtSCCRepeatedPass(PassT Pass, int MaxIterations,
bool DebugLogging = false) {
return DevirtSCCRepeatedPass<PassT>(std::move(Pass), MaxIterations,
DebugLogging);
}
}
#endif

View File

@ -297,7 +297,7 @@ class CallGraphNode {
/// resulting data.
class CallGraphAnalysis : public AnalysisInfoMixin<CallGraphAnalysis> {
friend AnalysisInfoMixin<CallGraphAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
/// \brief A formulaic typedef to inform clients of the result type.
@ -315,7 +315,7 @@ class CallGraphPrinterPass : public PassInfoMixin<CallGraphPrinterPass> {
public:
explicit CallGraphPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Module &M, AnalysisManager<Module> &AM);
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
};
/// \brief The \c ModulePass which wraps up a \c CallGraph and the logic to
@ -409,94 +409,87 @@ class CallGraphWrapperPass : public ModulePass {
// Provide graph traits for tranversing call graphs using standard graph
// traversals.
template <> struct GraphTraits<CallGraphNode *> {
typedef CallGraphNode NodeType;
typedef CallGraphNode *NodeRef;
typedef CallGraphNode::CallRecord CGNPairTy;
typedef std::pointer_to_unary_function<CGNPairTy, CallGraphNode *>
CGNDerefFun;
static NodeType *getEntryNode(CallGraphNode *CGN) { return CGN; }
static NodeRef getEntryNode(CallGraphNode *CGN) { return CGN; }
typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType;
static CallGraphNode *CGNGetValue(CGNPairTy P) { return P.second; }
static inline ChildIteratorType child_begin(NodeType *N) {
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
typedef mapped_iterator<CallGraphNode::iterator, decltype(&CGNGetValue)>
ChildIteratorType;
static ChildIteratorType child_begin(NodeRef N) {
return ChildIteratorType(N->begin(), &CGNGetValue);
}
static inline ChildIteratorType child_end(NodeType *N) {
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
static ChildIteratorType child_end(NodeRef N) {
return ChildIteratorType(N->end(), &CGNGetValue);
}
static CallGraphNode *CGNDeref(CGNPairTy P) { return P.second; }
};
template <> struct GraphTraits<const CallGraphNode *> {
typedef const CallGraphNode NodeType;
typedef const CallGraphNode *NodeRef;
typedef CallGraphNode::CallRecord CGNPairTy;
typedef std::pointer_to_unary_function<CGNPairTy, const CallGraphNode *>
CGNDerefFun;
static NodeType *getEntryNode(const CallGraphNode *CGN) { return CGN; }
static NodeRef getEntryNode(const CallGraphNode *CGN) { return CGN; }
typedef mapped_iterator<NodeType::const_iterator, CGNDerefFun>
static const CallGraphNode *CGNGetValue(CGNPairTy P) { return P.second; }
typedef mapped_iterator<CallGraphNode::const_iterator, decltype(&CGNGetValue)>
ChildIteratorType;
static inline ChildIteratorType child_begin(NodeType *N) {
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
static ChildIteratorType child_begin(NodeRef N) {
return ChildIteratorType(N->begin(), &CGNGetValue);
}
static inline ChildIteratorType child_end(NodeType *N) {
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
static ChildIteratorType child_end(NodeRef N) {
return ChildIteratorType(N->end(), &CGNGetValue);
}
static const CallGraphNode *CGNDeref(CGNPairTy P) { return P.second; }
};
template <>
struct GraphTraits<CallGraph *> : public GraphTraits<CallGraphNode *> {
static NodeType *getEntryNode(CallGraph *CGN) {
static NodeRef getEntryNode(CallGraph *CGN) {
return CGN->getExternalCallingNode(); // Start at the external node!
}
typedef std::pair<const Function *const, std::unique_ptr<CallGraphNode>>
PairTy;
typedef std::pointer_to_unary_function<const PairTy &, CallGraphNode &>
DerefFun;
static CallGraphNode *CGGetValuePtr(const PairTy &P) {
return P.second.get();
}
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
typedef mapped_iterator<CallGraph::iterator, DerefFun> nodes_iterator;
typedef mapped_iterator<CallGraph::iterator, decltype(&CGGetValuePtr)>
nodes_iterator;
static nodes_iterator nodes_begin(CallGraph *CG) {
return map_iterator(CG->begin(), DerefFun(CGdereference));
return nodes_iterator(CG->begin(), &CGGetValuePtr);
}
static nodes_iterator nodes_end(CallGraph *CG) {
return map_iterator(CG->end(), DerefFun(CGdereference));
return nodes_iterator(CG->end(), &CGGetValuePtr);
}
static CallGraphNode &CGdereference(const PairTy &P) { return *P.second; }
};
template <>
struct GraphTraits<const CallGraph *> : public GraphTraits<
const CallGraphNode *> {
static NodeType *getEntryNode(const CallGraph *CGN) {
static NodeRef getEntryNode(const CallGraph *CGN) {
return CGN->getExternalCallingNode(); // Start at the external node!
}
typedef std::pair<const Function *const, std::unique_ptr<CallGraphNode>>
PairTy;
typedef std::pointer_to_unary_function<const PairTy &, const CallGraphNode &>
DerefFun;
static const CallGraphNode *CGGetValuePtr(const PairTy &P) {
return P.second.get();
}
// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
typedef mapped_iterator<CallGraph::const_iterator, DerefFun> nodes_iterator;
typedef mapped_iterator<CallGraph::const_iterator, decltype(&CGGetValuePtr)>
nodes_iterator;
static nodes_iterator nodes_begin(const CallGraph *CG) {
return map_iterator(CG->begin(), DerefFun(CGdereference));
return nodes_iterator(CG->begin(), &CGGetValuePtr);
}
static nodes_iterator nodes_end(const CallGraph *CG) {
return map_iterator(CG->end(), DerefFun(CGdereference));
}
static const CallGraphNode &CGdereference(const PairTy &P) {
return *P.second;
return nodes_iterator(CG->end(), &CGGetValuePtr);
}
};

View File

@ -94,8 +94,8 @@ class CallGraphSCC {
public:
CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {}
void initialize(CallGraphNode *const *I, CallGraphNode *const *E) {
Nodes.assign(I, E);
void initialize(ArrayRef<CallGraphNode *> NewNodes) {
Nodes.assign(NewNodes.begin(), NewNodes.end());
}
bool isSingular() const { return Nodes.size() == 1; }

View File

@ -87,7 +87,7 @@ struct CodeMetrics {
/// \brief Add information about a block to the current state.
void analyzeBasicBlock(const BasicBlock *BB, const TargetTransformInfo &TTI,
SmallPtrSetImpl<const Value*> &EphValues);
const SmallPtrSetImpl<const Value*> &EphValues);
/// \brief Collect a loop's ephemeral values (those used only by an assume
/// or similar intrinsics in the loop).

View File

@ -23,8 +23,10 @@
namespace llvm {
class APInt;
template <typename T> class ArrayRef;
class CallSite;
class Constant;
class ConstantExpr;
class ConstantVector;
class DataLayout;
class Function;
class GlobalValue;
@ -45,11 +47,10 @@ bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset,
Constant *ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr);
/// ConstantFoldConstantExpression - Attempt to fold the constant expression
/// using the specified DataLayout. If successful, the constant result is
/// result is returned, if not, null is returned.
Constant *
ConstantFoldConstantExpression(const ConstantExpr *CE, const DataLayout &DL,
/// ConstantFoldConstant - Attempt to fold the constant using the
/// specified DataLayout.
/// If successful, the constant result is returned, if not, null is returned.
Constant *ConstantFoldConstant(const Constant *C, const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr);
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
@ -62,19 +63,6 @@ Constant *ConstantFoldInstOperands(Instruction *I, ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr);
/// ConstantFoldInstOperands - Attempt to constant fold an instruction with the
/// specified operands. If successful, the constant result is returned, if not,
/// null is returned. Note that this function can fail when attempting to
/// fold instructions like loads and stores, which have no constant expression
/// form.
///
/// This function doesn't work for compares (use ConstantFoldCompareInstOperands
/// for this) and GEPs.
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
ArrayRef<Constant *> Ops,
const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr);
/// ConstantFoldCompareInstOperands - Attempt to constant fold a compare
/// instruction (icmp/fcmp) with the specified operands. If it fails, it
/// returns a constant expression of the specified operands.
@ -137,6 +125,10 @@ bool canConstantFoldCallTo(const Function *F);
/// with the specified arguments, returning null if unsuccessful.
Constant *ConstantFoldCall(Function *F, ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI = nullptr);
/// \brief Check whether the given call has no side-effects.
/// Specifically checks for math routimes which sometimes set errno.
bool isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI);
}
#endif

View File

@ -89,7 +89,7 @@ class DemandedBitsWrapperPass : public FunctionPass {
/// An analysis that produces \c DemandedBits for a function.
class DemandedBitsAnalysis : public AnalysisInfoMixin<DemandedBitsAnalysis> {
friend AnalysisInfoMixin<DemandedBitsAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
/// \brief Provide the result typedef for this analysis pass.
@ -97,7 +97,7 @@ class DemandedBitsAnalysis : public AnalysisInfoMixin<DemandedBitsAnalysis> {
/// \brief Run the analysis pass over a function and produce demanded bits
/// information.
DemandedBits run(Function &F, AnalysisManager<Function> &AM);
DemandedBits run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Printer pass for DemandedBits
@ -106,7 +106,7 @@ class DemandedBitsPrinterPass : public PassInfoMixin<DemandedBitsPrinterPass> {
public:
explicit DemandedBitsPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// Create a demanded bits analysis pass.

View File

@ -70,13 +70,8 @@ template <typename T> class ArrayRef;
/// itelf.
class Dependence {
protected:
Dependence(const Dependence &) = default;
// FIXME: When we move to MSVC 2015 as the base compiler for Visual Studio
// support, uncomment this line to allow a defaulted move constructor for
// Dependence. Currently, FullDependence relies on the copy constructor, but
// that is acceptable given the triviality of the class.
// Dependence(Dependence &&) = default;
Dependence(Dependence &&) = default;
Dependence &operator=(Dependence &&) = default;
public:
Dependence(Instruction *Source,
@ -222,11 +217,6 @@ template <typename T> class ArrayRef;
FullDependence(Instruction *Src, Instruction *Dst, bool LoopIndependent,
unsigned Levels);
FullDependence(FullDependence &&RHS)
: Dependence(std::move(RHS)), Levels(RHS.Levels),
LoopIndependent(RHS.LoopIndependent), Consistent(RHS.Consistent),
DV(std::move(RHS.DV)) {}
/// isLoopIndependent - Returns true if this is a loop-independent
/// dependence.
bool isLoopIndependent() const override { return LoopIndependent; }
@ -931,7 +921,7 @@ template <typename T> class ArrayRef;
Result run(Function &F, FunctionAnalysisManager &FAM);
private:
static char PassID;
static AnalysisKey Key;
friend struct AnalysisInfoMixin<DependenceAnalysis>;
}; // class DependenceAnalysis

View File

@ -171,14 +171,14 @@ extern template class ForwardDominanceFrontierBase<BasicBlock>;
class DominanceFrontierAnalysis
: public AnalysisInfoMixin<DominanceFrontierAnalysis> {
friend AnalysisInfoMixin<DominanceFrontierAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
/// \brief Provide the result typedef for this analysis pass.
typedef DominanceFrontier Result;
/// \brief Run the analysis pass over a function and produce a dominator tree.
DominanceFrontier run(Function &F, AnalysisManager<Function> &AM);
DominanceFrontier run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Printer pass for the \c DominanceFrontier.
@ -188,7 +188,7 @@ class DominanceFrontierPrinterPass
public:
explicit DominanceFrontierPrinterPass(raw_ostream &OS);
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
} // End llvm namespace

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"
namespace llvm {
@ -39,6 +40,10 @@ enum class EHPersonality {
/// Unknown.
EHPersonality classifyEHPersonality(const Value *Pers);
StringRef getEHPersonalityName(EHPersonality Pers);
EHPersonality getDefaultEHPersonality(const Triple &T);
/// \brief Returns true if this personality function catches asynchronous
/// exceptions.
inline bool isAsynchronousEHPersonality(EHPersonality Pers) {

View File

@ -120,12 +120,12 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> {
/// Analysis pass providing a never-invalidated alias analysis result.
class GlobalsAA : public AnalysisInfoMixin<GlobalsAA> {
friend AnalysisInfoMixin<GlobalsAA>;
static char PassID;
static AnalysisKey Key;
public:
typedef GlobalsAAResult Result;
GlobalsAAResult run(Module &M, AnalysisManager<Module> &AM);
GlobalsAAResult run(Module &M, ModuleAnalysisManager &AM);
};
/// Legacy wrapper pass to provide the GlobalsAAResult object.

View File

@ -16,6 +16,7 @@
#define LLVM_ANALYSIS_IVUSERS_H
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/LoopPassManager.h"
#include "llvm/Analysis/ScalarEvolutionNormalization.h"
#include "llvm/IR/ValueHandle.h"
@ -90,33 +91,6 @@ class IVStrideUse final : public CallbackVH, public ilist_node<IVStrideUse> {
void deleted() override;
};
template<> struct ilist_traits<IVStrideUse>
: public ilist_default_traits<IVStrideUse> {
// createSentinel is used to get hold of a node that marks the end of
// the list...
// The sentinel is relative to this instance, so we use a non-static
// method.
IVStrideUse *createSentinel() const {
// since i(p)lists always publicly derive from the corresponding
// traits, placing a data member in this class will augment i(p)list.
// But since the NodeTy is expected to publicly derive from
// ilist_node<NodeTy>, there is a legal viable downcast from it
// to NodeTy. We use this trick to superpose i(p)list with a "ghostly"
// NodeTy, which becomes the sentinel. Dereferencing the sentinel is
// forbidden (save the ilist_node<NodeTy>) so no one will ever notice
// the superposition.
return static_cast<IVStrideUse*>(&Sentinel);
}
static void destroySentinel(IVStrideUse*) {}
IVStrideUse *provideInitialHead() const { return createSentinel(); }
IVStrideUse *ensureHead(IVStrideUse*) const { return createSentinel(); }
static void noteHead(IVStrideUse*, IVStrideUse*) {}
private:
mutable ilist_node<IVStrideUse> Sentinel;
};
class IVUsers {
friend class IVStrideUse;
Loop *L;
@ -137,6 +111,17 @@ class IVUsers {
IVUsers(Loop *L, AssumptionCache *AC, LoopInfo *LI, DominatorTree *DT,
ScalarEvolution *SE);
IVUsers(IVUsers &&X)
: L(std::move(X.L)), AC(std::move(X.AC)), DT(std::move(X.DT)),
SE(std::move(X.SE)), Processed(std::move(X.Processed)),
IVUses(std::move(X.IVUses)), EphValues(std::move(X.EphValues)) {
for (IVStrideUse &U : IVUses)
U.Parent = this;
}
IVUsers(const IVUsers &) = delete;
IVUsers &operator=(IVUsers &&) = delete;
IVUsers &operator=(const IVUsers &) = delete;
Loop *getLoop() const { return L; }
/// AddUsersIfInteresting - Inspect the specified Instruction. If it is a
@ -203,12 +188,12 @@ class IVUsersWrapperPass : public LoopPass {
/// Analysis pass that exposes the \c IVUsers for a loop.
class IVUsersAnalysis : public AnalysisInfoMixin<IVUsersAnalysis> {
friend AnalysisInfoMixin<IVUsersAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
typedef IVUsers Result;
IVUsers run(Loop &L, AnalysisManager<Loop> &AM);
IVUsers run(Loop &L, LoopAnalysisManager &AM);
};
/// Printer pass for the \c IVUsers for a loop.
@ -217,7 +202,7 @@ class IVUsersPrinterPass : public PassInfoMixin<IVUsersPrinterPass> {
public:
explicit IVUsersPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM);
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM);
};
}

View File

@ -15,6 +15,7 @@
#define LLVM_ANALYSIS_INLINECOST_H
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/AssumptionCache.h"
#include <cassert>
#include <climits>
@ -27,16 +28,26 @@ class ProfileSummaryInfo;
class TargetTransformInfo;
namespace InlineConstants {
// Various magic constants used to adjust heuristics.
const int InstrCost = 5;
const int IndirectCallThreshold = 100;
const int CallPenalty = 25;
const int LastCallToStaticBonus = -15000;
const int ColdccPenalty = 2000;
const int NoreturnPenalty = 10000;
/// Do not inline functions which allocate this many bytes on the stack
/// when the caller is recursive.
const unsigned TotalAllocaSizeRecursiveCaller = 1024;
// Various thresholds used by inline cost analysis.
/// Use when optsize (-Os) is specified.
const int OptSizeThreshold = 50;
/// Use when minsize (-Oz) is specified.
const int OptMinSizeThreshold = 5;
/// Use when -O3 is specified.
const int OptAggressiveThreshold = 250;
// Various magic constants used to adjust heuristics.
const int InstrCost = 5;
const int IndirectCallThreshold = 100;
const int CallPenalty = 25;
const int LastCallToStaticBonus = 15000;
const int ColdccPenalty = 2000;
const int NoreturnPenalty = 10000;
/// Do not inline functions which allocate this many bytes on the stack
/// when the caller is recursive.
const unsigned TotalAllocaSizeRecursiveCaller = 1024;
}
/// \brief Represents the cost of inlining a function.
@ -99,6 +110,52 @@ class InlineCost {
int getCostDelta() const { return Threshold - getCost(); }
};
/// Thresholds to tune inline cost analysis. The inline cost analysis decides
/// the condition to apply a threshold and applies it. Otherwise,
/// DefaultThreshold is used. If a threshold is Optional, it is applied only
/// when it has a valid value. Typically, users of inline cost analysis
/// obtain an InlineParams object through one of the \c getInlineParams methods
/// and pass it to \c getInlineCost. Some specialized versions of inliner
/// (such as the pre-inliner) might have custom logic to compute \c InlineParams
/// object.
struct InlineParams {
/// The default threshold to start with for a callee.
int DefaultThreshold;
/// Threshold to use for callees with inline hint.
Optional<int> HintThreshold;
/// Threshold to use for cold callees.
Optional<int> ColdThreshold;
/// Threshold to use when the caller is optimized for size.
Optional<int> OptSizeThreshold;
/// Threshold to use when the caller is optimized for minsize.
Optional<int> OptMinSizeThreshold;
/// Threshold to use when the callsite is considered hot.
Optional<int> HotCallSiteThreshold;
};
/// Generate the parameters to tune the inline cost analysis based only on the
/// commandline options.
InlineParams getInlineParams();
/// Generate the parameters to tune the inline cost analysis based on command
/// line options. If -inline-threshold option is not explicitly passed,
/// \p Threshold is used as the default threshold.
InlineParams getInlineParams(int Threshold);
/// Generate the parameters to tune the inline cost analysis based on command
/// line options. If -inline-threshold option is not explicitly passed,
/// the default threshold is computed from \p OptLevel and \p SizeOptLevel.
/// An \p OptLevel value above 3 is considered an aggressive optimization mode.
/// \p SizeOptLevel of 1 corresponds to the the -Os flag and 2 corresponds to
/// the -Oz flag.
InlineParams getInlineParams(unsigned OptLevel, unsigned SizeOptLevel);
/// \brief Get an InlineCost object representing the cost of inlining this
/// callsite.
///
@ -110,23 +167,22 @@ class InlineCost {
///
/// Also note that calling this function *dynamically* computes the cost of
/// inlining the callsite. It is an expensive, heavyweight call.
InlineCost getInlineCost(CallSite CS, int DefaultThreshold,
TargetTransformInfo &CalleeTTI,
AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI);
InlineCost
getInlineCost(CallSite CS, const InlineParams &Params,
TargetTransformInfo &CalleeTTI,
std::function<AssumptionCache &(Function &)> &GetAssumptionCache,
ProfileSummaryInfo *PSI);
/// \brief Get an InlineCost with the callee explicitly specified.
/// This allows you to calculate the cost of inlining a function via a
/// pointer. This behaves exactly as the version with no explicit callee
/// parameter in all other respects.
//
InlineCost getInlineCost(CallSite CS, Function *Callee, int DefaultThreshold,
TargetTransformInfo &CalleeTTI,
AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI);
int computeThresholdFromOptLevels(unsigned OptLevel, unsigned SizeOptLevel);
/// \brief Return the default value of -inline-threshold.
int getDefaultInlineThreshold();
InlineCost
getInlineCost(CallSite CS, Function *Callee, const InlineParams &Params,
TargetTransformInfo &CalleeTTI,
std::function<AssumptionCache &(Function &)> &GetAssumptionCache,
ProfileSummaryInfo *PSI);
/// \brief Minimal filter to detect invalid constructs for inlining.
bool isInlineViable(Function &Callee);

View File

@ -238,12 +238,13 @@ namespace llvm {
AssumptionCache *AC = nullptr,
const Instruction *CxtI = nullptr);
/// Given operands for an TruncInst, fold the result or return null.
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL,
const TargetLibraryInfo *TLI = nullptr,
const DominatorTree *DT = nullptr,
AssumptionCache *AC = nullptr,
const Instruction *CxtI = nullptr);
/// Given operands for a CastInst, fold the result or return null.
Value *SimplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
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.

View File

@ -121,30 +121,22 @@ inline Interval::pred_iterator pred_end(Interval *I) {
}
template <> struct GraphTraits<Interval*> {
typedef Interval NodeType;
typedef Interval *NodeRef;
typedef Interval::succ_iterator ChildIteratorType;
static NodeType *getEntryNode(Interval *I) { return I; }
static NodeRef getEntryNode(Interval *I) { return I; }
/// nodes_iterator/begin/end - Allow iteration over all nodes in the graph
static inline ChildIteratorType child_begin(NodeType *N) {
return succ_begin(N);
}
static inline ChildIteratorType child_end(NodeType *N) {
return succ_end(N);
}
static ChildIteratorType child_begin(NodeRef N) { return succ_begin(N); }
static ChildIteratorType child_end(NodeRef N) { return succ_end(N); }
};
template <> struct GraphTraits<Inverse<Interval*> > {
typedef Interval NodeType;
typedef Interval *NodeRef;
typedef Interval::pred_iterator ChildIteratorType;
static NodeType *getEntryNode(Inverse<Interval *> G) { return G.Graph; }
static inline ChildIteratorType child_begin(NodeType *N) {
return pred_begin(N);
}
static inline ChildIteratorType child_end(NodeType *N) {
return pred_end(N);
}
static NodeRef getEntryNode(Inverse<Interval *> G) { return G.Graph; }
static ChildIteratorType child_begin(NodeRef N) { return pred_begin(N); }
static ChildIteratorType child_end(NodeRef N) { return pred_end(N); }
};
} // End llvm namespace

View File

@ -89,7 +89,6 @@ class IDFCalculator {
DenseMap<DomTreeNode *, unsigned> DomLevels;
const SmallPtrSetImpl<BasicBlock *> *LiveInBlocks;
const SmallPtrSetImpl<BasicBlock *> *DefBlocks;
SmallVector<BasicBlock *, 32> PHIBlocks;
};
typedef IDFCalculator<BasicBlock *> ForwardIDFCalculator;
typedef IDFCalculator<Inverse<BasicBlock *>> ReverseIDFCalculator;

View File

@ -18,6 +18,7 @@
#define LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/LazyBranchProbabilityInfo.h"
#include "llvm/Pass.h"
namespace llvm {
@ -57,21 +58,21 @@ class LazyBlockFrequencyInfoPass : public FunctionPass {
class LazyBlockFrequencyInfo {
public:
LazyBlockFrequencyInfo()
: Calculated(false), F(nullptr), BPI(nullptr), LI(nullptr) {}
: Calculated(false), F(nullptr), BPIPass(nullptr), LI(nullptr) {}
/// Set up the per-function input.
void setAnalysis(const Function *F, const BranchProbabilityInfo *BPI,
void setAnalysis(const Function *F, LazyBranchProbabilityInfoPass *BPIPass,
const LoopInfo *LI) {
this->F = F;
this->BPI = BPI;
this->BPIPass = BPIPass;
this->LI = LI;
}
/// Retrieve the BFI with the block frequencies computed.
BlockFrequencyInfo &getCalculated() {
if (!Calculated) {
assert(F && BPI && LI && "call setAnalysis");
BFI.calculate(*F, *BPI, *LI);
assert(F && BPIPass && LI && "call setAnalysis");
BFI.calculate(*F, BPIPass->getBPI(), *LI);
Calculated = true;
}
return BFI;
@ -91,7 +92,7 @@ class LazyBlockFrequencyInfoPass : public FunctionPass {
BlockFrequencyInfo BFI;
bool Calculated;
const Function *F;
const BranchProbabilityInfo *BPI;
LazyBranchProbabilityInfoPass *BPIPass;
const LoopInfo *LI;
};

View File

@ -0,0 +1,109 @@
//===- LazyBranchProbabilityInfo.h - Lazy Branch Probability ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is an alternative analysis pass to BranchProbabilityInfoWrapperPass.
// The difference is that with this pass the branch probabilities are not
// computed when the analysis pass is executed but rather when the BPI results
// is explicitly requested by the analysis client.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_LAZYBRANCHPROBABILITYINFO_H
#define LLVM_ANALYSIS_LAZYBRANCHPROBABILITYINFO_H
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Pass.h"
namespace llvm {
class AnalysisUsage;
class Function;
class LoopInfo;
/// \brief This is an alternative analysis pass to
/// BranchProbabilityInfoWrapperPass. The difference is that with this pass the
/// branch probabilities are not computed when the analysis pass is executed but
/// rather when the BPI results is explicitly requested by the analysis client.
///
/// There are some additional requirements for any client pass that wants to use
/// the analysis:
///
/// 1. The pass needs to initialize dependent passes with:
///
/// INITIALIZE_PASS_DEPENDENCY(LazyBPIPass)
///
/// 2. Similarly, getAnalysisUsage should call:
///
/// LazyBranchProbabilityInfoPass::getLazyBPIAnalysisUsage(AU)
///
/// 3. The computed BPI should be requested with
/// getAnalysis<LazyBranchProbabilityInfoPass>().getBPI() before LoopInfo
/// could be invalidated for example by changing the CFG.
///
/// Note that it is expected that we wouldn't need this functionality for the
/// new PM since with the new PM, analyses are executed on demand.
class LazyBranchProbabilityInfoPass : public FunctionPass {
/// Wraps a BPI to allow lazy computation of the branch probabilities.
///
/// A pass that only conditionally uses BPI can uncondtionally require the
/// analysis without paying for the overhead if BPI doesn't end up being used.
class LazyBranchProbabilityInfo {
public:
LazyBranchProbabilityInfo(const Function *F, const LoopInfo *LI)
: Calculated(false), F(F), LI(LI) {}
/// Retrieve the BPI with the branch probabilities computed.
BranchProbabilityInfo &getCalculated() {
if (!Calculated) {
assert(F && LI && "call setAnalysis");
BPI.calculate(*F, *LI);
Calculated = true;
}
return BPI;
}
const BranchProbabilityInfo &getCalculated() const {
return const_cast<LazyBranchProbabilityInfo *>(this)->getCalculated();
}
private:
BranchProbabilityInfo BPI;
bool Calculated;
const Function *F;
const LoopInfo *LI;
};
std::unique_ptr<LazyBranchProbabilityInfo> LBPI;
public:
static char ID;
LazyBranchProbabilityInfoPass();
/// \brief Compute and return the branch probabilities.
BranchProbabilityInfo &getBPI() { return LBPI->getCalculated(); }
/// \brief Compute and return the branch probabilities.
const BranchProbabilityInfo &getBPI() const { return LBPI->getCalculated(); }
void getAnalysisUsage(AnalysisUsage &AU) const override;
/// Helper for client passes to set up the analysis usage on behalf of this
/// pass.
static void getLazyBPIAnalysisUsage(AnalysisUsage &AU);
bool runOnFunction(Function &F) override;
void releaseMemory() override;
void print(raw_ostream &OS, const Module *M) const override;
};
/// \brief Helper for client passes to initialize dependent passes for LBPI.
void initializeLazyBPIPassPass(PassRegistry &Registry);
}
#endif

View File

@ -44,6 +44,7 @@
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
@ -149,6 +150,9 @@ class LazyCallGraph {
/// around but clear them.
operator bool() const;
/// Returnss the \c Kind of the edge.
Kind getKind() const;
/// Test whether the edge represents a direct call to a function.
///
/// This requires that the edge is not null.
@ -177,6 +181,7 @@ class LazyCallGraph {
private:
friend class LazyCallGraph::Node;
friend class LazyCallGraph::RefSCC;
PointerIntPair<PointerUnion<Function *, Node *>, 1, Kind> Value;
@ -194,6 +199,7 @@ class LazyCallGraph {
class Node {
friend class LazyCallGraph;
friend class LazyCallGraph::SCC;
friend class LazyCallGraph::RefSCC;
LazyCallGraph *G;
Function &F;
@ -223,6 +229,11 @@ class LazyCallGraph {
/// Internal helper to remove the edge to the given function.
void removeEdgeInternal(Function &ChildF);
void clear() {
Edges.clear();
EdgeIndexMap.clear();
}
/// Print the name of this node's function.
friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) {
return OS << N.F.getName();
@ -248,6 +259,11 @@ class LazyCallGraph {
}
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());
}
@ -410,6 +426,32 @@ class LazyCallGraph {
RefSCC &getOuterRefSCC() const { return *OuterRefSCC; }
/// Test if this SCC is a parent of \a C.
///
/// Note that this is linear in the number of edges departing the current
/// SCC.
bool isParentOf(const SCC &C) const;
/// Test if this SCC is an ancestor of \a C.
///
/// Note that in the worst case this is linear in the number of edges
/// departing the current SCC and every SCC in the entire graph reachable
/// from this SCC. Thus this very well may walk every edge in the entire
/// call graph! Do not call this in a tight loop!
bool isAncestorOf(const SCC &C) const;
/// Test if this SCC is a child of \a C.
///
/// See the comments for \c isParentOf for detailed notes about the
/// complexity of this routine.
bool isChildOf(const SCC &C) const { return C.isParentOf(*this); }
/// Test if this SCC is a descendant of \a C.
///
/// See the comments for \c isParentOf for detailed notes about the
/// complexity of this routine.
bool isDescendantOf(const SCC &C) const { return C.isAncestorOf(*this); }
/// Provide a short name by printing this SCC to a std::string.
///
/// This copes with the fact that we don't have a name per-se for an SCC
@ -453,6 +495,12 @@ class LazyCallGraph {
/// formRefSCCFast on the graph itself.
RefSCC(LazyCallGraph &G);
void clear() {
Parents.clear();
SCCs.clear();
SCCIndices.clear();
}
/// Print a short description useful for debugging or logging.
///
/// We print the SCCs wrapped in '[]'s and skipping the middle SCCs if
@ -494,6 +542,10 @@ class LazyCallGraph {
void verify();
#endif
/// Handle any necessary parent set updates after inserting a trivial ref
/// or call edge.
void handleTrivialEdgeInsertion(Node &SourceN, Node &TargetN);
public:
typedef pointee_iterator<SmallVectorImpl<SCC *>::const_iterator> iterator;
typedef iterator_range<iterator> range;
@ -518,7 +570,7 @@ class LazyCallGraph {
return make_range(parent_begin(), parent_end());
}
/// Test if this SCC is a parent of \a C.
/// Test if this RefSCC is a parent of \a C.
bool isParentOf(const RefSCC &C) const { return C.isChildOf(*this); }
/// Test if this RefSCC is an ancestor of \a C.
@ -532,9 +584,9 @@ class LazyCallGraph {
/// Test if this RefSCC is a descendant of \a C.
bool isDescendantOf(const RefSCC &C) const;
/// Provide a short name by printing this SCC to a std::string.
/// Provide a short name by printing this RefSCC to a std::string.
///
/// This copes with the fact that we don't have a name per-se for an SCC
/// This copes with the fact that we don't have a name per-se for an RefSCC
/// while still making the use of this in debugging and logging useful.
std::string getName() const {
std::string Name;
@ -548,7 +600,7 @@ class LazyCallGraph {
/// \name Mutation API
///
/// These methods provide the core API for updating the call graph in the
/// presence of a (potentially still in-flight) DFS-found SCCs.
/// presence of (potentially still in-flight) DFS-found RefSCCs and SCCs.
///
/// Note that these methods sometimes have complex runtimes, so be careful
/// how you call them.
@ -568,18 +620,34 @@ class LazyCallGraph {
SmallVector<SCC *, 1> switchInternalEdgeToCall(Node &SourceN,
Node &TargetN);
/// Make an existing internal call edge into a ref edge.
/// Make an existing internal call edge between separate SCCs into a ref
/// edge.
///
/// If SourceN and TargetN are part of a single SCC, it may be split up due
/// to breaking a cycle in the call edges that formed it. If that happens,
/// then this routine will insert new SCCs into the postorder list *before*
/// the SCC of TargetN (previously the SCC of both). This preserves
/// postorder as the TargetN can reach all of the other nodes by definition
/// of previously being in a single SCC formed by the cycle from SourceN to
/// TargetN. The newly added nodes are added *immediately* and contiguously
/// prior to the TargetN SCC and so they may be iterated starting from
/// there.
void switchInternalEdgeToRef(Node &SourceN, Node &TargetN);
/// If SourceN and TargetN in separate SCCs within this RefSCC, changing
/// the call edge between them to a ref edge is a trivial operation that
/// does not require any structural changes to the call graph.
void switchTrivialInternalEdgeToRef(Node &SourceN, Node &TargetN);
/// Make an existing internal call edge within a single SCC into a ref
/// edge.
///
/// Since SourceN and TargetN are part of a single SCC, this SCC may be
/// split up due to breaking a cycle in the call edges that formed it. If
/// that happens, then this routine will insert new SCCs into the postorder
/// list *before* the SCC of TargetN (previously the SCC of both). This
/// preserves postorder as the TargetN can reach all of the other nodes by
/// definition of previously being in a single SCC formed by the cycle from
/// SourceN to TargetN.
///
/// The newly added SCCs are added *immediately* and contiguously
/// prior to the TargetN SCC and return the range covering the new SCCs in
/// the RefSCC's postorder sequence. You can directly iterate the returned
/// range to observe all of the new SCCs in postorder.
///
/// Note that if SourceN and TargetN are in separate SCCs, the simpler
/// routine `switchTrivialInternalEdgeToRef` should be used instead.
iterator_range<iterator> switchInternalEdgeToRef(Node &SourceN,
Node &TargetN);
/// Make an existing outgoing ref edge into a call edge.
///
@ -699,15 +767,41 @@ class LazyCallGraph {
SmallVector<RefSCC *, 1> removeInternalRefEdge(Node &SourceN,
Node &TargetN);
/// A convenience wrapper around the above to handle trivial cases of
/// inserting a new call edge.
///
/// This is trivial whenever the target is in the same SCC as the source or
/// the edge is an outgoing edge to some descendant SCC. In these cases
/// there is no change to the cyclic structure of SCCs or RefSCCs.
///
/// To further make calling this convenient, it also handles inserting
/// already existing edges.
void insertTrivialCallEdge(Node &SourceN, Node &TargetN);
/// A convenience wrapper around the above to handle trivial cases of
/// inserting a new ref edge.
///
/// This is trivial whenever the target is in the same RefSCC as the source
/// or the edge is an outgoing edge to some descendant RefSCC. In these
/// cases there is no change to the cyclic structure of the RefSCCs.
///
/// To further make calling this convenient, it also handles inserting
/// already existing edges.
void insertTrivialRefEdge(Node &SourceN, Node &TargetN);
///@}
};
/// A post-order depth-first SCC iterator over the call graph.
/// A post-order depth-first RefSCC iterator over the call graph.
///
/// This iterator triggers the Tarjan DFS-based formation of the SCC DAG for
/// the call graph, walking it lazily in depth-first post-order. That is, it
/// always visits SCCs for a callee prior to visiting the SCC for a caller
/// (when they are in different SCCs).
/// 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.
class postorder_ref_scc_iterator
: public iterator_facade_base<postorder_ref_scc_iterator,
std::forward_iterator_tag, RefSCC> {
@ -718,27 +812,39 @@ class LazyCallGraph {
struct IsAtEndT {};
LazyCallGraph *G;
RefSCC *C;
RefSCC *RC;
// Build the begin iterator for a node.
postorder_ref_scc_iterator(LazyCallGraph &G) : G(&G) {
C = G.getNextRefSCCInPostOrder();
}
/// Build the begin iterator for a node.
postorder_ref_scc_iterator(LazyCallGraph &G) : G(&G), RC(getRC(G, 0)) {}
// Build the end iterator for a node. This is selected purely by overload.
/// Build the end iterator for a node. This is selected purely by overload.
postorder_ref_scc_iterator(LazyCallGraph &G, IsAtEndT /*Nonce*/)
: G(&G), C(nullptr) {}
: G(&G), RC(nullptr) {}
/// Get the post-order RefSCC at the given index of the postorder walk,
/// 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;
assert(Index < (int)G.PostOrderRefSCCs.size() &&
"Built the next post-order RefSCC without growing list!");
return G.PostOrderRefSCCs[Index];
}
public:
bool operator==(const postorder_ref_scc_iterator &Arg) const {
return G == Arg.G && C == Arg.C;
return G == Arg.G && RC == Arg.RC;
}
reference operator*() const { return *C; }
reference operator*() const { return *RC; }
using iterator_facade_base::operator++;
postorder_ref_scc_iterator &operator++() {
C = G->getNextRefSCCInPostOrder();
assert(RC && "Cannot increment the end iterator!");
RC = getRC(*G, G->RefSCCIndices.find(RC)->second + 1);
return *this;
}
};
@ -777,7 +883,7 @@ class LazyCallGraph {
/// Lookup a function's SCC in the graph.
///
/// \returns null if the function hasn't been assigned an SCC via the SCC
/// \returns null if the function hasn't been assigned an SCC via the RefSCC
/// iterator walk.
SCC *lookupSCC(Node &N) const { return SCCMap.lookup(&N); }
@ -809,8 +915,9 @@ class LazyCallGraph {
/// call graph. They can be used to update the core node-graph during
/// a node-based inorder traversal that precedes any SCC-based traversal.
///
/// Once you begin manipulating a call graph's SCCs, you must perform all
/// mutation of the graph via the SCC methods.
/// Once you begin manipulating a call graph's SCCs, most mutation of the
/// graph must be performed via a RefSCC method. There are some exceptions
/// below.
/// Update the call graph after inserting a new edge.
void insertEdge(Node &Caller, Function &Callee, Edge::Kind EK);
@ -830,6 +937,72 @@ class LazyCallGraph {
///@}
///@{
/// \name General Mutation API
///
/// There are a very limited set of mutations allowed on the graph as a whole
/// once SCCs have started to be formed. These routines have strict contracts
/// but may be called at any point.
/// Remove a dead function from the call graph (typically to delete it).
///
/// Note that the function must have an empty use list, and the call graph
/// must be up-to-date prior to calling this. That means it is by itself in
/// a maximal SCC which is by itself in a maximal RefSCC, etc. No structural
/// changes result from calling this routine other than potentially removing
/// entry points into the call graph.
///
/// If SCC formation has begun, this function must not be part of the current
/// DFS in order to call this safely. Typically, the function will have been
/// fully visited by the DFS prior to calling this routine.
void removeDeadFunction(Function &F);
///@}
///@{
/// \name Static helpers for code doing updates to the call graph.
///
/// These helpers are used to implement parts of the call graph but are also
/// useful to code doing updates or otherwise wanting to walk the IR in the
/// same patterns as when we build the call graph.
/// Recursively visits the defined functions whose address is reachable from
/// every constant in the \p Worklist.
///
/// Doesn't recurse through any constants already in the \p Visited set, and
/// updates that set with every constant visited.
///
/// For each defined function, calls \p Callback with that function.
template <typename CallbackT>
static void visitReferences(SmallVectorImpl<Constant *> &Worklist,
SmallPtrSetImpl<Constant *> &Visited,
CallbackT Callback) {
while (!Worklist.empty()) {
Constant *C = Worklist.pop_back_val();
if (Function *F = dyn_cast<Function>(C)) {
if (!F->isDeclaration())
Callback(*F);
continue;
}
if (BlockAddress *BA = dyn_cast<BlockAddress>(C)) {
// The blockaddress constant expression is a weird special case, we
// can't generically walk its operands the way we do for all other
// constants.
if (Visited.insert(BA->getFunction()).second)
Worklist.push_back(BA->getFunction());
continue;
}
for (Value *Op : C->operand_values())
if (Visited.insert(cast<Constant>(Op)).second)
Worklist.push_back(cast<Constant>(Op));
}
}
///@}
private:
typedef SmallVectorImpl<Node *>::reverse_iterator node_stack_iterator;
typedef iterator_range<node_stack_iterator> node_stack_range;
@ -858,6 +1031,15 @@ class LazyCallGraph {
/// Allocator that holds all the call graph RefSCCs.
SpecificBumpPtrAllocator<RefSCC> RefSCCBPA;
/// The post-order sequence of RefSCCs.
///
/// This list is lazily formed the first time we walk the graph.
SmallVector<RefSCC *, 16> PostOrderRefSCCs;
/// A map from RefSCC to the index for it in the postorder sequence of
/// RefSCCs.
DenseMap<RefSCC *, int> RefSCCIndices;
/// The leaf RefSCCs of the graph.
///
/// These are all of the RefSCCs which have no children.
@ -869,7 +1051,7 @@ class LazyCallGraph {
/// Set of entry nodes not-yet-processed into RefSCCs.
SmallVector<Function *, 4> RefSCCEntryNodes;
/// Stack of nodes the DFS has walked but not yet put into a SCC.
/// 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.
@ -905,8 +1087,24 @@ class LazyCallGraph {
/// and updates the root leaf list.
void connectRefSCC(RefSCC &RC);
/// Retrieve the next node in the post-order RefSCC walk of the call graph.
RefSCC *getNextRefSCCInPostOrder();
/// Get the index of a RefSCC within the postorder traversal.
///
/// Requires that this RefSCC is a valid one in the (perhaps partial)
/// postorder traversed part of the graph.
int getRefSCCIndex(RefSCC &RC) {
auto IndexIt = RefSCCIndices.find(&RC);
assert(IndexIt != RefSCCIndices.end() && "RefSCC doesn't have an index!");
assert(PostOrderRefSCCs[IndexIt->second] == &RC &&
"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() {}
@ -917,9 +1115,14 @@ inline LazyCallGraph::Edge::operator bool() const {
return !Value.getPointer().isNull();
}
inline LazyCallGraph::Edge::Kind LazyCallGraph::Edge::getKind() const {
assert(*this && "Queried a null edge!");
return Value.getInt();
}
inline bool LazyCallGraph::Edge::isCall() const {
assert(*this && "Queried a null edge!");
return Value.getInt() == Call;
return getKind() == Call;
}
inline Function &LazyCallGraph::Edge::getFunction() const {
@ -953,26 +1156,26 @@ inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode(LazyCallGraph &G) {
// Provide GraphTraits specializations for call graphs.
template <> struct GraphTraits<LazyCallGraph::Node *> {
typedef LazyCallGraph::Node NodeType;
typedef LazyCallGraph::Node *NodeRef;
typedef LazyCallGraph::edge_iterator ChildIteratorType;
static NodeType *getEntryNode(NodeType *N) { return N; }
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
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(); }
};
template <> struct GraphTraits<LazyCallGraph *> {
typedef LazyCallGraph::Node NodeType;
typedef LazyCallGraph::Node *NodeRef;
typedef LazyCallGraph::edge_iterator ChildIteratorType;
static NodeType *getEntryNode(NodeType *N) { return N; }
static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
static ChildIteratorType child_end(NodeType *N) { return N->end(); }
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(); }
};
/// An analysis pass which computes the call graph for a module.
class LazyCallGraphAnalysis : public AnalysisInfoMixin<LazyCallGraphAnalysis> {
friend AnalysisInfoMixin<LazyCallGraphAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
/// Inform generic clients of the result type.

View File

@ -109,7 +109,7 @@ class LazyValueAnalysis : public AnalysisInfoMixin<LazyValueAnalysis> {
Result run(Function &F, FunctionAnalysisManager &FAM);
private:
static char PassID;
static AnalysisKey Key;
friend struct AnalysisInfoMixin<LazyValueAnalysis>;
};

View File

@ -71,15 +71,13 @@ extern cl::opt<unsigned> DefMaxInstsToScan;
/// the only relevant load gets deleted.)
///
/// \param Load The load we want to replace.
/// \param ScanBB The basic block to scan. FIXME: This is redundant.
/// \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] AATags The aliasing metadata for the operation which produced
/// the value. FIXME: This is basically useless.
/// \param [out] IsLoadCSE Whether the returned value is a load from the same
/// location in memory, as opposed to the value operand of a store.
///
@ -89,7 +87,6 @@ Value *FindAvailableLoadedValue(LoadInst *Load,
BasicBlock::iterator &ScanFrom,
unsigned MaxInstsToScan = DefMaxInstsToScan,
AliasAnalysis *AA = nullptr,
AAMDNodes *AATags = nullptr,
bool *IsLoadCSE = nullptr);
}

View File

@ -20,7 +20,9 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AliasSetTracker.h"
#include "llvm/Analysis/LoopPassManager.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
@ -34,6 +36,7 @@ class Loop;
class SCEV;
class SCEVUnionPredicate;
class LoopAccessInfo;
class OptimizationRemarkEmitter;
/// Optimization analysis message produced during vectorization. Messages inform
/// the user why vectorization did not occur.
@ -63,10 +66,9 @@ class LoopAccessReport {
/// \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 Function *TheFunction,
const Loop *TheLoop,
const char *PassName);
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
@ -516,38 +518,6 @@ class LoopAccessInfo {
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const TargetLibraryInfo *TLI,
AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI);
// FIXME:
// Hack for MSVC 2013 which sems like it can't synthesize this even
// with default keyword:
// LoopAccessInfo(LoopAccessInfo &&LAI) = default;
LoopAccessInfo(LoopAccessInfo &&LAI)
: PSE(std::move(LAI.PSE)), PtrRtChecking(std::move(LAI.PtrRtChecking)),
DepChecker(std::move(LAI.DepChecker)), TheLoop(LAI.TheLoop),
NumLoads(LAI.NumLoads), NumStores(LAI.NumStores),
MaxSafeDepDistBytes(LAI.MaxSafeDepDistBytes), CanVecMem(LAI.CanVecMem),
StoreToLoopInvariantAddress(LAI.StoreToLoopInvariantAddress),
Report(std::move(LAI.Report)),
SymbolicStrides(std::move(LAI.SymbolicStrides)),
StrideSet(std::move(LAI.StrideSet)) {}
// LoopAccessInfo &operator=(LoopAccessInfo &&LAI) = default;
LoopAccessInfo &operator=(LoopAccessInfo &&LAI) {
assert(this != &LAI);
PSE = std::move(LAI.PSE);
PtrRtChecking = std::move(LAI.PtrRtChecking);
DepChecker = std::move(LAI.DepChecker);
TheLoop = LAI.TheLoop;
NumLoads = LAI.NumLoads;
NumStores = LAI.NumStores;
MaxSafeDepDistBytes = LAI.MaxSafeDepDistBytes;
CanVecMem = LAI.CanVecMem;
StoreToLoopInvariantAddress = LAI.StoreToLoopInvariantAddress;
Report = std::move(LAI.Report);
SymbolicStrides = std::move(LAI.SymbolicStrides);
StrideSet = std::move(LAI.StrideSet);
return *this;
}
/// Return true we can analyze the memory accesses in the loop and there are
/// no memory dependence cycles.
bool canVectorizeMemory() const { return CanVecMem; }
@ -594,7 +564,7 @@ class LoopAccessInfo {
/// \brief The diagnostics report generated for the analysis. E.g. why we
/// couldn't analyze the loop.
const Optional<LoopAccessReport> &getReport() const { return Report; }
const OptimizationRemarkAnalysis *getReport() const { return Report.get(); }
/// \brief the Memory Dependence Checker which can determine the
/// loop-independent and loop-carried dependences between memory accesses.
@ -640,7 +610,13 @@ class LoopAccessInfo {
/// pass.
bool canAnalyzeLoop();
void emitAnalysis(LoopAccessReport &Message);
/// \brief Save the analysis remark.
///
/// LAA does not directly emits the remarks. Instead it stores it which the
/// client can retrieve and presents as its own analysis
/// (e.g. -Rpass-analysis=loop-vectorize).
OptimizationRemarkAnalysis &recordAnalysis(StringRef RemarkName,
Instruction *Instr = nullptr);
/// \brief Collect memory access with loop invariant strides.
///
@ -674,7 +650,7 @@ class LoopAccessInfo {
/// \brief The diagnostics report generated for the analysis. E.g. why we
/// couldn't analyze the loop.
Optional<LoopAccessReport> Report;
std::unique_ptr<OptimizationRemarkAnalysis> Report;
/// \brief If an access has a symbolic strides, this maps the pointer value to
/// the stride symbol.
@ -712,7 +688,7 @@ const SCEV *replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
/// run-time assumptions.
int64_t getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
const ValueToValueMap &StridesMap = ValueToValueMap(),
bool Assume = false);
bool Assume = false, bool ShouldCheckWrap = true);
/// \brief Returns true if the memory operations \p A and \p B are consecutive.
/// This is a simple API that does not depend on the analysis pass.
@ -773,11 +749,11 @@ class LoopAccessLegacyAnalysis : public FunctionPass {
class LoopAccessAnalysis
: public AnalysisInfoMixin<LoopAccessAnalysis> {
friend AnalysisInfoMixin<LoopAccessAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
typedef LoopAccessInfo Result;
Result run(Loop &, AnalysisManager<Loop> &);
Result run(Loop &, LoopAnalysisManager &);
static StringRef name() { return "LoopAccessAnalysis"; }
};
@ -788,7 +764,7 @@ class LoopAccessInfoPrinterPass
public:
explicit LoopAccessInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Loop &L, AnalysisManager<Loop> &AM);
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM);
};
inline Instruction *MemoryDepChecker::Dependence::getSource(

View File

@ -168,6 +168,19 @@ class LoopBase {
return false;
}
/// Returns true if \p BB is a loop-latch.
/// A latch block is a block that contains a branch back to the header.
/// This function is useful when there are multiple latches in a loop
/// because \fn getLoopLatch will return nullptr in that case.
bool isLoopLatch(const BlockT *BB) const {
assert(contains(BB) && "block does not belong to the loop");
BlockT *Header = getHeader();
auto PredBegin = GraphTraits<Inverse<BlockT*> >::child_begin(Header);
auto PredEnd = GraphTraits<Inverse<BlockT*> >::child_end(Header);
return std::find(PredBegin, PredEnd, BB) != PredEnd;
}
/// Calculate the number of back edges to the loop header.
unsigned getNumBackEdges() const {
unsigned NumBackEdges = 0;
@ -316,7 +329,7 @@ class LoopBase {
/// Blocks as appropriate. This does not update the mapping in the LoopInfo
/// class.
void removeBlockFromLoop(BlockT *BB) {
auto I = std::find(Blocks.begin(), Blocks.end(), BB);
auto I = find(Blocks, BB);
assert(I != Blocks.end() && "N is not in this list!");
Blocks.erase(I);
@ -329,7 +342,8 @@ class LoopBase {
/// Verify loop structure of this loop and all nested loops.
void verifyLoopNest(DenseSet<const LoopT*> *Loops) const;
void print(raw_ostream &OS, unsigned Depth = 0) const;
/// Print loop with all the BBs inside it.
void print(raw_ostream &OS, unsigned Depth = 0, bool Verbose = false) const;
protected:
friend class LoopInfoBase<BlockT, LoopT>;
@ -353,6 +367,27 @@ extern template class LoopBase<BasicBlock, Loop>;
/// in the CFG are neccessarily loops.
class Loop : public LoopBase<BasicBlock, Loop> {
public:
/// \brief A range representing the start and end location of a loop.
class LocRange {
DebugLoc Start;
DebugLoc End;
public:
LocRange() {}
LocRange(DebugLoc Start) : Start(std::move(Start)), End(std::move(Start)) {}
LocRange(DebugLoc Start, DebugLoc End) : Start(std::move(Start)),
End(std::move(End)) {}
const DebugLoc &getStart() const { return Start; }
const DebugLoc &getEnd() const { return End; }
/// \brief Check for null.
///
explicit operator bool() const {
return Start && End;
}
};
Loop() {}
/// Return true if the specified value is loop invariant.
@ -398,7 +433,7 @@ class Loop : public LoopBase<BasicBlock, Loop> {
bool isLCSSAForm(DominatorTree &DT) const;
/// Return true if this Loop and all inner subloops are in LCSSA form.
bool isRecursivelyLCSSAForm(DominatorTree &DT) const;
bool isRecursivelyLCSSAForm(DominatorTree &DT, const LoopInfo &LI) const;
/// Return true if the Loop is in the form that the LoopSimplify form
/// transforms loops to, which is sometimes called normal form.
@ -451,6 +486,7 @@ class Loop : public LoopBase<BasicBlock, Loop> {
BasicBlock *getUniqueExitBlock() const;
void dump() const;
void dumpVerbose() const;
/// Return the debug location of the start of this loop.
/// This looks for a BB terminating instruction with a known debug
@ -459,6 +495,9 @@ class Loop : public LoopBase<BasicBlock, Loop> {
/// it returns an unknown location.
DebugLoc getStartLoc() const;
/// Return the source code span of the loop.
LocRange getLocRange() const;
StringRef getName() const {
if (BasicBlock *Header = getHeader())
if (Header->hasName())
@ -579,7 +618,7 @@ class LoopInfoBase {
/// loop.
void changeTopLevelLoop(LoopT *OldLoop,
LoopT *NewLoop) {
auto I = std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
auto I = find(TopLevelLoops, OldLoop);
assert(I != TopLevelLoops.end() && "Old loop not at top level!");
*I = NewLoop;
assert(!NewLoop->ParentLoop && !OldLoop->ParentLoop &&
@ -620,7 +659,7 @@ class LoopInfoBase {
// Debugging
void print(raw_ostream &OS) const;
void verify() const;
void verify(const DominatorTreeBase<BlockT> &DomTree) const;
};
// Implementation in LoopInfoImpl.h
@ -746,40 +785,32 @@ class LoopInfo : public LoopInfoBase<BasicBlock, Loop> {
// Allow clients to walk the list of nested loops...
template <> struct GraphTraits<const Loop*> {
typedef const Loop NodeType;
typedef const Loop *NodeRef;
typedef LoopInfo::iterator ChildIteratorType;
static NodeType *getEntryNode(const Loop *L) { return L; }
static inline ChildIteratorType child_begin(NodeType *N) {
return N->begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->end();
}
static NodeRef getEntryNode(const Loop *L) { return L; }
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
};
template <> struct GraphTraits<Loop*> {
typedef Loop NodeType;
typedef Loop *NodeRef;
typedef LoopInfo::iterator ChildIteratorType;
static NodeType *getEntryNode(Loop *L) { return L; }
static inline ChildIteratorType child_begin(NodeType *N) {
return N->begin();
}
static inline ChildIteratorType child_end(NodeType *N) {
return N->end();
}
static NodeRef getEntryNode(Loop *L) { return L; }
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
};
/// \brief Analysis pass that exposes the \c LoopInfo for a function.
class LoopAnalysis : public AnalysisInfoMixin<LoopAnalysis> {
friend AnalysisInfoMixin<LoopAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
typedef LoopInfo Result;
LoopInfo run(Function &F, AnalysisManager<Function> &AM);
LoopInfo run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Printer pass for the \c LoopAnalysis results.
@ -788,7 +819,12 @@ class LoopPrinterPass : public PassInfoMixin<LoopPrinterPass> {
public:
explicit LoopPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief Verifier pass for the \c LoopAnalysis results.
struct LoopVerifierPass : public PassInfoMixin<LoopVerifierPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
/// \brief The legacy pass manager's analysis pass to compute loop information.

View File

@ -17,6 +17,7 @@
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/IR/Dominators.h"
@ -137,7 +138,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
for (typename InvBlockTraits::ChildIteratorType PI =
InvBlockTraits::child_begin(Header),
PE = InvBlockTraits::child_end(Header); PI != PE; ++PI) {
typename InvBlockTraits::NodeType *N = *PI;
typename InvBlockTraits::NodeRef N = *PI;
if (!contains(N)) { // If the block is not in the loop...
if (Out && Out != N)
return nullptr; // Multiple predecessors outside the loop
@ -162,7 +163,7 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopLatch() const {
InvBlockTraits::child_end(Header);
BlockT *Latch = nullptr;
for (; PI != PE; ++PI) {
typename InvBlockTraits::NodeType *N = *PI;
typename InvBlockTraits::NodeRef N = *PI;
if (contains(N)) {
if (Latch) return nullptr;
Latch = N;
@ -185,8 +186,13 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopLatch() const {
template<class BlockT, class LoopT>
void LoopBase<BlockT, LoopT>::
addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LIB) {
assert((Blocks.empty() || LIB[getHeader()] == this) &&
"Incorrect LI specified for this loop!");
#ifndef NDEBUG
if (!Blocks.empty()) {
auto SameHeader = LIB[getHeader()];
assert(contains(SameHeader) && getHeader() == SameHeader->getHeader()
&& "Incorrect LI specified for this loop!");
}
#endif
assert(NewBB && "Cannot add a null basic block to the loop!");
assert(!LIB[NewBB] && "BasicBlock already in the loop!");
@ -211,8 +217,7 @@ void LoopBase<BlockT, LoopT>::
replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild) {
assert(OldChild->ParentLoop == this && "This loop is already broken!");
assert(!NewChild->ParentLoop && "NewChild already has a parent!");
typename std::vector<LoopT *>::iterator I =
std::find(SubLoops.begin(), SubLoops.end(), OldChild);
typename std::vector<LoopT *>::iterator I = find(SubLoops, OldChild);
assert(I != SubLoops.end() && "OldChild not in loop!");
*I = NewChild;
OldChild->ParentLoop = nullptr;
@ -228,9 +233,9 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
// Setup for using a depth-first iterator to visit every block in the loop.
SmallVector<BlockT*, 8> ExitBBs;
getExitBlocks(ExitBBs);
llvm::SmallPtrSet<BlockT*, 8> VisitSet;
df_iterator_default_set<BlockT*> VisitSet;
VisitSet.insert(ExitBBs.begin(), ExitBBs.end());
df_ext_iterator<BlockT*, llvm::SmallPtrSet<BlockT*, 8> >
df_ext_iterator<BlockT*, df_iterator_default_set<BlockT*>>
BI = df_ext_begin(getHeader(), VisitSet),
BE = df_ext_end(getHeader(), VisitSet);
@ -240,28 +245,23 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
// Check the individual blocks.
for ( ; BI != BE; ++BI) {
BlockT *BB = *BI;
bool HasInsideLoopSuccs = false;
bool HasInsideLoopPreds = false;
SmallVector<BlockT *, 2> OutsideLoopPreds;
typedef GraphTraits<BlockT*> BlockTraits;
for (typename BlockTraits::ChildIteratorType SI =
BlockTraits::child_begin(BB), SE = BlockTraits::child_end(BB);
SI != SE; ++SI)
if (contains(*SI)) {
HasInsideLoopSuccs = true;
break;
}
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
for (typename InvBlockTraits::ChildIteratorType PI =
InvBlockTraits::child_begin(BB), PE = InvBlockTraits::child_end(BB);
PI != PE; ++PI) {
BlockT *N = *PI;
if (contains(N))
HasInsideLoopPreds = true;
else
OutsideLoopPreds.push_back(N);
}
assert(std::any_of(GraphTraits<BlockT*>::child_begin(BB),
GraphTraits<BlockT*>::child_end(BB),
[&](BlockT *B){return contains(B);}) &&
"Loop block has no in-loop successors!");
assert(std::any_of(GraphTraits<Inverse<BlockT*> >::child_begin(BB),
GraphTraits<Inverse<BlockT*> >::child_end(BB),
[&](BlockT *B){return contains(B);}) &&
"Loop block has no in-loop predecessors!");
SmallVector<BlockT *, 2> OutsideLoopPreds;
std::for_each(GraphTraits<Inverse<BlockT*> >::child_begin(BB),
GraphTraits<Inverse<BlockT*> >::child_end(BB),
[&](BlockT *B){if (!contains(B))
OutsideLoopPreds.push_back(B);
});
if (BB == getHeader()) {
assert(!OutsideLoopPreds.empty() && "Loop is unreachable!");
@ -275,8 +275,6 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
assert(CB != OutsideLoopPreds[i] &&
"Loop has multiple entry points!");
}
assert(HasInsideLoopPreds && "Loop block has no in-loop predecessors!");
assert(HasInsideLoopSuccs && "Loop block has no in-loop successors!");
assert(BB != &getHeader()->getParent()->front() &&
"Loop contains function entry block!");
@ -296,8 +294,7 @@ void LoopBase<BlockT, LoopT>::verifyLoop() const {
// Check the parent loop pointer.
if (ParentLoop) {
assert(std::find(ParentLoop->begin(), ParentLoop->end(), this) !=
ParentLoop->end() &&
assert(is_contained(*ParentLoop, this) &&
"Loop is not a subloop of its parent!");
}
#endif
@ -316,17 +313,24 @@ void LoopBase<BlockT, LoopT>::verifyLoopNest(
}
template<class BlockT, class LoopT>
void LoopBase<BlockT, LoopT>::print(raw_ostream &OS, unsigned Depth) const {
void LoopBase<BlockT, LoopT>::print(raw_ostream &OS, unsigned Depth,
bool Verbose) const {
OS.indent(Depth*2) << "Loop at depth " << getLoopDepth()
<< " containing: ";
BlockT *H = getHeader();
for (unsigned i = 0; i < getBlocks().size(); ++i) {
if (i) OS << ",";
BlockT *BB = getBlocks()[i];
BB->printAsOperand(OS, false);
if (BB == getHeader()) OS << "<header>";
if (BB == getLoopLatch()) OS << "<latch>";
if (isLoopExiting(BB)) OS << "<exiting>";
if (!Verbose) {
if (i) OS << ",";
BB->printAsOperand(OS, false);
} else OS << "\n";
if (BB == H) OS << "<header>";
if (isLoopLatch(BB)) OS << "<latch>";
if (isLoopExiting(BB)) OS << "<exiting>";
if (Verbose)
BB->print(OS);
}
OS << "\n";
@ -516,8 +520,26 @@ void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
#endif
}
template<class BlockT, class LoopT>
void LoopInfoBase<BlockT, LoopT>::verify() const {
template <typename T>
bool compareVectors(std::vector<T> &BB1, std::vector<T> &BB2) {
std::sort(BB1.begin(), BB1.end());
std::sort(BB2.begin(), BB2.end());
return BB1 == BB2;
}
template <class BlockT, class LoopT>
static 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);
}
template <class BlockT, class LoopT>
void LoopInfoBase<BlockT, LoopT>::verify(
const DominatorTreeBase<BlockT> &DomTree) const {
DenseSet<const LoopT*> Loops;
for (iterator I = begin(), E = end(); I != E; ++I) {
assert(!(*I)->getParentLoop() && "Top-level loop has a parent!");
@ -532,6 +554,48 @@ void LoopInfoBase<BlockT, LoopT>::verify() const {
assert(Loops.count(L) && "orphaned loop");
assert(L->contains(BB) && "orphaned block");
}
// Recompute LoopInfo to verify loops structure.
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);
for (LoopT *L : OtherLI)
addInnerLoopsToHeadersMap(LoopHeaders2, OtherLI, *L);
assert(LoopHeaders1.size() == LoopHeaders2.size() &&
"LoopInfo is incorrect.");
auto compareLoops = [&](const LoopT *L1, const LoopT *L2) {
BlockT *H1 = L1->getHeader();
BlockT *H2 = L2->getHeader();
if (H1 != H2)
return false;
std::vector<BlockT *> BB1 = L1->getBlocks();
std::vector<BlockT *> BB2 = L2->getBlocks();
if (!compareVectors(BB1, BB2))
return false;
std::vector<BlockT *> SubLoopHeaders1;
std::vector<BlockT *> SubLoopHeaders2;
for (LoopT *L : *L1)
SubLoopHeaders1.push_back(L->getHeader());
for (LoopT *L : *L2)
SubLoopHeaders2.push_back(L->getHeader());
if (!compareVectors(SubLoopHeaders1, SubLoopHeaders2))
return false;
return true;
};
for (auto &I : LoopHeaders1) {
BlockT *H = I.first;
bool LoopsMatch = compareLoops(LoopHeaders1[H], LoopHeaders2[H]);
assert(LoopsMatch && "LoopInfo is incorrect.");
}
#endif
}

View File

@ -31,6 +31,66 @@ namespace llvm {
class LoopBlocksTraversal;
// A traits type that is intended to be used in graph algorithms. The graph
// traits starts at the loop header, and traverses the BasicBlocks that are in
// the loop body, but not the loop header. Since the loop header is skipped,
// the back edges are excluded.
//
// TODO: Explore the possibility to implement LoopBlocksTraversal in terms of
// LoopBodyTraits, so that insertEdge doesn't have to be specialized.
struct LoopBodyTraits {
using NodeRef = std::pair<const Loop *, BasicBlock *>;
// This wraps a const Loop * into the iterator, so we know which edges to
// filter out.
class WrappedSuccIterator
: public iterator_adaptor_base<
WrappedSuccIterator, succ_iterator,
typename std::iterator_traits<succ_iterator>::iterator_category,
NodeRef, std::ptrdiff_t, NodeRef *, NodeRef> {
using BaseT = iterator_adaptor_base<
WrappedSuccIterator, succ_iterator,
typename std::iterator_traits<succ_iterator>::iterator_category,
NodeRef, std::ptrdiff_t, NodeRef *, NodeRef>;
const Loop *L;
public:
WrappedSuccIterator(succ_iterator Begin, const Loop *L)
: BaseT(Begin), L(L) {}
NodeRef operator*() const { return {L, *I}; }
};
struct LoopBodyFilter {
bool operator()(NodeRef N) const {
const Loop *L = N.first;
return N.second != L->getHeader() && L->contains(N.second);
}
};
using ChildIteratorType =
filter_iterator<WrappedSuccIterator, LoopBodyFilter>;
static NodeRef getEntryNode(const Loop &G) { return {&G, G.getHeader()}; }
static ChildIteratorType child_begin(NodeRef Node) {
return make_filter_range(make_range<WrappedSuccIterator>(
{succ_begin(Node.second), Node.first},
{succ_end(Node.second), Node.first}),
LoopBodyFilter{})
.begin();
}
static ChildIteratorType child_end(NodeRef Node) {
return make_filter_range(make_range<WrappedSuccIterator>(
{succ_begin(Node.second), Node.first},
{succ_end(Node.second), Node.first}),
LoopBodyFilter{})
.end();
}
};
/// Store the result of a depth first search within basic blocks contained by a
/// single loop.
///
@ -114,7 +174,7 @@ template<> class po_iterator_storage<LoopBlocksTraversal, true> {
public:
po_iterator_storage(LoopBlocksTraversal &lbs) : LBT(lbs) {}
// These functions are defined below.
bool insertEdge(BasicBlock *From, BasicBlock *To);
bool insertEdge(Optional<BasicBlock *> From, BasicBlock *To);
void finishPostorder(BasicBlock *BB);
};
@ -166,8 +226,8 @@ class LoopBlocksTraversal {
}
};
inline bool po_iterator_storage<LoopBlocksTraversal, true>::
insertEdge(BasicBlock *From, BasicBlock *To) {
inline bool po_iterator_storage<LoopBlocksTraversal, true>::insertEdge(
Optional<BasicBlock *> From, BasicBlock *To) {
return LBT.visitPreorder(To);
}

View File

@ -107,9 +107,7 @@ class LPPassManager : public FunctionPass, public PMDataManager {
// LPPassManager needs LoopInfo.
void getAnalysisUsage(AnalysisUsage &Info) const override;
const char *getPassName() const override {
return "Loop Pass Manager";
}
StringRef getPassName() const override { return "Loop Pass Manager"; }
PMDataManager *getAsPMDataManager() override { return this; }
Pass *getAsPass() override { return this; }
@ -157,6 +155,22 @@ class LPPassManager : public FunctionPass, public PMDataManager {
Loop *CurrentLoop;
};
// This pass is required by the LCSSA transformation. It is used inside
// LPPassManager to check if current pass preserves LCSSA form, and if it does
// pass manager calls lcssa verification for the current loop.
struct LCSSAVerificationPass : public FunctionPass {
static char ID;
LCSSAVerificationPass() : FunctionPass(ID) {
initializeLCSSAVerificationPassPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override { return false; }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
};
} // End llvm namespace
#endif

View File

@ -16,7 +16,11 @@
#define LLVM_ANALYSIS_LOOPPASSMANAGER_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/PassManager.h"
namespace llvm {
@ -38,11 +42,21 @@ extern template class AnalysisManager<Loop>;
/// pass manager infrastructure.
typedef AnalysisManager<Loop> LoopAnalysisManager;
extern template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
/// A proxy from a \c LoopAnalysisManager to a \c Function.
typedef InnerAnalysisManagerProxy<LoopAnalysisManager, Function>
LoopAnalysisManagerFunctionProxy;
/// Specialization of the invalidate method for the \c
/// LoopAnalysisManagerFunctionProxy's result.
template <>
bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv);
// Ensure the \c LoopAnalysisManagerFunctionProxy is provided as an extern
// template.
extern template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>;
/// A proxy from a \c FunctionAnalysisManager to a \c Loop.
typedef OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>
@ -64,21 +78,6 @@ class FunctionToLoopPassAdaptor
public:
explicit FunctionToLoopPassAdaptor(LoopPassT Pass)
: Pass(std::move(Pass)) {}
// We have to explicitly define all the special member functions because MSVC
// refuses to generate them.
FunctionToLoopPassAdaptor(const FunctionToLoopPassAdaptor &Arg)
: Pass(Arg.Pass) {}
FunctionToLoopPassAdaptor(FunctionToLoopPassAdaptor &&Arg)
: Pass(std::move(Arg.Pass)) {}
friend void swap(FunctionToLoopPassAdaptor &LHS,
FunctionToLoopPassAdaptor &RHS) {
using std::swap;
swap(LHS.Pass, RHS.Pass);
}
FunctionToLoopPassAdaptor &operator=(FunctionToLoopPassAdaptor RHS) {
swap(*this, RHS);
return *this;
}
/// \brief Runs the loop passes across every loop in the function.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
@ -88,6 +87,14 @@ class FunctionToLoopPassAdaptor
// Get the loop structure for this function
LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
// Also precompute all of the function analyses used by loop passes.
// FIXME: These should be handed into the loop passes when the loop pass
// management layer is reworked to follow the design of CGSCC.
(void)AM.getResult<AAManager>(F);
(void)AM.getResult<DominatorTreeAnalysis>(F);
(void)AM.getResult<ScalarEvolutionAnalysis>(F);
(void)AM.getResult<TargetLibraryAnalysis>(F);
PreservedAnalyses PA = PreservedAnalyses::all();
// We want to visit the loops in reverse post-order. We'll build the stack
@ -104,24 +111,24 @@ class FunctionToLoopPassAdaptor
// post-order.
for (auto *L : reverse(Loops)) {
PreservedAnalyses PassPA = Pass.run(*L, LAM);
assert(PassPA.preserved(getLoopPassPreservedAnalyses()) &&
"Loop passes must preserve all relevant analyses");
// FIXME: We should verify the set of analyses relevant to Loop passes
// are preserved.
// We know that the loop pass couldn't have invalidated any other loop's
// analyses (that's the contract of a loop pass), so directly handle the
// loop analysis manager's invalidation here. Also, update the
// preserved analyses to reflect that once invalidated these can again
// be preserved.
PassPA = LAM.invalidate(*L, std::move(PassPA));
// loop analysis manager's invalidation here.
LAM.invalidate(*L, PassPA);
// Then intersect the preserved set so that invalidation of module
// analyses will eventually occur when the module pass completes.
PA.intersect(std::move(PassPA));
}
// By definition we preserve the proxy. This precludes *any* invalidation of
// loop analyses by the proxy, but that's OK because we've taken care to
// invalidate analyses in the loop analysis manager incrementally above.
// By definition we preserve the proxy. We also preserve all analyses on
// Loops. This precludes *any* invalidation of loop analyses by the proxy,
// but that's OK because we've taken care to invalidate analyses in the
// loop analysis manager incrementally above.
PA.preserveSet<AllAnalysesOn<Loop>>();
PA.preserve<LoopAnalysisManagerFunctionProxy>();
return PA;
}

View File

@ -141,6 +141,16 @@ bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
const TargetLibraryInfo *TLI, bool RoundToAlign = false,
ObjSizeMode Mode = ObjSizeMode::Exact);
/// Try to turn a call to @llvm.objectsize into an integer value of the given
/// Type. Returns null on failure.
/// If MustSucceed is true, this function will not return null, and may return
/// conservative values governed by the second argument of the call to
/// objectsize.
ConstantInt *lowerObjectSizeCall(IntrinsicInst *ObjectSize,
const DataLayout &DL,
const TargetLibraryInfo *TLI,
bool MustSucceed);
typedef std::pair<APInt, APInt> SizeOffsetType;
/// \brief Evaluate the size and offset of an object pointed to by a Value*

View File

@ -70,7 +70,7 @@ class MemDepResult {
/// 1. This could be a load or store for dependence queries on
/// load/store. The value loaded or stored is the produced value.
/// Note that the pointer operand may be different than that of the
/// queried pointer due to must aliases and phi translation. Note
/// queried pointer due to must aliases and phi translation. Note
/// that the def may not be the same type as the query, the pointers
/// may just be must aliases.
/// 2. For loads and stores, this could be an allocation instruction. In
@ -350,9 +350,18 @@ class MemoryDependenceResults {
DominatorTree &DT)
: AA(AA), AC(AC), TLI(TLI), DT(DT) {}
/// Handle invalidation in the new PM.
bool invalidate(Function &F, const PreservedAnalyses &PA,
FunctionAnalysisManager::Invalidator &Inv);
/// Some methods limit the number of instructions they will examine.
/// The return value of this method is the default limit that will be
/// used if no limit is explicitly passed in.
unsigned getDefaultBlockScanLimit() const;
/// Returns the instruction on which a memory operation depends.
///
/// See the class comment for more details. It is illegal to call this on
/// See the class comment for more details. It is illegal to call this on
/// non-memory instructions.
MemDepResult getDependency(Instruction *QueryInst);
@ -409,19 +418,25 @@ class MemoryDependenceResults {
/// operations. If isLoad is false, this routine ignores may-aliases
/// with reads from read-only locations. If possible, pass the query
/// instruction as well; this function may take advantage of the metadata
/// annotated to the query instruction to refine the result.
/// annotated to the query instruction to refine the result. \p Limit
/// can be used to set the maximum number of instructions that will be
/// examined to find the pointer dependency. On return, it will be set to
/// the number of instructions left to examine. If a null pointer is passed
/// in, the limit will default to the value of -memdep-block-scan-limit.
///
/// Note that this is an uncached query, and thus may be inefficient.
MemDepResult getPointerDependencyFrom(const MemoryLocation &Loc, bool isLoad,
BasicBlock::iterator ScanIt,
BasicBlock *BB,
Instruction *QueryInst = nullptr);
Instruction *QueryInst = nullptr,
unsigned *Limit = nullptr);
MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc,
bool isLoad,
BasicBlock::iterator ScanIt,
BasicBlock *BB,
Instruction *QueryInst);
Instruction *QueryInst,
unsigned *Limit = nullptr);
/// This analysis looks for other loads and stores with invariant.group
/// metadata and the same pointer operand. Returns Unknown if it does not
@ -474,12 +489,12 @@ class MemoryDependenceResults {
class MemoryDependenceAnalysis
: public AnalysisInfoMixin<MemoryDependenceAnalysis> {
friend AnalysisInfoMixin<MemoryDependenceAnalysis>;
static char PassID;
static AnalysisKey Key;
public:
typedef MemoryDependenceResults Result;
MemoryDependenceResults run(Function &F, AnalysisManager<Function> &AM);
MemoryDependenceResults run(Function &F, FunctionAnalysisManager &AM);
};
/// A wrapper analysis pass for the legacy pass manager that exposes a \c

View File

@ -16,48 +16,39 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
namespace llvm {
class BlockFrequencyInfo;
class ProfileSummaryInfo;
/// Class to build a module summary index for the given Module, possibly from
/// a Pass.
class ModuleSummaryIndexBuilder {
/// The index being built
std::unique_ptr<ModuleSummaryIndex> Index;
/// The module for which we are building an index
const Module *M;
/// Direct function to compute a \c ModuleSummaryIndex from a given module.
///
/// If operating within a pass manager which has defined ways to compute the \c
/// BlockFrequencyInfo for a given function, that can be provided via
/// a std::function callback. Otherwise, this routine will manually construct
/// that information.
ModuleSummaryIndex buildModuleSummaryIndex(
const Module &M,
std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
ProfileSummaryInfo *PSI);
/// Analysis pass to provide the ModuleSummaryIndex object.
class ModuleSummaryIndexAnalysis
: public AnalysisInfoMixin<ModuleSummaryIndexAnalysis> {
friend AnalysisInfoMixin<ModuleSummaryIndexAnalysis>;
static AnalysisKey Key;
public:
/// Default constructor
ModuleSummaryIndexBuilder() = default;
typedef ModuleSummaryIndex Result;
/// Constructor that builds an index for the given Module. An optional
/// callback can be supplied to obtain the frequency info for a function.
ModuleSummaryIndexBuilder(
const Module *M,
std::function<BlockFrequencyInfo *(const Function &F)> Ftor = nullptr);
/// Get a reference to the index owned by builder
ModuleSummaryIndex &getIndex() const { return *Index; }
/// Take ownership of the built index
std::unique_ptr<ModuleSummaryIndex> takeIndex() { return std::move(Index); }
private:
/// Compute summary for given function with optional frequency information
void computeFunctionSummary(const Function &F,
BlockFrequencyInfo *BFI = nullptr);
/// Compute summary for given variable with optional frequency information
void computeVariableSummary(const GlobalVariable &V);
Result run(Module &M, ModuleAnalysisManager &AM);
};
/// Legacy wrapper pass to provide the ModuleSummaryIndex object.
class ModuleSummaryIndexWrapperPass : public ModulePass {
std::unique_ptr<ModuleSummaryIndexBuilder> IndexBuilder;
Optional<ModuleSummaryIndex> Index;
public:
static char ID;
@ -65,10 +56,8 @@ class ModuleSummaryIndexWrapperPass : public ModulePass {
ModuleSummaryIndexWrapperPass();
/// Get the index built by pass
ModuleSummaryIndex &getIndex() { return IndexBuilder->getIndex(); }
const ModuleSummaryIndex &getIndex() const {
return IndexBuilder->getIndex();
}
ModuleSummaryIndex &getIndex() { return *Index; }
const ModuleSummaryIndex &getIndex() const { return *Index; }
bool runOnModule(Module &M) override;
bool doFinalization(Module &M) override;
@ -81,11 +70,6 @@ class ModuleSummaryIndexWrapperPass : public ModulePass {
// object for the module, to be written to bitcode or LLVM assembly.
//
ModulePass *createModuleSummaryIndexWrapperPass();
/// Returns true if \p M is eligible for ThinLTO promotion.
///
/// Currently we check if it has any any InlineASM that uses an internal symbol.
bool moduleCanBeRenamedForThinLTO(const Module &M);
}
#endif

Some files were not shown because too many files have changed in this diff Show More