Merge llvm trunk r238337 from ^/vendor/llvm/dist, resolve conflicts, and
preserve our customizations, where necessary.
This commit is contained in:
commit
ff0cc061ec
@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
@ -169,6 +169,7 @@ typedef enum {
|
||||
LLVMNonNullAttribute = 1ULL << 37,
|
||||
LLVMJumpTableAttribute = 1ULL << 38,
|
||||
LLVMDereferenceableAttribute = 1ULL << 39,
|
||||
LLVMDereferenceableOrNullAttribute = 1ULL << 40,
|
||||
*/
|
||||
} LLVMAttribute;
|
||||
|
||||
|
@ -20,21 +20,23 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Note: LLVMLinkerPreserveSource has no effect. */
|
||||
/* This enum is provided for backwards-compatibility only. It has no effect. */
|
||||
typedef enum {
|
||||
LLVMLinkerDestroySource = 0, /* Allow source module to be destroyed. */
|
||||
LLVMLinkerPreserveSource = 1 /* Preserve the source module. */
|
||||
LLVMLinkerDestroySource = 0, /* This is the default behavior. */
|
||||
LLVMLinkerPreserveSource_Removed = 1 /* This option has been deprecated and
|
||||
should not be used. */
|
||||
} LLVMLinkerMode;
|
||||
|
||||
|
||||
/* Links the source module into the destination module, taking ownership
|
||||
* of the source module away from the caller. Optionally returns a
|
||||
* human-readable description of any errors that occurred in linking.
|
||||
* OutMessage must be disposed with LLVMDisposeMessage. The return value
|
||||
* is true if an error occurred, false otherwise. */
|
||||
* is true if an error occurred, false otherwise.
|
||||
*
|
||||
* Note that the linker mode parameter \p Unused is no longer used, and has
|
||||
* no effect. */
|
||||
LLVMBool LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src,
|
||||
LLVMLinkerMode Mode, char **OutMessage);
|
||||
LLVMLinkerMode Unused, char **OutMessage);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ extern "C" {
|
||||
/** See llvm::createAggressiveDCEPass function. */
|
||||
void LLVMAddAggressiveDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createBitTrackingDCEPass function. */
|
||||
void LLVMAddBitTrackingDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createAlignmentFromAssumptionsPass function. */
|
||||
void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
@ -40,7 +40,7 @@ typedef bool lto_bool_t;
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define LTO_API_VERSION 11
|
||||
#define LTO_API_VERSION 15
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
@ -171,7 +171,7 @@ lto_module_create_from_memory(const void* mem, size_t length);
|
||||
* Loads an object file from memory with an extra path argument.
|
||||
* Returns NULL on error (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=9
|
||||
* \since LTO_API_VERSION=9
|
||||
*/
|
||||
extern lto_module_t
|
||||
lto_module_create_from_memory_with_path(const void* mem, size_t length,
|
||||
@ -395,6 +395,17 @@ lto_codegen_dispose(lto_code_gen_t);
|
||||
extern lto_bool_t
|
||||
lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod);
|
||||
|
||||
/**
|
||||
* Sets the object module for code generation. This will transfer the ownship of
|
||||
* the module to code generator.
|
||||
*
|
||||
* \c cg and \c mod must both be in the same context.
|
||||
*
|
||||
* \since LTO_API_VERSION=13
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod);
|
||||
|
||||
/**
|
||||
* Sets if debug info should be generated.
|
||||
* Returns true on error (check lto_get_error_message() for details).
|
||||
@ -464,6 +475,8 @@ lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path);
|
||||
|
||||
/**
|
||||
* Generates code for all added modules into one native object file.
|
||||
* This calls lto_codegen_optimize then lto_codegen_compile_optimized.
|
||||
*
|
||||
* On success returns a pointer to a generated mach-o/ELF buffer and
|
||||
* length set to the buffer size. The buffer is owned by the
|
||||
* lto_code_gen_t and will be freed when lto_codegen_dispose()
|
||||
@ -477,6 +490,9 @@ lto_codegen_compile(lto_code_gen_t cg, size_t* length);
|
||||
|
||||
/**
|
||||
* Generates code for all added modules into one native object file.
|
||||
* This calls lto_codegen_optimize then lto_codegen_compile_optimized (instead
|
||||
* of returning a generated mach-o/ELF buffer, it writes to a file).
|
||||
*
|
||||
* The name of the file is written to name. Returns true on error.
|
||||
*
|
||||
* \since LTO_API_VERSION=5
|
||||
@ -484,6 +500,36 @@ lto_codegen_compile(lto_code_gen_t cg, size_t* length);
|
||||
extern lto_bool_t
|
||||
lto_codegen_compile_to_file(lto_code_gen_t cg, const char** name);
|
||||
|
||||
/**
|
||||
* Runs optimization for the merged module. Returns true on error.
|
||||
*
|
||||
* \since LTO_API_VERSION=12
|
||||
*/
|
||||
extern lto_bool_t
|
||||
lto_codegen_optimize(lto_code_gen_t cg);
|
||||
|
||||
/**
|
||||
* Generates code for the optimized merged module into one native object file.
|
||||
* It will not run any IR optimizations on the merged module.
|
||||
*
|
||||
* On success returns a pointer to a generated mach-o/ELF buffer and length set
|
||||
* to the buffer size. The buffer is owned by the lto_code_gen_t and will be
|
||||
* freed when lto_codegen_dispose() is called, or
|
||||
* lto_codegen_compile_optimized() is called again. On failure, returns NULL
|
||||
* (check lto_get_error_message() for details).
|
||||
*
|
||||
* \since LTO_API_VERSION=12
|
||||
*/
|
||||
extern const void*
|
||||
lto_codegen_compile_optimized(lto_code_gen_t cg, size_t* length);
|
||||
|
||||
/**
|
||||
* Returns the runtime API version.
|
||||
*
|
||||
* \since LTO_API_VERSION=12
|
||||
*/
|
||||
extern unsigned int
|
||||
lto_api_version(void);
|
||||
|
||||
/**
|
||||
* Sets options to help debug codegen bugs.
|
||||
@ -502,6 +548,28 @@ lto_codegen_debug_options(lto_code_gen_t cg, const char *);
|
||||
extern void
|
||||
lto_initialize_disassembler(void);
|
||||
|
||||
/**
|
||||
* Sets if we should run internalize pass during optimization and code
|
||||
* generation.
|
||||
*
|
||||
* \since LTO_API_VERSION=14
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_set_should_internalize(lto_code_gen_t cg,
|
||||
lto_bool_t ShouldInternalize);
|
||||
|
||||
/**
|
||||
* \brief Set whether to embed uselists in bitcode.
|
||||
*
|
||||
* Sets whether \a lto_codegen_write_merged_modules() should embed uselists in
|
||||
* output bitcode. This should be turned on for all -save-temps output.
|
||||
*
|
||||
* \since LTO_API_VERSION=15
|
||||
*/
|
||||
extern void
|
||||
lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
|
||||
lto_bool_t ShouldEmbedUselists);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -282,12 +282,6 @@ class APFloat {
|
||||
/// into FoldingSets.
|
||||
void Profile(FoldingSetNodeID &NID) const;
|
||||
|
||||
/// \brief Used by the Bitcode serializer to emit APInts to Bitcode.
|
||||
void Emit(Serializer &S) const;
|
||||
|
||||
/// \brief Used by the Bitcode deserializer to deserialize APInts.
|
||||
static APFloat ReadVal(Deserializer &D);
|
||||
|
||||
/// \name Arithmetic
|
||||
/// @{
|
||||
|
||||
@ -349,7 +343,7 @@ class APFloat {
|
||||
/// copied from some other APFloat.
|
||||
static APFloat copySign(APFloat Value, const APFloat &Sign) {
|
||||
Value.copySign(Sign);
|
||||
return std::move(Value);
|
||||
return Value;
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -376,7 +370,7 @@ 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 LLVM_DELETED_FUNCTION;
|
||||
bool operator==(const APFloat &) const = delete;
|
||||
|
||||
/// IEEE comparison with another floating point number (NaNs compare
|
||||
/// unordered, 0==-0).
|
||||
|
@ -25,9 +25,7 @@
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
class Deserializer;
|
||||
class FoldingSetNodeID;
|
||||
class Serializer;
|
||||
class StringRef;
|
||||
class hash_code;
|
||||
class raw_ostream;
|
||||
@ -409,6 +407,13 @@ class APInt {
|
||||
: getZExtValue();
|
||||
}
|
||||
|
||||
/// \brief Check if the APInt consists of a repeated bit pattern.
|
||||
///
|
||||
/// e.g. 0x01010101 satisfies isSplat(8).
|
||||
/// \param SplatSizeInBits The size of the pattern in bits. Must divide bit
|
||||
/// width without remainder.
|
||||
bool isSplat(unsigned SplatSizeInBits) const;
|
||||
|
||||
/// @}
|
||||
/// \name Value Generators
|
||||
/// @{
|
||||
@ -1356,7 +1361,7 @@ class APInt {
|
||||
|
||||
/// \brief Count the number of leading one bits.
|
||||
///
|
||||
/// This function is an APInt version of the countLeadingOnes_{32,64}
|
||||
/// This function is an APInt version of the countLeadingOnes
|
||||
/// functions in MathExtras.h. It counts the number of ones from the most
|
||||
/// significant bit to the first zero bit.
|
||||
///
|
||||
@ -1372,7 +1377,7 @@ class APInt {
|
||||
|
||||
/// \brief Count the number of trailing zero bits.
|
||||
///
|
||||
/// This function is an APInt version of the countTrailingZeros_{32,64}
|
||||
/// This function is an APInt version of the countTrailingZeros
|
||||
/// functions in MathExtras.h. It counts the number of zeros from the least
|
||||
/// significant bit to the first set bit.
|
||||
///
|
||||
@ -1382,7 +1387,7 @@ class APInt {
|
||||
|
||||
/// \brief Count the number of trailing one bits.
|
||||
///
|
||||
/// This function is an APInt version of the countTrailingOnes_{32,64}
|
||||
/// This function is an APInt version of the countTrailingOnes
|
||||
/// functions in MathExtras.h. It counts the number of ones from the least
|
||||
/// significant bit to the first zero bit.
|
||||
///
|
||||
@ -1390,19 +1395,19 @@ class APInt {
|
||||
/// of ones from the least significant bit to the first zero bit.
|
||||
unsigned countTrailingOnes() const {
|
||||
if (isSingleWord())
|
||||
return CountTrailingOnes_64(VAL);
|
||||
return llvm::countTrailingOnes(VAL);
|
||||
return countTrailingOnesSlowCase();
|
||||
}
|
||||
|
||||
/// \brief Count the number of bits set.
|
||||
///
|
||||
/// This function is an APInt version of the countPopulation_{32,64} functions
|
||||
/// This function is an APInt version of the countPopulation functions
|
||||
/// in MathExtras.h. It counts the number of 1 bits in the APInt value.
|
||||
///
|
||||
/// \returns 0 if the value is zero, otherwise returns the number of set bits.
|
||||
unsigned countPopulation() const {
|
||||
if (isSingleWord())
|
||||
return CountPopulation_64(VAL);
|
||||
return llvm::countPopulation(VAL);
|
||||
return countPopulationSlowCase();
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,12 @@ class APSInt : public APInt {
|
||||
}
|
||||
using APInt::toString;
|
||||
|
||||
/// \brief Get the correctly-extended \c int64_t value.
|
||||
int64_t getExtValue() const {
|
||||
assert(getMinSignedBits() <= 64 && "Too many bits for int64_t");
|
||||
return isSigned() ? getSExtValue() : getZExtValue();
|
||||
}
|
||||
|
||||
APSInt LLVM_ATTRIBUTE_UNUSED_RESULT trunc(uint32_t width) const {
|
||||
return APSInt(APInt::trunc(width), IsUnsigned);
|
||||
}
|
||||
@ -133,14 +139,27 @@ class APSInt : public APInt {
|
||||
assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!");
|
||||
return eq(RHS);
|
||||
}
|
||||
inline bool operator==(int64_t RHS) const {
|
||||
return isSameValue(*this, APSInt(APInt(64, RHS), true));
|
||||
}
|
||||
inline bool operator!=(const APSInt& RHS) const {
|
||||
return !((*this) == RHS);
|
||||
}
|
||||
inline bool operator!=(int64_t RHS) const {
|
||||
return !((*this) == RHS);
|
||||
|
||||
bool operator==(int64_t RHS) const {
|
||||
return compareValues(*this, get(RHS)) == 0;
|
||||
}
|
||||
bool operator!=(int64_t RHS) const {
|
||||
return compareValues(*this, get(RHS)) != 0;
|
||||
}
|
||||
bool operator<=(int64_t RHS) const {
|
||||
return compareValues(*this, get(RHS)) <= 0;
|
||||
}
|
||||
bool operator>=(int64_t RHS) const {
|
||||
return compareValues(*this, get(RHS)) >= 0;
|
||||
}
|
||||
bool operator<(int64_t RHS) const {
|
||||
return compareValues(*this, get(RHS)) < 0;
|
||||
}
|
||||
bool operator>(int64_t RHS) const {
|
||||
return compareValues(*this, get(RHS)) > 0;
|
||||
}
|
||||
|
||||
// The remaining operators just wrap the logic of APInt, but retain the
|
||||
@ -260,37 +279,49 @@ class APSInt : public APInt {
|
||||
/// \brief Determine if two APSInts have the same value, zero- or
|
||||
/// sign-extending as needed.
|
||||
static bool isSameValue(const APSInt &I1, const APSInt &I2) {
|
||||
return !compareValues(I1, I2);
|
||||
}
|
||||
|
||||
/// \brief Compare underlying values of two numbers.
|
||||
static int compareValues(const APSInt &I1, const APSInt &I2) {
|
||||
if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
|
||||
return I1 == I2;
|
||||
return I1 == I2 ? 0 : I1 > I2 ? 1 : -1;
|
||||
|
||||
// Check for a bit-width mismatch.
|
||||
if (I1.getBitWidth() > I2.getBitWidth())
|
||||
return isSameValue(I1, I2.extend(I1.getBitWidth()));
|
||||
return compareValues(I1, I2.extend(I1.getBitWidth()));
|
||||
else if (I2.getBitWidth() > I1.getBitWidth())
|
||||
return isSameValue(I1.extend(I2.getBitWidth()), I2);
|
||||
|
||||
assert(I1.isSigned() != I2.isSigned());
|
||||
return compareValues(I1.extend(I2.getBitWidth()), I2);
|
||||
|
||||
// We have a signedness mismatch. Check for negative values and do an
|
||||
// unsigned compare if signs match.
|
||||
if ((I1.isSigned() && I1.isNegative()) ||
|
||||
(!I1.isSigned() && I2.isNegative()))
|
||||
return false;
|
||||
// unsigned compare if both are positive.
|
||||
if (I1.isSigned()) {
|
||||
assert(!I2.isSigned() && "Expected signed mismatch");
|
||||
if (I1.isNegative())
|
||||
return -1;
|
||||
} else {
|
||||
assert(I2.isSigned() && "Expected signed mismatch");
|
||||
if (I2.isNegative())
|
||||
return 1;
|
||||
}
|
||||
|
||||
return I1.eq(I2);
|
||||
return I1.eq(I2) ? 0 : I1.ugt(I2) ? 1 : -1;
|
||||
}
|
||||
|
||||
static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); }
|
||||
static APSInt getUnsigned(uint64_t X) { return APSInt(APInt(64, X), true); }
|
||||
|
||||
/// Profile - Used to insert APSInt objects, or objects that contain APSInt
|
||||
/// objects, into FoldingSets.
|
||||
void Profile(FoldingSetNodeID& ID) const;
|
||||
};
|
||||
|
||||
inline bool operator==(int64_t V1, const APSInt& V2) {
|
||||
return V2 == V1;
|
||||
}
|
||||
inline bool operator!=(int64_t V1, const APSInt& V2) {
|
||||
return V2 != V1;
|
||||
}
|
||||
inline bool operator==(int64_t V1, const APSInt &V2) { return V2 == V1; }
|
||||
inline bool operator!=(int64_t V1, const APSInt &V2) { return V2 != V1; }
|
||||
inline bool operator<=(int64_t V1, const APSInt &V2) { return V2 >= V1; }
|
||||
inline bool operator>=(int64_t V1, const APSInt &V2) { return V2 <= V1; }
|
||||
inline bool operator<(int64_t V1, const APSInt &V2) { return V2 > V1; }
|
||||
inline bool operator>(int64_t V1, const APSInt &V2) { return V2 < V1; }
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const APSInt &I) {
|
||||
I.print(OS, I.isSigned());
|
||||
|
@ -11,7 +11,6 @@
|
||||
#define LLVM_ADT_ARRAYREF_H
|
||||
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <vector>
|
||||
|
||||
@ -44,19 +43,6 @@ namespace llvm {
|
||||
/// The number of elements.
|
||||
size_type Length;
|
||||
|
||||
/// \brief A dummy "optional" type that is only created by implicit
|
||||
/// conversion from a reference to T.
|
||||
///
|
||||
/// This type must *only* be used in a function argument or as a copy of
|
||||
/// a function argument, as otherwise it will hold a pointer to a temporary
|
||||
/// past that temporaries' lifetime.
|
||||
struct TRefOrNothing {
|
||||
const T *TPtr;
|
||||
|
||||
TRefOrNothing() : TPtr(nullptr) {}
|
||||
TRefOrNothing(const T &TRef) : TPtr(&TRef) {}
|
||||
};
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
@ -97,12 +83,10 @@ namespace llvm {
|
||||
/*implicit*/ LLVM_CONSTEXPR ArrayRef(const T (&Arr)[N])
|
||||
: Data(Arr), Length(N) {}
|
||||
|
||||
#if LLVM_HAS_INITIALIZER_LISTS
|
||||
/// Construct an ArrayRef from a std::initializer_list.
|
||||
/*implicit*/ ArrayRef(const std::initializer_list<T> &Vec)
|
||||
: Data(Vec.begin() == Vec.end() ? (T*)0 : Vec.begin()),
|
||||
Length(Vec.size()) {}
|
||||
#endif
|
||||
|
||||
/// Construct an ArrayRef<const T*> from ArrayRef<T*>. This uses SFINAE to
|
||||
/// ensure that only ArrayRefs of pointers can be converted.
|
||||
@ -112,6 +96,25 @@ namespace llvm {
|
||||
std::is_convertible<U *const *, T const *>::value>::type* = 0)
|
||||
: Data(A.data()), Length(A.size()) {}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from a SmallVector<T*>. This is
|
||||
/// templated in order to avoid instantiating SmallVectorTemplateCommon<T>
|
||||
/// whenever we copy-construct an ArrayRef.
|
||||
template<typename U, typename DummyT>
|
||||
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<U*, DummyT> &Vec,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *,
|
||||
T const *>::value>::type* = 0)
|
||||
: Data(Vec.data()), Length(Vec.size()) {
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef<const T*> from std::vector<T*>. This uses SFINAE
|
||||
/// to ensure that only vectors of pointers can be converted.
|
||||
template<typename U, typename A>
|
||||
ArrayRef(const std::vector<U *, A> &Vec,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<U *const *, T const *>::value>::type* = 0)
|
||||
: Data(Vec.data()), Length(Vec.size()) {}
|
||||
|
||||
/// @}
|
||||
/// @name Simple Operations
|
||||
/// @{
|
||||
@ -153,13 +156,9 @@ namespace llvm {
|
||||
bool equals(ArrayRef RHS) const {
|
||||
if (Length != RHS.Length)
|
||||
return false;
|
||||
// Don't use std::equal(), since it asserts in MSVC on nullptr iterators.
|
||||
for (auto L = begin(), LE = end(), R = RHS.begin(); L != LE; ++L, ++R)
|
||||
// Match std::equal() in using == (instead of !=) to minimize API
|
||||
// requirements of ArrayRef'ed types.
|
||||
if (!(*L == *R))
|
||||
return false;
|
||||
return true;
|
||||
if (Length == 0)
|
||||
return true;
|
||||
return std::equal(begin(), end(), RHS.begin());
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
@ -203,47 +202,6 @@ namespace llvm {
|
||||
return std::vector<T>(Data, Data+Length);
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @{
|
||||
/// @name Convenience methods
|
||||
|
||||
/// @brief Predicate for testing that the array equals the exact sequence of
|
||||
/// arguments.
|
||||
///
|
||||
/// Will return false if the size is not equal to the exact number of
|
||||
/// arguments given or if the array elements don't equal the argument
|
||||
/// elements in order. Currently supports up to 16 arguments, but can
|
||||
/// easily be extended.
|
||||
bool equals(TRefOrNothing Arg0 = TRefOrNothing(),
|
||||
TRefOrNothing Arg1 = TRefOrNothing(),
|
||||
TRefOrNothing Arg2 = TRefOrNothing(),
|
||||
TRefOrNothing Arg3 = TRefOrNothing(),
|
||||
TRefOrNothing Arg4 = TRefOrNothing(),
|
||||
TRefOrNothing Arg5 = TRefOrNothing(),
|
||||
TRefOrNothing Arg6 = TRefOrNothing(),
|
||||
TRefOrNothing Arg7 = TRefOrNothing(),
|
||||
TRefOrNothing Arg8 = TRefOrNothing(),
|
||||
TRefOrNothing Arg9 = TRefOrNothing(),
|
||||
TRefOrNothing Arg10 = TRefOrNothing(),
|
||||
TRefOrNothing Arg11 = TRefOrNothing(),
|
||||
TRefOrNothing Arg12 = TRefOrNothing(),
|
||||
TRefOrNothing Arg13 = TRefOrNothing(),
|
||||
TRefOrNothing Arg14 = TRefOrNothing(),
|
||||
TRefOrNothing Arg15 = TRefOrNothing()) {
|
||||
TRefOrNothing Args[] = {Arg0, Arg1, Arg2, Arg3, Arg4, Arg5,
|
||||
Arg6, Arg7, Arg8, Arg9, Arg10, Arg11,
|
||||
Arg12, Arg13, Arg14, Arg15};
|
||||
if (size() > array_lengthof(Args))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0, e = size(); i != e; ++i)
|
||||
if (Args[i].TPtr == nullptr || (*this)[i] != *Args[i].TPtr)
|
||||
return false;
|
||||
|
||||
// Either the size is exactly as many args, or the next arg must be null.
|
||||
return size() == array_lengthof(Args) || Args[size()].TPtr == nullptr;
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,9 @@ class BitVector {
|
||||
|
||||
enum { BITWORD_SIZE = (unsigned)sizeof(BitWord) * CHAR_BIT };
|
||||
|
||||
static_assert(BITWORD_SIZE == 64 || BITWORD_SIZE == 32,
|
||||
"Unsupported word size");
|
||||
|
||||
BitWord *Bits; // Actual bits.
|
||||
unsigned Size; // Size of bitvector in bits.
|
||||
unsigned Capacity; // Size of allocated memory in BitWord.
|
||||
@ -50,7 +53,7 @@ class BitVector {
|
||||
BitPos = Idx % BITWORD_SIZE;
|
||||
}
|
||||
|
||||
~reference() {}
|
||||
reference(const reference&) = default;
|
||||
|
||||
reference &operator=(reference t) {
|
||||
*this = bool(t);
|
||||
@ -118,12 +121,7 @@ class BitVector {
|
||||
size_type count() const {
|
||||
unsigned NumBits = 0;
|
||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
||||
if (sizeof(BitWord) == 4)
|
||||
NumBits += CountPopulation_32((uint32_t)Bits[i]);
|
||||
else if (sizeof(BitWord) == 8)
|
||||
NumBits += CountPopulation_64(Bits[i]);
|
||||
else
|
||||
llvm_unreachable("Unsupported!");
|
||||
NumBits += countPopulation(Bits[i]);
|
||||
return NumBits;
|
||||
}
|
||||
|
||||
@ -157,13 +155,8 @@ class BitVector {
|
||||
/// of the bits are set.
|
||||
int find_first() const {
|
||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
||||
if (Bits[i] != 0) {
|
||||
if (sizeof(BitWord) == 4)
|
||||
return i * BITWORD_SIZE + countTrailingZeros((uint32_t)Bits[i]);
|
||||
if (sizeof(BitWord) == 8)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
llvm_unreachable("Unsupported!");
|
||||
}
|
||||
if (Bits[i] != 0)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -180,23 +173,13 @@ class BitVector {
|
||||
// Mask off previous bits.
|
||||
Copy &= ~0UL << BitPos;
|
||||
|
||||
if (Copy != 0) {
|
||||
if (sizeof(BitWord) == 4)
|
||||
return WordPos * BITWORD_SIZE + countTrailingZeros((uint32_t)Copy);
|
||||
if (sizeof(BitWord) == 8)
|
||||
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
||||
llvm_unreachable("Unsupported!");
|
||||
}
|
||||
if (Copy != 0)
|
||||
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
||||
|
||||
// Check subsequent words.
|
||||
for (unsigned i = WordPos+1; i < NumBitWords(size()); ++i)
|
||||
if (Bits[i] != 0) {
|
||||
if (sizeof(BitWord) == 4)
|
||||
return i * BITWORD_SIZE + countTrailingZeros((uint32_t)Bits[i]);
|
||||
if (sizeof(BitWord) == 8)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
llvm_unreachable("Unsupported!");
|
||||
}
|
||||
if (Bits[i] != 0)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -559,7 +542,7 @@ class BitVector {
|
||||
|
||||
template<bool AddBits, bool InvertMask>
|
||||
void applyMask(const uint32_t *Mask, unsigned MaskWords) {
|
||||
assert(BITWORD_SIZE % 32 == 0 && "Unsupported BitWord size.");
|
||||
static_assert(BITWORD_SIZE % 32 == 0, "Unsupported BitWord size.");
|
||||
MaskWords = std::min(MaskWords, (size() + 31) / 32);
|
||||
const unsigned Scale = BITWORD_SIZE / 32;
|
||||
unsigned i;
|
||||
|
@ -77,6 +77,8 @@ class DeltaAlgorithm {
|
||||
/// ExecuteOneTest - Execute a single test predicate on the change set \p S.
|
||||
virtual bool ExecuteOneTest(const changeset_ty &S) = 0;
|
||||
|
||||
DeltaAlgorithm& operator=(const DeltaAlgorithm&) = default;
|
||||
|
||||
public:
|
||||
virtual ~DeltaAlgorithm();
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_ADT_DENSEMAP_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/EpochTracker.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
@ -50,7 +51,7 @@ class DenseMapIterator;
|
||||
|
||||
template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
|
||||
typename BucketT>
|
||||
class DenseMapBase {
|
||||
class DenseMapBase : public DebugEpochBase {
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
typedef KeyT key_type;
|
||||
@ -62,16 +63,17 @@ class DenseMapBase {
|
||||
const_iterator;
|
||||
inline iterator begin() {
|
||||
// When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().
|
||||
return empty() ? end() : iterator(getBuckets(), getBucketsEnd());
|
||||
return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this);
|
||||
}
|
||||
inline iterator end() {
|
||||
return iterator(getBucketsEnd(), getBucketsEnd(), true);
|
||||
return iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
}
|
||||
inline const_iterator begin() const {
|
||||
return empty() ? end() : const_iterator(getBuckets(), getBucketsEnd());
|
||||
return empty() ? end()
|
||||
: const_iterator(getBuckets(), getBucketsEnd(), *this);
|
||||
}
|
||||
inline const_iterator end() const {
|
||||
return const_iterator(getBucketsEnd(), getBucketsEnd(), true);
|
||||
return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true);
|
||||
}
|
||||
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const {
|
||||
@ -81,11 +83,13 @@ class DenseMapBase {
|
||||
|
||||
/// Grow the densemap so that it has at least Size buckets. Does not shrink
|
||||
void resize(size_type Size) {
|
||||
incrementEpoch();
|
||||
if (Size > getNumBuckets())
|
||||
grow(Size);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
incrementEpoch();
|
||||
if (getNumEntries() == 0 && getNumTombstones() == 0) return;
|
||||
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
@ -96,16 +100,18 @@ class DenseMapBase {
|
||||
}
|
||||
|
||||
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
|
||||
unsigned NumEntries = getNumEntries();
|
||||
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
|
||||
if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
|
||||
if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
|
||||
P->getSecond().~ValueT();
|
||||
decrementNumEntries();
|
||||
--NumEntries;
|
||||
}
|
||||
P->getFirst() = EmptyKey;
|
||||
}
|
||||
}
|
||||
assert(getNumEntries() == 0 && "Node count imbalance!");
|
||||
assert(NumEntries == 0 && "Node count imbalance!");
|
||||
setNumEntries(0);
|
||||
setNumTombstones(0);
|
||||
}
|
||||
|
||||
@ -118,13 +124,13 @@ class DenseMapBase {
|
||||
iterator find(const KeyT &Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return iterator(TheBucket, getBucketsEnd(), true);
|
||||
return iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
const_iterator find(const KeyT &Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return const_iterator(TheBucket, getBucketsEnd(), true);
|
||||
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
|
||||
@ -137,14 +143,14 @@ class DenseMapBase {
|
||||
iterator find_as(const LookupKeyT &Val) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return iterator(TheBucket, getBucketsEnd(), true);
|
||||
return iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
template<class LookupKeyT>
|
||||
const_iterator find_as(const LookupKeyT &Val) const {
|
||||
const BucketT *TheBucket;
|
||||
if (LookupBucketFor(Val, TheBucket))
|
||||
return const_iterator(TheBucket, getBucketsEnd(), true);
|
||||
return const_iterator(TheBucket, getBucketsEnd(), *this, true);
|
||||
return end();
|
||||
}
|
||||
|
||||
@ -163,12 +169,13 @@ class DenseMapBase {
|
||||
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(), true),
|
||||
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(), true), true);
|
||||
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.
|
||||
@ -177,14 +184,15 @@ class DenseMapBase {
|
||||
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
|
||||
BucketT *TheBucket;
|
||||
if (LookupBucketFor(KV.first, TheBucket))
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true),
|
||||
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);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
|
||||
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
|
||||
true);
|
||||
}
|
||||
|
||||
/// insert - Range insertion of pairs.
|
||||
@ -251,7 +259,7 @@ class DenseMapBase {
|
||||
const void *getPointerIntoBucketsArray() const { return getBuckets(); }
|
||||
|
||||
protected:
|
||||
DenseMapBase() {}
|
||||
DenseMapBase() = default;
|
||||
|
||||
void destroyAll() {
|
||||
if (getNumBuckets() == 0) // Nothing to do.
|
||||
@ -264,10 +272,6 @@ class DenseMapBase {
|
||||
P->getSecond().~ValueT();
|
||||
P->getFirst().~KeyT();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
memset((void*)getBuckets(), 0x5a, sizeof(BucketT)*getNumBuckets());
|
||||
#endif
|
||||
}
|
||||
|
||||
void initEmpty() {
|
||||
@ -304,12 +308,6 @@ class DenseMapBase {
|
||||
}
|
||||
B->getFirst().~KeyT();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (OldBucketsBegin != OldBucketsEnd)
|
||||
memset((void*)OldBucketsBegin, 0x5a,
|
||||
sizeof(BucketT) * (OldBucketsEnd - OldBucketsBegin));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename OtherBaseT>
|
||||
@ -335,11 +333,6 @@ class DenseMapBase {
|
||||
}
|
||||
}
|
||||
|
||||
void swap(DenseMapBase& RHS) {
|
||||
std::swap(getNumEntries(), RHS.getNumEntries());
|
||||
std::swap(getNumTombstones(), RHS.getNumTombstones());
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const KeyT &Val) {
|
||||
return KeyInfoT::getHashValue(Val);
|
||||
}
|
||||
@ -431,6 +424,8 @@ class DenseMapBase {
|
||||
}
|
||||
|
||||
BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
|
||||
incrementEpoch();
|
||||
|
||||
// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
|
||||
// the buckets are empty (meaning that many are filled with tombstones),
|
||||
// grow the table.
|
||||
@ -442,11 +437,12 @@ class DenseMapBase {
|
||||
// causing infinite loops in lookup.
|
||||
unsigned NewNumEntries = getNumEntries() + 1;
|
||||
unsigned NumBuckets = getNumBuckets();
|
||||
if (NewNumEntries*4 >= NumBuckets*3) {
|
||||
if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
|
||||
this->grow(NumBuckets * 2);
|
||||
LookupBucketFor(Key, TheBucket);
|
||||
NumBuckets = getNumBuckets();
|
||||
} else if (NumBuckets-(NewNumEntries+getNumTombstones()) <= NumBuckets/8) {
|
||||
} else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <=
|
||||
NumBuckets/8)) {
|
||||
this->grow(NumBuckets);
|
||||
LookupBucketFor(Key, TheBucket);
|
||||
}
|
||||
@ -492,14 +488,14 @@ class DenseMapBase {
|
||||
while (1) {
|
||||
const BucketT *ThisBucket = BucketsPtr + BucketNo;
|
||||
// Found Val's bucket? If so, return it.
|
||||
if (KeyInfoT::isEqual(Val, ThisBucket->getFirst())) {
|
||||
if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
|
||||
FoundBucket = ThisBucket;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we found an empty bucket, the key doesn't exist in the set.
|
||||
// Insert it and return the default value.
|
||||
if (KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey)) {
|
||||
if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
|
||||
// If we've already seen a tombstone while probing, fill it in instead
|
||||
// of the empty bucket we eventually probed to.
|
||||
FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
|
||||
@ -580,6 +576,8 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
}
|
||||
|
||||
void swap(DenseMap& RHS) {
|
||||
this->incrementEpoch();
|
||||
RHS.incrementEpoch();
|
||||
std::swap(Buckets, RHS.Buckets);
|
||||
std::swap(NumEntries, RHS.NumEntries);
|
||||
std::swap(NumTombstones, RHS.NumTombstones);
|
||||
@ -986,9 +984,10 @@ class SmallDenseMap
|
||||
|
||||
template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
|
||||
bool IsConst>
|
||||
class DenseMapIterator {
|
||||
class DenseMapIterator : DebugEpochBase::HandleBase {
|
||||
typedef DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true> ConstIterator;
|
||||
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
|
||||
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
|
||||
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
@ -1002,38 +1001,54 @@ class DenseMapIterator {
|
||||
public:
|
||||
DenseMapIterator() : Ptr(nullptr), End(nullptr) {}
|
||||
|
||||
DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
|
||||
: Ptr(Pos), End(E) {
|
||||
DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
|
||||
bool NoAdvance = false)
|
||||
: DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
|
||||
assert(isHandleInSync() && "invalid construction!");
|
||||
if (!NoAdvance) AdvancePastEmptyBuckets();
|
||||
}
|
||||
|
||||
// If IsConst is true this is a converting constructor from iterator to
|
||||
// const_iterator and the default copy constructor is used.
|
||||
// Otherwise this is a copy constructor for iterator.
|
||||
// Converting ctor from non-const iterators to const iterators. SFINAE'd out
|
||||
// for const iterator destinations so it doesn't end up as a user defined copy
|
||||
// constructor.
|
||||
template <bool IsConstSrc,
|
||||
typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
|
||||
DenseMapIterator(
|
||||
const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false> &I)
|
||||
: Ptr(I.Ptr), End(I.End) {}
|
||||
const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
|
||||
: DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
|
||||
|
||||
reference operator*() const {
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
return *Ptr;
|
||||
}
|
||||
pointer operator->() const {
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
bool operator==(const ConstIterator &RHS) const {
|
||||
return Ptr == RHS.operator->();
|
||||
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
|
||||
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
|
||||
assert(getEpochAddress() == RHS.getEpochAddress() &&
|
||||
"comparing incomparable iterators!");
|
||||
return Ptr == RHS.Ptr;
|
||||
}
|
||||
bool operator!=(const ConstIterator &RHS) const {
|
||||
return Ptr != RHS.operator->();
|
||||
assert((!Ptr || isHandleInSync()) && "handle not in sync!");
|
||||
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
|
||||
assert(getEpochAddress() == RHS.getEpochAddress() &&
|
||||
"comparing incomparable iterators!");
|
||||
return Ptr != RHS.Ptr;
|
||||
}
|
||||
|
||||
inline DenseMapIterator& operator++() { // Preincrement
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
++Ptr;
|
||||
AdvancePastEmptyBuckets();
|
||||
return *this;
|
||||
}
|
||||
DenseMapIterator operator++(int) { // Postincrement
|
||||
assert(isHandleInSync() && "invalid iterator access!");
|
||||
DenseMapIterator tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
|
||||
|
@ -113,9 +113,8 @@ class df_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
while (It != GT::child_end(Node)) {
|
||||
NodeType *Next = *It++;
|
||||
// Has our next sibling been visited?
|
||||
if (Next && !this->Visited.count(Next)) {
|
||||
if (Next && this->Visited.insert(Next).second) {
|
||||
// No, do it now.
|
||||
this->Visited.insert(Next);
|
||||
VisitStack.push_back(std::make_pair(PointerIntTy(Next, 0),
|
||||
GT::child_begin(Next)));
|
||||
return;
|
||||
@ -129,58 +128,59 @@ class df_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
|
||||
public:
|
||||
typedef typename super::pointer pointer;
|
||||
typedef df_iterator<GraphT, SetType, ExtStorage, GT> _Self;
|
||||
|
||||
// Provide static begin and end methods as our public "constructors"
|
||||
static inline _Self begin(const GraphT& G) {
|
||||
return _Self(GT::getEntryNode(G));
|
||||
static df_iterator begin(const GraphT &G) {
|
||||
return df_iterator(GT::getEntryNode(G));
|
||||
}
|
||||
static inline _Self end(const GraphT& G) { return _Self(); }
|
||||
static df_iterator end(const GraphT &G) { return df_iterator(); }
|
||||
|
||||
// Static begin and end methods as our public ctors for external iterators
|
||||
static inline _Self begin(const GraphT& G, SetType &S) {
|
||||
return _Self(GT::getEntryNode(G), S);
|
||||
static df_iterator begin(const GraphT &G, SetType &S) {
|
||||
return df_iterator(GT::getEntryNode(G), S);
|
||||
}
|
||||
static inline _Self end(const GraphT& G, SetType &S) { return _Self(S); }
|
||||
static df_iterator end(const GraphT &G, SetType &S) { return df_iterator(S); }
|
||||
|
||||
inline bool operator==(const _Self& x) const {
|
||||
bool operator==(const df_iterator &x) const {
|
||||
return VisitStack == x.VisitStack;
|
||||
}
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
bool operator!=(const df_iterator &x) const { return !(*this == x); }
|
||||
|
||||
inline pointer operator*() const {
|
||||
return VisitStack.back().first.getPointer();
|
||||
}
|
||||
pointer operator*() const { return VisitStack.back().first.getPointer(); }
|
||||
|
||||
// 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.
|
||||
//
|
||||
inline NodeType *operator->() const { return operator*(); }
|
||||
NodeType *operator->() const { return **this; }
|
||||
|
||||
inline _Self& operator++() { // Preincrement
|
||||
df_iterator &operator++() { // Preincrement
|
||||
toNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// skips all children of the current node and traverses to next node
|
||||
//
|
||||
inline _Self& skipChildren() {
|
||||
/// \brief Skips all children of the current node and traverses to next node
|
||||
///
|
||||
/// Note: This function takes care of incrementing the iterator. If you
|
||||
/// always increment and call this function, you risk walking off the end.
|
||||
df_iterator &skipChildren() {
|
||||
VisitStack.pop_back();
|
||||
if (!VisitStack.empty())
|
||||
toNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline _Self operator++(int) { // Postincrement
|
||||
_Self tmp = *this; ++*this; return tmp;
|
||||
df_iterator operator++(int) { // Postincrement
|
||||
df_iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// nodeVisited - return true if this iterator has already visited the
|
||||
// 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.
|
||||
//
|
||||
inline bool nodeVisited(NodeType *Node) const {
|
||||
bool nodeVisited(NodeType *Node) const {
|
||||
return this->Visited.count(Node) != 0;
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ df_iterator<T> df_end(const T& G) {
|
||||
// Provide an accessor method to use them in range-based patterns.
|
||||
template <class T>
|
||||
iterator_range<df_iterator<T>> depth_first(const T& G) {
|
||||
return iterator_range<df_iterator<T>>(df_begin(G), df_end(G));
|
||||
return make_range(df_begin(G), df_end(G));
|
||||
}
|
||||
|
||||
// Provide global definitions of external depth first iterators...
|
||||
@ -234,8 +234,7 @@ df_ext_iterator<T, SetTy> df_ext_end(const T& G, SetTy &S) {
|
||||
template <class T, class SetTy>
|
||||
iterator_range<df_ext_iterator<T, SetTy>> depth_first_ext(const T& G,
|
||||
SetTy &S) {
|
||||
return iterator_range<df_ext_iterator<T, SetTy>>(df_ext_begin(G, S),
|
||||
df_ext_end(G, S));
|
||||
return make_range(df_ext_begin(G, S), df_ext_end(G, S));
|
||||
}
|
||||
|
||||
|
||||
@ -261,7 +260,7 @@ idf_iterator<T> idf_end(const T& G){
|
||||
// Provide an accessor method to use them in range-based patterns.
|
||||
template <class T>
|
||||
iterator_range<idf_iterator<T>> inverse_depth_first(const T& G) {
|
||||
return iterator_range<idf_iterator<T>>(idf_begin(G), idf_end(G));
|
||||
return make_range(idf_begin(G), idf_end(G));
|
||||
}
|
||||
|
||||
// Provide global definitions of external inverse depth first iterators...
|
||||
@ -286,8 +285,7 @@ idf_ext_iterator<T, SetTy> idf_ext_end(const T& G, SetTy &S) {
|
||||
template <class T, class SetTy>
|
||||
iterator_range<idf_ext_iterator<T, SetTy>> inverse_depth_first_ext(const T& G,
|
||||
SetTy &S) {
|
||||
return iterator_range<idf_ext_iterator<T, SetTy>>(idf_ext_begin(G, S),
|
||||
idf_ext_end(G, S));
|
||||
return make_range(idf_ext_begin(G, S), idf_ext_end(G, S));
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
99
contrib/llvm/include/llvm/ADT/EpochTracker.h
Normal file
99
contrib/llvm/include/llvm/ADT/EpochTracker.h
Normal file
@ -0,0 +1,99 @@
|
||||
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- 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 DebugEpochBase and DebugEpochBase::HandleBase classes.
|
||||
// These can be used to write iterators that are fail-fast when LLVM is built
|
||||
// with asserts enabled.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_EPOCH_TRACKER_H
|
||||
#define LLVM_ADT_EPOCH_TRACKER_H
|
||||
|
||||
#include "llvm/Config/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
|
||||
|
||||
/// \brief A base class for data structure classes wishing to make iterators
|
||||
/// ("handles") pointing into themselves fail-fast. When building without
|
||||
/// asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// DebugEpochBase does not by itself track handles pointing into itself. The
|
||||
/// expectation is that routines touching the handles will poll on
|
||||
/// isHandleInSync at appropriate points to assert that the handle they're using
|
||||
/// is still valid.
|
||||
///
|
||||
class DebugEpochBase {
|
||||
uint64_t Epoch;
|
||||
|
||||
public:
|
||||
DebugEpochBase() : Epoch(0) {}
|
||||
|
||||
/// \brief Calling incrementEpoch invalidates all handles pointing into the
|
||||
/// calling instance.
|
||||
void incrementEpoch() { ++Epoch; }
|
||||
|
||||
/// \brief The destructor calls incrementEpoch to make use-after-free bugs
|
||||
/// more likely to crash deterministically.
|
||||
~DebugEpochBase() { incrementEpoch(); }
|
||||
|
||||
/// \brief A base class for iterator classes ("handles") that wish to poll for
|
||||
/// iterator invalidating modifications in the underlying data structure.
|
||||
/// When LLVM is built without asserts, this class is empty and does nothing.
|
||||
///
|
||||
/// HandleBase does not track the parent data structure by itself. It expects
|
||||
/// the routines modifying the data structure to call incrementEpoch when they
|
||||
/// make an iterator-invalidating modification.
|
||||
///
|
||||
class HandleBase {
|
||||
const uint64_t *EpochAddress;
|
||||
uint64_t EpochAtCreation;
|
||||
|
||||
public:
|
||||
HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {}
|
||||
|
||||
explicit HandleBase(const DebugEpochBase *Parent)
|
||||
: EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {}
|
||||
|
||||
/// \brief Returns true if the DebugEpochBase this Handle is linked to has
|
||||
/// not called incrementEpoch on itself since the creation of this
|
||||
/// HandleBase instance.
|
||||
bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
|
||||
|
||||
/// \brief Returns a pointer to the epoch word stored in the data structure
|
||||
/// this handle points into. Can be used to check if two iterators point
|
||||
/// into the same data structure.
|
||||
const void *getEpochAddress() const { return EpochAddress; }
|
||||
};
|
||||
};
|
||||
|
||||
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <set>
|
||||
|
||||
namespace llvm {
|
||||
@ -254,7 +255,7 @@ class EquivalenceClasses {
|
||||
assert(Node != nullptr && "Dereferencing end()!");
|
||||
return Node->getData();
|
||||
}
|
||||
reference operator->() const { return operator*(); }
|
||||
pointer operator->() const { return &operator*(); }
|
||||
|
||||
member_iterator &operator++() {
|
||||
assert(Node != nullptr && "++'d off the end of the list!");
|
||||
|
@ -18,13 +18,11 @@
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
class APFloat;
|
||||
class APInt;
|
||||
|
||||
/// 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
|
||||
@ -109,6 +107,8 @@ class FoldingSetNodeID;
|
||||
/// back to the bucket to facilitate node removal.
|
||||
///
|
||||
class FoldingSetImpl {
|
||||
virtual void anchor(); // Out of line virtual method.
|
||||
|
||||
protected:
|
||||
/// Buckets - Array of bucket chains.
|
||||
///
|
||||
@ -122,10 +122,11 @@ class FoldingSetImpl {
|
||||
/// is greater than twice the number of buckets.
|
||||
unsigned NumNodes;
|
||||
|
||||
public:
|
||||
explicit FoldingSetImpl(unsigned Log2InitSize = 6);
|
||||
virtual ~FoldingSetImpl();
|
||||
~FoldingSetImpl();
|
||||
|
||||
explicit FoldingSetImpl(unsigned Log2InitSize = 6);
|
||||
|
||||
public:
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Node - This class is used to maintain the singly linked bucket list in
|
||||
/// a folding set.
|
||||
@ -392,7 +393,7 @@ DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X,
|
||||
/// implementation of the folding set to the node class T. T must be a
|
||||
/// subclass of FoldingSetNode and implement a Profile function.
|
||||
///
|
||||
template<class T> class FoldingSet : public FoldingSetImpl {
|
||||
template <class T> class FoldingSet final : public FoldingSetImpl {
|
||||
private:
|
||||
/// GetNodeProfile - Each instantiatation of the FoldingSet needs to provide a
|
||||
/// way to convert nodes into a unique specifier.
|
||||
@ -462,7 +463,7 @@ template<class T> class FoldingSet : public FoldingSetImpl {
|
||||
/// function with signature
|
||||
/// void Profile(llvm::FoldingSetNodeID &, Ctx);
|
||||
template <class T, class Ctx>
|
||||
class ContextualFoldingSet : public FoldingSetImpl {
|
||||
class ContextualFoldingSet final : public FoldingSetImpl {
|
||||
// Unfortunately, this can't derive from FoldingSet<T> because the
|
||||
// construction vtable for FoldingSet<T> requires
|
||||
// FoldingSet<T>::GetNodeProfile to be instantiated, which in turn
|
||||
@ -531,46 +532,6 @@ class ContextualFoldingSet : public FoldingSetImpl {
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// FoldingSetVectorIterator - This implements an iterator for
|
||||
/// FoldingSetVector. It is only necessary because FoldingSetIterator provides
|
||||
/// a value_type of T, while the vector in FoldingSetVector exposes
|
||||
/// a value_type of T*. Fortunately, FoldingSetIterator doesn't expose very
|
||||
/// much besides operator* and operator->, so we just wrap the inner vector
|
||||
/// iterator and perform the extra dereference.
|
||||
template <class T, class VectorIteratorT>
|
||||
class FoldingSetVectorIterator {
|
||||
// Provide a typedef to workaround the lack of correct injected class name
|
||||
// support in older GCCs.
|
||||
typedef FoldingSetVectorIterator<T, VectorIteratorT> SelfT;
|
||||
|
||||
VectorIteratorT Iterator;
|
||||
|
||||
public:
|
||||
FoldingSetVectorIterator(VectorIteratorT I) : Iterator(I) {}
|
||||
|
||||
bool operator==(const SelfT &RHS) const {
|
||||
return Iterator == RHS.Iterator;
|
||||
}
|
||||
bool operator!=(const SelfT &RHS) const {
|
||||
return Iterator != RHS.Iterator;
|
||||
}
|
||||
|
||||
T &operator*() const { return **Iterator; }
|
||||
|
||||
T *operator->() const { return *Iterator; }
|
||||
|
||||
inline SelfT &operator++() {
|
||||
++Iterator;
|
||||
return *this;
|
||||
}
|
||||
SelfT operator++(int) {
|
||||
SelfT tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// FoldingSetVector - This template class combines a FoldingSet and a vector
|
||||
/// to provide the interface of FoldingSet but with deterministic iteration
|
||||
@ -586,12 +547,11 @@ class FoldingSetVector {
|
||||
: Set(Log2InitSize) {
|
||||
}
|
||||
|
||||
typedef FoldingSetVectorIterator<T, typename VectorT::iterator> iterator;
|
||||
typedef pointee_iterator<typename VectorT::iterator> iterator;
|
||||
iterator begin() { return Vector.begin(); }
|
||||
iterator end() { return Vector.end(); }
|
||||
|
||||
typedef FoldingSetVectorIterator<const T, typename VectorT::const_iterator>
|
||||
const_iterator;
|
||||
typedef pointee_iterator<typename VectorT::const_iterator> const_iterator;
|
||||
const_iterator begin() const { return Vector.begin(); }
|
||||
const_iterator end() const { return Vector.end(); }
|
||||
|
||||
@ -735,31 +695,9 @@ template <typename T>
|
||||
class FoldingSetNodeWrapper : public FoldingSetNode {
|
||||
T data;
|
||||
public:
|
||||
explicit FoldingSetNodeWrapper(const T &x) : data(x) {}
|
||||
virtual ~FoldingSetNodeWrapper() {}
|
||||
|
||||
template<typename A1>
|
||||
explicit FoldingSetNodeWrapper(const A1 &a1)
|
||||
: data(a1) {}
|
||||
|
||||
template <typename A1, typename A2>
|
||||
explicit FoldingSetNodeWrapper(const A1 &a1, const A2 &a2)
|
||||
: data(a1,a2) {}
|
||||
|
||||
template <typename A1, typename A2, typename A3>
|
||||
explicit FoldingSetNodeWrapper(const A1 &a1, const A2 &a2, const A3 &a3)
|
||||
: data(a1,a2,a3) {}
|
||||
|
||||
template <typename A1, typename A2, typename A3, typename A4>
|
||||
explicit FoldingSetNodeWrapper(const A1 &a1, const A2 &a2, const A3 &a3,
|
||||
const A4 &a4)
|
||||
: data(a1,a2,a3,a4) {}
|
||||
|
||||
template <typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
explicit FoldingSetNodeWrapper(const A1 &a1, const A2 &a2, const A3 &a3,
|
||||
const A4 &a4, const A5 &a5)
|
||||
: data(a1,a2,a3,a4,a5) {}
|
||||
|
||||
template <typename... Ts>
|
||||
explicit FoldingSetNodeWrapper(Ts &&... Args)
|
||||
: data(std::forward<Ts>(Args)...) {}
|
||||
|
||||
void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); }
|
||||
|
||||
|
@ -55,12 +55,6 @@
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
// Allow detecting C++11 feature availability when building with Clang without
|
||||
// breaking other compilers.
|
||||
#ifndef __has_feature
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief An opaque object representing a hash code.
|
||||
@ -81,7 +75,7 @@ class hash_code {
|
||||
public:
|
||||
/// \brief Default construct a hash_code.
|
||||
/// Note that this leaves the value uninitialized.
|
||||
hash_code() {}
|
||||
hash_code() = default;
|
||||
|
||||
/// \brief Form a hash code directly from a numerical value.
|
||||
hash_code(size_t value) : value(value) {}
|
||||
@ -553,8 +547,6 @@ struct hash_combine_recursive_helper {
|
||||
return buffer_ptr;
|
||||
}
|
||||
|
||||
#if defined(__has_feature) && __has_feature(__cxx_variadic_templates__)
|
||||
|
||||
/// \brief Recursive, variadic combining method.
|
||||
///
|
||||
/// This function recurses through each argument, combining that argument
|
||||
@ -568,53 +560,6 @@ struct hash_combine_recursive_helper {
|
||||
return combine(length, buffer_ptr, buffer_end, args...);
|
||||
}
|
||||
|
||||
#else
|
||||
// Manually expanded recursive combining methods. See variadic above for
|
||||
// documentation.
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T1 &arg1, const T2 &arg2, const T3 &arg3,
|
||||
const T4 &arg4, const T5 &arg5, const T6 &arg6) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
|
||||
return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6);
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T1 &arg1, const T2 &arg2, const T3 &arg3,
|
||||
const T4 &arg4, const T5 &arg5) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
|
||||
return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T1 &arg1, const T2 &arg2, const T3 &arg3,
|
||||
const T4 &arg4) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
|
||||
return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4);
|
||||
}
|
||||
template <typename T1, typename T2, typename T3>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T1 &arg1, const T2 &arg2, const T3 &arg3) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
|
||||
return combine(length, buffer_ptr, buffer_end, arg2, arg3);
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T1 &arg1, const T2 &arg2) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
|
||||
return combine(length, buffer_ptr, buffer_end, arg2);
|
||||
}
|
||||
template <typename T1>
|
||||
hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
|
||||
const T1 &arg1) {
|
||||
buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
|
||||
return combine(length, buffer_ptr, buffer_end);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// \brief Base case for recursive, variadic combining.
|
||||
///
|
||||
/// The base case when combining arguments recursively is reached when all
|
||||
@ -643,9 +588,6 @@ struct hash_combine_recursive_helper {
|
||||
} // namespace detail
|
||||
} // namespace hashing
|
||||
|
||||
|
||||
#if __has_feature(__cxx_variadic_templates__)
|
||||
|
||||
/// \brief Combine values into a single hash_code.
|
||||
///
|
||||
/// This routine accepts a varying number of arguments of any type. It will
|
||||
@ -663,52 +605,6 @@ template <typename ...Ts> hash_code hash_combine(const Ts &...args) {
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, args...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// What follows are manually exploded overloads for each argument width. See
|
||||
// the above variadic definition for documentation and specification.
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6>
|
||||
hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
|
||||
const T4 &arg4, const T5 &arg5, const T6 &arg6) {
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64,
|
||||
arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
|
||||
const T4 &arg4, const T5 &arg5) {
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64,
|
||||
arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
|
||||
const T4 &arg4) {
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64,
|
||||
arg1, arg2, arg3, arg4);
|
||||
}
|
||||
template <typename T1, typename T2, typename T3>
|
||||
hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3) {
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3);
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
hash_code hash_combine(const T1 &arg1, const T2 &arg2) {
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2);
|
||||
}
|
||||
template <typename T1>
|
||||
hash_code hash_combine(const T1 &arg1) {
|
||||
::llvm::hashing::detail::hash_combine_recursive_helper helper;
|
||||
return helper.combine(0, helper.buffer, helper.buffer + 64, arg1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Implementation details for implementations of hash_value overloads provided
|
||||
// here.
|
||||
namespace hashing {
|
||||
|
@ -33,8 +33,8 @@ class ImmutableListImpl : public FoldingSetNode {
|
||||
|
||||
friend class ImmutableListFactory<T>;
|
||||
|
||||
void operator=(const ImmutableListImpl&) LLVM_DELETED_FUNCTION;
|
||||
ImmutableListImpl(const ImmutableListImpl&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const ImmutableListImpl&) = delete;
|
||||
ImmutableListImpl(const ImmutableListImpl&) = delete;
|
||||
|
||||
public:
|
||||
const T& getHead() const { return Head; }
|
||||
|
@ -122,8 +122,8 @@ class ImmutableMap {
|
||||
}
|
||||
|
||||
private:
|
||||
Factory(const Factory& RHS) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Factory& RHS) LLVM_DELETED_FUNCTION;
|
||||
Factory(const Factory& RHS) = delete;
|
||||
void operator=(const Factory& RHS) = delete;
|
||||
};
|
||||
|
||||
bool contains(key_type_ref K) const {
|
||||
@ -203,33 +203,14 @@ class ImmutableMap {
|
||||
// Iterators.
|
||||
//===--------------------------------------------------===//
|
||||
|
||||
class iterator {
|
||||
typename TreeTy::iterator itr;
|
||||
|
||||
iterator() {}
|
||||
iterator(TreeTy* t) : itr(t) {}
|
||||
class iterator : public ImutAVLValueIterator<ImmutableMap> {
|
||||
iterator() = default;
|
||||
explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
|
||||
friend class ImmutableMap;
|
||||
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef typename ImmutableMap<KeyT,ValT,ValInfo>::value_type value_type;
|
||||
typedef typename ImmutableMap<KeyT,ValT,ValInfo>::value_type_ref reference;
|
||||
typedef typename iterator::value_type *pointer;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
typename iterator::reference operator*() const { return itr->getValue(); }
|
||||
typename iterator::pointer operator->() const { return &itr->getValue(); }
|
||||
|
||||
key_type_ref getKey() const { return itr->getValue().first; }
|
||||
data_type_ref getData() const { return itr->getValue().second; }
|
||||
|
||||
iterator& operator++() { ++itr; return *this; }
|
||||
iterator operator++(int) { iterator tmp(*this); ++itr; return tmp; }
|
||||
iterator& operator--() { --itr; return *this; }
|
||||
iterator operator--(int) { iterator tmp(*this); --itr; return tmp; }
|
||||
|
||||
bool operator==(const iterator& RHS) const { return RHS.itr == itr; }
|
||||
bool operator!=(const iterator& RHS) const { return RHS.itr != itr; }
|
||||
key_type_ref getKey() const { return (*this)->first; }
|
||||
data_type_ref getData() const { return (*this)->second; }
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator(Root); }
|
||||
@ -376,30 +357,17 @@ class ImmutableMapRef {
|
||||
//===--------------------------------------------------===//
|
||||
// Iterators.
|
||||
//===--------------------------------------------------===//
|
||||
|
||||
class iterator {
|
||||
typename TreeTy::iterator itr;
|
||||
|
||||
iterator() {}
|
||||
iterator(TreeTy* t) : itr(t) {}
|
||||
|
||||
class iterator : public ImutAVLValueIterator<ImmutableMapRef> {
|
||||
iterator() = default;
|
||||
explicit iterator(TreeTy *Tree) : iterator::ImutAVLValueIterator(Tree) {}
|
||||
friend class ImmutableMapRef;
|
||||
|
||||
|
||||
public:
|
||||
value_type_ref operator*() const { return itr->getValue(); }
|
||||
value_type* operator->() const { return &itr->getValue(); }
|
||||
|
||||
key_type_ref getKey() const { return itr->getValue().first; }
|
||||
data_type_ref getData() const { return itr->getValue().second; }
|
||||
|
||||
|
||||
iterator& operator++() { ++itr; return *this; }
|
||||
iterator operator++(int) { iterator tmp(*this); ++itr; return tmp; }
|
||||
iterator& operator--() { --itr; return *this; }
|
||||
iterator operator--(int) { iterator tmp(*this); --itr; return tmp; }
|
||||
bool operator==(const iterator& RHS) const { return RHS.itr == itr; }
|
||||
bool operator!=(const iterator& RHS) const { return RHS.itr != itr; }
|
||||
key_type_ref getKey() const { return (*this)->first; }
|
||||
data_type_ref getData() const { return (*this)->second; }
|
||||
};
|
||||
|
||||
|
||||
iterator begin() const { return iterator(Root); }
|
||||
iterator end() const { return iterator(); }
|
||||
|
||||
|
@ -142,13 +142,13 @@ class ImutAVLTree {
|
||||
iterator RItr = RHS.begin(), REnd = RHS.end();
|
||||
|
||||
while (LItr != LEnd && RItr != REnd) {
|
||||
if (*LItr == *RItr) {
|
||||
if (&*LItr == &*RItr) {
|
||||
LItr.skipSubTree();
|
||||
RItr.skipSubTree();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!LItr->isElementEqual(*RItr))
|
||||
if (!LItr->isElementEqual(&*RItr))
|
||||
return false;
|
||||
|
||||
++LItr;
|
||||
@ -293,8 +293,8 @@ class ImutAVLTree {
|
||||
height = h;
|
||||
}
|
||||
|
||||
static inline
|
||||
uint32_t computeDigest(ImutAVLTree* L, ImutAVLTree* R, value_type_ref V) {
|
||||
static uint32_t computeDigest(ImutAVLTree *L, ImutAVLTree *R,
|
||||
value_type_ref V) {
|
||||
uint32_t digest = 0;
|
||||
|
||||
if (L)
|
||||
@ -311,7 +311,7 @@ class ImutAVLTree {
|
||||
return digest;
|
||||
}
|
||||
|
||||
inline uint32_t computeDigest() {
|
||||
uint32_t computeDigest() {
|
||||
// Check the lowest bit to determine if digest has actually been
|
||||
// pre-computed.
|
||||
if (hasCachedDigest())
|
||||
@ -429,9 +429,7 @@ class ImutAVLFactory {
|
||||
value_type_ref getValue(TreeTy* T) const { return T->value; }
|
||||
|
||||
// Make sure the index is not the Tombstone or Entry key of the DenseMap.
|
||||
static inline unsigned maskCacheIndex(unsigned I) {
|
||||
return (I & ~0x02);
|
||||
}
|
||||
static unsigned maskCacheIndex(unsigned I) { return (I & ~0x02); }
|
||||
|
||||
unsigned incrementHeight(TreeTy* L, TreeTy* R) const {
|
||||
unsigned hl = getHeight(L);
|
||||
@ -444,7 +442,7 @@ class ImutAVLFactory {
|
||||
typename TreeTy::iterator& TE) {
|
||||
typename TreeTy::iterator I = T->begin(), E = T->end();
|
||||
for ( ; I!=E ; ++I, ++TI) {
|
||||
if (TI == TE || !I->isElementEqual(*TI))
|
||||
if (TI == TE || !I->isElementEqual(&*TI))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -647,24 +645,26 @@ class ImutAVLFactory {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename ImutInfo>
|
||||
class ImutAVLTreeGenericIterator {
|
||||
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;
|
||||
typedef ImutAVLTreeGenericIterator<ImutInfo> _Self;
|
||||
|
||||
inline ImutAVLTreeGenericIterator() {}
|
||||
inline ImutAVLTreeGenericIterator(const TreeTy* Root) {
|
||||
ImutAVLTreeGenericIterator() {}
|
||||
ImutAVLTreeGenericIterator(const TreeTy *Root) {
|
||||
if (Root) stack.push_back(reinterpret_cast<uintptr_t>(Root));
|
||||
}
|
||||
|
||||
TreeTy* operator*() const {
|
||||
TreeTy &operator*() const {
|
||||
assert(!stack.empty());
|
||||
return reinterpret_cast<TreeTy*>(stack.back() & ~Flags);
|
||||
return *reinterpret_cast<TreeTy *>(stack.back() & ~Flags);
|
||||
}
|
||||
TreeTy *operator->() const { return &*this; }
|
||||
|
||||
uintptr_t getVisitState() const {
|
||||
assert(!stack.empty());
|
||||
@ -695,13 +695,15 @@ class ImutAVLTreeGenericIterator {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator==(const _Self& x) const {
|
||||
bool operator==(const ImutAVLTreeGenericIterator &x) const {
|
||||
return stack == x.stack;
|
||||
}
|
||||
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
bool operator!=(const ImutAVLTreeGenericIterator &x) const {
|
||||
return !(*this == x);
|
||||
}
|
||||
|
||||
_Self& operator++() {
|
||||
ImutAVLTreeGenericIterator &operator++() {
|
||||
assert(!stack.empty());
|
||||
TreeTy* Current = reinterpret_cast<TreeTy*>(stack.back() & ~Flags);
|
||||
assert(Current);
|
||||
@ -727,7 +729,7 @@ class ImutAVLTreeGenericIterator {
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Self& operator--() {
|
||||
ImutAVLTreeGenericIterator &operator--() {
|
||||
assert(!stack.empty());
|
||||
TreeTy* Current = reinterpret_cast<TreeTy*>(stack.back() & ~Flags);
|
||||
assert(Current);
|
||||
@ -754,30 +756,34 @@ class ImutAVLTreeGenericIterator {
|
||||
};
|
||||
|
||||
template <typename ImutInfo>
|
||||
class ImutAVLTreeInOrderIterator {
|
||||
class ImutAVLTreeInOrderIterator
|
||||
: public std::iterator<std::bidirectional_iterator_tag,
|
||||
ImutAVLTree<ImutInfo>> {
|
||||
typedef ImutAVLTreeGenericIterator<ImutInfo> InternalIteratorTy;
|
||||
InternalIteratorTy InternalItr;
|
||||
|
||||
public:
|
||||
typedef ImutAVLTree<ImutInfo> TreeTy;
|
||||
typedef ImutAVLTreeInOrderIterator<ImutInfo> _Self;
|
||||
|
||||
ImutAVLTreeInOrderIterator(const TreeTy* Root) : InternalItr(Root) {
|
||||
if (Root) operator++(); // Advance to first element.
|
||||
if (Root)
|
||||
++*this; // Advance to first element.
|
||||
}
|
||||
|
||||
ImutAVLTreeInOrderIterator() : InternalItr() {}
|
||||
|
||||
inline bool operator==(const _Self& x) const {
|
||||
bool operator==(const ImutAVLTreeInOrderIterator &x) const {
|
||||
return InternalItr == x.InternalItr;
|
||||
}
|
||||
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
bool operator!=(const ImutAVLTreeInOrderIterator &x) const {
|
||||
return !(*this == x);
|
||||
}
|
||||
|
||||
inline TreeTy* operator*() const { return *InternalItr; }
|
||||
inline TreeTy* operator->() const { return *InternalItr; }
|
||||
TreeTy &operator*() const { return *InternalItr; }
|
||||
TreeTy *operator->() const { return &*InternalItr; }
|
||||
|
||||
inline _Self& operator++() {
|
||||
ImutAVLTreeInOrderIterator &operator++() {
|
||||
do ++InternalItr;
|
||||
while (!InternalItr.atEnd() &&
|
||||
InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft);
|
||||
@ -785,7 +791,7 @@ class ImutAVLTreeInOrderIterator {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline _Self& operator--() {
|
||||
ImutAVLTreeInOrderIterator &operator--() {
|
||||
do --InternalItr;
|
||||
while (!InternalItr.atBeginning() &&
|
||||
InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft);
|
||||
@ -793,7 +799,7 @@ class ImutAVLTreeInOrderIterator {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void skipSubTree() {
|
||||
void skipSubTree() {
|
||||
InternalItr.skipToParent();
|
||||
|
||||
while (!InternalItr.atEnd() &&
|
||||
@ -802,6 +808,24 @@ class ImutAVLTreeInOrderIterator {
|
||||
}
|
||||
};
|
||||
|
||||
/// Generic iterator that wraps a T::TreeTy::iterator and exposes
|
||||
/// iterator::getValue() on dereference.
|
||||
template <typename T>
|
||||
struct ImutAVLValueIterator
|
||||
: iterator_adaptor_base<
|
||||
ImutAVLValueIterator<T>, typename T::TreeTy::iterator,
|
||||
typename std::iterator_traits<
|
||||
typename T::TreeTy::iterator>::iterator_category,
|
||||
const typename T::value_type> {
|
||||
ImutAVLValueIterator() = default;
|
||||
explicit ImutAVLValueIterator(typename T::TreeTy *Tree)
|
||||
: ImutAVLValueIterator::iterator_adaptor_base(Tree) {}
|
||||
|
||||
typename ImutAVLValueIterator::reference operator*() const {
|
||||
return this->I->getValue();
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Trait classes for Profile information.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -814,7 +838,7 @@ struct ImutProfileInfo {
|
||||
typedef const T value_type;
|
||||
typedef const T& value_type_ref;
|
||||
|
||||
static inline void Profile(FoldingSetNodeID& ID, value_type_ref X) {
|
||||
static void Profile(FoldingSetNodeID &ID, value_type_ref X) {
|
||||
FoldingSetTrait<T>::Profile(X,ID);
|
||||
}
|
||||
};
|
||||
@ -825,7 +849,7 @@ struct ImutProfileInteger {
|
||||
typedef const T value_type;
|
||||
typedef const T& value_type_ref;
|
||||
|
||||
static inline void Profile(FoldingSetNodeID& ID, value_type_ref X) {
|
||||
static void Profile(FoldingSetNodeID &ID, value_type_ref X) {
|
||||
ID.AddInteger(X);
|
||||
}
|
||||
};
|
||||
@ -852,7 +876,7 @@ struct ImutProfileInfo<bool> {
|
||||
typedef const bool value_type;
|
||||
typedef const bool& value_type_ref;
|
||||
|
||||
static inline void Profile(FoldingSetNodeID& ID, value_type_ref X) {
|
||||
static void Profile(FoldingSetNodeID &ID, value_type_ref X) {
|
||||
ID.AddBoolean(X);
|
||||
}
|
||||
};
|
||||
@ -865,7 +889,7 @@ struct ImutProfileInfo<T*> {
|
||||
typedef const T* value_type;
|
||||
typedef value_type value_type_ref;
|
||||
|
||||
static inline void Profile(FoldingSetNodeID &ID, value_type_ref X) {
|
||||
static void Profile(FoldingSetNodeID &ID, value_type_ref X) {
|
||||
ID.AddPointer(X);
|
||||
}
|
||||
};
|
||||
@ -890,18 +914,18 @@ struct ImutContainerInfo : public ImutProfileInfo<T> {
|
||||
typedef bool data_type;
|
||||
typedef bool data_type_ref;
|
||||
|
||||
static inline key_type_ref KeyOfValue(value_type_ref D) { return D; }
|
||||
static inline data_type_ref DataOfValue(value_type_ref) { return true; }
|
||||
static key_type_ref KeyOfValue(value_type_ref D) { return D; }
|
||||
static data_type_ref DataOfValue(value_type_ref) { return true; }
|
||||
|
||||
static inline bool isEqual(key_type_ref LHS, key_type_ref RHS) {
|
||||
static bool isEqual(key_type_ref LHS, key_type_ref RHS) {
|
||||
return std::equal_to<key_type>()(LHS,RHS);
|
||||
}
|
||||
|
||||
static inline bool isLess(key_type_ref LHS, key_type_ref RHS) {
|
||||
static bool isLess(key_type_ref LHS, key_type_ref RHS) {
|
||||
return std::less<key_type>()(LHS,RHS);
|
||||
}
|
||||
|
||||
static inline bool isDataEqual(data_type_ref,data_type_ref) { return true; }
|
||||
static bool isDataEqual(data_type_ref, data_type_ref) { return true; }
|
||||
};
|
||||
|
||||
/// ImutContainerInfo - Specialization for pointer values to treat pointers
|
||||
@ -916,18 +940,14 @@ struct ImutContainerInfo<T*> : public ImutProfileInfo<T*> {
|
||||
typedef bool data_type;
|
||||
typedef bool data_type_ref;
|
||||
|
||||
static inline key_type_ref KeyOfValue(value_type_ref D) { return D; }
|
||||
static inline data_type_ref DataOfValue(value_type_ref) { return true; }
|
||||
static key_type_ref KeyOfValue(value_type_ref D) { return D; }
|
||||
static data_type_ref DataOfValue(value_type_ref) { return true; }
|
||||
|
||||
static inline bool isEqual(key_type_ref LHS, key_type_ref RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
static bool isEqual(key_type_ref LHS, key_type_ref RHS) { return LHS == RHS; }
|
||||
|
||||
static inline bool isLess(key_type_ref LHS, key_type_ref RHS) {
|
||||
return LHS < RHS;
|
||||
}
|
||||
static bool isLess(key_type_ref LHS, key_type_ref RHS) { return LHS < RHS; }
|
||||
|
||||
static inline bool isDataEqual(data_type_ref,data_type_ref) { return true; }
|
||||
static bool isDataEqual(data_type_ref, data_type_ref) { return true; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1014,8 +1034,8 @@ class ImmutableSet {
|
||||
}
|
||||
|
||||
private:
|
||||
Factory(const Factory& RHS) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const Factory& RHS) LLVM_DELETED_FUNCTION;
|
||||
Factory(const Factory& RHS) = delete;
|
||||
void operator=(const Factory& RHS) = delete;
|
||||
};
|
||||
|
||||
friend class Factory;
|
||||
@ -1059,31 +1079,7 @@ class ImmutableSet {
|
||||
// Iterators.
|
||||
//===--------------------------------------------------===//
|
||||
|
||||
class iterator {
|
||||
typename TreeTy::iterator itr;
|
||||
|
||||
iterator() {}
|
||||
iterator(TreeTy* t) : itr(t) {}
|
||||
friend class ImmutableSet<ValT,ValInfo>;
|
||||
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef typename ImmutableSet<ValT,ValInfo>::value_type value_type;
|
||||
typedef typename ImmutableSet<ValT,ValInfo>::value_type_ref reference;
|
||||
typedef typename iterator::value_type *pointer;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
typename iterator::reference operator*() const { return itr->getValue(); }
|
||||
typename iterator::pointer operator->() const { return &(operator*()); }
|
||||
|
||||
iterator& operator++() { ++itr; return *this; }
|
||||
iterator operator++(int) { iterator tmp(*this); ++itr; return tmp; }
|
||||
iterator& operator--() { --itr; return *this; }
|
||||
iterator operator--(int) { iterator tmp(*this); --itr; return tmp; }
|
||||
|
||||
bool operator==(const iterator& RHS) const { return RHS.itr == itr; }
|
||||
bool operator!=(const iterator& RHS) const { return RHS.itr != itr; }
|
||||
};
|
||||
typedef ImutAVLValueIterator<ImmutableSet> iterator;
|
||||
|
||||
iterator begin() const { return iterator(Root); }
|
||||
iterator end() const { return iterator(); }
|
||||
@ -1094,13 +1090,11 @@ class ImmutableSet {
|
||||
|
||||
unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
|
||||
|
||||
static inline void Profile(FoldingSetNodeID& ID, const ImmutableSet& S) {
|
||||
static void Profile(FoldingSetNodeID &ID, const ImmutableSet &S) {
|
||||
ID.AddPointer(S.Root);
|
||||
}
|
||||
|
||||
inline void Profile(FoldingSetNodeID& ID) const {
|
||||
return Profile(ID,*this);
|
||||
}
|
||||
void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); }
|
||||
|
||||
//===--------------------------------------------------===//
|
||||
// For testing.
|
||||
@ -1150,7 +1144,7 @@ class ImmutableSetRef {
|
||||
if (Root) { Root->release(); }
|
||||
}
|
||||
|
||||
static inline ImmutableSetRef getEmptySet(FactoryTy *F) {
|
||||
static ImmutableSetRef getEmptySet(FactoryTy *F) {
|
||||
return ImmutableSetRef(0, F);
|
||||
}
|
||||
|
||||
@ -1195,21 +1189,7 @@ class ImmutableSetRef {
|
||||
// Iterators.
|
||||
//===--------------------------------------------------===//
|
||||
|
||||
class iterator {
|
||||
typename TreeTy::iterator itr;
|
||||
iterator(TreeTy* t) : itr(t) {}
|
||||
friend class ImmutableSetRef<ValT,ValInfo>;
|
||||
public:
|
||||
iterator() {}
|
||||
inline value_type_ref operator*() const { return itr->getValue(); }
|
||||
inline iterator& operator++() { ++itr; return *this; }
|
||||
inline iterator operator++(int) { iterator tmp(*this); ++itr; return tmp; }
|
||||
inline iterator& operator--() { --itr; return *this; }
|
||||
inline iterator operator--(int) { iterator tmp(*this); --itr; return tmp; }
|
||||
inline bool operator==(const iterator& RHS) const { return RHS.itr == itr; }
|
||||
inline bool operator!=(const iterator& RHS) const { return RHS.itr != itr; }
|
||||
inline value_type *operator->() const { return &(operator*()); }
|
||||
};
|
||||
typedef ImutAVLValueIterator<ImmutableSetRef> iterator;
|
||||
|
||||
iterator begin() const { return iterator(Root); }
|
||||
iterator end() const { return iterator(); }
|
||||
@ -1220,13 +1200,11 @@ class ImmutableSetRef {
|
||||
|
||||
unsigned getHeight() const { return Root ? Root->getHeight() : 0; }
|
||||
|
||||
static inline void Profile(FoldingSetNodeID& ID, const ImmutableSetRef& S) {
|
||||
static void Profile(FoldingSetNodeID &ID, const ImmutableSetRef &S) {
|
||||
ID.AddPointer(S.Root);
|
||||
}
|
||||
|
||||
inline void Profile(FoldingSetNodeID& ID) const {
|
||||
return Profile(ID,*this);
|
||||
}
|
||||
void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); }
|
||||
|
||||
//===--------------------------------------------------===//
|
||||
// For testing.
|
||||
|
@ -21,16 +21,19 @@
|
||||
#define LLVM_ADT_INDEXEDMAP_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <typename T, typename ToIndexT = llvm::identity<unsigned> >
|
||||
class IndexedMap {
|
||||
typedef typename ToIndexT::argument_type IndexT;
|
||||
typedef std::vector<T> StorageT;
|
||||
// Prefer SmallVector with zero inline storage over std::vector. IndexedMaps
|
||||
// can grow very large and SmallVector grows more efficiently as long as T
|
||||
// is trivially copyable.
|
||||
typedef SmallVector<T, 0> StorageT;
|
||||
StorageT storage_;
|
||||
T nullVal_;
|
||||
ToIndexT toIndex_;
|
||||
|
@ -101,6 +101,7 @@
|
||||
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/RecyclingAllocator.h"
|
||||
#include <iterator>
|
||||
@ -496,7 +497,7 @@ class NodeRef {
|
||||
NodeRef() {}
|
||||
|
||||
/// operator bool - Detect a null ref.
|
||||
LLVM_EXPLICIT operator bool() const { return pip.getOpaqueValue(); }
|
||||
explicit operator bool() const { return pip.getOpaqueValue(); }
|
||||
|
||||
/// NodeRef - Create a reference to the node p with n elements.
|
||||
template <typename NodeT>
|
||||
@ -953,11 +954,6 @@ class IntervalMap {
|
||||
RootBranch node;
|
||||
};
|
||||
|
||||
enum {
|
||||
RootDataSize = sizeof(RootBranchData) > sizeof(RootLeaf) ?
|
||||
sizeof(RootBranchData) : sizeof(RootLeaf)
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename Sizer::Allocator Allocator;
|
||||
typedef KeyT KeyType;
|
||||
@ -966,13 +962,7 @@ class IntervalMap {
|
||||
|
||||
private:
|
||||
// The root data is either a RootLeaf or a RootBranchData instance.
|
||||
// We can't put them in a union since C++03 doesn't allow non-trivial
|
||||
// constructors in unions.
|
||||
// Instead, we use a char array with pointer alignment. The alignment is
|
||||
// ensured by the allocator member in the class, but still verified in the
|
||||
// constructor. We don't support keys or values that are more aligned than a
|
||||
// pointer.
|
||||
char data[RootDataSize];
|
||||
AlignedCharArrayUnion<RootLeaf, RootBranchData> data;
|
||||
|
||||
// Tree height.
|
||||
// 0: Leaves in root.
|
||||
@ -993,7 +983,7 @@ class IntervalMap {
|
||||
const char *d;
|
||||
T *t;
|
||||
} u;
|
||||
u.d = data;
|
||||
u.d = data.buffer;
|
||||
return *u.t;
|
||||
}
|
||||
|
||||
@ -1051,7 +1041,7 @@ class IntervalMap {
|
||||
|
||||
public:
|
||||
explicit IntervalMap(Allocator &a) : height(0), rootSize(0), allocator(a) {
|
||||
assert((uintptr_t(data) & (alignOf<RootLeaf>() - 1)) == 0 &&
|
||||
assert((uintptr_t(data.buffer) & (alignOf<RootLeaf>() - 1)) == 0 &&
|
||||
"Insufficient alignment");
|
||||
new(&rootLeaf()) RootLeaf();
|
||||
}
|
||||
|
@ -21,10 +21,9 @@
|
||||
#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
|
||||
#define LLVM_ADT_INTRUSIVEREFCNTPTR_H
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -84,7 +83,7 @@ namespace llvm {
|
||||
friend struct IntrusiveRefCntPtrInfo;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T> struct IntrusiveRefCntPtrInfo {
|
||||
static void retain(T *obj) { obj->Retain(); }
|
||||
static void release(T *obj) { obj->Release(); }
|
||||
@ -114,7 +113,7 @@ class ThreadSafeRefCountedBase {
|
||||
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
|
||||
@ -177,7 +176,7 @@ class ThreadSafeRefCountedBase {
|
||||
|
||||
T* get() const { return Obj; }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return Obj; }
|
||||
explicit operator bool() const { return Obj; }
|
||||
|
||||
void swap(IntrusiveRefCntPtr& other) {
|
||||
T* tmp = other.Obj;
|
||||
@ -268,6 +267,8 @@ class ThreadSafeRefCountedBase {
|
||||
// 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) {
|
||||
|
@ -67,6 +67,11 @@ class MapVector {
|
||||
Vector.clear();
|
||||
}
|
||||
|
||||
void swap(MapVector &RHS) {
|
||||
std::swap(Map, RHS.Map);
|
||||
std::swap(Vector, RHS.Vector);
|
||||
}
|
||||
|
||||
ValueT &operator[](const KeyT &Key) {
|
||||
std::pair<KeyT, unsigned> Pair = std::make_pair(Key, 0);
|
||||
std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair);
|
||||
|
@ -19,9 +19,8 @@
|
||||
namespace llvm {
|
||||
/// \brief A simple null object to allow implicit construction of Optional<T>
|
||||
/// and similar types without having to spell out the specialization's name.
|
||||
enum NoneType {
|
||||
None
|
||||
};
|
||||
enum class NoneType { None };
|
||||
const NoneType None = None;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -70,8 +70,6 @@ class Optional {
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template<typename ...ArgTypes>
|
||||
void emplace(ArgTypes &&...Args) {
|
||||
@ -80,51 +78,6 @@ class Optional {
|
||||
new (storage.buffer) T(std::forward<ArgTypes>(Args)...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/// Create a new object by default-constructing it in place.
|
||||
void emplace() {
|
||||
reset();
|
||||
hasVal = true;
|
||||
new (storage.buffer) T();
|
||||
}
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template<typename T1>
|
||||
void emplace(T1 &&A1) {
|
||||
reset();
|
||||
hasVal = true;
|
||||
new (storage.buffer) T(std::forward<T1>(A1));
|
||||
}
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template<typename T1, typename T2>
|
||||
void emplace(T1 &&A1, T2 &&A2) {
|
||||
reset();
|
||||
hasVal = true;
|
||||
new (storage.buffer) T(std::forward<T1>(A1), std::forward<T2>(A2));
|
||||
}
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template<typename T1, typename T2, typename T3>
|
||||
void emplace(T1 &&A1, T2 &&A2, T3 &&A3) {
|
||||
reset();
|
||||
hasVal = true;
|
||||
new (storage.buffer) T(std::forward<T1>(A1), std::forward<T2>(A2),
|
||||
std::forward<T3>(A3));
|
||||
}
|
||||
|
||||
/// Create a new object by constructing it in place with the given arguments.
|
||||
template<typename T1, typename T2, typename T3, typename T4>
|
||||
void emplace(T1 &&A1, T2 &&A2, T3 &&A3, T4 &&A4) {
|
||||
reset();
|
||||
hasVal = true;
|
||||
new (storage.buffer) T(std::forward<T1>(A1), std::forward<T2>(A2),
|
||||
std::forward<T3>(A3), std::forward<T4>(A4));
|
||||
}
|
||||
|
||||
#endif // LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
static inline Optional create(const T* y) {
|
||||
return y ? Optional(*y) : Optional();
|
||||
}
|
||||
@ -168,7 +121,7 @@ class Optional {
|
||||
const T& getValue() const LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
T& getValue() LLVM_LVALUE_FUNCTION { assert(hasVal); return *getPointer(); }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return hasVal; }
|
||||
explicit operator bool() const { return hasVal; }
|
||||
bool hasValue() const { return hasVal; }
|
||||
const T* operator->() const { return getPointer(); }
|
||||
T* operator->() { return getPointer(); }
|
||||
|
@ -61,7 +61,7 @@ namespace llvm {
|
||||
NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/// PointerUnion - This implements a discriminated union of two pointer types,
|
||||
/// and keeps the discriminator bit-mangled into the low bits of the pointer.
|
||||
/// This allows the implementation to be extremely efficient in space, but
|
||||
@ -80,7 +80,7 @@ namespace llvm {
|
||||
template <typename PT1, typename PT2>
|
||||
class PointerUnion {
|
||||
public:
|
||||
typedef PointerIntPair<void*, 1, bool,
|
||||
typedef PointerIntPair<void*, 1, bool,
|
||||
PointerUnionUIntTraits<PT1,PT2> > ValTy;
|
||||
private:
|
||||
ValTy Val;
|
||||
@ -96,14 +96,14 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
PointerUnion() {}
|
||||
|
||||
|
||||
PointerUnion(PT1 V) : Val(
|
||||
const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {
|
||||
}
|
||||
PointerUnion(PT2 V) : Val(
|
||||
const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)), 1) {
|
||||
}
|
||||
|
||||
|
||||
/// isNull - Return true if the pointer held in the union is null,
|
||||
/// regardless of which type it is.
|
||||
bool isNull() const {
|
||||
@ -111,7 +111,7 @@ namespace llvm {
|
||||
// we recursively strip off low bits if we have a nested PointerUnion.
|
||||
return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
|
||||
}
|
||||
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
/// is<T>() return true if the Union currently holds the type matching T.
|
||||
template<typename T>
|
||||
@ -123,7 +123,7 @@ namespace llvm {
|
||||
int TyNo = Ty::Num;
|
||||
return static_cast<int>(Val.getInt()) == TyNo;
|
||||
}
|
||||
|
||||
|
||||
/// get<T>() - Return the value of the specified pointer type. If the
|
||||
/// specified pointer type is incorrect, assert.
|
||||
template<typename T>
|
||||
@ -131,7 +131,7 @@ namespace llvm {
|
||||
assert(is<T>() && "Invalid accessor called");
|
||||
return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
|
||||
}
|
||||
|
||||
|
||||
/// dyn_cast<T>() - If the current value is of the specified pointer type,
|
||||
/// return it, otherwise return null.
|
||||
template<typename T>
|
||||
@ -160,7 +160,7 @@ namespace llvm {
|
||||
Val.initWithPointer(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// Assignment operators - Allow assigning into this union from either
|
||||
/// pointer type, setting the discriminator to remember what it came from.
|
||||
const PointerUnion &operator=(const PT1 &RHS) {
|
||||
@ -174,7 +174,7 @@ namespace llvm {
|
||||
1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
|
||||
static inline PointerUnion getFromOpaqueValue(void *VP) {
|
||||
PointerUnion V;
|
||||
@ -195,6 +195,12 @@ namespace llvm {
|
||||
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
template<typename PT1, typename PT2>
|
||||
static bool operator<(PointerUnion<PT1, PT2> lhs,
|
||||
PointerUnion<PT1, PT2> rhs) {
|
||||
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
|
||||
}
|
||||
|
||||
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
|
||||
// # low bits available = min(PT1bits,PT2bits)-1.
|
||||
template<typename PT1, typename PT2>
|
||||
@ -208,16 +214,16 @@ namespace llvm {
|
||||
getFromVoidPointer(void *P) {
|
||||
return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
|
||||
// The number of bits available are the min of the two pointer types.
|
||||
enum {
|
||||
NumLowBitsAvailable =
|
||||
NumLowBitsAvailable =
|
||||
PointerLikeTypeTraits<typename PointerUnion<PT1,PT2>::ValTy>
|
||||
::NumLowBitsAvailable
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/// PointerUnion3 - This is a pointer union of three pointer types. See
|
||||
/// documentation for PointerUnion for usage.
|
||||
template <typename PT1, typename PT2, typename PT3>
|
||||
@ -233,7 +239,7 @@ namespace llvm {
|
||||
IsInnerUnion(ValTy val) : Val(val) { }
|
||||
template<typename T>
|
||||
int is() const {
|
||||
return Val.template is<InnerUnion>() &&
|
||||
return Val.template is<InnerUnion>() &&
|
||||
Val.template get<InnerUnion>().template is<T>();
|
||||
}
|
||||
template<typename T>
|
||||
@ -257,7 +263,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
PointerUnion3() {}
|
||||
|
||||
|
||||
PointerUnion3(PT1 V) {
|
||||
Val = InnerUnion(V);
|
||||
}
|
||||
@ -267,12 +273,12 @@ namespace llvm {
|
||||
PointerUnion3(PT3 V) {
|
||||
Val = V;
|
||||
}
|
||||
|
||||
|
||||
/// isNull - Return true if the pointer held in the union is null,
|
||||
/// regardless of which type it is.
|
||||
bool isNull() const { return Val.isNull(); }
|
||||
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
/// is<T>() return true if the Union currently holds the type matching T.
|
||||
template<typename T>
|
||||
int is() const {
|
||||
@ -283,7 +289,7 @@ namespace llvm {
|
||||
>::Return Ty;
|
||||
return Ty(Val).template is<T>();
|
||||
}
|
||||
|
||||
|
||||
/// get<T>() - Return the value of the specified pointer type. If the
|
||||
/// specified pointer type is incorrect, assert.
|
||||
template<typename T>
|
||||
@ -296,7 +302,7 @@ namespace llvm {
|
||||
>::Return Ty;
|
||||
return Ty(Val).template get<T>();
|
||||
}
|
||||
|
||||
|
||||
/// dyn_cast<T>() - If the current value is of the specified pointer type,
|
||||
/// return it, otherwise return null.
|
||||
template<typename T>
|
||||
@ -310,7 +316,7 @@ namespace llvm {
|
||||
Val = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// Assignment operators - Allow assigning into this union from either
|
||||
/// pointer type, setting the discriminator to remember what it came from.
|
||||
const PointerUnion3 &operator=(const PT1 &RHS) {
|
||||
@ -325,7 +331,7 @@ namespace llvm {
|
||||
Val = RHS;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
|
||||
static inline PointerUnion3 getFromOpaqueValue(void *VP) {
|
||||
PointerUnion3 V;
|
||||
@ -333,7 +339,7 @@ namespace llvm {
|
||||
return V;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
|
||||
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
|
||||
template<typename PT1, typename PT2, typename PT3>
|
||||
@ -347,10 +353,10 @@ namespace llvm {
|
||||
getFromVoidPointer(void *P) {
|
||||
return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
|
||||
// The number of bits available are the min of the two pointer types.
|
||||
enum {
|
||||
NumLowBitsAvailable =
|
||||
NumLowBitsAvailable =
|
||||
PointerLikeTypeTraits<typename PointerUnion3<PT1, PT2, PT3>::ValTy>
|
||||
::NumLowBitsAvailable
|
||||
};
|
||||
@ -368,7 +374,7 @@ namespace llvm {
|
||||
ValTy Val;
|
||||
public:
|
||||
PointerUnion4() {}
|
||||
|
||||
|
||||
PointerUnion4(PT1 V) {
|
||||
Val = InnerUnion1(V);
|
||||
}
|
||||
@ -381,12 +387,12 @@ namespace llvm {
|
||||
PointerUnion4(PT4 V) {
|
||||
Val = InnerUnion2(V);
|
||||
}
|
||||
|
||||
|
||||
/// isNull - Return true if the pointer held in the union is null,
|
||||
/// regardless of which type it is.
|
||||
bool isNull() const { return Val.isNull(); }
|
||||
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
/// is<T>() return true if the Union currently holds the type matching T.
|
||||
template<typename T>
|
||||
int is() const {
|
||||
@ -395,10 +401,10 @@ namespace llvm {
|
||||
::llvm::PointerUnionTypeSelector<PT1, T, InnerUnion1,
|
||||
::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1, InnerUnion2 >
|
||||
>::Return Ty;
|
||||
return Val.template is<Ty>() &&
|
||||
return Val.template is<Ty>() &&
|
||||
Val.template get<Ty>().template is<T>();
|
||||
}
|
||||
|
||||
|
||||
/// get<T>() - Return the value of the specified pointer type. If the
|
||||
/// specified pointer type is incorrect, assert.
|
||||
template<typename T>
|
||||
@ -411,7 +417,7 @@ namespace llvm {
|
||||
>::Return Ty;
|
||||
return Val.template get<Ty>().template get<T>();
|
||||
}
|
||||
|
||||
|
||||
/// dyn_cast<T>() - If the current value is of the specified pointer type,
|
||||
/// return it, otherwise return null.
|
||||
template<typename T>
|
||||
@ -425,7 +431,7 @@ namespace llvm {
|
||||
Val = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// Assignment operators - Allow assigning into this union from either
|
||||
/// pointer type, setting the discriminator to remember what it came from.
|
||||
const PointerUnion4 &operator=(const PT1 &RHS) {
|
||||
@ -444,7 +450,7 @@ namespace llvm {
|
||||
Val = InnerUnion2(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
|
||||
static inline PointerUnion4 getFromOpaqueValue(void *VP) {
|
||||
PointerUnion4 V;
|
||||
@ -452,7 +458,7 @@ namespace llvm {
|
||||
return V;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
|
||||
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
|
||||
template<typename PT1, typename PT2, typename PT3, typename PT4>
|
||||
@ -466,10 +472,10 @@ namespace llvm {
|
||||
getFromVoidPointer(void *P) {
|
||||
return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
|
||||
}
|
||||
|
||||
|
||||
// The number of bits available are the min of the two pointer types.
|
||||
enum {
|
||||
NumLowBitsAvailable =
|
||||
NumLowBitsAvailable =
|
||||
PointerLikeTypeTraits<typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>
|
||||
::NumLowBitsAvailable
|
||||
};
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@ -111,53 +112,52 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
}
|
||||
}
|
||||
|
||||
inline po_iterator(NodeType *BB) {
|
||||
po_iterator(NodeType *BB) {
|
||||
this->insertEdge((NodeType*)nullptr, BB);
|
||||
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||
traverseChild();
|
||||
}
|
||||
inline po_iterator() {} // End is when stack is empty.
|
||||
po_iterator() {} // End is when stack is empty.
|
||||
|
||||
inline po_iterator(NodeType *BB, SetType &S) :
|
||||
po_iterator_storage<SetType, ExtStorage>(S) {
|
||||
po_iterator(NodeType *BB, SetType &S)
|
||||
: po_iterator_storage<SetType, ExtStorage>(S) {
|
||||
if (this->insertEdge((NodeType*)nullptr, BB)) {
|
||||
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||
traverseChild();
|
||||
}
|
||||
}
|
||||
|
||||
inline po_iterator(SetType &S) :
|
||||
po_iterator_storage<SetType, ExtStorage>(S) {
|
||||
po_iterator(SetType &S)
|
||||
: po_iterator_storage<SetType, ExtStorage>(S) {
|
||||
} // End is when stack is empty.
|
||||
public:
|
||||
typedef typename super::pointer pointer;
|
||||
typedef po_iterator<GraphT, SetType, ExtStorage, GT> _Self;
|
||||
|
||||
// Provide static "constructors"...
|
||||
static inline _Self begin(GraphT G) { return _Self(GT::getEntryNode(G)); }
|
||||
static inline _Self end (GraphT G) { return _Self(); }
|
||||
|
||||
static inline _Self begin(GraphT G, SetType &S) {
|
||||
return _Self(GT::getEntryNode(G), S);
|
||||
static po_iterator begin(GraphT G) {
|
||||
return po_iterator(GT::getEntryNode(G));
|
||||
}
|
||||
static inline _Self end (GraphT G, SetType &S) { return _Self(S); }
|
||||
static po_iterator end(GraphT G) { return po_iterator(); }
|
||||
|
||||
inline bool operator==(const _Self& x) const {
|
||||
static po_iterator begin(GraphT G, SetType &S) {
|
||||
return po_iterator(GT::getEntryNode(G), S);
|
||||
}
|
||||
static po_iterator end(GraphT G, SetType &S) { return po_iterator(S); }
|
||||
|
||||
bool operator==(const po_iterator &x) const {
|
||||
return VisitStack == x.VisitStack;
|
||||
}
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
bool operator!=(const po_iterator &x) const { return !(*this == x); }
|
||||
|
||||
inline pointer operator*() const {
|
||||
return VisitStack.back().first;
|
||||
}
|
||||
pointer 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.
|
||||
//
|
||||
inline NodeType *operator->() const { return operator*(); }
|
||||
NodeType *operator->() const { return **this; }
|
||||
|
||||
inline _Self& operator++() { // Preincrement
|
||||
po_iterator &operator++() { // Preincrement
|
||||
this->finishPostorder(VisitStack.back().first);
|
||||
VisitStack.pop_back();
|
||||
if (!VisitStack.empty())
|
||||
@ -165,17 +165,23 @@ class po_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline _Self operator++(int) { // Postincrement
|
||||
_Self tmp = *this; ++*this; return tmp;
|
||||
po_iterator operator++(int) { // Postincrement
|
||||
po_iterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide global constructors that automatically figure out correct types...
|
||||
//
|
||||
template <class T>
|
||||
po_iterator<T> po_begin(T G) { return po_iterator<T>::begin(G); }
|
||||
po_iterator<T> po_begin(const T &G) { return po_iterator<T>::begin(G); }
|
||||
template <class T>
|
||||
po_iterator<T> po_end (T G) { return po_iterator<T>::end(G); }
|
||||
po_iterator<T> po_end (const T &G) { return po_iterator<T>::end(G); }
|
||||
|
||||
template <class T> iterator_range<po_iterator<T>> post_order(const T &G) {
|
||||
return make_range(po_begin(G), po_end(G));
|
||||
}
|
||||
|
||||
// Provide global definitions of external postorder iterators...
|
||||
template<class T, class SetType=std::set<typename GraphTraits<T>::NodeType*> >
|
||||
@ -194,6 +200,11 @@ po_ext_iterator<T, SetType> po_ext_end(T G, SetType &S) {
|
||||
return po_ext_iterator<T, SetType>::end(G, S);
|
||||
}
|
||||
|
||||
template <class T, class SetType>
|
||||
iterator_range<po_ext_iterator<T, SetType>> post_order_ext(const T &G, SetType &S) {
|
||||
return make_range(po_ext_begin(G, S), po_ext_end(G, S));
|
||||
}
|
||||
|
||||
// Provide global definitions of inverse post order iterators...
|
||||
template <class T,
|
||||
class SetType = std::set<typename GraphTraits<T>::NodeType*>,
|
||||
@ -204,15 +215,20 @@ struct ipo_iterator : public po_iterator<Inverse<T>, SetType, External > {
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ipo_iterator<T> ipo_begin(T G, bool Reverse = false) {
|
||||
ipo_iterator<T> ipo_begin(const T &G, bool Reverse = false) {
|
||||
return ipo_iterator<T>::begin(G, Reverse);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ipo_iterator<T> ipo_end(T G){
|
||||
ipo_iterator<T> ipo_end(const T &G){
|
||||
return ipo_iterator<T>::end(G);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
iterator_range<ipo_iterator<T>> inverse_post_order(const T &G, bool Reverse = false) {
|
||||
return make_range(ipo_begin(G, Reverse), ipo_end(G));
|
||||
}
|
||||
|
||||
// Provide global definitions of external inverse postorder iterators...
|
||||
template <class T,
|
||||
class SetType = std::set<typename GraphTraits<T>::NodeType*> >
|
||||
@ -224,15 +240,21 @@ struct ipo_ext_iterator : public ipo_iterator<T, SetType, true> {
|
||||
};
|
||||
|
||||
template <class T, class SetType>
|
||||
ipo_ext_iterator<T, SetType> ipo_ext_begin(T G, SetType &S) {
|
||||
ipo_ext_iterator<T, SetType> ipo_ext_begin(const T &G, SetType &S) {
|
||||
return ipo_ext_iterator<T, SetType>::begin(G, S);
|
||||
}
|
||||
|
||||
template <class T, class SetType>
|
||||
ipo_ext_iterator<T, SetType> ipo_ext_end(T G, SetType &S) {
|
||||
ipo_ext_iterator<T, SetType> ipo_ext_end(const T &G, SetType &S) {
|
||||
return ipo_ext_iterator<T, SetType>::end(G, S);
|
||||
}
|
||||
|
||||
template <class T, class SetType>
|
||||
iterator_range<ipo_ext_iterator<T, SetType>>
|
||||
inverse_post_order_ext(const T &G, SetType &S) {
|
||||
return make_range(ipo_ext_begin(G, S), ipo_ext_end(G, S));
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Reverse Post Order CFG iterator code
|
||||
//===--------------------------------------------------------------------===//
|
||||
@ -260,19 +282,17 @@ template<class GraphT, class GT = GraphTraits<GraphT> >
|
||||
class ReversePostOrderTraversal {
|
||||
typedef typename GT::NodeType NodeType;
|
||||
std::vector<NodeType*> Blocks; // Block list in normal PO order
|
||||
inline void Initialize(NodeType *BB) {
|
||||
void Initialize(NodeType *BB) {
|
||||
std::copy(po_begin(BB), po_end(BB), std::back_inserter(Blocks));
|
||||
}
|
||||
public:
|
||||
typedef typename std::vector<NodeType*>::reverse_iterator rpo_iterator;
|
||||
|
||||
inline ReversePostOrderTraversal(GraphT G) {
|
||||
Initialize(GT::getEntryNode(G));
|
||||
}
|
||||
ReversePostOrderTraversal(GraphT G) { Initialize(GT::getEntryNode(G)); }
|
||||
|
||||
// Because we want a reverse post order, use reverse iterators from the vector
|
||||
inline rpo_iterator begin() { return Blocks.rbegin(); }
|
||||
inline rpo_iterator end() { return Blocks.rend(); }
|
||||
rpo_iterator begin() { return Blocks.rbegin(); }
|
||||
rpo_iterator end() { return Blocks.rend(); }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -18,6 +18,8 @@
|
||||
#define LLVM_ADT_STLEXTRAS_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <algorithm> // for std::all_of
|
||||
#include <cassert>
|
||||
#include <cstddef> // for std::size_t
|
||||
#include <cstdlib> // for qsort
|
||||
#include <functional>
|
||||
@ -63,8 +65,6 @@ struct greater_ptr : public std::binary_function<Ty, Ty, bool> {
|
||||
/// a function_ref.
|
||||
template<typename Fn> class function_ref;
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
template<typename Ret, typename ...Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(intptr_t callable, Params ...params);
|
||||
@ -89,112 +89,6 @@ class function_ref<Ret(Params...)> {
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<typename Ret>
|
||||
class function_ref<Ret()> {
|
||||
Ret (*callback)(intptr_t callable);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable) {
|
||||
return (*reinterpret_cast<Callable*>(callable))();
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type * = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()() const { return callback(callable); }
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1>
|
||||
class function_ref<Ret(Param1)> {
|
||||
Ret (*callback)(intptr_t callable, Param1 param1);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Param1 param1) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Param1>(param1));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type * = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Param1 param1) {
|
||||
return callback(callable, std::forward<Param1>(param1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1, typename Param2>
|
||||
class function_ref<Ret(Param1, Param2)> {
|
||||
Ret (*callback)(intptr_t callable, Param1 param1, Param2 param2);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Param1 param1, Param2 param2) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type * = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Param1 param1, Param2 param2) {
|
||||
return callback(callable,
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Param1, typename Param2, typename Param3>
|
||||
class function_ref<Ret(Param1, Param2, Param3)> {
|
||||
Ret (*callback)(intptr_t callable, Param1 param1, Param2 param2, Param3 param3);
|
||||
intptr_t callable;
|
||||
|
||||
template<typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Param1 param1, Param2 param2,
|
||||
Param3 param3) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2),
|
||||
std::forward<Param3>(param3));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Callable>
|
||||
function_ref(Callable &&callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<typename std::remove_reference<Callable>::type,
|
||||
function_ref>::value>::type * = nullptr)
|
||||
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
Ret operator()(Param1 param1, Param2 param2, Param3 param3) {
|
||||
return callback(callable,
|
||||
std::forward<Param1>(param1),
|
||||
std::forward<Param2>(param2),
|
||||
std::forward<Param3>(param3));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// deleter - Very very very simple method that is used to invoke operator
|
||||
// delete on something. It is used like this:
|
||||
//
|
||||
@ -230,7 +124,6 @@ class mapped_iterator {
|
||||
typedef void reference; // Can't modify value returned by fn
|
||||
|
||||
typedef RootIt iterator_type;
|
||||
typedef mapped_iterator<RootIt, UnaryFunc> _Self;
|
||||
|
||||
inline const RootIt &getCurrent() const { return current; }
|
||||
inline const UnaryFunc &getFunc() const { return Fn; }
|
||||
@ -242,34 +135,56 @@ class mapped_iterator {
|
||||
return Fn(*current); // little change
|
||||
}
|
||||
|
||||
_Self& operator++() { ++current; return *this; }
|
||||
_Self& operator--() { --current; return *this; }
|
||||
_Self operator++(int) { _Self __tmp = *this; ++current; return __tmp; }
|
||||
_Self operator--(int) { _Self __tmp = *this; --current; return __tmp; }
|
||||
_Self operator+ (difference_type n) const {
|
||||
return _Self(current + n, Fn);
|
||||
mapped_iterator &operator++() {
|
||||
++current;
|
||||
return *this;
|
||||
}
|
||||
_Self& operator+= (difference_type n) { current += n; return *this; }
|
||||
_Self operator- (difference_type n) const {
|
||||
return _Self(current - n, Fn);
|
||||
mapped_iterator &operator--() {
|
||||
--current;
|
||||
return *this;
|
||||
}
|
||||
mapped_iterator operator++(int) {
|
||||
mapped_iterator __tmp = *this;
|
||||
++current;
|
||||
return __tmp;
|
||||
}
|
||||
mapped_iterator operator--(int) {
|
||||
mapped_iterator __tmp = *this;
|
||||
--current;
|
||||
return __tmp;
|
||||
}
|
||||
mapped_iterator operator+(difference_type n) const {
|
||||
return mapped_iterator(current + n, Fn);
|
||||
}
|
||||
mapped_iterator &operator+=(difference_type n) {
|
||||
current += n;
|
||||
return *this;
|
||||
}
|
||||
mapped_iterator operator-(difference_type n) const {
|
||||
return mapped_iterator(current - n, Fn);
|
||||
}
|
||||
mapped_iterator &operator-=(difference_type n) {
|
||||
current -= n;
|
||||
return *this;
|
||||
}
|
||||
_Self& operator-= (difference_type n) { current -= n; return *this; }
|
||||
reference operator[](difference_type n) const { return *(*this + n); }
|
||||
|
||||
inline bool operator!=(const _Self &X) const { return !operator==(X); }
|
||||
inline bool operator==(const _Self &X) const { return current == X.current; }
|
||||
inline bool operator< (const _Self &X) const { return current < X.current; }
|
||||
bool operator!=(const mapped_iterator &X) const { return !operator==(X); }
|
||||
bool operator==(const mapped_iterator &X) const {
|
||||
return current == X.current;
|
||||
}
|
||||
bool operator<(const mapped_iterator &X) const { return current < X.current; }
|
||||
|
||||
inline difference_type operator-(const _Self &X) const {
|
||||
difference_type operator-(const mapped_iterator &X) const {
|
||||
return current - X.current;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Iterator, class Func>
|
||||
inline mapped_iterator<_Iterator, Func>
|
||||
operator+(typename mapped_iterator<_Iterator, Func>::difference_type N,
|
||||
const mapped_iterator<_Iterator, Func>& X) {
|
||||
return mapped_iterator<_Iterator, Func>(X.getCurrent() - N, X.getFunc());
|
||||
template <class Iterator, class Func>
|
||||
inline mapped_iterator<Iterator, Func>
|
||||
operator+(typename mapped_iterator<Iterator, Func>::difference_type N,
|
||||
const mapped_iterator<Iterator, Func> &X) {
|
||||
return mapped_iterator<Iterator, Func>(X.getCurrent() - N, X.getFunc());
|
||||
}
|
||||
|
||||
|
||||
@ -301,6 +216,28 @@ struct less_second {
|
||||
}
|
||||
};
|
||||
|
||||
// A subset of N3658. More stuff can be added as-needed.
|
||||
|
||||
/// \brief Represents a compile-time sequence of integers.
|
||||
template <class T, T... I> struct integer_sequence {
|
||||
typedef T value_type;
|
||||
|
||||
static LLVM_CONSTEXPR size_t size() { return sizeof...(I); }
|
||||
};
|
||||
|
||||
/// \brief Alias for the common case of a sequence of size_ts.
|
||||
template <size_t... I>
|
||||
struct index_sequence : integer_sequence<std::size_t, I...> {};
|
||||
|
||||
template <std::size_t N, std::size_t... I>
|
||||
struct build_index_impl : build_index_impl<N - 1, N - 1, I...> {};
|
||||
template <std::size_t... I>
|
||||
struct build_index_impl<0, I...> : index_sequence<I...> {};
|
||||
|
||||
/// \brief Creates a compile-time integer sequence for a parameter pack.
|
||||
template <class... Ts>
|
||||
struct index_sequence_for : build_index_impl<sizeof...(Ts)> {};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions for arrays
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -348,10 +285,11 @@ inline int (*get_array_pod_sort_comparator(const T &))
|
||||
/// default to std::less.
|
||||
template<class IteratorTy>
|
||||
inline void array_pod_sort(IteratorTy Start, IteratorTy End) {
|
||||
// Don't dereference start iterator of empty sequence.
|
||||
if (Start == End) return;
|
||||
qsort(&*Start, End-Start, sizeof(*Start),
|
||||
get_array_pod_sort_comparator(*Start));
|
||||
// Don't inefficiently call qsort with one element or trigger undefined
|
||||
// behavior with an empty sequence.
|
||||
auto NElts = End - Start;
|
||||
if (NElts <= 1) return;
|
||||
qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start));
|
||||
}
|
||||
|
||||
template <class IteratorTy>
|
||||
@ -360,9 +298,11 @@ inline void array_pod_sort(
|
||||
int (*Compare)(
|
||||
const typename std::iterator_traits<IteratorTy>::value_type *,
|
||||
const typename std::iterator_traits<IteratorTy>::value_type *)) {
|
||||
// Don't dereference start iterator of empty sequence.
|
||||
if (Start == End) return;
|
||||
qsort(&*Start, End - Start, sizeof(*Start),
|
||||
// Don't inefficiently call qsort with one element or trigger undefined
|
||||
// behavior with an empty sequence.
|
||||
auto NElts = End - Start;
|
||||
if (NElts <= 1) return;
|
||||
qsort(&*Start, NElts, sizeof(*Start),
|
||||
reinterpret_cast<int (*)(const void *, const void *)>(Compare));
|
||||
}
|
||||
|
||||
@ -388,12 +328,18 @@ void DeleteContainerSeconds(Container &C) {
|
||||
C.clear();
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::all_of which take ranges instead of having to pass
|
||||
/// being/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));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Extra additions to <memory>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
// Implement make_unique according to N3656.
|
||||
|
||||
/// \brief Constructs a `new T()` with the given args and returns a
|
||||
@ -427,123 +373,7 @@ make_unique(size_t n) {
|
||||
/// This function isn't used and is only here to provide better compile errors.
|
||||
template <class T, class... Args>
|
||||
typename std::enable_if<std::extent<T>::value != 0>::type
|
||||
make_unique(Args &&...) LLVM_DELETED_FUNCTION;
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique() {
|
||||
return std::unique_ptr<T>(new T());
|
||||
}
|
||||
|
||||
template <class T, class Arg1>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1),
|
||||
std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7, class Arg8>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7), std::forward<Arg8>(arg8)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7, class Arg8, class Arg9>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8, Arg9 &&arg9) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7), std::forward<Arg8>(arg8),
|
||||
std::forward<Arg9>(arg9)));
|
||||
}
|
||||
|
||||
template <class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5,
|
||||
class Arg6, class Arg7, class Arg8, class Arg9, class Arg10>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5,
|
||||
Arg6 &&arg6, Arg7 &&arg7, Arg8 &&arg8, Arg9 &&arg9, Arg10 &&arg10) {
|
||||
return std::unique_ptr<T>(
|
||||
new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Arg3>(arg3), std::forward<Arg4>(arg4),
|
||||
std::forward<Arg5>(arg5), std::forward<Arg6>(arg6),
|
||||
std::forward<Arg7>(arg7), std::forward<Arg8>(arg8),
|
||||
std::forward<Arg9>(arg9), std::forward<Arg10>(arg10)));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename std::enable_if<std::is_array<T>::value &&std::extent<T>::value == 0,
|
||||
std::unique_ptr<T>>::type
|
||||
make_unique(size_t n) {
|
||||
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[n]());
|
||||
}
|
||||
|
||||
#endif
|
||||
make_unique(Args &&...) = delete;
|
||||
|
||||
struct FreeDeleter {
|
||||
void operator()(void* v) {
|
||||
@ -558,6 +388,35 @@ struct pair_hash {
|
||||
}
|
||||
};
|
||||
|
||||
/// A functor like C++14's std::less<void> in its absence.
|
||||
struct less {
|
||||
template <typename A, typename B> bool operator()(A &&a, B &&b) const {
|
||||
return std::forward<A>(a) < std::forward<B>(b);
|
||||
}
|
||||
};
|
||||
|
||||
/// A functor like C++14's std::equal<void> in its absence.
|
||||
struct equal {
|
||||
template <typename A, typename B> bool operator()(A &&a, B &&b) const {
|
||||
return std::forward<A>(a) == std::forward<B>(b);
|
||||
}
|
||||
};
|
||||
|
||||
/// Binary functor that adapts to any other binary functor after dereferencing
|
||||
/// operands.
|
||||
template <typename T> struct deref {
|
||||
T func;
|
||||
// Could be further improved to cope with non-derivable functors and
|
||||
// non-binary functors (should be a variadic template member function
|
||||
// operator()).
|
||||
template <typename A, typename B>
|
||||
auto operator()(A &lhs, B &rhs) const -> decltype(func(*lhs, *rhs)) {
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
return func(*lhs, *rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -90,8 +90,8 @@ 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&) LLVM_DELETED_FUNCTION;
|
||||
ScopedHashTableScope(ScopedHashTableScope&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(ScopedHashTableScope&) = delete;
|
||||
ScopedHashTableScope(ScopedHashTableScope&) = delete;
|
||||
public:
|
||||
ScopedHashTableScope(ScopedHashTable<K, V, KInfo, AllocatorTy> &HT);
|
||||
~ScopedHashTableScope();
|
||||
|
@ -53,6 +53,9 @@ class SmallBitVector {
|
||||
SmallNumDataBits = SmallNumRawBits - SmallNumSizeBits
|
||||
};
|
||||
|
||||
static_assert(NumBaseBits == 64 || NumBaseBits == 32,
|
||||
"Unsupported word size");
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
// Encapsulation of a single bit.
|
||||
@ -63,6 +66,8 @@ class SmallBitVector {
|
||||
public:
|
||||
reference(SmallBitVector &b, unsigned Idx) : TheVector(b), BitPos(Idx) {}
|
||||
|
||||
reference(const reference&) = default;
|
||||
|
||||
reference& operator=(reference t) {
|
||||
*this = bool(t);
|
||||
return *this;
|
||||
@ -177,11 +182,7 @@ class SmallBitVector {
|
||||
size_type count() const {
|
||||
if (isSmall()) {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
if (NumBaseBits == 32)
|
||||
return CountPopulation_32(Bits);
|
||||
if (NumBaseBits == 64)
|
||||
return CountPopulation_64(Bits);
|
||||
llvm_unreachable("Unsupported!");
|
||||
return countPopulation(Bits);
|
||||
}
|
||||
return getPointer()->count();
|
||||
}
|
||||
@ -214,11 +215,7 @@ class SmallBitVector {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
if (Bits == 0)
|
||||
return -1;
|
||||
if (NumBaseBits == 32)
|
||||
return countTrailingZeros(Bits);
|
||||
if (NumBaseBits == 64)
|
||||
return countTrailingZeros(Bits);
|
||||
llvm_unreachable("Unsupported!");
|
||||
return countTrailingZeros(Bits);
|
||||
}
|
||||
return getPointer()->find_first();
|
||||
}
|
||||
@ -232,11 +229,7 @@ class SmallBitVector {
|
||||
Bits &= ~uintptr_t(0) << (Prev + 1);
|
||||
if (Bits == 0 || Prev + 1 >= getSmallSize())
|
||||
return -1;
|
||||
if (NumBaseBits == 32)
|
||||
return countTrailingZeros(Bits);
|
||||
if (NumBaseBits == 64)
|
||||
return countTrailingZeros(Bits);
|
||||
llvm_unreachable("Unsupported!");
|
||||
return countTrailingZeros(Bits);
|
||||
}
|
||||
return getPointer()->find_next(Prev);
|
||||
}
|
||||
@ -560,7 +553,6 @@ class SmallBitVector {
|
||||
private:
|
||||
template<bool AddBits, bool InvertMask>
|
||||
void applyMask(const uint32_t *Mask, unsigned MaskWords) {
|
||||
assert((NumBaseBits == 64 || NumBaseBits == 32) && "Unsupported word size");
|
||||
if (NumBaseBits == 64 && MaskWords >= 2) {
|
||||
uint64_t M = Mask[0] | (uint64_t(Mask[1]) << 32);
|
||||
if (InvertMask) M = ~M;
|
||||
|
@ -132,7 +132,7 @@ class SmallPtrSetImplBase {
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
void Grow(unsigned NewSize);
|
||||
|
||||
void operator=(const SmallPtrSetImplBase &RHS) LLVM_DELETED_FUNCTION;
|
||||
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.
|
||||
@ -242,7 +242,7 @@ template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
||||
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl&) LLVM_DELETED_FUNCTION;
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl&) = delete;
|
||||
protected:
|
||||
// Constructors that forward to the base.
|
||||
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
@ -236,51 +237,6 @@ class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
|
||||
this->setEnd(this->end()-1);
|
||||
this->end()->~T();
|
||||
}
|
||||
|
||||
#if LLVM_HAS_VARIADIC_TEMPLATES
|
||||
template <typename... ArgTypes> void emplace_back(ArgTypes &&... Args) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
|
||||
this->setEnd(this->end() + 1);
|
||||
}
|
||||
#else
|
||||
private:
|
||||
template <typename Constructor> void emplace_back_impl(Constructor construct) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
construct((void *)this->end());
|
||||
this->setEnd(this->end() + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
void emplace_back() {
|
||||
emplace_back_impl([](void *Mem) { ::new (Mem) T(); });
|
||||
}
|
||||
template <typename T1> void emplace_back(T1 &&A1) {
|
||||
emplace_back_impl([&](void *Mem) { ::new (Mem) T(std::forward<T1>(A1)); });
|
||||
}
|
||||
template <typename T1, typename T2> void emplace_back(T1 &&A1, T2 &&A2) {
|
||||
emplace_back_impl([&](void *Mem) {
|
||||
::new (Mem) T(std::forward<T1>(A1), std::forward<T2>(A2));
|
||||
});
|
||||
}
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void emplace_back(T1 &&A1, T2 &&A2, T3 &&A3) {
|
||||
T(std::forward<T1>(A1), std::forward<T2>(A2), std::forward<T3>(A3));
|
||||
emplace_back_impl([&](void *Mem) {
|
||||
::new (Mem)
|
||||
T(std::forward<T1>(A1), std::forward<T2>(A2), std::forward<T3>(A3));
|
||||
});
|
||||
}
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void emplace_back(T1 &&A1, T2 &&A2, T3 &&A3, T4 &&A4) {
|
||||
emplace_back_impl([&](void *Mem) {
|
||||
::new (Mem) T(std::forward<T1>(A1), std::forward<T2>(A2),
|
||||
std::forward<T3>(A3), std::forward<T4>(A4));
|
||||
});
|
||||
}
|
||||
#endif // LLVM_HAS_VARIADIC_TEMPLATES
|
||||
};
|
||||
|
||||
// Define this out-of-line to dissuade the C++ compiler from inlining it.
|
||||
@ -352,8 +308,11 @@ class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename T1, typename T2>
|
||||
static void uninitialized_copy(T1 *I, T1 *E, T2 *Dest) {
|
||||
template <typename T1, typename T2>
|
||||
static void uninitialized_copy(
|
||||
T1 *I, T1 *E, T2 *Dest,
|
||||
typename std::enable_if<std::is_same<typename std::remove_const<T1>::type,
|
||||
T2>::value>::type * = nullptr) {
|
||||
// Use memcpy for PODs iterated by pointers (which includes SmallVector
|
||||
// iterators): std::uninitialized_copy optimizes to memmove, but we can
|
||||
// use memcpy here.
|
||||
@ -385,7 +344,7 @@ template <typename T>
|
||||
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
|
||||
|
||||
SmallVectorImpl(const SmallVectorImpl&) LLVM_DELETED_FUNCTION;
|
||||
SmallVectorImpl(const SmallVectorImpl&) = delete;
|
||||
public:
|
||||
typedef typename SuperClass::iterator iterator;
|
||||
typedef typename SuperClass::size_type size_type;
|
||||
@ -459,9 +418,7 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
this->grow(this->size()+NumInputs);
|
||||
|
||||
// Copy the new elements over.
|
||||
// TODO: NEED To compile time dispatch on whether in_iter is a random access
|
||||
// iterator to use the fast uninitialized_copy.
|
||||
std::uninitialized_copy(in_start, in_end, this->end());
|
||||
this->uninitialized_copy(in_start, in_end, this->end());
|
||||
this->setEnd(this->end() + NumInputs);
|
||||
}
|
||||
|
||||
@ -476,6 +433,10 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
this->setEnd(this->end() + NumInputs);
|
||||
}
|
||||
|
||||
void append(std::initializer_list<T> IL) {
|
||||
append(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
void assign(size_type NumElts, const T &Elt) {
|
||||
clear();
|
||||
if (this->capacity() < NumElts)
|
||||
@ -484,6 +445,11 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
std::uninitialized_fill(this->begin(), this->end(), Elt);
|
||||
}
|
||||
|
||||
void assign(std::initializer_list<T> IL) {
|
||||
clear();
|
||||
append(IL);
|
||||
}
|
||||
|
||||
iterator erase(iterator I) {
|
||||
assert(I >= this->begin() && "Iterator to erase is out of bounds.");
|
||||
assert(I < this->end() && "Erasing at past-the-end iterator.");
|
||||
@ -677,6 +643,17 @@ class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||
return I;
|
||||
}
|
||||
|
||||
void insert(iterator I, std::initializer_list<T> IL) {
|
||||
insert(I, IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
template <typename... ArgTypes> void emplace_back(ArgTypes &&... Args) {
|
||||
if (LLVM_UNLIKELY(this->EndX >= this->CapacityX))
|
||||
this->grow();
|
||||
::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
|
||||
this->setEnd(this->end() + 1);
|
||||
}
|
||||
|
||||
SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
|
||||
|
||||
SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
|
||||
@ -902,6 +879,10 @@ class SmallVector : public SmallVectorImpl<T> {
|
||||
this->append(R.begin(), R.end());
|
||||
}
|
||||
|
||||
SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
|
||||
this->assign(IL);
|
||||
}
|
||||
|
||||
SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(RHS);
|
||||
@ -921,6 +902,21 @@ class SmallVector : public SmallVectorImpl<T> {
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
|
||||
if (!RHS.empty())
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
}
|
||||
|
||||
const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
|
||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
const SmallVector &operator=(std::initializer_list<T> IL) {
|
||||
this->assign(IL);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, unsigned N>
|
||||
|
@ -124,25 +124,15 @@ struct SparseBitVectorElement
|
||||
size_type count() const {
|
||||
unsigned NumBits = 0;
|
||||
for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i)
|
||||
if (sizeof(BitWord) == 4)
|
||||
NumBits += CountPopulation_32(Bits[i]);
|
||||
else if (sizeof(BitWord) == 8)
|
||||
NumBits += CountPopulation_64(Bits[i]);
|
||||
else
|
||||
llvm_unreachable("Unsupported!");
|
||||
NumBits += countPopulation(Bits[i]);
|
||||
return NumBits;
|
||||
}
|
||||
|
||||
/// find_first - Returns the index of the first set bit.
|
||||
int find_first() const {
|
||||
for (unsigned i = 0; i < BITWORDS_PER_ELEMENT; ++i)
|
||||
if (Bits[i] != 0) {
|
||||
if (sizeof(BitWord) == 4)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
if (sizeof(BitWord) == 8)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
llvm_unreachable("Unsupported!");
|
||||
}
|
||||
if (Bits[i] != 0)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
llvm_unreachable("Illegal empty element");
|
||||
}
|
||||
|
||||
@ -161,23 +151,13 @@ struct SparseBitVectorElement
|
||||
// Mask off previous bits.
|
||||
Copy &= ~0UL << BitPos;
|
||||
|
||||
if (Copy != 0) {
|
||||
if (sizeof(BitWord) == 4)
|
||||
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
||||
if (sizeof(BitWord) == 8)
|
||||
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
||||
llvm_unreachable("Unsupported!");
|
||||
}
|
||||
if (Copy != 0)
|
||||
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
||||
|
||||
// Check subsequent words.
|
||||
for (unsigned i = WordPos+1; i < BITWORDS_PER_ELEMENT; ++i)
|
||||
if (Bits[i] != 0) {
|
||||
if (sizeof(BitWord) == 4)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
if (sizeof(BitWord) == 8)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
llvm_unreachable("Unsupported!");
|
||||
}
|
||||
if (Bits[i] != 0)
|
||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -133,8 +133,8 @@ class SparseMultiSet {
|
||||
|
||||
// Disable copy construction and assignment.
|
||||
// This data structure is not meant to be used that way.
|
||||
SparseMultiSet(const SparseMultiSet&) LLVM_DELETED_FUNCTION;
|
||||
SparseMultiSet &operator=(const SparseMultiSet&) LLVM_DELETED_FUNCTION;
|
||||
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
|
||||
|
@ -133,8 +133,8 @@ class SparseSet {
|
||||
|
||||
// Disable copy construction and assignment.
|
||||
// This data structure is not meant to be used that way.
|
||||
SparseSet(const SparseSet&) LLVM_DELETED_FUNCTION;
|
||||
SparseSet &operator=(const SparseSet&) LLVM_DELETED_FUNCTION;
|
||||
SparseSet(const SparseSet&) = delete;
|
||||
SparseSet &operator=(const SparseSet&) = delete;
|
||||
|
||||
public:
|
||||
typedef ValueT value_type;
|
||||
|
@ -111,7 +111,7 @@ class StringMapImpl {
|
||||
/// and data.
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry : public StringMapEntryBase {
|
||||
StringMapEntry(StringMapEntry &E) LLVM_DELETED_FUNCTION;
|
||||
StringMapEntry(StringMapEntry &E) = delete;
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
|
@ -238,9 +238,12 @@ namespace llvm {
|
||||
/// \returns The index of the first occurrence of \p C, or npos if not
|
||||
/// found.
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
for (size_t i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (Data[i] == C)
|
||||
return i;
|
||||
size_t FindBegin = std::min(From, Length);
|
||||
if (FindBegin < Length) { // Avoid calling memchr with nullptr.
|
||||
// Just forward to memchr, which is faster than a hand-rolled loop.
|
||||
if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin))
|
||||
return static_cast<const char *>(P) - Data;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,12 @@ class TinyPtrVector {
|
||||
public:
|
||||
typedef llvm::SmallVector<EltTy, 4> VecTy;
|
||||
typedef typename VecTy::value_type value_type;
|
||||
typedef llvm::PointerUnion<EltTy, VecTy *> PtrUnion;
|
||||
|
||||
llvm::PointerUnion<EltTy, VecTy*> Val;
|
||||
private:
|
||||
PtrUnion Val;
|
||||
|
||||
public:
|
||||
TinyPtrVector() {}
|
||||
~TinyPtrVector() {
|
||||
if (VecTy *V = Val.template dyn_cast<VecTy*>())
|
||||
@ -96,12 +99,13 @@ class TinyPtrVector {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Constructor from a single element.
|
||||
explicit TinyPtrVector(EltTy Elt) : Val(Elt) {}
|
||||
|
||||
/// Constructor from an ArrayRef.
|
||||
///
|
||||
/// This also is a constructor for individual array elements due to the single
|
||||
/// element constructor for ArrayRef.
|
||||
explicit TinyPtrVector(ArrayRef<EltTy> Elts)
|
||||
: Val(new VecTy(Elts.begin(), Elts.end())) {}
|
||||
: Val(Elts.size() == 1 ? PtrUnion(Elts[0])
|
||||
: PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {}
|
||||
|
||||
// implicit conversion operator to ArrayRef.
|
||||
operator ArrayRef<EltTy>() const {
|
||||
@ -112,6 +116,15 @@ class TinyPtrVector {
|
||||
return *Val.template get<VecTy*>();
|
||||
}
|
||||
|
||||
// implicit conversion operator to MutableArrayRef.
|
||||
operator MutableArrayRef<EltTy>() {
|
||||
if (Val.isNull())
|
||||
return None;
|
||||
if (Val.template is<EltTy>())
|
||||
return *Val.getAddrOfPtr1();
|
||||
return *Val.template get<VecTy*>();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
// This vector can be empty if it contains no element, or if it
|
||||
// contains a pointer to an empty vector.
|
||||
|
@ -50,6 +50,7 @@ class Triple {
|
||||
armeb, // ARM (big endian): armeb
|
||||
aarch64, // AArch64 (little endian): aarch64
|
||||
aarch64_be, // AArch64 (big endian): aarch64_be
|
||||
bpf, // eBPF or extended BPF or 64-bit BPF (little endian)
|
||||
hexagon, // Hexagon: hexagon
|
||||
mips, // MIPS: mips, mipsallegrex
|
||||
mipsel, // MIPSEL: mipsel, mipsallegrexel
|
||||
@ -63,6 +64,7 @@ class Triple {
|
||||
amdgcn, // AMDGCN: AMD GCN GPUs
|
||||
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
|
||||
thumb, // Thumb (little endian): thumb, thumbv.*
|
||||
@ -80,11 +82,13 @@ class Triple {
|
||||
hsail64, // AMD HSAIL with 64-bit pointers
|
||||
spir, // SPIR: standard portable IR for OpenCL 32-bit version
|
||||
spir64, // SPIR: standard portable IR for OpenCL 64-bit version
|
||||
kalimba // Kalimba: generic kalimba
|
||||
kalimba, // Kalimba: generic kalimba
|
||||
LastArchType = kalimba
|
||||
};
|
||||
enum SubArchType {
|
||||
NoSubArch,
|
||||
|
||||
ARMSubArch_v8_1a,
|
||||
ARMSubArch_v8,
|
||||
ARMSubArch_v7,
|
||||
ARMSubArch_v7em,
|
||||
@ -92,6 +96,7 @@ class Triple {
|
||||
ARMSubArch_v7s,
|
||||
ARMSubArch_v6,
|
||||
ARMSubArch_v6m,
|
||||
ARMSubArch_v6k,
|
||||
ARMSubArch_v6t2,
|
||||
ARMSubArch_v5,
|
||||
ARMSubArch_v5te,
|
||||
@ -114,11 +119,13 @@ class Triple {
|
||||
ImaginationTechnologies,
|
||||
MipsTechnologies,
|
||||
NVIDIA,
|
||||
CSR
|
||||
CSR,
|
||||
LastVendorType = CSR
|
||||
};
|
||||
enum OSType {
|
||||
UnknownOS,
|
||||
|
||||
CloudABI,
|
||||
Darwin,
|
||||
DragonFly,
|
||||
FreeBSD,
|
||||
@ -140,7 +147,9 @@ class Triple {
|
||||
AIX,
|
||||
CUDA, // NVIDIA CUDA
|
||||
NVCL, // NVIDIA OpenCL
|
||||
AMDHSA // AMD HSA Runtime
|
||||
AMDHSA, // AMD HSA Runtime
|
||||
PS4,
|
||||
LastOSType = PS4
|
||||
};
|
||||
enum EnvironmentType {
|
||||
UnknownEnvironment,
|
||||
@ -157,6 +166,7 @@ class Triple {
|
||||
MSVC,
|
||||
Itanium,
|
||||
Cygnus,
|
||||
LastEnvironmentType = Cygnus
|
||||
};
|
||||
enum ObjectFormatType {
|
||||
UnknownObjectFormat,
|
||||
@ -200,6 +210,13 @@ class Triple {
|
||||
Triple(const Twine &ArchStr, const Twine &VendorStr, const Twine &OSStr,
|
||||
const Twine &EnvironmentStr);
|
||||
|
||||
bool operator==(const Triple &Other) const {
|
||||
return Arch == Other.Arch && SubArch == Other.SubArch &&
|
||||
Vendor == Other.Vendor && OS == Other.OS &&
|
||||
Environment == Other.Environment &&
|
||||
ObjectFormat == Other.ObjectFormat;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Normalization
|
||||
/// @{
|
||||
@ -210,6 +227,9 @@ class Triple {
|
||||
/// common case in which otherwise valid components are in the wrong order.
|
||||
static std::string normalize(StringRef Str);
|
||||
|
||||
/// \brief Return the normalized form of this triple's string.
|
||||
std::string normalize() const { return normalize(Data); }
|
||||
|
||||
/// @}
|
||||
/// @name Typed Component Access
|
||||
/// @{
|
||||
@ -334,6 +354,12 @@ class Triple {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isOSVersionLT(const Triple &Other) const {
|
||||
unsigned RHS[3];
|
||||
Other.getOSVersion(RHS[0], RHS[1], RHS[2]);
|
||||
return isOSVersionLT(RHS[0], RHS[1], RHS[2]);
|
||||
}
|
||||
|
||||
/// isMacOSXVersionLT - Comparison function for checking OS X version
|
||||
/// compatibility, which handles supporting skewed version numbering schemes
|
||||
/// used by the "darwin" triples.
|
||||
@ -423,7 +449,7 @@ class Triple {
|
||||
|
||||
/// \brief Tests whether the OS is Windows.
|
||||
bool isOSWindows() const {
|
||||
return getOS() == Triple::Win32 || isOSCygMing();
|
||||
return getOS() == Triple::Win32;
|
||||
}
|
||||
|
||||
/// \brief Tests whether the OS is NaCl (Native Client)
|
||||
@ -451,6 +477,19 @@ class Triple {
|
||||
return getObjectFormat() == Triple::MachO;
|
||||
}
|
||||
|
||||
/// \brief Tests whether the target is the PS4 CPU
|
||||
bool isPS4CPU() const {
|
||||
return getArch() == Triple::x86_64 &&
|
||||
getVendor() == Triple::SCEI &&
|
||||
getOS() == Triple::PS4;
|
||||
}
|
||||
|
||||
/// \brief Tests whether the target is the PS4 platform
|
||||
bool isPS4() const {
|
||||
return getVendor() == Triple::SCEI &&
|
||||
getOS() == Triple::PS4;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Mutators
|
||||
/// @{
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_ADT_TWINE_H
|
||||
#define LLVM_ADT_TWINE_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -17,9 +18,6 @@
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
template <typename T>
|
||||
class SmallVectorImpl;
|
||||
class StringRef;
|
||||
class raw_ostream;
|
||||
|
||||
/// Twine - A lightweight data structure for efficiently representing the
|
||||
@ -100,6 +98,9 @@ namespace llvm {
|
||||
/// A pointer to a StringRef instance.
|
||||
StringRefKind,
|
||||
|
||||
/// A pointer to a SmallString instance.
|
||||
SmallStringKind,
|
||||
|
||||
/// A char value reinterpreted as a pointer, to render as a character.
|
||||
CharKind,
|
||||
|
||||
@ -136,6 +137,7 @@ namespace llvm {
|
||||
const char *cString;
|
||||
const std::string *stdString;
|
||||
const StringRef *stringRef;
|
||||
const SmallVectorImpl<char> *smallString;
|
||||
char character;
|
||||
unsigned int decUI;
|
||||
int decI;
|
||||
@ -166,50 +168,49 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// Construct a binary twine.
|
||||
explicit Twine(const Twine &_LHS, const Twine &_RHS)
|
||||
: LHSKind(TwineKind), RHSKind(TwineKind) {
|
||||
LHS.twine = &_LHS;
|
||||
RHS.twine = &_RHS;
|
||||
explicit Twine(const Twine &LHS, const Twine &RHS)
|
||||
: LHSKind(TwineKind), RHSKind(TwineKind) {
|
||||
this->LHS.twine = &LHS;
|
||||
this->RHS.twine = &RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct a twine from explicit values.
|
||||
explicit Twine(Child _LHS, NodeKind _LHSKind,
|
||||
Child _RHS, NodeKind _RHSKind)
|
||||
: LHS(_LHS), RHS(_RHS), LHSKind(_LHSKind), RHSKind(_RHSKind) {
|
||||
explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind)
|
||||
: LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) {
|
||||
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) LLVM_DELETED_FUNCTION;
|
||||
Twine &operator=(const Twine &Other) = delete;
|
||||
|
||||
/// isNull - Check for the null twine.
|
||||
/// Check for the null twine.
|
||||
bool isNull() const {
|
||||
return getLHSKind() == NullKind;
|
||||
}
|
||||
|
||||
/// isEmpty - Check for the empty twine.
|
||||
/// Check for the empty twine.
|
||||
bool isEmpty() const {
|
||||
return getLHSKind() == EmptyKind;
|
||||
}
|
||||
|
||||
/// isNullary - Check if this is a nullary twine (null or empty).
|
||||
/// Check if this is a nullary twine (null or empty).
|
||||
bool isNullary() const {
|
||||
return isNull() || isEmpty();
|
||||
}
|
||||
|
||||
/// isUnary - Check if this is a unary twine.
|
||||
/// Check if this is a unary twine.
|
||||
bool isUnary() const {
|
||||
return getRHSKind() == EmptyKind && !isNullary();
|
||||
}
|
||||
|
||||
/// isBinary - Check if this is a binary twine.
|
||||
/// Check if this is a binary twine.
|
||||
bool isBinary() const {
|
||||
return getLHSKind() != NullKind && getRHSKind() != EmptyKind;
|
||||
}
|
||||
|
||||
/// isValid - Check if this is a valid twine (satisfying the invariants on
|
||||
/// Check if this is a valid twine (satisfying the invariants on
|
||||
/// order and number of arguments).
|
||||
bool isValid() const {
|
||||
// Nullary twines always have Empty on the RHS.
|
||||
@ -235,16 +236,16 @@ namespace llvm {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// getLHSKind - Get the NodeKind of the left-hand side.
|
||||
/// Get the NodeKind of the left-hand side.
|
||||
NodeKind getLHSKind() const { return LHSKind; }
|
||||
|
||||
/// getRHSKind - Get the NodeKind of the right-hand side.
|
||||
/// Get the NodeKind of the right-hand side.
|
||||
NodeKind getRHSKind() const { return RHSKind; }
|
||||
|
||||
/// printOneChild - Print one child from a twine.
|
||||
/// Print one child from a twine.
|
||||
void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const;
|
||||
|
||||
/// printOneChildRepr - Print the representation of one child from a twine.
|
||||
/// Print the representation of one child from a twine.
|
||||
void printOneChildRepr(raw_ostream &OS, Child Ptr,
|
||||
NodeKind Kind) const;
|
||||
|
||||
@ -257,6 +258,8 @@ namespace llvm {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
Twine(const Twine &) = default;
|
||||
|
||||
/// Construct from a C string.
|
||||
///
|
||||
/// We take care here to optimize "" into the empty twine -- this will be
|
||||
@ -287,6 +290,13 @@ namespace llvm {
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a SmallString.
|
||||
/*implicit*/ Twine(const SmallVectorImpl<char> &Str)
|
||||
: LHSKind(SmallStringKind), RHSKind(EmptyKind) {
|
||||
LHS.smallString = &Str;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct from a char.
|
||||
explicit Twine(char Val)
|
||||
: LHSKind(CharKind), RHSKind(EmptyKind) {
|
||||
@ -347,18 +357,18 @@ namespace llvm {
|
||||
// right thing. Yet.
|
||||
|
||||
/// Construct as the concatenation of a C string and a StringRef.
|
||||
/*implicit*/ Twine(const char *_LHS, const StringRef &_RHS)
|
||||
: LHSKind(CStringKind), RHSKind(StringRefKind) {
|
||||
LHS.cString = _LHS;
|
||||
RHS.stringRef = &_RHS;
|
||||
/*implicit*/ Twine(const char *LHS, const StringRef &RHS)
|
||||
: LHSKind(CStringKind), RHSKind(StringRefKind) {
|
||||
this->LHS.cString = LHS;
|
||||
this->RHS.stringRef = &RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
/// Construct as the concatenation of a StringRef and a C string.
|
||||
/*implicit*/ Twine(const StringRef &_LHS, const char *_RHS)
|
||||
: LHSKind(StringRefKind), RHSKind(CStringKind) {
|
||||
LHS.stringRef = &_LHS;
|
||||
RHS.cString = _RHS;
|
||||
/*implicit*/ Twine(const StringRef &LHS, const char *RHS)
|
||||
: LHSKind(StringRefKind), RHSKind(CStringKind) {
|
||||
this->LHS.stringRef = &LHS;
|
||||
this->RHS.cString = RHS;
|
||||
assert(isValid() && "Invalid twine!");
|
||||
}
|
||||
|
||||
@ -384,14 +394,14 @@ namespace llvm {
|
||||
/// @name Predicate Operations
|
||||
/// @{
|
||||
|
||||
/// isTriviallyEmpty - Check if this twine is trivially empty; a false
|
||||
/// return value does not necessarily mean the twine is empty.
|
||||
/// Check if this twine is trivially empty; a false return value does not
|
||||
/// necessarily mean the twine is empty.
|
||||
bool isTriviallyEmpty() const {
|
||||
return isNullary();
|
||||
}
|
||||
|
||||
/// isSingleStringRef - Return true if this twine can be dynamically
|
||||
/// accessed as a single StringRef value with getSingleStringRef().
|
||||
/// Return true if this twine can be dynamically accessed as a single
|
||||
/// StringRef value with getSingleStringRef().
|
||||
bool isSingleStringRef() const {
|
||||
if (getRHSKind() != EmptyKind) return false;
|
||||
|
||||
@ -400,6 +410,7 @@ namespace llvm {
|
||||
case CStringKind:
|
||||
case StdStringKind:
|
||||
case StringRefKind:
|
||||
case SmallStringKind:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -416,15 +427,14 @@ namespace llvm {
|
||||
/// @name Output & Conversion.
|
||||
/// @{
|
||||
|
||||
/// str - Return the twine contents as a std::string.
|
||||
/// Return the twine contents as a std::string.
|
||||
std::string str() const;
|
||||
|
||||
/// toVector - Write the concatenated string into the given SmallString or
|
||||
/// SmallVector.
|
||||
/// Append the concatenated string into the given SmallString or SmallVector.
|
||||
void toVector(SmallVectorImpl<char> &Out) const;
|
||||
|
||||
/// getSingleStringRef - This returns the twine as a single StringRef. This
|
||||
/// method is only valid if isSingleStringRef() is true.
|
||||
/// This returns the twine as a single StringRef. This method is only valid
|
||||
/// if isSingleStringRef() is true.
|
||||
StringRef getSingleStringRef() const {
|
||||
assert(isSingleStringRef() &&"This cannot be had as a single stringref!");
|
||||
switch (getLHSKind()) {
|
||||
@ -433,18 +443,24 @@ namespace llvm {
|
||||
case CStringKind: return StringRef(LHS.cString);
|
||||
case StdStringKind: return StringRef(*LHS.stdString);
|
||||
case StringRefKind: return *LHS.stringRef;
|
||||
case SmallStringKind:
|
||||
return StringRef(LHS.smallString->data(), LHS.smallString->size());
|
||||
}
|
||||
}
|
||||
|
||||
/// toStringRef - This returns the twine as a single StringRef if it can be
|
||||
/// This returns the twine as a single StringRef if it can be
|
||||
/// represented as such. Otherwise the twine is written into the given
|
||||
/// SmallVector and a StringRef to the SmallVector's data is returned.
|
||||
StringRef toStringRef(SmallVectorImpl<char> &Out) const;
|
||||
StringRef toStringRef(SmallVectorImpl<char> &Out) const {
|
||||
if (isSingleStringRef())
|
||||
return getSingleStringRef();
|
||||
toVector(Out);
|
||||
return StringRef(Out.data(), Out.size());
|
||||
}
|
||||
|
||||
/// toNullTerminatedStringRef - This returns the twine as a single null
|
||||
/// terminated StringRef if it can be represented as such. Otherwise the
|
||||
/// twine is written into the given SmallVector and a StringRef to the
|
||||
/// SmallVector's data is returned.
|
||||
/// This returns the twine as a single null terminated StringRef if it
|
||||
/// can be represented as such. Otherwise the twine is written into the
|
||||
/// given SmallVector and a StringRef to the SmallVector's data is returned.
|
||||
///
|
||||
/// The returned StringRef's size does not include the null terminator.
|
||||
StringRef toNullTerminatedStringRef(SmallVectorImpl<char> &Out) const;
|
||||
|
@ -50,7 +50,7 @@ unsigned ComputeEditDistance(ArrayRef<T> FromArray, ArrayRef<T> ToArray,
|
||||
// http://en.wikipedia.org/wiki/Levenshtein_distance
|
||||
//
|
||||
// Although the algorithm is typically described using an m x n
|
||||
// array, only two rows are used at a time, so this implemenation
|
||||
// array, only two rows are used at a time, so this implementation
|
||||
// just keeps two separate vectors for those two rows.
|
||||
typename ArrayRef<T>::size_type m = FromArray.size();
|
||||
typename ArrayRef<T>::size_type n = ToArray.size();
|
||||
|
@ -237,14 +237,14 @@ class ilist_iterator
|
||||
// These are to catch errors when people try to use them as random access
|
||||
// iterators.
|
||||
template<typename T>
|
||||
void operator-(int, ilist_iterator<T>) LLVM_DELETED_FUNCTION;
|
||||
void operator-(int, ilist_iterator<T>) = delete;
|
||||
template<typename T>
|
||||
void operator-(ilist_iterator<T>,int) LLVM_DELETED_FUNCTION;
|
||||
void operator-(ilist_iterator<T>,int) = delete;
|
||||
|
||||
template<typename T>
|
||||
void operator+(int, ilist_iterator<T>) LLVM_DELETED_FUNCTION;
|
||||
void operator+(int, ilist_iterator<T>) = delete;
|
||||
template<typename T>
|
||||
void operator+(ilist_iterator<T>,int) LLVM_DELETED_FUNCTION;
|
||||
void operator+(ilist_iterator<T>,int) = delete;
|
||||
|
||||
// operator!=/operator== - Allow mixed comparisons without dereferencing
|
||||
// the iterator, which could very likely be pointing to end().
|
||||
@ -332,8 +332,8 @@ class iplist : public Traits {
|
||||
|
||||
// No fundamental reason why iplist can't be copyable, but the default
|
||||
// copy/copy-assign won't do.
|
||||
iplist(const iplist &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const iplist &) LLVM_DELETED_FUNCTION;
|
||||
iplist(const iplist &) = delete;
|
||||
void operator=(const iplist &) = delete;
|
||||
|
||||
public:
|
||||
typedef NodeTy *pointer;
|
||||
|
@ -150,7 +150,7 @@ class iterator_adaptor_base
|
||||
protected:
|
||||
WrappedIteratorT I;
|
||||
|
||||
iterator_adaptor_base() {}
|
||||
iterator_adaptor_base() = default;
|
||||
|
||||
template <typename U>
|
||||
explicit iterator_adaptor_base(
|
||||
@ -231,7 +231,7 @@ struct pointee_iterator
|
||||
pointee_iterator<WrappedIteratorT>, WrappedIteratorT,
|
||||
typename std::iterator_traits<WrappedIteratorT>::iterator_category,
|
||||
T> {
|
||||
pointee_iterator() {}
|
||||
pointee_iterator() = default;
|
||||
template <typename U>
|
||||
pointee_iterator(U &&u)
|
||||
: pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
|
||||
|
@ -68,7 +68,7 @@ class AliasAnalysis {
|
||||
/// typically called by the run* methods of these subclasses. This may be
|
||||
/// called multiple times.
|
||||
///
|
||||
void InitializeAliasAnalysis(Pass *P);
|
||||
void InitializeAliasAnalysis(Pass *P, const DataLayout *DL);
|
||||
|
||||
/// getAnalysisUsage - All alias analysis implementations should invoke this
|
||||
/// directly (using AliasAnalysis::getAnalysisUsage(AU)).
|
||||
@ -84,11 +84,6 @@ class AliasAnalysis {
|
||||
/// know the sizes of the potential memory references.
|
||||
static uint64_t const UnknownSize = ~UINT64_C(0);
|
||||
|
||||
/// getDataLayout - Return a pointer to the current DataLayout object, or
|
||||
/// null if no DataLayout object is available.
|
||||
///
|
||||
const DataLayout *getDataLayout() const { return DL; }
|
||||
|
||||
/// getTargetLibraryInfo - Return a pointer to the current TargetLibraryInfo
|
||||
/// object, or null if no TargetLibraryInfo object is available.
|
||||
///
|
||||
@ -139,6 +134,10 @@ class AliasAnalysis {
|
||||
Copy.AATags = AAMDNodes();
|
||||
return Copy;
|
||||
}
|
||||
|
||||
bool operator==(const AliasAnalysis::Location &Other) const {
|
||||
return Ptr == Other.Ptr && Size == Other.Size && AATags == Other.AATags;
|
||||
}
|
||||
};
|
||||
|
||||
/// getLocation - Fill in Loc with information about the memory reference by
|
||||
@ -150,6 +149,19 @@ class AliasAnalysis {
|
||||
Location getLocation(const AtomicRMWInst *RMWI);
|
||||
static Location getLocationForSource(const MemTransferInst *MTI);
|
||||
static Location getLocationForDest(const MemIntrinsic *MI);
|
||||
Location getLocation(const Instruction *Inst) {
|
||||
if (auto *I = dyn_cast<LoadInst>(Inst))
|
||||
return getLocation(I);
|
||||
else if (auto *I = dyn_cast<StoreInst>(Inst))
|
||||
return getLocation(I);
|
||||
else if (auto *I = dyn_cast<VAArgInst>(Inst))
|
||||
return getLocation(I);
|
||||
else if (auto *I = dyn_cast<AtomicCmpXchgInst>(Inst))
|
||||
return getLocation(I);
|
||||
else if (auto *I = dyn_cast<AtomicRMWInst>(Inst))
|
||||
return getLocation(I);
|
||||
llvm_unreachable("unsupported memory instruction");
|
||||
}
|
||||
|
||||
/// Alias analysis result - Either we know for sure that it does not alias, we
|
||||
/// know for sure it must alias, or we don't know anything: The two pointers
|
||||
@ -357,6 +369,24 @@ class AliasAnalysis {
|
||||
return (MRB & ModRef) && (MRB & ArgumentPointees);
|
||||
}
|
||||
|
||||
/// getModRefInfo - Return information about whether or not an
|
||||
/// instruction may read or write memory (without regard to a
|
||||
/// specific location)
|
||||
ModRefResult getModRefInfo(const Instruction *I) {
|
||||
if (auto CS = ImmutableCallSite(I)) {
|
||||
auto MRB = getModRefBehavior(CS);
|
||||
if (MRB & ModRef)
|
||||
return ModRef;
|
||||
else if (MRB & Ref)
|
||||
return Ref;
|
||||
else if (MRB & Mod)
|
||||
return Mod;
|
||||
return NoModRef;
|
||||
}
|
||||
|
||||
return getModRefInfo(I, Location());
|
||||
}
|
||||
|
||||
/// getModRefInfo - Return information about whether or not an instruction may
|
||||
/// read or write the specified memory location. An instruction
|
||||
/// that doesn't read or write memory may be trivially LICM'd for example.
|
||||
@ -477,6 +507,10 @@ class AliasAnalysis {
|
||||
ModRefResult getModRefInfo(const VAArgInst* I, const Value* P, uint64_t Size){
|
||||
return getModRefInfo(I, Location(P, Size));
|
||||
}
|
||||
/// getModRefInfo - Return information about whether a call and an instruction
|
||||
/// may refer to the same memory locations.
|
||||
ModRefResult getModRefInfo(Instruction *I,
|
||||
ImmutableCallSite Call);
|
||||
|
||||
/// getModRefInfo - Return information about whether two call sites may refer
|
||||
/// to the same set of memory locations. See
|
||||
@ -585,9 +619,7 @@ struct DenseMapInfo<AliasAnalysis::Location> {
|
||||
}
|
||||
static bool isEqual(const AliasAnalysis::Location &LHS,
|
||||
const AliasAnalysis::Location &RHS) {
|
||||
return LHS.Ptr == RHS.Ptr &&
|
||||
LHS.Size == RHS.Size &&
|
||||
LHS.AATags == RHS.AATags;
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -192,11 +192,6 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
}
|
||||
bool operator!=(const iterator& x) const { return !operator==(x); }
|
||||
|
||||
const iterator &operator=(const iterator &I) {
|
||||
CurNode = I.CurNode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type &operator*() const {
|
||||
assert(CurNode && "Dereferencing AliasSet.end()!");
|
||||
return *CurNode;
|
||||
@ -226,8 +221,8 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
AccessTy(NoModRef), AliasTy(MustAlias), Volatile(false) {
|
||||
}
|
||||
|
||||
AliasSet(const AliasSet &AS) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const AliasSet &AS) LLVM_DELETED_FUNCTION;
|
||||
AliasSet(const AliasSet &AS) = delete;
|
||||
void operator=(const AliasSet &AS) = delete;
|
||||
|
||||
PointerRec *getSomePointer() const {
|
||||
return PtrList;
|
||||
@ -273,7 +268,7 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
///
|
||||
bool aliasesPointer(const Value *Ptr, uint64_t Size, const AAMDNodes &AAInfo,
|
||||
AliasAnalysis &AA) const;
|
||||
bool aliasesUnknownInst(Instruction *Inst, AliasAnalysis &AA) const;
|
||||
bool aliasesUnknownInst(const Instruction *Inst, AliasAnalysis &AA) const;
|
||||
};
|
||||
|
||||
inline raw_ostream& operator<<(raw_ostream &OS, const AliasSet &AS) {
|
||||
@ -363,7 +358,7 @@ class AliasSetTracker {
|
||||
|
||||
/// getAliasSetForPointerIfExists - Return the alias set containing the
|
||||
/// location specified if one exists, otherwise return null.
|
||||
AliasSet *getAliasSetForPointerIfExists(Value *P, uint64_t Size,
|
||||
AliasSet *getAliasSetForPointerIfExists(const Value *P, uint64_t Size,
|
||||
const AAMDNodes &AAInfo) {
|
||||
return findAliasSetForPointer(P, Size, AAInfo);
|
||||
}
|
||||
@ -371,11 +366,12 @@ class AliasSetTracker {
|
||||
/// containsPointer - 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(Value *P, uint64_t Size, const AAMDNodes &AAInfo) const;
|
||||
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(Instruction *I) const;
|
||||
bool containsUnknown(const Instruction *I) const;
|
||||
|
||||
/// getAliasAnalysis - Return the underlying alias analysis object used by
|
||||
/// this tracker.
|
||||
|
@ -27,6 +27,11 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// FIXME: Replace this brittle forward declaration with the include of the new
|
||||
// PassManager.h when doing so doesn't break the PassManagerBuilder.
|
||||
template <typename IRUnitT> class AnalysisManager;
|
||||
class PreservedAnalyses;
|
||||
|
||||
/// \brief A cache of @llvm.assume calls within a function.
|
||||
///
|
||||
/// This cache provides fast lookup of assumptions within a function by caching
|
||||
@ -88,6 +93,42 @@ class AssumptionCache {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A function analysis which provides an \c AssumptionCache.
|
||||
///
|
||||
/// This analysis is intended for use with the new pass manager and will vend
|
||||
/// assumption caches for a given function.
|
||||
class AssumptionAnalysis {
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef AssumptionCache Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Provide a name for the analysis for debugging and logging.
|
||||
static StringRef name() { return "AssumptionAnalysis"; }
|
||||
|
||||
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) { return AssumptionCache(F); }
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c AssumptionAnalysis results.
|
||||
class AssumptionPrinterPass {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
static StringRef name() { return "AssumptionPrinterPass"; }
|
||||
};
|
||||
|
||||
/// \brief An immutable pass that tracks lazily created \c AssumptionCache
|
||||
/// objects.
|
||||
///
|
||||
@ -124,7 +165,7 @@ class AssumptionCacheTracker : public ImmutablePass {
|
||||
AssumptionCache &getAssumptionCache(Function &F);
|
||||
|
||||
AssumptionCacheTracker();
|
||||
~AssumptionCacheTracker();
|
||||
~AssumptionCacheTracker() override;
|
||||
|
||||
void releaseMemory() override { AssumptionCaches.shrink_and_clear(); }
|
||||
|
||||
|
@ -34,7 +34,7 @@ class BlockFrequencyInfo : public FunctionPass {
|
||||
|
||||
BlockFrequencyInfo();
|
||||
|
||||
~BlockFrequencyInfo();
|
||||
~BlockFrequencyInfo() override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
|
@ -718,9 +718,6 @@ void IrreducibleGraph::addEdges(const BlockNode &Node,
|
||||
///
|
||||
/// It has some known flaws.
|
||||
///
|
||||
/// - Loop scale is limited to 4096 per loop (2^12) to avoid exhausting
|
||||
/// BlockFrequency's 64-bit integer precision.
|
||||
///
|
||||
/// - The model of irreducible control flow is a rough approximation.
|
||||
///
|
||||
/// Modelling irreducible control flow exactly involves setting up and
|
||||
|
@ -263,8 +263,7 @@ template <typename CGSCCPassT> class ModuleToPostOrderCGSCCPassAdaptor {
|
||||
template <typename CGSCCPassT>
|
||||
ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>
|
||||
createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) {
|
||||
return std::move(
|
||||
ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass)));
|
||||
return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass));
|
||||
}
|
||||
|
||||
/// \brief A CGSCC analysis which acts as a proxy for a function analysis
|
||||
@ -484,7 +483,7 @@ template <typename FunctionPassT> class CGSCCToFunctionPassAdaptor {
|
||||
template <typename FunctionPassT>
|
||||
CGSCCToFunctionPassAdaptor<FunctionPassT>
|
||||
createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) {
|
||||
return std::move(CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass)));
|
||||
return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,8 +273,8 @@ class CallGraphNode {
|
||||
/// CalledFunctions array of this or other CallGraphNodes.
|
||||
unsigned NumReferences;
|
||||
|
||||
CallGraphNode(const CallGraphNode &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const CallGraphNode &) LLVM_DELETED_FUNCTION;
|
||||
CallGraphNode(const CallGraphNode &) = delete;
|
||||
void operator=(const CallGraphNode &) = delete;
|
||||
|
||||
void DropRef() { --NumReferences; }
|
||||
void AddRef() { ++NumReferences; }
|
||||
@ -318,7 +318,7 @@ class CallGraphWrapperPass : public ModulePass {
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
|
||||
CallGraphWrapperPass();
|
||||
virtual ~CallGraphWrapperPass();
|
||||
~CallGraphWrapperPass() override;
|
||||
|
||||
/// \brief The internal \c CallGraph around which the rest of this interface
|
||||
/// is wrapped.
|
||||
|
@ -36,16 +36,15 @@ namespace llvm {
|
||||
/// Note that this fails if not all of the operands are constant. Otherwise,
|
||||
/// this function can only fail when attempting to fold instructions like loads
|
||||
/// and stores, which have no constant expression form.
|
||||
Constant *ConstantFoldInstruction(Instruction *I,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
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 *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI =nullptr);
|
||||
Constant *
|
||||
ConstantFoldConstantExpression(const ConstantExpr *CE, 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,
|
||||
@ -53,19 +52,19 @@ Constant *ConstantFoldConstantExpression(const ConstantExpr *CE,
|
||||
/// fold instructions like loads and stores, which have no constant expression
|
||||
/// form.
|
||||
///
|
||||
Constant *ConstantFoldInstOperands(unsigned Opcode, Type *DestTy,
|
||||
ArrayRef<Constant *> Ops,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
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.
|
||||
///
|
||||
Constant *ConstantFoldCompareInstOperands(unsigned Predicate,
|
||||
Constant *LHS, Constant *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI=nullptr);
|
||||
Constant *
|
||||
ConstantFoldCompareInstOperands(unsigned Predicate, Constant *LHS,
|
||||
Constant *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// ConstantFoldInsertValueInstruction - Attempt to constant fold an insertvalue
|
||||
/// instruction with the specified operands and indices. The constant result is
|
||||
@ -76,8 +75,7 @@ Constant *ConstantFoldInsertValueInstruction(Constant *Agg, Constant *Val,
|
||||
/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would
|
||||
/// produce if it is constant and determinable. If this is not determinable,
|
||||
/// return null.
|
||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C,
|
||||
const DataLayout *TD = nullptr);
|
||||
Constant *ConstantFoldLoadFromConstPtr(Constant *C, const DataLayout &DL);
|
||||
|
||||
/// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a
|
||||
/// getelementptr constantexpr, return the constant value being addressed by the
|
||||
|
@ -1,93 +0,0 @@
|
||||
//==- llvm/Analysis/ConstantsScanner.h - Iterate over constants -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements an iterator to walk through the constants referenced by
|
||||
// a method. This is used by the Bitcode & Assembly writers to build constant
|
||||
// pools.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
||||
#define LLVM_ANALYSIS_CONSTANTSSCANNER_H
|
||||
|
||||
#include "llvm/IR/InstIterator.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Constant;
|
||||
|
||||
class constant_iterator : public std::iterator<std::forward_iterator_tag,
|
||||
const Constant, ptrdiff_t> {
|
||||
const_inst_iterator InstI; // Method instruction iterator
|
||||
unsigned OpIdx; // Operand index
|
||||
|
||||
typedef constant_iterator _Self;
|
||||
|
||||
inline bool isAtConstant() const {
|
||||
assert(!InstI.atEnd() && OpIdx < InstI->getNumOperands() &&
|
||||
"isAtConstant called with invalid arguments!");
|
||||
return isa<Constant>(InstI->getOperand(OpIdx));
|
||||
}
|
||||
|
||||
public:
|
||||
inline constant_iterator(const Function *F) : InstI(inst_begin(F)), OpIdx(0) {
|
||||
// Advance to first constant... if we are not already at constant or end
|
||||
if (InstI != inst_end(F) && // InstI is valid?
|
||||
(InstI->getNumOperands() == 0 || !isAtConstant())) // Not at constant?
|
||||
operator++();
|
||||
}
|
||||
|
||||
inline constant_iterator(const Function *F, bool) // end ctor
|
||||
: InstI(inst_end(F)), OpIdx(0) {
|
||||
}
|
||||
|
||||
inline bool operator==(const _Self& x) const { return OpIdx == x.OpIdx &&
|
||||
InstI == x.InstI; }
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
|
||||
inline pointer operator*() const {
|
||||
assert(isAtConstant() && "Dereferenced an iterator at the end!");
|
||||
return cast<Constant>(InstI->getOperand(OpIdx));
|
||||
}
|
||||
inline pointer operator->() const { return operator*(); }
|
||||
|
||||
inline _Self& operator++() { // Preincrement implementation
|
||||
++OpIdx;
|
||||
do {
|
||||
unsigned NumOperands = InstI->getNumOperands();
|
||||
while (OpIdx < NumOperands && !isAtConstant()) {
|
||||
++OpIdx;
|
||||
}
|
||||
|
||||
if (OpIdx < NumOperands) return *this; // Found a constant!
|
||||
++InstI;
|
||||
OpIdx = 0;
|
||||
} while (!InstI.atEnd());
|
||||
|
||||
return *this; // At the end of the method
|
||||
}
|
||||
|
||||
inline _Self operator++(int) { // Postincrement
|
||||
_Self tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
|
||||
inline bool atEnd() const { return InstI.atEnd(); }
|
||||
};
|
||||
|
||||
inline constant_iterator constant_begin(const Function *F) {
|
||||
return constant_iterator(F);
|
||||
}
|
||||
|
||||
inline constant_iterator constant_end(const Function *F) {
|
||||
return constant_iterator(F, true);
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -217,13 +217,9 @@ namespace llvm {
|
||||
/// input dependences are unordered.
|
||||
class FullDependence : public Dependence {
|
||||
public:
|
||||
FullDependence(Instruction *Src,
|
||||
Instruction *Dst,
|
||||
bool LoopIndependent,
|
||||
FullDependence(Instruction *Src, Instruction *Dst, bool LoopIndependent,
|
||||
unsigned Levels);
|
||||
~FullDependence() {
|
||||
delete[] DV;
|
||||
}
|
||||
~FullDependence() override { delete[] DV; }
|
||||
|
||||
/// isLoopIndependent - Returns true if this is a loop-independent
|
||||
/// dependence.
|
||||
@ -266,6 +262,7 @@ namespace llvm {
|
||||
/// if no subscript in the source or destination mention the induction
|
||||
/// variable associated with the loop at this level.
|
||||
bool isScalar(unsigned Level) const override;
|
||||
|
||||
private:
|
||||
unsigned short Levels;
|
||||
bool LoopIndependent;
|
||||
@ -278,8 +275,8 @@ namespace llvm {
|
||||
/// DependenceAnalysis - This class is the main dependence-analysis driver.
|
||||
///
|
||||
class DependenceAnalysis : public FunctionPass {
|
||||
void operator=(const DependenceAnalysis &) LLVM_DELETED_FUNCTION;
|
||||
DependenceAnalysis(const DependenceAnalysis &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const DependenceAnalysis &) = delete;
|
||||
DependenceAnalysis(const DependenceAnalysis &) = delete;
|
||||
public:
|
||||
/// depends - Tests for a dependence between the Src and Dst instructions.
|
||||
/// Returns NULL if no dependence; otherwise, returns a Dependence (or a
|
||||
|
@ -19,11 +19,12 @@
|
||||
#define LLVM_ANALYSIS_DOMINANCEFRONTIERIMPL_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/DominanceFrontier.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/GenericDomTree.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace {
|
||||
template <class BlockT>
|
||||
class DFCalculateWorkObject {
|
||||
public:
|
||||
@ -37,7 +38,6 @@ class DFCalculateWorkObject {
|
||||
const DomTreeNodeT *Node;
|
||||
const DomTreeNodeT *parentNode;
|
||||
};
|
||||
}
|
||||
|
||||
template <class BlockT>
|
||||
void DominanceFrontierBase<BlockT>::removeBlock(BlockT *BB) {
|
||||
|
@ -1,49 +0,0 @@
|
||||
//===- llvm/Analysis/FunctionTargetTransformInfo.h --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass wraps a TargetTransformInfo in a FunctionPass so that it can
|
||||
// forward along the current Function so that we can make target specific
|
||||
// decisions based on the particular subtarget specified for each Function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_FUNCTIONTARGETTRANSFORMINFO_H
|
||||
#define LLVM_ANALYSIS_FUNCTIONTARGETTRANSFORMINFO_H
|
||||
|
||||
#include "TargetTransformInfo.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
class FunctionTargetTransformInfo final : public FunctionPass {
|
||||
private:
|
||||
const Function *Fn;
|
||||
const TargetTransformInfo *TTI;
|
||||
|
||||
FunctionTargetTransformInfo(const FunctionTargetTransformInfo &)
|
||||
LLVM_DELETED_FUNCTION;
|
||||
void operator=(const FunctionTargetTransformInfo &) LLVM_DELETED_FUNCTION;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
FunctionTargetTransformInfo();
|
||||
|
||||
// Implementation boilerplate.
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
void releaseMemory() override;
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
// Shimmed functions from TargetTransformInfo.
|
||||
void
|
||||
getUnrollingPreferences(Loop *L,
|
||||
TargetTransformInfo::UnrollingPreferences &UP) const {
|
||||
TTI->getUnrollingPreferences(Fn, L, UP);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
@ -122,7 +122,6 @@ class IVUsers : public LoopPass {
|
||||
LoopInfo *LI;
|
||||
DominatorTree *DT;
|
||||
ScalarEvolution *SE;
|
||||
const DataLayout *DL;
|
||||
SmallPtrSet<Instruction*,16> Processed;
|
||||
|
||||
/// IVUses - A list of all tracked IV uses of induction variable expressions
|
||||
|
@ -23,7 +23,7 @@ class AssumptionCacheTracker;
|
||||
class CallSite;
|
||||
class DataLayout;
|
||||
class Function;
|
||||
class TargetTransformInfo;
|
||||
class TargetTransformInfoWrapperPass;
|
||||
|
||||
namespace InlineConstants {
|
||||
// Various magic constants used to adjust heuristics.
|
||||
@ -77,7 +77,7 @@ class InlineCost {
|
||||
}
|
||||
|
||||
/// \brief Test whether the inline cost is low enough for inlining.
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
explicit operator bool() const {
|
||||
return Cost < Threshold;
|
||||
}
|
||||
|
||||
@ -100,14 +100,14 @@ class InlineCost {
|
||||
|
||||
/// \brief Cost analyzer used by inliner.
|
||||
class InlineCostAnalysis : public CallGraphSCCPass {
|
||||
const TargetTransformInfo *TTI;
|
||||
TargetTransformInfoWrapperPass *TTIWP;
|
||||
AssumptionCacheTracker *ACT;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
InlineCostAnalysis();
|
||||
~InlineCostAnalysis();
|
||||
~InlineCostAnalysis() override;
|
||||
|
||||
// Pass interface implementation.
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
@ -49,7 +49,7 @@ namespace llvm {
|
||||
/// SimplifyAddInst - Given operands for an Add, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -58,7 +58,7 @@ namespace llvm {
|
||||
/// SimplifySubInst - Given operands for a Sub, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -67,7 +67,7 @@ namespace llvm {
|
||||
/// Given operands for an FAdd, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -76,7 +76,7 @@ namespace llvm {
|
||||
/// Given operands for an FSub, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -85,7 +85,7 @@ namespace llvm {
|
||||
/// Given operands for an FMul, see if we can fold the result. If not, this
|
||||
/// returns null.
|
||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -93,7 +93,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyMulInst - Given operands for a Mul, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -101,8 +101,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifySDivInst - Given operands for an SDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -110,8 +109,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -119,8 +117,8 @@ namespace llvm {
|
||||
|
||||
/// SimplifyFDivInst - Given operands for an FDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -128,8 +126,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifySRemInst - Given operands for an SRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -137,8 +134,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyURemInst - Given operands for a URem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -146,8 +142,8 @@ namespace llvm {
|
||||
|
||||
/// SimplifyFRemInst - Given operands for an FRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -156,7 +152,7 @@ namespace llvm {
|
||||
/// SimplifyShlInst - Given operands for a Shl, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -165,7 +161,7 @@ namespace llvm {
|
||||
/// SimplifyLShrInst - Given operands for a LShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -174,7 +170,7 @@ namespace llvm {
|
||||
/// SimplifyAShrInst - Given operands for a AShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -182,7 +178,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyAndInst - Given operands for an And, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -190,7 +186,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyOrInst - Given operands for an Or, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -198,7 +194,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyXorInst - Given operands for a Xor, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -207,7 +203,7 @@ namespace llvm {
|
||||
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -216,7 +212,7 @@ namespace llvm {
|
||||
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -225,7 +221,7 @@ namespace llvm {
|
||||
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -233,7 +229,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -242,8 +238,7 @@ namespace llvm {
|
||||
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
|
||||
/// can fold the result. If not, this returns null.
|
||||
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||
ArrayRef<unsigned> Idxs,
|
||||
const DataLayout *TD = nullptr,
|
||||
ArrayRef<unsigned> Idxs, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -251,7 +246,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyTruncInst - Given operands for an TruncInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -263,7 +258,7 @@ namespace llvm {
|
||||
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -272,18 +267,28 @@ namespace llvm {
|
||||
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const DataLayout *TD = nullptr,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
/// SimplifyFPBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the
|
||||
/// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp.
|
||||
Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const FastMathFlags &FMF, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// \brief Given a function and iterators over arguments, see if we can fold
|
||||
/// the result.
|
||||
///
|
||||
/// If this call could not be simplified returns null.
|
||||
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
||||
User::op_iterator ArgEnd, const DataLayout *TD = nullptr,
|
||||
User::op_iterator ArgEnd, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -293,8 +298,7 @@ namespace llvm {
|
||||
/// result.
|
||||
///
|
||||
/// If this call could not be simplified returns null.
|
||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args,
|
||||
const DataLayout *TD = nullptr,
|
||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
@ -302,7 +306,7 @@ namespace llvm {
|
||||
|
||||
/// SimplifyInstruction - See if we can compute a simplified version of this
|
||||
/// instruction. If not, this returns null.
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout *TD = nullptr,
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
@ -316,7 +320,6 @@ namespace llvm {
|
||||
///
|
||||
/// The function returns true if any simplifications were performed.
|
||||
bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
@ -328,7 +331,6 @@ namespace llvm {
|
||||
/// of the users impacted. It returns true if any simplifications were
|
||||
/// performed.
|
||||
bool recursivelySimplifyInstruction(Instruction *I,
|
||||
const DataLayout *TD = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
|
@ -78,7 +78,7 @@ inline void addNodeToInterval(Interval *Int, BasicBlock *BB) {
|
||||
//
|
||||
inline void addNodeToInterval(Interval *Int, Interval *I) {
|
||||
// Add all of the nodes in I as new nodes in Int.
|
||||
copy(I->Nodes.begin(), I->Nodes.end(), back_inserter(Int->Nodes));
|
||||
Int->Nodes.insert(Int->Nodes.end(), I->Nodes.begin(), I->Nodes.end());
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,6 @@ class IntervalIterator {
|
||||
bool IOwnMem; // If True, delete intervals when done with them
|
||||
// See file header for conditions of use
|
||||
public:
|
||||
typedef IntervalIterator<NodeTy, OrigContainer_t> _Self;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
IntervalIterator() {} // End iterator, empty stack
|
||||
@ -105,6 +104,12 @@ class IntervalIterator {
|
||||
}
|
||||
}
|
||||
|
||||
IntervalIterator(IntervalIterator &&x)
|
||||
: IntStack(std::move(x.IntStack)), Visited(std::move(x.Visited)),
|
||||
OrigContainer(x.OrigContainer), IOwnMem(x.IOwnMem) {
|
||||
x.IOwnMem = false;
|
||||
}
|
||||
|
||||
IntervalIterator(IntervalPartition &IP, bool OwnMemory) : IOwnMem(OwnMemory) {
|
||||
OrigContainer = &IP;
|
||||
if (!ProcessInterval(IP.getRootInterval())) {
|
||||
@ -112,7 +117,7 @@ class IntervalIterator {
|
||||
}
|
||||
}
|
||||
|
||||
inline ~IntervalIterator() {
|
||||
~IntervalIterator() {
|
||||
if (IOwnMem)
|
||||
while (!IntStack.empty()) {
|
||||
delete operator*();
|
||||
@ -120,15 +125,17 @@ class IntervalIterator {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator==(const _Self& x) const { return IntStack == x.IntStack;}
|
||||
inline bool operator!=(const _Self& x) const { return !operator==(x); }
|
||||
bool operator==(const IntervalIterator &x) const {
|
||||
return IntStack == x.IntStack;
|
||||
}
|
||||
bool operator!=(const IntervalIterator &x) const { return !(*this == x); }
|
||||
|
||||
inline const Interval *operator*() const { return IntStack.back().first; }
|
||||
inline Interval *operator*() { return IntStack.back().first; }
|
||||
inline const Interval *operator->() const { return operator*(); }
|
||||
inline Interval *operator->() { return operator*(); }
|
||||
const Interval *operator*() const { return IntStack.back().first; }
|
||||
Interval *operator*() { return IntStack.back().first; }
|
||||
const Interval *operator->() const { return operator*(); }
|
||||
Interval *operator->() { return operator*(); }
|
||||
|
||||
_Self& operator++() { // Preincrement
|
||||
IntervalIterator &operator++() { // Preincrement
|
||||
assert(!IntStack.empty() && "Attempting to use interval iterator at end!");
|
||||
do {
|
||||
// All of the intervals on the stack have been visited. Try visiting
|
||||
@ -150,8 +157,10 @@ class IntervalIterator {
|
||||
|
||||
return *this;
|
||||
}
|
||||
inline _Self operator++(int) { // Postincrement
|
||||
_Self tmp = *this; ++*this; return tmp;
|
||||
IntervalIterator operator++(int) { // Postincrement
|
||||
IntervalIterator tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -0,0 +1,96 @@
|
||||
//===- IteratedDominanceFrontier.h - Calculate IDF --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \brief Compute iterated dominance frontiers using a linear time algorithm.
|
||||
///
|
||||
/// The algorithm used here is based on:
|
||||
///
|
||||
/// Sreedhar and Gao. A linear time algorithm for placing phi-nodes.
|
||||
/// In Proceedings of the 22nd ACM SIGPLAN-SIGACT Symposium on Principles of
|
||||
/// Programming Languages
|
||||
/// POPL '95. ACM, New York, NY, 62-73.
|
||||
///
|
||||
/// It has been modified to not explicitly use the DJ graph data structure and
|
||||
/// to directly compute pruned SSA using per-variable liveness information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_IDF_H
|
||||
#define LLVM_ANALYSIS_IDF_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BasicBlock;
|
||||
template <class T> class DomTreeNodeBase;
|
||||
typedef DomTreeNodeBase<BasicBlock> DomTreeNode;
|
||||
class DominatorTree;
|
||||
|
||||
/// \brief Determine the iterated dominance frontier, given a set of defining
|
||||
/// blocks, and optionally, a set of live-in blocks.
|
||||
///
|
||||
/// In turn, the results can be used to place phi nodes.
|
||||
///
|
||||
/// This algorithm is a linear time computation of Iterated Dominance Frontiers,
|
||||
/// pruned using the live-in set.
|
||||
/// By default, liveness is not used to prune the IDF computation.
|
||||
class IDFCalculator {
|
||||
|
||||
public:
|
||||
IDFCalculator(DominatorTree &DT) : DT(DT), useLiveIn(false) {}
|
||||
|
||||
/// \brief Give the IDF calculator the set of blocks in which the value is
|
||||
/// defined. This is equivalent to the set of starting blocks it should be
|
||||
/// calculating the IDF for (though later gets pruned based on liveness).
|
||||
///
|
||||
/// Note: This set *must* live for the entire lifetime of the IDF calculator.
|
||||
void setDefiningBlocks(const SmallPtrSetImpl<BasicBlock *> &Blocks) {
|
||||
DefBlocks = &Blocks;
|
||||
}
|
||||
|
||||
/// \brief Give the IDF calculator the set of blocks in which the value is
|
||||
/// live on entry to the block. This is used to prune the IDF calculation to
|
||||
/// not include blocks where any phi insertion would be dead.
|
||||
///
|
||||
/// Note: This set *must* live for the entire lifetime of the IDF calculator.
|
||||
|
||||
void setLiveInBlocks(const SmallPtrSetImpl<BasicBlock *> &Blocks) {
|
||||
LiveInBlocks = &Blocks;
|
||||
useLiveIn = true;
|
||||
}
|
||||
|
||||
/// \brief Reset the live-in block set to be empty, and tell the IDF
|
||||
/// calculator to not use liveness anymore.
|
||||
void resetLiveInBlocks() {
|
||||
LiveInBlocks = nullptr;
|
||||
useLiveIn = false;
|
||||
}
|
||||
|
||||
/// \brief Calculate iterated dominance frontiers
|
||||
///
|
||||
/// This uses the linear-time phi algorithm based on DJ-graphs mentioned in
|
||||
/// the file-level comment. It performs DF->IDF pruning using the live-in
|
||||
/// set, to avoid computing the IDF for blocks where an inserted PHI node
|
||||
/// would be dead.
|
||||
void calculate(SmallVectorImpl<BasicBlock *> &IDFBlocks);
|
||||
|
||||
private:
|
||||
DominatorTree &DT;
|
||||
bool useLiveIn;
|
||||
DenseMap<DomTreeNode *, unsigned> DomLevels;
|
||||
const SmallPtrSetImpl<BasicBlock *> *LiveInBlocks;
|
||||
const SmallPtrSetImpl<BasicBlock *> *DefBlocks;
|
||||
SmallVector<BasicBlock *, 32> PHIBlocks;
|
||||
};
|
||||
}
|
||||
#endif
|
@ -39,7 +39,7 @@ class JumpInstrTableInfo : public ImmutablePass {
|
||||
/// The default byte alignment for jump tables is 16, which is large but
|
||||
/// usually safe.
|
||||
JumpInstrTableInfo(uint64_t ByteAlign = 16);
|
||||
virtual ~JumpInstrTableInfo();
|
||||
~JumpInstrTableInfo() override;
|
||||
const char *getPassName() const override {
|
||||
return "Jump-Instruction Table Info";
|
||||
}
|
||||
|
@ -29,18 +29,17 @@ namespace llvm {
|
||||
/// This pass computes, caches, and vends lazy value constraint information.
|
||||
class LazyValueInfo : public FunctionPass {
|
||||
AssumptionCache *AC;
|
||||
const DataLayout *DL;
|
||||
class TargetLibraryInfo *TLI;
|
||||
DominatorTree *DT;
|
||||
void *PImpl;
|
||||
LazyValueInfo(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const LazyValueInfo&) LLVM_DELETED_FUNCTION;
|
||||
LazyValueInfo(const LazyValueInfo&) = delete;
|
||||
void operator=(const LazyValueInfo&) = delete;
|
||||
public:
|
||||
static char ID;
|
||||
LazyValueInfo() : FunctionPass(ID), PImpl(nullptr) {
|
||||
initializeLazyValueInfoPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
~LazyValueInfo() { assert(!PImpl && "releaseMemory not called"); }
|
||||
~LazyValueInfo() override { assert(!PImpl && "releaseMemory not called"); }
|
||||
|
||||
/// This is used to return true/false/dunno results.
|
||||
enum Tristate {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_ANALYSIS_LIBCALLALIASANALYSIS_H
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -35,8 +36,8 @@ namespace llvm {
|
||||
: FunctionPass(ID), LCI(LC) {
|
||||
initializeLibCallAliasAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
~LibCallAliasAnalysis();
|
||||
|
||||
~LibCallAliasAnalysis() override;
|
||||
|
||||
ModRefResult getModRefInfo(ImmutableCallSite CS,
|
||||
const Location &Loc) override;
|
||||
|
||||
@ -48,11 +49,8 @@ namespace llvm {
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
InitializeAliasAnalysis(this); // set up super class
|
||||
return false;
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
/// getAdjustedAnalysisPointer - This method is used when a pass implements
|
||||
/// an analysis interface through multiple inheritance. If needed, it
|
||||
/// should override this to adjust the this pointer as needed for the
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
|
||||
namespace llvm {
|
||||
class InvokeInst;
|
||||
|
||||
/// LibCallLocationInfo - This struct describes a set of memory locations that
|
||||
/// are accessed by libcalls. Identification of a location is doing with a
|
||||
@ -162,6 +163,52 @@ namespace llvm {
|
||||
virtual const LibCallFunctionInfo *getFunctionInfoArray() const = 0;
|
||||
};
|
||||
|
||||
enum class EHPersonality {
|
||||
Unknown,
|
||||
GNU_Ada,
|
||||
GNU_C,
|
||||
GNU_CXX,
|
||||
GNU_ObjC,
|
||||
MSVC_X86SEH,
|
||||
MSVC_Win64SEH,
|
||||
MSVC_CXX,
|
||||
};
|
||||
|
||||
/// \brief See if the given exception handling personality function is one
|
||||
/// that we understand. If so, return a description of it; otherwise return
|
||||
/// Unknown.
|
||||
EHPersonality classifyEHPersonality(const Value *Pers);
|
||||
|
||||
/// \brief Returns true if this personality function catches asynchronous
|
||||
/// exceptions.
|
||||
inline bool isAsynchronousEHPersonality(EHPersonality Pers) {
|
||||
// The two SEH personality functions can catch asynch exceptions. We assume
|
||||
// unknown personalities don't catch asynch exceptions.
|
||||
switch (Pers) {
|
||||
case EHPersonality::MSVC_X86SEH:
|
||||
case EHPersonality::MSVC_Win64SEH:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
llvm_unreachable("invalid enum");
|
||||
}
|
||||
|
||||
/// \brief Returns true if this is an MSVC personality function.
|
||||
inline bool isMSVCEHPersonality(EHPersonality Pers) {
|
||||
// The two SEH personality functions can catch asynch exceptions. We assume
|
||||
// unknown personalities don't catch asynch exceptions.
|
||||
switch (Pers) {
|
||||
case EHPersonality::MSVC_CXX:
|
||||
case EHPersonality::MSVC_X86SEH:
|
||||
case EHPersonality::MSVC_Win64SEH:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
llvm_unreachable("invalid enum");
|
||||
}
|
||||
|
||||
bool canSimplifyInvokeNoUnwind(const InvokeInst *II);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -27,8 +27,7 @@ class MDNode;
|
||||
/// specified pointer, we do a quick local scan of the basic block containing
|
||||
/// ScanFrom, to determine if the address is already accessed.
|
||||
bool isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
|
||||
unsigned Align,
|
||||
const DataLayout *TD = nullptr);
|
||||
unsigned Align);
|
||||
|
||||
/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at
|
||||
/// the instruction before ScanFrom) checking to see if we have the value at
|
||||
|
552
contrib/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Normal file
552
contrib/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Normal file
@ -0,0 +1,552 @@
|
||||
//===- llvm/Analysis/LoopAccessAnalysis.h -----------------------*- 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 interface for the loop memory dependence framework that
|
||||
// was originally developed for the Loop Vectorizer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPACCESSANALYSIS_H
|
||||
#define LLVM_ANALYSIS_LOOPACCESSANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/EquivalenceClasses.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/AliasSetTracker.h"
|
||||
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Value;
|
||||
class DataLayout;
|
||||
class AliasAnalysis;
|
||||
class ScalarEvolution;
|
||||
class Loop;
|
||||
class SCEV;
|
||||
|
||||
/// Optimization analysis message produced during vectorization. Messages inform
|
||||
/// the user why vectorization did not occur.
|
||||
class LoopAccessReport {
|
||||
std::string Message;
|
||||
const Instruction *Instr;
|
||||
|
||||
protected:
|
||||
LoopAccessReport(const Twine &Message, const Instruction *I)
|
||||
: Message(Message.str()), Instr(I) {}
|
||||
|
||||
public:
|
||||
LoopAccessReport(const Instruction *I = nullptr) : Instr(I) {}
|
||||
|
||||
template <typename A> LoopAccessReport &operator<<(const A &Value) {
|
||||
raw_string_ostream Out(Message);
|
||||
Out << Value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Instruction *getInstr() const { return Instr; }
|
||||
|
||||
std::string &str() { return Message; }
|
||||
const std::string &str() const { return Message; }
|
||||
operator Twine() { return Message; }
|
||||
|
||||
/// \brief Emit an analysis note for \p PassName with the debug location from
|
||||
/// the instruction in \p Message if available. Otherwise use the location of
|
||||
/// \p TheLoop.
|
||||
static void emitAnalysis(const LoopAccessReport &Message,
|
||||
const Function *TheFunction,
|
||||
const Loop *TheLoop,
|
||||
const char *PassName);
|
||||
};
|
||||
|
||||
/// \brief Collection of parameters shared beetween the Loop Vectorizer and the
|
||||
/// Loop Access Analysis.
|
||||
struct VectorizerParams {
|
||||
/// \brief Maximum SIMD width.
|
||||
static const unsigned MaxVectorWidth;
|
||||
|
||||
/// \brief VF as overridden by the user.
|
||||
static unsigned VectorizationFactor;
|
||||
/// \brief Interleave factor as overridden by the user.
|
||||
static unsigned VectorizationInterleave;
|
||||
/// \brief True if force-vector-interleave was specified by the user.
|
||||
static bool isInterleaveForced();
|
||||
|
||||
/// \\brief When performing memory disambiguation checks at runtime do not
|
||||
/// make more than this number of comparisons.
|
||||
static unsigned RuntimeMemoryCheckThreshold;
|
||||
};
|
||||
|
||||
/// \brief Checks memory dependences among accesses to the same underlying
|
||||
/// object to determine whether there vectorization is legal or not (and at
|
||||
/// which vectorization factor).
|
||||
///
|
||||
/// Note: This class will compute a conservative dependence for access to
|
||||
/// different underlying pointers. Clients, such as the loop vectorizer, will
|
||||
/// sometimes deal these potential dependencies by emitting runtime checks.
|
||||
///
|
||||
/// We use the ScalarEvolution framework to symbolically evalutate access
|
||||
/// functions pairs. Since we currently don't restructure the loop we can rely
|
||||
/// on the program order of memory accesses to determine their safety.
|
||||
/// At the moment we will only deem accesses as safe for:
|
||||
/// * A negative constant distance assuming program order.
|
||||
///
|
||||
/// Safe: tmp = a[i + 1]; OR a[i + 1] = x;
|
||||
/// a[i] = tmp; y = a[i];
|
||||
///
|
||||
/// The latter case is safe because later checks guarantuee that there can't
|
||||
/// be a cycle through a phi node (that is, we check that "x" and "y" is not
|
||||
/// the same variable: a header phi can only be an induction or a reduction, a
|
||||
/// reduction can't have a memory sink, an induction can't have a memory
|
||||
/// source). This is important and must not be violated (or we have to
|
||||
/// resort to checking for cycles through memory).
|
||||
///
|
||||
/// * A positive constant distance assuming program order that is bigger
|
||||
/// than the biggest memory access.
|
||||
///
|
||||
/// tmp = a[i] OR b[i] = x
|
||||
/// a[i+2] = tmp y = b[i+2];
|
||||
///
|
||||
/// Safe distance: 2 x sizeof(a[0]), and 2 x sizeof(b[0]), respectively.
|
||||
///
|
||||
/// * Zero distances and all accesses have the same size.
|
||||
///
|
||||
class MemoryDepChecker {
|
||||
public:
|
||||
typedef PointerIntPair<Value *, 1, bool> MemAccessInfo;
|
||||
typedef SmallPtrSet<MemAccessInfo, 8> MemAccessInfoSet;
|
||||
/// \brief Set of potential dependent memory accesses.
|
||||
typedef EquivalenceClasses<MemAccessInfo> DepCandidates;
|
||||
|
||||
/// \brief Dependece between memory access instructions.
|
||||
struct Dependence {
|
||||
/// \brief The type of the dependence.
|
||||
enum DepType {
|
||||
// No dependence.
|
||||
NoDep,
|
||||
// We couldn't determine the direction or the distance.
|
||||
Unknown,
|
||||
// Lexically forward.
|
||||
Forward,
|
||||
// Forward, but if vectorized, is likely to prevent store-to-load
|
||||
// forwarding.
|
||||
ForwardButPreventsForwarding,
|
||||
// Lexically backward.
|
||||
Backward,
|
||||
// Backward, but the distance allows a vectorization factor of
|
||||
// MaxSafeDepDistBytes.
|
||||
BackwardVectorizable,
|
||||
// Same, but may prevent store-to-load forwarding.
|
||||
BackwardVectorizableButPreventsForwarding
|
||||
};
|
||||
|
||||
/// \brief String version of the types.
|
||||
static const char *DepName[];
|
||||
|
||||
/// \brief Index of the source of the dependence in the InstMap vector.
|
||||
unsigned Source;
|
||||
/// \brief Index of the destination of the dependence in the InstMap vector.
|
||||
unsigned Destination;
|
||||
/// \brief The type of the dependence.
|
||||
DepType Type;
|
||||
|
||||
Dependence(unsigned Source, unsigned Destination, DepType Type)
|
||||
: Source(Source), Destination(Destination), Type(Type) {}
|
||||
|
||||
/// \brief Dependence types that don't prevent vectorization.
|
||||
static bool isSafeForVectorization(DepType Type);
|
||||
|
||||
/// \brief Dependence types that can be queried from the analysis.
|
||||
static bool isInterestingDependence(DepType Type);
|
||||
|
||||
/// \brief Lexically backward dependence types.
|
||||
bool isPossiblyBackward() const;
|
||||
|
||||
/// \brief Print the dependence. \p Instr is used to map the instruction
|
||||
/// indices to instructions.
|
||||
void print(raw_ostream &OS, unsigned Depth,
|
||||
const SmallVectorImpl<Instruction *> &Instrs) const;
|
||||
};
|
||||
|
||||
MemoryDepChecker(ScalarEvolution *Se, const Loop *L)
|
||||
: SE(Se), InnermostLoop(L), AccessIdx(0),
|
||||
ShouldRetryWithRuntimeCheck(false), SafeForVectorization(true),
|
||||
RecordInterestingDependences(true) {}
|
||||
|
||||
/// \brief Register the location (instructions are given increasing numbers)
|
||||
/// of a write access.
|
||||
void addAccess(StoreInst *SI) {
|
||||
Value *Ptr = SI->getPointerOperand();
|
||||
Accesses[MemAccessInfo(Ptr, true)].push_back(AccessIdx);
|
||||
InstMap.push_back(SI);
|
||||
++AccessIdx;
|
||||
}
|
||||
|
||||
/// \brief Register the location (instructions are given increasing numbers)
|
||||
/// of a write access.
|
||||
void addAccess(LoadInst *LI) {
|
||||
Value *Ptr = LI->getPointerOperand();
|
||||
Accesses[MemAccessInfo(Ptr, false)].push_back(AccessIdx);
|
||||
InstMap.push_back(LI);
|
||||
++AccessIdx;
|
||||
}
|
||||
|
||||
/// \brief Check whether the dependencies between the accesses are safe.
|
||||
///
|
||||
/// Only checks sets with elements in \p CheckDeps.
|
||||
bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoSet &CheckDeps,
|
||||
const ValueToValueMap &Strides);
|
||||
|
||||
/// \brief No memory dependence was encountered that would inhibit
|
||||
/// vectorization.
|
||||
bool isSafeForVectorization() const { return SafeForVectorization; }
|
||||
|
||||
/// \brief The maximum number of bytes of a vector register we can vectorize
|
||||
/// the accesses safely with.
|
||||
unsigned getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; }
|
||||
|
||||
/// \brief In same cases when the dependency check fails we can still
|
||||
/// vectorize the loop with a dynamic array access check.
|
||||
bool shouldRetryWithRuntimeCheck() { return ShouldRetryWithRuntimeCheck; }
|
||||
|
||||
/// \brief Returns the interesting dependences. If null is returned we
|
||||
/// exceeded the MaxInterestingDependence threshold and this information is
|
||||
/// not available.
|
||||
const SmallVectorImpl<Dependence> *getInterestingDependences() const {
|
||||
return RecordInterestingDependences ? &InterestingDependences : nullptr;
|
||||
}
|
||||
|
||||
void clearInterestingDependences() { InterestingDependences.clear(); }
|
||||
|
||||
/// \brief The vector of memory access instructions. The indices are used as
|
||||
/// instruction identifiers in the Dependence class.
|
||||
const SmallVectorImpl<Instruction *> &getMemoryInstructions() const {
|
||||
return InstMap;
|
||||
}
|
||||
|
||||
/// \brief Find the set of instructions that read or write via \p Ptr.
|
||||
SmallVector<Instruction *, 4> getInstructionsForAccess(Value *Ptr,
|
||||
bool isWrite) const;
|
||||
|
||||
private:
|
||||
ScalarEvolution *SE;
|
||||
const Loop *InnermostLoop;
|
||||
|
||||
/// \brief Maps access locations (ptr, read/write) to program order.
|
||||
DenseMap<MemAccessInfo, std::vector<unsigned> > Accesses;
|
||||
|
||||
/// \brief Memory access instructions in program order.
|
||||
SmallVector<Instruction *, 16> InstMap;
|
||||
|
||||
/// \brief The program order index to be used for the next instruction.
|
||||
unsigned AccessIdx;
|
||||
|
||||
// We can access this many bytes in parallel safely.
|
||||
unsigned MaxSafeDepDistBytes;
|
||||
|
||||
/// \brief If we see a non-constant dependence distance we can still try to
|
||||
/// vectorize this loop with runtime checks.
|
||||
bool ShouldRetryWithRuntimeCheck;
|
||||
|
||||
/// \brief No memory dependence was encountered that would inhibit
|
||||
/// vectorization.
|
||||
bool SafeForVectorization;
|
||||
|
||||
//// \brief True if InterestingDependences reflects the dependences in the
|
||||
//// loop. If false we exceeded MaxInterestingDependence and
|
||||
//// InterestingDependences is invalid.
|
||||
bool RecordInterestingDependences;
|
||||
|
||||
/// \brief Interesting memory dependences collected during the analysis as
|
||||
/// defined by isInterestingDependence. Only valid if
|
||||
/// RecordInterestingDependences is true.
|
||||
SmallVector<Dependence, 8> InterestingDependences;
|
||||
|
||||
/// \brief Check whether there is a plausible dependence between the two
|
||||
/// accesses.
|
||||
///
|
||||
/// Access \p A must happen before \p B in program order. The two indices
|
||||
/// identify the index into the program order map.
|
||||
///
|
||||
/// This function checks whether there is a plausible dependence (or the
|
||||
/// absence of such can't be proved) between the two accesses. If there is a
|
||||
/// plausible dependence but the dependence distance is bigger than one
|
||||
/// element access it records this distance in \p MaxSafeDepDistBytes (if this
|
||||
/// distance is smaller than any other distance encountered so far).
|
||||
/// Otherwise, this function returns true signaling a possible dependence.
|
||||
Dependence::DepType isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
const MemAccessInfo &B, unsigned BIdx,
|
||||
const ValueToValueMap &Strides);
|
||||
|
||||
/// \brief Check whether the data dependence could prevent store-load
|
||||
/// forwarding.
|
||||
bool couldPreventStoreLoadForward(unsigned Distance, unsigned TypeByteSize);
|
||||
};
|
||||
|
||||
/// \brief Drive the analysis of memory accesses in the loop
|
||||
///
|
||||
/// This class is responsible for analyzing the memory accesses of a loop. It
|
||||
/// collects the accesses and then its main helper the AccessAnalysis class
|
||||
/// finds and categorizes the dependences in buildDependenceSets.
|
||||
///
|
||||
/// For memory dependences that can be analyzed at compile time, it determines
|
||||
/// whether the dependence is part of cycle inhibiting vectorization. This work
|
||||
/// is delegated to the MemoryDepChecker class.
|
||||
///
|
||||
/// For memory dependences that cannot be determined at compile time, it
|
||||
/// generates run-time checks to prove independence. This is done by
|
||||
/// AccessAnalysis::canCheckPtrAtRT and the checks are maintained by the
|
||||
/// RuntimePointerCheck class.
|
||||
class LoopAccessInfo {
|
||||
public:
|
||||
/// This struct holds information about the memory runtime legality check that
|
||||
/// a group of pointers do not overlap.
|
||||
struct RuntimePointerCheck {
|
||||
RuntimePointerCheck() : Need(false) {}
|
||||
|
||||
/// Reset the state of the pointer runtime information.
|
||||
void reset() {
|
||||
Need = false;
|
||||
Pointers.clear();
|
||||
Starts.clear();
|
||||
Ends.clear();
|
||||
IsWritePtr.clear();
|
||||
DependencySetId.clear();
|
||||
AliasSetId.clear();
|
||||
}
|
||||
|
||||
/// Insert a pointer and calculate the start and end SCEVs.
|
||||
void insert(ScalarEvolution *SE, Loop *Lp, Value *Ptr, bool WritePtr,
|
||||
unsigned DepSetId, unsigned ASId,
|
||||
const ValueToValueMap &Strides);
|
||||
|
||||
/// \brief No run-time memory checking is necessary.
|
||||
bool empty() const { return Pointers.empty(); }
|
||||
|
||||
/// \brief Decide whether we need to issue a run-time check for pointer at
|
||||
/// index \p I and \p J to prove their independence.
|
||||
///
|
||||
/// If \p PtrPartition is set, it contains the partition number for
|
||||
/// pointers (-1 if the pointer belongs to multiple partitions). In this
|
||||
/// case omit checks between pointers belonging to the same partition.
|
||||
bool needsChecking(unsigned I, unsigned J,
|
||||
const SmallVectorImpl<int> *PtrPartition) const;
|
||||
|
||||
/// \brief Return true if any pointer requires run-time checking according
|
||||
/// to needsChecking.
|
||||
bool needsAnyChecking(const SmallVectorImpl<int> *PtrPartition) const;
|
||||
|
||||
/// \brief Print the list run-time memory checks necessary.
|
||||
///
|
||||
/// If \p PtrPartition is set, it contains the partition number for
|
||||
/// pointers (-1 if the pointer belongs to multiple partitions). In this
|
||||
/// case omit checks between pointers belonging to the same partition.
|
||||
void print(raw_ostream &OS, unsigned Depth = 0,
|
||||
const SmallVectorImpl<int> *PtrPartition = nullptr) const;
|
||||
|
||||
/// This flag indicates if we need to add the runtime check.
|
||||
bool Need;
|
||||
/// Holds the pointers that we need to check.
|
||||
SmallVector<TrackingVH<Value>, 2> Pointers;
|
||||
/// Holds the pointer value at the beginning of the loop.
|
||||
SmallVector<const SCEV*, 2> Starts;
|
||||
/// Holds the pointer value at the end of the loop.
|
||||
SmallVector<const SCEV*, 2> Ends;
|
||||
/// Holds the information if this pointer is used for writing to memory.
|
||||
SmallVector<bool, 2> IsWritePtr;
|
||||
/// Holds the id of the set of pointers that could be dependent because of a
|
||||
/// shared underlying object.
|
||||
SmallVector<unsigned, 2> DependencySetId;
|
||||
/// Holds the id of the disjoint alias set to which this pointer belongs.
|
||||
SmallVector<unsigned, 2> AliasSetId;
|
||||
};
|
||||
|
||||
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI, AliasAnalysis *AA,
|
||||
DominatorTree *DT, LoopInfo *LI,
|
||||
const ValueToValueMap &Strides);
|
||||
|
||||
/// Return true we can analyze the memory accesses in the loop and there are
|
||||
/// no memory dependence cycles.
|
||||
bool canVectorizeMemory() const { return CanVecMem; }
|
||||
|
||||
const RuntimePointerCheck *getRuntimePointerCheck() const {
|
||||
return &PtrRtCheck;
|
||||
}
|
||||
|
||||
/// \brief Number of memchecks required to prove independence of otherwise
|
||||
/// may-alias pointers.
|
||||
unsigned getNumRuntimePointerChecks() const { return NumComparisons; }
|
||||
|
||||
/// Return true if the block BB needs to be predicated in order for the loop
|
||||
/// to be vectorized.
|
||||
static bool blockNeedsPredication(BasicBlock *BB, Loop *TheLoop,
|
||||
DominatorTree *DT);
|
||||
|
||||
/// Returns true if the value V is uniform within the loop.
|
||||
bool isUniform(Value *V) const;
|
||||
|
||||
unsigned getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; }
|
||||
unsigned getNumStores() const { return NumStores; }
|
||||
unsigned getNumLoads() const { return NumLoads;}
|
||||
|
||||
/// \brief Add code that checks at runtime if the accessed arrays overlap.
|
||||
///
|
||||
/// Returns a pair of instructions where the first element is the first
|
||||
/// instruction generated in possibly a sequence of instructions and the
|
||||
/// second value is the final comparator value or NULL if no check is needed.
|
||||
///
|
||||
/// If \p PtrPartition is set, it contains the partition number for pointers
|
||||
/// (-1 if the pointer belongs to multiple partitions). In this case omit
|
||||
/// checks between pointers belonging to the same partition.
|
||||
std::pair<Instruction *, Instruction *>
|
||||
addRuntimeCheck(Instruction *Loc,
|
||||
const SmallVectorImpl<int> *PtrPartition = nullptr) const;
|
||||
|
||||
/// \brief The diagnostics report generated for the analysis. E.g. why we
|
||||
/// couldn't analyze the loop.
|
||||
const Optional<LoopAccessReport> &getReport() const { return Report; }
|
||||
|
||||
/// \brief the Memory Dependence Checker which can determine the
|
||||
/// loop-independent and loop-carried dependences between memory accesses.
|
||||
const MemoryDepChecker &getDepChecker() const { return DepChecker; }
|
||||
|
||||
/// \brief Return the list of instructions that use \p Ptr to read or write
|
||||
/// memory.
|
||||
SmallVector<Instruction *, 4> getInstructionsForAccess(Value *Ptr,
|
||||
bool isWrite) const {
|
||||
return DepChecker.getInstructionsForAccess(Ptr, isWrite);
|
||||
}
|
||||
|
||||
/// \brief Print the information about the memory accesses in the loop.
|
||||
void print(raw_ostream &OS, unsigned Depth = 0) const;
|
||||
|
||||
/// \brief Used to ensure that if the analysis was run with speculating the
|
||||
/// value of symbolic strides, the client queries it with the same assumption.
|
||||
/// Only used in DEBUG build but we don't want NDEBUG-dependent ABI.
|
||||
unsigned NumSymbolicStrides;
|
||||
|
||||
/// \brief Checks existence of store to invariant address inside loop.
|
||||
/// If the loop has any store to invariant address, then it returns true,
|
||||
/// else returns false.
|
||||
bool hasStoreToLoopInvariantAddress() const {
|
||||
return StoreToLoopInvariantAddress;
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Analyze the loop. Substitute symbolic strides using Strides.
|
||||
void analyzeLoop(const ValueToValueMap &Strides);
|
||||
|
||||
/// \brief Check if the structure of the loop allows it to be analyzed by this
|
||||
/// pass.
|
||||
bool canAnalyzeLoop();
|
||||
|
||||
void emitAnalysis(LoopAccessReport &Message);
|
||||
|
||||
/// We need to check that all of the pointers in this list are disjoint
|
||||
/// at runtime.
|
||||
RuntimePointerCheck PtrRtCheck;
|
||||
|
||||
/// \brief the Memory Dependence Checker which can determine the
|
||||
/// loop-independent and loop-carried dependences between memory accesses.
|
||||
MemoryDepChecker DepChecker;
|
||||
|
||||
/// \brief Number of memchecks required to prove independence of otherwise
|
||||
/// may-alias pointers
|
||||
unsigned NumComparisons;
|
||||
|
||||
Loop *TheLoop;
|
||||
ScalarEvolution *SE;
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
AliasAnalysis *AA;
|
||||
DominatorTree *DT;
|
||||
LoopInfo *LI;
|
||||
|
||||
unsigned NumLoads;
|
||||
unsigned NumStores;
|
||||
|
||||
unsigned MaxSafeDepDistBytes;
|
||||
|
||||
/// \brief Cache the result of analyzeLoop.
|
||||
bool CanVecMem;
|
||||
|
||||
/// \brief Indicator for storing to uniform addresses.
|
||||
/// If a loop has write to a loop invariant address then it should be true.
|
||||
bool StoreToLoopInvariantAddress;
|
||||
|
||||
/// \brief The diagnostics report generated for the analysis. E.g. why we
|
||||
/// couldn't analyze the loop.
|
||||
Optional<LoopAccessReport> Report;
|
||||
};
|
||||
|
||||
Value *stripIntegerCast(Value *V);
|
||||
|
||||
///\brief Return the SCEV corresponding to a pointer with the symbolic stride
|
||||
///replaced with constant one.
|
||||
///
|
||||
/// If \p OrigPtr is not null, use it to look up the stride value instead of \p
|
||||
/// Ptr. \p PtrToStride provides the mapping between the pointer value and its
|
||||
/// stride as collected by LoopVectorizationLegality::collectStridedAccess.
|
||||
const SCEV *replaceSymbolicStrideSCEV(ScalarEvolution *SE,
|
||||
const ValueToValueMap &PtrToStride,
|
||||
Value *Ptr, Value *OrigPtr = nullptr);
|
||||
|
||||
/// \brief This analysis provides dependence information for the memory accesses
|
||||
/// of a loop.
|
||||
///
|
||||
/// It runs the analysis for a loop on demand. This can be initiated by
|
||||
/// querying the loop access info via LAA::getInfo. getInfo return a
|
||||
/// LoopAccessInfo object. See this class for the specifics of what information
|
||||
/// is provided.
|
||||
class LoopAccessAnalysis : public FunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LoopAccessAnalysis() : FunctionPass(ID) {
|
||||
initializeLoopAccessAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// \brief Query the result of the loop access information for the loop \p L.
|
||||
///
|
||||
/// If the client speculates (and then issues run-time checks) for the values
|
||||
/// of symbolic strides, \p Strides provides the mapping (see
|
||||
/// replaceSymbolicStrideSCEV). If there is no cached result available run
|
||||
/// the analysis.
|
||||
const LoopAccessInfo &getInfo(Loop *L, const ValueToValueMap &Strides);
|
||||
|
||||
void releaseMemory() override {
|
||||
// Invalidate the cache when the pass is freed.
|
||||
LoopAccessInfoMap.clear();
|
||||
}
|
||||
|
||||
/// \brief Print the result of the analysis when invoked with -analyze.
|
||||
void print(raw_ostream &OS, const Module *M = nullptr) const override;
|
||||
|
||||
private:
|
||||
/// \brief The cache.
|
||||
DenseMap<Loop *, std::unique_ptr<LoopAccessInfo>> LoopAccessInfoMap;
|
||||
|
||||
// The used analysis passes.
|
||||
ScalarEvolution *SE;
|
||||
const TargetLibraryInfo *TLI;
|
||||
AliasAnalysis *AA;
|
||||
DominatorTree *DT;
|
||||
LoopInfo *LI;
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
@ -42,6 +42,11 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// FIXME: Replace this brittle forward declaration with the include of the new
|
||||
// PassManager.h when doing so doesn't break the PassManagerBuilder.
|
||||
template <typename IRUnitT> class AnalysisManager;
|
||||
class PreservedAnalyses;
|
||||
|
||||
template<typename T>
|
||||
inline void RemoveFromVector(std::vector<T*> &V, T *N) {
|
||||
typename std::vector<T*>::iterator I = std::find(V.begin(), V.end(), N);
|
||||
@ -74,9 +79,9 @@ class LoopBase {
|
||||
|
||||
SmallPtrSet<const BlockT*, 8> DenseBlockSet;
|
||||
|
||||
LoopBase(const LoopBase<BlockT, LoopT> &) LLVM_DELETED_FUNCTION;
|
||||
LoopBase(const LoopBase<BlockT, LoopT> &) = delete;
|
||||
const LoopBase<BlockT, LoopT>&
|
||||
operator=(const LoopBase<BlockT, LoopT> &) LLVM_DELETED_FUNCTION;
|
||||
operator=(const LoopBase<BlockT, LoopT> &) = delete;
|
||||
public:
|
||||
/// Loop ctor - This creates an empty loop.
|
||||
LoopBase() : ParentLoop(nullptr) {}
|
||||
@ -356,11 +361,11 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
|
||||
/// isLoopInvariant - Return true if the specified value is loop invariant
|
||||
///
|
||||
bool isLoopInvariant(Value *V) const;
|
||||
bool isLoopInvariant(const Value *V) const;
|
||||
|
||||
/// hasLoopInvariantOperands - Return true if all the operands of the
|
||||
/// specified instruction are loop invariant.
|
||||
bool hasLoopInvariantOperands(Instruction *I) const;
|
||||
bool hasLoopInvariantOperands(const Instruction *I) const;
|
||||
|
||||
/// makeLoopInvariant - If the given value is an instruction inside of the
|
||||
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
|
||||
@ -459,23 +464,20 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
/// cannot find a terminating instruction with location information,
|
||||
/// it returns an unknown location.
|
||||
DebugLoc getStartLoc() const {
|
||||
DebugLoc StartLoc;
|
||||
BasicBlock *HeadBB;
|
||||
|
||||
// Try the pre-header first.
|
||||
if ((HeadBB = getLoopPreheader()) != nullptr) {
|
||||
StartLoc = HeadBB->getTerminator()->getDebugLoc();
|
||||
if (!StartLoc.isUnknown())
|
||||
return StartLoc;
|
||||
}
|
||||
if ((HeadBB = getLoopPreheader()) != nullptr)
|
||||
if (DebugLoc DL = HeadBB->getTerminator()->getDebugLoc())
|
||||
return DL;
|
||||
|
||||
// If we have no pre-header or there are no instructions with debug
|
||||
// info in it, try the header.
|
||||
HeadBB = getHeader();
|
||||
if (HeadBB)
|
||||
StartLoc = HeadBB->getTerminator()->getDebugLoc();
|
||||
return HeadBB->getTerminator()->getDebugLoc();
|
||||
|
||||
return StartLoc;
|
||||
return DebugLoc();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -496,18 +498,33 @@ class LoopInfoBase {
|
||||
friend class LoopBase<BlockT, LoopT>;
|
||||
friend class LoopInfo;
|
||||
|
||||
void operator=(const LoopInfoBase &) LLVM_DELETED_FUNCTION;
|
||||
LoopInfoBase(const LoopInfo &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const LoopInfoBase &) = delete;
|
||||
LoopInfoBase(const LoopInfoBase &) = delete;
|
||||
public:
|
||||
LoopInfoBase() { }
|
||||
~LoopInfoBase() { releaseMemory(); }
|
||||
|
||||
void releaseMemory() {
|
||||
for (typename std::vector<LoopT *>::iterator I =
|
||||
TopLevelLoops.begin(), E = TopLevelLoops.end(); I != E; ++I)
|
||||
delete *I; // Delete all of the loops...
|
||||
LoopInfoBase(LoopInfoBase &&Arg)
|
||||
: BBMap(std::move(Arg.BBMap)),
|
||||
TopLevelLoops(std::move(Arg.TopLevelLoops)) {
|
||||
// We have to clear the arguments top level loops as we've taken ownership.
|
||||
Arg.TopLevelLoops.clear();
|
||||
}
|
||||
LoopInfoBase &operator=(LoopInfoBase &&RHS) {
|
||||
BBMap = std::move(RHS.BBMap);
|
||||
|
||||
BBMap.clear(); // Reset internal state of analysis
|
||||
for (auto *L : TopLevelLoops)
|
||||
delete L;
|
||||
TopLevelLoops = std::move(RHS.TopLevelLoops);
|
||||
RHS.TopLevelLoops.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void releaseMemory() {
|
||||
BBMap.clear();
|
||||
|
||||
for (auto *L : TopLevelLoops)
|
||||
delete L;
|
||||
TopLevelLoops.clear();
|
||||
}
|
||||
|
||||
@ -576,8 +593,7 @@ class LoopInfoBase {
|
||||
/// list with the indicated loop.
|
||||
void changeTopLevelLoop(LoopT *OldLoop,
|
||||
LoopT *NewLoop) {
|
||||
typename std::vector<LoopT *>::iterator I =
|
||||
std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
|
||||
auto I = std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
|
||||
assert(I != TopLevelLoops.end() && "Old loop not at top level!");
|
||||
*I = NewLoop;
|
||||
assert(!NewLoop->ParentLoop && !OldLoop->ParentLoop &&
|
||||
@ -595,7 +611,7 @@ class LoopInfoBase {
|
||||
/// including all of the Loop objects it is nested in and our mapping from
|
||||
/// BasicBlocks to loops.
|
||||
void removeBlock(BlockT *BB) {
|
||||
typename DenseMap<BlockT *, LoopT *>::iterator I = BBMap.find(BB);
|
||||
auto I = BBMap.find(BB);
|
||||
if (I != BBMap.end()) {
|
||||
for (LoopT *L = I->second; L; L = L->getParentLoop())
|
||||
L->removeBlockFromLoop(BB);
|
||||
@ -617,8 +633,9 @@ class LoopInfoBase {
|
||||
void Analyze(DominatorTreeBase<BlockT> &DomTree);
|
||||
|
||||
// Debugging
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
void verify() const;
|
||||
};
|
||||
|
||||
// Implementation in LoopInfoImpl.h
|
||||
@ -626,99 +643,23 @@ class LoopInfoBase {
|
||||
__extension__ extern template class LoopInfoBase<BasicBlock, Loop>;
|
||||
#endif
|
||||
|
||||
class LoopInfo : public FunctionPass {
|
||||
LoopInfoBase<BasicBlock, Loop> LI;
|
||||
class LoopInfo : public LoopInfoBase<BasicBlock, Loop> {
|
||||
typedef LoopInfoBase<BasicBlock, Loop> BaseT;
|
||||
|
||||
friend class LoopBase<BasicBlock, Loop>;
|
||||
|
||||
void operator=(const LoopInfo &) LLVM_DELETED_FUNCTION;
|
||||
LoopInfo(const LoopInfo &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const LoopInfo &) = delete;
|
||||
LoopInfo(const LoopInfo &) = delete;
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
LoopInfo() {}
|
||||
|
||||
LoopInfo() : FunctionPass(ID) {
|
||||
initializeLoopInfoPass(*PassRegistry::getPassRegistry());
|
||||
LoopInfo(LoopInfo &&Arg) : BaseT(std::move(static_cast<BaseT &>(Arg))) {}
|
||||
LoopInfo &operator=(LoopInfo &&RHS) {
|
||||
BaseT::operator=(std::move(static_cast<BaseT &>(RHS)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
LoopInfoBase<BasicBlock, Loop>& getBase() { return LI; }
|
||||
|
||||
/// iterator/begin/end - The interface to the top-level loops in the current
|
||||
/// function.
|
||||
///
|
||||
typedef LoopInfoBase<BasicBlock, Loop>::iterator iterator;
|
||||
typedef LoopInfoBase<BasicBlock, Loop>::reverse_iterator reverse_iterator;
|
||||
inline iterator begin() const { return LI.begin(); }
|
||||
inline iterator end() const { return LI.end(); }
|
||||
inline reverse_iterator rbegin() const { return LI.rbegin(); }
|
||||
inline reverse_iterator rend() const { return LI.rend(); }
|
||||
bool empty() const { return LI.empty(); }
|
||||
|
||||
/// getLoopFor - Return the inner most loop that BB lives in. If a basic
|
||||
/// block is in no loop (for example the entry node), null is returned.
|
||||
///
|
||||
inline Loop *getLoopFor(const BasicBlock *BB) const {
|
||||
return LI.getLoopFor(BB);
|
||||
}
|
||||
|
||||
/// operator[] - same as getLoopFor...
|
||||
///
|
||||
inline const Loop *operator[](const BasicBlock *BB) const {
|
||||
return LI.getLoopFor(BB);
|
||||
}
|
||||
|
||||
/// getLoopDepth - Return the loop nesting level of the specified block. A
|
||||
/// depth of 0 means the block is not inside any loop.
|
||||
///
|
||||
inline unsigned getLoopDepth(const BasicBlock *BB) const {
|
||||
return LI.getLoopDepth(BB);
|
||||
}
|
||||
|
||||
// isLoopHeader - True if the block is a loop header node
|
||||
inline bool isLoopHeader(BasicBlock *BB) const {
|
||||
return LI.isLoopHeader(BB);
|
||||
}
|
||||
|
||||
/// runOnFunction - Calculate the natural loop information.
|
||||
///
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
void verifyAnalysis() const override;
|
||||
|
||||
void releaseMemory() override { LI.releaseMemory(); }
|
||||
|
||||
void print(raw_ostream &O, const Module* M = nullptr) const override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// removeLoop - This removes the specified top-level loop from this loop info
|
||||
/// object. The loop is not deleted, as it will presumably be inserted into
|
||||
/// another loop.
|
||||
inline Loop *removeLoop(iterator I) { return LI.removeLoop(I); }
|
||||
|
||||
/// changeLoopFor - Change the top-level loop that contains BB to the
|
||||
/// specified loop. This should be used by transformations that restructure
|
||||
/// the loop hierarchy tree.
|
||||
inline void changeLoopFor(BasicBlock *BB, Loop *L) {
|
||||
LI.changeLoopFor(BB, L);
|
||||
}
|
||||
|
||||
/// changeTopLevelLoop - Replace the specified loop in the top-level loops
|
||||
/// list with the indicated loop.
|
||||
inline void changeTopLevelLoop(Loop *OldLoop, Loop *NewLoop) {
|
||||
LI.changeTopLevelLoop(OldLoop, NewLoop);
|
||||
}
|
||||
|
||||
/// addTopLevelLoop - This adds the specified loop to the collection of
|
||||
/// top-level loops.
|
||||
inline void addTopLevelLoop(Loop *New) {
|
||||
LI.addTopLevelLoop(New);
|
||||
}
|
||||
|
||||
/// removeBlock - This method completely removes BB from all data structures,
|
||||
/// including all of the Loop objects it is nested in and our mapping from
|
||||
/// BasicBlocks to loops.
|
||||
void removeBlock(BasicBlock *BB) {
|
||||
LI.removeBlock(BB);
|
||||
}
|
||||
// Most of the public interface is provided via LoopInfoBase.
|
||||
|
||||
/// updateUnloop - Update LoopInfo after removing the last backedge from a
|
||||
/// loop--now the "unloop". This updates the loop forest and parent loops for
|
||||
@ -748,7 +689,6 @@ class LoopInfo : public FunctionPass {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Allow clients to walk the list of nested loops...
|
||||
template <> struct GraphTraits<const Loop*> {
|
||||
typedef const Loop NodeType;
|
||||
@ -776,6 +716,65 @@ template <> struct GraphTraits<Loop*> {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Analysis pass that exposes the \c LoopInfo for a function.
|
||||
class LoopAnalysis {
|
||||
static char PassID;
|
||||
|
||||
public:
|
||||
typedef LoopInfo Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Provide a name for the analysis for debugging and logging.
|
||||
static StringRef name() { return "LoopAnalysis"; }
|
||||
|
||||
LoopAnalysis() {}
|
||||
LoopAnalysis(const LoopAnalysis &Arg) {}
|
||||
LoopAnalysis(LoopAnalysis &&Arg) {}
|
||||
LoopAnalysis &operator=(const LoopAnalysis &RHS) { return *this; }
|
||||
LoopAnalysis &operator=(LoopAnalysis &&RHS) { return *this; }
|
||||
|
||||
LoopInfo run(Function &F, AnalysisManager<Function> *AM);
|
||||
};
|
||||
|
||||
/// \brief Printer pass for the \c LoopAnalysis results.
|
||||
class LoopPrinterPass {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit LoopPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Function &F, AnalysisManager<Function> *AM);
|
||||
|
||||
static StringRef name() { return "LoopPrinterPass"; }
|
||||
};
|
||||
|
||||
/// \brief The legacy pass manager's analysis pass to compute loop information.
|
||||
class LoopInfoWrapperPass : public FunctionPass {
|
||||
LoopInfo LI;
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
LoopInfoWrapperPass() : FunctionPass(ID) {
|
||||
initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
LoopInfo &getLoopInfo() { return LI; }
|
||||
const LoopInfo &getLoopInfo() const { return LI; }
|
||||
|
||||
/// \brief Calculate the natural loop information for a given function.
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
void verifyAnalysis() const override;
|
||||
|
||||
void releaseMemory() override { LI.releaseMemory(); }
|
||||
|
||||
void print(raw_ostream &O, const Module *M = nullptr) const override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -402,7 +402,6 @@ static void discoverAndMapSubloop(LoopT *L, ArrayRef<BlockT*> Backedges,
|
||||
L->reserveBlocks(NumBlocks);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Populate all loop data in a stable order during a single forward DFS.
|
||||
template<class BlockT, class LoopT>
|
||||
class PopulateLoopsDFS {
|
||||
@ -410,9 +409,6 @@ class PopulateLoopsDFS {
|
||||
typedef typename BlockTraits::ChildIteratorType SuccIterTy;
|
||||
|
||||
LoopInfoBase<BlockT, LoopT> *LI;
|
||||
DenseSet<const BlockT *> VisitedBlocks;
|
||||
std::vector<std::pair<BlockT*, SuccIterTy> > DFSStack;
|
||||
|
||||
public:
|
||||
PopulateLoopsDFS(LoopInfoBase<BlockT, LoopT> *li):
|
||||
LI(li) {}
|
||||
@ -421,37 +417,13 @@ class PopulateLoopsDFS {
|
||||
|
||||
protected:
|
||||
void insertIntoLoop(BlockT *Block);
|
||||
|
||||
BlockT *dfsSource() { return DFSStack.back().first; }
|
||||
SuccIterTy &dfsSucc() { return DFSStack.back().second; }
|
||||
SuccIterTy dfsSuccEnd() { return BlockTraits::child_end(dfsSource()); }
|
||||
|
||||
void pushBlock(BlockT *Block) {
|
||||
DFSStack.push_back(std::make_pair(Block, BlockTraits::child_begin(Block)));
|
||||
}
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
/// Top-level driver for the forward DFS within the loop.
|
||||
template<class BlockT, class LoopT>
|
||||
void PopulateLoopsDFS<BlockT, LoopT>::traverse(BlockT *EntryBlock) {
|
||||
pushBlock(EntryBlock);
|
||||
VisitedBlocks.insert(EntryBlock);
|
||||
while (!DFSStack.empty()) {
|
||||
// Traverse the leftmost path as far as possible.
|
||||
while (dfsSucc() != dfsSuccEnd()) {
|
||||
BlockT *BB = *dfsSucc();
|
||||
++dfsSucc();
|
||||
if (!VisitedBlocks.insert(BB).second)
|
||||
continue;
|
||||
|
||||
// Push the next DFS successor onto the stack.
|
||||
pushBlock(BB);
|
||||
}
|
||||
// Visit the top of the stack in postorder and backtrack.
|
||||
insertIntoLoop(dfsSource());
|
||||
DFSStack.pop_back();
|
||||
}
|
||||
for (BlockT *BB : post_order(EntryBlock))
|
||||
insertIntoLoop(BB);
|
||||
}
|
||||
|
||||
/// Add a single Block to its ancestor loops in PostOrder. If the block is a
|
||||
@ -500,10 +472,9 @@ Analyze(DominatorTreeBase<BlockT> &DomTree) {
|
||||
|
||||
// Postorder traversal of the dominator tree.
|
||||
DomTreeNodeBase<BlockT>* DomRoot = DomTree.getRootNode();
|
||||
for (po_iterator<DomTreeNodeBase<BlockT>*> DomIter = po_begin(DomRoot),
|
||||
DomEnd = po_end(DomRoot); DomIter != DomEnd; ++DomIter) {
|
||||
for (auto DomNode : post_order(DomRoot)) {
|
||||
|
||||
BlockT *Header = DomIter->getBlock();
|
||||
BlockT *Header = DomNode->getBlock();
|
||||
SmallVector<BlockT *, 4> Backedges;
|
||||
|
||||
// Check each predecessor of the potential loop header.
|
||||
@ -545,6 +516,25 @@ void LoopInfoBase<BlockT, LoopT>::print(raw_ostream &OS) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class BlockT, class LoopT>
|
||||
void LoopInfoBase<BlockT, LoopT>::verify() const {
|
||||
DenseSet<const LoopT*> Loops;
|
||||
for (iterator I = begin(), E = end(); I != E; ++I) {
|
||||
assert(!(*I)->getParentLoop() && "Top-level loop has a parent!");
|
||||
(*I)->verifyLoopNest(&Loops);
|
||||
}
|
||||
|
||||
// Verify that blocks are mapped to valid loops.
|
||||
#ifndef NDEBUG
|
||||
for (auto &Entry : BBMap) {
|
||||
BlockT *BB = Entry.first;
|
||||
LoopT *L = Entry.second;
|
||||
assert(Loops.count(L) && "orphaned loop");
|
||||
assert(L->contains(BB) && "orphaned block");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -82,12 +82,6 @@ static inline CallInst *extractMallocCall(Value *I,
|
||||
return const_cast<CallInst*>(extractMallocCall((const Value*)I, TLI));
|
||||
}
|
||||
|
||||
/// isArrayMalloc - Returns the corresponding CallInst if the instruction
|
||||
/// is a call to malloc whose array size can be determined and the array size
|
||||
/// is not constant 1. Otherwise, return NULL.
|
||||
const CallInst *isArrayMalloc(const Value *I, const DataLayout *DL,
|
||||
const TargetLibraryInfo *TLI);
|
||||
|
||||
/// getMallocType - Returns the PointerType resulting from the malloc call.
|
||||
/// The PointerType depends on the number of bitcast uses of the malloc call:
|
||||
/// 0: PointerType is the malloc calls' return type.
|
||||
@ -107,11 +101,10 @@ Type *getMallocAllocatedType(const CallInst *CI, const TargetLibraryInfo *TLI);
|
||||
/// then return that multiple. For non-array mallocs, the multiple is
|
||||
/// constant 1. Otherwise, return NULL for mallocs whose array size cannot be
|
||||
/// determined.
|
||||
Value *getMallocArraySize(CallInst *CI, const DataLayout *DL,
|
||||
Value *getMallocArraySize(CallInst *CI, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI,
|
||||
bool LookThroughSExt = false);
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// calloc Call Utility Functions.
|
||||
//
|
||||
@ -147,11 +140,9 @@ static inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
|
||||
/// underlying object pointed to by Ptr.
|
||||
/// If RoundToAlign is true, then Size is rounded up to the aligment of allocas,
|
||||
/// byval arguments, and global variables.
|
||||
bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout *DL,
|
||||
bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI, bool RoundToAlign = false);
|
||||
|
||||
|
||||
|
||||
typedef std::pair<APInt, APInt> SizeOffsetType;
|
||||
|
||||
/// \brief Evaluate the size and offset of an object pointed to by a Value*
|
||||
@ -159,7 +150,7 @@ typedef std::pair<APInt, APInt> SizeOffsetType;
|
||||
class ObjectSizeOffsetVisitor
|
||||
: public InstVisitor<ObjectSizeOffsetVisitor, SizeOffsetType> {
|
||||
|
||||
const DataLayout *DL;
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
bool RoundToAlign;
|
||||
unsigned IntTyBits;
|
||||
@ -173,7 +164,7 @@ class ObjectSizeOffsetVisitor
|
||||
}
|
||||
|
||||
public:
|
||||
ObjectSizeOffsetVisitor(const DataLayout *DL, const TargetLibraryInfo *TLI,
|
||||
ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
LLVMContext &Context, bool RoundToAlign = false);
|
||||
|
||||
SizeOffsetType compute(Value *V);
|
||||
@ -222,7 +213,7 @@ class ObjectSizeOffsetEvaluator
|
||||
typedef DenseMap<const Value*, WeakEvalType> CacheMapTy;
|
||||
typedef SmallPtrSet<const Value*, 8> PtrSetTy;
|
||||
|
||||
const DataLayout *DL;
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI;
|
||||
LLVMContext &Context;
|
||||
BuilderTy Builder;
|
||||
@ -238,7 +229,7 @@ class ObjectSizeOffsetEvaluator
|
||||
SizeOffsetEvalType compute_(Value *V);
|
||||
|
||||
public:
|
||||
ObjectSizeOffsetEvaluator(const DataLayout *DL, const TargetLibraryInfo *TLI,
|
||||
ObjectSizeOffsetEvaluator(const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
LLVMContext &Context, bool RoundToAlign = false);
|
||||
SizeOffsetEvalType compute(Value *V);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/PredIteratorCache.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
@ -29,7 +30,6 @@ namespace llvm {
|
||||
class CallSite;
|
||||
class AliasAnalysis;
|
||||
class AssumptionCache;
|
||||
class DataLayout;
|
||||
class MemoryDependenceAnalysis;
|
||||
class PredIteratorCache;
|
||||
class DominatorTree;
|
||||
@ -324,14 +324,13 @@ namespace llvm {
|
||||
|
||||
/// Current AA implementation, just a cache.
|
||||
AliasAnalysis *AA;
|
||||
const DataLayout *DL;
|
||||
DominatorTree *DT;
|
||||
AssumptionCache *AC;
|
||||
std::unique_ptr<PredIteratorCache> PredCache;
|
||||
PredIteratorCache PredCache;
|
||||
|
||||
public:
|
||||
MemoryDependenceAnalysis();
|
||||
~MemoryDependenceAnalysis();
|
||||
~MemoryDependenceAnalysis() override;
|
||||
static char ID;
|
||||
|
||||
/// Pass Implementation stuff. This doesn't do any analysis eagerly.
|
||||
@ -421,20 +420,21 @@ namespace llvm {
|
||||
static unsigned getLoadLoadClobberFullWidthSize(const Value *MemLocBase,
|
||||
int64_t MemLocOffs,
|
||||
unsigned MemLocSize,
|
||||
const LoadInst *LI,
|
||||
const DataLayout &DL);
|
||||
const LoadInst *LI);
|
||||
|
||||
private:
|
||||
MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall,
|
||||
BasicBlock::iterator ScanIt,
|
||||
BasicBlock *BB);
|
||||
bool getNonLocalPointerDepFromBB(const PHITransAddr &Pointer,
|
||||
bool getNonLocalPointerDepFromBB(Instruction *QueryInst,
|
||||
const PHITransAddr &Pointer,
|
||||
const AliasAnalysis::Location &Loc,
|
||||
bool isLoad, BasicBlock *BB,
|
||||
SmallVectorImpl<NonLocalDepResult> &Result,
|
||||
DenseMap<BasicBlock*, Value*> &Visited,
|
||||
bool SkipFirstBlock = false);
|
||||
MemDepResult GetNonLocalInfoForBlock(const AliasAnalysis::Location &Loc,
|
||||
MemDepResult GetNonLocalInfoForBlock(Instruction *QueryInst,
|
||||
const AliasAnalysis::Location &Loc,
|
||||
bool isLoad, BasicBlock *BB,
|
||||
NonLocalDepInfo *Cache,
|
||||
unsigned NumSortedEntries);
|
||||
|
@ -36,9 +36,9 @@ namespace llvm {
|
||||
class PHITransAddr {
|
||||
/// Addr - The actual address we're analyzing.
|
||||
Value *Addr;
|
||||
|
||||
/// The DataLayout we are playing with if known, otherwise null.
|
||||
const DataLayout *DL;
|
||||
|
||||
/// The DataLayout we are playing with.
|
||||
const DataLayout &DL;
|
||||
|
||||
/// TLI - The target library info if known, otherwise null.
|
||||
const TargetLibraryInfo *TLI;
|
||||
@ -49,7 +49,7 @@ class PHITransAddr {
|
||||
/// InstInputs - The inputs for our symbolic address.
|
||||
SmallVector<Instruction*, 4> InstInputs;
|
||||
public:
|
||||
PHITransAddr(Value *addr, const DataLayout *DL, AssumptionCache *AC)
|
||||
PHITransAddr(Value *addr, const DataLayout &DL, AssumptionCache *AC)
|
||||
: Addr(addr), DL(DL), TLI(nullptr), AC(AC) {
|
||||
// If the address is an instruction, the whole thing is considered an input.
|
||||
if (Instruction *I = dyn_cast<Instruction>(Addr))
|
||||
|
@ -136,6 +136,13 @@ namespace llvm {
|
||||
//
|
||||
FunctionPass *createDelinearizationPass();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createDivergenceAnalysisPass - This pass determines which branches in a GPU
|
||||
// program are divergent.
|
||||
//
|
||||
FunctionPass *createDivergenceAnalysisPass();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// Minor pass prototypes, allowing us to expose them through bugpoint and
|
||||
@ -159,9 +166,13 @@ namespace llvm {
|
||||
//
|
||||
FunctionPass *createMemDepPrinter();
|
||||
|
||||
// createJumpInstrTableInfoPass - This creates a pass that stores information
|
||||
// about the jump tables created by JumpInstrTables
|
||||
ImmutablePass *createJumpInstrTableInfoPass();
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createMemDerefPrinter - This pass collects memory dereferenceability
|
||||
// information and prints it with -analyze.
|
||||
//
|
||||
FunctionPass *createMemDerefPrinter();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -30,7 +30,7 @@ struct PostDominatorTree : public FunctionPass {
|
||||
DT = new DominatorTreeBase<BasicBlock>(true);
|
||||
}
|
||||
|
||||
~PostDominatorTree();
|
||||
~PostDominatorTree() override;
|
||||
|
||||
bool runOnFunction(Function &F) override;
|
||||
|
||||
|
@ -115,8 +115,8 @@ class RegionNodeBase {
|
||||
typedef typename Tr::RegionT RegionT;
|
||||
|
||||
private:
|
||||
RegionNodeBase(const RegionNodeBase &) LLVM_DELETED_FUNCTION;
|
||||
const RegionNodeBase &operator=(const RegionNodeBase &) LLVM_DELETED_FUNCTION;
|
||||
RegionNodeBase(const RegionNodeBase &) = delete;
|
||||
const RegionNodeBase &operator=(const RegionNodeBase &) = delete;
|
||||
|
||||
/// This is the entry basic block that starts this region node. If this is a
|
||||
/// BasicBlock RegionNode, then entry is just the basic block, that this
|
||||
@ -261,8 +261,8 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
typedef typename InvBlockTraits::ChildIteratorType PredIterTy;
|
||||
|
||||
friend class RegionInfoBase<Tr>;
|
||||
RegionBase(const RegionBase &) LLVM_DELETED_FUNCTION;
|
||||
const RegionBase &operator=(const RegionBase &) LLVM_DELETED_FUNCTION;
|
||||
RegionBase(const RegionBase &) = delete;
|
||||
const RegionBase &operator=(const RegionBase &) = delete;
|
||||
|
||||
// Information necessary to manage this Region.
|
||||
RegionInfoT *RI;
|
||||
@ -674,8 +674,8 @@ class RegionInfoBase {
|
||||
RegionInfoBase();
|
||||
virtual ~RegionInfoBase();
|
||||
|
||||
RegionInfoBase(const RegionInfoBase &) LLVM_DELETED_FUNCTION;
|
||||
const RegionInfoBase &operator=(const RegionInfoBase &) LLVM_DELETED_FUNCTION;
|
||||
RegionInfoBase(const RegionInfoBase &) = delete;
|
||||
const RegionInfoBase &operator=(const RegionInfoBase &) = delete;
|
||||
|
||||
DomTreeT *DT;
|
||||
PostDomTreeT *PDT;
|
||||
@ -820,8 +820,6 @@ class RegionNode : public RegionNodeBase<RegionTraits<Function>> {
|
||||
inline RegionNode(Region *Parent, BasicBlock *Entry, bool isSubRegion = false)
|
||||
: RegionNodeBase<RegionTraits<Function>>(Parent, Entry, isSubRegion) {}
|
||||
|
||||
~RegionNode() {}
|
||||
|
||||
bool operator==(const Region &RN) const {
|
||||
return this == reinterpret_cast<const RegionNode *>(&RN);
|
||||
}
|
||||
@ -842,7 +840,7 @@ class RegionInfo : public RegionInfoBase<RegionTraits<Function>> {
|
||||
public:
|
||||
explicit RegionInfo();
|
||||
|
||||
virtual ~RegionInfo();
|
||||
~RegionInfo() override;
|
||||
|
||||
// updateStatistics - Update statistic about created regions.
|
||||
void updateStatistics(Region *R) final;
|
||||
@ -858,7 +856,7 @@ class RegionInfoPass : public FunctionPass {
|
||||
static char ID;
|
||||
explicit RegionInfoPass();
|
||||
|
||||
~RegionInfoPass();
|
||||
~RegionInfoPass() override;
|
||||
|
||||
RegionInfo &getRegionInfo() { return RI; }
|
||||
|
||||
|
@ -487,7 +487,7 @@ void RegionBase<Tr>::print(raw_ostream &OS, bool print_tree, unsigned level,
|
||||
OS.indent(level * 2 + 2);
|
||||
|
||||
if (Style == PrintBB) {
|
||||
for (const auto &BB : blocks())
|
||||
for (const auto *BB : blocks())
|
||||
OS << BB->getName() << ", "; // TODO: remove the last ","
|
||||
} else if (Style == PrintRN) {
|
||||
for (const_element_iterator I = element_begin(), E = element_end();
|
||||
@ -714,10 +714,8 @@ void RegionInfoBase<Tr>::scanForRegions(FuncT &F, BBtoBBMap *ShortCut) {
|
||||
// regions from the bottom of the dominance tree. If the small regions are
|
||||
// detected first, detection of bigger regions is faster, as we can jump
|
||||
// over the small regions.
|
||||
for (po_iterator<DomTreeNodeT *> FI = po_begin(N), FE = po_end(N); FI != FE;
|
||||
++FI) {
|
||||
findRegionsWithEntry(FI->getBlock(), ShortCut);
|
||||
}
|
||||
for (auto DomNode : post_order(N))
|
||||
findRegionsWithEntry(DomNode->getBlock(), ShortCut);
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
|
@ -145,16 +145,6 @@ class RNSuccIterator : public std::iterator<std::forward_iterator_tag,
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline const Self &operator=(const Self &I) {
|
||||
if (this != &I) {
|
||||
assert(getNode()->getParent() == I.getNode()->getParent()
|
||||
&& "Cannot assign iterators of two different regions!");
|
||||
Node = I.Node;
|
||||
BItor = I.BItor;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -240,16 +230,6 @@ class RNSuccIterator<FlatIt<NodeType>, BlockT, RegionT>
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline const Self &operator=(const Self &I) {
|
||||
if (this != &I) {
|
||||
assert(Node->getParent() == I.Node->getParent()
|
||||
&& "Cannot assign iterators to two different regions!");
|
||||
Node = I.Node;
|
||||
Itor = I.Itor;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<class NodeType, class BlockT, class RegionT>
|
||||
|
@ -71,8 +71,8 @@ namespace llvm {
|
||||
unsigned short SubclassData;
|
||||
|
||||
private:
|
||||
SCEV(const SCEV &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const SCEV &) LLVM_DELETED_FUNCTION;
|
||||
SCEV(const SCEV &) = delete;
|
||||
void operator=(const SCEV &) = delete;
|
||||
|
||||
public:
|
||||
/// NoWrapFlags are bitfield indices into SubclassData.
|
||||
@ -82,12 +82,13 @@ namespace llvm {
|
||||
/// operator. NSW is a misnomer that we use to mean no signed overflow or
|
||||
/// underflow.
|
||||
///
|
||||
/// AddRec expression may have a no-self-wraparound <NW> property if the
|
||||
/// result can never reach the start value. This property is independent of
|
||||
/// the actual start value and step direction. Self-wraparound is defined
|
||||
/// purely in terms of the recurrence's loop, step size, and
|
||||
/// bitwidth. Formally, a recurrence with no self-wraparound satisfies:
|
||||
/// abs(step) * max-iteration(loop) <= unsigned-max(bitwidth).
|
||||
/// AddRec expressions may have a no-self-wraparound <NW> property if, in
|
||||
/// the integer domain, abs(step) * max-iteration(loop) <=
|
||||
/// unsigned-max(bitwidth). This means that the recurrence will never reach
|
||||
/// its start value if the step is non-zero. Computing the same value on
|
||||
/// each iteration is not considered wrapping, and recurrences with step = 0
|
||||
/// are trivially <NW>. <NW> is independent of the sign of step and the
|
||||
/// value the add recurrence starts with.
|
||||
///
|
||||
/// Note that NUW and NSW are also valid properties of a recurrence, and
|
||||
/// either implies NW. For convenience, NW will be set for a recurrence
|
||||
@ -231,10 +232,6 @@ namespace llvm {
|
||||
///
|
||||
LoopInfo *LI;
|
||||
|
||||
/// The DataLayout information for the target we are targeting.
|
||||
///
|
||||
const DataLayout *DL;
|
||||
|
||||
/// TLI - The target library information for the target we are targeting.
|
||||
///
|
||||
TargetLibraryInfo *TLI;
|
||||
@ -259,6 +256,10 @@ namespace llvm {
|
||||
/// Mark predicate values currently being processed by isImpliedCond.
|
||||
DenseSet<Value*> PendingLoopPredicates;
|
||||
|
||||
/// Set to true by isLoopBackedgeGuardedByCond when we're walking the set of
|
||||
/// conditions dominating the backedge of a loop.
|
||||
bool WalkingBEDominatingConds;
|
||||
|
||||
/// ExitLimit - Information about the number of loop iterations for which a
|
||||
/// loop exit's branch condition evaluates to the not-taken path. This is a
|
||||
/// temporary pair of exact and max expressions that are eventually
|
||||
@ -372,43 +373,45 @@ namespace llvm {
|
||||
|
||||
/// LoopDispositions - Memoized computeLoopDisposition results.
|
||||
DenseMap<const SCEV *,
|
||||
SmallVector<std::pair<const Loop *, LoopDisposition>, 2> > LoopDispositions;
|
||||
SmallVector<PointerIntPair<const Loop *, 2, LoopDisposition>, 2>>
|
||||
LoopDispositions;
|
||||
|
||||
/// computeLoopDisposition - Compute a LoopDisposition value.
|
||||
LoopDisposition computeLoopDisposition(const SCEV *S, const Loop *L);
|
||||
|
||||
/// BlockDispositions - Memoized computeBlockDisposition results.
|
||||
DenseMap<const SCEV *,
|
||||
SmallVector<std::pair<const BasicBlock *, BlockDisposition>, 2> > BlockDispositions;
|
||||
DenseMap<
|
||||
const SCEV *,
|
||||
SmallVector<PointerIntPair<const BasicBlock *, 2, BlockDisposition>, 2>>
|
||||
BlockDispositions;
|
||||
|
||||
/// computeBlockDisposition - Compute a BlockDisposition value.
|
||||
BlockDisposition computeBlockDisposition(const SCEV *S, const BasicBlock *BB);
|
||||
|
||||
/// UnsignedRanges - Memoized results from getUnsignedRange
|
||||
/// UnsignedRanges - Memoized results from getRange
|
||||
DenseMap<const SCEV *, ConstantRange> UnsignedRanges;
|
||||
|
||||
/// SignedRanges - Memoized results from getSignedRange
|
||||
/// SignedRanges - Memoized results from getRange
|
||||
DenseMap<const SCEV *, ConstantRange> SignedRanges;
|
||||
|
||||
/// setUnsignedRange - Set the memoized unsigned range for the given SCEV.
|
||||
const ConstantRange &setUnsignedRange(const SCEV *S,
|
||||
const ConstantRange &CR) {
|
||||
/// RangeSignHint - Used to parameterize getRange
|
||||
enum RangeSignHint { HINT_RANGE_UNSIGNED, HINT_RANGE_SIGNED };
|
||||
|
||||
/// setRange - Set the memoized range for the given SCEV.
|
||||
const ConstantRange &setRange(const SCEV *S, RangeSignHint Hint,
|
||||
const ConstantRange &CR) {
|
||||
DenseMap<const SCEV *, ConstantRange> &Cache =
|
||||
Hint == HINT_RANGE_UNSIGNED ? UnsignedRanges : SignedRanges;
|
||||
|
||||
std::pair<DenseMap<const SCEV *, ConstantRange>::iterator, bool> Pair =
|
||||
UnsignedRanges.insert(std::make_pair(S, CR));
|
||||
Cache.insert(std::make_pair(S, CR));
|
||||
if (!Pair.second)
|
||||
Pair.first->second = CR;
|
||||
return Pair.first->second;
|
||||
}
|
||||
|
||||
/// setUnsignedRange - Set the memoized signed range for the given SCEV.
|
||||
const ConstantRange &setSignedRange(const SCEV *S,
|
||||
const ConstantRange &CR) {
|
||||
std::pair<DenseMap<const SCEV *, ConstantRange>::iterator, bool> Pair =
|
||||
SignedRanges.insert(std::make_pair(S, CR));
|
||||
if (!Pair.second)
|
||||
Pair.first->second = CR;
|
||||
return Pair.first->second;
|
||||
}
|
||||
/// getRange - Determine the range for a particular SCEV.
|
||||
ConstantRange getRange(const SCEV *S, RangeSignHint Hint);
|
||||
|
||||
/// createSCEV - We know that there is no SCEV for the specified value.
|
||||
/// Analyze the expression.
|
||||
@ -536,6 +539,15 @@ namespace llvm {
|
||||
const SCEV *FoundLHS,
|
||||
const SCEV *FoundRHS);
|
||||
|
||||
/// isImpliedCondOperandsViaRanges - Test whether the condition described by
|
||||
/// Pred, LHS, and RHS is true whenever the condition described by Pred,
|
||||
/// FoundLHS, and FoundRHS is true. Utility function used by
|
||||
/// isImpliedCondOperands.
|
||||
bool isImpliedCondOperandsViaRanges(ICmpInst::Predicate Pred,
|
||||
const SCEV *LHS, const SCEV *RHS,
|
||||
const SCEV *FoundLHS,
|
||||
const SCEV *FoundRHS);
|
||||
|
||||
/// getConstantEvolutionLoopExitValue - If we know that the specified Phi is
|
||||
/// in the header of its containing loop, we know the loop executes a
|
||||
/// constant number of times, and the PHI node is just a recurrence
|
||||
@ -557,6 +569,15 @@ namespace llvm {
|
||||
/// pointer.
|
||||
bool checkValidity(const SCEV *S) const;
|
||||
|
||||
// Return true if `ExtendOpTy`({`Start`,+,`Step`}) can be proved to be equal
|
||||
// to {`ExtendOpTy`(`Start`),+,`ExtendOpTy`(`Step`)}. This is equivalent to
|
||||
// proving no signed (resp. unsigned) wrap in {`Start`,+,`Step`} if
|
||||
// `ExtendOpTy` is `SCEVSignExtendExpr` (resp. `SCEVZeroExtendExpr`).
|
||||
//
|
||||
template<typename ExtendOpTy>
|
||||
bool proveNoWrapByVaryingStart(const SCEV *Start, const SCEV *Step,
|
||||
const Loop *L);
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
ScalarEvolution();
|
||||
@ -636,6 +657,15 @@ namespace llvm {
|
||||
SmallVector<const SCEV *, 4> NewOp(Operands.begin(), Operands.end());
|
||||
return getAddRecExpr(NewOp, L, Flags);
|
||||
}
|
||||
/// \brief Returns an expression for a GEP
|
||||
///
|
||||
/// \p PointeeType The type used as the basis for the pointer arithmetics
|
||||
/// \p BaseExpr The expression for the pointer operand.
|
||||
/// \p IndexExprs The expressions for the indices.
|
||||
/// \p InBounds Whether the GEP is in bounds.
|
||||
const SCEV *getGEPExpr(Type *PointeeType, const SCEV *BaseExpr,
|
||||
const SmallVectorImpl<const SCEV *> &IndexExprs,
|
||||
bool InBounds = false);
|
||||
const SCEV *getSMaxExpr(const SCEV *LHS, const SCEV *RHS);
|
||||
const SCEV *getSMaxExpr(SmallVectorImpl<const SCEV *> &Operands);
|
||||
const SCEV *getUMaxExpr(const SCEV *LHS, const SCEV *RHS);
|
||||
@ -830,11 +860,15 @@ namespace llvm {
|
||||
|
||||
/// getUnsignedRange - Determine the unsigned range for a particular SCEV.
|
||||
///
|
||||
ConstantRange getUnsignedRange(const SCEV *S);
|
||||
ConstantRange getUnsignedRange(const SCEV *S) {
|
||||
return getRange(S, HINT_RANGE_UNSIGNED);
|
||||
}
|
||||
|
||||
/// getSignedRange - Determine the signed range for a particular SCEV.
|
||||
///
|
||||
ConstantRange getSignedRange(const SCEV *S);
|
||||
ConstantRange getSignedRange(const SCEV *S) {
|
||||
return getRange(S, HINT_RANGE_SIGNED);
|
||||
}
|
||||
|
||||
/// isKnownNegative - Test if the given expression is known to be negative.
|
||||
///
|
||||
|
@ -28,7 +28,7 @@ namespace llvm {
|
||||
/// all materialized values are safe to speculate.
|
||||
bool isSafeToExpand(const SCEV *S, ScalarEvolution &SE);
|
||||
|
||||
/// SCEVExpander - This class uses information about analyze scalars to
|
||||
/// This class uses information about analyze scalars to
|
||||
/// rewrite expressions in canonical form.
|
||||
///
|
||||
/// Clients should create an instance of this class when rewriting is needed,
|
||||
@ -36,6 +36,7 @@ namespace llvm {
|
||||
/// memory.
|
||||
class SCEVExpander : public SCEVVisitor<SCEVExpander, Value*> {
|
||||
ScalarEvolution &SE;
|
||||
const DataLayout &DL;
|
||||
|
||||
// New instructions receive a name to identifies them with the current pass.
|
||||
const char* IVName;
|
||||
@ -47,37 +48,36 @@ namespace llvm {
|
||||
std::set<AssertingVH<Value> > InsertedValues;
|
||||
std::set<AssertingVH<Value> > InsertedPostIncValues;
|
||||
|
||||
/// RelevantLoops - A memoization of the "relevant" loop for a given SCEV.
|
||||
/// A memoization of the "relevant" loop for a given SCEV.
|
||||
DenseMap<const SCEV *, const Loop *> RelevantLoops;
|
||||
|
||||
/// PostIncLoops - Addrecs referring to any of the given loops are expanded
|
||||
/// \brief Addrecs referring to any of the given loops are expanded
|
||||
/// in post-inc mode. For example, expanding {1,+,1}<L> in post-inc mode
|
||||
/// returns the add instruction that adds one to the phi for {0,+,1}<L>,
|
||||
/// as opposed to a new phi starting at 1. This is only supported in
|
||||
/// non-canonical mode.
|
||||
PostIncLoopSet PostIncLoops;
|
||||
|
||||
/// IVIncInsertPos - When this is non-null, addrecs expanded in the
|
||||
/// loop it indicates should be inserted with increments at
|
||||
/// IVIncInsertPos.
|
||||
/// \brief When this is non-null, addrecs expanded in the loop it indicates
|
||||
/// should be inserted with increments at IVIncInsertPos.
|
||||
const Loop *IVIncInsertLoop;
|
||||
|
||||
/// IVIncInsertPos - When expanding addrecs in the IVIncInsertLoop loop,
|
||||
/// insert the IV increment at this position.
|
||||
/// \brief When expanding addrecs in the IVIncInsertLoop loop, insert the IV
|
||||
/// increment at this position.
|
||||
Instruction *IVIncInsertPos;
|
||||
|
||||
/// Phis that complete an IV chain. Reuse
|
||||
/// \brief Phis that complete an IV chain. Reuse
|
||||
std::set<AssertingVH<PHINode> > ChainedPhis;
|
||||
|
||||
/// CanonicalMode - When true, expressions are expanded in "canonical"
|
||||
/// form. In particular, addrecs are expanded as arithmetic based on
|
||||
/// a canonical induction variable. When false, expression are expanded
|
||||
/// in a more literal form.
|
||||
/// \brief When true, expressions are expanded in "canonical" form. In
|
||||
/// particular, addrecs are expanded as arithmetic based on a canonical
|
||||
/// induction variable. When false, expression are expanded in a more
|
||||
/// literal form.
|
||||
bool CanonicalMode;
|
||||
|
||||
/// When invoked from LSR, the expander is in "strength reduction" mode. The
|
||||
/// only difference is that phi's are only reused if they are already in
|
||||
/// "expanded" form.
|
||||
/// \brief When invoked from LSR, the expander is in "strength reduction"
|
||||
/// mode. The only difference is that phi's are only reused if they are
|
||||
/// already in "expanded" form.
|
||||
bool LSRMode;
|
||||
|
||||
typedef IRBuilder<true, TargetFolder> BuilderType;
|
||||
@ -90,11 +90,12 @@ namespace llvm {
|
||||
friend struct SCEVVisitor<SCEVExpander, Value*>;
|
||||
|
||||
public:
|
||||
/// SCEVExpander - Construct a SCEVExpander in "canonical" mode.
|
||||
explicit SCEVExpander(ScalarEvolution &se, const char *name)
|
||||
: SE(se), IVName(name), IVIncInsertLoop(nullptr), IVIncInsertPos(nullptr),
|
||||
CanonicalMode(true), LSRMode(false),
|
||||
Builder(se.getContext(), TargetFolder(se.DL)) {
|
||||
/// \brief Construct a SCEVExpander in "canonical" mode.
|
||||
explicit SCEVExpander(ScalarEvolution &se, const DataLayout &DL,
|
||||
const char *name)
|
||||
: SE(se), DL(DL), IVName(name), IVIncInsertLoop(nullptr),
|
||||
IVIncInsertPos(nullptr), CanonicalMode(true), LSRMode(false),
|
||||
Builder(se.getContext(), TargetFolder(DL)) {
|
||||
#ifndef NDEBUG
|
||||
DebugType = "";
|
||||
#endif
|
||||
@ -104,7 +105,7 @@ namespace llvm {
|
||||
void setDebugType(const char* s) { DebugType = s; }
|
||||
#endif
|
||||
|
||||
/// clear - Erase the contents of the InsertedExpressions map so that users
|
||||
/// \brief Erase the contents of the InsertedExpressions map so that users
|
||||
/// trying to expand the same expression into multiple BasicBlocks or
|
||||
/// different places within the same BasicBlock can do so.
|
||||
void clear() {
|
||||
@ -114,31 +115,38 @@ namespace llvm {
|
||||
ChainedPhis.clear();
|
||||
}
|
||||
|
||||
/// getOrInsertCanonicalInductionVariable - This method returns the
|
||||
/// canonical induction variable of the specified type for the specified
|
||||
/// loop (inserting one if there is none). A canonical induction variable
|
||||
/// starts at zero and steps by one on each iteration.
|
||||
/// \brief Return true for expressions that may incur non-trivial cost to
|
||||
/// evaluate at runtime.
|
||||
bool isHighCostExpansion(const SCEV *Expr, Loop *L) {
|
||||
SmallPtrSet<const SCEV *, 8> Processed;
|
||||
return isHighCostExpansionHelper(Expr, L, Processed);
|
||||
}
|
||||
|
||||
/// \brief This method returns the canonical induction variable of the
|
||||
/// specified type for the specified loop (inserting one if there is none).
|
||||
/// A canonical induction variable starts at zero and steps by one on each
|
||||
/// iteration.
|
||||
PHINode *getOrInsertCanonicalInductionVariable(const Loop *L, Type *Ty);
|
||||
|
||||
/// getIVIncOperand - Return the induction variable increment's IV operand.
|
||||
/// \brief Return the induction variable increment's IV operand.
|
||||
Instruction *getIVIncOperand(Instruction *IncV, Instruction *InsertPos,
|
||||
bool allowScale);
|
||||
|
||||
/// hoistIVInc - Utility for hoisting an IV increment.
|
||||
/// \brief Utility for hoisting an IV increment.
|
||||
bool hoistIVInc(Instruction *IncV, Instruction *InsertPos);
|
||||
|
||||
/// replaceCongruentIVs - replace congruent phis with their most canonical
|
||||
/// \brief replace congruent phis with their most canonical
|
||||
/// representative. Return the number of phis eliminated.
|
||||
unsigned replaceCongruentIVs(Loop *L, const DominatorTree *DT,
|
||||
SmallVectorImpl<WeakVH> &DeadInsts,
|
||||
const TargetTransformInfo *TTI = nullptr);
|
||||
|
||||
/// expandCodeFor - Insert code to directly compute the specified SCEV
|
||||
/// expression into the program. The inserted code is inserted into the
|
||||
/// specified block.
|
||||
/// \brief Insert code to directly compute the specified SCEV expression
|
||||
/// into the program. The inserted code is inserted into the specified
|
||||
/// block.
|
||||
Value *expandCodeFor(const SCEV *SH, Type *Ty, Instruction *I);
|
||||
|
||||
/// setIVIncInsertPos - Set the current IV increment loop and position.
|
||||
/// \brief Set the current IV increment loop and position.
|
||||
void setIVIncInsertPos(const Loop *L, Instruction *Pos) {
|
||||
assert(!CanonicalMode &&
|
||||
"IV increment positions are not supported in CanonicalMode");
|
||||
@ -146,16 +154,15 @@ namespace llvm {
|
||||
IVIncInsertPos = Pos;
|
||||
}
|
||||
|
||||
/// setPostInc - Enable post-inc expansion for addrecs referring to the
|
||||
/// given loops. Post-inc expansion is only supported in non-canonical
|
||||
/// mode.
|
||||
/// \brief Enable post-inc expansion for addrecs referring to the given
|
||||
/// loops. Post-inc expansion is only supported in non-canonical mode.
|
||||
void setPostInc(const PostIncLoopSet &L) {
|
||||
assert(!CanonicalMode &&
|
||||
"Post-inc expansion is not supported in CanonicalMode");
|
||||
PostIncLoops = L;
|
||||
}
|
||||
|
||||
/// clearPostInc - Disable all post-inc expansion.
|
||||
/// \brief Disable all post-inc expansion.
|
||||
void clearPostInc() {
|
||||
PostIncLoops.clear();
|
||||
|
||||
@ -164,23 +171,22 @@ namespace llvm {
|
||||
InsertedPostIncValues.clear();
|
||||
}
|
||||
|
||||
/// disableCanonicalMode - Disable the behavior of expanding expressions in
|
||||
/// canonical form rather than in a more literal form. Non-canonical mode
|
||||
/// is useful for late optimization passes.
|
||||
/// \brief Disable the behavior of expanding expressions in canonical form
|
||||
/// rather than in a more literal form. Non-canonical mode is useful for
|
||||
/// late optimization passes.
|
||||
void disableCanonicalMode() { CanonicalMode = false; }
|
||||
|
||||
void enableLSRMode() { LSRMode = true; }
|
||||
|
||||
/// clearInsertPoint - Clear the current insertion point. This is useful
|
||||
/// if the instruction that had been serving as the insertion point may
|
||||
/// have been deleted.
|
||||
/// \brief Clear the current insertion point. This is useful if the
|
||||
/// instruction that had been serving as the insertion point may have been
|
||||
/// deleted.
|
||||
void clearInsertPoint() {
|
||||
Builder.ClearInsertionPoint();
|
||||
}
|
||||
|
||||
/// isInsertedInstruction - Return true if the specified instruction was
|
||||
/// inserted by the code rewriter. If so, the client should not modify the
|
||||
/// instruction.
|
||||
/// \brief Return true if the specified instruction was inserted by the code
|
||||
/// rewriter. If so, the client should not modify the instruction.
|
||||
bool isInsertedInstruction(Instruction *I) const {
|
||||
return InsertedValues.count(I) || InsertedPostIncValues.count(I);
|
||||
}
|
||||
@ -190,24 +196,27 @@ namespace llvm {
|
||||
private:
|
||||
LLVMContext &getContext() const { return SE.getContext(); }
|
||||
|
||||
/// InsertBinop - Insert the specified binary operator, doing a small amount
|
||||
/// \brief Recursive helper function for isHighCostExpansion.
|
||||
bool isHighCostExpansionHelper(const SCEV *S, Loop *L,
|
||||
SmallPtrSetImpl<const SCEV *> &Processed);
|
||||
|
||||
/// \brief Insert the specified binary operator, doing a small amount
|
||||
/// of work to avoid inserting an obviously redundant operation.
|
||||
Value *InsertBinop(Instruction::BinaryOps Opcode, Value *LHS, Value *RHS);
|
||||
|
||||
/// ReuseOrCreateCast - Arange for there to be a cast of V to Ty at IP,
|
||||
/// reusing an existing cast if a suitable one exists, moving an existing
|
||||
/// cast if a suitable one exists but isn't in the right place, or
|
||||
/// or creating a new one.
|
||||
/// \brief Arrange for there to be a cast of V to Ty at IP, reusing an
|
||||
/// existing cast if a suitable one exists, moving an existing cast if a
|
||||
/// suitable one exists but isn't in the right place, or or creating a new
|
||||
/// one.
|
||||
Value *ReuseOrCreateCast(Value *V, Type *Ty,
|
||||
Instruction::CastOps Op,
|
||||
BasicBlock::iterator IP);
|
||||
|
||||
/// InsertNoopCastOfTo - Insert a cast of V to the specified type,
|
||||
/// which must be possible with a noop cast, doing what we can to
|
||||
/// share the casts.
|
||||
/// \brief Insert a cast of V to the specified type, which must be possible
|
||||
/// with a noop cast, doing what we can to share the casts.
|
||||
Value *InsertNoopCastOfTo(Value *V, Type *Ty);
|
||||
|
||||
/// expandAddToGEP - Expand a SCEVAddExpr with a pointer type into a GEP
|
||||
/// \brief Expand a SCEVAddExpr with a pointer type into a GEP
|
||||
/// instead of using ptrtoint+arithmetic+inttoptr.
|
||||
Value *expandAddToGEP(const SCEV *const *op_begin,
|
||||
const SCEV *const *op_end,
|
||||
@ -215,13 +224,13 @@ namespace llvm {
|
||||
|
||||
Value *expand(const SCEV *S);
|
||||
|
||||
/// expandCodeFor - Insert code to directly compute the specified SCEV
|
||||
/// expression into the program. The inserted code is inserted into the
|
||||
/// SCEVExpander's current insertion point. If a type is specified, the
|
||||
/// result will be expanded to have that type, with a cast if necessary.
|
||||
/// \brief Insert code to directly compute the specified SCEV expression
|
||||
/// into the program. The inserted code is inserted into the SCEVExpander's
|
||||
/// current insertion point. If a type is specified, the result will be
|
||||
/// expanded to have that type, with a cast if necessary.
|
||||
Value *expandCodeFor(const SCEV *SH, Type *Ty = nullptr);
|
||||
|
||||
/// getRelevantLoop - Determine the most "relevant" loop for the given SCEV.
|
||||
/// \brief Determine the most "relevant" loop for the given SCEV.
|
||||
const Loop *getRelevantLoop(const SCEV *);
|
||||
|
||||
Value *visitConstant(const SCEVConstant *S) {
|
||||
|
@ -131,8 +131,8 @@ class SparseSolver {
|
||||
typedef std::pair<BasicBlock*,BasicBlock*> Edge;
|
||||
std::set<Edge> KnownFeasibleEdges;
|
||||
|
||||
SparseSolver(const SparseSolver&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const SparseSolver&) LLVM_DELETED_FUNCTION;
|
||||
SparseSolver(const SparseSolver&) = delete;
|
||||
void operator=(const SparseSolver&) = delete;
|
||||
public:
|
||||
explicit SparseSolver(AbstractLatticeFunction *Lattice)
|
||||
: LatticeFunc(Lattice) {}
|
||||
|
@ -30,7 +30,7 @@ class DataLayout;
|
||||
|
||||
/// TargetFolder - Create constants with target dependent folding.
|
||||
class TargetFolder {
|
||||
const DataLayout *DL;
|
||||
const DataLayout &DL;
|
||||
|
||||
/// Fold - Fold the constant using target specific information.
|
||||
Constant *Fold(Constant *C) const {
|
||||
@ -41,7 +41,7 @@ class TargetFolder {
|
||||
}
|
||||
|
||||
public:
|
||||
explicit TargetFolder(const DataLayout *DL) : DL(DL) {}
|
||||
explicit TargetFolder(const DataLayout &DL) : DL(DL) {}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Binary Operators
|
||||
@ -130,34 +130,35 @@ class TargetFolder {
|
||||
// Memory Instructions
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
Constant *CreateGetElementPtr(Constant *C,
|
||||
Constant *CreateGetElementPtr(Type *Ty, Constant *C,
|
||||
ArrayRef<Constant *> IdxList) const {
|
||||
return Fold(ConstantExpr::getGetElementPtr(C, IdxList));
|
||||
return Fold(ConstantExpr::getGetElementPtr(Ty, C, IdxList));
|
||||
}
|
||||
Constant *CreateGetElementPtr(Constant *C, Constant *Idx) const {
|
||||
Constant *CreateGetElementPtr(Type *Ty, Constant *C, Constant *Idx) const {
|
||||
// This form of the function only exists to avoid ambiguous overload
|
||||
// warnings about whether to convert Idx to ArrayRef<Constant *> or
|
||||
// ArrayRef<Value *>.
|
||||
return Fold(ConstantExpr::getGetElementPtr(C, Idx));
|
||||
return Fold(ConstantExpr::getGetElementPtr(Ty, C, Idx));
|
||||
}
|
||||
Constant *CreateGetElementPtr(Constant *C,
|
||||
Constant *CreateGetElementPtr(Type *Ty, Constant *C,
|
||||
ArrayRef<Value *> IdxList) const {
|
||||
return Fold(ConstantExpr::getGetElementPtr(C, IdxList));
|
||||
return Fold(ConstantExpr::getGetElementPtr(Ty, C, IdxList));
|
||||
}
|
||||
|
||||
Constant *CreateInBoundsGetElementPtr(Constant *C,
|
||||
Constant *CreateInBoundsGetElementPtr(Type *Ty, Constant *C,
|
||||
ArrayRef<Constant *> IdxList) const {
|
||||
return Fold(ConstantExpr::getInBoundsGetElementPtr(C, IdxList));
|
||||
return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, C, IdxList));
|
||||
}
|
||||
Constant *CreateInBoundsGetElementPtr(Constant *C, Constant *Idx) const {
|
||||
Constant *CreateInBoundsGetElementPtr(Type *Ty, Constant *C,
|
||||
Constant *Idx) const {
|
||||
// This form of the function only exists to avoid ambiguous overload
|
||||
// warnings about whether to convert Idx to ArrayRef<Constant *> or
|
||||
// ArrayRef<Value *>.
|
||||
return Fold(ConstantExpr::getInBoundsGetElementPtr(C, Idx));
|
||||
return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, C, Idx));
|
||||
}
|
||||
Constant *CreateInBoundsGetElementPtr(Constant *C,
|
||||
Constant *CreateInBoundsGetElementPtr(Type *Ty, Constant *C,
|
||||
ArrayRef<Value *> IdxList) const {
|
||||
return Fold(ConstantExpr::getInBoundsGetElementPtr(C, IdxList));
|
||||
return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, C, IdxList));
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
1029
contrib/llvm/include/llvm/Analysis/TargetLibraryInfo.def
Normal file
1029
contrib/llvm/include/llvm/Analysis/TargetLibraryInfo.def
Normal file
File diff suppressed because it is too large
Load Diff
328
contrib/llvm/include/llvm/Analysis/TargetLibraryInfo.h
Normal file
328
contrib/llvm/include/llvm/Analysis/TargetLibraryInfo.h
Normal file
@ -0,0 +1,328 @@
|
||||
//===-- TargetLibraryInfo.h - Library information ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_TARGETLIBRARYINFO_H
|
||||
#define LLVM_ANALYSIS_TARGETLIBRARYINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
/// VecDesc - Describes a possible vectorization of a function.
|
||||
/// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized
|
||||
/// by a factor 'VectorizationFactor'.
|
||||
struct VecDesc {
|
||||
const char *ScalarFnName;
|
||||
const char *VectorFnName;
|
||||
unsigned VectorizationFactor;
|
||||
};
|
||||
class PreservedAnalyses;
|
||||
|
||||
namespace LibFunc {
|
||||
enum Func {
|
||||
#define TLI_DEFINE_ENUM
|
||||
#include "llvm/Analysis/TargetLibraryInfo.def"
|
||||
|
||||
NumLibFuncs
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Implementation of the target library information.
|
||||
///
|
||||
/// This class constructs tables that hold the target library information and
|
||||
/// make it available. However, it is somewhat expensive to compute and only
|
||||
/// depends on the triple. So users typicaly interact with the \c
|
||||
/// TargetLibraryInfo wrapper below.
|
||||
class TargetLibraryInfoImpl {
|
||||
friend class TargetLibraryInfo;
|
||||
|
||||
unsigned char AvailableArray[(LibFunc::NumLibFuncs+3)/4];
|
||||
llvm::DenseMap<unsigned, std::string> CustomNames;
|
||||
static const char *const StandardNames[LibFunc::NumLibFuncs];
|
||||
|
||||
enum AvailabilityState {
|
||||
StandardName = 3, // (memset to all ones)
|
||||
CustomName = 1,
|
||||
Unavailable = 0 // (memset to all zeros)
|
||||
};
|
||||
void setState(LibFunc::Func F, AvailabilityState State) {
|
||||
AvailableArray[F/4] &= ~(3 << 2*(F&3));
|
||||
AvailableArray[F/4] |= State << 2*(F&3);
|
||||
}
|
||||
AvailabilityState getState(LibFunc::Func F) const {
|
||||
return static_cast<AvailabilityState>((AvailableArray[F/4] >> 2*(F&3)) & 3);
|
||||
}
|
||||
|
||||
/// Vectorization descriptors - sorted by ScalarFnName.
|
||||
std::vector<VecDesc> VectorDescs;
|
||||
/// Scalarization descriptors - same content as VectorDescs but sorted based
|
||||
/// on VectorFnName rather than ScalarFnName.
|
||||
std::vector<VecDesc> ScalarDescs;
|
||||
|
||||
public:
|
||||
/// \brief List of known vector-functions libraries.
|
||||
///
|
||||
/// The vector-functions library defines, which functions are vectorizable
|
||||
/// and with which factor. The library can be specified by either frontend,
|
||||
/// or a commandline option, and then used by
|
||||
/// addVectorizableFunctionsFromVecLib for filling up the tables of
|
||||
/// vectorizable functions.
|
||||
enum VectorLibrary {
|
||||
NoLibrary, // Don't use any vector library.
|
||||
Accelerate // Use Accelerate framework.
|
||||
};
|
||||
|
||||
TargetLibraryInfoImpl();
|
||||
explicit TargetLibraryInfoImpl(const Triple &T);
|
||||
|
||||
// Provide value semantics.
|
||||
TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI);
|
||||
TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI);
|
||||
TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI);
|
||||
TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI);
|
||||
|
||||
/// \brief Searches for a particular function name.
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(StringRef funcName, LibFunc::Func &F) const;
|
||||
|
||||
/// \brief Forces a function to be marked as unavailable.
|
||||
void setUnavailable(LibFunc::Func F) {
|
||||
setState(F, Unavailable);
|
||||
}
|
||||
|
||||
/// \brief Forces a function to be marked as available.
|
||||
void setAvailable(LibFunc::Func F) {
|
||||
setState(F, StandardName);
|
||||
}
|
||||
|
||||
/// \brief Forces a function to be marked as available and provide an
|
||||
/// alternate name that must be used.
|
||||
void setAvailableWithName(LibFunc::Func F, StringRef Name) {
|
||||
if (StandardNames[F] != Name) {
|
||||
setState(F, CustomName);
|
||||
CustomNames[F] = Name;
|
||||
assert(CustomNames.find(F) != CustomNames.end());
|
||||
} else {
|
||||
setState(F, StandardName);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Disables all builtins.
|
||||
///
|
||||
/// This can be used for options like -fno-builtin.
|
||||
void disableAllFunctions();
|
||||
|
||||
/// addVectorizableFunctions - Add a set of scalar -> vector mappings,
|
||||
/// queryable via getVectorizedFunction and getScalarizedFunction.
|
||||
void addVectorizableFunctions(ArrayRef<VecDesc> Fns);
|
||||
|
||||
/// Calls addVectorizableFunctions with a known preset of functions for the
|
||||
/// given vector library.
|
||||
void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib);
|
||||
|
||||
/// isFunctionVectorizable - Return true if the function F has a
|
||||
/// vector equivalent with vectorization factor VF.
|
||||
bool isFunctionVectorizable(StringRef F, unsigned VF) const {
|
||||
return !getVectorizedFunction(F, VF).empty();
|
||||
}
|
||||
|
||||
/// isFunctionVectorizable - Return true if the function F has a
|
||||
/// vector equivalent with any vectorization factor.
|
||||
bool isFunctionVectorizable(StringRef F) const;
|
||||
|
||||
/// getVectorizedFunction - Return the name of the equivalent of
|
||||
/// F, vectorized with factor VF. If no such mapping exists,
|
||||
/// return the empty string.
|
||||
StringRef getVectorizedFunction(StringRef F, unsigned VF) const;
|
||||
|
||||
/// isFunctionScalarizable - Return true if the function F has a
|
||||
/// scalar equivalent, and set VF to be the vectorization factor.
|
||||
bool isFunctionScalarizable(StringRef F, unsigned &VF) const {
|
||||
return !getScalarizedFunction(F, VF).empty();
|
||||
}
|
||||
|
||||
/// getScalarizedFunction - Return the name of the equivalent of
|
||||
/// F, scalarized. If no such mapping exists, return the empty string.
|
||||
///
|
||||
/// Set VF to the vectorization factor.
|
||||
StringRef getScalarizedFunction(StringRef F, unsigned &VF) const;
|
||||
};
|
||||
|
||||
/// \brief Provides information about what library functions are available for
|
||||
/// the current target.
|
||||
///
|
||||
/// This both allows optimizations to handle them specially and frontends to
|
||||
/// disable such optimizations through -fno-builtin etc.
|
||||
class TargetLibraryInfo {
|
||||
friend class TargetLibraryAnalysis;
|
||||
friend class TargetLibraryInfoWrapperPass;
|
||||
|
||||
const TargetLibraryInfoImpl *Impl;
|
||||
|
||||
public:
|
||||
explicit TargetLibraryInfo(const TargetLibraryInfoImpl &Impl) : Impl(&Impl) {}
|
||||
|
||||
// Provide value semantics.
|
||||
TargetLibraryInfo(const TargetLibraryInfo &TLI) : Impl(TLI.Impl) {}
|
||||
TargetLibraryInfo(TargetLibraryInfo &&TLI) : Impl(TLI.Impl) {}
|
||||
TargetLibraryInfo &operator=(const TargetLibraryInfo &TLI) {
|
||||
Impl = TLI.Impl;
|
||||
return *this;
|
||||
}
|
||||
TargetLibraryInfo &operator=(TargetLibraryInfo &&TLI) {
|
||||
Impl = TLI.Impl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Searches for a particular function name.
|
||||
///
|
||||
/// If it is one of the known library functions, return true and set F to the
|
||||
/// corresponding value.
|
||||
bool getLibFunc(StringRef funcName, LibFunc::Func &F) const {
|
||||
return Impl->getLibFunc(funcName, F);
|
||||
}
|
||||
|
||||
/// \brief Tests whether a library function is available.
|
||||
bool has(LibFunc::Func F) const {
|
||||
return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable;
|
||||
}
|
||||
bool isFunctionVectorizable(StringRef F, unsigned VF) const {
|
||||
return Impl->isFunctionVectorizable(F, VF);
|
||||
};
|
||||
bool isFunctionVectorizable(StringRef F) const {
|
||||
return Impl->isFunctionVectorizable(F);
|
||||
};
|
||||
StringRef getVectorizedFunction(StringRef F, unsigned VF) const {
|
||||
return Impl->getVectorizedFunction(F, VF);
|
||||
};
|
||||
|
||||
/// \brief Tests if the function is both available and a candidate for
|
||||
/// optimized code generation.
|
||||
bool hasOptimizedCodeGen(LibFunc::Func F) const {
|
||||
if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable)
|
||||
return false;
|
||||
switch (F) {
|
||||
default: break;
|
||||
case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl:
|
||||
case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl:
|
||||
case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl:
|
||||
case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl:
|
||||
case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl:
|
||||
case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite:
|
||||
case LibFunc::sqrtl_finite:
|
||||
case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl:
|
||||
case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl:
|
||||
case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl:
|
||||
case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl:
|
||||
case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill:
|
||||
case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl:
|
||||
case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl:
|
||||
case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl:
|
||||
case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l:
|
||||
case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l:
|
||||
case LibFunc::memcmp: case LibFunc::strcmp: case LibFunc::strcpy:
|
||||
case LibFunc::stpcpy: case LibFunc::strlen: case LibFunc::strnlen:
|
||||
case LibFunc::memchr:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
StringRef getName(LibFunc::Func F) const {
|
||||
auto State = Impl->getState(F);
|
||||
if (State == TargetLibraryInfoImpl::Unavailable)
|
||||
return StringRef();
|
||||
if (State == TargetLibraryInfoImpl::StandardName)
|
||||
return Impl->StandardNames[F];
|
||||
assert(State == TargetLibraryInfoImpl::CustomName);
|
||||
return Impl->CustomNames.find(F)->second;
|
||||
}
|
||||
|
||||
/// \brief Handle invalidation from the pass manager.
|
||||
///
|
||||
/// If we try to invalidate this info, just return false. It cannot become
|
||||
/// invalid even if the module changes.
|
||||
bool invalidate(Module &, const PreservedAnalyses &) { return false; }
|
||||
};
|
||||
|
||||
/// \brief Analysis pass providing the \c TargetLibraryInfo.
|
||||
///
|
||||
/// Note that this pass's result cannot be invalidated, it is immutable for the
|
||||
/// life of the module.
|
||||
class TargetLibraryAnalysis {
|
||||
public:
|
||||
typedef TargetLibraryInfo Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Default construct the library analysis.
|
||||
///
|
||||
/// This will use the module's triple to construct the library info for that
|
||||
/// module.
|
||||
TargetLibraryAnalysis() {}
|
||||
|
||||
/// \brief Construct a library analysis with preset info.
|
||||
///
|
||||
/// This will directly copy the preset info into the result without
|
||||
/// consulting the module's triple.
|
||||
TargetLibraryAnalysis(TargetLibraryInfoImpl PresetInfoImpl)
|
||||
: PresetInfoImpl(std::move(PresetInfoImpl)) {}
|
||||
|
||||
// Move semantics. We spell out the constructors for MSVC.
|
||||
TargetLibraryAnalysis(TargetLibraryAnalysis &&Arg)
|
||||
: PresetInfoImpl(std::move(Arg.PresetInfoImpl)), Impls(std::move(Arg.Impls)) {}
|
||||
TargetLibraryAnalysis &operator=(TargetLibraryAnalysis &&RHS) {
|
||||
PresetInfoImpl = std::move(RHS.PresetInfoImpl);
|
||||
Impls = std::move(RHS.Impls);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TargetLibraryInfo run(Module &M);
|
||||
TargetLibraryInfo run(Function &F);
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "TargetLibraryAnalysis"; }
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
|
||||
Optional<TargetLibraryInfoImpl> PresetInfoImpl;
|
||||
|
||||
StringMap<std::unique_ptr<TargetLibraryInfoImpl>> Impls;
|
||||
|
||||
TargetLibraryInfoImpl &lookupInfoImpl(Triple T);
|
||||
};
|
||||
|
||||
class TargetLibraryInfoWrapperPass : public ImmutablePass {
|
||||
TargetLibraryInfoImpl TLIImpl;
|
||||
TargetLibraryInfo TLI;
|
||||
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
TargetLibraryInfoWrapperPass();
|
||||
explicit TargetLibraryInfoWrapperPass(const Triple &T);
|
||||
explicit TargetLibraryInfoWrapperPass(const TargetLibraryInfoImpl &TLI);
|
||||
|
||||
TargetLibraryInfo &getTLI() { return TLI; }
|
||||
const TargetLibraryInfo &getTLI() const { return TLI; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
//===- llvm/Analysis/TargetTransformInfo.h ----------------------*- C++ -*-===//
|
||||
//===- TargetTransformInfo.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -6,66 +6,89 @@
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass exposes codegen information to IR-level passes. Every
|
||||
// transformation that uses codegen information is broken into three parts:
|
||||
// 1. The IR-level analysis pass.
|
||||
// 2. The IR-level transformation interface which provides the needed
|
||||
// information.
|
||||
// 3. Codegen-level implementation which uses target-specific hooks.
|
||||
//
|
||||
// This file defines #2, which is the interface that IR-level transformations
|
||||
// use for querying the codegen.
|
||||
//
|
||||
/// \file
|
||||
/// This pass exposes codegen information to IR-level passes. Every
|
||||
/// transformation that uses codegen information is broken into three parts:
|
||||
/// 1. The IR-level analysis pass.
|
||||
/// 2. The IR-level transformation interface which provides the needed
|
||||
/// information.
|
||||
/// 3. Codegen-level implementation which uses target-specific hooks.
|
||||
///
|
||||
/// This file defines #2, which is the interface that IR-level transformations
|
||||
/// use for querying the codegen.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_TARGETTRANSFORMINFO_H
|
||||
#define LLVM_ANALYSIS_TARGETTRANSFORMINFO_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
class GlobalValue;
|
||||
class Loop;
|
||||
class PreservedAnalyses;
|
||||
class Type;
|
||||
class User;
|
||||
class Value;
|
||||
|
||||
/// TargetTransformInfo - This pass provides access to the codegen
|
||||
/// interfaces that are needed for IR-level transformations.
|
||||
/// \brief Information about a load/store intrinsic defined by the target.
|
||||
struct MemIntrinsicInfo {
|
||||
MemIntrinsicInfo()
|
||||
: ReadMem(false), WriteMem(false), Vol(false), MatchingId(0),
|
||||
NumMemRefs(0), PtrVal(nullptr) {}
|
||||
bool ReadMem;
|
||||
bool WriteMem;
|
||||
bool Vol;
|
||||
// Same Id is set by the target for corresponding load/store intrinsics.
|
||||
unsigned short MatchingId;
|
||||
int NumMemRefs;
|
||||
Value *PtrVal;
|
||||
};
|
||||
|
||||
/// \brief This pass provides access to the codegen interfaces that are needed
|
||||
/// for IR-level transformations.
|
||||
class TargetTransformInfo {
|
||||
protected:
|
||||
/// \brief The TTI instance one level down the stack.
|
||||
///
|
||||
/// This is used to implement the default behavior all of the methods which
|
||||
/// is to delegate up through the stack of TTIs until one can answer the
|
||||
/// query.
|
||||
TargetTransformInfo *PrevTTI;
|
||||
|
||||
/// \brief The top of the stack of TTI analyses available.
|
||||
///
|
||||
/// This is a convenience routine maintained as TTI analyses become available
|
||||
/// that complements the PrevTTI delegation chain. When one part of an
|
||||
/// analysis pass wants to query another part of the analysis pass it can use
|
||||
/// this to start back at the top of the stack.
|
||||
TargetTransformInfo *TopTTI;
|
||||
|
||||
/// All pass subclasses must in their initializePass routine call
|
||||
/// pushTTIStack with themselves to update the pointers tracking the previous
|
||||
/// TTI instance in the analysis group's stack, and the top of the analysis
|
||||
/// group's stack.
|
||||
void pushTTIStack(Pass *P);
|
||||
|
||||
/// All pass subclasses must call TargetTransformInfo::getAnalysisUsage.
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||
|
||||
public:
|
||||
/// This class is intended to be subclassed by real implementations.
|
||||
virtual ~TargetTransformInfo() = 0;
|
||||
/// \brief Construct a TTI object using a type implementing the \c Concept
|
||||
/// API below.
|
||||
///
|
||||
/// This is used by targets to construct a TTI wrapping their target-specific
|
||||
/// implementaion that encodes appropriate costs for their target.
|
||||
template <typename T> TargetTransformInfo(T Impl);
|
||||
|
||||
/// \brief Construct a baseline TTI object using a minimal implementation of
|
||||
/// the \c Concept API below.
|
||||
///
|
||||
/// The TTI implementation will reflect the information in the DataLayout
|
||||
/// provided if non-null.
|
||||
explicit TargetTransformInfo(const DataLayout *DL);
|
||||
|
||||
// Provide move semantics.
|
||||
TargetTransformInfo(TargetTransformInfo &&Arg);
|
||||
TargetTransformInfo &operator=(TargetTransformInfo &&RHS);
|
||||
|
||||
// We need to define the destructor out-of-line to define our sub-classes
|
||||
// out-of-line.
|
||||
~TargetTransformInfo();
|
||||
|
||||
/// \brief Handle the invalidation of this information.
|
||||
///
|
||||
/// When used as a result of \c TargetIRAnalysis this method will be called
|
||||
/// when the function this was computed for changes. When it returns false,
|
||||
/// the information is preserved across those changes.
|
||||
bool invalidate(Function &, const PreservedAnalyses &) {
|
||||
// FIXME: We should probably in some way ensure that the subtarget
|
||||
// information for a function hasn't changed.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \name Generic Target Information
|
||||
/// @{
|
||||
@ -86,9 +109,9 @@ class TargetTransformInfo {
|
||||
/// skipped by renaming the registers in the CPU, but they still are encoded
|
||||
/// and thus wouldn't be considered 'free' here.
|
||||
enum TargetCostConstants {
|
||||
TCC_Free = 0, ///< Expected to fold away in lowering.
|
||||
TCC_Basic = 1, ///< The cost of a typical 'add' instruction.
|
||||
TCC_Expensive = 4 ///< The cost of a 'div' instruction on x86.
|
||||
TCC_Free = 0, ///< Expected to fold away in lowering.
|
||||
TCC_Basic = 1, ///< The cost of a typical 'add' instruction.
|
||||
TCC_Expensive = 4 ///< The cost of a 'div' instruction on x86.
|
||||
};
|
||||
|
||||
/// \brief Estimate the cost of a specific operation when lowered.
|
||||
@ -105,16 +128,15 @@ class TargetTransformInfo {
|
||||
///
|
||||
/// The returned cost is defined in terms of \c TargetCostConstants, see its
|
||||
/// comments for a detailed explanation of the cost values.
|
||||
virtual unsigned getOperationCost(unsigned Opcode, Type *Ty,
|
||||
Type *OpTy = nullptr) const;
|
||||
unsigned getOperationCost(unsigned Opcode, Type *Ty,
|
||||
Type *OpTy = nullptr) const;
|
||||
|
||||
/// \brief Estimate the cost of a GEP operation when lowered.
|
||||
///
|
||||
/// The contract for this function is the same as \c getOperationCost except
|
||||
/// that it supports an interface that provides extra information specific to
|
||||
/// the GEP operation.
|
||||
virtual unsigned getGEPCost(const Value *Ptr,
|
||||
ArrayRef<const Value *> Operands) const;
|
||||
unsigned getGEPCost(const Value *Ptr, ArrayRef<const Value *> Operands) const;
|
||||
|
||||
/// \brief Estimate the cost of a function call when lowered.
|
||||
///
|
||||
@ -125,31 +147,31 @@ class TargetTransformInfo {
|
||||
/// This is the most basic query for estimating call cost: it only knows the
|
||||
/// function type and (potentially) the number of arguments at the call site.
|
||||
/// The latter is only interesting for varargs function types.
|
||||
virtual unsigned getCallCost(FunctionType *FTy, int NumArgs = -1) const;
|
||||
unsigned getCallCost(FunctionType *FTy, int NumArgs = -1) const;
|
||||
|
||||
/// \brief Estimate the cost of calling a specific function when lowered.
|
||||
///
|
||||
/// This overload adds the ability to reason about the particular function
|
||||
/// being called in the event it is a library call with special lowering.
|
||||
virtual unsigned getCallCost(const Function *F, int NumArgs = -1) const;
|
||||
unsigned getCallCost(const Function *F, int NumArgs = -1) const;
|
||||
|
||||
/// \brief Estimate the cost of calling a specific function when lowered.
|
||||
///
|
||||
/// This overload allows specifying a set of candidate argument values.
|
||||
virtual unsigned getCallCost(const Function *F,
|
||||
ArrayRef<const Value *> Arguments) const;
|
||||
unsigned getCallCost(const Function *F,
|
||||
ArrayRef<const Value *> Arguments) const;
|
||||
|
||||
/// \brief Estimate the cost of an intrinsic when lowered.
|
||||
///
|
||||
/// Mirrors the \c getCallCost method but uses an intrinsic identifier.
|
||||
virtual unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> ParamTys) const;
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> ParamTys) const;
|
||||
|
||||
/// \brief Estimate the cost of an intrinsic when lowered.
|
||||
///
|
||||
/// Mirrors the \c getCallCost method but uses an intrinsic identifier.
|
||||
virtual unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<const Value *> Arguments) const;
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<const Value *> Arguments) const;
|
||||
|
||||
/// \brief Estimate the cost of a given IR user when lowered.
|
||||
///
|
||||
@ -166,13 +188,22 @@ class TargetTransformInfo {
|
||||
///
|
||||
/// The returned cost is defined in terms of \c TargetCostConstants, see its
|
||||
/// comments for a detailed explanation of the cost values.
|
||||
virtual unsigned getUserCost(const User *U) const;
|
||||
unsigned getUserCost(const User *U) const;
|
||||
|
||||
/// \brief hasBranchDivergence - Return true if branch divergence exists.
|
||||
/// \brief Return true if branch divergence exists.
|
||||
///
|
||||
/// Branch divergence has a significantly negative impact on GPU performance
|
||||
/// when threads in the same wavefront take different paths due to conditional
|
||||
/// branches.
|
||||
virtual bool hasBranchDivergence() const;
|
||||
bool hasBranchDivergence() const;
|
||||
|
||||
/// \brief Returns whether V is a source of divergence.
|
||||
///
|
||||
/// This function provides the target-dependent information for
|
||||
/// the target-independent DivergenceAnalysis. DivergenceAnalysis first
|
||||
/// builds the dependency graph, and then runs the reachability algorithm
|
||||
/// starting with the sources of divergence.
|
||||
bool isSourceOfDivergence(const Value *V) const;
|
||||
|
||||
/// \brief Test whether calls to a function lower to actual program function
|
||||
/// calls.
|
||||
@ -186,7 +217,7 @@ class TargetTransformInfo {
|
||||
/// and execution-speed costs. This would allow modelling the core of this
|
||||
/// query more accurately as a call is a single small instruction, but
|
||||
/// incurs significant execution cost.
|
||||
virtual bool isLoweredToCall(const Function *F) const;
|
||||
bool isLoweredToCall(const Function *F) const;
|
||||
|
||||
/// Parameters that control the generic loop unrolling transformation.
|
||||
struct UnrollingPreferences {
|
||||
@ -196,6 +227,13 @@ class TargetTransformInfo {
|
||||
/// exceed this cost. Set this to UINT_MAX to disable the loop body cost
|
||||
/// restriction.
|
||||
unsigned Threshold;
|
||||
/// If complete unrolling could help other optimizations (e.g. InstSimplify)
|
||||
/// to remove N% of instructions, then we can go beyond unroll threshold.
|
||||
/// This value set the minimal percent for allowing that.
|
||||
unsigned MinPercentOfOptimized;
|
||||
/// The absolute cost threshold. We won't go beyond this even if complete
|
||||
/// unrolling could result in optimizing out 90% of instructions.
|
||||
unsigned AbsoluteThreshold;
|
||||
/// The cost threshold for the unrolled loop when optimizing for size (set
|
||||
/// to UINT_MAX to disable).
|
||||
unsigned OptSizeThreshold;
|
||||
@ -203,8 +241,8 @@ class TargetTransformInfo {
|
||||
/// for partial/runtime unrolling (set to UINT_MAX to disable).
|
||||
unsigned PartialThreshold;
|
||||
/// The cost threshold for the unrolled loop when optimizing for size, like
|
||||
/// OptSizeThreshold, but used for partial/runtime unrolling (set to UINT_MAX
|
||||
/// to disable).
|
||||
/// OptSizeThreshold, but used for partial/runtime unrolling (set to
|
||||
/// UINT_MAX to disable).
|
||||
unsigned PartialOptSizeThreshold;
|
||||
/// A forced unrolling factor (the number of concatenated bodies of the
|
||||
/// original loop in the unrolled loop body). When set to 0, the unrolling
|
||||
@ -218,18 +256,20 @@ class TargetTransformInfo {
|
||||
unsigned MaxCount;
|
||||
/// Allow partial unrolling (unrolling of loops to expand the size of the
|
||||
/// loop body, not only to eliminate small constant-trip-count loops).
|
||||
bool Partial;
|
||||
bool Partial;
|
||||
/// Allow runtime unrolling (unrolling of loops to expand the size of the
|
||||
/// loop body even when the number of loop iterations is not known at compile
|
||||
/// time).
|
||||
bool Runtime;
|
||||
/// loop body even when the number of loop iterations is not known at
|
||||
/// compile time).
|
||||
bool Runtime;
|
||||
/// Allow emitting expensive instructions (such as divisions) when computing
|
||||
/// the trip count of a loop for runtime unrolling.
|
||||
bool AllowExpensiveTripCount;
|
||||
};
|
||||
|
||||
/// \brief Get target-customized preferences for the generic loop unrolling
|
||||
/// transformation. The caller will initialize UP with the current
|
||||
/// target-independent defaults.
|
||||
virtual void getUnrollingPreferences(const Function *F, Loop *L,
|
||||
UnrollingPreferences &UP) const;
|
||||
void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) const;
|
||||
|
||||
/// @}
|
||||
|
||||
@ -244,38 +284,33 @@ class TargetTransformInfo {
|
||||
/// support is considered as "Fast" if it can outperform, or is on a par
|
||||
/// with, SW implementation when the population is sparse; otherwise, it is
|
||||
/// considered as "Slow".
|
||||
enum PopcntSupportKind {
|
||||
PSK_Software,
|
||||
PSK_SlowHardware,
|
||||
PSK_FastHardware
|
||||
};
|
||||
enum PopcntSupportKind { PSK_Software, PSK_SlowHardware, PSK_FastHardware };
|
||||
|
||||
/// \brief Return true if the specified immediate is legal add immediate, that
|
||||
/// is the target has add instructions which can add a register with the
|
||||
/// immediate without having to materialize the immediate into a register.
|
||||
virtual bool isLegalAddImmediate(int64_t Imm) const;
|
||||
bool isLegalAddImmediate(int64_t Imm) const;
|
||||
|
||||
/// \brief Return true if the specified immediate is legal icmp immediate,
|
||||
/// that is the target has icmp instructions which can compare a register
|
||||
/// against the immediate without having to materialize the immediate into a
|
||||
/// register.
|
||||
virtual bool isLegalICmpImmediate(int64_t Imm) const;
|
||||
bool isLegalICmpImmediate(int64_t Imm) const;
|
||||
|
||||
/// \brief Return true if the addressing mode represented by AM is legal for
|
||||
/// this target, for a load/store of the specified type.
|
||||
/// The type may be VoidTy, in which case only return true if the addressing
|
||||
/// mode is legal for a load/store of any legal type.
|
||||
/// TODO: Handle pre/postinc as well.
|
||||
virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
|
||||
int64_t BaseOffset, bool HasBaseReg,
|
||||
int64_t Scale) const;
|
||||
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) const;
|
||||
|
||||
/// \brief Return true if the target works with masked instruction
|
||||
/// AVX2 allows masks for consecutive load and store for i32 and i64 elements.
|
||||
/// AVX-512 architecture will also allow masks for non-consecutive memory
|
||||
/// accesses.
|
||||
virtual bool isLegalMaskedStore(Type *DataType, int Consecutive) const;
|
||||
virtual bool isLegalMaskedLoad (Type *DataType, int Consecutive) const;
|
||||
bool isLegalMaskedStore(Type *DataType, int Consecutive) const;
|
||||
bool isLegalMaskedLoad(Type *DataType, int Consecutive) const;
|
||||
|
||||
/// \brief Return the cost of the scaling factor used in the addressing
|
||||
/// mode represented by AM for this target, for a load/store
|
||||
@ -283,45 +318,55 @@ class TargetTransformInfo {
|
||||
/// If the AM is supported, the return value must be >= 0.
|
||||
/// If the AM is not supported, it returns a negative value.
|
||||
/// TODO: Handle pre/postinc as well.
|
||||
virtual int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
|
||||
int64_t BaseOffset, bool HasBaseReg,
|
||||
int64_t Scale) const;
|
||||
int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) const;
|
||||
|
||||
/// \brief Return true if it's free to truncate a value of type Ty1 to type
|
||||
/// Ty2. e.g. On x86 it's free to truncate a i32 value in register EAX to i16
|
||||
/// by referencing its sub-register AX.
|
||||
virtual bool isTruncateFree(Type *Ty1, Type *Ty2) const;
|
||||
bool isTruncateFree(Type *Ty1, Type *Ty2) const;
|
||||
|
||||
/// \brief Return true if it is profitable to hoist instruction in the
|
||||
/// then/else to before if.
|
||||
bool isProfitableToHoist(Instruction *I) const;
|
||||
|
||||
/// \brief Return true if this type is legal.
|
||||
virtual bool isTypeLegal(Type *Ty) const;
|
||||
bool isTypeLegal(Type *Ty) const;
|
||||
|
||||
/// \brief Returns the target's jmp_buf alignment in bytes.
|
||||
virtual unsigned getJumpBufAlignment() const;
|
||||
unsigned getJumpBufAlignment() const;
|
||||
|
||||
/// \brief Returns the target's jmp_buf size in bytes.
|
||||
virtual unsigned getJumpBufSize() const;
|
||||
unsigned getJumpBufSize() const;
|
||||
|
||||
/// \brief Return true if switches should be turned into lookup tables for the
|
||||
/// target.
|
||||
virtual bool shouldBuildLookupTables() const;
|
||||
bool shouldBuildLookupTables() const;
|
||||
|
||||
/// \brief Don't restrict interleaved unrolling to small loops.
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) const;
|
||||
|
||||
/// \brief Return hardware support for population count.
|
||||
virtual PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) const;
|
||||
PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) const;
|
||||
|
||||
/// \brief Return true if the hardware has a fast square-root instruction.
|
||||
virtual bool haveFastSqrt(Type *Ty) const;
|
||||
bool haveFastSqrt(Type *Ty) const;
|
||||
|
||||
/// \brief Return the expected cost of supporting the floating point operation
|
||||
/// of the specified type.
|
||||
unsigned getFPOpCost(Type *Ty) const;
|
||||
|
||||
/// \brief Return the expected cost of materializing for the given integer
|
||||
/// immediate of the specified type.
|
||||
virtual unsigned getIntImmCost(const APInt &Imm, Type *Ty) const;
|
||||
unsigned getIntImmCost(const APInt &Imm, Type *Ty) const;
|
||||
|
||||
/// \brief Return the expected cost of materialization for the given integer
|
||||
/// immediate of the specified type for a given instruction. The cost can be
|
||||
/// zero if the immediate can be folded into the specified instruction.
|
||||
virtual unsigned getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) const;
|
||||
virtual unsigned getIntImmCost(Intrinsic::ID IID, unsigned Idx,
|
||||
const APInt &Imm, Type *Ty) const;
|
||||
unsigned getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) const;
|
||||
unsigned getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) const;
|
||||
/// @}
|
||||
|
||||
/// \name Vector Target Information
|
||||
@ -338,10 +383,10 @@ class TargetTransformInfo {
|
||||
|
||||
/// \brief Additional information about an operand's possible values.
|
||||
enum OperandValueKind {
|
||||
OK_AnyValue, // Operand can have any value.
|
||||
OK_UniformValue, // Operand is uniform (splat of a value).
|
||||
OK_UniformConstantValue, // Operand is uniform constant.
|
||||
OK_NonUniformConstantValue // Operand is a non uniform constant value.
|
||||
OK_AnyValue, // Operand can have any value.
|
||||
OK_UniformValue, // Operand is uniform (splat of a value).
|
||||
OK_UniformConstantValue, // Operand is uniform constant.
|
||||
OK_NonUniformConstantValue // Operand is a non uniform constant value.
|
||||
};
|
||||
|
||||
/// \brief Additional properties of an operand's values.
|
||||
@ -350,18 +395,18 @@ class TargetTransformInfo {
|
||||
/// \return The number of scalar or vector registers that the target has.
|
||||
/// If 'Vectors' is true, it returns the number of vector registers. If it is
|
||||
/// set to false, it returns the number of scalar registers.
|
||||
virtual unsigned getNumberOfRegisters(bool Vector) const;
|
||||
unsigned getNumberOfRegisters(bool Vector) const;
|
||||
|
||||
/// \return The width of the largest scalar or vector register type.
|
||||
virtual unsigned getRegisterBitWidth(bool Vector) const;
|
||||
unsigned getRegisterBitWidth(bool Vector) const;
|
||||
|
||||
/// \return The maximum interleave factor that any transform should try to
|
||||
/// perform for this target. This number depends on the level of parallelism
|
||||
/// and the number of execution units in the CPU.
|
||||
virtual unsigned getMaxInterleaveFactor() const;
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) const;
|
||||
|
||||
/// \return The expected cost of arithmetic ops, such as mul, xor, fsub, etc.
|
||||
virtual unsigned
|
||||
unsigned
|
||||
getArithmeticInstrCost(unsigned Opcode, Type *Ty,
|
||||
OperandValueKind Opd1Info = OK_AnyValue,
|
||||
OperandValueKind Opd2Info = OK_AnyValue,
|
||||
@ -371,31 +416,33 @@ class TargetTransformInfo {
|
||||
/// \return The cost of a shuffle instruction of kind Kind and of type Tp.
|
||||
/// The index and subtype parameters are used by the subvector insertion and
|
||||
/// extraction shuffle kinds.
|
||||
virtual unsigned getShuffleCost(ShuffleKind Kind, Type *Tp, int Index = 0,
|
||||
Type *SubTp = nullptr) const;
|
||||
unsigned getShuffleCost(ShuffleKind Kind, Type *Tp, int Index = 0,
|
||||
Type *SubTp = nullptr) const;
|
||||
|
||||
/// \return The expected cost of cast instructions, such as bitcast, trunc,
|
||||
/// zext, etc.
|
||||
virtual unsigned getCastInstrCost(unsigned Opcode, Type *Dst,
|
||||
Type *Src) const;
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) const;
|
||||
|
||||
/// \return The expected cost of control-flow related instructions such as
|
||||
/// Phi, Ret, Br.
|
||||
virtual unsigned getCFInstrCost(unsigned Opcode) const;
|
||||
unsigned getCFInstrCost(unsigned Opcode) const;
|
||||
|
||||
/// \returns The expected cost of compare and select instructions.
|
||||
virtual unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
|
||||
Type *CondTy = nullptr) const;
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
|
||||
Type *CondTy = nullptr) const;
|
||||
|
||||
/// \return The expected cost of vector Insert and Extract.
|
||||
/// Use -1 to indicate that there is no information on the index value.
|
||||
virtual unsigned getVectorInstrCost(unsigned Opcode, Type *Val,
|
||||
unsigned Index = -1) const;
|
||||
unsigned getVectorInstrCost(unsigned Opcode, Type *Val,
|
||||
unsigned Index = -1) const;
|
||||
|
||||
/// \return The cost of Load and Store instructions.
|
||||
virtual unsigned getMemoryOpCost(unsigned Opcode, Type *Src,
|
||||
unsigned Alignment,
|
||||
unsigned AddressSpace) const;
|
||||
unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) const;
|
||||
|
||||
/// \return The cost of masked Load and Store instructions.
|
||||
unsigned getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) const;
|
||||
|
||||
/// \brief Calculate the cost of performing a vector reduction.
|
||||
///
|
||||
@ -410,16 +457,20 @@ class TargetTransformInfo {
|
||||
/// Split:
|
||||
/// (v0, v1, v2, v3)
|
||||
/// ((v0+v2), (v1+v3), undef, undef)
|
||||
virtual unsigned getReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) const;
|
||||
unsigned getReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) const;
|
||||
|
||||
/// \returns The cost of Intrinsic instructions.
|
||||
virtual unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) const;
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) const;
|
||||
|
||||
/// \returns The cost of Call instructions.
|
||||
unsigned getCallInstrCost(Function *F, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) const;
|
||||
|
||||
/// \returns The number of pieces into which the provided type must be
|
||||
/// split during legalization. Zero is returned when the answer is unknown.
|
||||
virtual unsigned getNumberOfParts(Type *Tp) const;
|
||||
unsigned getNumberOfParts(Type *Tp) const;
|
||||
|
||||
/// \returns The cost of the address computation. For most targets this can be
|
||||
/// merged into the instruction indexing mode. Some targets might want to
|
||||
@ -428,28 +479,399 @@ class TargetTransformInfo {
|
||||
/// The 'IsComplex' parameter is a hint that the address computation is likely
|
||||
/// to involve multiple instructions and as such unlikely to be merged into
|
||||
/// the address indexing mode.
|
||||
virtual unsigned getAddressComputationCost(Type *Ty,
|
||||
bool IsComplex = false) const;
|
||||
unsigned getAddressComputationCost(Type *Ty, bool IsComplex = false) const;
|
||||
|
||||
/// \returns The cost, if any, of keeping values of the given types alive
|
||||
/// over a callsite.
|
||||
///
|
||||
/// Some types may require the use of register classes that do not have
|
||||
/// any callee-saved registers, so would require a spill and fill.
|
||||
virtual unsigned getCostOfKeepingLiveOverCall(ArrayRef<Type*> Tys) const;
|
||||
unsigned getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) const;
|
||||
|
||||
/// \returns True if the intrinsic is a supported memory intrinsic. Info
|
||||
/// will contain additional information - whether the intrinsic may write
|
||||
/// or read to memory, volatility and the pointer. Info is undefined
|
||||
/// if false is returned.
|
||||
bool getTgtMemIntrinsic(IntrinsicInst *Inst, MemIntrinsicInfo &Info) const;
|
||||
|
||||
/// \returns A value which is the result of the given memory intrinsic. New
|
||||
/// instructions may be created to extract the result from the given intrinsic
|
||||
/// memory operation. Returns nullptr if the target cannot create a result
|
||||
/// from the given intrinsic.
|
||||
Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
|
||||
Type *ExpectedType) const;
|
||||
|
||||
/// @}
|
||||
|
||||
/// Analysis group identification.
|
||||
static char ID;
|
||||
private:
|
||||
/// \brief The abstract base class used to type erase specific TTI
|
||||
/// implementations.
|
||||
class Concept;
|
||||
|
||||
/// \brief The template model for the base class which wraps a concrete
|
||||
/// implementation in a type erased interface.
|
||||
template <typename T> class Model;
|
||||
|
||||
std::unique_ptr<Concept> TTIImpl;
|
||||
};
|
||||
|
||||
/// \brief Create the base case instance of a pass in the TTI analysis group.
|
||||
class TargetTransformInfo::Concept {
|
||||
public:
|
||||
virtual ~Concept() = 0;
|
||||
|
||||
virtual unsigned getOperationCost(unsigned Opcode, Type *Ty, Type *OpTy) = 0;
|
||||
virtual unsigned getGEPCost(const Value *Ptr,
|
||||
ArrayRef<const Value *> Operands) = 0;
|
||||
virtual unsigned getCallCost(FunctionType *FTy, int NumArgs) = 0;
|
||||
virtual unsigned getCallCost(const Function *F, int NumArgs) = 0;
|
||||
virtual unsigned getCallCost(const Function *F,
|
||||
ArrayRef<const Value *> Arguments) = 0;
|
||||
virtual unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> ParamTys) = 0;
|
||||
virtual unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<const Value *> Arguments) = 0;
|
||||
virtual unsigned getUserCost(const User *U) = 0;
|
||||
virtual bool hasBranchDivergence() = 0;
|
||||
virtual bool isSourceOfDivergence(const Value *V) = 0;
|
||||
virtual bool isLoweredToCall(const Function *F) = 0;
|
||||
virtual void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) = 0;
|
||||
virtual bool isLegalAddImmediate(int64_t Imm) = 0;
|
||||
virtual bool isLegalICmpImmediate(int64_t Imm) = 0;
|
||||
virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
|
||||
int64_t BaseOffset, bool HasBaseReg,
|
||||
int64_t Scale) = 0;
|
||||
virtual bool isLegalMaskedStore(Type *DataType, int Consecutive) = 0;
|
||||
virtual bool isLegalMaskedLoad(Type *DataType, int Consecutive) = 0;
|
||||
virtual int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
|
||||
int64_t BaseOffset, bool HasBaseReg,
|
||||
int64_t Scale) = 0;
|
||||
virtual bool isTruncateFree(Type *Ty1, Type *Ty2) = 0;
|
||||
virtual bool isProfitableToHoist(Instruction *I) = 0;
|
||||
virtual bool isTypeLegal(Type *Ty) = 0;
|
||||
virtual unsigned getJumpBufAlignment() = 0;
|
||||
virtual unsigned getJumpBufSize() = 0;
|
||||
virtual bool shouldBuildLookupTables() = 0;
|
||||
virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0;
|
||||
virtual PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) = 0;
|
||||
virtual bool haveFastSqrt(Type *Ty) = 0;
|
||||
virtual unsigned getFPOpCost(Type *Ty) = 0;
|
||||
virtual unsigned getIntImmCost(const APInt &Imm, Type *Ty) = 0;
|
||||
virtual unsigned getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) = 0;
|
||||
virtual unsigned getIntImmCost(Intrinsic::ID IID, unsigned Idx,
|
||||
const APInt &Imm, Type *Ty) = 0;
|
||||
virtual unsigned getNumberOfRegisters(bool Vector) = 0;
|
||||
virtual unsigned getRegisterBitWidth(bool Vector) = 0;
|
||||
virtual unsigned getMaxInterleaveFactor(unsigned VF) = 0;
|
||||
virtual unsigned
|
||||
getArithmeticInstrCost(unsigned Opcode, Type *Ty, OperandValueKind Opd1Info,
|
||||
OperandValueKind Opd2Info,
|
||||
OperandValueProperties Opd1PropInfo,
|
||||
OperandValueProperties Opd2PropInfo) = 0;
|
||||
virtual unsigned getShuffleCost(ShuffleKind Kind, Type *Tp, int Index,
|
||||
Type *SubTp) = 0;
|
||||
virtual unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) = 0;
|
||||
virtual unsigned getCFInstrCost(unsigned Opcode) = 0;
|
||||
virtual unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
|
||||
Type *CondTy) = 0;
|
||||
virtual unsigned getVectorInstrCost(unsigned Opcode, Type *Val,
|
||||
unsigned Index) = 0;
|
||||
virtual unsigned getMemoryOpCost(unsigned Opcode, Type *Src,
|
||||
unsigned Alignment,
|
||||
unsigned AddressSpace) = 0;
|
||||
virtual unsigned getMaskedMemoryOpCost(unsigned Opcode, Type *Src,
|
||||
unsigned Alignment,
|
||||
unsigned AddressSpace) = 0;
|
||||
virtual unsigned getReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) = 0;
|
||||
virtual unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) = 0;
|
||||
virtual unsigned getCallInstrCost(Function *F, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) = 0;
|
||||
virtual unsigned getNumberOfParts(Type *Tp) = 0;
|
||||
virtual unsigned getAddressComputationCost(Type *Ty, bool IsComplex) = 0;
|
||||
virtual unsigned getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) = 0;
|
||||
virtual bool getTgtMemIntrinsic(IntrinsicInst *Inst,
|
||||
MemIntrinsicInfo &Info) = 0;
|
||||
virtual Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
|
||||
Type *ExpectedType) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
T Impl;
|
||||
|
||||
public:
|
||||
Model(T Impl) : Impl(std::move(Impl)) {}
|
||||
~Model() override {}
|
||||
|
||||
unsigned getOperationCost(unsigned Opcode, Type *Ty, Type *OpTy) override {
|
||||
return Impl.getOperationCost(Opcode, Ty, OpTy);
|
||||
}
|
||||
unsigned getGEPCost(const Value *Ptr,
|
||||
ArrayRef<const Value *> Operands) override {
|
||||
return Impl.getGEPCost(Ptr, Operands);
|
||||
}
|
||||
unsigned getCallCost(FunctionType *FTy, int NumArgs) override {
|
||||
return Impl.getCallCost(FTy, NumArgs);
|
||||
}
|
||||
unsigned getCallCost(const Function *F, int NumArgs) override {
|
||||
return Impl.getCallCost(F, NumArgs);
|
||||
}
|
||||
unsigned getCallCost(const Function *F,
|
||||
ArrayRef<const Value *> Arguments) override {
|
||||
return Impl.getCallCost(F, Arguments);
|
||||
}
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> ParamTys) override {
|
||||
return Impl.getIntrinsicCost(IID, RetTy, ParamTys);
|
||||
}
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<const Value *> Arguments) override {
|
||||
return Impl.getIntrinsicCost(IID, RetTy, Arguments);
|
||||
}
|
||||
unsigned getUserCost(const User *U) override { return Impl.getUserCost(U); }
|
||||
bool hasBranchDivergence() override { return Impl.hasBranchDivergence(); }
|
||||
bool isSourceOfDivergence(const Value *V) override {
|
||||
return Impl.isSourceOfDivergence(V);
|
||||
}
|
||||
bool isLoweredToCall(const Function *F) override {
|
||||
return Impl.isLoweredToCall(F);
|
||||
}
|
||||
void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) override {
|
||||
return Impl.getUnrollingPreferences(L, UP);
|
||||
}
|
||||
bool isLegalAddImmediate(int64_t Imm) override {
|
||||
return Impl.isLegalAddImmediate(Imm);
|
||||
}
|
||||
bool isLegalICmpImmediate(int64_t Imm) override {
|
||||
return Impl.isLegalICmpImmediate(Imm);
|
||||
}
|
||||
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) override {
|
||||
return Impl.isLegalAddressingMode(Ty, BaseGV, BaseOffset, HasBaseReg,
|
||||
Scale);
|
||||
}
|
||||
bool isLegalMaskedStore(Type *DataType, int Consecutive) override {
|
||||
return Impl.isLegalMaskedStore(DataType, Consecutive);
|
||||
}
|
||||
bool isLegalMaskedLoad(Type *DataType, int Consecutive) override {
|
||||
return Impl.isLegalMaskedLoad(DataType, Consecutive);
|
||||
}
|
||||
int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) override {
|
||||
return Impl.getScalingFactorCost(Ty, BaseGV, BaseOffset, HasBaseReg, Scale);
|
||||
}
|
||||
bool isTruncateFree(Type *Ty1, Type *Ty2) override {
|
||||
return Impl.isTruncateFree(Ty1, Ty2);
|
||||
}
|
||||
bool isProfitableToHoist(Instruction *I) override {
|
||||
return Impl.isProfitableToHoist(I);
|
||||
}
|
||||
bool isTypeLegal(Type *Ty) override { return Impl.isTypeLegal(Ty); }
|
||||
unsigned getJumpBufAlignment() override { return Impl.getJumpBufAlignment(); }
|
||||
unsigned getJumpBufSize() override { return Impl.getJumpBufSize(); }
|
||||
bool shouldBuildLookupTables() override {
|
||||
return Impl.shouldBuildLookupTables();
|
||||
}
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) override {
|
||||
return Impl.enableAggressiveInterleaving(LoopHasReductions);
|
||||
}
|
||||
PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) override {
|
||||
return Impl.getPopcntSupport(IntTyWidthInBit);
|
||||
}
|
||||
bool haveFastSqrt(Type *Ty) override { return Impl.haveFastSqrt(Ty); }
|
||||
|
||||
unsigned getFPOpCost(Type *Ty) override {
|
||||
return Impl.getFPOpCost(Ty);
|
||||
}
|
||||
|
||||
unsigned getIntImmCost(const APInt &Imm, Type *Ty) override {
|
||||
return Impl.getIntImmCost(Imm, Ty);
|
||||
}
|
||||
unsigned getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) override {
|
||||
return Impl.getIntImmCost(Opc, Idx, Imm, Ty);
|
||||
}
|
||||
unsigned getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) override {
|
||||
return Impl.getIntImmCost(IID, Idx, Imm, Ty);
|
||||
}
|
||||
unsigned getNumberOfRegisters(bool Vector) override {
|
||||
return Impl.getNumberOfRegisters(Vector);
|
||||
}
|
||||
unsigned getRegisterBitWidth(bool Vector) override {
|
||||
return Impl.getRegisterBitWidth(Vector);
|
||||
}
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) override {
|
||||
return Impl.getMaxInterleaveFactor(VF);
|
||||
}
|
||||
unsigned
|
||||
getArithmeticInstrCost(unsigned Opcode, Type *Ty, OperandValueKind Opd1Info,
|
||||
OperandValueKind Opd2Info,
|
||||
OperandValueProperties Opd1PropInfo,
|
||||
OperandValueProperties Opd2PropInfo) override {
|
||||
return Impl.getArithmeticInstrCost(Opcode, Ty, Opd1Info, Opd2Info,
|
||||
Opd1PropInfo, Opd2PropInfo);
|
||||
}
|
||||
unsigned getShuffleCost(ShuffleKind Kind, Type *Tp, int Index,
|
||||
Type *SubTp) override {
|
||||
return Impl.getShuffleCost(Kind, Tp, Index, SubTp);
|
||||
}
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) override {
|
||||
return Impl.getCastInstrCost(Opcode, Dst, Src);
|
||||
}
|
||||
unsigned getCFInstrCost(unsigned Opcode) override {
|
||||
return Impl.getCFInstrCost(Opcode);
|
||||
}
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
|
||||
Type *CondTy) override {
|
||||
return Impl.getCmpSelInstrCost(Opcode, ValTy, CondTy);
|
||||
}
|
||||
unsigned getVectorInstrCost(unsigned Opcode, Type *Val,
|
||||
unsigned Index) override {
|
||||
return Impl.getVectorInstrCost(Opcode, Val, Index);
|
||||
}
|
||||
unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) override {
|
||||
return Impl.getMemoryOpCost(Opcode, Src, Alignment, AddressSpace);
|
||||
}
|
||||
unsigned getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) override {
|
||||
return Impl.getMaskedMemoryOpCost(Opcode, Src, Alignment, AddressSpace);
|
||||
}
|
||||
unsigned getReductionCost(unsigned Opcode, Type *Ty,
|
||||
bool IsPairwiseForm) override {
|
||||
return Impl.getReductionCost(Opcode, Ty, IsPairwiseForm);
|
||||
}
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) override {
|
||||
return Impl.getIntrinsicInstrCost(ID, RetTy, Tys);
|
||||
}
|
||||
unsigned getCallInstrCost(Function *F, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) override {
|
||||
return Impl.getCallInstrCost(F, RetTy, Tys);
|
||||
}
|
||||
unsigned getNumberOfParts(Type *Tp) override {
|
||||
return Impl.getNumberOfParts(Tp);
|
||||
}
|
||||
unsigned getAddressComputationCost(Type *Ty, bool IsComplex) override {
|
||||
return Impl.getAddressComputationCost(Ty, IsComplex);
|
||||
}
|
||||
unsigned getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) override {
|
||||
return Impl.getCostOfKeepingLiveOverCall(Tys);
|
||||
}
|
||||
bool getTgtMemIntrinsic(IntrinsicInst *Inst,
|
||||
MemIntrinsicInfo &Info) override {
|
||||
return Impl.getTgtMemIntrinsic(Inst, Info);
|
||||
}
|
||||
Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
|
||||
Type *ExpectedType) override {
|
||||
return Impl.getOrCreateResultFromMemIntrinsic(Inst, ExpectedType);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
TargetTransformInfo::TargetTransformInfo(T Impl)
|
||||
: TTIImpl(new Model<T>(Impl)) {}
|
||||
|
||||
/// \brief Analysis pass providing the \c TargetTransformInfo.
|
||||
///
|
||||
/// This class provides the base case for the stack of TTI analyzes. It doesn't
|
||||
/// delegate to anything and uses the STTI and VTTI objects passed in to
|
||||
/// satisfy the queries.
|
||||
ImmutablePass *createNoTargetTransformInfoPass();
|
||||
/// The core idea of the TargetIRAnalysis is to expose an interface through
|
||||
/// which LLVM targets can analyze and provide information about the middle
|
||||
/// end's target-independent IR. This supports use cases such as target-aware
|
||||
/// cost modeling of IR constructs.
|
||||
///
|
||||
/// This is a function analysis because much of the cost modeling for targets
|
||||
/// is done in a subtarget specific way and LLVM supports compiling different
|
||||
/// functions targeting different subtargets in order to support runtime
|
||||
/// dispatch according to the observed subtarget.
|
||||
class TargetIRAnalysis {
|
||||
public:
|
||||
typedef TargetTransformInfo Result;
|
||||
|
||||
/// \brief Opaque, unique identifier for this analysis pass.
|
||||
static void *ID() { return (void *)&PassID; }
|
||||
|
||||
/// \brief Provide access to a name for this pass for debugging purposes.
|
||||
static StringRef name() { return "TargetIRAnalysis"; }
|
||||
|
||||
/// \brief Default construct a target IR analysis.
|
||||
///
|
||||
/// This will use the module's datalayout to construct a baseline
|
||||
/// conservative TTI result.
|
||||
TargetIRAnalysis();
|
||||
|
||||
/// \brief Construct an IR analysis pass around a target-provide callback.
|
||||
///
|
||||
/// The callback will be called with a particular function for which the TTI
|
||||
/// is needed and must return a TTI object for that function.
|
||||
TargetIRAnalysis(std::function<Result(Function &)> TTICallback);
|
||||
|
||||
// Value semantics. We spell out the constructors for MSVC.
|
||||
TargetIRAnalysis(const TargetIRAnalysis &Arg)
|
||||
: TTICallback(Arg.TTICallback) {}
|
||||
TargetIRAnalysis(TargetIRAnalysis &&Arg)
|
||||
: TTICallback(std::move(Arg.TTICallback)) {}
|
||||
TargetIRAnalysis &operator=(const TargetIRAnalysis &RHS) {
|
||||
TTICallback = RHS.TTICallback;
|
||||
return *this;
|
||||
}
|
||||
TargetIRAnalysis &operator=(TargetIRAnalysis &&RHS) {
|
||||
TTICallback = std::move(RHS.TTICallback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Result run(Function &F);
|
||||
|
||||
private:
|
||||
static char PassID;
|
||||
|
||||
/// \brief The callback used to produce a result.
|
||||
///
|
||||
/// We use a completely opaque callback so that targets can provide whatever
|
||||
/// mechanism they desire for constructing the TTI for a given function.
|
||||
///
|
||||
/// FIXME: Should we really use std::function? It's relatively inefficient.
|
||||
/// It might be possible to arrange for even stateful callbacks to outlive
|
||||
/// the analysis and thus use a function_ref which would be lighter weight.
|
||||
/// This may also be less error prone as the callback is likely to reference
|
||||
/// the external TargetMachine, and that reference needs to never dangle.
|
||||
std::function<Result(Function &)> TTICallback;
|
||||
|
||||
/// \brief Helper function used as the callback in the default constructor.
|
||||
static Result getDefaultTTI(Function &F);
|
||||
};
|
||||
|
||||
/// \brief Wrapper pass for TargetTransformInfo.
|
||||
///
|
||||
/// This pass can be constructed from a TTI object which it stores internally
|
||||
/// and is queried by passes.
|
||||
class TargetTransformInfoWrapperPass : public ImmutablePass {
|
||||
TargetIRAnalysis TIRA;
|
||||
Optional<TargetTransformInfo> TTI;
|
||||
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
/// \brief We must provide a default constructor for the pass but it should
|
||||
/// never be used.
|
||||
///
|
||||
/// Use the constructor below or call one of the creation routines.
|
||||
TargetTransformInfoWrapperPass();
|
||||
|
||||
explicit TargetTransformInfoWrapperPass(TargetIRAnalysis TIRA);
|
||||
|
||||
TargetTransformInfo &getTTI(Function &F);
|
||||
};
|
||||
|
||||
/// \brief Create an analysis pass wrapper around a TTI object.
|
||||
///
|
||||
/// This analysis pass just holds the TTI instance and makes it available to
|
||||
/// clients.
|
||||
ImmutablePass *createTargetTransformInfoWrapperPass(TargetIRAnalysis TIRA);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
441
contrib/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
Normal file
441
contrib/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
Normal file
@ -0,0 +1,441 @@
|
||||
//===- TargetTransformInfoImpl.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file provides helpers for the implementation of
|
||||
/// a TargetTransformInfo-conforming class.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_TARGETTRANSFORMINFOIMPL_H
|
||||
#define LLVM_ANALYSIS_TARGETTRANSFORMINFOIMPL_H
|
||||
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief Base class for use as a mix-in that aids implementing
|
||||
/// a TargetTransformInfo-compatible class.
|
||||
class TargetTransformInfoImplBase {
|
||||
protected:
|
||||
typedef TargetTransformInfo TTI;
|
||||
|
||||
const DataLayout *DL;
|
||||
|
||||
explicit TargetTransformInfoImplBase(const DataLayout *DL)
|
||||
: DL(DL) {}
|
||||
|
||||
public:
|
||||
// Provide value semantics. MSVC requires that we spell all of these out.
|
||||
TargetTransformInfoImplBase(const TargetTransformInfoImplBase &Arg)
|
||||
: DL(Arg.DL) {}
|
||||
TargetTransformInfoImplBase(TargetTransformInfoImplBase &&Arg)
|
||||
: DL(std::move(Arg.DL)) {}
|
||||
TargetTransformInfoImplBase &
|
||||
operator=(const TargetTransformInfoImplBase &RHS) {
|
||||
DL = RHS.DL;
|
||||
return *this;
|
||||
}
|
||||
TargetTransformInfoImplBase &operator=(TargetTransformInfoImplBase &&RHS) {
|
||||
DL = std::move(RHS.DL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned getOperationCost(unsigned Opcode, Type *Ty, Type *OpTy) {
|
||||
switch (Opcode) {
|
||||
default:
|
||||
// By default, just classify everything as 'basic'.
|
||||
return TTI::TCC_Basic;
|
||||
|
||||
case Instruction::GetElementPtr:
|
||||
llvm_unreachable("Use getGEPCost for GEP operations!");
|
||||
|
||||
case Instruction::BitCast:
|
||||
assert(OpTy && "Cast instructions must provide the operand type");
|
||||
if (Ty == OpTy || (Ty->isPointerTy() && OpTy->isPointerTy()))
|
||||
// Identity and pointer-to-pointer casts are free.
|
||||
return TTI::TCC_Free;
|
||||
|
||||
// Otherwise, the default basic cost is used.
|
||||
return TTI::TCC_Basic;
|
||||
|
||||
case Instruction::IntToPtr: {
|
||||
if (!DL)
|
||||
return TTI::TCC_Basic;
|
||||
|
||||
// An inttoptr cast is free so long as the input is a legal integer type
|
||||
// which doesn't contain values outside the range of a pointer.
|
||||
unsigned OpSize = OpTy->getScalarSizeInBits();
|
||||
if (DL->isLegalInteger(OpSize) &&
|
||||
OpSize <= DL->getPointerTypeSizeInBits(Ty))
|
||||
return TTI::TCC_Free;
|
||||
|
||||
// Otherwise it's not a no-op.
|
||||
return TTI::TCC_Basic;
|
||||
}
|
||||
case Instruction::PtrToInt: {
|
||||
if (!DL)
|
||||
return TTI::TCC_Basic;
|
||||
|
||||
// A ptrtoint cast is free so long as the result is large enough to store
|
||||
// the pointer, and a legal integer type.
|
||||
unsigned DestSize = Ty->getScalarSizeInBits();
|
||||
if (DL->isLegalInteger(DestSize) &&
|
||||
DestSize >= DL->getPointerTypeSizeInBits(OpTy))
|
||||
return TTI::TCC_Free;
|
||||
|
||||
// Otherwise it's not a no-op.
|
||||
return TTI::TCC_Basic;
|
||||
}
|
||||
case Instruction::Trunc:
|
||||
// trunc to a native type is free (assuming the target has compare and
|
||||
// shift-right of the same width).
|
||||
if (DL && DL->isLegalInteger(DL->getTypeSizeInBits(Ty)))
|
||||
return TTI::TCC_Free;
|
||||
|
||||
return TTI::TCC_Basic;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getGEPCost(const Value *Ptr, ArrayRef<const Value *> Operands) {
|
||||
// In the basic model, we just assume that all-constant GEPs will be folded
|
||||
// into their uses via addressing modes.
|
||||
for (unsigned Idx = 0, Size = Operands.size(); Idx != Size; ++Idx)
|
||||
if (!isa<Constant>(Operands[Idx]))
|
||||
return TTI::TCC_Basic;
|
||||
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
|
||||
unsigned getCallCost(FunctionType *FTy, int NumArgs) {
|
||||
assert(FTy && "FunctionType must be provided to this routine.");
|
||||
|
||||
// The target-independent implementation just measures the size of the
|
||||
// function by approximating that each argument will take on average one
|
||||
// instruction to prepare.
|
||||
|
||||
if (NumArgs < 0)
|
||||
// Set the argument number to the number of explicit arguments in the
|
||||
// function.
|
||||
NumArgs = FTy->getNumParams();
|
||||
|
||||
return TTI::TCC_Basic * (NumArgs + 1);
|
||||
}
|
||||
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> ParamTys) {
|
||||
switch (IID) {
|
||||
default:
|
||||
// Intrinsics rarely (if ever) have normal argument setup constraints.
|
||||
// Model them as having a basic instruction cost.
|
||||
// FIXME: This is wrong for libc intrinsics.
|
||||
return TTI::TCC_Basic;
|
||||
|
||||
case Intrinsic::annotation:
|
||||
case Intrinsic::assume:
|
||||
case Intrinsic::dbg_declare:
|
||||
case Intrinsic::dbg_value:
|
||||
case Intrinsic::invariant_start:
|
||||
case Intrinsic::invariant_end:
|
||||
case Intrinsic::lifetime_start:
|
||||
case Intrinsic::lifetime_end:
|
||||
case Intrinsic::objectsize:
|
||||
case Intrinsic::ptr_annotation:
|
||||
case Intrinsic::var_annotation:
|
||||
case Intrinsic::experimental_gc_result_int:
|
||||
case Intrinsic::experimental_gc_result_float:
|
||||
case Intrinsic::experimental_gc_result_ptr:
|
||||
case Intrinsic::experimental_gc_result:
|
||||
case Intrinsic::experimental_gc_relocate:
|
||||
// These intrinsics don't actually represent code after lowering.
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasBranchDivergence() { return false; }
|
||||
|
||||
bool isSourceOfDivergence(const Value *V) { return false; }
|
||||
|
||||
bool isLoweredToCall(const Function *F) {
|
||||
// FIXME: These should almost certainly not be handled here, and instead
|
||||
// handled with the help of TLI or the target itself. This was largely
|
||||
// ported from existing analysis heuristics here so that such refactorings
|
||||
// can take place in the future.
|
||||
|
||||
if (F->isIntrinsic())
|
||||
return false;
|
||||
|
||||
if (F->hasLocalLinkage() || !F->hasName())
|
||||
return true;
|
||||
|
||||
StringRef Name = F->getName();
|
||||
|
||||
// These will all likely lower to a single selection DAG node.
|
||||
if (Name == "copysign" || Name == "copysignf" || Name == "copysignl" ||
|
||||
Name == "fabs" || Name == "fabsf" || Name == "fabsl" || Name == "sin" ||
|
||||
Name == "fmin" || Name == "fminf" || Name == "fminl" ||
|
||||
Name == "fmax" || Name == "fmaxf" || Name == "fmaxl" ||
|
||||
Name == "sinf" || Name == "sinl" || Name == "cos" || Name == "cosf" ||
|
||||
Name == "cosl" || Name == "sqrt" || Name == "sqrtf" || Name == "sqrtl")
|
||||
return false;
|
||||
|
||||
// These are all likely to be optimized into something smaller.
|
||||
if (Name == "pow" || Name == "powf" || Name == "powl" || Name == "exp2" ||
|
||||
Name == "exp2l" || Name == "exp2f" || Name == "floor" ||
|
||||
Name == "floorf" || Name == "ceil" || Name == "round" ||
|
||||
Name == "ffs" || Name == "ffsl" || Name == "abs" || Name == "labs" ||
|
||||
Name == "llabs")
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void getUnrollingPreferences(Loop *, TTI::UnrollingPreferences &) {}
|
||||
|
||||
bool isLegalAddImmediate(int64_t Imm) { return false; }
|
||||
|
||||
bool isLegalICmpImmediate(int64_t Imm) { return false; }
|
||||
|
||||
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) {
|
||||
// Guess that only reg and reg+reg addressing is allowed. This heuristic is
|
||||
// taken from the implementation of LSR.
|
||||
return !BaseGV && BaseOffset == 0 && (Scale == 0 || Scale == 1);
|
||||
}
|
||||
|
||||
bool isLegalMaskedStore(Type *DataType, int Consecutive) { return false; }
|
||||
|
||||
bool isLegalMaskedLoad(Type *DataType, int Consecutive) { return false; }
|
||||
|
||||
int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) {
|
||||
// Guess that all legal addressing mode are free.
|
||||
if (isLegalAddressingMode(Ty, BaseGV, BaseOffset, HasBaseReg, Scale))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool isTruncateFree(Type *Ty1, Type *Ty2) { return false; }
|
||||
|
||||
bool isProfitableToHoist(Instruction *I) { return true; }
|
||||
|
||||
bool isTypeLegal(Type *Ty) { return false; }
|
||||
|
||||
unsigned getJumpBufAlignment() { return 0; }
|
||||
|
||||
unsigned getJumpBufSize() { return 0; }
|
||||
|
||||
bool shouldBuildLookupTables() { return true; }
|
||||
|
||||
bool enableAggressiveInterleaving(bool LoopHasReductions) { return false; }
|
||||
|
||||
TTI::PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) {
|
||||
return TTI::PSK_Software;
|
||||
}
|
||||
|
||||
bool haveFastSqrt(Type *Ty) { return false; }
|
||||
|
||||
unsigned getFPOpCost(Type *Ty) { return TargetTransformInfo::TCC_Basic; }
|
||||
|
||||
unsigned getIntImmCost(const APInt &Imm, Type *Ty) { return TTI::TCC_Basic; }
|
||||
|
||||
unsigned getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) {
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
|
||||
unsigned getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) {
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
|
||||
unsigned getNumberOfRegisters(bool Vector) { return 8; }
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) { return 32; }
|
||||
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) { return 1; }
|
||||
|
||||
unsigned getArithmeticInstrCost(unsigned Opcode, Type *Ty,
|
||||
TTI::OperandValueKind Opd1Info,
|
||||
TTI::OperandValueKind Opd2Info,
|
||||
TTI::OperandValueProperties Opd1PropInfo,
|
||||
TTI::OperandValueProperties Opd2PropInfo) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getShuffleCost(TTI::ShuffleKind Kind, Type *Ty, int Index,
|
||||
Type *SubTp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { return 1; }
|
||||
|
||||
unsigned getCFInstrCost(unsigned Opcode) { return 1; }
|
||||
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getMaskedMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getNumberOfParts(Type *Tp) { return 0; }
|
||||
|
||||
unsigned getAddressComputationCost(Type *Tp, bool) { return 0; }
|
||||
|
||||
unsigned getReductionCost(unsigned, Type *, bool) { return 1; }
|
||||
|
||||
unsigned getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) { return 0; }
|
||||
|
||||
bool getTgtMemIntrinsic(IntrinsicInst *Inst, MemIntrinsicInfo &Info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
|
||||
Type *ExpectedType) {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief CRTP base class for use as a mix-in that aids implementing
|
||||
/// a TargetTransformInfo-compatible class.
|
||||
template <typename T>
|
||||
class TargetTransformInfoImplCRTPBase : public TargetTransformInfoImplBase {
|
||||
private:
|
||||
typedef TargetTransformInfoImplBase BaseT;
|
||||
|
||||
protected:
|
||||
explicit TargetTransformInfoImplCRTPBase(const DataLayout *DL)
|
||||
: BaseT(DL) {}
|
||||
|
||||
public:
|
||||
// Provide value semantics. MSVC requires that we spell all of these out.
|
||||
TargetTransformInfoImplCRTPBase(const TargetTransformInfoImplCRTPBase &Arg)
|
||||
: BaseT(static_cast<const BaseT &>(Arg)) {}
|
||||
TargetTransformInfoImplCRTPBase(TargetTransformInfoImplCRTPBase &&Arg)
|
||||
: BaseT(std::move(static_cast<BaseT &>(Arg))) {}
|
||||
TargetTransformInfoImplCRTPBase &
|
||||
operator=(const TargetTransformInfoImplCRTPBase &RHS) {
|
||||
BaseT::operator=(static_cast<const BaseT &>(RHS));
|
||||
return *this;
|
||||
}
|
||||
TargetTransformInfoImplCRTPBase &
|
||||
operator=(TargetTransformInfoImplCRTPBase &&RHS) {
|
||||
BaseT::operator=(std::move(static_cast<BaseT &>(RHS)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
using BaseT::getCallCost;
|
||||
|
||||
unsigned getCallCost(const Function *F, int NumArgs) {
|
||||
assert(F && "A concrete function must be provided to this routine.");
|
||||
|
||||
if (NumArgs < 0)
|
||||
// Set the argument number to the number of explicit arguments in the
|
||||
// function.
|
||||
NumArgs = F->arg_size();
|
||||
|
||||
if (Intrinsic::ID IID = F->getIntrinsicID()) {
|
||||
FunctionType *FTy = F->getFunctionType();
|
||||
SmallVector<Type *, 8> ParamTys(FTy->param_begin(), FTy->param_end());
|
||||
return static_cast<T *>(this)
|
||||
->getIntrinsicCost(IID, FTy->getReturnType(), ParamTys);
|
||||
}
|
||||
|
||||
if (!static_cast<T *>(this)->isLoweredToCall(F))
|
||||
return TTI::TCC_Basic; // Give a basic cost if it will be lowered
|
||||
// directly.
|
||||
|
||||
return static_cast<T *>(this)->getCallCost(F->getFunctionType(), NumArgs);
|
||||
}
|
||||
|
||||
unsigned getCallCost(const Function *F, ArrayRef<const Value *> Arguments) {
|
||||
// Simply delegate to generic handling of the call.
|
||||
// FIXME: We should use instsimplify or something else to catch calls which
|
||||
// will constant fold with these arguments.
|
||||
return static_cast<T *>(this)->getCallCost(F, Arguments.size());
|
||||
}
|
||||
|
||||
using BaseT::getIntrinsicCost;
|
||||
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<const Value *> Arguments) {
|
||||
// Delegate to the generic intrinsic handling code. This mostly provides an
|
||||
// opportunity for targets to (for example) special case the cost of
|
||||
// certain intrinsics based on constants used as arguments.
|
||||
SmallVector<Type *, 8> ParamTys;
|
||||
ParamTys.reserve(Arguments.size());
|
||||
for (unsigned Idx = 0, Size = Arguments.size(); Idx != Size; ++Idx)
|
||||
ParamTys.push_back(Arguments[Idx]->getType());
|
||||
return static_cast<T *>(this)->getIntrinsicCost(IID, RetTy, ParamTys);
|
||||
}
|
||||
|
||||
unsigned getUserCost(const User *U) {
|
||||
if (isa<PHINode>(U))
|
||||
return TTI::TCC_Free; // Model all PHI nodes as free.
|
||||
|
||||
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
|
||||
SmallVector<const Value *, 4> Indices(GEP->idx_begin(), GEP->idx_end());
|
||||
return static_cast<T *>(this)
|
||||
->getGEPCost(GEP->getPointerOperand(), Indices);
|
||||
}
|
||||
|
||||
if (auto CS = ImmutableCallSite(U)) {
|
||||
const Function *F = CS.getCalledFunction();
|
||||
if (!F) {
|
||||
// Just use the called value type.
|
||||
Type *FTy = CS.getCalledValue()->getType()->getPointerElementType();
|
||||
return static_cast<T *>(this)
|
||||
->getCallCost(cast<FunctionType>(FTy), CS.arg_size());
|
||||
}
|
||||
|
||||
SmallVector<const Value *, 8> Arguments(CS.arg_begin(), CS.arg_end());
|
||||
return static_cast<T *>(this)->getCallCost(F, Arguments);
|
||||
}
|
||||
|
||||
if (const CastInst *CI = dyn_cast<CastInst>(U)) {
|
||||
// Result of a cmp instruction is often extended (to be used by other
|
||||
// cmp instructions, logical or return instructions). These are usually
|
||||
// nop on most sane targets.
|
||||
if (isa<CmpInst>(CI->getOperand(0)))
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
|
||||
return static_cast<T *>(this)->getOperationCost(
|
||||
Operator::getOpcode(U), U->getType(),
|
||||
U->getNumOperands() == 1 ? U->getOperand(0)->getType() : nullptr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#define LLVM_ANALYSIS_VALUETRACKING_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -28,17 +29,18 @@ namespace llvm {
|
||||
class AssumptionCache;
|
||||
class DominatorTree;
|
||||
class TargetLibraryInfo;
|
||||
class LoopInfo;
|
||||
|
||||
/// Determine which bits of V are known to be either zero or one and return
|
||||
/// them in the KnownZero/KnownOne bit sets.
|
||||
///
|
||||
/// This function is defined on values with integer type, values with pointer
|
||||
/// type (but only if TD is non-null), and vectors of integers. In the case
|
||||
/// type, and vectors of integers. In the case
|
||||
/// where V is a vector, the known zero and known one values are the
|
||||
/// same width as the vector element, and the bit is set only if it is true
|
||||
/// for all of the elements in the vector.
|
||||
void computeKnownBits(Value *V, APInt &KnownZero, APInt &KnownOne,
|
||||
const DataLayout *TD = nullptr, unsigned Depth = 0,
|
||||
const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
@ -46,11 +48,16 @@ namespace llvm {
|
||||
/// \p KnownZero the set of bits that are known to be zero
|
||||
void computeKnownBitsFromRangeMetadata(const MDNode &Ranges,
|
||||
APInt &KnownZero);
|
||||
/// Returns true if LHS and RHS have no common bits set.
|
||||
bool haveNoCommonBitsSet(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// ComputeSignBit - Determine whether the sign bit is known to be zero or
|
||||
/// one. Convenience wrapper around computeKnownBits.
|
||||
void ComputeSignBit(Value *V, bool &KnownZero, bool &KnownOne,
|
||||
const DataLayout *TD = nullptr, unsigned Depth = 0,
|
||||
const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
@ -60,7 +67,8 @@ namespace llvm {
|
||||
/// element is known to be a power of two when defined. Supports values with
|
||||
/// integer or pointer type and vectors of integers. If 'OrZero' is set then
|
||||
/// returns true if the given value is either a power of two or zero.
|
||||
bool isKnownToBeAPowerOfTwo(Value *V, bool OrZero = false, unsigned Depth = 0,
|
||||
bool isKnownToBeAPowerOfTwo(Value *V, const DataLayout &DL,
|
||||
bool OrZero = false, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
@ -69,8 +77,8 @@ namespace llvm {
|
||||
/// when defined. For vectors return true if every element is known to be
|
||||
/// non-zero when defined. Supports values with integer or pointer type and
|
||||
/// vectors of integers.
|
||||
bool isKnownNonZero(Value *V, const DataLayout *TD = nullptr,
|
||||
unsigned Depth = 0, AssumptionCache *AC = nullptr,
|
||||
bool isKnownNonZero(Value *V, const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
@ -79,13 +87,12 @@ namespace llvm {
|
||||
/// zero for bits that V cannot have.
|
||||
///
|
||||
/// This function is defined on values with integer type, values with pointer
|
||||
/// type (but only if TD is non-null), and vectors of integers. In the case
|
||||
/// type, and vectors of integers. In the case
|
||||
/// where V is a vector, the mask, known zero, and known one values are the
|
||||
/// same width as the vector element, and the bit is set only if it is true
|
||||
/// for all of the elements in the vector.
|
||||
bool MaskedValueIsZero(Value *V, const APInt &Mask,
|
||||
const DataLayout *TD = nullptr, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
bool MaskedValueIsZero(Value *V, const APInt &Mask, const DataLayout &DL,
|
||||
unsigned Depth = 0, AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
@ -97,7 +104,7 @@ namespace llvm {
|
||||
///
|
||||
/// 'Op' must have a scalar integer type.
|
||||
///
|
||||
unsigned ComputeNumSignBits(Value *Op, const DataLayout *TD = nullptr,
|
||||
unsigned ComputeNumSignBits(Value *Op, const DataLayout &DL,
|
||||
unsigned Depth = 0, AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
@ -116,6 +123,11 @@ namespace llvm {
|
||||
///
|
||||
bool CannotBeNegativeZero(const Value *V, unsigned Depth = 0);
|
||||
|
||||
/// CannotBeOrderedLessThanZero - Return true if we can prove that the
|
||||
/// specified FP value is either a NaN or never less than 0.0.
|
||||
///
|
||||
bool CannotBeOrderedLessThanZero(const Value *V, unsigned Depth = 0);
|
||||
|
||||
/// isBytewiseValue - If the specified value can be set by repeating the same
|
||||
/// byte in memory, return the i8 value that it is represented with. This is
|
||||
/// true for all i8 values obviously, but is also true for i32 0, i32 -1,
|
||||
@ -137,11 +149,12 @@ namespace llvm {
|
||||
/// it can be expressed as a base pointer plus a constant offset. Return the
|
||||
/// base and offset to the caller.
|
||||
Value *GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset,
|
||||
const DataLayout *TD);
|
||||
const DataLayout &DL);
|
||||
static inline const Value *
|
||||
GetPointerBaseWithConstantOffset(const Value *Ptr, int64_t &Offset,
|
||||
const DataLayout *TD) {
|
||||
return GetPointerBaseWithConstantOffset(const_cast<Value*>(Ptr), Offset,TD);
|
||||
const DataLayout &DL) {
|
||||
return GetPointerBaseWithConstantOffset(const_cast<Value *>(Ptr), Offset,
|
||||
DL);
|
||||
}
|
||||
|
||||
/// getConstantStringInfo - This function computes the length of a
|
||||
@ -162,26 +175,59 @@ namespace llvm {
|
||||
/// being addressed. Note that the returned value has pointer type if the
|
||||
/// specified value does. If the MaxLookup value is non-zero, it limits the
|
||||
/// number of instructions to be stripped off.
|
||||
Value *GetUnderlyingObject(Value *V, const DataLayout *TD = nullptr,
|
||||
Value *GetUnderlyingObject(Value *V, const DataLayout &DL,
|
||||
unsigned MaxLookup = 6);
|
||||
static inline const Value *
|
||||
GetUnderlyingObject(const Value *V, const DataLayout *TD = nullptr,
|
||||
unsigned MaxLookup = 6) {
|
||||
return GetUnderlyingObject(const_cast<Value *>(V), TD, MaxLookup);
|
||||
static inline const Value *GetUnderlyingObject(const Value *V,
|
||||
const DataLayout &DL,
|
||||
unsigned MaxLookup = 6) {
|
||||
return GetUnderlyingObject(const_cast<Value *>(V), DL, MaxLookup);
|
||||
}
|
||||
|
||||
/// GetUnderlyingObjects - This method is similar to GetUnderlyingObject
|
||||
/// except that it can look through phi and select instructions and return
|
||||
/// multiple objects.
|
||||
void GetUnderlyingObjects(Value *V,
|
||||
SmallVectorImpl<Value *> &Objects,
|
||||
const DataLayout *TD = nullptr,
|
||||
/// \brief This method is similar to GetUnderlyingObject except that it can
|
||||
/// look through phi and select instructions and return multiple objects.
|
||||
///
|
||||
/// If LoopInfo is passed, loop phis are further analyzed. If a pointer
|
||||
/// accesses different objects in each iteration, we don't look through the
|
||||
/// phi node. E.g. consider this loop nest:
|
||||
///
|
||||
/// int **A;
|
||||
/// for (i)
|
||||
/// for (j) {
|
||||
/// A[i][j] = A[i-1][j] * B[j]
|
||||
/// }
|
||||
///
|
||||
/// This is transformed by Load-PRE to stash away A[i] for the next iteration
|
||||
/// of the outer loop:
|
||||
///
|
||||
/// Curr = A[0]; // Prev_0
|
||||
/// for (i: 1..N) {
|
||||
/// Prev = Curr; // Prev = PHI (Prev_0, Curr)
|
||||
/// Curr = A[i];
|
||||
/// for (j: 0..N) {
|
||||
/// Curr[j] = Prev[j] * B[j]
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Since A[i] and A[i-1] are independent pointers, getUnderlyingObjects
|
||||
/// should not assume that Curr and Prev share the same underlying object thus
|
||||
/// it shouldn't look through the phi above.
|
||||
void GetUnderlyingObjects(Value *V, SmallVectorImpl<Value *> &Objects,
|
||||
const DataLayout &DL, LoopInfo *LI = nullptr,
|
||||
unsigned MaxLookup = 6);
|
||||
|
||||
/// onlyUsedByLifetimeMarkers - Return true if the only users of this pointer
|
||||
/// are lifetime markers.
|
||||
bool onlyUsedByLifetimeMarkers(const Value *V);
|
||||
|
||||
/// isDereferenceablePointer - Return true if this is always a dereferenceable
|
||||
/// pointer. If the context instruction is specified perform context-sensitive
|
||||
/// analysis and return true if the pointer is dereferenceable at the
|
||||
/// specified instruction.
|
||||
bool isDereferenceablePointer(const Value *V, const DataLayout &DL,
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// isSafeToSpeculativelyExecute - Return true if the instruction does not
|
||||
/// have any effects besides calculating the result and does not have
|
||||
/// undefined behavior.
|
||||
@ -195,37 +241,82 @@ namespace llvm {
|
||||
/// memory leak. It also returns false for instructions related to control
|
||||
/// flow, specifically terminators and PHI nodes.
|
||||
///
|
||||
/// This method only looks at the instruction itself and its operands, so if
|
||||
/// this method returns true, it is safe to move the instruction as long as
|
||||
/// the correct dominance relationships for the operands and users hold.
|
||||
/// However, this method can return true for instructions that read memory;
|
||||
/// If the CtxI is specified this method performs context-sensitive analysis
|
||||
/// and returns true if it is safe to execute the instruction immediately
|
||||
/// before the CtxI.
|
||||
///
|
||||
/// If the CtxI is NOT specified this method only looks at the instruction
|
||||
/// itself and its operands, so if this method returns true, it is safe to
|
||||
/// move the instruction as long as the correct dominance relationships for
|
||||
/// the operands and users hold.
|
||||
///
|
||||
/// This method can return true for instructions that read memory;
|
||||
/// for such instructions, moving them may change the resulting value.
|
||||
bool isSafeToSpeculativelyExecute(const Value *V,
|
||||
const DataLayout *TD = nullptr);
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// isKnownNonNull - Return true if this pointer couldn't possibly be null by
|
||||
/// its definition. This returns true for allocas, non-extern-weak globals
|
||||
/// and byval arguments.
|
||||
bool isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// isKnownNonNullAt - Return true if this pointer couldn't possibly be null.
|
||||
/// If the context instruction is specified perform context-sensitive analysis
|
||||
/// and return true if the pointer couldn't possibly be null at the specified
|
||||
/// instruction.
|
||||
bool isKnownNonNullAt(const Value *V,
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
const TargetLibraryInfo *TLI = nullptr);
|
||||
|
||||
/// Return true if it is valid to use the assumptions provided by an
|
||||
/// assume intrinsic, I, at the point in the control-flow identified by the
|
||||
/// context instruction, CxtI.
|
||||
bool isValidAssumeForContext(const Instruction *I, const Instruction *CxtI,
|
||||
const DataLayout *DL = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
enum class OverflowResult { AlwaysOverflows, MayOverflow, NeverOverflows };
|
||||
OverflowResult computeOverflowForUnsignedMul(Value *LHS, Value *RHS,
|
||||
const DataLayout *DL,
|
||||
const DataLayout &DL,
|
||||
AssumptionCache *AC,
|
||||
const Instruction *CxtI,
|
||||
const DominatorTree *DT);
|
||||
OverflowResult computeOverflowForUnsignedAdd(Value *LHS, Value *RHS,
|
||||
const DataLayout *DL,
|
||||
const DataLayout &DL,
|
||||
AssumptionCache *AC,
|
||||
const Instruction *CxtI,
|
||||
const DominatorTree *DT);
|
||||
|
||||
/// \brief Specific patterns of select instructions we can match.
|
||||
enum SelectPatternFlavor {
|
||||
SPF_UNKNOWN = 0,
|
||||
SPF_SMIN, // Signed minimum
|
||||
SPF_UMIN, // Unsigned minimum
|
||||
SPF_SMAX, // Signed maximum
|
||||
SPF_UMAX, // Unsigned maximum
|
||||
SPF_ABS, // Absolute value
|
||||
SPF_NABS // Negated absolute value
|
||||
};
|
||||
/// Pattern match integer [SU]MIN, [SU]MAX and ABS idioms, returning the kind
|
||||
/// and providing the out parameter results if we successfully match.
|
||||
///
|
||||
/// If CastOp is not nullptr, also match MIN/MAX idioms where the type does
|
||||
/// not match that of the original select. If this is the case, the cast
|
||||
/// operation (one of Trunc,SExt,Zext) that must be done to transform the
|
||||
/// type of LHS and RHS into the type of V is returned in CastOp.
|
||||
///
|
||||
/// For example:
|
||||
/// %1 = icmp slt i32 %a, i32 4
|
||||
/// %2 = sext i32 %a to i64
|
||||
/// %3 = select i1 %1, i64 %2, i64 4
|
||||
///
|
||||
/// -> LHS = %a, RHS = i32 4, *CastOp = Instruction::SExt
|
||||
///
|
||||
SelectPatternFlavor matchSelectPattern(Value *V, Value *&LHS, Value *&RHS,
|
||||
Instruction::CastOps *CastOp = nullptr);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -125,7 +125,7 @@ class BitCodeAbbrevOp {
|
||||
case Blob:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("Invalid encoding");
|
||||
report_fatal_error("Invalid encoding");
|
||||
}
|
||||
|
||||
/// isChar6 - Return true if this character is legal in the Char6 encoding.
|
||||
@ -164,8 +164,8 @@ template <> struct isPodLike<BitCodeAbbrevOp> { static const bool value=true; };
|
||||
/// specialized format instead of the fully-general, fully-vbr, format.
|
||||
class BitCodeAbbrev : public RefCountedBase<BitCodeAbbrev> {
|
||||
SmallVector<BitCodeAbbrevOp, 32> OperandList;
|
||||
~BitCodeAbbrev() {}
|
||||
// Only RefCountedBase is allowed to delete.
|
||||
~BitCodeAbbrev() = default;
|
||||
friend class RefCountedBase<BitCodeAbbrev>;
|
||||
|
||||
public:
|
||||
|
@ -26,7 +26,11 @@ class PreservedAnalyses;
|
||||
/// \brief Create and return a pass that writes the module to the specified
|
||||
/// ostream. Note that this pass is designed for use with the legacy pass
|
||||
/// manager.
|
||||
ModulePass *createBitcodeWriterPass(raw_ostream &Str);
|
||||
///
|
||||
/// If \c ShouldPreserveUseListOrder, encode use-list order so it can be
|
||||
/// reproduced when deserialized.
|
||||
ModulePass *createBitcodeWriterPass(raw_ostream &Str,
|
||||
bool ShouldPreserveUseListOrder = false);
|
||||
|
||||
/// \brief Pass for writing a module of IR out to a bitcode file.
|
||||
///
|
||||
@ -34,10 +38,16 @@ ModulePass *createBitcodeWriterPass(raw_ostream &Str);
|
||||
/// a pass for the legacy pass manager, use the function above.
|
||||
class BitcodeWriterPass {
|
||||
raw_ostream &OS;
|
||||
bool ShouldPreserveUseListOrder;
|
||||
|
||||
public:
|
||||
/// \brief Construct a bitcode writer pass around a particular output stream.
|
||||
explicit BitcodeWriterPass(raw_ostream &OS) : OS(OS) {}
|
||||
///
|
||||
/// If \c ShouldPreserveUseListOrder, encode use-list order so it can be
|
||||
/// reproduced when deserialized.
|
||||
explicit BitcodeWriterPass(raw_ostream &OS,
|
||||
bool ShouldPreserveUseListOrder = false)
|
||||
: OS(OS), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {}
|
||||
|
||||
/// \brief Run the bitcode writer pass, and output the module to the selected
|
||||
/// output stream.
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Deserializer;
|
||||
|
||||
/// This class is used to read from an LLVM bitcode stream, maintaining
|
||||
/// information that is global to decoding the entire file. While a file is
|
||||
/// being read, multiple cursors can be independently advanced or skipped around
|
||||
@ -50,8 +48,8 @@ class BitstreamReader {
|
||||
/// information in the BlockInfo block. Only llvm-bcanalyzer uses this.
|
||||
bool IgnoreBlockInfoNames;
|
||||
|
||||
BitstreamReader(const BitstreamReader&) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const BitstreamReader&) LLVM_DELETED_FUNCTION;
|
||||
BitstreamReader(const BitstreamReader&) = delete;
|
||||
void operator=(const BitstreamReader&) = delete;
|
||||
public:
|
||||
BitstreamReader() : IgnoreBlockInfoNames(true) {
|
||||
}
|
||||
@ -164,7 +162,6 @@ struct BitstreamEntry {
|
||||
/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not
|
||||
/// be passed by value.
|
||||
class BitstreamCursor {
|
||||
friend class Deserializer;
|
||||
BitstreamReader *BitStream;
|
||||
size_t NextChar;
|
||||
|
||||
@ -201,6 +198,8 @@ class BitstreamCursor {
|
||||
|
||||
|
||||
public:
|
||||
static const size_t MaxChunkSize = sizeof(word_t) * 8;
|
||||
|
||||
BitstreamCursor() { init(nullptr); }
|
||||
|
||||
explicit BitstreamCursor(BitstreamReader &R) { init(&R); }
|
||||
@ -258,8 +257,8 @@ class BitstreamCursor {
|
||||
AF_DontAutoprocessAbbrevs = 2
|
||||
};
|
||||
|
||||
/// Advance the current bitstream, returning the next entry in the stream.
|
||||
BitstreamEntry advance(unsigned Flags = 0) {
|
||||
/// Advance the current bitstream, returning the next entry in the stream.
|
||||
BitstreamEntry advance(unsigned Flags = 0) {
|
||||
while (1) {
|
||||
unsigned Code = ReadCode();
|
||||
if (Code == bitc::END_BLOCK) {
|
||||
@ -301,7 +300,7 @@ class BitstreamCursor {
|
||||
|
||||
/// Reset the stream to the specified bit number.
|
||||
void JumpToBit(uint64_t BitNo) {
|
||||
uintptr_t ByteNo = uintptr_t(BitNo/8) & ~(sizeof(word_t)-1);
|
||||
size_t ByteNo = size_t(BitNo/8) & ~(sizeof(word_t)-1);
|
||||
unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1));
|
||||
assert(canSkipToPos(ByteNo) && "Invalid location");
|
||||
|
||||
@ -315,7 +314,8 @@ class BitstreamCursor {
|
||||
}
|
||||
|
||||
void fillCurWord() {
|
||||
assert(Size == 0 || NextChar < (unsigned)Size);
|
||||
if (Size != 0 && NextChar >= Size)
|
||||
report_fatal_error("Unexpected end of file");
|
||||
|
||||
// Read the next word from the stream.
|
||||
uint8_t Array[sizeof(word_t)] = {0};
|
||||
@ -337,7 +337,7 @@ class BitstreamCursor {
|
||||
}
|
||||
|
||||
word_t Read(unsigned NumBits) {
|
||||
static const unsigned BitsInWord = sizeof(word_t) * 8;
|
||||
static const unsigned BitsInWord = MaxChunkSize;
|
||||
|
||||
assert(NumBits && NumBits <= BitsInWord &&
|
||||
"Cannot return zero or more than BitsInWord bits!");
|
||||
@ -490,11 +490,11 @@ class BitstreamCursor {
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
public:
|
||||
|
||||
/// Return the abbreviation for the specified AbbrevId.
|
||||
const BitCodeAbbrev *getAbbrev(unsigned AbbrevID) {
|
||||
unsigned AbbrevNo = AbbrevID-bitc::FIRST_APPLICATION_ABBREV;
|
||||
assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!");
|
||||
unsigned AbbrevNo = AbbrevID - bitc::FIRST_APPLICATION_ABBREV;
|
||||
if (AbbrevNo >= CurAbbrevs.size())
|
||||
report_fatal_error("Invalid abbrev number");
|
||||
return CurAbbrevs[AbbrevNo].get();
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,27 @@ namespace bitc {
|
||||
METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)]
|
||||
METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)]
|
||||
METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes]
|
||||
METADATA_ATTACHMENT = 11 // [m x [value, [n x [id, mdnode]]]
|
||||
METADATA_ATTACHMENT = 11, // [m x [value, [n x [id, mdnode]]]
|
||||
METADATA_GENERIC_DEBUG = 12, // [distinct, tag, vers, header, n x md num]
|
||||
METADATA_SUBRANGE = 13, // [distinct, count, lo]
|
||||
METADATA_ENUMERATOR = 14, // [distinct, value, name]
|
||||
METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc]
|
||||
METADATA_FILE = 16, // [distinct, filename, directory]
|
||||
METADATA_DERIVED_TYPE = 17, // [distinct, ...]
|
||||
METADATA_COMPOSITE_TYPE= 18, // [distinct, ...]
|
||||
METADATA_SUBROUTINE_TYPE=19, // [distinct, flags, types]
|
||||
METADATA_COMPILE_UNIT = 20, // [distinct, ...]
|
||||
METADATA_SUBPROGRAM = 21, // [distinct, ...]
|
||||
METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column]
|
||||
METADATA_LEXICAL_BLOCK_FILE=23,//[distinct, scope, file, discriminator]
|
||||
METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line]
|
||||
METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...]
|
||||
METADATA_TEMPLATE_VALUE= 26, // [distinct, scope, name, type, value, ...]
|
||||
METADATA_GLOBAL_VAR = 27, // [distinct, ...]
|
||||
METADATA_LOCAL_VAR = 28, // [distinct, ...]
|
||||
METADATA_EXPRESSION = 29, // [distinct, n x element]
|
||||
METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...]
|
||||
METADATA_IMPORTED_ENTITY=31, // [distinct, tag, scope, entity, line, name]
|
||||
};
|
||||
|
||||
// The constants block (CONSTANTS_BLOCK_ID) describes emission for each
|
||||
@ -273,7 +293,7 @@ namespace bitc {
|
||||
|
||||
FUNC_CODE_INST_BINOP = 2, // BINOP: [opcode, ty, opval, opval]
|
||||
FUNC_CODE_INST_CAST = 3, // CAST: [opcode, ty, opty, opval]
|
||||
FUNC_CODE_INST_GEP = 4, // GEP: [n x operands]
|
||||
FUNC_CODE_INST_GEP_OLD = 4, // GEP: [n x operands]
|
||||
FUNC_CODE_INST_SELECT = 5, // SELECT: [ty, opval, opval, opval]
|
||||
FUNC_CODE_INST_EXTRACTELT = 6, // EXTRACTELT: [opty, opval, opval]
|
||||
FUNC_CODE_INST_INSERTELT = 7, // INSERTELT: [ty, opval, opval, opval]
|
||||
@ -298,7 +318,7 @@ namespace bitc {
|
||||
// This store code encodes the pointer type, rather than the value type
|
||||
// this is so information only available in the pointer type (e.g. address
|
||||
// spaces) is retained.
|
||||
FUNC_CODE_INST_STORE = 24, // STORE: [ptrty,ptr,val, align, vol]
|
||||
FUNC_CODE_INST_STORE_OLD = 24, // STORE: [ptrty,ptr,val, align, vol]
|
||||
// 25 is unused.
|
||||
FUNC_CODE_INST_EXTRACTVAL = 26, // EXTRACTVAL: [n x operands]
|
||||
FUNC_CODE_INST_INSERTVAL = 27, // INSERTVAL: [n x operands]
|
||||
@ -307,7 +327,7 @@ namespace bitc {
|
||||
FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred]
|
||||
// new select on i1 or [N x i1]
|
||||
FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred]
|
||||
FUNC_CODE_INST_INBOUNDS_GEP= 30, // INBOUNDS_GEP: [n x operands]
|
||||
FUNC_CODE_INST_INBOUNDS_GEP_OLD = 30, // INBOUNDS_GEP: [n x operands]
|
||||
FUNC_CODE_INST_INDIRECTBR = 31, // INDIRECTBR: [opty, op0, op1, ...]
|
||||
// 32 is unused.
|
||||
FUNC_CODE_DEBUG_LOC_AGAIN = 33, // DEBUG_LOC_AGAIN
|
||||
@ -316,7 +336,7 @@ namespace bitc {
|
||||
|
||||
FUNC_CODE_DEBUG_LOC = 35, // DEBUG_LOC: [Line,Col,ScopeVal, IAVal]
|
||||
FUNC_CODE_INST_FENCE = 36, // FENCE: [ordering, synchscope]
|
||||
FUNC_CODE_INST_CMPXCHG = 37, // CMPXCHG: [ptrty,ptr,cmp,new, align, vol,
|
||||
FUNC_CODE_INST_CMPXCHG_OLD = 37, // CMPXCHG: [ptrty,ptr,cmp,new, align, vol,
|
||||
// ordering, synchscope]
|
||||
FUNC_CODE_INST_ATOMICRMW = 38, // ATOMICRMW: [ptrty,ptr,val, operation,
|
||||
// align, vol,
|
||||
@ -325,8 +345,13 @@ namespace bitc {
|
||||
FUNC_CODE_INST_LANDINGPAD = 40, // LANDINGPAD: [ty,val,val,num,id0,val0...]
|
||||
FUNC_CODE_INST_LOADATOMIC = 41, // LOAD: [opty, op, align, vol,
|
||||
// ordering, synchscope]
|
||||
FUNC_CODE_INST_STOREATOMIC = 42 // STORE: [ptrty,ptr,val, align, vol
|
||||
FUNC_CODE_INST_STOREATOMIC_OLD = 42, // STORE: [ptrty,ptr,val, align, vol
|
||||
// ordering, synchscope]
|
||||
FUNC_CODE_INST_GEP = 43, // GEP: [inbounds, n x operands]
|
||||
FUNC_CODE_INST_STORE = 44, // STORE: [ptrty,ptr,valty,val, align, vol]
|
||||
FUNC_CODE_INST_STOREATOMIC = 45, // STORE: [ptrty,ptr,val, align, vol
|
||||
FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align,
|
||||
// vol,ordering,synchscope]
|
||||
};
|
||||
|
||||
enum UseListCodes {
|
||||
@ -376,7 +401,9 @@ namespace bitc {
|
||||
ATTR_KIND_IN_ALLOCA = 38,
|
||||
ATTR_KIND_NON_NULL = 39,
|
||||
ATTR_KIND_JUMP_TABLE = 40,
|
||||
ATTR_KIND_DEREFERENCEABLE = 41
|
||||
ATTR_KIND_DEREFERENCEABLE = 41,
|
||||
ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42,
|
||||
ATTR_KIND_CONVERGENT = 43
|
||||
};
|
||||
|
||||
enum ComdatSelectionKindCodes {
|
||||
|
@ -29,12 +29,14 @@ namespace llvm {
|
||||
class raw_ostream;
|
||||
|
||||
/// Read the header of the specified bitcode buffer and prepare for lazy
|
||||
/// deserialization of function bodies. If successful, this moves Buffer. On
|
||||
/// deserialization of function bodies. If ShouldLazyLoadMetadata is true,
|
||||
/// lazily load metadata as well. If successful, this moves Buffer. On
|
||||
/// error, this *does not* move Buffer.
|
||||
ErrorOr<Module *>
|
||||
getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
|
||||
LLVMContext &Context,
|
||||
DiagnosticHandlerFunction DiagnosticHandler = nullptr);
|
||||
DiagnosticHandlerFunction DiagnosticHandler = nullptr,
|
||||
bool ShouldLazyLoadMetadata = false);
|
||||
|
||||
/// Read the header of the specified stream and prepare for lazy
|
||||
/// deserialization and streaming of function bodies.
|
||||
@ -54,11 +56,16 @@ namespace llvm {
|
||||
parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
|
||||
DiagnosticHandlerFunction DiagnosticHandler = nullptr);
|
||||
|
||||
/// WriteBitcodeToFile - Write the specified module to the specified
|
||||
/// raw output stream. For streams where it matters, the given stream
|
||||
/// should be in "binary" mode.
|
||||
void WriteBitcodeToFile(const Module *M, raw_ostream &Out);
|
||||
|
||||
/// \brief Write the specified module to the specified raw output stream.
|
||||
///
|
||||
/// For streams where it matters, the given stream should be in "binary"
|
||||
/// mode.
|
||||
///
|
||||
/// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a
|
||||
/// Value in \c M. These will be reconstructed exactly when \a M is
|
||||
/// deserialized.
|
||||
void WriteBitcodeToFile(const Module *M, raw_ostream &Out,
|
||||
bool ShouldPreserveUseListOrder = false);
|
||||
|
||||
/// isBitcodeWrapper - Return true if the given bytes are the magic bytes
|
||||
/// for an LLVM IR bitcode wrapper.
|
||||
|
@ -16,8 +16,10 @@
|
||||
#ifndef LLVM_CODEGEN_ASMPRINTER_H
|
||||
#define LLVM_CODEGEN_ASMPRINTER_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
@ -29,6 +31,8 @@ class ByteStreamer;
|
||||
class GCStrategy;
|
||||
class Constant;
|
||||
class ConstantArray;
|
||||
class DIE;
|
||||
class DIEAbbrev;
|
||||
class GCMetadataPrinter;
|
||||
class GlobalValue;
|
||||
class GlobalVariable;
|
||||
@ -46,11 +50,11 @@ class MCCFIInstruction;
|
||||
class MCContext;
|
||||
class MCExpr;
|
||||
class MCInst;
|
||||
class MCInstrInfo;
|
||||
class MCSection;
|
||||
class MCStreamer;
|
||||
class MCSubtargetInfo;
|
||||
class MCSymbol;
|
||||
class MCTargetOptions;
|
||||
class MDNode;
|
||||
class DwarfDebug;
|
||||
class Mangler;
|
||||
@ -69,7 +73,6 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
///
|
||||
const MCAsmInfo *MAI;
|
||||
|
||||
const MCInstrInfo *MII;
|
||||
/// This is the context for the output file that we are streaming. This owns
|
||||
/// all of the global MC-related objects for the generated translation unit.
|
||||
MCContext &OutContext;
|
||||
@ -77,7 +80,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// This is the MCStreamer object for the file we are generating. This
|
||||
/// contains the transient state for the current translation unit that we are
|
||||
/// generating (such as the current section etc).
|
||||
MCStreamer &OutStreamer;
|
||||
std::unique_ptr<MCStreamer> OutStreamer;
|
||||
|
||||
/// The current machine function.
|
||||
const MachineFunction *MF;
|
||||
@ -99,7 +102,16 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// default, this is equal to CurrentFnSym.
|
||||
MCSymbol *CurrentFnSymForSize;
|
||||
|
||||
/// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of
|
||||
/// its number of uses by other globals.
|
||||
typedef std::pair<const GlobalVariable *, unsigned> GOTEquivUsePair;
|
||||
MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs;
|
||||
|
||||
private:
|
||||
MCSymbol *CurrentFnBegin;
|
||||
MCSymbol *CurrentFnEnd;
|
||||
MCSymbol *CurExceptionSym;
|
||||
|
||||
// The garbage collection metadata printer table.
|
||||
void *GCMetadataPrinters; // Really a DenseMap.
|
||||
|
||||
@ -127,10 +139,10 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
DwarfDebug *DD;
|
||||
|
||||
protected:
|
||||
explicit AsmPrinter(TargetMachine &TM, MCStreamer &Streamer);
|
||||
explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
|
||||
|
||||
public:
|
||||
virtual ~AsmPrinter();
|
||||
~AsmPrinter() override;
|
||||
|
||||
DwarfDebug *getDwarfDebug() { return DD; }
|
||||
DwarfDebug *getDwarfDebug() const { return DD; }
|
||||
@ -143,6 +155,10 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
///
|
||||
unsigned getFunctionNumber() const;
|
||||
|
||||
MCSymbol *getFunctionBegin() const { return CurrentFnBegin; }
|
||||
MCSymbol *getFunctionEnd() const { return CurrentFnEnd; }
|
||||
MCSymbol *getCurExceptionSym();
|
||||
|
||||
/// Return information about object file lowering.
|
||||
const TargetLoweringObjectFile &getObjFileLowering() const;
|
||||
|
||||
@ -184,7 +200,6 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// Emit the specified function out to the OutStreamer.
|
||||
bool runOnMachineFunction(MachineFunction &MF) override {
|
||||
SetupMachineFunction(MF);
|
||||
EmitFunctionHeader();
|
||||
EmitFunctionBody();
|
||||
return false;
|
||||
}
|
||||
@ -197,9 +212,6 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// runOnMachineFunction.
|
||||
void SetupMachineFunction(MachineFunction &MF);
|
||||
|
||||
/// This method emits the header for the current function.
|
||||
void EmitFunctionHeader();
|
||||
|
||||
/// This method emits the body and trailer for a function.
|
||||
void EmitFunctionBody();
|
||||
|
||||
@ -238,16 +250,27 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
///
|
||||
void EmitAlignment(unsigned NumBits, const GlobalObject *GO = nullptr) const;
|
||||
|
||||
/// This method prints the label for the specified MachineBasicBlock, an
|
||||
/// alignment (if present) and a comment describing it if appropriate.
|
||||
void EmitBasicBlockStart(const MachineBasicBlock &MBB) const;
|
||||
|
||||
/// Lower the specified LLVM Constant to an MCExpr.
|
||||
const MCExpr *lowerConstant(const Constant *CV);
|
||||
|
||||
/// \brief Print a general LLVM constant to the .s file.
|
||||
void EmitGlobalConstant(const Constant *CV);
|
||||
|
||||
/// \brief Unnamed constant global variables solely contaning a pointer to
|
||||
/// another globals variable act like a global variable "proxy", or GOT
|
||||
/// equivalents, i.e., it's only used to hold the address of the latter. One
|
||||
/// optimization is to replace accesses to these proxies by using the GOT
|
||||
/// entry for the final global instead. Hence, we select GOT equivalent
|
||||
/// candidates among all the module global variables, avoid emitting them
|
||||
/// unnecessarily and finally replace references to them by pc relative
|
||||
/// accesses to GOT entries.
|
||||
void computeGlobalGOTEquivs(Module &M);
|
||||
|
||||
/// \brief Constant expressions using GOT equivalent globals may not be
|
||||
/// eligible for PC relative GOT entry conversion, in such cases we need to
|
||||
/// emit the proxies we previously omitted in EmitGlobalVariable.
|
||||
void emitGlobalGOTEquivs();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Overridable Hooks
|
||||
//===------------------------------------------------------------------===//
|
||||
@ -271,6 +294,12 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// function.
|
||||
virtual void EmitFunctionBodyEnd() {}
|
||||
|
||||
/// Targets can override this to emit stuff at the start of a basic block.
|
||||
/// By default, this method prints the label for the specified
|
||||
/// MachineBasicBlock, an alignment (if present) and a comment describing it
|
||||
/// if appropriate.
|
||||
virtual void EmitBasicBlockStart(const MachineBasicBlock &MBB) const;
|
||||
|
||||
/// Targets can override this to emit stuff at the end of a basic block.
|
||||
virtual void EmitBasicBlockEnd(const MachineBasicBlock &MBB) {}
|
||||
|
||||
@ -304,12 +333,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
// Symbol Lowering Routines.
|
||||
//===------------------------------------------------------------------===//
|
||||
public:
|
||||
/// Return the MCSymbol corresponding to the assembler temporary label with
|
||||
/// the specified stem and unique ID.
|
||||
MCSymbol *GetTempSymbol(Twine Name, unsigned ID) const;
|
||||
|
||||
/// Return an assembler temporary label with the specified stem.
|
||||
MCSymbol *GetTempSymbol(Twine Name) const;
|
||||
MCSymbol *createTempSymbol(const Twine &Name) const;
|
||||
|
||||
/// Return the MCSymbol for a private symbol with global value name as its
|
||||
/// base, with the specified suffix.
|
||||
@ -397,42 +421,21 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// Emit the 4-byte offset of Label from the start of its section. This can
|
||||
/// be done with a special directive if the target supports it (e.g. cygwin)
|
||||
/// or by emitting it as an offset from a label at the start of the section.
|
||||
void emitSectionOffset(const MCSymbol *Label) const;
|
||||
|
||||
/// Emit the 4-byte offset of a string from the start of its section.
|
||||
///
|
||||
/// SectionLabel is a temporary label emitted at the start of the section
|
||||
/// that Label lives in.
|
||||
void EmitSectionOffset(const MCSymbol *Label,
|
||||
const MCSymbol *SectionLabel) const;
|
||||
/// When possible, emit a DwarfStringPool section offset without any
|
||||
/// relocations, and without using the symbol. Otherwise, defers to \a
|
||||
/// emitSectionOffset().
|
||||
void emitDwarfStringOffset(DwarfStringPoolEntryRef S) const;
|
||||
|
||||
/// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified.
|
||||
virtual unsigned getISAEncoding() { return 0; }
|
||||
|
||||
/// Emit a dwarf register operation for describing
|
||||
/// - a small value occupying only part of a register or
|
||||
/// - a register representing only part of a value.
|
||||
void EmitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits,
|
||||
unsigned OffsetInBits = 0) const;
|
||||
|
||||
|
||||
/// \brief Emit a partial DWARF register operation.
|
||||
/// \param MLoc the register
|
||||
/// \param PieceSize size and
|
||||
/// \param PieceOffset offset of the piece in bits, if this is one
|
||||
/// piece of an aggregate value.
|
||||
///
|
||||
/// If size and offset is zero an operation for the entire
|
||||
/// register is emitted: Some targets do not provide a DWARF
|
||||
/// register number for every register. If this is the case, this
|
||||
/// function will attempt to emit a DWARF register by emitting a
|
||||
/// piece of a super-register or by piecing together multiple
|
||||
/// subregisters that alias the register.
|
||||
void EmitDwarfRegOpPiece(ByteStreamer &BS, const MachineLocation &MLoc,
|
||||
unsigned PieceSize = 0,
|
||||
unsigned PieceOffset = 0) const;
|
||||
|
||||
/// EmitDwarfRegOp - Emit a dwarf register operation.
|
||||
/// \param Indirect whether this is a register-indirect address
|
||||
virtual void EmitDwarfRegOp(ByteStreamer &BS, const MachineLocation &MLoc,
|
||||
bool Indirect) const;
|
||||
virtual void EmitDwarfRegOp(ByteStreamer &BS,
|
||||
const MachineLocation &MLoc) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Dwarf Lowering Routines
|
||||
@ -441,6 +444,12 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// \brief Emit frame instruction to describe the layout of the frame.
|
||||
void emitCFIInstruction(const MCCFIInstruction &Inst) const;
|
||||
|
||||
/// \brief Emit Dwarf abbreviation table.
|
||||
void emitDwarfAbbrevs(const std::vector<DIEAbbrev *>& Abbrevs) const;
|
||||
|
||||
/// \brief Recursively emit Dwarf DIE tree.
|
||||
void emitDwarfDIE(const DIE &Die) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Inline Asm Support
|
||||
//===------------------------------------------------------------------===//
|
||||
@ -474,7 +483,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
|
||||
/// Let the target do anything it needs to do before emitting inlineasm.
|
||||
/// \p StartInfo - the subtarget info before parsing inline asm
|
||||
virtual void emitInlineAsmStart(const MCSubtargetInfo &StartInfo) const;
|
||||
virtual void emitInlineAsmStart() const;
|
||||
|
||||
/// Let the target do anything it needs to do after emitting inlineasm.
|
||||
/// This callback can be used restore the original mode in case the
|
||||
@ -491,11 +500,15 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
mutable const MachineInstr *LastMI;
|
||||
mutable unsigned LastFn;
|
||||
mutable unsigned Counter;
|
||||
mutable unsigned SetCounter;
|
||||
|
||||
/// This method emits the header for the current function.
|
||||
virtual void EmitFunctionHeader();
|
||||
|
||||
/// Emit a blob of inline asm to the output streamer.
|
||||
void
|
||||
EmitInlineAsm(StringRef Str, const MDNode *LocMDNode = nullptr,
|
||||
EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
||||
const MCTargetOptions &MCOptions,
|
||||
const MDNode *LocMDNode = nullptr,
|
||||
InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT) const;
|
||||
|
||||
/// This method formats and emits the specified machine instruction that is an
|
||||
|
767
contrib/llvm/include/llvm/CodeGen/BasicTTIImpl.h
Normal file
767
contrib/llvm/include/llvm/CodeGen/BasicTTIImpl.h
Normal file
@ -0,0 +1,767 @@
|
||||
//===- BasicTTIImpl.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file provides a helper that implements much of the TTI interface in
|
||||
/// terms of the target-independent code generator and TargetLowering
|
||||
/// interfaces.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_BASICTTIIMPL_H
|
||||
#define LLVM_CODEGEN_BASICTTIIMPL_H
|
||||
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfoImpl.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern cl::opt<unsigned> PartialUnrollingThreshold;
|
||||
|
||||
/// \brief Base class which can be used to help build a TTI implementation.
|
||||
///
|
||||
/// This class provides as much implementation of the TTI interface as is
|
||||
/// possible using the target independent parts of the code generator.
|
||||
///
|
||||
/// In order to subclass it, your class must implement a getST() method to
|
||||
/// return the subtarget, and a getTLI() method to return the target lowering.
|
||||
/// We need these methods implemented in the derived class so that this class
|
||||
/// doesn't have to duplicate storage for them.
|
||||
template <typename T>
|
||||
class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
private:
|
||||
typedef TargetTransformInfoImplCRTPBase<T> BaseT;
|
||||
typedef TargetTransformInfo TTI;
|
||||
|
||||
/// Estimate the overhead of scalarizing an instruction. Insert and Extract
|
||||
/// are set if the result needs to be inserted and/or extracted from vectors.
|
||||
unsigned getScalarizationOverhead(Type *Ty, bool Insert, bool Extract) {
|
||||
assert(Ty->isVectorTy() && "Can only scalarize vectors");
|
||||
unsigned Cost = 0;
|
||||
|
||||
for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) {
|
||||
if (Insert)
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::InsertElement, Ty, i);
|
||||
if (Extract)
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::ExtractElement, Ty, i);
|
||||
}
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
/// Estimate the cost overhead of SK_Alternate shuffle.
|
||||
unsigned getAltShuffleOverhead(Type *Ty) {
|
||||
assert(Ty->isVectorTy() && "Can only shuffle vectors");
|
||||
unsigned Cost = 0;
|
||||
// Shuffle cost is equal to the cost of extracting element from its argument
|
||||
// plus the cost of inserting them onto the result vector.
|
||||
|
||||
// e.g. <4 x float> has a mask of <0,5,2,7> i.e we need to extract from
|
||||
// index 0 of first vector, index 1 of second vector,index 2 of first
|
||||
// vector and finally index 3 of second vector and insert them at index
|
||||
// <0,1,2,3> of result vector.
|
||||
for (int i = 0, e = Ty->getVectorNumElements(); i < e; ++i) {
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::InsertElement, Ty, i);
|
||||
Cost += static_cast<T *>(this)
|
||||
->getVectorInstrCost(Instruction::ExtractElement, Ty, i);
|
||||
}
|
||||
return Cost;
|
||||
}
|
||||
|
||||
/// \brief Local query method delegates up to T which *must* implement this!
|
||||
const TargetSubtargetInfo *getST() const {
|
||||
return static_cast<const T *>(this)->getST();
|
||||
}
|
||||
|
||||
/// \brief Local query method delegates up to T which *must* implement this!
|
||||
const TargetLoweringBase *getTLI() const {
|
||||
return static_cast<const T *>(this)->getTLI();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit BasicTTIImplBase(const TargetMachine *TM)
|
||||
: BaseT(TM->getDataLayout()) {}
|
||||
|
||||
public:
|
||||
// Provide value semantics. MSVC requires that we spell all of these out.
|
||||
BasicTTIImplBase(const BasicTTIImplBase &Arg)
|
||||
: BaseT(static_cast<const BaseT &>(Arg)) {}
|
||||
BasicTTIImplBase(BasicTTIImplBase &&Arg)
|
||||
: BaseT(std::move(static_cast<BaseT &>(Arg))) {}
|
||||
BasicTTIImplBase &operator=(const BasicTTIImplBase &RHS) {
|
||||
BaseT::operator=(static_cast<const BaseT &>(RHS));
|
||||
return *this;
|
||||
}
|
||||
BasicTTIImplBase &operator=(BasicTTIImplBase &&RHS) {
|
||||
BaseT::operator=(std::move(static_cast<BaseT &>(RHS)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \name Scalar TTI Implementations
|
||||
/// @{
|
||||
|
||||
bool hasBranchDivergence() { return false; }
|
||||
|
||||
bool isSourceOfDivergence(const Value *V) { return false; }
|
||||
|
||||
bool isLegalAddImmediate(int64_t imm) {
|
||||
return getTLI()->isLegalAddImmediate(imm);
|
||||
}
|
||||
|
||||
bool isLegalICmpImmediate(int64_t imm) {
|
||||
return getTLI()->isLegalICmpImmediate(imm);
|
||||
}
|
||||
|
||||
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) {
|
||||
TargetLoweringBase::AddrMode AM;
|
||||
AM.BaseGV = BaseGV;
|
||||
AM.BaseOffs = BaseOffset;
|
||||
AM.HasBaseReg = HasBaseReg;
|
||||
AM.Scale = Scale;
|
||||
return getTLI()->isLegalAddressingMode(AM, Ty);
|
||||
}
|
||||
|
||||
int getScalingFactorCost(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset,
|
||||
bool HasBaseReg, int64_t Scale) {
|
||||
TargetLoweringBase::AddrMode AM;
|
||||
AM.BaseGV = BaseGV;
|
||||
AM.BaseOffs = BaseOffset;
|
||||
AM.HasBaseReg = HasBaseReg;
|
||||
AM.Scale = Scale;
|
||||
return getTLI()->getScalingFactorCost(AM, Ty);
|
||||
}
|
||||
|
||||
bool isTruncateFree(Type *Ty1, Type *Ty2) {
|
||||
return getTLI()->isTruncateFree(Ty1, Ty2);
|
||||
}
|
||||
|
||||
bool isProfitableToHoist(Instruction *I) {
|
||||
return getTLI()->isProfitableToHoist(I);
|
||||
}
|
||||
|
||||
bool isTypeLegal(Type *Ty) {
|
||||
EVT VT = getTLI()->getValueType(Ty);
|
||||
return getTLI()->isTypeLegal(VT);
|
||||
}
|
||||
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<const Value *> Arguments) {
|
||||
return BaseT::getIntrinsicCost(IID, RetTy, Arguments);
|
||||
}
|
||||
|
||||
unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> ParamTys) {
|
||||
if (IID == Intrinsic::cttz) {
|
||||
if (getTLI()->isCheapToSpeculateCttz())
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
return TargetTransformInfo::TCC_Expensive;
|
||||
}
|
||||
|
||||
if (IID == Intrinsic::ctlz) {
|
||||
if (getTLI()->isCheapToSpeculateCtlz())
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
return TargetTransformInfo::TCC_Expensive;
|
||||
}
|
||||
|
||||
return BaseT::getIntrinsicCost(IID, RetTy, ParamTys);
|
||||
}
|
||||
|
||||
unsigned getJumpBufAlignment() { return getTLI()->getJumpBufAlignment(); }
|
||||
|
||||
unsigned getJumpBufSize() { return getTLI()->getJumpBufSize(); }
|
||||
|
||||
bool shouldBuildLookupTables() {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
return TLI->isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) ||
|
||||
TLI->isOperationLegalOrCustom(ISD::BRIND, MVT::Other);
|
||||
}
|
||||
|
||||
bool haveFastSqrt(Type *Ty) {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
EVT VT = TLI->getValueType(Ty);
|
||||
return TLI->isTypeLegal(VT) &&
|
||||
TLI->isOperationLegalOrCustom(ISD::FSQRT, VT);
|
||||
}
|
||||
|
||||
unsigned getFPOpCost(Type *Ty) {
|
||||
// By default, FP instructions are no more expensive since they are
|
||||
// implemented in HW. Target specific TTI can override this.
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
}
|
||||
|
||||
unsigned getOperationCost(unsigned Opcode, Type *Ty, Type *OpTy) {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
switch (Opcode) {
|
||||
default: break;
|
||||
case Instruction::Trunc: {
|
||||
if (TLI->isTruncateFree(OpTy, Ty))
|
||||
return TargetTransformInfo::TCC_Free;
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
}
|
||||
case Instruction::ZExt: {
|
||||
if (TLI->isZExtFree(OpTy, Ty))
|
||||
return TargetTransformInfo::TCC_Free;
|
||||
return TargetTransformInfo::TCC_Basic;
|
||||
}
|
||||
}
|
||||
|
||||
return BaseT::getOperationCost(Opcode, Ty, OpTy);
|
||||
}
|
||||
|
||||
void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP) {
|
||||
// This unrolling functionality is target independent, but to provide some
|
||||
// motivation for its intended use, for x86:
|
||||
|
||||
// According to the Intel 64 and IA-32 Architectures Optimization Reference
|
||||
// Manual, Intel Core models and later have a loop stream detector (and
|
||||
// associated uop queue) that can benefit from partial unrolling.
|
||||
// The relevant requirements are:
|
||||
// - The loop must have no more than 4 (8 for Nehalem and later) branches
|
||||
// taken, and none of them may be calls.
|
||||
// - The loop can have no more than 18 (28 for Nehalem and later) uops.
|
||||
|
||||
// According to the Software Optimization Guide for AMD Family 15h
|
||||
// Processors, models 30h-4fh (Steamroller and later) have a loop predictor
|
||||
// and loop buffer which can benefit from partial unrolling.
|
||||
// The relevant requirements are:
|
||||
// - The loop must have fewer than 16 branches
|
||||
// - The loop must have less than 40 uops in all executed loop branches
|
||||
|
||||
// The number of taken branches in a loop is hard to estimate here, and
|
||||
// benchmarking has revealed that it is better not to be conservative when
|
||||
// estimating the branch count. As a result, we'll ignore the branch limits
|
||||
// until someone finds a case where it matters in practice.
|
||||
|
||||
unsigned MaxOps;
|
||||
const TargetSubtargetInfo *ST = getST();
|
||||
if (PartialUnrollingThreshold.getNumOccurrences() > 0)
|
||||
MaxOps = PartialUnrollingThreshold;
|
||||
else if (ST->getSchedModel().LoopMicroOpBufferSize > 0)
|
||||
MaxOps = ST->getSchedModel().LoopMicroOpBufferSize;
|
||||
else
|
||||
return;
|
||||
|
||||
// Scan the loop: don't unroll loops with calls.
|
||||
for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E;
|
||||
++I) {
|
||||
BasicBlock *BB = *I;
|
||||
|
||||
for (BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; ++J)
|
||||
if (isa<CallInst>(J) || isa<InvokeInst>(J)) {
|
||||
ImmutableCallSite CS(J);
|
||||
if (const Function *F = CS.getCalledFunction()) {
|
||||
if (!static_cast<T *>(this)->isLoweredToCall(F))
|
||||
continue;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable runtime and partial unrolling up to the specified size.
|
||||
UP.Partial = UP.Runtime = true;
|
||||
UP.PartialThreshold = UP.PartialOptSizeThreshold = MaxOps;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Vector TTI Implementations
|
||||
/// @{
|
||||
|
||||
unsigned getNumberOfRegisters(bool Vector) { return 1; }
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) { return 32; }
|
||||
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) { return 1; }
|
||||
|
||||
unsigned getArithmeticInstrCost(
|
||||
unsigned Opcode, Type *Ty,
|
||||
TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue,
|
||||
TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue,
|
||||
TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None,
|
||||
TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None) {
|
||||
// Check if any of the operands are vector operands.
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
int ISD = TLI->InstructionOpcodeToISD(Opcode);
|
||||
assert(ISD && "Invalid opcode");
|
||||
|
||||
std::pair<unsigned, MVT> LT = TLI->getTypeLegalizationCost(Ty);
|
||||
|
||||
bool IsFloat = Ty->getScalarType()->isFloatingPointTy();
|
||||
// Assume that floating point arithmetic operations cost twice as much as
|
||||
// integer operations.
|
||||
unsigned OpCost = (IsFloat ? 2 : 1);
|
||||
|
||||
if (TLI->isOperationLegalOrPromote(ISD, LT.second)) {
|
||||
// The operation is legal. Assume it costs 1.
|
||||
// If the type is split to multiple registers, assume that there is some
|
||||
// overhead to this.
|
||||
// TODO: Once we have extract/insert subvector cost we need to use them.
|
||||
if (LT.first > 1)
|
||||
return LT.first * 2 * OpCost;
|
||||
return LT.first * 1 * OpCost;
|
||||
}
|
||||
|
||||
if (!TLI->isOperationExpand(ISD, LT.second)) {
|
||||
// If the operation is custom lowered then assume
|
||||
// thare the code is twice as expensive.
|
||||
return LT.first * 2 * OpCost;
|
||||
}
|
||||
|
||||
// Else, assume that we need to scalarize this op.
|
||||
if (Ty->isVectorTy()) {
|
||||
unsigned Num = Ty->getVectorNumElements();
|
||||
unsigned Cost = static_cast<T *>(this)
|
||||
->getArithmeticInstrCost(Opcode, Ty->getScalarType());
|
||||
// return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting
|
||||
// and extracting the values.
|
||||
return getScalarizationOverhead(Ty, true, true) + Num * Cost;
|
||||
}
|
||||
|
||||
// We don't know anything about this scalar instruction.
|
||||
return OpCost;
|
||||
}
|
||||
|
||||
unsigned getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index,
|
||||
Type *SubTp) {
|
||||
if (Kind == TTI::SK_Alternate) {
|
||||
return getAltShuffleOverhead(Tp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
int ISD = TLI->InstructionOpcodeToISD(Opcode);
|
||||
assert(ISD && "Invalid opcode");
|
||||
|
||||
std::pair<unsigned, MVT> SrcLT = TLI->getTypeLegalizationCost(Src);
|
||||
std::pair<unsigned, MVT> DstLT = TLI->getTypeLegalizationCost(Dst);
|
||||
|
||||
// Check for NOOP conversions.
|
||||
if (SrcLT.first == DstLT.first &&
|
||||
SrcLT.second.getSizeInBits() == DstLT.second.getSizeInBits()) {
|
||||
|
||||
// Bitcast between types that are legalized to the same type are free.
|
||||
if (Opcode == Instruction::BitCast || Opcode == Instruction::Trunc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Opcode == Instruction::Trunc &&
|
||||
TLI->isTruncateFree(SrcLT.second, DstLT.second))
|
||||
return 0;
|
||||
|
||||
if (Opcode == Instruction::ZExt &&
|
||||
TLI->isZExtFree(SrcLT.second, DstLT.second))
|
||||
return 0;
|
||||
|
||||
// If the cast is marked as legal (or promote) then assume low cost.
|
||||
if (SrcLT.first == DstLT.first &&
|
||||
TLI->isOperationLegalOrPromote(ISD, DstLT.second))
|
||||
return 1;
|
||||
|
||||
// Handle scalar conversions.
|
||||
if (!Src->isVectorTy() && !Dst->isVectorTy()) {
|
||||
|
||||
// Scalar bitcasts are usually free.
|
||||
if (Opcode == Instruction::BitCast)
|
||||
return 0;
|
||||
|
||||
// Just check the op cost. If the operation is legal then assume it costs
|
||||
// 1.
|
||||
if (!TLI->isOperationExpand(ISD, DstLT.second))
|
||||
return 1;
|
||||
|
||||
// Assume that illegal scalar instruction are expensive.
|
||||
return 4;
|
||||
}
|
||||
|
||||
// Check vector-to-vector casts.
|
||||
if (Dst->isVectorTy() && Src->isVectorTy()) {
|
||||
|
||||
// If the cast is between same-sized registers, then the check is simple.
|
||||
if (SrcLT.first == DstLT.first &&
|
||||
SrcLT.second.getSizeInBits() == DstLT.second.getSizeInBits()) {
|
||||
|
||||
// Assume that Zext is done using AND.
|
||||
if (Opcode == Instruction::ZExt)
|
||||
return 1;
|
||||
|
||||
// Assume that sext is done using SHL and SRA.
|
||||
if (Opcode == Instruction::SExt)
|
||||
return 2;
|
||||
|
||||
// Just check the op cost. If the operation is legal then assume it
|
||||
// costs
|
||||
// 1 and multiply by the type-legalization overhead.
|
||||
if (!TLI->isOperationExpand(ISD, DstLT.second))
|
||||
return SrcLT.first * 1;
|
||||
}
|
||||
|
||||
// If we are converting vectors and the operation is illegal, or
|
||||
// if the vectors are legalized to different types, estimate the
|
||||
// scalarization costs.
|
||||
unsigned Num = Dst->getVectorNumElements();
|
||||
unsigned Cost = static_cast<T *>(this)->getCastInstrCost(
|
||||
Opcode, Dst->getScalarType(), Src->getScalarType());
|
||||
|
||||
// Return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting and extracting the values.
|
||||
return getScalarizationOverhead(Dst, true, true) + Num * Cost;
|
||||
}
|
||||
|
||||
// We already handled vector-to-vector and scalar-to-scalar conversions.
|
||||
// This
|
||||
// is where we handle bitcast between vectors and scalars. We need to assume
|
||||
// that the conversion is scalarized in one way or another.
|
||||
if (Opcode == Instruction::BitCast)
|
||||
// Illegal bitcasts are done by storing and loading from a stack slot.
|
||||
return (Src->isVectorTy() ? getScalarizationOverhead(Src, false, true)
|
||||
: 0) +
|
||||
(Dst->isVectorTy() ? getScalarizationOverhead(Dst, true, false)
|
||||
: 0);
|
||||
|
||||
llvm_unreachable("Unhandled cast");
|
||||
}
|
||||
|
||||
unsigned getCFInstrCost(unsigned Opcode) {
|
||||
// Branches are assumed to be predicted.
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
int ISD = TLI->InstructionOpcodeToISD(Opcode);
|
||||
assert(ISD && "Invalid opcode");
|
||||
|
||||
// Selects on vectors are actually vector selects.
|
||||
if (ISD == ISD::SELECT) {
|
||||
assert(CondTy && "CondTy must exist");
|
||||
if (CondTy->isVectorTy())
|
||||
ISD = ISD::VSELECT;
|
||||
}
|
||||
|
||||
std::pair<unsigned, MVT> LT = TLI->getTypeLegalizationCost(ValTy);
|
||||
|
||||
if (!(ValTy->isVectorTy() && !LT.second.isVector()) &&
|
||||
!TLI->isOperationExpand(ISD, LT.second)) {
|
||||
// The operation is legal. Assume it costs 1. Multiply
|
||||
// by the type-legalization overhead.
|
||||
return LT.first * 1;
|
||||
}
|
||||
|
||||
// Otherwise, assume that the cast is scalarized.
|
||||
if (ValTy->isVectorTy()) {
|
||||
unsigned Num = ValTy->getVectorNumElements();
|
||||
if (CondTy)
|
||||
CondTy = CondTy->getScalarType();
|
||||
unsigned Cost = static_cast<T *>(this)->getCmpSelInstrCost(
|
||||
Opcode, ValTy->getScalarType(), CondTy);
|
||||
|
||||
// Return the cost of multiple scalar invocation plus the cost of
|
||||
// inserting
|
||||
// and extracting the values.
|
||||
return getScalarizationOverhead(ValTy, true, false) + Num * Cost;
|
||||
}
|
||||
|
||||
// Unknown scalar opcode.
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) {
|
||||
std::pair<unsigned, MVT> LT =
|
||||
getTLI()->getTypeLegalizationCost(Val->getScalarType());
|
||||
|
||||
return LT.first;
|
||||
}
|
||||
|
||||
unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment,
|
||||
unsigned AddressSpace) {
|
||||
assert(!Src->isVoidTy() && "Invalid type");
|
||||
std::pair<unsigned, MVT> LT = getTLI()->getTypeLegalizationCost(Src);
|
||||
|
||||
// Assuming that all loads of legal types cost 1.
|
||||
unsigned Cost = LT.first;
|
||||
|
||||
if (Src->isVectorTy() &&
|
||||
Src->getPrimitiveSizeInBits() < LT.second.getSizeInBits()) {
|
||||
// This is a vector load that legalizes to a larger type than the vector
|
||||
// itself. Unless the corresponding extending load or truncating store is
|
||||
// legal, then this will scalarize.
|
||||
TargetLowering::LegalizeAction LA = TargetLowering::Expand;
|
||||
EVT MemVT = getTLI()->getValueType(Src, true);
|
||||
if (MemVT.isSimple() && MemVT != MVT::Other) {
|
||||
if (Opcode == Instruction::Store)
|
||||
LA = getTLI()->getTruncStoreAction(LT.second, MemVT.getSimpleVT());
|
||||
else
|
||||
LA = getTLI()->getLoadExtAction(ISD::EXTLOAD, LT.second, MemVT);
|
||||
}
|
||||
|
||||
if (LA != TargetLowering::Legal && LA != TargetLowering::Custom) {
|
||||
// This is a vector load/store for some illegal type that is scalarized.
|
||||
// We must account for the cost of building or decomposing the vector.
|
||||
Cost += getScalarizationOverhead(Src, Opcode != Instruction::Store,
|
||||
Opcode == Instruction::Store);
|
||||
}
|
||||
}
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
|
||||
ArrayRef<Type *> Tys) {
|
||||
unsigned ISD = 0;
|
||||
switch (IID) {
|
||||
default: {
|
||||
// Assume that we need to scalarize this intrinsic.
|
||||
unsigned ScalarizationCost = 0;
|
||||
unsigned ScalarCalls = 1;
|
||||
Type *ScalarRetTy = RetTy;
|
||||
if (RetTy->isVectorTy()) {
|
||||
ScalarizationCost = getScalarizationOverhead(RetTy, true, false);
|
||||
ScalarCalls = std::max(ScalarCalls, RetTy->getVectorNumElements());
|
||||
ScalarRetTy = RetTy->getScalarType();
|
||||
}
|
||||
SmallVector<Type *, 4> ScalarTys;
|
||||
for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) {
|
||||
Type *Ty = Tys[i];
|
||||
if (Ty->isVectorTy()) {
|
||||
ScalarizationCost += getScalarizationOverhead(Ty, false, true);
|
||||
ScalarCalls = std::max(ScalarCalls, Ty->getVectorNumElements());
|
||||
Ty = Ty->getScalarType();
|
||||
}
|
||||
ScalarTys.push_back(Ty);
|
||||
}
|
||||
if (ScalarCalls == 1)
|
||||
return 1; // Return cost of a scalar intrinsic. Assume it to be cheap.
|
||||
|
||||
unsigned ScalarCost = static_cast<T *>(this)->getIntrinsicInstrCost(
|
||||
IID, ScalarRetTy, ScalarTys);
|
||||
|
||||
return ScalarCalls * ScalarCost + ScalarizationCost;
|
||||
}
|
||||
// Look for intrinsics that can be lowered directly or turned into a scalar
|
||||
// intrinsic call.
|
||||
case Intrinsic::sqrt:
|
||||
ISD = ISD::FSQRT;
|
||||
break;
|
||||
case Intrinsic::sin:
|
||||
ISD = ISD::FSIN;
|
||||
break;
|
||||
case Intrinsic::cos:
|
||||
ISD = ISD::FCOS;
|
||||
break;
|
||||
case Intrinsic::exp:
|
||||
ISD = ISD::FEXP;
|
||||
break;
|
||||
case Intrinsic::exp2:
|
||||
ISD = ISD::FEXP2;
|
||||
break;
|
||||
case Intrinsic::log:
|
||||
ISD = ISD::FLOG;
|
||||
break;
|
||||
case Intrinsic::log10:
|
||||
ISD = ISD::FLOG10;
|
||||
break;
|
||||
case Intrinsic::log2:
|
||||
ISD = ISD::FLOG2;
|
||||
break;
|
||||
case Intrinsic::fabs:
|
||||
ISD = ISD::FABS;
|
||||
break;
|
||||
case Intrinsic::minnum:
|
||||
ISD = ISD::FMINNUM;
|
||||
break;
|
||||
case Intrinsic::maxnum:
|
||||
ISD = ISD::FMAXNUM;
|
||||
break;
|
||||
case Intrinsic::copysign:
|
||||
ISD = ISD::FCOPYSIGN;
|
||||
break;
|
||||
case Intrinsic::floor:
|
||||
ISD = ISD::FFLOOR;
|
||||
break;
|
||||
case Intrinsic::ceil:
|
||||
ISD = ISD::FCEIL;
|
||||
break;
|
||||
case Intrinsic::trunc:
|
||||
ISD = ISD::FTRUNC;
|
||||
break;
|
||||
case Intrinsic::nearbyint:
|
||||
ISD = ISD::FNEARBYINT;
|
||||
break;
|
||||
case Intrinsic::rint:
|
||||
ISD = ISD::FRINT;
|
||||
break;
|
||||
case Intrinsic::round:
|
||||
ISD = ISD::FROUND;
|
||||
break;
|
||||
case Intrinsic::pow:
|
||||
ISD = ISD::FPOW;
|
||||
break;
|
||||
case Intrinsic::fma:
|
||||
ISD = ISD::FMA;
|
||||
break;
|
||||
case Intrinsic::fmuladd:
|
||||
ISD = ISD::FMA;
|
||||
break;
|
||||
// FIXME: We should return 0 whenever getIntrinsicCost == TCC_Free.
|
||||
case Intrinsic::lifetime_start:
|
||||
case Intrinsic::lifetime_end:
|
||||
return 0;
|
||||
case Intrinsic::masked_store:
|
||||
return static_cast<T *>(this)
|
||||
->getMaskedMemoryOpCost(Instruction::Store, Tys[0], 0, 0);
|
||||
case Intrinsic::masked_load:
|
||||
return static_cast<T *>(this)
|
||||
->getMaskedMemoryOpCost(Instruction::Load, RetTy, 0, 0);
|
||||
}
|
||||
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
std::pair<unsigned, MVT> LT = TLI->getTypeLegalizationCost(RetTy);
|
||||
|
||||
if (TLI->isOperationLegalOrPromote(ISD, LT.second)) {
|
||||
// The operation is legal. Assume it costs 1.
|
||||
// If the type is split to multiple registers, assume that there is some
|
||||
// overhead to this.
|
||||
// TODO: Once we have extract/insert subvector cost we need to use them.
|
||||
if (LT.first > 1)
|
||||
return LT.first * 2;
|
||||
return LT.first * 1;
|
||||
}
|
||||
|
||||
if (!TLI->isOperationExpand(ISD, LT.second)) {
|
||||
// If the operation is custom lowered then assume
|
||||
// thare the code is twice as expensive.
|
||||
return LT.first * 2;
|
||||
}
|
||||
|
||||
// If we can't lower fmuladd into an FMA estimate the cost as a floating
|
||||
// point mul followed by an add.
|
||||
if (IID == Intrinsic::fmuladd)
|
||||
return static_cast<T *>(this)
|
||||
->getArithmeticInstrCost(BinaryOperator::FMul, RetTy) +
|
||||
static_cast<T *>(this)
|
||||
->getArithmeticInstrCost(BinaryOperator::FAdd, RetTy);
|
||||
|
||||
// Else, assume that we need to scalarize this intrinsic. For math builtins
|
||||
// this will emit a costly libcall, adding call overhead and spills. Make it
|
||||
// very expensive.
|
||||
if (RetTy->isVectorTy()) {
|
||||
unsigned ScalarizationCost = getScalarizationOverhead(RetTy, true, false);
|
||||
unsigned ScalarCalls = RetTy->getVectorNumElements();
|
||||
SmallVector<Type *, 4> ScalarTys;
|
||||
for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) {
|
||||
Type *Ty = Tys[i];
|
||||
if (Ty->isVectorTy())
|
||||
Ty = Ty->getScalarType();
|
||||
ScalarTys.push_back(Ty);
|
||||
}
|
||||
unsigned ScalarCost = static_cast<T *>(this)->getIntrinsicInstrCost(
|
||||
IID, RetTy->getScalarType(), ScalarTys);
|
||||
for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) {
|
||||
if (Tys[i]->isVectorTy()) {
|
||||
ScalarizationCost += getScalarizationOverhead(Tys[i], false, true);
|
||||
ScalarCalls = std::max(ScalarCalls, Tys[i]->getVectorNumElements());
|
||||
}
|
||||
}
|
||||
|
||||
return ScalarCalls * ScalarCost + ScalarizationCost;
|
||||
}
|
||||
|
||||
// This is going to be turned into a library call, make it expensive.
|
||||
return 10;
|
||||
}
|
||||
|
||||
/// \brief Compute a cost of the given call instruction.
|
||||
///
|
||||
/// Compute the cost of calling function F with return type RetTy and
|
||||
/// argument types Tys. F might be nullptr, in this case the cost of an
|
||||
/// arbitrary call with the specified signature will be returned.
|
||||
/// This is used, for instance, when we estimate call of a vector
|
||||
/// counterpart of the given function.
|
||||
/// \param F Called function, might be nullptr.
|
||||
/// \param RetTy Return value types.
|
||||
/// \param Tys Argument types.
|
||||
/// \returns The cost of Call instruction.
|
||||
unsigned getCallInstrCost(Function *F, Type *RetTy, ArrayRef<Type *> Tys) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
unsigned getNumberOfParts(Type *Tp) {
|
||||
std::pair<unsigned, MVT> LT = getTLI()->getTypeLegalizationCost(Tp);
|
||||
return LT.first;
|
||||
}
|
||||
|
||||
unsigned getAddressComputationCost(Type *Ty, bool IsComplex) { return 0; }
|
||||
|
||||
unsigned getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwise) {
|
||||
assert(Ty->isVectorTy() && "Expect a vector type");
|
||||
unsigned NumVecElts = Ty->getVectorNumElements();
|
||||
unsigned NumReduxLevels = Log2_32(NumVecElts);
|
||||
unsigned ArithCost =
|
||||
NumReduxLevels *
|
||||
static_cast<T *>(this)->getArithmeticInstrCost(Opcode, Ty);
|
||||
// Assume the pairwise shuffles add a cost.
|
||||
unsigned ShuffleCost =
|
||||
NumReduxLevels * (IsPairwise + 1) *
|
||||
static_cast<T *>(this)
|
||||
->getShuffleCost(TTI::SK_ExtractSubvector, Ty, NumVecElts / 2, Ty);
|
||||
return ShuffleCost + ArithCost + getScalarizationOverhead(Ty, false, true);
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// \brief Concrete BasicTTIImpl that can be used if no further customization
|
||||
/// is needed.
|
||||
class BasicTTIImpl : public BasicTTIImplBase<BasicTTIImpl> {
|
||||
typedef BasicTTIImplBase<BasicTTIImpl> BaseT;
|
||||
friend class BasicTTIImplBase<BasicTTIImpl>;
|
||||
|
||||
const TargetSubtargetInfo *ST;
|
||||
const TargetLoweringBase *TLI;
|
||||
|
||||
const TargetSubtargetInfo *getST() const { return ST; }
|
||||
const TargetLoweringBase *getTLI() const { return TLI; }
|
||||
|
||||
public:
|
||||
explicit BasicTTIImpl(const TargetMachine *ST, Function &F);
|
||||
|
||||
// Provide value semantics. MSVC requires that we spell all of these out.
|
||||
BasicTTIImpl(const BasicTTIImpl &Arg)
|
||||
: BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {}
|
||||
BasicTTIImpl(BasicTTIImpl &&Arg)
|
||||
: BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)),
|
||||
TLI(std::move(Arg.TLI)) {}
|
||||
BasicTTIImpl &operator=(const BasicTTIImpl &RHS) {
|
||||
BaseT::operator=(static_cast<const BaseT &>(RHS));
|
||||
ST = RHS.ST;
|
||||
TLI = RHS.TLI;
|
||||
return *this;
|
||||
}
|
||||
BasicTTIImpl &operator=(BasicTTIImpl &&RHS) {
|
||||
BaseT::operator=(std::move(static_cast<BaseT &>(RHS)));
|
||||
ST = std::move(RHS.ST);
|
||||
TLI = std::move(RHS.TLI);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -19,6 +19,7 @@
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Target/TargetCallingConv.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -313,13 +314,13 @@ class CCState {
|
||||
/// produce a single value.
|
||||
void AnalyzeCallResult(MVT VT, CCAssignFn Fn);
|
||||
|
||||
/// getFirstUnallocated - Return the first unallocated register in the set, or
|
||||
/// NumRegs if they are all allocated.
|
||||
unsigned getFirstUnallocated(const MCPhysReg *Regs, unsigned NumRegs) const {
|
||||
for (unsigned i = 0; i != NumRegs; ++i)
|
||||
/// getFirstUnallocated - Return the index of the first unallocated register
|
||||
/// in the set, or Regs.size() if they are all allocated.
|
||||
unsigned getFirstUnallocated(ArrayRef<MCPhysReg> Regs) const {
|
||||
for (unsigned i = 0; i < Regs.size(); ++i)
|
||||
if (!isAllocated(Regs[i]))
|
||||
return i;
|
||||
return NumRegs;
|
||||
return Regs.size();
|
||||
}
|
||||
|
||||
/// AllocateReg - Attempt to allocate one register. If it is not available,
|
||||
@ -342,9 +343,9 @@ class CCState {
|
||||
/// AllocateReg - Attempt to allocate one of the specified registers. If none
|
||||
/// are available, return zero. Otherwise, return the first one available,
|
||||
/// marking it and any aliases as allocated.
|
||||
unsigned AllocateReg(const MCPhysReg *Regs, unsigned NumRegs) {
|
||||
unsigned FirstUnalloc = getFirstUnallocated(Regs, NumRegs);
|
||||
if (FirstUnalloc == NumRegs)
|
||||
unsigned AllocateReg(ArrayRef<MCPhysReg> Regs) {
|
||||
unsigned FirstUnalloc = getFirstUnallocated(Regs);
|
||||
if (FirstUnalloc == Regs.size())
|
||||
return 0; // Didn't find the reg.
|
||||
|
||||
// Mark the register and any aliases as allocated.
|
||||
@ -383,10 +384,9 @@ class CCState {
|
||||
}
|
||||
|
||||
/// Version of AllocateReg with list of registers to be shadowed.
|
||||
unsigned AllocateReg(const MCPhysReg *Regs, const MCPhysReg *ShadowRegs,
|
||||
unsigned NumRegs) {
|
||||
unsigned FirstUnalloc = getFirstUnallocated(Regs, NumRegs);
|
||||
if (FirstUnalloc == NumRegs)
|
||||
unsigned AllocateReg(ArrayRef<MCPhysReg> Regs, const MCPhysReg *ShadowRegs) {
|
||||
unsigned FirstUnalloc = getFirstUnallocated(Regs);
|
||||
if (FirstUnalloc == Regs.size())
|
||||
return 0; // Didn't find the reg.
|
||||
|
||||
// Mark the register and any aliases as allocated.
|
||||
@ -416,8 +416,8 @@ class CCState {
|
||||
/// Version of AllocateStack with list of extra registers to be shadowed.
|
||||
/// Note that, unlike AllocateReg, this shadows ALL of the shadow registers.
|
||||
unsigned AllocateStack(unsigned Size, unsigned Align,
|
||||
const MCPhysReg *ShadowRegs, unsigned NumShadowRegs) {
|
||||
for (unsigned i = 0; i < NumShadowRegs; ++i)
|
||||
ArrayRef<MCPhysReg> ShadowRegs) {
|
||||
for (unsigned i = 0; i < ShadowRegs.size(); ++i)
|
||||
MarkAllocated(ShadowRegs[i]);
|
||||
return AllocateStack(Size, Align);
|
||||
}
|
||||
|
@ -16,9 +16,12 @@
|
||||
#ifndef LLVM_CODEGEN_COMMANDFLAGS_H
|
||||
#define LLVM_CODEGEN_COMMANDFLAGS_H
|
||||
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
|
||||
#include "llvm//MC/SubtargetFeature.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include <string>
|
||||
@ -123,11 +126,6 @@ EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
|
||||
cl::desc("Force codegen to assume rounding mode can change dynamically"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool>
|
||||
GenerateSoftFloatCalls("soft-float",
|
||||
cl::desc("Generate software floating point library calls"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<llvm::FloatABI::ABIType>
|
||||
FloatABIForCalls("float-abi",
|
||||
cl::desc("Choose float ABI type"),
|
||||
@ -207,6 +205,10 @@ FunctionSections("function-sections",
|
||||
cl::desc("Emit functions into separate sections"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool> UniqueSectionNames("unique-section-names",
|
||||
cl::desc("Give unique names to every section"),
|
||||
cl::init(true));
|
||||
|
||||
cl::opt<llvm::JumpTable::JumpTableType>
|
||||
JTableType("jump-table-type",
|
||||
cl::desc("Choose the type of Jump-Instruction Table for jumptable."),
|
||||
@ -222,57 +224,17 @@ JTableType("jump-table-type",
|
||||
"Create one table per unique function type."),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<bool>
|
||||
FCFI("fcfi",
|
||||
cl::desc("Apply forward-edge control-flow integrity"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<llvm::CFIntegrity>
|
||||
CFIType("cfi-type",
|
||||
cl::desc("Choose the type of Control-Flow Integrity check to add"),
|
||||
cl::init(CFIntegrity::Sub),
|
||||
cl::values(
|
||||
clEnumValN(CFIntegrity::Sub, "sub",
|
||||
"Subtract the pointer from the table base, then mask."),
|
||||
clEnumValN(CFIntegrity::Ror, "ror",
|
||||
"Use rotate to check the offset from a table base."),
|
||||
clEnumValN(CFIntegrity::Add, "add",
|
||||
"Mask out the high bits and add to an aligned base."),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<bool>
|
||||
CFIEnforcing("cfi-enforcing",
|
||||
cl::desc("Enforce CFI or pass the violation to a function."),
|
||||
cl::init(false));
|
||||
|
||||
// Note that this option is linked to the cfi-enforcing option above: if
|
||||
// cfi-enforcing is set, then the cfi-func-name option is entirely ignored. If
|
||||
// cfi-enforcing is false and no cfi-func-name is set, then a default function
|
||||
// will be generated that ignores all CFI violations. The expected signature for
|
||||
// functions called with CFI violations is
|
||||
//
|
||||
// void (i8*, i8*)
|
||||
//
|
||||
// The first pointer is a C string containing the name of the function in which
|
||||
// the violation occurs, and the second pointer is the pointer that violated
|
||||
// CFI.
|
||||
cl::opt<std::string>
|
||||
CFIFuncName("cfi-func-name", cl::desc("The name of the CFI function to call"),
|
||||
cl::init(""));
|
||||
|
||||
// Common utility function tightly tied to the options listed here. Initializes
|
||||
// a TargetOptions object with CodeGen flags and returns it.
|
||||
static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||
TargetOptions Options;
|
||||
Options.LessPreciseFPMADOption = EnableFPMAD;
|
||||
Options.NoFramePointerElim = DisableFPElim;
|
||||
Options.AllowFPOpFusion = FuseFPOps;
|
||||
Options.UnsafeFPMath = EnableUnsafeFPMath;
|
||||
Options.NoInfsFPMath = EnableNoInfsFPMath;
|
||||
Options.NoNaNsFPMath = EnableNoNaNsFPMath;
|
||||
Options.HonorSignDependentRoundingFPMathOption =
|
||||
EnableHonorSignDependentRoundingFPMath;
|
||||
Options.UseSoftFloat = GenerateSoftFloatCalls;
|
||||
if (FloatABIForCalls != FloatABI::Default)
|
||||
Options.FloatABIType = FloatABIForCalls;
|
||||
Options.NoZerosInBSS = DontPlaceZerosInBSS;
|
||||
@ -284,17 +246,71 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||
Options.UseInitArray = !UseCtors;
|
||||
Options.DataSections = DataSections;
|
||||
Options.FunctionSections = FunctionSections;
|
||||
Options.UniqueSectionNames = UniqueSectionNames;
|
||||
|
||||
Options.MCOptions = InitMCTargetOptionsFromFlags();
|
||||
Options.JTType = JTableType;
|
||||
Options.FCFI = FCFI;
|
||||
Options.CFIType = CFIType;
|
||||
Options.CFIEnforcing = CFIEnforcing;
|
||||
Options.CFIFuncName = CFIFuncName;
|
||||
|
||||
Options.ThreadModel = TMModel;
|
||||
|
||||
return Options;
|
||||
}
|
||||
|
||||
static inline std::string getCPUStr() {
|
||||
// If user asked for the 'native' CPU, autodetect here. If autodection fails,
|
||||
// this will set the CPU to an empty string which tells the target to
|
||||
// pick a basic default.
|
||||
if (MCPU == "native")
|
||||
return sys::getHostCPUName();
|
||||
|
||||
return MCPU;
|
||||
}
|
||||
|
||||
static inline std::string getFeaturesStr() {
|
||||
SubtargetFeatures Features;
|
||||
|
||||
// If user asked for the 'native' CPU, we need to autodetect features.
|
||||
// This is necessary for x86 where the CPU might not support all the
|
||||
// features the autodetected CPU name lists in the target. For example,
|
||||
// not all Sandybridge processors support AVX.
|
||||
if (MCPU == "native") {
|
||||
StringMap<bool> HostFeatures;
|
||||
if (sys::getHostCPUFeatures(HostFeatures))
|
||||
for (auto &F : HostFeatures)
|
||||
Features.AddFeature(F.first(), F.second);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i != MAttrs.size(); ++i)
|
||||
Features.AddFeature(MAttrs[i]);
|
||||
|
||||
return Features.getString();
|
||||
}
|
||||
|
||||
/// \brief Set function attributes of functions in Module M based on CPU,
|
||||
/// Features, and command line flags.
|
||||
static inline void setFunctionAttributes(StringRef CPU, StringRef Features,
|
||||
Module &M) {
|
||||
for (auto &F : M) {
|
||||
auto &Ctx = F.getContext();
|
||||
AttributeSet Attrs = F.getAttributes(), NewAttrs;
|
||||
|
||||
if (!CPU.empty())
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
"target-cpu", CPU);
|
||||
|
||||
if (!Features.empty())
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
"target-features", Features);
|
||||
|
||||
if (DisableFPElim.getNumOccurrences() > 0)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex,
|
||||
"no-frame-pointer-elim",
|
||||
DisableFPElim ? "true" : "false");
|
||||
|
||||
// Let NewAttrs override Attrs.
|
||||
NewAttrs = Attrs.addAttributes(Ctx, AttributeSet::FunctionIndex, NewAttrs);
|
||||
F.setAttributes(NewAttrs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include <vector>
|
||||
|
||||
@ -95,7 +96,7 @@ class DIEAbbrev : public FoldingSetNode {
|
||||
|
||||
/// Emit - Print the abbreviation using the specified asm printer.
|
||||
///
|
||||
void Emit(AsmPrinter *AP) const;
|
||||
void Emit(const AsmPrinter *AP) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O);
|
||||
@ -200,8 +201,6 @@ class DIE {
|
||||
/// to DWARF attribute classes.
|
||||
///
|
||||
class DIEValue {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
isInteger,
|
||||
@ -216,13 +215,14 @@ class DIEValue {
|
||||
isLocList,
|
||||
};
|
||||
|
||||
protected:
|
||||
private:
|
||||
/// Ty - Type of data stored in the value.
|
||||
///
|
||||
Type Ty;
|
||||
|
||||
protected:
|
||||
explicit DIEValue(Type T) : Ty(T) {}
|
||||
virtual ~DIEValue() {}
|
||||
~DIEValue() {}
|
||||
|
||||
public:
|
||||
// Accessors
|
||||
@ -230,14 +230,14 @@ class DIEValue {
|
||||
|
||||
/// EmitValue - Emit value via the Dwarf writer.
|
||||
///
|
||||
virtual void EmitValue(AsmPrinter *AP, dwarf::Form Form) const = 0;
|
||||
void EmitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
/// SizeOf - Return the size of a value in bytes.
|
||||
///
|
||||
virtual unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const = 0;
|
||||
unsigned SizeOf(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
virtual void print(raw_ostream &O) const = 0;
|
||||
void print(raw_ostream &O) const;
|
||||
void dump() const;
|
||||
#endif
|
||||
};
|
||||
@ -246,6 +246,8 @@ class DIEValue {
|
||||
/// DIEInteger - An integer value DIE.
|
||||
///
|
||||
class DIEInteger : public DIEValue {
|
||||
friend DIEValue;
|
||||
|
||||
uint64_t Integer;
|
||||
|
||||
public:
|
||||
@ -273,21 +275,18 @@ class DIEInteger : public DIEValue {
|
||||
return dwarf::DW_FORM_data8;
|
||||
}
|
||||
|
||||
/// EmitValue - Emit integer of appropriate size.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
uint64_t getValue() const { return Integer; }
|
||||
|
||||
/// SizeOf - Determine size of integer value in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
void setValue(uint64_t Val) { Integer = Val; }
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *I) { return I->getType() == isInteger; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -295,28 +294,26 @@ class DIEInteger : public DIEValue {
|
||||
/// DIEExpr - An expression DIE.
|
||||
//
|
||||
class DIEExpr : public DIEValue {
|
||||
friend class DIEValue;
|
||||
|
||||
const MCExpr *Expr;
|
||||
|
||||
public:
|
||||
explicit DIEExpr(const MCExpr *E) : DIEValue(isExpr), Expr(E) {}
|
||||
|
||||
/// EmitValue - Emit expression value.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// getValue - Get MCExpr.
|
||||
///
|
||||
const MCExpr *getValue() const { return Expr; }
|
||||
|
||||
/// SizeOf - Determine size of expression value in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *E) { return E->getType() == isExpr; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -324,28 +321,26 @@ class DIEExpr : public DIEValue {
|
||||
/// DIELabel - A label DIE.
|
||||
//
|
||||
class DIELabel : public DIEValue {
|
||||
friend class DIEValue;
|
||||
|
||||
const MCSymbol *Label;
|
||||
|
||||
public:
|
||||
explicit DIELabel(const MCSymbol *L) : DIEValue(isLabel), Label(L) {}
|
||||
|
||||
/// EmitValue - Emit label value.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// getValue - Get MCSymbol.
|
||||
///
|
||||
const MCSymbol *getValue() const { return Label; }
|
||||
|
||||
/// SizeOf - Determine size of label value in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *L) { return L->getType() == isLabel; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -353,6 +348,8 @@ class DIELabel : public DIEValue {
|
||||
/// DIEDelta - A simple label difference DIE.
|
||||
///
|
||||
class DIEDelta : public DIEValue {
|
||||
friend class DIEValue;
|
||||
|
||||
const MCSymbol *LabelHi;
|
||||
const MCSymbol *LabelLo;
|
||||
|
||||
@ -360,19 +357,15 @@ class DIEDelta : public DIEValue {
|
||||
DIEDelta(const MCSymbol *Hi, const MCSymbol *Lo)
|
||||
: DIEValue(isDelta), LabelHi(Hi), LabelLo(Lo) {}
|
||||
|
||||
/// EmitValue - Emit delta value.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// SizeOf - Determine size of delta value in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *D) { return D->getType() == isDelta; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -380,29 +373,25 @@ class DIEDelta : public DIEValue {
|
||||
/// DIEString - A container for string values.
|
||||
///
|
||||
class DIEString : public DIEValue {
|
||||
const DIEValue *Access;
|
||||
StringRef Str;
|
||||
friend class DIEValue;
|
||||
|
||||
DwarfStringPoolEntryRef S;
|
||||
|
||||
public:
|
||||
DIEString(const DIEValue *Acc, StringRef S)
|
||||
: DIEValue(isString), Access(Acc), Str(S) {}
|
||||
DIEString(DwarfStringPoolEntryRef S) : DIEValue(isString), S(S) {}
|
||||
|
||||
/// getString - Grab the string out of the object.
|
||||
StringRef getString() const { return Str; }
|
||||
|
||||
/// EmitValue - Emit delta value.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// SizeOf - Determine size of delta value in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
StringRef getString() const { return S.getString(); }
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *D) { return D->getType() == isString; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -411,6 +400,8 @@ class DIEString : public DIEValue {
|
||||
/// this class can also be used as a proxy for a debug information entry not
|
||||
/// yet defined (ie. types.)
|
||||
class DIEEntry : public DIEValue {
|
||||
friend class DIEValue;
|
||||
|
||||
DIE &Entry;
|
||||
|
||||
public:
|
||||
@ -419,53 +410,49 @@ class DIEEntry : public DIEValue {
|
||||
|
||||
DIE &getEntry() const { return Entry; }
|
||||
|
||||
/// EmitValue - Emit debug information entry offset.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// SizeOf - Determine size of debug information entry in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override {
|
||||
return Form == dwarf::DW_FORM_ref_addr ? getRefAddrSize(AP)
|
||||
: sizeof(int32_t);
|
||||
}
|
||||
|
||||
/// Returns size of a ref_addr entry.
|
||||
static unsigned getRefAddrSize(AsmPrinter *AP);
|
||||
static unsigned getRefAddrSize(const AsmPrinter *AP);
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *E) { return E->getType() == isEntry; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
return Form == dwarf::DW_FORM_ref_addr ? getRefAddrSize(AP)
|
||||
: sizeof(int32_t);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// \brief A signature reference to a type unit.
|
||||
class DIETypeSignature : public DIEValue {
|
||||
friend class DIEValue;
|
||||
|
||||
const DwarfTypeUnit &Unit;
|
||||
|
||||
public:
|
||||
explicit DIETypeSignature(const DwarfTypeUnit &Unit)
|
||||
: DIEValue(isTypeSignature), Unit(Unit) {}
|
||||
|
||||
/// \brief Emit type unit signature.
|
||||
void EmitValue(AsmPrinter *Asm, dwarf::Form Form) const override;
|
||||
|
||||
/// Returns size of a ref_sig8 entry.
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override {
|
||||
assert(Form == dwarf::DW_FORM_ref_sig8);
|
||||
return 8;
|
||||
}
|
||||
|
||||
// \brief Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *E) {
|
||||
return E->getType() == isTypeSignature;
|
||||
}
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
assert(Form == dwarf::DW_FORM_ref_sig8);
|
||||
return 8;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void dump() const;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -473,13 +460,15 @@ class DIETypeSignature : public DIEValue {
|
||||
/// DIELoc - Represents an expression location.
|
||||
//
|
||||
class DIELoc : public DIEValue, public DIE {
|
||||
friend class DIEValue;
|
||||
|
||||
mutable unsigned Size; // Size in bytes excluding size header.
|
||||
public:
|
||||
DIELoc() : DIEValue(isLoc), Size(0) {}
|
||||
|
||||
/// ComputeSize - Calculate the size of the location expression.
|
||||
///
|
||||
unsigned ComputeSize(AsmPrinter *AP) const;
|
||||
unsigned ComputeSize(const AsmPrinter *AP) const;
|
||||
|
||||
/// BestForm - Choose the best form for data.
|
||||
///
|
||||
@ -496,19 +485,15 @@ class DIELoc : public DIEValue, public DIE {
|
||||
return dwarf::DW_FORM_block;
|
||||
}
|
||||
|
||||
/// EmitValue - Emit location data.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// SizeOf - Determine size of location data in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *E) { return E->getType() == isLoc; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -516,13 +501,15 @@ class DIELoc : public DIEValue, public DIE {
|
||||
/// DIEBlock - Represents a block of values.
|
||||
//
|
||||
class DIEBlock : public DIEValue, public DIE {
|
||||
friend class DIEValue;
|
||||
|
||||
mutable unsigned Size; // Size in bytes excluding size header.
|
||||
public:
|
||||
DIEBlock() : DIEValue(isBlock), Size(0) {}
|
||||
|
||||
/// ComputeSize - Calculate the size of the location expression.
|
||||
///
|
||||
unsigned ComputeSize(AsmPrinter *AP) const;
|
||||
unsigned ComputeSize(const AsmPrinter *AP) const;
|
||||
|
||||
/// BestForm - Choose the best form for data.
|
||||
///
|
||||
@ -536,19 +523,15 @@ class DIEBlock : public DIEValue, public DIE {
|
||||
return dwarf::DW_FORM_block;
|
||||
}
|
||||
|
||||
/// EmitValue - Emit location data.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// SizeOf - Determine size of location data in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *E) { return E->getType() == isBlock; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -557,6 +540,8 @@ class DIEBlock : public DIEValue, public DIE {
|
||||
/// section.
|
||||
//
|
||||
class DIELocList : public DIEValue {
|
||||
friend class DIEValue;
|
||||
|
||||
// Index into the .debug_loc vector.
|
||||
size_t Index;
|
||||
|
||||
@ -566,19 +551,15 @@ class DIELocList : public DIEValue {
|
||||
/// getValue - Grab the current index out.
|
||||
size_t getValue() const { return Index; }
|
||||
|
||||
/// EmitValue - Emit location data.
|
||||
///
|
||||
void EmitValue(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
/// SizeOf - Determine size of location data in bytes.
|
||||
///
|
||||
unsigned SizeOf(AsmPrinter *AP, dwarf::Form Form) const override;
|
||||
|
||||
// Implement isa/cast/dyncast.
|
||||
static bool classof(const DIEValue *E) { return E->getType() == isLocList; }
|
||||
|
||||
private:
|
||||
void EmitValueImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned SizeOfImpl(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &O) const override;
|
||||
void printImpl(raw_ostream &O) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
51
contrib/llvm/include/llvm/CodeGen/DwarfStringPoolEntry.h
Normal file
51
contrib/llvm/include/llvm/CodeGen/DwarfStringPoolEntry.h
Normal file
@ -0,0 +1,51 @@
|
||||
//===- llvm/CodeGen/DwarfStringPoolEntry.h - String pool entry --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H
|
||||
#define LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCSymbol;
|
||||
|
||||
/// Data for a string pool entry.
|
||||
struct DwarfStringPoolEntry {
|
||||
MCSymbol *Symbol;
|
||||
unsigned Offset;
|
||||
unsigned Index;
|
||||
};
|
||||
|
||||
/// String pool entry reference.
|
||||
struct DwarfStringPoolEntryRef {
|
||||
const StringMapEntry<DwarfStringPoolEntry> *I = nullptr;
|
||||
|
||||
public:
|
||||
DwarfStringPoolEntryRef() = default;
|
||||
explicit DwarfStringPoolEntryRef(
|
||||
const StringMapEntry<DwarfStringPoolEntry> &I)
|
||||
: I(&I) {}
|
||||
|
||||
explicit operator bool() const { return I; }
|
||||
MCSymbol *getSymbol() const {
|
||||
assert(I->second.Symbol && "No symbol available!");
|
||||
return I->second.Symbol;
|
||||
}
|
||||
unsigned getOffset() const { return I->second.Offset; }
|
||||
unsigned getIndex() const { return I->second.Index; }
|
||||
StringRef getString() const { return I->first(); }
|
||||
|
||||
bool operator==(const DwarfStringPoolEntryRef &X) const { return I == X.I; }
|
||||
bool operator!=(const DwarfStringPoolEntryRef &X) const { return I != X.I; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,122 +0,0 @@
|
||||
//===-- ForwardControlFlowIntegrity.h: Forward-Edge CFI ---------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass instruments indirect calls with checks to ensure that these calls
|
||||
// pass through the appropriate jump-instruction table generated by
|
||||
// JumpInstrTables.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
|
||||
#define LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AnalysisUsage;
|
||||
class BasicBlock;
|
||||
class Constant;
|
||||
class Function;
|
||||
class Instruction;
|
||||
class Module;
|
||||
class Value;
|
||||
|
||||
/// ForwardControlFlowIntegrity uses the information from JumpInstrTableInfo to
|
||||
/// prepend checks to indirect calls to make sure that these calls target valid
|
||||
/// locations.
|
||||
class ForwardControlFlowIntegrity : public ModulePass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
ForwardControlFlowIntegrity();
|
||||
ForwardControlFlowIntegrity(JumpTable::JumpTableType JTT,
|
||||
CFIntegrity CFIType,
|
||||
bool CFIEnforcing, std::string CFIFuncName);
|
||||
~ForwardControlFlowIntegrity() override;
|
||||
|
||||
/// Runs the CFI pass on a given module. This works best if the module in
|
||||
/// question is the result of link-time optimization (see lib/LTO).
|
||||
bool runOnModule(Module &M) override;
|
||||
const char *getPassName() const override {
|
||||
return "Forward Control-Flow Integrity";
|
||||
}
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
private:
|
||||
typedef SmallVector<Instruction *, 64> CallSet;
|
||||
|
||||
/// A structure that is used to keep track of constant table information.
|
||||
struct CFIConstants {
|
||||
Constant *StartValue;
|
||||
Constant *MaskValue;
|
||||
Constant *Size;
|
||||
};
|
||||
|
||||
/// A map from function type to the base of the table for this type and a mask
|
||||
/// for the table
|
||||
typedef DenseMap<FunctionType *, CFIConstants> CFITables;
|
||||
|
||||
CallSet IndirectCalls;
|
||||
|
||||
/// The type of jumptable implementation.
|
||||
JumpTable::JumpTableType JTType;
|
||||
|
||||
/// The type of CFI check to add before each indirect call.
|
||||
CFIntegrity CFIType;
|
||||
|
||||
/// A value that controls whether or not CFI violations cause a halt.
|
||||
bool CFIEnforcing;
|
||||
|
||||
/// The name of the function to call in case of a CFI violation when
|
||||
/// CFIEnforcing is false. There is a default function that ignores
|
||||
/// violations.
|
||||
std::string CFIFuncName;
|
||||
|
||||
/// The alignment of each entry in the table, from JumpInstrTableInfo. The
|
||||
/// JumpInstrTableInfo class always makes this a power of two.
|
||||
uint64_t ByteAlignment;
|
||||
|
||||
/// The base-2 logarithm of ByteAlignment, needed for some of the transforms
|
||||
/// (like CFIntegrity::Ror)
|
||||
unsigned LogByteAlignment;
|
||||
|
||||
/// Adds checks to each indirect call site to make sure that it is calling a
|
||||
/// function in our jump table.
|
||||
void updateIndirectCalls(Module &M, CFITables &CFIT);
|
||||
|
||||
/// Walks the instructions to find all the indirect calls.
|
||||
void getIndirectCalls(Module &M);
|
||||
|
||||
/// Adds a function that handles violations in non-enforcing mode
|
||||
/// (!CFIEnforcing). The default warning function simply returns, since the
|
||||
/// exact details of how to handle CFI violations depend on the application.
|
||||
void addWarningFunction(Module &M);
|
||||
|
||||
/// Rewrites a function pointer in a call/invoke instruction to force it into
|
||||
/// a table.
|
||||
void rewriteFunctionPointer(Module &M, Instruction *I, Value *FunPtr,
|
||||
Constant *JumpTableStart, Constant *JumpTableMask,
|
||||
Constant *JumpTableSize);
|
||||
|
||||
/// Inserts a check and a call to a warning function at a given instruction
|
||||
/// that must be an indirect call.
|
||||
void insertWarning(Module &M, BasicBlock *Block, Instruction *I,
|
||||
Value *FunPtr);
|
||||
};
|
||||
|
||||
ModulePass *
|
||||
createForwardControlFlowIntegrityPass(JumpTable::JumpTableType JTT,
|
||||
CFIntegrity CFIType,
|
||||
bool CFIEnforcing, StringRef CFIFuncName);
|
||||
}
|
||||
|
||||
#endif // LLVM_CODEGEN_FORWARDCONTROLFLOWINTEGRITY_H
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/ISDOpcodes.h"
|
||||
@ -73,6 +74,16 @@ class FunctionLoweringInfo {
|
||||
/// cross-basic-block values.
|
||||
DenseMap<const Value*, unsigned> ValueMap;
|
||||
|
||||
// Keep track of frame indices allocated for statepoints as they could be used
|
||||
// across basic block boundaries.
|
||||
// Key of the map is statepoint instruction, value is a map from spilled
|
||||
// llvm Value to the optional stack stack slot index.
|
||||
// If optional is unspecified it means that we have visited this value
|
||||
// but didn't spill it.
|
||||
typedef DenseMap<const Value*, Optional<int>> StatepointSpilledValueMapTy;
|
||||
DenseMap<const Instruction*, StatepointSpilledValueMapTy>
|
||||
StatepointRelocatedValues;
|
||||
|
||||
/// StaticAllocaMap - Keep track of frame indices for fixed sized allocas in
|
||||
/// the entry block. This allows the allocas to be efficiently referenced
|
||||
/// anywhere in the function.
|
||||
@ -221,6 +232,8 @@ class FunctionLoweringInfo {
|
||||
int getArgumentFrameIndex(const Argument *A);
|
||||
|
||||
private:
|
||||
void addSEHHandlersForLPads(ArrayRef<const LandingPadInst *> LPads);
|
||||
|
||||
/// LiveOutRegInfo - Information about live out vregs.
|
||||
IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;
|
||||
};
|
||||
@ -232,11 +245,6 @@ class FunctionLoweringInfo {
|
||||
/// floating-point support.
|
||||
void ComputeUsesVAFloatArgument(const CallInst &I, MachineModuleInfo *MMI);
|
||||
|
||||
/// AddCatchInfo - Extract the personality and type infos from an eh.selector
|
||||
/// call, and add them to the specified machine basic block.
|
||||
void AddCatchInfo(const CallInst &I,
|
||||
MachineModuleInfo *MMI, MachineBasicBlock *MBB);
|
||||
|
||||
/// AddLandingPadInfo - Extract the exception handling information from the
|
||||
/// landingpad instruction and add them to the specified machine module info.
|
||||
void AddLandingPadInfo(const LandingPadInst &I, MachineModuleInfo &MMI,
|
||||
|
@ -34,184 +34,173 @@
|
||||
#define LLVM_CODEGEN_GCMETADATA_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/CodeGen/GCStrategy.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
class AsmPrinter;
|
||||
class GCStrategy;
|
||||
class Constant;
|
||||
class MCSymbol;
|
||||
class AsmPrinter;
|
||||
class Constant;
|
||||
class MCSymbol;
|
||||
|
||||
namespace GC {
|
||||
/// PointKind - The type of a collector-safe point.
|
||||
///
|
||||
enum PointKind {
|
||||
Loop, ///< Instr is a loop (backwards branch).
|
||||
Return, ///< Instr is a return instruction.
|
||||
PreCall, ///< Instr is a call instruction.
|
||||
PostCall ///< Instr is the return address of a call.
|
||||
};
|
||||
/// GCPoint - Metadata for a collector-safe point in machine code.
|
||||
///
|
||||
struct GCPoint {
|
||||
GC::PointKind Kind; ///< The kind of the safe point.
|
||||
MCSymbol *Label; ///< A label.
|
||||
DebugLoc Loc;
|
||||
|
||||
GCPoint(GC::PointKind K, MCSymbol *L, DebugLoc DL)
|
||||
: Kind(K), Label(L), Loc(DL) {}
|
||||
};
|
||||
|
||||
/// GCRoot - Metadata for a pointer to an object managed by the garbage
|
||||
/// collector.
|
||||
struct GCRoot {
|
||||
int Num; ///< Usually a frame index.
|
||||
int StackOffset; ///< Offset from the stack pointer.
|
||||
const Constant *Metadata; ///< Metadata straight from the call
|
||||
///< to llvm.gcroot.
|
||||
|
||||
GCRoot(int N, const Constant *MD) : Num(N), StackOffset(-1), Metadata(MD) {}
|
||||
};
|
||||
|
||||
/// Garbage collection metadata for a single function. Currently, this
|
||||
/// information only applies to GCStrategies which use GCRoot.
|
||||
class GCFunctionInfo {
|
||||
public:
|
||||
typedef std::vector<GCPoint>::iterator iterator;
|
||||
typedef std::vector<GCRoot>::iterator roots_iterator;
|
||||
typedef std::vector<GCRoot>::const_iterator live_iterator;
|
||||
|
||||
private:
|
||||
const Function &F;
|
||||
GCStrategy &S;
|
||||
uint64_t FrameSize;
|
||||
std::vector<GCRoot> Roots;
|
||||
std::vector<GCPoint> SafePoints;
|
||||
|
||||
// FIXME: Liveness. A 2D BitVector, perhaps?
|
||||
//
|
||||
// BitVector Liveness;
|
||||
//
|
||||
// bool islive(int point, int root) =
|
||||
// Liveness[point * SafePoints.size() + root]
|
||||
//
|
||||
// The bit vector is the more compact representation where >3.2% of roots
|
||||
// are live per safe point (1.5% on 64-bit hosts).
|
||||
|
||||
public:
|
||||
GCFunctionInfo(const Function &F, GCStrategy &S);
|
||||
~GCFunctionInfo();
|
||||
|
||||
/// getFunction - Return the function to which this metadata applies.
|
||||
///
|
||||
const Function &getFunction() const { return F; }
|
||||
|
||||
/// getStrategy - Return the GC strategy for the function.
|
||||
///
|
||||
GCStrategy &getStrategy() { return S; }
|
||||
|
||||
/// addStackRoot - Registers a root that lives on the stack. Num is the
|
||||
/// stack object ID for the alloca (if the code generator is
|
||||
// using MachineFrameInfo).
|
||||
void addStackRoot(int Num, const Constant *Metadata) {
|
||||
Roots.push_back(GCRoot(Num, Metadata));
|
||||
}
|
||||
|
||||
/// GCPoint - Metadata for a collector-safe point in machine code.
|
||||
/// removeStackRoot - Removes a root.
|
||||
roots_iterator removeStackRoot(roots_iterator position) {
|
||||
return Roots.erase(position);
|
||||
}
|
||||
|
||||
/// addSafePoint - Notes the existence of a safe point. Num is the ID of the
|
||||
/// label just prior to the safe point (if the code generator is using
|
||||
/// MachineModuleInfo).
|
||||
void addSafePoint(GC::PointKind Kind, MCSymbol *Label, DebugLoc DL) {
|
||||
SafePoints.push_back(GCPoint(Kind, Label, DL));
|
||||
}
|
||||
|
||||
/// getFrameSize/setFrameSize - Records the function's frame size.
|
||||
///
|
||||
struct GCPoint {
|
||||
GC::PointKind Kind; ///< The kind of the safe point.
|
||||
MCSymbol *Label; ///< A label.
|
||||
DebugLoc Loc;
|
||||
uint64_t getFrameSize() const { return FrameSize; }
|
||||
void setFrameSize(uint64_t S) { FrameSize = S; }
|
||||
|
||||
GCPoint(GC::PointKind K, MCSymbol *L, DebugLoc DL)
|
||||
: Kind(K), Label(L), Loc(DL) {}
|
||||
};
|
||||
/// begin/end - Iterators for safe points.
|
||||
///
|
||||
iterator begin() { return SafePoints.begin(); }
|
||||
iterator end() { return SafePoints.end(); }
|
||||
size_t size() const { return SafePoints.size(); }
|
||||
|
||||
/// GCRoot - Metadata for a pointer to an object managed by the garbage
|
||||
/// collector.
|
||||
struct GCRoot {
|
||||
int Num; ///< Usually a frame index.
|
||||
int StackOffset; ///< Offset from the stack pointer.
|
||||
const Constant *Metadata; ///< Metadata straight from the call
|
||||
///< to llvm.gcroot.
|
||||
/// roots_begin/roots_end - Iterators for all roots in the function.
|
||||
///
|
||||
roots_iterator roots_begin() { return Roots.begin(); }
|
||||
roots_iterator roots_end() { return Roots.end(); }
|
||||
size_t roots_size() const { return Roots.size(); }
|
||||
|
||||
GCRoot(int N, const Constant *MD) : Num(N), StackOffset(-1), Metadata(MD) {}
|
||||
};
|
||||
/// live_begin/live_end - Iterators for live roots at a given safe point.
|
||||
///
|
||||
live_iterator live_begin(const iterator &p) { return roots_begin(); }
|
||||
live_iterator live_end(const iterator &p) { return roots_end(); }
|
||||
size_t live_size(const iterator &p) const { return roots_size(); }
|
||||
};
|
||||
|
||||
/// An analysis pass which caches information about the entire Module.
|
||||
/// Records both the function level information used by GCRoots and a
|
||||
/// cache of the 'active' gc strategy objects for the current Module.
|
||||
class GCModuleInfo : public ImmutablePass {
|
||||
/// An owning list of all GCStrategies which have been created
|
||||
SmallVector<std::unique_ptr<GCStrategy>, 1> GCStrategyList;
|
||||
/// A helper map to speedup lookups into the above list
|
||||
StringMap<GCStrategy*> GCStrategyMap;
|
||||
|
||||
/// Garbage collection metadata for a single function. Currently, this
|
||||
/// information only applies to GCStrategies which use GCRoot.
|
||||
class GCFunctionInfo {
|
||||
public:
|
||||
typedef std::vector<GCPoint>::iterator iterator;
|
||||
typedef std::vector<GCRoot>::iterator roots_iterator;
|
||||
typedef std::vector<GCRoot>::const_iterator live_iterator;
|
||||
public:
|
||||
/// Lookup the GCStrategy object associated with the given gc name.
|
||||
/// Objects are owned internally; No caller should attempt to delete the
|
||||
/// returned objects.
|
||||
GCStrategy *getGCStrategy(const StringRef Name);
|
||||
|
||||
/// List of per function info objects. In theory, Each of these
|
||||
/// may be associated with a different GC.
|
||||
typedef std::vector<std::unique_ptr<GCFunctionInfo>> FuncInfoVec;
|
||||
|
||||
private:
|
||||
const Function &F;
|
||||
GCStrategy &S;
|
||||
uint64_t FrameSize;
|
||||
std::vector<GCRoot> Roots;
|
||||
std::vector<GCPoint> SafePoints;
|
||||
FuncInfoVec::iterator funcinfo_begin() { return Functions.begin(); }
|
||||
FuncInfoVec::iterator funcinfo_end() { return Functions.end(); }
|
||||
|
||||
// FIXME: Liveness. A 2D BitVector, perhaps?
|
||||
//
|
||||
// BitVector Liveness;
|
||||
//
|
||||
// bool islive(int point, int root) =
|
||||
// Liveness[point * SafePoints.size() + root]
|
||||
//
|
||||
// The bit vector is the more compact representation where >3.2% of roots
|
||||
// are live per safe point (1.5% on 64-bit hosts).
|
||||
private:
|
||||
/// Owning list of all GCFunctionInfos associated with this Module
|
||||
FuncInfoVec Functions;
|
||||
|
||||
public:
|
||||
GCFunctionInfo(const Function &F, GCStrategy &S);
|
||||
~GCFunctionInfo();
|
||||
/// Non-owning map to bypass linear search when finding the GCFunctionInfo
|
||||
/// associated with a particular Function.
|
||||
typedef DenseMap<const Function *, GCFunctionInfo *> finfo_map_type;
|
||||
finfo_map_type FInfoMap;
|
||||
|
||||
/// getFunction - Return the function to which this metadata applies.
|
||||
///
|
||||
const Function &getFunction() const { return F; }
|
||||
public:
|
||||
typedef SmallVector<std::unique_ptr<GCStrategy>,1>::const_iterator iterator;
|
||||
|
||||
/// getStrategy - Return the GC strategy for the function.
|
||||
///
|
||||
GCStrategy &getStrategy() { return S; }
|
||||
static char ID;
|
||||
|
||||
/// addStackRoot - Registers a root that lives on the stack. Num is the
|
||||
/// stack object ID for the alloca (if the code generator is
|
||||
// using MachineFrameInfo).
|
||||
void addStackRoot(int Num, const Constant *Metadata) {
|
||||
Roots.push_back(GCRoot(Num, Metadata));
|
||||
}
|
||||
GCModuleInfo();
|
||||
|
||||
/// removeStackRoot - Removes a root.
|
||||
roots_iterator removeStackRoot(roots_iterator position) {
|
||||
return Roots.erase(position);
|
||||
}
|
||||
/// clear - Resets the pass. Any pass, which uses GCModuleInfo, should
|
||||
/// call it in doFinalization().
|
||||
///
|
||||
void clear();
|
||||
|
||||
/// addSafePoint - Notes the existence of a safe point. Num is the ID of the
|
||||
/// label just prior to the safe point (if the code generator is using
|
||||
/// MachineModuleInfo).
|
||||
void addSafePoint(GC::PointKind Kind, MCSymbol *Label, DebugLoc DL) {
|
||||
SafePoints.push_back(GCPoint(Kind, Label, DL));
|
||||
}
|
||||
|
||||
/// getFrameSize/setFrameSize - Records the function's frame size.
|
||||
///
|
||||
uint64_t getFrameSize() const { return FrameSize; }
|
||||
void setFrameSize(uint64_t S) { FrameSize = S; }
|
||||
|
||||
/// begin/end - Iterators for safe points.
|
||||
///
|
||||
iterator begin() { return SafePoints.begin(); }
|
||||
iterator end() { return SafePoints.end(); }
|
||||
size_t size() const { return SafePoints.size(); }
|
||||
|
||||
/// roots_begin/roots_end - Iterators for all roots in the function.
|
||||
///
|
||||
roots_iterator roots_begin() { return Roots.begin(); }
|
||||
roots_iterator roots_end () { return Roots.end(); }
|
||||
size_t roots_size() const { return Roots.size(); }
|
||||
|
||||
/// live_begin/live_end - Iterators for live roots at a given safe point.
|
||||
///
|
||||
live_iterator live_begin(const iterator &p) { return roots_begin(); }
|
||||
live_iterator live_end (const iterator &p) { return roots_end(); }
|
||||
size_t live_size(const iterator &p) const { return roots_size(); }
|
||||
};
|
||||
|
||||
/// An analysis pass which caches information about the entire Module.
|
||||
/// Records both the function level information used by GCRoots and a
|
||||
/// cache of the 'active' gc strategy objects for the current Module.
|
||||
class GCModuleInfo : public ImmutablePass {
|
||||
typedef StringMap<GCStrategy*> strategy_map_type;
|
||||
typedef std::vector<std::unique_ptr<GCStrategy>> list_type;
|
||||
|
||||
strategy_map_type StrategyMap;
|
||||
list_type StrategyList;
|
||||
|
||||
GCStrategy *getOrCreateStrategy(const Module *M, const std::string &Name);
|
||||
|
||||
public:
|
||||
/// List of per function info objects. In theory, Each of these
|
||||
/// may be associated with a different GC.
|
||||
typedef std::vector<std::unique_ptr<GCFunctionInfo>> FuncInfoVec;
|
||||
|
||||
FuncInfoVec::iterator funcinfo_begin() { return Functions.begin(); }
|
||||
FuncInfoVec::iterator funcinfo_end() { return Functions.end(); }
|
||||
|
||||
|
||||
private:
|
||||
/// Owning list of all GCFunctionInfos associated with this Module
|
||||
FuncInfoVec Functions;
|
||||
|
||||
/// Non-owning map to bypass linear search when finding the GCFunctionInfo
|
||||
/// associated with a particular Function.
|
||||
typedef DenseMap<const Function*,GCFunctionInfo*> finfo_map_type;
|
||||
finfo_map_type FInfoMap;
|
||||
public:
|
||||
|
||||
typedef list_type::const_iterator iterator;
|
||||
|
||||
static char ID;
|
||||
|
||||
GCModuleInfo();
|
||||
|
||||
/// clear - Resets the pass. Any pass, which uses GCModuleInfo, should
|
||||
/// call it in doFinalization().
|
||||
///
|
||||
void clear();
|
||||
|
||||
/// begin/end - Iterators for used strategies.
|
||||
///
|
||||
iterator begin() const { return StrategyList.begin(); }
|
||||
iterator end() const { return StrategyList.end(); }
|
||||
|
||||
/// get - Look up function metadata. This is currently assumed
|
||||
/// have the side effect of initializing the associated GCStrategy. That
|
||||
/// will soon change.
|
||||
GCFunctionInfo &getFunctionInfo(const Function &F);
|
||||
};
|
||||
/// begin/end - Iterators for used strategies.
|
||||
///
|
||||
iterator begin() const { return GCStrategyList.begin(); }
|
||||
iterator end() const { return GCStrategyList.end(); }
|
||||
|
||||
/// get - Look up function metadata. This is currently assumed
|
||||
/// have the side effect of initializing the associated GCStrategy. That
|
||||
/// will soon change.
|
||||
GCFunctionInfo &getFunctionInfo(const Function &F);
|
||||
};
|
||||
}
|
||||
|
||||
#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