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:
commit
d88c1a5a57
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang400-import/; revision=311142
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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!");
|
||||
|
226
contrib/llvm/include/llvm/ADT/AllocatorList.h
Normal file
226
contrib/llvm/include/llvm/ADT/AllocatorList.h
Normal 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
|
@ -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
|
||||
/// @{
|
||||
|
||||
|
@ -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) {
|
||||
|
184
contrib/llvm/include/llvm/ADT/CachedHashString.h
Normal file
184
contrib/llvm/include/llvm/ADT/CachedHashString.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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*> {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
54
contrib/llvm/include/llvm/ADT/ScopeExit.h
Normal file
54
contrib/llvm/include/llvm/ADT/ScopeExit.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
95
contrib/llvm/include/llvm/ADT/ilist_base.h
Normal file
95
contrib/llvm/include/llvm/ADT/ilist_base.h
Normal 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
|
185
contrib/llvm/include/llvm/ADT/ilist_iterator.h
Normal file
185
contrib/llvm/include/llvm/ADT/ilist_iterator.h
Normal 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
|
@ -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;
|
||||
|
||||
|
53
contrib/llvm/include/llvm/ADT/ilist_node_base.h
Normal file
53
contrib/llvm/include/llvm/ADT/ilist_node_base.h
Normal 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
|
133
contrib/llvm/include/llvm/ADT/ilist_node_options.h
Normal file
133
contrib/llvm/include/llvm/ADT/ilist_node_options.h
Normal 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
|
@ -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
|
||||
|
310
contrib/llvm/include/llvm/ADT/simple_ilist.h
Normal file
310
contrib/llvm/include/llvm/ADT/simple_ilist.h
Normal 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
|
@ -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>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
109
contrib/llvm/include/llvm/Analysis/LazyBranchProbabilityInfo.h
Normal file
109
contrib/llvm/include/llvm/Analysis/LazyBranchProbabilityInfo.h
Normal 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
|
@ -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.
|
||||
|
@ -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>;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user