Vendor import of stripped llvm trunk r375505, the last commit before the
upstream Subversion repository was made read-only, and the LLVM project migrated to GitHub: https://llvm.org/svn/llvm-project/llvm/trunk@375505
This commit is contained in:
parent
e6d1592492
commit
1d5ae1026e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/llvm/dist/; revision=353940 svn path=/vendor/llvm/llvm-r375505/; revision=353941; tag=vendor/llvm/llvm-trunk-r375505
@ -370,9 +370,13 @@ typedef enum {
|
||||
LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
|
||||
original using an unsigned comparison and return
|
||||
the old one */
|
||||
LLVMAtomicRMWBinOpUMin /**< Sets the value if it's greater than the
|
||||
original using an unsigned comparison and return
|
||||
the old one */
|
||||
LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
|
||||
original using an unsigned comparison and return
|
||||
the old one */
|
||||
LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
|
||||
old one */
|
||||
LLVMAtomicRMWBinOpFSub /**< Subtract a floating point value and return the
|
||||
old one */
|
||||
} LLVMAtomicRMWBinOp;
|
||||
|
||||
typedef enum {
|
||||
@ -1539,6 +1543,7 @@ LLVMTypeRef LLVMX86MMXType(void);
|
||||
macro(GlobalVariable) \
|
||||
macro(UndefValue) \
|
||||
macro(Instruction) \
|
||||
macro(UnaryOperator) \
|
||||
macro(BinaryOperator) \
|
||||
macro(CallInst) \
|
||||
macro(IntrinsicInst) \
|
||||
@ -1571,6 +1576,8 @@ LLVMTypeRef LLVMX86MMXType(void);
|
||||
macro(ResumeInst) \
|
||||
macro(CleanupReturnInst) \
|
||||
macro(CatchReturnInst) \
|
||||
macro(CatchSwitchInst) \
|
||||
macro(CallBrInst) \
|
||||
macro(FuncletPadInst) \
|
||||
macro(CatchPadInst) \
|
||||
macro(CleanupPadInst) \
|
||||
@ -1592,7 +1599,10 @@ LLVMTypeRef LLVMX86MMXType(void);
|
||||
macro(ZExtInst) \
|
||||
macro(ExtractValueInst) \
|
||||
macro(LoadInst) \
|
||||
macro(VAArgInst)
|
||||
macro(VAArgInst) \
|
||||
macro(AtomicCmpXchgInst) \
|
||||
macro(AtomicRMWInst) \
|
||||
macro(FenceInst)
|
||||
|
||||
/**
|
||||
* @defgroup LLVMCCoreValueGeneral General APIs
|
||||
@ -3807,8 +3817,12 @@ LLVMValueRef LLVMBuildGlobalStringPtr(LLVMBuilderRef B, const char *Str,
|
||||
const char *Name);
|
||||
LLVMBool LLVMGetVolatile(LLVMValueRef MemoryAccessInst);
|
||||
void LLVMSetVolatile(LLVMValueRef MemoryAccessInst, LLVMBool IsVolatile);
|
||||
LLVMBool LLVMGetWeak(LLVMValueRef CmpXchgInst);
|
||||
void LLVMSetWeak(LLVMValueRef CmpXchgInst, LLVMBool IsWeak);
|
||||
LLVMAtomicOrdering LLVMGetOrdering(LLVMValueRef MemoryAccessInst);
|
||||
void LLVMSetOrdering(LLVMValueRef MemoryAccessInst, LLVMAtomicOrdering Ordering);
|
||||
LLVMAtomicRMWBinOp LLVMGetAtomicRMWBinOp(LLVMValueRef AtomicRMWInst);
|
||||
void LLVMSetAtomicRMWBinOp(LLVMValueRef AtomicRMWInst, LLVMAtomicRMWBinOp BinOp);
|
||||
|
||||
/* Casts */
|
||||
LLVMValueRef LLVMBuildTrunc(LLVMBuilderRef, LLVMValueRef Val,
|
||||
|
@ -32,7 +32,7 @@ typedef enum {
|
||||
LLVMDIFlagPublic = 3,
|
||||
LLVMDIFlagFwdDecl = 1 << 2,
|
||||
LLVMDIFlagAppleBlock = 1 << 3,
|
||||
LLVMDIFlagBlockByrefStruct = 1 << 4,
|
||||
LLVMDIFlagReservedBit4 = 1 << 4,
|
||||
LLVMDIFlagVirtual = 1 << 5,
|
||||
LLVMDIFlagArtificial = 1 << 6,
|
||||
LLVMDIFlagExplicit = 1 << 7,
|
||||
@ -169,6 +169,19 @@ typedef unsigned LLVMMetadataKind;
|
||||
*/
|
||||
typedef unsigned LLVMDWARFTypeEncoding;
|
||||
|
||||
/**
|
||||
* Describes the kind of macro declaration used for LLVMDIBuilderCreateMacro.
|
||||
* @see llvm::dwarf::MacinfoRecordType
|
||||
* @note Values are from DW_MACINFO_* constants in the DWARF specification.
|
||||
*/
|
||||
typedef enum {
|
||||
LLVMDWARFMacinfoRecordTypeDefine = 0x01,
|
||||
LLVMDWARFMacinfoRecordTypeMacro = 0x02,
|
||||
LLVMDWARFMacinfoRecordTypeStartFile = 0x03,
|
||||
LLVMDWARFMacinfoRecordTypeEndFile = 0x04,
|
||||
LLVMDWARFMacinfoRecordTypeVendorExt = 0xff
|
||||
} LLVMDWARFMacinfoRecordType;
|
||||
|
||||
/**
|
||||
* The current debug metadata version number.
|
||||
*/
|
||||
@ -521,6 +534,38 @@ LLVMDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder,
|
||||
unsigned NumParameterTypes,
|
||||
LLVMDIFlags Flags);
|
||||
|
||||
/**
|
||||
* Create debugging information entry for a macro.
|
||||
* @param Builder The DIBuilder.
|
||||
* @param ParentMacroFile Macro parent (could be NULL).
|
||||
* @param Line Source line number where the macro is defined.
|
||||
* @param RecordType DW_MACINFO_define or DW_MACINFO_undef.
|
||||
* @param Name Macro name.
|
||||
* @param NameLen Macro name length.
|
||||
* @param Value Macro value.
|
||||
* @param ValueLen Macro value length.
|
||||
*/
|
||||
LLVMMetadataRef LLVMDIBuilderCreateMacro(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef ParentMacroFile,
|
||||
unsigned Line,
|
||||
LLVMDWARFMacinfoRecordType RecordType,
|
||||
const char *Name, size_t NameLen,
|
||||
const char *Value, size_t ValueLen);
|
||||
|
||||
/**
|
||||
* Create debugging information temporary entry for a macro file.
|
||||
* List of macro node direct children will be calculated by DIBuilder,
|
||||
* using the \p ParentMacroFile relationship.
|
||||
* @param Builder The DIBuilder.
|
||||
* @param ParentMacroFile Macro parent (could be NULL).
|
||||
* @param Line Source line number where the macro file is included.
|
||||
* @param File File descriptor containing the name of the macro file.
|
||||
*/
|
||||
LLVMMetadataRef
|
||||
LLVMDIBuilderCreateTempMacroFile(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef ParentMacroFile, unsigned Line,
|
||||
LLVMMetadataRef File);
|
||||
|
||||
/**
|
||||
* Create debugging information entry for an enumerator.
|
||||
* @param Builder The DIBuilder.
|
||||
|
@ -30,7 +30,8 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define REMARKS_API_VERSION 0
|
||||
// 0 -> 1: Bitstream remarks support.
|
||||
#define REMARKS_API_VERSION 1
|
||||
|
||||
/**
|
||||
* The type of the emitted remark.
|
||||
@ -240,6 +241,20 @@ typedef struct LLVMRemarkOpaqueParser *LLVMRemarkParserRef;
|
||||
extern LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
|
||||
uint64_t Size);
|
||||
|
||||
/**
|
||||
* Creates a remark parser that can be used to parse the buffer located in \p
|
||||
* Buf of size \p Size bytes.
|
||||
*
|
||||
* \p Buf cannot be `NULL`.
|
||||
*
|
||||
* This function should be paired with LLVMRemarkParserDispose() to avoid
|
||||
* leaking resources.
|
||||
*
|
||||
* \since REMARKS_API_VERSION=1
|
||||
*/
|
||||
extern LLVMRemarkParserRef LLVMRemarkParserCreateBitstream(const void *Buf,
|
||||
uint64_t Size);
|
||||
|
||||
/**
|
||||
* Returns the next remark in the file.
|
||||
*
|
||||
|
@ -34,6 +34,9 @@ void LLVMAddArgumentPromotionPass(LLVMPassManagerRef PM);
|
||||
/** See llvm::createConstantMergePass function. */
|
||||
void LLVMAddConstantMergePass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createMergeFunctionsPass function. */
|
||||
void LLVMAddMergeFunctionsPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createCalledValuePropagationPass function. */
|
||||
void LLVMAddCalledValuePropagationPass(LLVMPassManagerRef PM);
|
||||
|
||||
@ -67,6 +70,21 @@ void LLVMAddIPSCCPPass(LLVMPassManagerRef PM);
|
||||
/** See llvm::createInternalizePass function. */
|
||||
void LLVMAddInternalizePass(LLVMPassManagerRef, unsigned AllButMain);
|
||||
|
||||
/**
|
||||
* Create and add the internalize pass to the given pass manager with the
|
||||
* provided preservation callback.
|
||||
*
|
||||
* The context parameter is forwarded to the callback on each invocation.
|
||||
* As such, it is the responsibility of the caller to extend its lifetime
|
||||
* until execution of this pass has finished.
|
||||
*
|
||||
* @see llvm::createInternalizePass function.
|
||||
*/
|
||||
void LLVMAddInternalizePassWithMustPreservePredicate(
|
||||
LLVMPassManagerRef PM,
|
||||
void *Context,
|
||||
LLVMBool (*MustPreserve)(LLVMValueRef, void *));
|
||||
|
||||
/** See llvm::createStripDeadPrototypesPass function. */
|
||||
void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
@ -35,6 +35,9 @@ extern "C" {
|
||||
/** See llvm::createAggressiveDCEPass function. */
|
||||
void LLVMAddAggressiveDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createDeadCodeEliminationPass function. */
|
||||
void LLVMAddDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createBitTrackingDCEPass function. */
|
||||
void LLVMAddBitTrackingDCEPass(LLVMPassManagerRef PM);
|
||||
|
||||
@ -144,6 +147,9 @@ void LLVMAddEarlyCSEMemSSAPass(LLVMPassManagerRef PM);
|
||||
/** See llvm::createLowerExpectIntrinsicPass function */
|
||||
void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createLowerConstantIntrinsicsPass function */
|
||||
void LLVMAddLowerConstantIntrinsicsPass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createTypeBasedAliasAnalysisPass function */
|
||||
void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM);
|
||||
|
||||
|
@ -44,7 +44,7 @@ typedef bool lto_bool_t;
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define LTO_API_VERSION 24
|
||||
#define LTO_API_VERSION 25
|
||||
|
||||
/**
|
||||
* \since prior to LTO_API_VERSION=3
|
||||
@ -550,6 +550,56 @@ extern void
|
||||
lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
|
||||
lto_bool_t ShouldEmbedUselists);
|
||||
|
||||
/** Opaque reference to an LTO input file */
|
||||
typedef struct LLVMOpaqueLTOInput *lto_input_t;
|
||||
|
||||
/**
|
||||
* Creates an LTO input file from a buffer. The path
|
||||
* argument is used for diagnotics as this function
|
||||
* otherwise does not know which file the given buffer
|
||||
* is associated with.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern lto_input_t lto_input_create(const void *buffer,
|
||||
size_t buffer_size,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* Frees all memory internally allocated by the LTO input file.
|
||||
* Upon return the lto_module_t is no longer valid.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern void lto_input_dispose(lto_input_t input);
|
||||
|
||||
/**
|
||||
* Returns the number of dependent library specifiers
|
||||
* for the given LTO input file.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern unsigned lto_input_get_num_dependent_libraries(lto_input_t input);
|
||||
|
||||
/**
|
||||
* Returns the ith dependent library specifier
|
||||
* for the given LTO input file. The returned
|
||||
* string is not null-terminated.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern const char * lto_input_get_dependent_library(lto_input_t input,
|
||||
size_t index,
|
||||
size_t *size);
|
||||
|
||||
/**
|
||||
* Returns the list of libcall symbols that can be generated by LTO
|
||||
* that might not be visible from the symbol table of bitcode files.
|
||||
*
|
||||
* \since prior to LTO_API_VERSION=25
|
||||
*/
|
||||
extern const char *const *lto_runtime_lib_symbols_list(size_t *size);
|
||||
|
||||
/**
|
||||
* @} // endgoup LLVMCLTO
|
||||
* @defgroup LLVMCTLTO ThinLTO
|
||||
@ -846,48 +896,6 @@ thinlto_codegen_set_cache_size_megabytes(thinlto_code_gen_t cg,
|
||||
extern void thinlto_codegen_set_cache_size_files(thinlto_code_gen_t cg,
|
||||
unsigned max_size_files);
|
||||
|
||||
/** Opaque reference to an LTO input file */
|
||||
typedef struct LLVMOpaqueLTOInput *lto_input_t;
|
||||
|
||||
/**
|
||||
* Creates an LTO input file from a buffer. The path
|
||||
* argument is used for diagnotics as this function
|
||||
* otherwise does not know which file the given buffer
|
||||
* is associated with.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern lto_input_t lto_input_create(const void *buffer,
|
||||
size_t buffer_size,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* Frees all memory internally allocated by the LTO input file.
|
||||
* Upon return the lto_module_t is no longer valid.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern void lto_input_dispose(lto_input_t input);
|
||||
|
||||
/**
|
||||
* Returns the number of dependent library specifiers
|
||||
* for the given LTO input file.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern unsigned lto_input_get_num_dependent_libraries(lto_input_t input);
|
||||
|
||||
/**
|
||||
* Returns the ith dependent library specifier
|
||||
* for the given LTO input file. The returned
|
||||
* string is not null-terminated.
|
||||
*
|
||||
* \since LTO_API_VERSION=24
|
||||
*/
|
||||
extern const char * lto_input_get_dependent_library(lto_input_t input,
|
||||
size_t index,
|
||||
size_t *size);
|
||||
|
||||
/**
|
||||
* @} // endgroup LLVMCTLTO_CACHING
|
||||
*/
|
||||
|
@ -192,6 +192,11 @@ struct APFloatBase {
|
||||
/// IEEE-754R 7: Default exception handling.
|
||||
///
|
||||
/// opUnderflow or opOverflow are always returned or-ed with opInexact.
|
||||
///
|
||||
/// APFloat models this behavior specified by IEEE-754:
|
||||
/// "For operations producing results in floating-point format, the default
|
||||
/// result of an operation that signals the invalid operation exception
|
||||
/// shall be a quiet NaN."
|
||||
enum opStatus {
|
||||
opOK = 0x00,
|
||||
opInvalidOp = 0x01,
|
||||
|
@ -1467,6 +1467,13 @@ class LLVM_NODISCARD APInt {
|
||||
U.pVal[whichWord(BitPosition)] &= Mask;
|
||||
}
|
||||
|
||||
/// Set bottom loBits bits to 0.
|
||||
void clearLowBits(unsigned loBits) {
|
||||
assert(loBits <= BitWidth && "More bits than bitwidth");
|
||||
APInt Keep = getHighBitsSet(BitWidth, BitWidth - loBits);
|
||||
*this &= Keep;
|
||||
}
|
||||
|
||||
/// Set the sign bit to 0.
|
||||
void clearSignBit() {
|
||||
clearBit(BitWidth - 1);
|
||||
@ -1496,9 +1503,11 @@ class LLVM_NODISCARD APInt {
|
||||
|
||||
/// Insert the bits from a smaller APInt starting at bitPosition.
|
||||
void insertBits(const APInt &SubBits, unsigned bitPosition);
|
||||
void insertBits(uint64_t SubBits, unsigned bitPosition, unsigned numBits);
|
||||
|
||||
/// Return an APInt with the extracted bits [bitPosition,bitPosition+numBits).
|
||||
APInt extractBits(unsigned numBits, unsigned bitPosition) const;
|
||||
uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const;
|
||||
|
||||
/// @}
|
||||
/// \name Value Characterization Functions
|
||||
|
@ -38,7 +38,7 @@ class Any {
|
||||
explicit StorageImpl(T &&Value) : Value(std::move(Value)) {}
|
||||
|
||||
std::unique_ptr<StorageBase> clone() const override {
|
||||
return llvm::make_unique<StorageImpl<T>>(Value);
|
||||
return std::make_unique<StorageImpl<T>>(Value);
|
||||
}
|
||||
|
||||
const void *id() const override { return &TypeId<T>::Id; }
|
||||
@ -78,7 +78,7 @@ class Any {
|
||||
int>::type = 0>
|
||||
Any(T &&Value) {
|
||||
using U = typename std::decay<T>::type;
|
||||
Storage = llvm::make_unique<StorageImpl<U>>(std::forward<T>(Value));
|
||||
Storage = std::make_unique<StorageImpl<U>>(std::forward<T>(Value));
|
||||
}
|
||||
|
||||
Any(Any &&Other) : Storage(std::move(Other.Storage)) {}
|
||||
|
@ -481,6 +481,12 @@ namespace llvm {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a std::array.
|
||||
template <typename T, std::size_t N>
|
||||
ArrayRef<T> makeArrayRef(const std::array<T, N> &Arr) {
|
||||
return Arr;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from an ArrayRef (no-op) (const)
|
||||
template <typename T> ArrayRef<T> makeArrayRef(const ArrayRef<T> &Vec) {
|
||||
return Vec;
|
||||
|
@ -38,33 +38,7 @@ namespace detail {
|
||||
// implementation without requiring two members.
|
||||
template <typename KeyT, typename ValueT>
|
||||
struct DenseMapPair : public std::pair<KeyT, ValueT> {
|
||||
|
||||
// FIXME: Switch to inheriting constructors when we drop support for older
|
||||
// clang versions.
|
||||
// NOTE: This default constructor is declared with '{}' rather than
|
||||
// '= default' to work around a separate bug in clang-3.8. This can
|
||||
// also go when we switch to inheriting constructors.
|
||||
DenseMapPair() {}
|
||||
|
||||
DenseMapPair(const KeyT &Key, const ValueT &Value)
|
||||
: std::pair<KeyT, ValueT>(Key, Value) {}
|
||||
|
||||
DenseMapPair(KeyT &&Key, ValueT &&Value)
|
||||
: std::pair<KeyT, ValueT>(std::move(Key), std::move(Value)) {}
|
||||
|
||||
template <typename AltKeyT, typename AltValueT>
|
||||
DenseMapPair(AltKeyT &&AltKey, AltValueT &&AltValue,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<AltKeyT, KeyT>::value &&
|
||||
std::is_convertible<AltValueT, ValueT>::value>::type * = 0)
|
||||
: std::pair<KeyT, ValueT>(std::forward<AltKeyT>(AltKey),
|
||||
std::forward<AltValueT>(AltValue)) {}
|
||||
|
||||
template <typename AltPairT>
|
||||
DenseMapPair(AltPairT &&AltPair,
|
||||
typename std::enable_if<std::is_convertible<
|
||||
AltPairT, std::pair<KeyT, ValueT>>::value>::type * = nullptr)
|
||||
: std::pair<KeyT, ValueT>(std::forward<AltPairT>(AltPair)) {}
|
||||
using std::pair<KeyT, ValueT>::pair;
|
||||
|
||||
KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
|
||||
const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
|
||||
@ -748,7 +722,7 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
|
||||
~DenseMap() {
|
||||
this->destroyAll();
|
||||
operator delete(Buckets);
|
||||
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
|
||||
}
|
||||
|
||||
void swap(DenseMap& RHS) {
|
||||
@ -768,7 +742,7 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
|
||||
DenseMap& operator=(DenseMap &&other) {
|
||||
this->destroyAll();
|
||||
operator delete(Buckets);
|
||||
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
|
||||
init(0);
|
||||
swap(other);
|
||||
return *this;
|
||||
@ -776,7 +750,7 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
|
||||
void copyFrom(const DenseMap& other) {
|
||||
this->destroyAll();
|
||||
operator delete(Buckets);
|
||||
deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
|
||||
if (allocateBuckets(other.NumBuckets)) {
|
||||
this->BaseT::copyFrom(other);
|
||||
} else {
|
||||
@ -809,10 +783,12 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);
|
||||
|
||||
// Free the old table.
|
||||
operator delete(OldBuckets);
|
||||
deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets,
|
||||
alignof(BucketT));
|
||||
}
|
||||
|
||||
void shrink_and_clear() {
|
||||
unsigned OldNumBuckets = NumBuckets;
|
||||
unsigned OldNumEntries = NumEntries;
|
||||
this->destroyAll();
|
||||
|
||||
@ -825,7 +801,8 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
return;
|
||||
}
|
||||
|
||||
operator delete(Buckets);
|
||||
deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets,
|
||||
alignof(BucketT));
|
||||
init(NewNumBuckets);
|
||||
}
|
||||
|
||||
@ -861,7 +838,8 @@ class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
|
||||
return false;
|
||||
}
|
||||
|
||||
Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) * NumBuckets));
|
||||
Buckets = static_cast<BucketT *>(
|
||||
allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT)));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -1076,7 +1054,8 @@ class SmallDenseMap
|
||||
this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets);
|
||||
|
||||
// Free the old table.
|
||||
operator delete(OldRep.Buckets);
|
||||
deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets,
|
||||
alignof(BucketT));
|
||||
}
|
||||
|
||||
void shrink_and_clear() {
|
||||
@ -1160,15 +1139,17 @@ class SmallDenseMap
|
||||
if (Small)
|
||||
return;
|
||||
|
||||
operator delete(getLargeRep()->Buckets);
|
||||
deallocate_buffer(getLargeRep()->Buckets,
|
||||
sizeof(BucketT) * getLargeRep()->NumBuckets,
|
||||
alignof(BucketT));
|
||||
getLargeRep()->~LargeRep();
|
||||
}
|
||||
|
||||
LargeRep allocateBuckets(unsigned Num) {
|
||||
assert(Num > InlineBuckets && "Must allocate more buckets than are inline");
|
||||
LargeRep Rep = {
|
||||
static_cast<BucketT*>(operator new(sizeof(BucketT) * Num)), Num
|
||||
};
|
||||
LargeRep Rep = {static_cast<BucketT *>(allocate_buffer(
|
||||
sizeof(BucketT) * Num, alignof(BucketT))),
|
||||
Num};
|
||||
return Rep;
|
||||
}
|
||||
};
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include "llvm/Support/ScalableSize.h"
|
||||
#include "llvm/Support/TypeSize.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@ -67,6 +67,17 @@ template<> struct DenseMapInfo<char> {
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned chars.
|
||||
template <> struct DenseMapInfo<unsigned char> {
|
||||
static inline unsigned char getEmptyKey() { return ~0; }
|
||||
static inline unsigned char getTombstoneKey() { return ~0 - 1; }
|
||||
static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
|
||||
|
||||
static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide DenseMapInfo for unsigned shorts.
|
||||
template <> struct DenseMapInfo<unsigned short> {
|
||||
static inline unsigned short getEmptyKey() { return 0xFFFF; }
|
||||
|
270
include/llvm/ADT/DirectedGraph.h
Normal file
270
include/llvm/ADT/DirectedGraph.h
Normal file
@ -0,0 +1,270 @@
|
||||
//===- llvm/ADT/DirectedGraph.h - Directed Graph ----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interface and a base class implementation for a
|
||||
// directed graph.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_DIRECTEDGRAPH_H
|
||||
#define LLVM_ADT_DIRECTEDGRAPH_H
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Represent an edge in the directed graph.
|
||||
/// The edge contains the target node it connects to.
|
||||
template <class NodeType, class EdgeType> class DGEdge {
|
||||
public:
|
||||
DGEdge() = delete;
|
||||
/// Create an edge pointing to the given node \p N.
|
||||
explicit DGEdge(NodeType &N) : TargetNode(N) {}
|
||||
explicit DGEdge(const DGEdge<NodeType, EdgeType> &E)
|
||||
: TargetNode(E.TargetNode) {}
|
||||
DGEdge<NodeType, EdgeType> &operator=(const DGEdge<NodeType, EdgeType> &E) {
|
||||
TargetNode = E.TargetNode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Static polymorphism: delegate implementation (via isEqualTo) to the
|
||||
/// derived class.
|
||||
bool operator==(const EdgeType &E) const { return getDerived().isEqualTo(E); }
|
||||
bool operator!=(const EdgeType &E) const { return !operator==(E); }
|
||||
|
||||
/// Retrieve the target node this edge connects to.
|
||||
const NodeType &getTargetNode() const { return TargetNode; }
|
||||
NodeType &getTargetNode() {
|
||||
return const_cast<NodeType &>(
|
||||
static_cast<const DGEdge<NodeType, EdgeType> &>(*this).getTargetNode());
|
||||
}
|
||||
|
||||
protected:
|
||||
// As the default implementation use address comparison for equality.
|
||||
bool isEqualTo(const EdgeType &E) const { return this == &E; }
|
||||
|
||||
// Cast the 'this' pointer to the derived type and return a reference.
|
||||
EdgeType &getDerived() { return *static_cast<EdgeType *>(this); }
|
||||
const EdgeType &getDerived() const {
|
||||
return *static_cast<const EdgeType *>(this);
|
||||
}
|
||||
|
||||
// The target node this edge connects to.
|
||||
NodeType &TargetNode;
|
||||
};
|
||||
|
||||
/// Represent a node in the directed graph.
|
||||
/// The node has a (possibly empty) list of outgoing edges.
|
||||
template <class NodeType, class EdgeType> class DGNode {
|
||||
public:
|
||||
using EdgeListTy = SetVector<EdgeType *>;
|
||||
using iterator = typename EdgeListTy::iterator;
|
||||
using const_iterator = typename EdgeListTy::const_iterator;
|
||||
|
||||
/// Create a node with a single outgoing edge \p E.
|
||||
explicit DGNode(EdgeType &E) : Edges() { Edges.insert(&E); }
|
||||
DGNode() = default;
|
||||
|
||||
explicit DGNode(const DGNode<NodeType, EdgeType> &N) : Edges(N.Edges) {}
|
||||
DGNode(DGNode<NodeType, EdgeType> &&N) : Edges(std::move(N.Edges)) {}
|
||||
|
||||
DGNode<NodeType, EdgeType> &operator=(const DGNode<NodeType, EdgeType> &N) {
|
||||
Edges = N.Edges;
|
||||
return *this;
|
||||
}
|
||||
DGNode<NodeType, EdgeType> &operator=(const DGNode<NodeType, EdgeType> &&N) {
|
||||
Edges = std::move(N.Edges);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Static polymorphism: delegate implementation (via isEqualTo) to the
|
||||
/// derived class.
|
||||
bool operator==(const NodeType &N) const { return getDerived().isEqualTo(N); }
|
||||
bool operator!=(const NodeType &N) const { return !operator==(N); }
|
||||
|
||||
const_iterator begin() const { return Edges.begin(); }
|
||||
const_iterator end() const { return Edges.end(); }
|
||||
iterator begin() { return Edges.begin(); }
|
||||
iterator end() { return Edges.end(); }
|
||||
const EdgeType &front() const { return *Edges.front(); }
|
||||
EdgeType &front() { return *Edges.front(); }
|
||||
const EdgeType &back() const { return *Edges.back(); }
|
||||
EdgeType &back() { return *Edges.back(); }
|
||||
|
||||
/// Collect in \p EL, all the edges from this node to \p N.
|
||||
/// Return true if at least one edge was found, and false otherwise.
|
||||
/// Note that this implementation allows more than one edge to connect
|
||||
/// a given pair of nodes.
|
||||
bool findEdgesTo(const NodeType &N, SmallVectorImpl<EdgeType *> &EL) const {
|
||||
assert(EL.empty() && "Expected the list of edges to be empty.");
|
||||
for (auto *E : Edges)
|
||||
if (E->getTargetNode() == N)
|
||||
EL.push_back(E);
|
||||
return !EL.empty();
|
||||
}
|
||||
|
||||
/// Add the given edge \p E to this node, if it doesn't exist already. Returns
|
||||
/// true if the edge is added and false otherwise.
|
||||
bool addEdge(EdgeType &E) { return Edges.insert(&E); }
|
||||
|
||||
/// Remove the given edge \p E from this node, if it exists.
|
||||
void removeEdge(EdgeType &E) { Edges.remove(&E); }
|
||||
|
||||
/// Test whether there is an edge that goes from this node to \p N.
|
||||
bool hasEdgeTo(const NodeType &N) const {
|
||||
return (findEdgeTo(N) != Edges.end());
|
||||
}
|
||||
|
||||
/// Retrieve the outgoing edges for the node.
|
||||
const EdgeListTy &getEdges() const { return Edges; }
|
||||
EdgeListTy &getEdges() {
|
||||
return const_cast<EdgeListTy &>(
|
||||
static_cast<const DGNode<NodeType, EdgeType> &>(*this).Edges);
|
||||
}
|
||||
|
||||
/// Clear the outgoing edges.
|
||||
void clear() { Edges.clear(); }
|
||||
|
||||
protected:
|
||||
// As the default implementation use address comparison for equality.
|
||||
bool isEqualTo(const NodeType &N) const { return this == &N; }
|
||||
|
||||
// Cast the 'this' pointer to the derived type and return a reference.
|
||||
NodeType &getDerived() { return *static_cast<NodeType *>(this); }
|
||||
const NodeType &getDerived() const {
|
||||
return *static_cast<const NodeType *>(this);
|
||||
}
|
||||
|
||||
/// Find an edge to \p N. If more than one edge exists, this will return
|
||||
/// the first one in the list of edges.
|
||||
const_iterator findEdgeTo(const NodeType &N) const {
|
||||
return llvm::find_if(
|
||||
Edges, [&N](const EdgeType *E) { return E->getTargetNode() == N; });
|
||||
}
|
||||
|
||||
// The list of outgoing edges.
|
||||
EdgeListTy Edges;
|
||||
};
|
||||
|
||||
/// Directed graph
|
||||
///
|
||||
/// The graph is represented by a table of nodes.
|
||||
/// Each node contains a (possibly empty) list of outgoing edges.
|
||||
/// Each edge contains the target node it connects to.
|
||||
template <class NodeType, class EdgeType> class DirectedGraph {
|
||||
protected:
|
||||
using NodeListTy = SmallVector<NodeType *, 10>;
|
||||
using EdgeListTy = SmallVector<EdgeType *, 10>;
|
||||
public:
|
||||
using iterator = typename NodeListTy::iterator;
|
||||
using const_iterator = typename NodeListTy::const_iterator;
|
||||
using DGraphType = DirectedGraph<NodeType, EdgeType>;
|
||||
|
||||
DirectedGraph() = default;
|
||||
explicit DirectedGraph(NodeType &N) : Nodes() { addNode(N); }
|
||||
DirectedGraph(const DGraphType &G) : Nodes(G.Nodes) {}
|
||||
DirectedGraph(DGraphType &&RHS) : Nodes(std::move(RHS.Nodes)) {}
|
||||
DGraphType &operator=(const DGraphType &G) {
|
||||
Nodes = G.Nodes;
|
||||
return *this;
|
||||
}
|
||||
DGraphType &operator=(const DGraphType &&G) {
|
||||
Nodes = std::move(G.Nodes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator begin() const { return Nodes.begin(); }
|
||||
const_iterator end() const { return Nodes.end(); }
|
||||
iterator begin() { return Nodes.begin(); }
|
||||
iterator end() { return Nodes.end(); }
|
||||
const NodeType &front() const { return *Nodes.front(); }
|
||||
NodeType &front() { return *Nodes.front(); }
|
||||
const NodeType &back() const { return *Nodes.back(); }
|
||||
NodeType &back() { return *Nodes.back(); }
|
||||
|
||||
size_t size() const { return Nodes.size(); }
|
||||
|
||||
/// Find the given node \p N in the table.
|
||||
const_iterator findNode(const NodeType &N) const {
|
||||
return llvm::find_if(Nodes,
|
||||
[&N](const NodeType *Node) { return *Node == N; });
|
||||
}
|
||||
iterator findNode(const NodeType &N) {
|
||||
return const_cast<iterator>(
|
||||
static_cast<const DGraphType &>(*this).findNode(N));
|
||||
}
|
||||
|
||||
/// Add the given node \p N to the graph if it is not already present.
|
||||
bool addNode(NodeType &N) {
|
||||
if (findNode(N) != Nodes.end())
|
||||
return false;
|
||||
Nodes.push_back(&N);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Collect in \p EL all edges that are coming into node \p N. Return true
|
||||
/// if at least one edge was found, and false otherwise.
|
||||
bool findIncomingEdgesToNode(const NodeType &N, SmallVectorImpl<EdgeType*> &EL) const {
|
||||
assert(EL.empty() && "Expected the list of edges to be empty.");
|
||||
EdgeListTy TempList;
|
||||
for (auto *Node : Nodes) {
|
||||
if (*Node == N)
|
||||
continue;
|
||||
Node->findEdgesTo(N, TempList);
|
||||
EL.insert(EL.end(), TempList.begin(), TempList.end());
|
||||
TempList.clear();
|
||||
}
|
||||
return !EL.empty();
|
||||
}
|
||||
|
||||
/// Remove the given node \p N from the graph. If the node has incoming or
|
||||
/// outgoing edges, they are also removed. Return true if the node was found
|
||||
/// and then removed, and false if the node was not found in the graph to
|
||||
/// begin with.
|
||||
bool removeNode(NodeType &N) {
|
||||
iterator IT = findNode(N);
|
||||
if (IT == Nodes.end())
|
||||
return false;
|
||||
// Remove incoming edges.
|
||||
EdgeListTy EL;
|
||||
for (auto *Node : Nodes) {
|
||||
if (*Node == N)
|
||||
continue;
|
||||
Node->findEdgesTo(N, EL);
|
||||
for (auto *E : EL)
|
||||
Node->removeEdge(*E);
|
||||
EL.clear();
|
||||
}
|
||||
N.clear();
|
||||
Nodes.erase(IT);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Assuming nodes \p Src and \p Dst are already in the graph, connect node \p
|
||||
/// Src to node \p Dst using the provided edge \p E. Return true if \p Src is
|
||||
/// not already connected to \p Dst via \p E, and false otherwise.
|
||||
bool connect(NodeType &Src, NodeType &Dst, EdgeType &E) {
|
||||
assert(findNode(Src) != Nodes.end() && "Src node should be present.");
|
||||
assert(findNode(Dst) != Nodes.end() && "Dst node should be present.");
|
||||
assert((E.getTargetNode() == Dst) &&
|
||||
"Target of the given edge does not match Dst.");
|
||||
return Src.addEdge(E);
|
||||
}
|
||||
|
||||
protected:
|
||||
// The list of nodes in the graph.
|
||||
NodeListTy Nodes;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_DIRECTEDGRAPH_H
|
@ -45,7 +45,6 @@
|
||||
#define LLVM_ADT_HASHING_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/SwapByteOrder.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <algorithm>
|
||||
|
@ -963,8 +963,8 @@ class IntervalMap {
|
||||
|
||||
private:
|
||||
// The root data is either a RootLeaf or a RootBranchData instance.
|
||||
LLVM_ALIGNAS(RootLeaf) LLVM_ALIGNAS(RootBranchData)
|
||||
AlignedCharArrayUnion<RootLeaf, RootBranchData> data;
|
||||
alignas(RootLeaf) alignas(RootBranchData)
|
||||
AlignedCharArrayUnion<RootLeaf, RootBranchData> data;
|
||||
|
||||
// Tree height.
|
||||
// 0: Leaves in root.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#ifndef LLVM_ADT_POINTERINTPAIR_H
|
||||
#define LLVM_ADT_POINTERINTPAIR_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <cassert>
|
||||
@ -59,19 +60,19 @@ class PointerIntPair {
|
||||
|
||||
IntType getInt() const { return (IntType)Info::getInt(Value); }
|
||||
|
||||
void setPointer(PointerTy PtrVal) {
|
||||
void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updatePointer(Value, PtrVal);
|
||||
}
|
||||
|
||||
void setInt(IntType IntVal) {
|
||||
void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
void initWithPointer(PointerTy PtrVal) {
|
||||
void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updatePointer(0, PtrVal);
|
||||
}
|
||||
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
|
||||
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
|
||||
static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
@ -89,7 +90,7 @@ class PointerIntPair {
|
||||
|
||||
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
|
||||
|
||||
void setFromOpaqueValue(void *Val) {
|
||||
void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
|
||||
Value = reinterpret_cast<intptr_t>(Val);
|
||||
}
|
||||
|
||||
|
@ -54,21 +54,14 @@ struct PointerUnionTypeSelectorReturn<
|
||||
};
|
||||
|
||||
namespace pointer_union_detail {
|
||||
constexpr int constexprMin(int a, int b) { return a < b ? a : b; }
|
||||
/// Determine the number of bits required to store integers with values < n.
|
||||
/// This is ceil(log2(n)).
|
||||
constexpr int bitsRequired(unsigned n) {
|
||||
return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
|
||||
}
|
||||
|
||||
// FIXME: In C++14, replace this with
|
||||
// std::min({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...})
|
||||
template <typename T> constexpr int lowBitsAvailable() {
|
||||
return PointerLikeTypeTraits<T>::NumLowBitsAvailable;
|
||||
}
|
||||
template <typename T1, typename T2, typename... Ts>
|
||||
constexpr int lowBitsAvailable() {
|
||||
return constexprMin(lowBitsAvailable<T1>(), lowBitsAvailable<T2, Ts...>());
|
||||
template <typename... Ts> constexpr int lowBitsAvailable() {
|
||||
return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
|
||||
}
|
||||
|
||||
/// Find the index of a type in a list of types. TypeIndex<T, Us...>::Index
|
||||
@ -167,10 +160,11 @@ class PointerUnion
|
||||
void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
|
||||
pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
|
||||
0, PTs...> {
|
||||
// The first type is special in some ways, but we don't want PointerUnion to
|
||||
// be a 'template <typename First, typename ...Rest>' because it's much more
|
||||
// convenient to have a name for the whole pack. So split off the first type
|
||||
// here.
|
||||
// The first type is special because we want to directly cast a pointer to a
|
||||
// default-initialized union to a pointer to the first type. But we don't
|
||||
// want PointerUnion to be a 'template <typename First, typename ...Rest>'
|
||||
// because it's much more convenient to have a name for the whole pack. So
|
||||
// split off the first type here.
|
||||
using First = typename pointer_union_detail::GetFirstType<PTs...>::type;
|
||||
using Base = typename PointerUnion::PointerUnionMembers;
|
||||
|
||||
@ -182,12 +176,7 @@ class PointerUnion
|
||||
|
||||
/// Test if the pointer held in the union is null, regardless of
|
||||
/// which type it is.
|
||||
bool isNull() const {
|
||||
// Convert from the void* to one of the pointer types, to make sure that
|
||||
// we recursively strip off low bits if we have a nested PointerUnion.
|
||||
return !PointerLikeTypeTraits<First>::getFromVoidPointer(
|
||||
this->Val.getPointer());
|
||||
}
|
||||
bool isNull() const { return !this->Val.getPointer(); }
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
@ -226,7 +215,8 @@ class PointerUnion
|
||||
First *getAddrOfPtr1() {
|
||||
assert(is<First>() && "Val is not the first pointer");
|
||||
assert(
|
||||
get<First>() == this->Val.getPointer() &&
|
||||
PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
|
||||
this->Val.getPointer() &&
|
||||
"Can't get the address because PointerLikeTypeTraits changes the ptr");
|
||||
return const_cast<First *>(
|
||||
reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
|
||||
|
@ -95,18 +95,6 @@ template <class Ty> struct identity {
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ty> struct less_ptr {
|
||||
bool operator()(const Ty* left, const Ty* right) const {
|
||||
return *left < *right;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ty> struct greater_ptr {
|
||||
bool operator()(const Ty* left, const Ty* right) const {
|
||||
return *right < *left;
|
||||
}
|
||||
};
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
@ -530,10 +518,6 @@ bool all_of(R &&range, UnaryPredicate P);
|
||||
template <typename R, typename UnaryPredicate>
|
||||
bool any_of(R &&range, UnaryPredicate P);
|
||||
|
||||
template <size_t... I> struct index_sequence;
|
||||
|
||||
template <class... Ts> struct index_sequence_for;
|
||||
|
||||
namespace detail {
|
||||
|
||||
using std::declval;
|
||||
@ -568,38 +552,38 @@ struct zip_common : public zip_traits<ZipType, Iters...> {
|
||||
std::tuple<Iters...> iterators;
|
||||
|
||||
protected:
|
||||
template <size_t... Ns> value_type deref(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const {
|
||||
return value_type(*std::get<Ns>(iterators)...);
|
||||
}
|
||||
|
||||
template <size_t... Ns>
|
||||
decltype(iterators) tup_inc(index_sequence<Ns...>) const {
|
||||
decltype(iterators) tup_inc(std::index_sequence<Ns...>) const {
|
||||
return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...);
|
||||
}
|
||||
|
||||
template <size_t... Ns>
|
||||
decltype(iterators) tup_dec(index_sequence<Ns...>) const {
|
||||
decltype(iterators) tup_dec(std::index_sequence<Ns...>) const {
|
||||
return std::tuple<Iters...>(std::prev(std::get<Ns>(iterators))...);
|
||||
}
|
||||
|
||||
public:
|
||||
zip_common(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
|
||||
|
||||
value_type operator*() { return deref(index_sequence_for<Iters...>{}); }
|
||||
value_type operator*() { return deref(std::index_sequence_for<Iters...>{}); }
|
||||
|
||||
const value_type operator*() const {
|
||||
return deref(index_sequence_for<Iters...>{});
|
||||
return deref(std::index_sequence_for<Iters...>{});
|
||||
}
|
||||
|
||||
ZipType &operator++() {
|
||||
iterators = tup_inc(index_sequence_for<Iters...>{});
|
||||
iterators = tup_inc(std::index_sequence_for<Iters...>{});
|
||||
return *reinterpret_cast<ZipType *>(this);
|
||||
}
|
||||
|
||||
ZipType &operator--() {
|
||||
static_assert(Base::IsBidirectional,
|
||||
"All inner iterators must be at least bidirectional.");
|
||||
iterators = tup_dec(index_sequence_for<Iters...>{});
|
||||
iterators = tup_dec(std::index_sequence_for<Iters...>{});
|
||||
return *reinterpret_cast<ZipType *>(this);
|
||||
}
|
||||
};
|
||||
@ -618,7 +602,8 @@ struct zip_first : public zip_common<zip_first<Iters...>, Iters...> {
|
||||
template <typename... Iters>
|
||||
class zip_shortest : public zip_common<zip_shortest<Iters...>, Iters...> {
|
||||
template <size_t... Ns>
|
||||
bool test(const zip_shortest<Iters...> &other, index_sequence<Ns...>) const {
|
||||
bool test(const zip_shortest<Iters...> &other,
|
||||
std::index_sequence<Ns...>) const {
|
||||
return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
|
||||
std::get<Ns>(other.iterators)...},
|
||||
identity<bool>{});
|
||||
@ -630,7 +615,7 @@ class zip_shortest : public zip_common<zip_shortest<Iters...>, Iters...> {
|
||||
zip_shortest(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {}
|
||||
|
||||
bool operator==(const zip_shortest<Iters...> &other) const {
|
||||
return !test(other, index_sequence_for<Iters...>{});
|
||||
return !test(other, std::index_sequence_for<Iters...>{});
|
||||
}
|
||||
};
|
||||
|
||||
@ -646,18 +631,21 @@ template <template <typename...> class ItType, typename... Args> class zippy {
|
||||
private:
|
||||
std::tuple<Args...> ts;
|
||||
|
||||
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns>
|
||||
iterator begin_impl(std::index_sequence<Ns...>) const {
|
||||
return iterator(std::begin(std::get<Ns>(ts))...);
|
||||
}
|
||||
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const {
|
||||
return iterator(std::end(std::get<Ns>(ts))...);
|
||||
}
|
||||
|
||||
public:
|
||||
zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
|
||||
|
||||
iterator begin() const { return begin_impl(index_sequence_for<Args...>{}); }
|
||||
iterator end() const { return end_impl(index_sequence_for<Args...>{}); }
|
||||
iterator begin() const {
|
||||
return begin_impl(std::index_sequence_for<Args...>{});
|
||||
}
|
||||
iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); }
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
@ -727,20 +715,20 @@ class zip_longest_iterator
|
||||
|
||||
template <size_t... Ns>
|
||||
bool test(const zip_longest_iterator<Iters...> &other,
|
||||
index_sequence<Ns...>) const {
|
||||
std::index_sequence<Ns...>) const {
|
||||
return llvm::any_of(
|
||||
std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
|
||||
std::get<Ns>(other.iterators)...},
|
||||
identity<bool>{});
|
||||
}
|
||||
|
||||
template <size_t... Ns> value_type deref(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const {
|
||||
return value_type(
|
||||
deref_or_none(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...);
|
||||
}
|
||||
|
||||
template <size_t... Ns>
|
||||
decltype(iterators) tup_inc(index_sequence<Ns...>) const {
|
||||
decltype(iterators) tup_inc(std::index_sequence<Ns...>) const {
|
||||
return std::tuple<Iters...>(
|
||||
next_or_end(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...);
|
||||
}
|
||||
@ -750,17 +738,19 @@ class zip_longest_iterator
|
||||
: iterators(std::forward<Iters>(ts.first)...),
|
||||
end_iterators(std::forward<Iters>(ts.second)...) {}
|
||||
|
||||
value_type operator*() { return deref(index_sequence_for<Iters...>{}); }
|
||||
value_type operator*() { return deref(std::index_sequence_for<Iters...>{}); }
|
||||
|
||||
value_type operator*() const { return deref(index_sequence_for<Iters...>{}); }
|
||||
value_type operator*() const {
|
||||
return deref(std::index_sequence_for<Iters...>{});
|
||||
}
|
||||
|
||||
zip_longest_iterator<Iters...> &operator++() {
|
||||
iterators = tup_inc(index_sequence_for<Iters...>{});
|
||||
iterators = tup_inc(std::index_sequence_for<Iters...>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const zip_longest_iterator<Iters...> &other) const {
|
||||
return !test(other, index_sequence_for<Iters...>{});
|
||||
return !test(other, std::index_sequence_for<Iters...>{});
|
||||
}
|
||||
};
|
||||
|
||||
@ -777,12 +767,13 @@ template <typename... Args> class zip_longest_range {
|
||||
private:
|
||||
std::tuple<Args...> ts;
|
||||
|
||||
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns>
|
||||
iterator begin_impl(std::index_sequence<Ns...>) const {
|
||||
return iterator(std::make_pair(adl_begin(std::get<Ns>(ts)),
|
||||
adl_end(std::get<Ns>(ts)))...);
|
||||
}
|
||||
|
||||
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const {
|
||||
return iterator(std::make_pair(adl_end(std::get<Ns>(ts)),
|
||||
adl_end(std::get<Ns>(ts)))...);
|
||||
}
|
||||
@ -790,8 +781,10 @@ template <typename... Args> class zip_longest_range {
|
||||
public:
|
||||
zip_longest_range(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
|
||||
|
||||
iterator begin() const { return begin_impl(index_sequence_for<Args...>{}); }
|
||||
iterator end() const { return end_impl(index_sequence_for<Args...>{}); }
|
||||
iterator begin() const {
|
||||
return begin_impl(std::index_sequence_for<Args...>{});
|
||||
}
|
||||
iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
@ -847,7 +840,7 @@ class concat_iterator
|
||||
/// Increments the first non-end iterator.
|
||||
///
|
||||
/// It is an error to call this with all iterators at the end.
|
||||
template <size_t... Ns> void increment(index_sequence<Ns...>) {
|
||||
template <size_t... Ns> void increment(std::index_sequence<Ns...>) {
|
||||
// Build a sequence of functions to increment each iterator if possible.
|
||||
bool (concat_iterator::*IncrementHelperFns[])() = {
|
||||
&concat_iterator::incrementHelper<Ns>...};
|
||||
@ -876,7 +869,7 @@ class concat_iterator
|
||||
/// reference.
|
||||
///
|
||||
/// It is an error to call this with all iterators at the end.
|
||||
template <size_t... Ns> ValueT &get(index_sequence<Ns...>) const {
|
||||
template <size_t... Ns> ValueT &get(std::index_sequence<Ns...>) const {
|
||||
// Build a sequence of functions to get from iterator if possible.
|
||||
ValueT *(concat_iterator::*GetHelperFns[])() const = {
|
||||
&concat_iterator::getHelper<Ns>...};
|
||||
@ -901,11 +894,13 @@ class concat_iterator
|
||||
using BaseT::operator++;
|
||||
|
||||
concat_iterator &operator++() {
|
||||
increment(index_sequence_for<IterTs...>());
|
||||
increment(std::index_sequence_for<IterTs...>());
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueT &operator*() const { return get(index_sequence_for<IterTs...>()); }
|
||||
ValueT &operator*() const {
|
||||
return get(std::index_sequence_for<IterTs...>());
|
||||
}
|
||||
|
||||
bool operator==(const concat_iterator &RHS) const {
|
||||
return Begins == RHS.Begins && Ends == RHS.Ends;
|
||||
@ -928,10 +923,10 @@ template <typename ValueT, typename... RangeTs> class concat_range {
|
||||
private:
|
||||
std::tuple<RangeTs...> Ranges;
|
||||
|
||||
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
|
||||
template <size_t... Ns> iterator begin_impl(std::index_sequence<Ns...>) {
|
||||
return iterator(std::get<Ns>(Ranges)...);
|
||||
}
|
||||
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
|
||||
template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) {
|
||||
return iterator(make_range(std::end(std::get<Ns>(Ranges)),
|
||||
std::end(std::get<Ns>(Ranges)))...);
|
||||
}
|
||||
@ -940,8 +935,8 @@ template <typename ValueT, typename... RangeTs> class concat_range {
|
||||
concat_range(RangeTs &&... Ranges)
|
||||
: Ranges(std::forward<RangeTs>(Ranges)...) {}
|
||||
|
||||
iterator begin() { return begin_impl(index_sequence_for<RangeTs...>{}); }
|
||||
iterator end() { return end_impl(index_sequence_for<RangeTs...>{}); }
|
||||
iterator begin() { return begin_impl(std::index_sequence_for<RangeTs...>{}); }
|
||||
iterator end() { return end_impl(std::index_sequence_for<RangeTs...>{}); }
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
@ -990,28 +985,6 @@ struct on_first {
|
||||
}
|
||||
};
|
||||
|
||||
// A subset of N3658. More stuff can be added as-needed.
|
||||
|
||||
/// Represents a compile-time sequence of integers.
|
||||
template <class T, T... I> struct integer_sequence {
|
||||
using value_type = T;
|
||||
|
||||
static constexpr size_t size() { return sizeof...(I); }
|
||||
};
|
||||
|
||||
/// 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...> {};
|
||||
|
||||
/// Creates a compile-time integer sequence for a parameter pack.
|
||||
template <class... Ts>
|
||||
struct index_sequence_for : build_index_impl<sizeof...(Ts)> {};
|
||||
|
||||
/// Utility type to build an inheritance chain that makes it easy to rank
|
||||
/// overload candidates.
|
||||
template <int N> struct rank : rank<N - 1> {};
|
||||
@ -1391,41 +1364,6 @@ void replace(Container &Cont, typename Container::iterator ContIt,
|
||||
// Extra additions to <memory>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Implement make_unique according to N3656.
|
||||
|
||||
/// Constructs a `new T()` with the given args and returns a
|
||||
/// `unique_ptr<T>` which owns the object.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// auto p = make_unique<int>();
|
||||
/// auto p = make_unique<std::tuple<int, int>>(0, 1);
|
||||
template <class T, class... Args>
|
||||
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
||||
make_unique(Args &&... args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/// Constructs a `new T[n]` with the given args and returns a
|
||||
/// `unique_ptr<T[]>` which owns the object.
|
||||
///
|
||||
/// \param n size of the new array.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// auto p = make_unique<int[]>(2); // value-initializes the array with 0's.
|
||||
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]());
|
||||
}
|
||||
|
||||
/// 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 &&...) = delete;
|
||||
|
||||
struct FreeDeleter {
|
||||
void operator()(void* v) {
|
||||
::free(v);
|
||||
@ -1439,20 +1377,6 @@ 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 {
|
||||
@ -1580,7 +1504,7 @@ template <typename R> detail::enumerator<R> enumerate(R &&TheRange) {
|
||||
namespace detail {
|
||||
|
||||
template <typename F, typename Tuple, std::size_t... I>
|
||||
auto apply_tuple_impl(F &&f, Tuple &&t, index_sequence<I...>)
|
||||
auto apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>)
|
||||
-> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...)) {
|
||||
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
@ -1593,9 +1517,9 @@ auto apply_tuple_impl(F &&f, Tuple &&t, index_sequence<I...>)
|
||||
template <typename F, typename Tuple>
|
||||
auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(
|
||||
std::forward<F>(f), std::forward<Tuple>(t),
|
||||
build_index_impl<
|
||||
std::make_index_sequence<
|
||||
std::tuple_size<typename std::decay<Tuple>::type>::value>{})) {
|
||||
using Indices = build_index_impl<
|
||||
using Indices = std::make_index_sequence<
|
||||
std::tuple_size<typename std::decay<Tuple>::type>::value>;
|
||||
|
||||
return detail::apply_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t),
|
||||
|
@ -290,7 +290,7 @@ class SmallBitVector {
|
||||
++Prev;
|
||||
uintptr_t Bits = getSmallBits();
|
||||
// Mask in previous bits.
|
||||
uintptr_t Mask = (1 << Prev) - 1;
|
||||
uintptr_t Mask = (uintptr_t(1) << Prev) - 1;
|
||||
Bits |= Mask;
|
||||
|
||||
if (Bits == ~uintptr_t(0) || Prev + 1 >= getSmallSize())
|
||||
|
@ -44,38 +44,39 @@ class raw_ostream;
|
||||
class raw_fd_ostream;
|
||||
class StringRef;
|
||||
|
||||
class Statistic {
|
||||
class StatisticBase {
|
||||
public:
|
||||
const char *DebugType;
|
||||
const char *Name;
|
||||
const char *Desc;
|
||||
std::atomic<unsigned> Value;
|
||||
std::atomic<bool> Initialized;
|
||||
|
||||
unsigned getValue() const { return Value.load(std::memory_order_relaxed); }
|
||||
StatisticBase(const char *DebugType, const char *Name, const char *Desc)
|
||||
: DebugType(DebugType), Name(Name), Desc(Desc) {}
|
||||
|
||||
const char *getDebugType() const { return DebugType; }
|
||||
const char *getName() const { return Name; }
|
||||
const char *getDesc() const { return Desc; }
|
||||
};
|
||||
|
||||
/// construct - This should only be called for non-global statistics.
|
||||
void construct(const char *debugtype, const char *name, const char *desc) {
|
||||
DebugType = debugtype;
|
||||
Name = name;
|
||||
Desc = desc;
|
||||
Value = 0;
|
||||
Initialized = false;
|
||||
}
|
||||
class TrackingStatistic : public StatisticBase {
|
||||
public:
|
||||
std::atomic<unsigned> Value;
|
||||
std::atomic<bool> Initialized;
|
||||
|
||||
TrackingStatistic(const char *DebugType, const char *Name, const char *Desc)
|
||||
: StatisticBase(DebugType, Name, Desc), Value(0), Initialized(false) {}
|
||||
|
||||
unsigned getValue() const { return Value.load(std::memory_order_relaxed); }
|
||||
|
||||
// Allow use of this class as the value itself.
|
||||
operator unsigned() const { return getValue(); }
|
||||
|
||||
#if LLVM_ENABLE_STATS
|
||||
const Statistic &operator=(unsigned Val) {
|
||||
const TrackingStatistic &operator=(unsigned Val) {
|
||||
Value.store(Val, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
const Statistic &operator++() {
|
||||
const TrackingStatistic &operator++() {
|
||||
Value.fetch_add(1, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
@ -85,7 +86,7 @@ class Statistic {
|
||||
return Value.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
const Statistic &operator--() {
|
||||
const TrackingStatistic &operator--() {
|
||||
Value.fetch_sub(1, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
@ -95,14 +96,14 @@ class Statistic {
|
||||
return Value.fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
const Statistic &operator+=(unsigned V) {
|
||||
const TrackingStatistic &operator+=(unsigned V) {
|
||||
if (V == 0)
|
||||
return *this;
|
||||
Value.fetch_add(V, std::memory_order_relaxed);
|
||||
return init();
|
||||
}
|
||||
|
||||
const Statistic &operator-=(unsigned V) {
|
||||
const TrackingStatistic &operator-=(unsigned V) {
|
||||
if (V == 0)
|
||||
return *this;
|
||||
Value.fetch_sub(V, std::memory_order_relaxed);
|
||||
@ -119,42 +120,8 @@ class Statistic {
|
||||
init();
|
||||
}
|
||||
|
||||
#else // Statistics are disabled in release builds.
|
||||
|
||||
const Statistic &operator=(unsigned Val) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Statistic &operator++() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned operator++(int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Statistic &operator--() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned operator--(int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Statistic &operator+=(const unsigned &V) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Statistic &operator-=(const unsigned &V) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void updateMax(unsigned V) {}
|
||||
|
||||
#endif // LLVM_ENABLE_STATS
|
||||
|
||||
protected:
|
||||
Statistic &init() {
|
||||
TrackingStatistic &init() {
|
||||
if (!Initialized.load(std::memory_order_acquire))
|
||||
RegisterStatistic();
|
||||
return *this;
|
||||
@ -163,10 +130,47 @@ class Statistic {
|
||||
void RegisterStatistic();
|
||||
};
|
||||
|
||||
class NoopStatistic : public StatisticBase {
|
||||
public:
|
||||
using StatisticBase::StatisticBase;
|
||||
|
||||
unsigned getValue() const { return 0; }
|
||||
|
||||
// Allow use of this class as the value itself.
|
||||
operator unsigned() const { return 0; }
|
||||
|
||||
const NoopStatistic &operator=(unsigned Val) { return *this; }
|
||||
|
||||
const NoopStatistic &operator++() { return *this; }
|
||||
|
||||
unsigned operator++(int) { return 0; }
|
||||
|
||||
const NoopStatistic &operator--() { return *this; }
|
||||
|
||||
unsigned operator--(int) { return 0; }
|
||||
|
||||
const NoopStatistic &operator+=(const unsigned &V) { return *this; }
|
||||
|
||||
const NoopStatistic &operator-=(const unsigned &V) { return *this; }
|
||||
|
||||
void updateMax(unsigned V) {}
|
||||
};
|
||||
|
||||
#if LLVM_ENABLE_STATS
|
||||
using Statistic = TrackingStatistic;
|
||||
#else
|
||||
using Statistic = NoopStatistic;
|
||||
#endif
|
||||
|
||||
// STATISTIC - A macro to make definition of statistics really simple. This
|
||||
// automatically passes the DEBUG_TYPE of the file into the statistic.
|
||||
#define STATISTIC(VARNAME, DESC) \
|
||||
static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, {false}}
|
||||
static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC}
|
||||
|
||||
// ALWAYS_ENABLED_STATISTIC - A macro to define a statistic like STATISTIC but
|
||||
// it is enabled even if LLVM_ENABLE_STATS is off.
|
||||
#define ALWAYS_ENABLED_STATISTIC(VARNAME, DESC) \
|
||||
static llvm::TrackingStatistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC}
|
||||
|
||||
/// Enable the collection and printing of statistics.
|
||||
void EnableStatistics(bool PrintOnExit = true);
|
||||
|
@ -345,7 +345,7 @@ inline void join_items_impl(std::string &Result, Sep Separator, const Arg1 &A1,
|
||||
join_items_impl(Result, Separator, std::forward<Args>(Items)...);
|
||||
}
|
||||
|
||||
inline size_t join_one_item_size(char C) { return 1; }
|
||||
inline size_t join_one_item_size(char) { return 1; }
|
||||
inline size_t join_one_item_size(const char *S) { return S ? ::strlen(S) : 0; }
|
||||
|
||||
template <typename T> inline size_t join_one_item_size(const T &Str) {
|
||||
|
@ -118,36 +118,59 @@ class StringMapImpl {
|
||||
}
|
||||
};
|
||||
|
||||
/// StringMapEntry - This is used to represent one value that is inserted into
|
||||
/// a StringMap. It contains the Value itself and the key: the string length
|
||||
/// and data.
|
||||
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
|
||||
///
|
||||
/// Factored out into a separate base class to make it easier to specialize.
|
||||
/// This is primarily intended to support StringSet, which doesn't need a value
|
||||
/// stored at all.
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry : public StringMapEntryBase {
|
||||
class StringMapEntryStorage : public StringMapEntryBase {
|
||||
public:
|
||||
ValueTy second;
|
||||
|
||||
explicit StringMapEntry(size_t strLen)
|
||||
explicit StringMapEntryStorage(size_t strLen)
|
||||
: StringMapEntryBase(strLen), second() {}
|
||||
template <typename... InitTy>
|
||||
StringMapEntry(size_t strLen, InitTy &&... InitVals)
|
||||
StringMapEntryStorage(size_t strLen, InitTy &&... InitVals)
|
||||
: StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
|
||||
StringMapEntry(StringMapEntry &E) = delete;
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), getKeyLength());
|
||||
}
|
||||
StringMapEntryStorage(StringMapEntryStorage &E) = delete;
|
||||
|
||||
const ValueTy &getValue() const { return second; }
|
||||
ValueTy &getValue() { return second; }
|
||||
|
||||
void setValue(const ValueTy &V) { second = V; }
|
||||
};
|
||||
|
||||
template<>
|
||||
class StringMapEntryStorage<NoneType> : public StringMapEntryBase {
|
||||
public:
|
||||
explicit StringMapEntryStorage(size_t strLen, NoneType none = None)
|
||||
: StringMapEntryBase(strLen) {}
|
||||
StringMapEntryStorage(StringMapEntryStorage &E) = delete;
|
||||
|
||||
NoneType getValue() const { return None; }
|
||||
};
|
||||
|
||||
/// StringMapEntry - This is used to represent one value that is inserted into
|
||||
/// a StringMap. It contains the Value itself and the key: the string length
|
||||
/// and data.
|
||||
template<typename ValueTy>
|
||||
class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
|
||||
public:
|
||||
using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
|
||||
|
||||
StringRef getKey() const {
|
||||
return StringRef(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// getKeyData - Return the start of the string data that is the key for this
|
||||
/// value. The string data is always stored immediately after the
|
||||
/// StringMapEntry object.
|
||||
const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
|
||||
|
||||
StringRef first() const { return StringRef(getKeyData(), getKeyLength()); }
|
||||
StringRef first() const {
|
||||
return StringRef(getKeyData(), this->getKeyLength());
|
||||
}
|
||||
|
||||
/// Create a StringMapEntry for the specified key construct the value using
|
||||
/// \p InitiVals.
|
||||
@ -199,7 +222,7 @@ class StringMapEntry : public StringMapEntryBase {
|
||||
template<typename AllocatorTy>
|
||||
void Destroy(AllocatorTy &Allocator) {
|
||||
// Free memory referenced by the item.
|
||||
size_t AllocSize = sizeof(StringMapEntry) + getKeyLength() + 1;
|
||||
size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
|
||||
this->~StringMapEntry();
|
||||
Allocator.Deallocate(static_cast<void *>(this), AllocSize);
|
||||
}
|
||||
@ -391,6 +414,16 @@ class StringMap : public StringMapImpl {
|
||||
return try_emplace(KV.first, std::move(KV.second));
|
||||
}
|
||||
|
||||
/// Inserts an element or assigns to the current element if the key already
|
||||
/// exists. The return type is the same as try_emplace.
|
||||
template <typename V>
|
||||
std::pair<iterator, bool> insert_or_assign(StringRef Key, V &&Val) {
|
||||
auto Ret = try_emplace(Key, std::forward<V>(Val));
|
||||
if (!Ret.second)
|
||||
Ret.first->second = std::forward<V>(Val);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/// Emplace a new element for the specified key into the map if the key isn't
|
||||
/// already in the map. The bool component of the returned pair is true
|
||||
/// if and only if the insertion takes place, and the iterator component of
|
||||
|
@ -67,6 +67,20 @@ namespace llvm {
|
||||
return ::memcmp(Lhs,Rhs,Length);
|
||||
}
|
||||
|
||||
// Constexpr version of std::strlen.
|
||||
static constexpr size_t strLen(const char *Str) {
|
||||
#if __cplusplus > 201402L
|
||||
return std::char_traits<char>::length(Str);
|
||||
#elif __has_builtin(__builtin_strlen) || defined(__GNUC__)
|
||||
return __builtin_strlen(Str);
|
||||
#else
|
||||
const char *Begin = Str;
|
||||
while (*Str != '\0')
|
||||
++Str;
|
||||
return Str - Begin;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
/// @name Constructors
|
||||
/// @{
|
||||
@ -79,8 +93,8 @@ namespace llvm {
|
||||
StringRef(std::nullptr_t) = delete;
|
||||
|
||||
/// Construct a string ref from a cstring.
|
||||
/*implicit*/ StringRef(const char *Str)
|
||||
: Data(Str), Length(Str ? ::strlen(Str) : 0) {}
|
||||
/*implicit*/ constexpr StringRef(const char *Str)
|
||||
: Data(Str), Length(Str ? strLen(Str) : 0) {}
|
||||
|
||||
/// Construct a string ref from a pointer and length.
|
||||
/*implicit*/ constexpr StringRef(const char *data, size_t length)
|
||||
|
@ -24,8 +24,8 @@ namespace llvm {
|
||||
|
||||
/// StringSet - A wrapper for StringMap that provides set-like functionality.
|
||||
template <class AllocatorTy = MallocAllocator>
|
||||
class StringSet : public StringMap<char, AllocatorTy> {
|
||||
using base = StringMap<char, AllocatorTy>;
|
||||
class StringSet : public StringMap<NoneType, AllocatorTy> {
|
||||
using base = StringMap<NoneType, AllocatorTy>;
|
||||
|
||||
public:
|
||||
StringSet() = default;
|
||||
@ -37,13 +37,13 @@ namespace llvm {
|
||||
|
||||
std::pair<typename base::iterator, bool> insert(StringRef Key) {
|
||||
assert(!Key.empty());
|
||||
return base::insert(std::make_pair(Key, '\0'));
|
||||
return base::insert(std::make_pair(Key, None));
|
||||
}
|
||||
|
||||
template <typename InputIt>
|
||||
void insert(const InputIt &Begin, const InputIt &End) {
|
||||
for (auto It = Begin; It != End; ++It)
|
||||
base::insert(std::make_pair(*It, '\0'));
|
||||
base::insert(std::make_pair(*It, None));
|
||||
}
|
||||
|
||||
template <typename ValueTy>
|
||||
|
@ -31,6 +31,10 @@ class TinyPtrVector {
|
||||
public:
|
||||
using VecTy = SmallVector<EltTy, 4>;
|
||||
using value_type = typename VecTy::value_type;
|
||||
// EltTy must be the first pointer type so that is<EltTy> is true for the
|
||||
// default-constructed PtrUnion. This allows an empty TinyPtrVector to
|
||||
// naturally vend a begin/end iterator of type EltTy* without an additional
|
||||
// check for the empty state.
|
||||
using PtrUnion = PointerUnion<EltTy, VecTy *>;
|
||||
|
||||
private:
|
||||
@ -96,14 +100,14 @@ class TinyPtrVector {
|
||||
if (RHS.Val.template is<EltTy>()) {
|
||||
V->clear();
|
||||
V->push_back(RHS.front());
|
||||
RHS.Val = (EltTy)nullptr;
|
||||
RHS.Val = EltTy();
|
||||
return *this;
|
||||
}
|
||||
delete V;
|
||||
}
|
||||
|
||||
Val = RHS.Val;
|
||||
RHS.Val = (EltTy)nullptr;
|
||||
RHS.Val = EltTy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -213,9 +217,9 @@ class TinyPtrVector {
|
||||
|
||||
EltTy operator[](unsigned i) const {
|
||||
assert(!Val.isNull() && "can't index into an empty vector");
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||
if (Val.template is<EltTy>()) {
|
||||
assert(i == 0 && "tinyvector index out of range");
|
||||
return V;
|
||||
return Val.template get<EltTy>();
|
||||
}
|
||||
|
||||
assert(i < Val.template get<VecTy*>()->size() &&
|
||||
@ -225,29 +229,29 @@ class TinyPtrVector {
|
||||
|
||||
EltTy front() const {
|
||||
assert(!empty() && "vector empty");
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>())
|
||||
return V;
|
||||
if (Val.template is<EltTy>())
|
||||
return Val.template get<EltTy>();
|
||||
return Val.template get<VecTy*>()->front();
|
||||
}
|
||||
|
||||
EltTy back() const {
|
||||
assert(!empty() && "vector empty");
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>())
|
||||
return V;
|
||||
if (Val.template is<EltTy>())
|
||||
return Val.template get<EltTy>();
|
||||
return Val.template get<VecTy*>()->back();
|
||||
}
|
||||
|
||||
void push_back(EltTy NewVal) {
|
||||
assert(NewVal && "Can't add a null value");
|
||||
|
||||
// If we have nothing, add something.
|
||||
if (Val.isNull()) {
|
||||
Val = NewVal;
|
||||
assert(!Val.isNull() && "Can't add a null value");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a single value, convert to a vector.
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||
if (Val.template is<EltTy>()) {
|
||||
EltTy V = Val.template get<EltTy>();
|
||||
Val = new VecTy();
|
||||
Val.template get<VecTy*>()->push_back(V);
|
||||
}
|
||||
@ -267,7 +271,7 @@ class TinyPtrVector {
|
||||
void clear() {
|
||||
// If we have a single value, convert to empty.
|
||||
if (Val.template is<EltTy>()) {
|
||||
Val = (EltTy)nullptr;
|
||||
Val = EltTy();
|
||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||
// If we have a vector form, just clear it.
|
||||
Vec->clear();
|
||||
@ -282,7 +286,7 @@ class TinyPtrVector {
|
||||
// If we have a single value, convert to empty.
|
||||
if (Val.template is<EltTy>()) {
|
||||
if (I == begin())
|
||||
Val = (EltTy)nullptr;
|
||||
Val = EltTy();
|
||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||
// multiple items in a vector; just do the erase, there is no
|
||||
// benefit to collapsing back to a pointer
|
||||
@ -298,7 +302,7 @@ class TinyPtrVector {
|
||||
|
||||
if (Val.template is<EltTy>()) {
|
||||
if (S == begin() && S != E)
|
||||
Val = (EltTy)nullptr;
|
||||
Val = EltTy();
|
||||
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
||||
return Vec->erase(S, E);
|
||||
}
|
||||
@ -313,7 +317,8 @@ class TinyPtrVector {
|
||||
return std::prev(end());
|
||||
}
|
||||
assert(!Val.isNull() && "Null value with non-end insert iterator.");
|
||||
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||
if (Val.template is<EltTy>()) {
|
||||
EltTy V = Val.template get<EltTy>();
|
||||
assert(I == begin());
|
||||
Val = Elt;
|
||||
push_back(V);
|
||||
@ -339,7 +344,8 @@ class TinyPtrVector {
|
||||
}
|
||||
|
||||
Val = new VecTy();
|
||||
} else if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
||||
} else if (Val.template is<EltTy>()) {
|
||||
EltTy V = Val.template get<EltTy>();
|
||||
Val = new VecTy();
|
||||
Val.template get<VecTy*>()->push_back(V);
|
||||
}
|
||||
|
@ -1,330 +0,0 @@
|
||||
//===- VariadicFunction.h - Variadic Functions ------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements compile-time type-safe variadic functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_VARIADICFUNCTION_H
|
||||
#define LLVM_ADT_VARIADICFUNCTION_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Define macros to aid in expanding a comma separated series with the index of
|
||||
// the series pasted onto the last token.
|
||||
#define LLVM_COMMA_JOIN1(x) x ## 0
|
||||
#define LLVM_COMMA_JOIN2(x) LLVM_COMMA_JOIN1(x), x ## 1
|
||||
#define LLVM_COMMA_JOIN3(x) LLVM_COMMA_JOIN2(x), x ## 2
|
||||
#define LLVM_COMMA_JOIN4(x) LLVM_COMMA_JOIN3(x), x ## 3
|
||||
#define LLVM_COMMA_JOIN5(x) LLVM_COMMA_JOIN4(x), x ## 4
|
||||
#define LLVM_COMMA_JOIN6(x) LLVM_COMMA_JOIN5(x), x ## 5
|
||||
#define LLVM_COMMA_JOIN7(x) LLVM_COMMA_JOIN6(x), x ## 6
|
||||
#define LLVM_COMMA_JOIN8(x) LLVM_COMMA_JOIN7(x), x ## 7
|
||||
#define LLVM_COMMA_JOIN9(x) LLVM_COMMA_JOIN8(x), x ## 8
|
||||
#define LLVM_COMMA_JOIN10(x) LLVM_COMMA_JOIN9(x), x ## 9
|
||||
#define LLVM_COMMA_JOIN11(x) LLVM_COMMA_JOIN10(x), x ## 10
|
||||
#define LLVM_COMMA_JOIN12(x) LLVM_COMMA_JOIN11(x), x ## 11
|
||||
#define LLVM_COMMA_JOIN13(x) LLVM_COMMA_JOIN12(x), x ## 12
|
||||
#define LLVM_COMMA_JOIN14(x) LLVM_COMMA_JOIN13(x), x ## 13
|
||||
#define LLVM_COMMA_JOIN15(x) LLVM_COMMA_JOIN14(x), x ## 14
|
||||
#define LLVM_COMMA_JOIN16(x) LLVM_COMMA_JOIN15(x), x ## 15
|
||||
#define LLVM_COMMA_JOIN17(x) LLVM_COMMA_JOIN16(x), x ## 16
|
||||
#define LLVM_COMMA_JOIN18(x) LLVM_COMMA_JOIN17(x), x ## 17
|
||||
#define LLVM_COMMA_JOIN19(x) LLVM_COMMA_JOIN18(x), x ## 18
|
||||
#define LLVM_COMMA_JOIN20(x) LLVM_COMMA_JOIN19(x), x ## 19
|
||||
#define LLVM_COMMA_JOIN21(x) LLVM_COMMA_JOIN20(x), x ## 20
|
||||
#define LLVM_COMMA_JOIN22(x) LLVM_COMMA_JOIN21(x), x ## 21
|
||||
#define LLVM_COMMA_JOIN23(x) LLVM_COMMA_JOIN22(x), x ## 22
|
||||
#define LLVM_COMMA_JOIN24(x) LLVM_COMMA_JOIN23(x), x ## 23
|
||||
#define LLVM_COMMA_JOIN25(x) LLVM_COMMA_JOIN24(x), x ## 24
|
||||
#define LLVM_COMMA_JOIN26(x) LLVM_COMMA_JOIN25(x), x ## 25
|
||||
#define LLVM_COMMA_JOIN27(x) LLVM_COMMA_JOIN26(x), x ## 26
|
||||
#define LLVM_COMMA_JOIN28(x) LLVM_COMMA_JOIN27(x), x ## 27
|
||||
#define LLVM_COMMA_JOIN29(x) LLVM_COMMA_JOIN28(x), x ## 28
|
||||
#define LLVM_COMMA_JOIN30(x) LLVM_COMMA_JOIN29(x), x ## 29
|
||||
#define LLVM_COMMA_JOIN31(x) LLVM_COMMA_JOIN30(x), x ## 30
|
||||
#define LLVM_COMMA_JOIN32(x) LLVM_COMMA_JOIN31(x), x ## 31
|
||||
|
||||
/// Class which can simulate a type-safe variadic function.
|
||||
///
|
||||
/// The VariadicFunction class template makes it easy to define
|
||||
/// type-safe variadic functions where all arguments have the same
|
||||
/// type.
|
||||
///
|
||||
/// Suppose we need a variadic function like this:
|
||||
///
|
||||
/// ResultT Foo(const ArgT &A_0, const ArgT &A_1, ..., const ArgT &A_N);
|
||||
///
|
||||
/// Instead of many overloads of Foo(), we only need to define a helper
|
||||
/// function that takes an array of arguments:
|
||||
///
|
||||
/// ResultT FooImpl(ArrayRef<const ArgT *> Args) {
|
||||
/// // 'Args[i]' is a pointer to the i-th argument passed to Foo().
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// and then define Foo() like this:
|
||||
///
|
||||
/// const VariadicFunction<ResultT, ArgT, FooImpl> Foo;
|
||||
///
|
||||
/// VariadicFunction takes care of defining the overloads of Foo().
|
||||
///
|
||||
/// Actually, Foo is a function object (i.e. functor) instead of a plain
|
||||
/// function. This object is stateless and its constructor/destructor
|
||||
/// does nothing, so it's safe to create global objects and call Foo(...) at
|
||||
/// any time.
|
||||
///
|
||||
/// Sometimes we need a variadic function to have some fixed leading
|
||||
/// arguments whose types may be different from that of the optional
|
||||
/// arguments. For example:
|
||||
///
|
||||
/// bool FullMatch(const StringRef &S, const RE &Regex,
|
||||
/// const ArgT &A_0, ..., const ArgT &A_N);
|
||||
///
|
||||
/// VariadicFunctionN is for such cases, where N is the number of fixed
|
||||
/// arguments. It is like VariadicFunction, except that it takes N more
|
||||
/// template arguments for the types of the fixed arguments:
|
||||
///
|
||||
/// bool FullMatchImpl(const StringRef &S, const RE &Regex,
|
||||
/// ArrayRef<const ArgT *> Args) { ... }
|
||||
/// const VariadicFunction2<bool, const StringRef&,
|
||||
/// const RE&, ArgT, FullMatchImpl>
|
||||
/// FullMatch;
|
||||
///
|
||||
/// Currently VariadicFunction and friends support up-to 3
|
||||
/// fixed leading arguments and up-to 32 optional arguments.
|
||||
template <typename ResultT, typename ArgT,
|
||||
ResultT (*Func)(ArrayRef<const ArgT *>)>
|
||||
struct VariadicFunction {
|
||||
ResultT operator()() const {
|
||||
return Func(None);
|
||||
}
|
||||
|
||||
#define LLVM_DEFINE_OVERLOAD(N) \
|
||||
ResultT operator()(LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
|
||||
const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
|
||||
return Func(makeArrayRef(Args)); \
|
||||
}
|
||||
LLVM_DEFINE_OVERLOAD(1)
|
||||
LLVM_DEFINE_OVERLOAD(2)
|
||||
LLVM_DEFINE_OVERLOAD(3)
|
||||
LLVM_DEFINE_OVERLOAD(4)
|
||||
LLVM_DEFINE_OVERLOAD(5)
|
||||
LLVM_DEFINE_OVERLOAD(6)
|
||||
LLVM_DEFINE_OVERLOAD(7)
|
||||
LLVM_DEFINE_OVERLOAD(8)
|
||||
LLVM_DEFINE_OVERLOAD(9)
|
||||
LLVM_DEFINE_OVERLOAD(10)
|
||||
LLVM_DEFINE_OVERLOAD(11)
|
||||
LLVM_DEFINE_OVERLOAD(12)
|
||||
LLVM_DEFINE_OVERLOAD(13)
|
||||
LLVM_DEFINE_OVERLOAD(14)
|
||||
LLVM_DEFINE_OVERLOAD(15)
|
||||
LLVM_DEFINE_OVERLOAD(16)
|
||||
LLVM_DEFINE_OVERLOAD(17)
|
||||
LLVM_DEFINE_OVERLOAD(18)
|
||||
LLVM_DEFINE_OVERLOAD(19)
|
||||
LLVM_DEFINE_OVERLOAD(20)
|
||||
LLVM_DEFINE_OVERLOAD(21)
|
||||
LLVM_DEFINE_OVERLOAD(22)
|
||||
LLVM_DEFINE_OVERLOAD(23)
|
||||
LLVM_DEFINE_OVERLOAD(24)
|
||||
LLVM_DEFINE_OVERLOAD(25)
|
||||
LLVM_DEFINE_OVERLOAD(26)
|
||||
LLVM_DEFINE_OVERLOAD(27)
|
||||
LLVM_DEFINE_OVERLOAD(28)
|
||||
LLVM_DEFINE_OVERLOAD(29)
|
||||
LLVM_DEFINE_OVERLOAD(30)
|
||||
LLVM_DEFINE_OVERLOAD(31)
|
||||
LLVM_DEFINE_OVERLOAD(32)
|
||||
#undef LLVM_DEFINE_OVERLOAD
|
||||
};
|
||||
|
||||
template <typename ResultT, typename Param0T, typename ArgT,
|
||||
ResultT (*Func)(Param0T, ArrayRef<const ArgT *>)>
|
||||
struct VariadicFunction1 {
|
||||
ResultT operator()(Param0T P0) const {
|
||||
return Func(P0, None);
|
||||
}
|
||||
|
||||
#define LLVM_DEFINE_OVERLOAD(N) \
|
||||
ResultT operator()(Param0T P0, LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
|
||||
const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
|
||||
return Func(P0, makeArrayRef(Args)); \
|
||||
}
|
||||
LLVM_DEFINE_OVERLOAD(1)
|
||||
LLVM_DEFINE_OVERLOAD(2)
|
||||
LLVM_DEFINE_OVERLOAD(3)
|
||||
LLVM_DEFINE_OVERLOAD(4)
|
||||
LLVM_DEFINE_OVERLOAD(5)
|
||||
LLVM_DEFINE_OVERLOAD(6)
|
||||
LLVM_DEFINE_OVERLOAD(7)
|
||||
LLVM_DEFINE_OVERLOAD(8)
|
||||
LLVM_DEFINE_OVERLOAD(9)
|
||||
LLVM_DEFINE_OVERLOAD(10)
|
||||
LLVM_DEFINE_OVERLOAD(11)
|
||||
LLVM_DEFINE_OVERLOAD(12)
|
||||
LLVM_DEFINE_OVERLOAD(13)
|
||||
LLVM_DEFINE_OVERLOAD(14)
|
||||
LLVM_DEFINE_OVERLOAD(15)
|
||||
LLVM_DEFINE_OVERLOAD(16)
|
||||
LLVM_DEFINE_OVERLOAD(17)
|
||||
LLVM_DEFINE_OVERLOAD(18)
|
||||
LLVM_DEFINE_OVERLOAD(19)
|
||||
LLVM_DEFINE_OVERLOAD(20)
|
||||
LLVM_DEFINE_OVERLOAD(21)
|
||||
LLVM_DEFINE_OVERLOAD(22)
|
||||
LLVM_DEFINE_OVERLOAD(23)
|
||||
LLVM_DEFINE_OVERLOAD(24)
|
||||
LLVM_DEFINE_OVERLOAD(25)
|
||||
LLVM_DEFINE_OVERLOAD(26)
|
||||
LLVM_DEFINE_OVERLOAD(27)
|
||||
LLVM_DEFINE_OVERLOAD(28)
|
||||
LLVM_DEFINE_OVERLOAD(29)
|
||||
LLVM_DEFINE_OVERLOAD(30)
|
||||
LLVM_DEFINE_OVERLOAD(31)
|
||||
LLVM_DEFINE_OVERLOAD(32)
|
||||
#undef LLVM_DEFINE_OVERLOAD
|
||||
};
|
||||
|
||||
template <typename ResultT, typename Param0T, typename Param1T, typename ArgT,
|
||||
ResultT (*Func)(Param0T, Param1T, ArrayRef<const ArgT *>)>
|
||||
struct VariadicFunction2 {
|
||||
ResultT operator()(Param0T P0, Param1T P1) const {
|
||||
return Func(P0, P1, None);
|
||||
}
|
||||
|
||||
#define LLVM_DEFINE_OVERLOAD(N) \
|
||||
ResultT operator()(Param0T P0, Param1T P1, \
|
||||
LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
|
||||
const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
|
||||
return Func(P0, P1, makeArrayRef(Args)); \
|
||||
}
|
||||
LLVM_DEFINE_OVERLOAD(1)
|
||||
LLVM_DEFINE_OVERLOAD(2)
|
||||
LLVM_DEFINE_OVERLOAD(3)
|
||||
LLVM_DEFINE_OVERLOAD(4)
|
||||
LLVM_DEFINE_OVERLOAD(5)
|
||||
LLVM_DEFINE_OVERLOAD(6)
|
||||
LLVM_DEFINE_OVERLOAD(7)
|
||||
LLVM_DEFINE_OVERLOAD(8)
|
||||
LLVM_DEFINE_OVERLOAD(9)
|
||||
LLVM_DEFINE_OVERLOAD(10)
|
||||
LLVM_DEFINE_OVERLOAD(11)
|
||||
LLVM_DEFINE_OVERLOAD(12)
|
||||
LLVM_DEFINE_OVERLOAD(13)
|
||||
LLVM_DEFINE_OVERLOAD(14)
|
||||
LLVM_DEFINE_OVERLOAD(15)
|
||||
LLVM_DEFINE_OVERLOAD(16)
|
||||
LLVM_DEFINE_OVERLOAD(17)
|
||||
LLVM_DEFINE_OVERLOAD(18)
|
||||
LLVM_DEFINE_OVERLOAD(19)
|
||||
LLVM_DEFINE_OVERLOAD(20)
|
||||
LLVM_DEFINE_OVERLOAD(21)
|
||||
LLVM_DEFINE_OVERLOAD(22)
|
||||
LLVM_DEFINE_OVERLOAD(23)
|
||||
LLVM_DEFINE_OVERLOAD(24)
|
||||
LLVM_DEFINE_OVERLOAD(25)
|
||||
LLVM_DEFINE_OVERLOAD(26)
|
||||
LLVM_DEFINE_OVERLOAD(27)
|
||||
LLVM_DEFINE_OVERLOAD(28)
|
||||
LLVM_DEFINE_OVERLOAD(29)
|
||||
LLVM_DEFINE_OVERLOAD(30)
|
||||
LLVM_DEFINE_OVERLOAD(31)
|
||||
LLVM_DEFINE_OVERLOAD(32)
|
||||
#undef LLVM_DEFINE_OVERLOAD
|
||||
};
|
||||
|
||||
template <typename ResultT, typename Param0T, typename Param1T,
|
||||
typename Param2T, typename ArgT,
|
||||
ResultT (*Func)(Param0T, Param1T, Param2T, ArrayRef<const ArgT *>)>
|
||||
struct VariadicFunction3 {
|
||||
ResultT operator()(Param0T P0, Param1T P1, Param2T P2) const {
|
||||
return Func(P0, P1, P2, None);
|
||||
}
|
||||
|
||||
#define LLVM_DEFINE_OVERLOAD(N) \
|
||||
ResultT operator()(Param0T P0, Param1T P1, Param2T P2, \
|
||||
LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
|
||||
const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
|
||||
return Func(P0, P1, P2, makeArrayRef(Args)); \
|
||||
}
|
||||
LLVM_DEFINE_OVERLOAD(1)
|
||||
LLVM_DEFINE_OVERLOAD(2)
|
||||
LLVM_DEFINE_OVERLOAD(3)
|
||||
LLVM_DEFINE_OVERLOAD(4)
|
||||
LLVM_DEFINE_OVERLOAD(5)
|
||||
LLVM_DEFINE_OVERLOAD(6)
|
||||
LLVM_DEFINE_OVERLOAD(7)
|
||||
LLVM_DEFINE_OVERLOAD(8)
|
||||
LLVM_DEFINE_OVERLOAD(9)
|
||||
LLVM_DEFINE_OVERLOAD(10)
|
||||
LLVM_DEFINE_OVERLOAD(11)
|
||||
LLVM_DEFINE_OVERLOAD(12)
|
||||
LLVM_DEFINE_OVERLOAD(13)
|
||||
LLVM_DEFINE_OVERLOAD(14)
|
||||
LLVM_DEFINE_OVERLOAD(15)
|
||||
LLVM_DEFINE_OVERLOAD(16)
|
||||
LLVM_DEFINE_OVERLOAD(17)
|
||||
LLVM_DEFINE_OVERLOAD(18)
|
||||
LLVM_DEFINE_OVERLOAD(19)
|
||||
LLVM_DEFINE_OVERLOAD(20)
|
||||
LLVM_DEFINE_OVERLOAD(21)
|
||||
LLVM_DEFINE_OVERLOAD(22)
|
||||
LLVM_DEFINE_OVERLOAD(23)
|
||||
LLVM_DEFINE_OVERLOAD(24)
|
||||
LLVM_DEFINE_OVERLOAD(25)
|
||||
LLVM_DEFINE_OVERLOAD(26)
|
||||
LLVM_DEFINE_OVERLOAD(27)
|
||||
LLVM_DEFINE_OVERLOAD(28)
|
||||
LLVM_DEFINE_OVERLOAD(29)
|
||||
LLVM_DEFINE_OVERLOAD(30)
|
||||
LLVM_DEFINE_OVERLOAD(31)
|
||||
LLVM_DEFINE_OVERLOAD(32)
|
||||
#undef LLVM_DEFINE_OVERLOAD
|
||||
};
|
||||
|
||||
// Cleanup the macro namespace.
|
||||
#undef LLVM_COMMA_JOIN1
|
||||
#undef LLVM_COMMA_JOIN2
|
||||
#undef LLVM_COMMA_JOIN3
|
||||
#undef LLVM_COMMA_JOIN4
|
||||
#undef LLVM_COMMA_JOIN5
|
||||
#undef LLVM_COMMA_JOIN6
|
||||
#undef LLVM_COMMA_JOIN7
|
||||
#undef LLVM_COMMA_JOIN8
|
||||
#undef LLVM_COMMA_JOIN9
|
||||
#undef LLVM_COMMA_JOIN10
|
||||
#undef LLVM_COMMA_JOIN11
|
||||
#undef LLVM_COMMA_JOIN12
|
||||
#undef LLVM_COMMA_JOIN13
|
||||
#undef LLVM_COMMA_JOIN14
|
||||
#undef LLVM_COMMA_JOIN15
|
||||
#undef LLVM_COMMA_JOIN16
|
||||
#undef LLVM_COMMA_JOIN17
|
||||
#undef LLVM_COMMA_JOIN18
|
||||
#undef LLVM_COMMA_JOIN19
|
||||
#undef LLVM_COMMA_JOIN20
|
||||
#undef LLVM_COMMA_JOIN21
|
||||
#undef LLVM_COMMA_JOIN22
|
||||
#undef LLVM_COMMA_JOIN23
|
||||
#undef LLVM_COMMA_JOIN24
|
||||
#undef LLVM_COMMA_JOIN25
|
||||
#undef LLVM_COMMA_JOIN26
|
||||
#undef LLVM_COMMA_JOIN27
|
||||
#undef LLVM_COMMA_JOIN28
|
||||
#undef LLVM_COMMA_JOIN29
|
||||
#undef LLVM_COMMA_JOIN30
|
||||
#undef LLVM_COMMA_JOIN31
|
||||
#undef LLVM_COMMA_JOIN32
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ADT_VARIADICFUNCTION_H
|
@ -44,6 +44,7 @@ class iterator_range {
|
||||
|
||||
IteratorT begin() const { return begin_iterator; }
|
||||
IteratorT end() const { return end_iterator; }
|
||||
bool empty() const { return begin_iterator == end_iterator; }
|
||||
};
|
||||
|
||||
/// Convenience function for iterating over sub-ranges.
|
||||
|
@ -949,7 +949,7 @@ template <typename DerivedT> class AAResultBase {
|
||||
|
||||
/// A pointer to the AAResults object that this AAResult is
|
||||
/// aggregated within. May be null if not aggregated.
|
||||
AAResults *AAR;
|
||||
AAResults *AAR = nullptr;
|
||||
|
||||
/// Helper to dispatch calls back through the derived type.
|
||||
DerivedT &derived() { return static_cast<DerivedT &>(*this); }
|
||||
|
@ -87,10 +87,11 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
AAInfo = NewAAInfo;
|
||||
else {
|
||||
AAMDNodes Intersection(AAInfo.intersect(NewAAInfo));
|
||||
if (!Intersection) {
|
||||
if (!Intersection.TBAA || !Intersection.Scope ||
|
||||
!Intersection.NoAlias) {
|
||||
// NewAAInfo conflicts with AAInfo.
|
||||
AAInfo = DenseMapInfo<AAMDNodes>::getTombstoneKey();
|
||||
return SizeChanged;
|
||||
SizeChanged = true;
|
||||
}
|
||||
AAInfo = Intersection;
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ class AssumptionCache {
|
||||
/// Get the vector of assumptions which affect a value from the cache.
|
||||
SmallVector<WeakTrackingVH, 1> &getOrInsertAffectedValues(Value *V);
|
||||
|
||||
/// Copy affected values in the cache for OV to be affected values for NV.
|
||||
void copyAffectedValuesInCache(Value *OV, Value *NV);
|
||||
/// Move affected values in the cache for OV to be affected values for NV.
|
||||
void transferAffectedValuesInCache(Value *OV, Value *NV);
|
||||
|
||||
/// Flag tracking whether we have scanned the function yet.
|
||||
///
|
||||
|
@ -46,6 +46,8 @@ unsigned GetSuccessorNumber(const BasicBlock *BB, const BasicBlock *Succ);
|
||||
///
|
||||
bool isCriticalEdge(const Instruction *TI, unsigned SuccNum,
|
||||
bool AllowIdenticalEdges = false);
|
||||
bool isCriticalEdge(const Instruction *TI, const BasicBlock *Succ,
|
||||
bool AllowIdenticalEdges = false);
|
||||
|
||||
/// Determine whether instruction 'To' is reachable from 'From', without passing
|
||||
/// through any blocks in ExclusionSet, returning true if uncertain.
|
||||
|
@ -41,7 +41,8 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
|
||||
class FunctionInfo;
|
||||
|
||||
public:
|
||||
explicit CFLAndersAAResult(const TargetLibraryInfo &TLI);
|
||||
explicit CFLAndersAAResult(
|
||||
std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
|
||||
CFLAndersAAResult(CFLAndersAAResult &&RHS);
|
||||
~CFLAndersAAResult();
|
||||
|
||||
@ -74,7 +75,7 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
|
||||
/// Build summary for a given function
|
||||
FunctionInfo buildInfoFrom(const Function &);
|
||||
|
||||
const TargetLibraryInfo &TLI;
|
||||
std::function<const TargetLibraryInfo &(Function &F)> GetTLI;
|
||||
|
||||
/// Cached mapping of Functions to their StratifiedSets.
|
||||
/// If a function's sets are currently being built, it is marked
|
||||
|
@ -42,7 +42,8 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
|
||||
class FunctionInfo;
|
||||
|
||||
public:
|
||||
explicit CFLSteensAAResult(const TargetLibraryInfo &TLI);
|
||||
explicit CFLSteensAAResult(
|
||||
std::function<const TargetLibraryInfo &(Function &)> GetTLI);
|
||||
CFLSteensAAResult(CFLSteensAAResult &&Arg);
|
||||
~CFLSteensAAResult();
|
||||
|
||||
@ -90,7 +91,7 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
|
||||
}
|
||||
|
||||
private:
|
||||
const TargetLibraryInfo &TLI;
|
||||
std::function<const TargetLibraryInfo &(Function &)> GetTLI;
|
||||
|
||||
/// Cached mapping of Functions to their StratifiedSets.
|
||||
/// If a function's sets are currently being built, it is marked
|
||||
|
@ -88,6 +88,7 @@
|
||||
#ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H
|
||||
#define LLVM_ANALYSIS_CGSCCPASSMANAGER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/PriorityWorklist.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
@ -583,10 +584,12 @@ class DevirtSCCRepeatedPass
|
||||
SmallVectorImpl<WeakTrackingVH> &CallHandles) {
|
||||
assert(CallHandles.empty() && "Must start with a clear set of handles.");
|
||||
|
||||
SmallVector<CallCount, 4> CallCounts;
|
||||
SmallDenseMap<Function *, CallCount> CallCounts;
|
||||
CallCount CountLocal = {0, 0};
|
||||
for (LazyCallGraph::Node &N : C) {
|
||||
CallCounts.push_back({0, 0});
|
||||
CallCount &Count = CallCounts.back();
|
||||
CallCount &Count =
|
||||
CallCounts.insert(std::make_pair(&N.getFunction(), CountLocal))
|
||||
.first->second;
|
||||
for (Instruction &I : instructions(N.getFunction()))
|
||||
if (auto CS = CallSite(&I)) {
|
||||
if (CS.getCalledFunction()) {
|
||||
@ -626,8 +629,6 @@ class DevirtSCCRepeatedPass
|
||||
// Check that we didn't miss any update scenario.
|
||||
assert(!UR.InvalidatedSCCs.count(C) && "Processing an invalid SCC!");
|
||||
assert(C->begin() != C->end() && "Cannot have an empty SCC!");
|
||||
assert((int)CallCounts.size() == C->size() &&
|
||||
"Cannot have changed the size of the SCC!");
|
||||
|
||||
// Check whether any of the handles were devirtualized.
|
||||
auto IsDevirtualizedHandle = [&](WeakTrackingVH &CallH) {
|
||||
@ -642,7 +643,7 @@ class DevirtSCCRepeatedPass
|
||||
if (!F)
|
||||
return false;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Found devirutalized call from "
|
||||
LLVM_DEBUG(dbgs() << "Found devirtualized call from "
|
||||
<< CS.getParent()->getParent()->getName() << " to "
|
||||
<< F->getName() << "\n");
|
||||
|
||||
@ -664,12 +665,20 @@ class DevirtSCCRepeatedPass
|
||||
// manner of transformations such as DCE and other things, but seems to
|
||||
// work well in practice.
|
||||
if (!Devirt)
|
||||
for (int i = 0, Size = C->size(); i < Size; ++i)
|
||||
if (CallCounts[i].Indirect > NewCallCounts[i].Indirect &&
|
||||
CallCounts[i].Direct < NewCallCounts[i].Direct) {
|
||||
Devirt = true;
|
||||
break;
|
||||
// Iterate over the keys in NewCallCounts, if Function also exists in
|
||||
// CallCounts, make the check below.
|
||||
for (auto &Pair : NewCallCounts) {
|
||||
auto &CallCountNew = Pair.second;
|
||||
auto CountIt = CallCounts.find(Pair.first);
|
||||
if (CountIt != CallCounts.end()) {
|
||||
const auto &CallCountOld = CountIt->second;
|
||||
if (CallCountOld.Indirect > CallCountNew.Indirect &&
|
||||
CallCountOld.Direct < CallCountNew.Direct) {
|
||||
Devirt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Devirt) {
|
||||
PA.intersect(std::move(PassPA));
|
||||
|
@ -17,6 +17,7 @@ namespace llvm {
|
||||
|
||||
class Value;
|
||||
class Use;
|
||||
class DataLayout;
|
||||
class Instruction;
|
||||
class DominatorTree;
|
||||
class OrderedBasicBlock;
|
||||
@ -83,6 +84,11 @@ namespace llvm {
|
||||
/// use U. Return true to stop the traversal or false to continue looking
|
||||
/// for more capturing instructions.
|
||||
virtual bool captured(const Use *U) = 0;
|
||||
|
||||
/// isDereferenceableOrNull - Overload to allow clients with additional
|
||||
/// knowledge about pointer dereferenceability to provide it and thereby
|
||||
/// avoid conservative responses when a pointer is compared to null.
|
||||
virtual bool isDereferenceableOrNull(Value *O, const DataLayout &DL);
|
||||
};
|
||||
|
||||
/// PointerMayBeCaptured - Visit the value and the values derived from it and
|
||||
|
430
include/llvm/Analysis/DDG.h
Normal file
430
include/llvm/Analysis/DDG.h
Normal file
@ -0,0 +1,430 @@
|
||||
//===- llvm/Analysis/DDG.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the Data-Dependence Graph (DDG).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DDG_H
|
||||
#define LLVM_ANALYSIS_DDG_H
|
||||
|
||||
#include "llvm/ADT/DirectedGraph.h"
|
||||
#include "llvm/Analysis/DependenceAnalysis.h"
|
||||
#include "llvm/Analysis/DependenceGraphBuilder.h"
|
||||
#include "llvm/Analysis/LoopAnalysisManager.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
class DDGNode;
|
||||
class DDGEdge;
|
||||
using DDGNodeBase = DGNode<DDGNode, DDGEdge>;
|
||||
using DDGEdgeBase = DGEdge<DDGNode, DDGEdge>;
|
||||
using DDGBase = DirectedGraph<DDGNode, DDGEdge>;
|
||||
class LPMUpdater;
|
||||
|
||||
/// Data Dependence Graph Node
|
||||
/// The graph can represent the following types of nodes:
|
||||
/// 1. Single instruction node containing just one instruction.
|
||||
/// 2. Multiple instruction node where two or more instructions from
|
||||
/// the same basic block are merged into one node.
|
||||
/// 3. Root node is a special node that connects to all components such that
|
||||
/// there is always a path from it to any node in the graph.
|
||||
class DDGNode : public DDGNodeBase {
|
||||
public:
|
||||
using InstructionListType = SmallVectorImpl<Instruction *>;
|
||||
|
||||
enum class NodeKind {
|
||||
Unknown,
|
||||
SingleInstruction,
|
||||
MultiInstruction,
|
||||
Root,
|
||||
};
|
||||
|
||||
DDGNode() = delete;
|
||||
DDGNode(const NodeKind K) : DDGNodeBase(), Kind(K) {}
|
||||
DDGNode(const DDGNode &N) : DDGNodeBase(N), Kind(N.Kind) {}
|
||||
DDGNode(DDGNode &&N) : DDGNodeBase(std::move(N)), Kind(N.Kind) {}
|
||||
virtual ~DDGNode() = 0;
|
||||
|
||||
DDGNode &operator=(const DDGNode &N) {
|
||||
DGNode::operator=(N);
|
||||
Kind = N.Kind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DDGNode &operator=(DDGNode &&N) {
|
||||
DGNode::operator=(std::move(N));
|
||||
Kind = N.Kind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Getter for the kind of this node.
|
||||
NodeKind getKind() const { return Kind; }
|
||||
|
||||
/// Collect a list of instructions, in \p IList, for which predicate \p Pred
|
||||
/// evaluates to true when iterating over instructions of this node. Return
|
||||
/// true if at least one instruction was collected, and false otherwise.
|
||||
bool collectInstructions(llvm::function_ref<bool(Instruction *)> const &Pred,
|
||||
InstructionListType &IList) const;
|
||||
|
||||
protected:
|
||||
/// Setter for the kind of this node.
|
||||
void setKind(NodeKind K) { Kind = K; }
|
||||
|
||||
private:
|
||||
NodeKind Kind;
|
||||
};
|
||||
|
||||
/// Subclass of DDGNode representing the root node of the graph.
|
||||
/// There should only be one such node in a given graph.
|
||||
class RootDDGNode : public DDGNode {
|
||||
public:
|
||||
RootDDGNode() : DDGNode(NodeKind::Root) {}
|
||||
RootDDGNode(const RootDDGNode &N) = delete;
|
||||
RootDDGNode(RootDDGNode &&N) : DDGNode(std::move(N)) {}
|
||||
~RootDDGNode() {}
|
||||
|
||||
/// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
|
||||
static bool classof(const DDGNode *N) {
|
||||
return N->getKind() == NodeKind::Root;
|
||||
}
|
||||
static bool classof(const RootDDGNode *N) { return true; }
|
||||
};
|
||||
|
||||
/// Subclass of DDGNode representing single or multi-instruction nodes.
|
||||
class SimpleDDGNode : public DDGNode {
|
||||
public:
|
||||
SimpleDDGNode() = delete;
|
||||
SimpleDDGNode(Instruction &I);
|
||||
SimpleDDGNode(const SimpleDDGNode &N);
|
||||
SimpleDDGNode(SimpleDDGNode &&N);
|
||||
~SimpleDDGNode();
|
||||
|
||||
SimpleDDGNode &operator=(const SimpleDDGNode &N) {
|
||||
DDGNode::operator=(N);
|
||||
InstList = N.InstList;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SimpleDDGNode &operator=(SimpleDDGNode &&N) {
|
||||
DDGNode::operator=(std::move(N));
|
||||
InstList = std::move(N.InstList);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Get the list of instructions in this node.
|
||||
const InstructionListType &getInstructions() const {
|
||||
assert(!InstList.empty() && "Instruction List is empty.");
|
||||
return InstList;
|
||||
}
|
||||
InstructionListType &getInstructions() {
|
||||
return const_cast<InstructionListType &>(
|
||||
static_cast<const SimpleDDGNode *>(this)->getInstructions());
|
||||
}
|
||||
|
||||
/// Get the first/last instruction in the node.
|
||||
Instruction *getFirstInstruction() const { return getInstructions().front(); }
|
||||
Instruction *getLastInstruction() const { return getInstructions().back(); }
|
||||
|
||||
/// Define classof to be able to use isa<>, cast<>, dyn_cast<>, etc.
|
||||
static bool classof(const DDGNode *N) {
|
||||
return N->getKind() == NodeKind::SingleInstruction ||
|
||||
N->getKind() == NodeKind::MultiInstruction;
|
||||
}
|
||||
static bool classof(const SimpleDDGNode *N) { return true; }
|
||||
|
||||
private:
|
||||
/// Append the list of instructions in \p Input to this node.
|
||||
void appendInstructions(const InstructionListType &Input) {
|
||||
setKind((InstList.size() == 0 && Input.size() == 1)
|
||||
? NodeKind::SingleInstruction
|
||||
: NodeKind::MultiInstruction);
|
||||
InstList.insert(InstList.end(), Input.begin(), Input.end());
|
||||
}
|
||||
void appendInstructions(const SimpleDDGNode &Input) {
|
||||
appendInstructions(Input.getInstructions());
|
||||
}
|
||||
|
||||
/// List of instructions associated with a single or multi-instruction node.
|
||||
SmallVector<Instruction *, 2> InstList;
|
||||
};
|
||||
|
||||
/// Data Dependency Graph Edge.
|
||||
/// An edge in the DDG can represent a def-use relationship or
|
||||
/// a memory dependence based on the result of DependenceAnalysis.
|
||||
/// A rooted edge connects the root node to one of the components
|
||||
/// of the graph.
|
||||
class DDGEdge : public DDGEdgeBase {
|
||||
public:
|
||||
/// The kind of edge in the DDG
|
||||
enum class EdgeKind { Unknown, RegisterDefUse, MemoryDependence, Rooted };
|
||||
|
||||
explicit DDGEdge(DDGNode &N) = delete;
|
||||
DDGEdge(DDGNode &N, EdgeKind K) : DDGEdgeBase(N), Kind(K) {}
|
||||
DDGEdge(const DDGEdge &E) : DDGEdgeBase(E), Kind(E.getKind()) {}
|
||||
DDGEdge(DDGEdge &&E) : DDGEdgeBase(std::move(E)), Kind(E.Kind) {}
|
||||
DDGEdge &operator=(const DDGEdge &E) {
|
||||
DDGEdgeBase::operator=(E);
|
||||
Kind = E.Kind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DDGEdge &operator=(DDGEdge &&E) {
|
||||
DDGEdgeBase::operator=(std::move(E));
|
||||
Kind = E.Kind;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Get the edge kind
|
||||
EdgeKind getKind() const { return Kind; };
|
||||
|
||||
/// Return true if this is a def-use edge, and false otherwise.
|
||||
bool isDefUse() const { return Kind == EdgeKind::RegisterDefUse; }
|
||||
|
||||
/// Return true if this is a memory dependence edge, and false otherwise.
|
||||
bool isMemoryDependence() const { return Kind == EdgeKind::MemoryDependence; }
|
||||
|
||||
/// Return true if this is an edge stemming from the root node, and false
|
||||
/// otherwise.
|
||||
bool isRooted() const { return Kind == EdgeKind::Rooted; }
|
||||
|
||||
private:
|
||||
EdgeKind Kind;
|
||||
};
|
||||
|
||||
/// Encapsulate some common data and functionality needed for different
|
||||
/// variations of data dependence graphs.
|
||||
template <typename NodeType> class DependenceGraphInfo {
|
||||
public:
|
||||
using DependenceList = SmallVector<std::unique_ptr<Dependence>, 1>;
|
||||
|
||||
DependenceGraphInfo() = delete;
|
||||
DependenceGraphInfo(const DependenceGraphInfo &G) = delete;
|
||||
DependenceGraphInfo(const std::string &N, const DependenceInfo &DepInfo)
|
||||
: Name(N), DI(DepInfo), Root(nullptr) {}
|
||||
DependenceGraphInfo(DependenceGraphInfo &&G)
|
||||
: Name(std::move(G.Name)), DI(std::move(G.DI)), Root(G.Root) {}
|
||||
virtual ~DependenceGraphInfo() {}
|
||||
|
||||
/// Return the label that is used to name this graph.
|
||||
const StringRef getName() const { return Name; }
|
||||
|
||||
/// Return the root node of the graph.
|
||||
NodeType &getRoot() const {
|
||||
assert(Root && "Root node is not available yet. Graph construction may "
|
||||
"still be in progress\n");
|
||||
return *Root;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Name of the graph.
|
||||
std::string Name;
|
||||
|
||||
// Store a copy of DependenceInfo in the graph, so that individual memory
|
||||
// dependencies don't need to be stored. Instead when the dependence is
|
||||
// queried it is recomputed using @DI.
|
||||
const DependenceInfo DI;
|
||||
|
||||
// A special node in the graph that has an edge to every connected component of
|
||||
// the graph, to ensure all nodes are reachable in a graph walk.
|
||||
NodeType *Root = nullptr;
|
||||
};
|
||||
|
||||
using DDGInfo = DependenceGraphInfo<DDGNode>;
|
||||
|
||||
/// Data Dependency Graph
|
||||
class DataDependenceGraph : public DDGBase, public DDGInfo {
|
||||
friend class DDGBuilder;
|
||||
|
||||
public:
|
||||
using NodeType = DDGNode;
|
||||
using EdgeType = DDGEdge;
|
||||
|
||||
DataDependenceGraph() = delete;
|
||||
DataDependenceGraph(const DataDependenceGraph &G) = delete;
|
||||
DataDependenceGraph(DataDependenceGraph &&G)
|
||||
: DDGBase(std::move(G)), DDGInfo(std::move(G)) {}
|
||||
DataDependenceGraph(Function &F, DependenceInfo &DI);
|
||||
DataDependenceGraph(const Loop &L, DependenceInfo &DI);
|
||||
~DataDependenceGraph();
|
||||
|
||||
protected:
|
||||
/// Add node \p N to the graph, if it's not added yet, and keep track of
|
||||
/// the root node. Return true if node is successfully added.
|
||||
bool addNode(NodeType &N);
|
||||
|
||||
};
|
||||
|
||||
/// Concrete implementation of a pure data dependence graph builder. This class
|
||||
/// provides custom implementation for the pure-virtual functions used in the
|
||||
/// generic dependence graph build algorithm.
|
||||
///
|
||||
/// For information about time complexity of the build algorithm see the
|
||||
/// comments near the declaration of AbstractDependenceGraphBuilder.
|
||||
class DDGBuilder : public AbstractDependenceGraphBuilder<DataDependenceGraph> {
|
||||
public:
|
||||
DDGBuilder(DataDependenceGraph &G, DependenceInfo &D,
|
||||
const BasicBlockListType &BBs)
|
||||
: AbstractDependenceGraphBuilder(G, D, BBs) {}
|
||||
DDGNode &createRootNode() final override {
|
||||
auto *RN = new RootDDGNode();
|
||||
assert(RN && "Failed to allocate memory for DDG root node.");
|
||||
Graph.addNode(*RN);
|
||||
return *RN;
|
||||
}
|
||||
DDGNode &createFineGrainedNode(Instruction &I) final override {
|
||||
auto *SN = new SimpleDDGNode(I);
|
||||
assert(SN && "Failed to allocate memory for simple DDG node.");
|
||||
Graph.addNode(*SN);
|
||||
return *SN;
|
||||
}
|
||||
DDGEdge &createDefUseEdge(DDGNode &Src, DDGNode &Tgt) final override {
|
||||
auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::RegisterDefUse);
|
||||
assert(E && "Failed to allocate memory for edge");
|
||||
Graph.connect(Src, Tgt, *E);
|
||||
return *E;
|
||||
}
|
||||
DDGEdge &createMemoryEdge(DDGNode &Src, DDGNode &Tgt) final override {
|
||||
auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::MemoryDependence);
|
||||
assert(E && "Failed to allocate memory for edge");
|
||||
Graph.connect(Src, Tgt, *E);
|
||||
return *E;
|
||||
}
|
||||
DDGEdge &createRootedEdge(DDGNode &Src, DDGNode &Tgt) final override {
|
||||
auto *E = new DDGEdge(Tgt, DDGEdge::EdgeKind::Rooted);
|
||||
assert(E && "Failed to allocate memory for edge");
|
||||
assert(isa<RootDDGNode>(Src) && "Expected root node");
|
||||
Graph.connect(Src, Tgt, *E);
|
||||
return *E;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const DDGNode &N);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const DDGNode::NodeKind K);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const DDGEdge &E);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const DDGEdge::EdgeKind K);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const DataDependenceGraph &G);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// DDG Analysis Passes
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Analysis pass that builds the DDG for a loop.
|
||||
class DDGAnalysis : public AnalysisInfoMixin<DDGAnalysis> {
|
||||
public:
|
||||
using Result = std::unique_ptr<DataDependenceGraph>;
|
||||
Result run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR);
|
||||
|
||||
private:
|
||||
friend AnalysisInfoMixin<DDGAnalysis>;
|
||||
static AnalysisKey Key;
|
||||
};
|
||||
|
||||
/// Textual printer pass for the DDG of a loop.
|
||||
class DDGAnalysisPrinterPass : public PassInfoMixin<DDGAnalysisPrinterPass> {
|
||||
public:
|
||||
explicit DDGAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
|
||||
LoopStandardAnalysisResults &AR, LPMUpdater &U);
|
||||
|
||||
private:
|
||||
raw_ostream &OS;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// GraphTraits specializations for the DDG
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// non-const versions of the grapth trait specializations for DDG
|
||||
template <> struct GraphTraits<DDGNode *> {
|
||||
using NodeRef = DDGNode *;
|
||||
|
||||
static DDGNode *DDGGetTargetNode(DGEdge<DDGNode, DDGEdge> *P) {
|
||||
return &P->getTargetNode();
|
||||
}
|
||||
|
||||
// Provide a mapped iterator so that the GraphTrait-based implementations can
|
||||
// find the target nodes without having to explicitly go through the edges.
|
||||
using ChildIteratorType =
|
||||
mapped_iterator<DDGNode::iterator, decltype(&DDGGetTargetNode)>;
|
||||
using ChildEdgeIteratorType = DDGNode::iterator;
|
||||
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeRef N) {
|
||||
return ChildIteratorType(N->begin(), &DDGGetTargetNode);
|
||||
}
|
||||
static ChildIteratorType child_end(NodeRef N) {
|
||||
return ChildIteratorType(N->end(), &DDGGetTargetNode);
|
||||
}
|
||||
|
||||
static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
|
||||
return N->begin();
|
||||
}
|
||||
static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GraphTraits<DataDependenceGraph *> : public GraphTraits<DDGNode *> {
|
||||
using nodes_iterator = DataDependenceGraph::iterator;
|
||||
static NodeRef getEntryNode(DataDependenceGraph *DG) {
|
||||
return &DG->getRoot();
|
||||
}
|
||||
static nodes_iterator nodes_begin(DataDependenceGraph *DG) {
|
||||
return DG->begin();
|
||||
}
|
||||
static nodes_iterator nodes_end(DataDependenceGraph *DG) { return DG->end(); }
|
||||
};
|
||||
|
||||
/// const versions of the grapth trait specializations for DDG
|
||||
template <> struct GraphTraits<const DDGNode *> {
|
||||
using NodeRef = const DDGNode *;
|
||||
|
||||
static const DDGNode *DDGGetTargetNode(const DGEdge<DDGNode, DDGEdge> *P) {
|
||||
return &P->getTargetNode();
|
||||
}
|
||||
|
||||
// Provide a mapped iterator so that the GraphTrait-based implementations can
|
||||
// find the target nodes without having to explicitly go through the edges.
|
||||
using ChildIteratorType =
|
||||
mapped_iterator<DDGNode::const_iterator, decltype(&DDGGetTargetNode)>;
|
||||
using ChildEdgeIteratorType = DDGNode::const_iterator;
|
||||
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; }
|
||||
static ChildIteratorType child_begin(NodeRef N) {
|
||||
return ChildIteratorType(N->begin(), &DDGGetTargetNode);
|
||||
}
|
||||
static ChildIteratorType child_end(NodeRef N) {
|
||||
return ChildIteratorType(N->end(), &DDGGetTargetNode);
|
||||
}
|
||||
|
||||
static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
|
||||
return N->begin();
|
||||
}
|
||||
static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GraphTraits<const DataDependenceGraph *>
|
||||
: public GraphTraits<const DDGNode *> {
|
||||
using nodes_iterator = DataDependenceGraph::const_iterator;
|
||||
static NodeRef getEntryNode(const DataDependenceGraph *DG) {
|
||||
return &DG->getRoot();
|
||||
}
|
||||
static nodes_iterator nodes_begin(const DataDependenceGraph *DG) {
|
||||
return DG->begin();
|
||||
}
|
||||
static nodes_iterator nodes_end(const DataDependenceGraph *DG) {
|
||||
return DG->end();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_DDG_H
|
@ -99,7 +99,7 @@ class DOTGraphTraitsPrinter : public FunctionPass {
|
||||
|
||||
errs() << "Writing '" << Filename << "'...";
|
||||
|
||||
raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
|
||||
raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
|
||||
std::string GraphName = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||
std::string Title = GraphName + " for '" + F.getName().str() + "' function";
|
||||
|
||||
@ -162,7 +162,7 @@ class DOTGraphTraitsModulePrinter : public ModulePass {
|
||||
|
||||
errs() << "Writing '" << Filename << "'...";
|
||||
|
||||
raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
|
||||
raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
|
||||
std::string Title = DOTGraphTraits<GraphT>::getGraphName(Graph);
|
||||
|
||||
if (!EC)
|
||||
|
119
include/llvm/Analysis/DependenceGraphBuilder.h
Normal file
119
include/llvm/Analysis/DependenceGraphBuilder.h
Normal file
@ -0,0 +1,119 @@
|
||||
//===- llvm/Analysis/DependenceGraphBuilder.h -------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a builder interface that can be used to populate dependence
|
||||
// graphs such as DDG and PDG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_DEPENDENCE_GRAPH_BUILDER_H
|
||||
#define LLVM_ANALYSIS_DEPENDENCE_GRAPH_BUILDER_H
|
||||
|
||||
#include "llvm/ADT/EquivalenceClasses.h"
|
||||
#include "llvm/Analysis/DependenceAnalysis.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// This abstract builder class defines a set of high-level steps for creating
|
||||
/// DDG-like graphs. The client code is expected to inherit from this class and
|
||||
/// define concrete implementation for each of the pure virtual functions used
|
||||
/// in the high-level algorithm.
|
||||
template <class GraphType> class AbstractDependenceGraphBuilder {
|
||||
protected:
|
||||
using BasicBlockListType = SmallVectorImpl<BasicBlock *>;
|
||||
|
||||
private:
|
||||
using NodeType = typename GraphType::NodeType;
|
||||
using EdgeType = typename GraphType::EdgeType;
|
||||
|
||||
public:
|
||||
using ClassesType = EquivalenceClasses<BasicBlock *>;
|
||||
using NodeListType = SmallVector<NodeType *, 4>;
|
||||
|
||||
AbstractDependenceGraphBuilder(GraphType &G, DependenceInfo &D,
|
||||
const BasicBlockListType &BBs)
|
||||
: Graph(G), DI(D), BBList(BBs) {}
|
||||
virtual ~AbstractDependenceGraphBuilder() {}
|
||||
|
||||
/// The main entry to the graph construction algorithm. It starts by
|
||||
/// creating nodes in increasing order of granularity and then
|
||||
/// adds def-use and memory edges.
|
||||
///
|
||||
/// The algorithmic complexity of this implementation is O(V^2 * I^2), where V
|
||||
/// is the number of vertecies (nodes) and I is the number of instructions in
|
||||
/// each node. The total number of instructions, N, is equal to V * I,
|
||||
/// therefore the worst-case time complexity is O(N^2). The average time
|
||||
/// complexity is O((N^2)/2).
|
||||
void populate() {
|
||||
createFineGrainedNodes();
|
||||
createDefUseEdges();
|
||||
createMemoryDependencyEdges();
|
||||
createAndConnectRootNode();
|
||||
}
|
||||
|
||||
/// Create fine grained nodes. These are typically atomic nodes that
|
||||
/// consist of a single instruction.
|
||||
void createFineGrainedNodes();
|
||||
|
||||
/// Analyze the def-use chains and create edges from the nodes containing
|
||||
/// definitions to the nodes containing the uses.
|
||||
void createDefUseEdges();
|
||||
|
||||
/// Analyze data dependencies that exist between memory loads or stores,
|
||||
/// in the graph nodes and create edges between them.
|
||||
void createMemoryDependencyEdges();
|
||||
|
||||
/// Create a root node and add edges such that each node in the graph is
|
||||
/// reachable from the root.
|
||||
void createAndConnectRootNode();
|
||||
|
||||
protected:
|
||||
/// Create the root node of the graph.
|
||||
virtual NodeType &createRootNode() = 0;
|
||||
|
||||
/// Create an atomic node in the graph given a single instruction.
|
||||
virtual NodeType &createFineGrainedNode(Instruction &I) = 0;
|
||||
|
||||
/// Create a def-use edge going from \p Src to \p Tgt.
|
||||
virtual EdgeType &createDefUseEdge(NodeType &Src, NodeType &Tgt) = 0;
|
||||
|
||||
/// Create a memory dependence edge going from \p Src to \p Tgt.
|
||||
virtual EdgeType &createMemoryEdge(NodeType &Src, NodeType &Tgt) = 0;
|
||||
|
||||
/// Create a rooted edge going from \p Src to \p Tgt .
|
||||
virtual EdgeType &createRootedEdge(NodeType &Src, NodeType &Tgt) = 0;
|
||||
|
||||
/// Deallocate memory of edge \p E.
|
||||
virtual void destroyEdge(EdgeType &E) { delete &E; }
|
||||
|
||||
/// Deallocate memory of node \p N.
|
||||
virtual void destroyNode(NodeType &N) { delete &N; }
|
||||
|
||||
/// Map types to map instructions to nodes used when populating the graph.
|
||||
using InstToNodeMap = DenseMap<Instruction *, NodeType *>;
|
||||
|
||||
/// Reference to the graph that gets built by a concrete implementation of
|
||||
/// this builder.
|
||||
GraphType &Graph;
|
||||
|
||||
/// Dependence information used to create memory dependence edges in the
|
||||
/// graph.
|
||||
DependenceInfo &DI;
|
||||
|
||||
/// The list of basic blocks to consider when building the graph.
|
||||
const BasicBlockListType &BBList;
|
||||
|
||||
/// A mapping from instructions to the corresponding nodes in the graph.
|
||||
InstToNodeMap IMap;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_DEPENDENCE_GRAPH_BUILDER_H
|
@ -73,9 +73,12 @@ class DivergenceAnalysis {
|
||||
/// operands
|
||||
bool isAlwaysUniform(const Value &Val) const;
|
||||
|
||||
/// \brief Whether \p Val is a divergent value
|
||||
/// \brief Whether \p Val is divergent at its definition.
|
||||
bool isDivergent(const Value &Val) const;
|
||||
|
||||
/// \brief Whether \p U is divergent. Uses of a uniform value can be divergent.
|
||||
bool isDivergentUse(const Use &U) const;
|
||||
|
||||
void print(raw_ostream &OS, const Module *) const;
|
||||
|
||||
private:
|
||||
@ -189,12 +192,19 @@ class GPUDivergenceAnalysis {
|
||||
/// The GPU kernel this analysis result is for
|
||||
const Function &getFunction() const { return DA.getFunction(); }
|
||||
|
||||
/// Whether \p V is divergent.
|
||||
/// Whether \p V is divergent at its definition.
|
||||
bool isDivergent(const Value &V) const;
|
||||
|
||||
/// Whether \p V is uniform/non-divergent
|
||||
/// Whether \p U is divergent. Uses of a uniform value can be divergent.
|
||||
bool isDivergentUse(const Use &U) const;
|
||||
|
||||
/// Whether \p V is uniform/non-divergent.
|
||||
bool isUniform(const Value &V) const { return !isDivergent(V); }
|
||||
|
||||
/// Whether \p U is uniform/non-divergent. Uses of a uniform value can be
|
||||
/// divergent.
|
||||
bool isUniformUse(const Use &U) const { return !isDivergentUse(U); }
|
||||
|
||||
/// Print all divergent values in the kernel.
|
||||
void print(raw_ostream &OS, const Module *) const;
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> {
|
||||
class FunctionInfo;
|
||||
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo &TLI;
|
||||
std::function<const TargetLibraryInfo &(Function &F)> GetTLI;
|
||||
|
||||
/// The globals that do not have their addresses taken.
|
||||
SmallPtrSet<const GlobalValue *, 8> NonAddressTakenGlobals;
|
||||
@ -72,14 +72,18 @@ class GlobalsAAResult : public AAResultBase<GlobalsAAResult> {
|
||||
/// could perform to the memory utilization here if this becomes a problem.
|
||||
std::list<DeletionCallbackHandle> Handles;
|
||||
|
||||
explicit GlobalsAAResult(const DataLayout &DL, const TargetLibraryInfo &TLI);
|
||||
explicit GlobalsAAResult(
|
||||
const DataLayout &DL,
|
||||
std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
|
||||
|
||||
public:
|
||||
GlobalsAAResult(GlobalsAAResult &&Arg);
|
||||
~GlobalsAAResult();
|
||||
|
||||
static GlobalsAAResult analyzeModule(Module &M, const TargetLibraryInfo &TLI,
|
||||
CallGraph &CG);
|
||||
static GlobalsAAResult
|
||||
analyzeModule(Module &M,
|
||||
std::function<const TargetLibraryInfo &(Function &F)> GetTLI,
|
||||
CallGraph &CG);
|
||||
|
||||
//------------------------------------------------
|
||||
// Implement the AliasAnalysis API
|
||||
|
@ -31,6 +31,7 @@
|
||||
#ifndef LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H
|
||||
#define LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H
|
||||
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/User.h"
|
||||
@ -141,6 +142,13 @@ Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
|
||||
/// Given operands for the multiplication of a FMA, fold the result or return
|
||||
/// null. In contrast to SimplifyFMulInst, this function will not perform
|
||||
/// simplifications whose unrounded results differ when rounded to the argument
|
||||
/// type.
|
||||
Value *SimplifyFMAFMul(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
|
||||
/// Given operands for a Mul, fold the result or return null.
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
|
||||
@ -234,21 +242,19 @@ Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
/// Given operand for a UnaryOperator, fold the result or return null.
|
||||
Value *SimplifyUnOp(unsigned Opcode, Value *Op, const SimplifyQuery &Q);
|
||||
|
||||
/// Given operand for an FP UnaryOperator, fold the result or return null.
|
||||
/// In contrast to SimplifyUnOp, try to use FastMathFlag when folding the
|
||||
/// result. In case we don't need FastMathFlags, simply fall to SimplifyUnOp.
|
||||
Value *SimplifyFPUnOp(unsigned Opcode, Value *Op, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
/// Given operand for a UnaryOperator, fold the result or return null.
|
||||
/// Try to use FastMathFlags when folding the result.
|
||||
Value *SimplifyUnOp(unsigned Opcode, Value *Op, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
|
||||
/// Given operands for a BinaryOperator, fold the result or return null.
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const SimplifyQuery &Q);
|
||||
|
||||
/// Given operands for an FP BinaryOperator, fold the result or return 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,
|
||||
FastMathFlags FMF, const SimplifyQuery &Q);
|
||||
/// Given operands for a BinaryOperator, fold the result or return null.
|
||||
/// Try to use FastMathFlags when folding the result.
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF, const SimplifyQuery &Q);
|
||||
|
||||
/// Given a callsite, fold the result or return null.
|
||||
Value *SimplifyCall(CallBase *Call, const SimplifyQuery &Q);
|
||||
@ -263,12 +269,14 @@ Value *SimplifyInstruction(Instruction *I, const SimplifyQuery &Q,
|
||||
/// This first performs a normal RAUW of I with SimpleV. It then recursively
|
||||
/// attempts to simplify those users updated by the operation. The 'I'
|
||||
/// instruction must not be equal to the simplified value 'SimpleV'.
|
||||
/// If UnsimplifiedUsers is provided, instructions that could not be simplified
|
||||
/// are added to it.
|
||||
///
|
||||
/// The function returns true if any simplifications were performed.
|
||||
bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr);
|
||||
bool replaceAndRecursivelySimplify(
|
||||
Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr,
|
||||
SmallSetVector<Instruction *, 8> *UnsimplifiedUsers = nullptr);
|
||||
|
||||
/// Recursively attempt to simplify an instruction.
|
||||
///
|
||||
|
@ -931,7 +931,8 @@ class LazyCallGraph {
|
||||
/// This sets up the graph and computes all of the entry points of the graph.
|
||||
/// No function definitions are scanned until their nodes in the graph are
|
||||
/// requested during traversal.
|
||||
LazyCallGraph(Module &M, TargetLibraryInfo &TLI);
|
||||
LazyCallGraph(Module &M,
|
||||
function_ref<TargetLibraryInfo &(Function &)> GetTLI);
|
||||
|
||||
LazyCallGraph(LazyCallGraph &&G);
|
||||
LazyCallGraph &operator=(LazyCallGraph &&RHS);
|
||||
@ -1267,7 +1268,12 @@ class LazyCallGraphAnalysis : public AnalysisInfoMixin<LazyCallGraphAnalysis> {
|
||||
/// This just builds the set of entry points to the call graph. The rest is
|
||||
/// built lazily as it is walked.
|
||||
LazyCallGraph run(Module &M, ModuleAnalysisManager &AM) {
|
||||
return LazyCallGraph(M, AM.getResult<TargetLibraryAnalysis>(M));
|
||||
FunctionAnalysisManager &FAM =
|
||||
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
|
||||
auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
|
||||
return FAM.getResult<TargetLibraryAnalysis>(F);
|
||||
};
|
||||
return LazyCallGraph(M, GetTLI);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -39,17 +39,18 @@ class LegacyDivergenceAnalysis : public FunctionPass {
|
||||
void print(raw_ostream &OS, const Module *) const override;
|
||||
|
||||
// Returns true if V is divergent at its definition.
|
||||
//
|
||||
// Even if this function returns false, V may still be divergent when used
|
||||
// in a different basic block.
|
||||
bool isDivergent(const Value *V) const;
|
||||
|
||||
// Returns true if U is divergent. Uses of a uniform value can be divergent.
|
||||
bool isDivergentUse(const Use *U) const;
|
||||
|
||||
// Returns true if V is uniform/non-divergent.
|
||||
//
|
||||
// Even if this function returns true, V may still be divergent when used
|
||||
// in a different basic block.
|
||||
bool isUniform(const Value *V) const { return !isDivergent(V); }
|
||||
|
||||
// Returns true if U is uniform/non-divergent. Uses of a uniform value can be
|
||||
// divergent.
|
||||
bool isUniformUse(const Use *U) const { return !isDivergentUse(U); }
|
||||
|
||||
// Keep the analysis results uptodate by removing an erased value.
|
||||
void removeValue(const Value *V) { DivergentValues.erase(V); }
|
||||
|
||||
@ -62,6 +63,9 @@ class LegacyDivergenceAnalysis : public FunctionPass {
|
||||
|
||||
// Stores all divergent values.
|
||||
DenseSet<const Value *> DivergentValues;
|
||||
|
||||
// Stores divergent uses of possibly uniform values.
|
||||
DenseSet<const Use *> DivergentUses;
|
||||
};
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -20,7 +20,9 @@
|
||||
namespace llvm {
|
||||
|
||||
class DataLayout;
|
||||
class Loop;
|
||||
class MDNode;
|
||||
class ScalarEvolution;
|
||||
|
||||
/// Return true if this is always a dereferenceable pointer. If the context
|
||||
/// instruction is specified perform context-sensitive analysis and return true
|
||||
@ -35,7 +37,8 @@ bool isDereferenceablePointer(const Value *V, Type *Ty,
|
||||
/// performs context-sensitive analysis and returns true if the pointer is
|
||||
/// dereferenceable at the specified instruction.
|
||||
bool isDereferenceableAndAlignedPointer(const Value *V, Type *Ty,
|
||||
unsigned Align, const DataLayout &DL,
|
||||
MaybeAlign Alignment,
|
||||
const DataLayout &DL,
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
@ -43,7 +46,7 @@ bool isDereferenceableAndAlignedPointer(const Value *V, Type *Ty,
|
||||
/// greater or equal than requested. If the context instruction is specified
|
||||
/// performs context-sensitive analysis and returns true if the pointer is
|
||||
/// dereferenceable at the specified instruction.
|
||||
bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align,
|
||||
bool isDereferenceableAndAlignedPointer(const Value *V, Align Alignment,
|
||||
const APInt &Size, const DataLayout &DL,
|
||||
const Instruction *CtxI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
@ -56,11 +59,22 @@ bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align,
|
||||
/// If it is not obviously safe to load from the 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, unsigned Align, APInt &Size,
|
||||
bool isSafeToLoadUnconditionally(Value *V, MaybeAlign Alignment, APInt &Size,
|
||||
const DataLayout &DL,
|
||||
Instruction *ScanFrom = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
||||
/// Return true if we can prove that the given load (which is assumed to be
|
||||
/// within the specified loop) would access only dereferenceable memory, and
|
||||
/// be properly aligned on every iteration of the specified loop regardless of
|
||||
/// its placement within the loop. (i.e. does not require predication beyond
|
||||
/// that required by the the header itself and could be hoisted into the header
|
||||
/// if desired.) This is more powerful than the variants above when the
|
||||
/// address loaded from is analyzeable by SCEV.
|
||||
bool isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L,
|
||||
ScalarEvolution &SE,
|
||||
DominatorTree &DT);
|
||||
|
||||
/// Return true if we know that executing a load from this value cannot trap.
|
||||
///
|
||||
/// If DT and ScanFrom are specified this method performs context-sensitive
|
||||
@ -69,7 +83,7 @@ bool isSafeToLoadUnconditionally(Value *V, unsigned Align, APInt &Size,
|
||||
/// If it is not obviously safe to load from the 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, Type *Ty, unsigned Align,
|
||||
bool isSafeToLoadUnconditionally(Value *V, Type *Ty, MaybeAlign Alignment,
|
||||
const DataLayout &DL,
|
||||
Instruction *ScanFrom = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
@ -86,8 +86,9 @@ typedef InnerAnalysisManagerProxy<LoopAnalysisManager, Function>
|
||||
template <> class LoopAnalysisManagerFunctionProxy::Result {
|
||||
public:
|
||||
explicit Result(LoopAnalysisManager &InnerAM, LoopInfo &LI)
|
||||
: InnerAM(&InnerAM), LI(&LI) {}
|
||||
Result(Result &&Arg) : InnerAM(std::move(Arg.InnerAM)), LI(Arg.LI) {
|
||||
: InnerAM(&InnerAM), LI(&LI), MSSAUsed(false) {}
|
||||
Result(Result &&Arg)
|
||||
: InnerAM(std::move(Arg.InnerAM)), LI(Arg.LI), MSSAUsed(Arg.MSSAUsed) {
|
||||
// We have to null out the analysis manager in the moved-from state
|
||||
// because we are taking ownership of the responsibilty to clear the
|
||||
// analysis state.
|
||||
@ -96,6 +97,7 @@ template <> class LoopAnalysisManagerFunctionProxy::Result {
|
||||
Result &operator=(Result &&RHS) {
|
||||
InnerAM = RHS.InnerAM;
|
||||
LI = RHS.LI;
|
||||
MSSAUsed = RHS.MSSAUsed;
|
||||
// We have to null out the analysis manager in the moved-from state
|
||||
// because we are taking ownership of the responsibilty to clear the
|
||||
// analysis state.
|
||||
@ -112,6 +114,9 @@ template <> class LoopAnalysisManagerFunctionProxy::Result {
|
||||
InnerAM->clear();
|
||||
}
|
||||
|
||||
/// Mark MemorySSA as used so we can invalidate self if MSSA is invalidated.
|
||||
void markMSSAUsed() { MSSAUsed = true; }
|
||||
|
||||
/// Accessor for the analysis manager.
|
||||
LoopAnalysisManager &getManager() { return *InnerAM; }
|
||||
|
||||
@ -130,6 +135,7 @@ template <> class LoopAnalysisManagerFunctionProxy::Result {
|
||||
private:
|
||||
LoopAnalysisManager *InnerAM;
|
||||
LoopInfo *LI;
|
||||
bool MSSAUsed;
|
||||
};
|
||||
|
||||
/// Provide a specialized run method for the \c LoopAnalysisManagerFunctionProxy
|
||||
|
281
include/llvm/Analysis/LoopCacheAnalysis.h
Normal file
281
include/llvm/Analysis/LoopCacheAnalysis.h
Normal file
@ -0,0 +1,281 @@
|
||||
//===- llvm/Analysis/LoopCacheAnalysis.h ------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file defines the interface for the loop cache analysis.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPCACHEANALYSIS_H
|
||||
#define LLVM_ANALYSIS_LOOPCACHEANALYSIS_H
|
||||
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/DependenceAnalysis.h"
|
||||
#include "llvm/Analysis/LoopAnalysisManager.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/ScalarEvolution.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class LPMUpdater;
|
||||
using CacheCostTy = int64_t;
|
||||
using LoopVectorTy = SmallVector<Loop *, 8>;
|
||||
|
||||
/// Represents a memory reference as a base pointer and a set of indexing
|
||||
/// operations. For example given the array reference A[i][2j+1][3k+2] in a
|
||||
/// 3-dim loop nest:
|
||||
/// for(i=0;i<n;++i)
|
||||
/// for(j=0;j<m;++j)
|
||||
/// for(k=0;k<o;++k)
|
||||
/// ... A[i][2j+1][3k+2] ...
|
||||
/// We expect:
|
||||
/// BasePointer -> A
|
||||
/// Subscripts -> [{0,+,1}<%for.i>][{1,+,2}<%for.j>][{2,+,3}<%for.k>]
|
||||
/// Sizes -> [m][o][4]
|
||||
class IndexedReference {
|
||||
friend raw_ostream &operator<<(raw_ostream &OS, const IndexedReference &R);
|
||||
|
||||
public:
|
||||
/// Construct an indexed reference given a \p StoreOrLoadInst instruction.
|
||||
IndexedReference(Instruction &StoreOrLoadInst, const LoopInfo &LI,
|
||||
ScalarEvolution &SE);
|
||||
|
||||
bool isValid() const { return IsValid; }
|
||||
const SCEV *getBasePointer() const { return BasePointer; }
|
||||
size_t getNumSubscripts() const { return Subscripts.size(); }
|
||||
const SCEV *getSubscript(unsigned SubNum) const {
|
||||
assert(SubNum < getNumSubscripts() && "Invalid subscript number");
|
||||
return Subscripts[SubNum];
|
||||
}
|
||||
const SCEV *getFirstSubscript() const {
|
||||
assert(!Subscripts.empty() && "Expecting non-empty container");
|
||||
return Subscripts.front();
|
||||
}
|
||||
const SCEV *getLastSubscript() const {
|
||||
assert(!Subscripts.empty() && "Expecting non-empty container");
|
||||
return Subscripts.back();
|
||||
}
|
||||
|
||||
/// Return true/false if the current object and the indexed reference \p Other
|
||||
/// are/aren't in the same cache line of size \p CLS. Two references are in
|
||||
/// the same chace line iff the distance between them in the innermost
|
||||
/// dimension is less than the cache line size. Return None if unsure.
|
||||
Optional<bool> hasSpacialReuse(const IndexedReference &Other, unsigned CLS,
|
||||
AliasAnalysis &AA) const;
|
||||
|
||||
/// Return true if the current object and the indexed reference \p Other
|
||||
/// have distance smaller than \p MaxDistance in the dimension associated with
|
||||
/// the given loop \p L. Return false if the distance is not smaller than \p
|
||||
/// MaxDistance and None if unsure.
|
||||
Optional<bool> hasTemporalReuse(const IndexedReference &Other,
|
||||
unsigned MaxDistance, const Loop &L,
|
||||
DependenceInfo &DI, AliasAnalysis &AA) const;
|
||||
|
||||
/// Compute the cost of the reference w.r.t. the given loop \p L when it is
|
||||
/// considered in the innermost position in the loop nest.
|
||||
/// The cost is defined as:
|
||||
/// - equal to one if the reference is loop invariant, or
|
||||
/// - equal to '(TripCount * stride) / cache_line_size' if:
|
||||
/// + the reference stride is less than the cache line size, and
|
||||
/// + the coefficient of this loop's index variable used in all other
|
||||
/// subscripts is zero
|
||||
/// - or otherwise equal to 'TripCount'.
|
||||
CacheCostTy computeRefCost(const Loop &L, unsigned CLS) const;
|
||||
|
||||
private:
|
||||
/// Attempt to delinearize the indexed reference.
|
||||
bool delinearize(const LoopInfo &LI);
|
||||
|
||||
/// Return true if the index reference is invariant with respect to loop \p L.
|
||||
bool isLoopInvariant(const Loop &L) const;
|
||||
|
||||
/// Return true if the indexed reference is 'consecutive' in loop \p L.
|
||||
/// An indexed reference is 'consecutive' if the only coefficient that uses
|
||||
/// the loop induction variable is the rightmost one, and the access stride is
|
||||
/// smaller than the cache line size \p CLS.
|
||||
bool isConsecutive(const Loop &L, unsigned CLS) const;
|
||||
|
||||
/// Return the coefficient used in the rightmost dimension.
|
||||
const SCEV *getLastCoefficient() const;
|
||||
|
||||
/// Return true if the coefficient corresponding to induction variable of
|
||||
/// loop \p L in the given \p Subscript is zero or is loop invariant in \p L.
|
||||
bool isCoeffForLoopZeroOrInvariant(const SCEV &Subscript,
|
||||
const Loop &L) const;
|
||||
|
||||
/// Verify that the given \p Subscript is 'well formed' (must be a simple add
|
||||
/// recurrence).
|
||||
bool isSimpleAddRecurrence(const SCEV &Subscript, const Loop &L) const;
|
||||
|
||||
/// Return true if the given reference \p Other is definetely aliased with
|
||||
/// the indexed reference represented by this class.
|
||||
bool isAliased(const IndexedReference &Other, AliasAnalysis &AA) const;
|
||||
|
||||
private:
|
||||
/// True if the reference can be delinearized, false otherwise.
|
||||
bool IsValid = false;
|
||||
|
||||
/// Represent the memory reference instruction.
|
||||
Instruction &StoreOrLoadInst;
|
||||
|
||||
/// The base pointer of the memory reference.
|
||||
const SCEV *BasePointer = nullptr;
|
||||
|
||||
/// The subscript (indexes) of the memory reference.
|
||||
SmallVector<const SCEV *, 3> Subscripts;
|
||||
|
||||
/// The dimensions of the memory reference.
|
||||
SmallVector<const SCEV *, 3> Sizes;
|
||||
|
||||
ScalarEvolution &SE;
|
||||
};
|
||||
|
||||
/// A reference group represents a set of memory references that exhibit
|
||||
/// temporal or spacial reuse. Two references belong to the same
|
||||
/// reference group with respect to a inner loop L iff:
|
||||
/// 1. they have a loop independent dependency, or
|
||||
/// 2. they have a loop carried dependence with a small dependence distance
|
||||
/// (e.g. less than 2) carried by the inner loop, or
|
||||
/// 3. they refer to the same array, and the subscript in their innermost
|
||||
/// dimension is less than or equal to 'd' (where 'd' is less than the cache
|
||||
/// line size)
|
||||
///
|
||||
/// Intuitively a reference group represents memory references that access
|
||||
/// the same cache line. Conditions 1,2 above account for temporal reuse, while
|
||||
/// contition 3 accounts for spacial reuse.
|
||||
using ReferenceGroupTy = SmallVector<std::unique_ptr<IndexedReference>, 8>;
|
||||
using ReferenceGroupsTy = SmallVector<ReferenceGroupTy, 8>;
|
||||
|
||||
/// \c CacheCost represents the estimated cost of a inner loop as the number of
|
||||
/// cache lines used by the memory references it contains.
|
||||
/// The 'cache cost' of a loop 'L' in a loop nest 'LN' is computed as the sum of
|
||||
/// the cache costs of all of its reference groups when the loop is considered
|
||||
/// to be in the innermost position in the nest.
|
||||
/// A reference group represents memory references that fall into the same cache
|
||||
/// line. Each reference group is analysed with respect to the innermost loop in
|
||||
/// a loop nest. The cost of a reference is defined as follow:
|
||||
/// - one if it is loop invariant w.r.t the innermost loop,
|
||||
/// - equal to the loop trip count divided by the cache line times the
|
||||
/// reference stride if the reference stride is less than the cache line
|
||||
/// size (CLS), and the coefficient of this loop's index variable used in all
|
||||
/// other subscripts is zero (e.g. RefCost = TripCount/(CLS/RefStride))
|
||||
/// - equal to the innermost loop trip count if the reference stride is greater
|
||||
/// or equal to the cache line size CLS.
|
||||
class CacheCost {
|
||||
friend raw_ostream &operator<<(raw_ostream &OS, const CacheCost &CC);
|
||||
using LoopTripCountTy = std::pair<const Loop *, unsigned>;
|
||||
using LoopCacheCostTy = std::pair<const Loop *, CacheCostTy>;
|
||||
|
||||
public:
|
||||
static CacheCostTy constexpr InvalidCost = -1;
|
||||
|
||||
/// Construct a CacheCost object for the loop nest described by \p Loops.
|
||||
/// The optional parameter \p TRT can be used to specify the max. distance
|
||||
/// between array elements accessed in a loop so that the elements are
|
||||
/// classified to have temporal reuse.
|
||||
CacheCost(const LoopVectorTy &Loops, const LoopInfo &LI, ScalarEvolution &SE,
|
||||
TargetTransformInfo &TTI, AliasAnalysis &AA, DependenceInfo &DI,
|
||||
Optional<unsigned> TRT = None);
|
||||
|
||||
/// Create a CacheCost for the loop nest rooted by \p Root.
|
||||
/// The optional parameter \p TRT can be used to specify the max. distance
|
||||
/// between array elements accessed in a loop so that the elements are
|
||||
/// classified to have temporal reuse.
|
||||
static std::unique_ptr<CacheCost>
|
||||
getCacheCost(Loop &Root, LoopStandardAnalysisResults &AR, DependenceInfo &DI,
|
||||
Optional<unsigned> TRT = None);
|
||||
|
||||
/// Return the estimated cost of loop \p L if the given loop is part of the
|
||||
/// loop nest associated with this object. Return -1 otherwise.
|
||||
CacheCostTy getLoopCost(const Loop &L) const {
|
||||
auto IT = std::find_if(
|
||||
LoopCosts.begin(), LoopCosts.end(),
|
||||
[&L](const LoopCacheCostTy &LCC) { return LCC.first == &L; });
|
||||
return (IT != LoopCosts.end()) ? (*IT).second : -1;
|
||||
}
|
||||
|
||||
/// Return the estimated ordered loop costs.
|
||||
const ArrayRef<LoopCacheCostTy> getLoopCosts() const { return LoopCosts; }
|
||||
|
||||
private:
|
||||
/// Calculate the cache footprint of each loop in the nest (when it is
|
||||
/// considered to be in the innermost position).
|
||||
void calculateCacheFootprint();
|
||||
|
||||
/// Partition store/load instructions in the loop nest into reference groups.
|
||||
/// Two or more memory accesses belong in the same reference group if they
|
||||
/// share the same cache line.
|
||||
bool populateReferenceGroups(ReferenceGroupsTy &RefGroups) const;
|
||||
|
||||
/// Calculate the cost of the given loop \p L assuming it is the innermost
|
||||
/// loop in nest.
|
||||
CacheCostTy computeLoopCacheCost(const Loop &L,
|
||||
const ReferenceGroupsTy &RefGroups) const;
|
||||
|
||||
/// Compute the cost of a representative reference in reference group \p RG
|
||||
/// when the given loop \p L is considered as the innermost loop in the nest.
|
||||
/// The computed cost is an estimate for the number of cache lines used by the
|
||||
/// reference group. The representative reference cost is defined as:
|
||||
/// - equal to one if the reference is loop invariant, or
|
||||
/// - equal to '(TripCount * stride) / cache_line_size' if (a) loop \p L's
|
||||
/// induction variable is used only in the reference subscript associated
|
||||
/// with loop \p L, and (b) the reference stride is less than the cache
|
||||
/// line size, or
|
||||
/// - TripCount otherwise
|
||||
CacheCostTy computeRefGroupCacheCost(const ReferenceGroupTy &RG,
|
||||
const Loop &L) const;
|
||||
|
||||
/// Sort the LoopCosts vector by decreasing cache cost.
|
||||
void sortLoopCosts() {
|
||||
sort(LoopCosts, [](const LoopCacheCostTy &A, const LoopCacheCostTy &B) {
|
||||
return A.second > B.second;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
/// Loops in the loop nest associated with this object.
|
||||
LoopVectorTy Loops;
|
||||
|
||||
/// Trip counts for the loops in the loop nest associated with this object.
|
||||
SmallVector<LoopTripCountTy, 3> TripCounts;
|
||||
|
||||
/// Cache costs for the loops in the loop nest associated with this object.
|
||||
SmallVector<LoopCacheCostTy, 3> LoopCosts;
|
||||
|
||||
/// The max. distance between array elements accessed in a loop so that the
|
||||
/// elements are classified to have temporal reuse.
|
||||
Optional<unsigned> TRT;
|
||||
|
||||
const LoopInfo &LI;
|
||||
ScalarEvolution &SE;
|
||||
TargetTransformInfo &TTI;
|
||||
AliasAnalysis &AA;
|
||||
DependenceInfo &DI;
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const IndexedReference &R);
|
||||
raw_ostream &operator<<(raw_ostream &OS, const CacheCost &CC);
|
||||
|
||||
/// Printer pass for the \c CacheCost results.
|
||||
class LoopCachePrinterPass : public PassInfoMixin<LoopCachePrinterPass> {
|
||||
raw_ostream &OS;
|
||||
|
||||
public:
|
||||
explicit LoopCachePrinterPass(raw_ostream &OS) : OS(OS) {}
|
||||
|
||||
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM,
|
||||
LoopStandardAnalysisResults &AR, LPMUpdater &U);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_LOOPCACHEANALYSIS_H
|
@ -30,6 +30,9 @@
|
||||
// instance. In particular, a Loop might be inside such a non-loop SCC, or a
|
||||
// non-loop SCC might contain a sub-SCC which is a Loop.
|
||||
//
|
||||
// For an overview of terminology used in this API (and thus all of our loop
|
||||
// analyses or transforms), see docs/LoopTerminology.rst.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_LOOPINFO_H
|
||||
@ -570,9 +573,9 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
bool getIncomingAndBackEdge(BasicBlock *&Incoming,
|
||||
BasicBlock *&Backedge) const;
|
||||
|
||||
/// Below are some utilities to get loop bounds and induction variable, and
|
||||
/// check if a given phinode is an auxiliary induction variable, as well as
|
||||
/// checking if the loop is canonical.
|
||||
/// Below are some utilities to get the loop guard, loop bounds and induction
|
||||
/// variable, and to check if a given phinode is an auxiliary induction
|
||||
/// variable, if the loop is guarded, and if the loop is canonical.
|
||||
///
|
||||
/// Here is an example:
|
||||
/// \code
|
||||
@ -604,6 +607,9 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
///
|
||||
/// - getInductionVariable --> i_1
|
||||
/// - isAuxiliaryInductionVariable(x) --> true if x == i_1
|
||||
/// - getLoopGuardBranch()
|
||||
/// --> `if (guardcmp) goto preheader; else goto afterloop`
|
||||
/// - isGuarded() --> true
|
||||
/// - isCanonical --> false
|
||||
struct LoopBounds {
|
||||
/// Return the LoopBounds object if
|
||||
@ -725,6 +731,31 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
bool isAuxiliaryInductionVariable(PHINode &AuxIndVar,
|
||||
ScalarEvolution &SE) const;
|
||||
|
||||
/// Return the loop guard branch, if it exists.
|
||||
///
|
||||
/// This currently only works on simplified loop, as it requires a preheader
|
||||
/// and a latch to identify the guard. It will work on loops of the form:
|
||||
/// \code
|
||||
/// GuardBB:
|
||||
/// br cond1, Preheader, ExitSucc <== GuardBranch
|
||||
/// Preheader:
|
||||
/// br Header
|
||||
/// Header:
|
||||
/// ...
|
||||
/// br Latch
|
||||
/// Latch:
|
||||
/// br cond2, Header, ExitBlock
|
||||
/// ExitBlock:
|
||||
/// br ExitSucc
|
||||
/// ExitSucc:
|
||||
/// \endcode
|
||||
BranchInst *getLoopGuardBranch() const;
|
||||
|
||||
/// Return true iff the loop is
|
||||
/// - in simplify rotated form, and
|
||||
/// - guarded by a loop guard branch.
|
||||
bool isGuarded() const { return (getLoopGuardBranch() != nullptr); }
|
||||
|
||||
/// Return true if the loop induction variable starts at zero and increments
|
||||
/// by one each time through the loop.
|
||||
bool isCanonical(ScalarEvolution &SE) const;
|
||||
|
@ -85,9 +85,9 @@ template <class BlockT, class LoopT>
|
||||
bool LoopBase<BlockT, LoopT>::hasDedicatedExits() const {
|
||||
// Each predecessor of each exit block of a normal loop is contained
|
||||
// within the loop.
|
||||
SmallVector<BlockT *, 4> ExitBlocks;
|
||||
getExitBlocks(ExitBlocks);
|
||||
for (BlockT *EB : ExitBlocks)
|
||||
SmallVector<BlockT *, 4> UniqueExitBlocks;
|
||||
getUniqueExitBlocks(UniqueExitBlocks);
|
||||
for (BlockT *EB : UniqueExitBlocks)
|
||||
for (BlockT *Predecessor : children<Inverse<BlockT *>>(EB))
|
||||
if (!contains(Predecessor))
|
||||
return false;
|
||||
@ -200,8 +200,6 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure there is only one exit out of the preheader.
|
||||
assert(Out && "Header of loop has no predecessors from outside loop?");
|
||||
return Out;
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,9 @@ class Value;
|
||||
/// like).
|
||||
bool isAllocationFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
bool isAllocationFn(const Value *V,
|
||||
function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// Tests if a value is a call or invoke to a function that returns a
|
||||
/// NoAlias pointer (including malloc/calloc/realloc/strdup-like functions).
|
||||
@ -68,6 +71,9 @@ bool isNoAliasFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
/// allocates uninitialized memory (such as malloc).
|
||||
bool isMallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
bool isMallocLikeFn(const Value *V,
|
||||
function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates zero-filled memory (such as calloc).
|
||||
@ -93,6 +99,16 @@ bool isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
/// reallocates memory (e.g., realloc).
|
||||
bool isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI);
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory and throws if an allocation failed (e.g., new).
|
||||
bool isOpNewLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory (strdup, strndup).
|
||||
bool isStrdupLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// malloc Call Utility Functions.
|
||||
//
|
||||
@ -100,9 +116,13 @@ bool isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI);
|
||||
/// extractMallocCall - Returns the corresponding CallInst if the instruction
|
||||
/// is a malloc call. Since CallInst::CreateMalloc() only creates calls, we
|
||||
/// ignore InvokeInst here.
|
||||
const CallInst *extractMallocCall(const Value *I, const TargetLibraryInfo *TLI);
|
||||
inline CallInst *extractMallocCall(Value *I, const TargetLibraryInfo *TLI) {
|
||||
return const_cast<CallInst*>(extractMallocCall((const Value*)I, TLI));
|
||||
const CallInst *
|
||||
extractMallocCall(const Value *I,
|
||||
function_ref<const TargetLibraryInfo &(Function &)> GetTLI);
|
||||
inline CallInst *
|
||||
extractMallocCall(Value *I,
|
||||
function_ref<const TargetLibraryInfo &(Function &)> GetTLI) {
|
||||
return const_cast<CallInst *>(extractMallocCall((const Value *)I, GetTLI));
|
||||
}
|
||||
|
||||
/// getMallocType - Returns the PointerType resulting from the malloc call.
|
||||
|
@ -362,11 +362,14 @@ class MemoryDependenceResults {
|
||||
PhiValues &PV;
|
||||
PredIteratorCache PredCache;
|
||||
|
||||
unsigned DefaultBlockScanLimit;
|
||||
|
||||
public:
|
||||
MemoryDependenceResults(AliasAnalysis &AA, AssumptionCache &AC,
|
||||
const TargetLibraryInfo &TLI,
|
||||
DominatorTree &DT, PhiValues &PV)
|
||||
: AA(AA), AC(AC), TLI(TLI), DT(DT), PV(PV) {}
|
||||
const TargetLibraryInfo &TLI, DominatorTree &DT,
|
||||
PhiValues &PV, unsigned DefaultBlockScanLimit)
|
||||
: AA(AA), AC(AC), TLI(TLI), DT(DT), PV(PV),
|
||||
DefaultBlockScanLimit(DefaultBlockScanLimit) {}
|
||||
|
||||
/// Handle invalidation in the new PM.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
@ -511,9 +514,14 @@ class MemoryDependenceAnalysis
|
||||
|
||||
static AnalysisKey Key;
|
||||
|
||||
unsigned DefaultBlockScanLimit;
|
||||
|
||||
public:
|
||||
using Result = MemoryDependenceResults;
|
||||
|
||||
MemoryDependenceAnalysis();
|
||||
MemoryDependenceAnalysis(unsigned DefaultBlockScanLimit) : DefaultBlockScanLimit(DefaultBlockScanLimit) { }
|
||||
|
||||
MemoryDependenceResults run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
|
@ -793,6 +793,7 @@ class MemorySSA {
|
||||
friend class MemorySSAPrinterLegacyPass;
|
||||
friend class MemorySSAUpdater;
|
||||
|
||||
void verifyPrevDefInPhis(Function &F) const;
|
||||
void verifyDefUses(Function &F) const;
|
||||
void verifyDomination(Function &F) const;
|
||||
void verifyOrdering(Function &F) const;
|
||||
@ -830,7 +831,8 @@ class MemorySSA {
|
||||
void insertIntoListsBefore(MemoryAccess *, const BasicBlock *,
|
||||
AccessList::iterator);
|
||||
MemoryUseOrDef *createDefinedAccess(Instruction *, MemoryAccess *,
|
||||
const MemoryUseOrDef *Template = nullptr);
|
||||
const MemoryUseOrDef *Template = nullptr,
|
||||
bool CreationMustSucceed = true);
|
||||
|
||||
private:
|
||||
template <class AliasAnalysisType> class ClobberWalkerBase;
|
||||
|
@ -99,7 +99,7 @@ class MemorySSAUpdater {
|
||||
/// load a
|
||||
/// Where a mayalias b, *does* require RenameUses be set to true.
|
||||
void insertDef(MemoryDef *Def, bool RenameUses = false);
|
||||
void insertUse(MemoryUse *Use);
|
||||
void insertUse(MemoryUse *Use, bool RenameUses = false);
|
||||
/// Update the MemoryPhi in `To` following an edge deletion between `From` and
|
||||
/// `To`. If `To` becomes unreachable, a call to removeBlocks should be made.
|
||||
void removeEdge(BasicBlock *From, BasicBlock *To);
|
||||
@ -275,6 +275,7 @@ class MemorySSAUpdater {
|
||||
getPreviousDefRecursive(BasicBlock *,
|
||||
DenseMap<BasicBlock *, TrackingVH<MemoryAccess>> &);
|
||||
MemoryAccess *recursePhi(MemoryAccess *Phi);
|
||||
MemoryAccess *tryRemoveTrivialPhi(MemoryPhi *Phi);
|
||||
template <class RangeType>
|
||||
MemoryAccess *tryRemoveTrivialPhi(MemoryPhi *Phi, RangeType &Operands);
|
||||
void tryRemoveTrivialPhis(ArrayRef<WeakVH> UpdatedPHIs);
|
||||
|
@ -7,10 +7,17 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Contains a collection of routines for determining if a given instruction is
|
||||
/// guaranteed to execute if a given point in control flow is reached. The most
|
||||
/// guaranteed to execute if a given point in control flow is reached. The most
|
||||
/// common example is an instruction within a loop being provably executed if we
|
||||
/// branch to the header of it's containing loop.
|
||||
///
|
||||
/// There are two interfaces available to determine if an instruction is
|
||||
/// executed once a given point in the control flow is reached:
|
||||
/// 1) A loop-centric one derived from LoopSafetyInfo.
|
||||
/// 2) A "must be executed context"-based one implemented in the
|
||||
/// MustBeExecutedContextExplorer.
|
||||
/// Please refer to the class comments for more information.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_MUSTEXECUTE_H
|
||||
@ -164,6 +171,280 @@ class ICFLoopSafetyInfo: public LoopSafetyInfo {
|
||||
virtual ~ICFLoopSafetyInfo() {};
|
||||
};
|
||||
|
||||
}
|
||||
struct MustBeExecutedContextExplorer;
|
||||
|
||||
/// Must be executed iterators visit stretches of instructions that are
|
||||
/// guaranteed to be executed together, potentially with other instruction
|
||||
/// executed in-between.
|
||||
///
|
||||
/// Given the following code, and assuming all statements are single
|
||||
/// instructions which transfer execution to the successor (see
|
||||
/// isGuaranteedToTransferExecutionToSuccessor), there are two possible
|
||||
/// outcomes. If we start the iterator at A, B, or E, we will visit only A, B,
|
||||
/// and E. If we start at C or D, we will visit all instructions A-E.
|
||||
///
|
||||
/// \code
|
||||
/// A;
|
||||
/// B;
|
||||
/// if (...) {
|
||||
/// C;
|
||||
/// D;
|
||||
/// }
|
||||
/// E;
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
/// Below is the example extneded with instructions F and G. Now we assume F
|
||||
/// might not transfer execution to it's successor G. As a result we get the
|
||||
/// following visit sets:
|
||||
///
|
||||
/// Start Instruction | Visit Set
|
||||
/// A | A, B, E, F
|
||||
/// B | A, B, E, F
|
||||
/// C | A, B, C, D, E, F
|
||||
/// D | A, B, C, D, E, F
|
||||
/// E | A, B, E, F
|
||||
/// F | A, B, E, F
|
||||
/// G | A, B, E, F, G
|
||||
///
|
||||
///
|
||||
/// \code
|
||||
/// A;
|
||||
/// B;
|
||||
/// if (...) {
|
||||
/// C;
|
||||
/// D;
|
||||
/// }
|
||||
/// E;
|
||||
/// F; // Might not transfer execution to its successor G.
|
||||
/// G;
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
/// A more complex example involving conditionals, loops, break, and continue
|
||||
/// is shown below. We again assume all instructions will transmit control to
|
||||
/// the successor and we assume we can prove the inner loop to be finite. We
|
||||
/// omit non-trivial branch conditions as the exploration is oblivious to them.
|
||||
/// Constant branches are assumed to be unconditional in the CFG. The resulting
|
||||
/// visist sets are shown in the table below.
|
||||
///
|
||||
/// \code
|
||||
/// A;
|
||||
/// while (true) {
|
||||
/// B;
|
||||
/// if (...)
|
||||
/// C;
|
||||
/// if (...)
|
||||
/// continue;
|
||||
/// D;
|
||||
/// if (...)
|
||||
/// break;
|
||||
/// do {
|
||||
/// if (...)
|
||||
/// continue;
|
||||
/// E;
|
||||
/// } while (...);
|
||||
/// F;
|
||||
/// }
|
||||
/// G;
|
||||
/// \endcode
|
||||
///
|
||||
/// Start Instruction | Visit Set
|
||||
/// A | A, B
|
||||
/// B | A, B
|
||||
/// C | A, B, C
|
||||
/// D | A, B, D
|
||||
/// E | A, B, D, E, F
|
||||
/// F | A, B, D, F
|
||||
/// G | A, B, D, G
|
||||
///
|
||||
///
|
||||
/// Note that the examples show optimal visist sets but not necessarily the ones
|
||||
/// derived by the explorer depending on the available CFG analyses (see
|
||||
/// MustBeExecutedContextExplorer). Also note that we, depending on the options,
|
||||
/// the visit set can contain instructions from other functions.
|
||||
struct MustBeExecutedIterator {
|
||||
/// Type declarations that make his class an input iterator.
|
||||
///{
|
||||
typedef const Instruction *value_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef const Instruction **pointer;
|
||||
typedef const Instruction *&reference;
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
///}
|
||||
|
||||
using ExplorerTy = MustBeExecutedContextExplorer;
|
||||
|
||||
MustBeExecutedIterator(const MustBeExecutedIterator &Other)
|
||||
: Visited(Other.Visited), Explorer(Other.Explorer),
|
||||
CurInst(Other.CurInst) {}
|
||||
|
||||
MustBeExecutedIterator(MustBeExecutedIterator &&Other)
|
||||
: Visited(std::move(Other.Visited)), Explorer(Other.Explorer),
|
||||
CurInst(Other.CurInst) {}
|
||||
|
||||
MustBeExecutedIterator &operator=(MustBeExecutedIterator &&Other) {
|
||||
if (this != &Other) {
|
||||
std::swap(Visited, Other.Visited);
|
||||
std::swap(CurInst, Other.CurInst);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~MustBeExecutedIterator() {}
|
||||
|
||||
/// Pre- and post-increment operators.
|
||||
///{
|
||||
MustBeExecutedIterator &operator++() {
|
||||
CurInst = advance();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MustBeExecutedIterator operator++(int) {
|
||||
MustBeExecutedIterator tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
///}
|
||||
|
||||
/// Equality and inequality operators. Note that we ignore the history here.
|
||||
///{
|
||||
bool operator==(const MustBeExecutedIterator &Other) const {
|
||||
return CurInst == Other.CurInst;
|
||||
}
|
||||
|
||||
bool operator!=(const MustBeExecutedIterator &Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
///}
|
||||
|
||||
/// Return the underlying instruction.
|
||||
const Instruction *&operator*() { return CurInst; }
|
||||
const Instruction *getCurrentInst() const { return CurInst; }
|
||||
|
||||
/// Return true if \p I was encountered by this iterator already.
|
||||
bool count(const Instruction *I) const { return Visited.count(I); }
|
||||
|
||||
private:
|
||||
using VisitedSetTy = DenseSet<const Instruction *>;
|
||||
|
||||
/// Private constructors.
|
||||
MustBeExecutedIterator(ExplorerTy &Explorer, const Instruction *I);
|
||||
|
||||
/// Reset the iterator to its initial state pointing at \p I.
|
||||
void reset(const Instruction *I);
|
||||
|
||||
/// Try to advance one of the underlying positions (Head or Tail).
|
||||
///
|
||||
/// \return The next instruction in the must be executed context, or nullptr
|
||||
/// if none was found.
|
||||
const Instruction *advance();
|
||||
|
||||
/// A set to track the visited instructions in order to deal with endless
|
||||
/// loops and recursion.
|
||||
VisitedSetTy Visited;
|
||||
|
||||
/// A reference to the explorer that created this iterator.
|
||||
ExplorerTy &Explorer;
|
||||
|
||||
/// The instruction we are currently exposing to the user. There is always an
|
||||
/// instruction that we know is executed with the given program point,
|
||||
/// initially the program point itself.
|
||||
const Instruction *CurInst;
|
||||
|
||||
friend struct MustBeExecutedContextExplorer;
|
||||
};
|
||||
|
||||
/// A "must be executed context" for a given program point PP is the set of
|
||||
/// instructions, potentially before and after PP, that are executed always when
|
||||
/// PP is reached. The MustBeExecutedContextExplorer an interface to explore
|
||||
/// "must be executed contexts" in a module through the use of
|
||||
/// MustBeExecutedIterator.
|
||||
///
|
||||
/// The explorer exposes "must be executed iterators" that traverse the must be
|
||||
/// executed context. There is little information sharing between iterators as
|
||||
/// the expected use case involves few iterators for "far apart" instructions.
|
||||
/// If that changes, we should consider caching more intermediate results.
|
||||
struct MustBeExecutedContextExplorer {
|
||||
|
||||
/// In the description of the parameters we use PP to denote a program point
|
||||
/// for which the must be executed context is explored, or put differently,
|
||||
/// for which the MustBeExecutedIterator is created.
|
||||
///
|
||||
/// \param ExploreInterBlock Flag to indicate if instructions in blocks
|
||||
/// other than the parent of PP should be
|
||||
/// explored.
|
||||
MustBeExecutedContextExplorer(bool ExploreInterBlock)
|
||||
: ExploreInterBlock(ExploreInterBlock), EndIterator(*this, nullptr) {}
|
||||
|
||||
/// Clean up the dynamically allocated iterators.
|
||||
~MustBeExecutedContextExplorer() {
|
||||
DeleteContainerSeconds(InstructionIteratorMap);
|
||||
}
|
||||
|
||||
/// Iterator-based interface. \see MustBeExecutedIterator.
|
||||
///{
|
||||
using iterator = MustBeExecutedIterator;
|
||||
using const_iterator = const MustBeExecutedIterator;
|
||||
|
||||
/// Return an iterator to explore the context around \p PP.
|
||||
iterator &begin(const Instruction *PP) {
|
||||
auto *&It = InstructionIteratorMap[PP];
|
||||
if (!It)
|
||||
It = new iterator(*this, PP);
|
||||
return *It;
|
||||
}
|
||||
|
||||
/// Return an iterator to explore the cached context around \p PP.
|
||||
const_iterator &begin(const Instruction *PP) const {
|
||||
return *InstructionIteratorMap.lookup(PP);
|
||||
}
|
||||
|
||||
/// Return an universal end iterator.
|
||||
///{
|
||||
iterator &end() { return EndIterator; }
|
||||
iterator &end(const Instruction *) { return EndIterator; }
|
||||
|
||||
const_iterator &end() const { return EndIterator; }
|
||||
const_iterator &end(const Instruction *) const { return EndIterator; }
|
||||
///}
|
||||
|
||||
/// Return an iterator range to explore the context around \p PP.
|
||||
llvm::iterator_range<iterator> range(const Instruction *PP) {
|
||||
return llvm::make_range(begin(PP), end(PP));
|
||||
}
|
||||
|
||||
/// Return an iterator range to explore the cached context around \p PP.
|
||||
llvm::iterator_range<const_iterator> range(const Instruction *PP) const {
|
||||
return llvm::make_range(begin(PP), end(PP));
|
||||
}
|
||||
///}
|
||||
|
||||
/// Return the next instruction that is guaranteed to be executed after \p PP.
|
||||
///
|
||||
/// \param It The iterator that is used to traverse the must be
|
||||
/// executed context.
|
||||
/// \param PP The program point for which the next instruction
|
||||
/// that is guaranteed to execute is determined.
|
||||
const Instruction *
|
||||
getMustBeExecutedNextInstruction(MustBeExecutedIterator &It,
|
||||
const Instruction *PP);
|
||||
|
||||
/// Parameter that limit the performed exploration. See the constructor for
|
||||
/// their meaning.
|
||||
///{
|
||||
const bool ExploreInterBlock;
|
||||
///}
|
||||
|
||||
private:
|
||||
/// Map from instructions to associated must be executed iterators.
|
||||
DenseMap<const Instruction *, MustBeExecutedIterator *>
|
||||
InstructionIteratorMap;
|
||||
|
||||
/// A unique end iterator.
|
||||
MustBeExecutedIterator EndIterator;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -103,6 +103,13 @@ namespace llvm {
|
||||
//
|
||||
FunctionPass *createMustExecutePrinter();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// createMustBeExecutedContextPrinter - This pass prints information about which
|
||||
// instructions are guaranteed to execute together (run with -analyze).
|
||||
//
|
||||
ModulePass *createMustBeExecutedContextPrinter();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -52,6 +52,15 @@ class ProfileSummaryInfo {
|
||||
// because the number of profile counts required to reach the hot
|
||||
// percentile is above a huge threshold.
|
||||
Optional<bool> HasHugeWorkingSetSize;
|
||||
// True if the working set size of the code is considered large,
|
||||
// because the number of profile counts required to reach the hot
|
||||
// percentile is above a large threshold.
|
||||
Optional<bool> HasLargeWorkingSetSize;
|
||||
// Compute the threshold for a given cutoff.
|
||||
Optional<uint64_t> computeThreshold(int PercentileCutoff);
|
||||
// The map that caches the threshold values. The keys are the percentile
|
||||
// cutoff values and the values are the corresponding threshold values.
|
||||
DenseMap<int, uint64_t> ThresholdCache;
|
||||
|
||||
public:
|
||||
ProfileSummaryInfo(Module &M) : M(M) {}
|
||||
@ -96,6 +105,8 @@ class ProfileSummaryInfo {
|
||||
bool AllowSynthetic = false);
|
||||
/// Returns true if the working set size of the code is considered huge.
|
||||
bool hasHugeWorkingSetSize();
|
||||
/// Returns true if the working set size of the code is considered large.
|
||||
bool hasLargeWorkingSetSize();
|
||||
/// Returns true if \p F has hot function entry.
|
||||
bool isFunctionEntryHot(const Function *F);
|
||||
/// Returns true if \p F contains hot code.
|
||||
@ -104,14 +115,26 @@ class ProfileSummaryInfo {
|
||||
bool isFunctionEntryCold(const Function *F);
|
||||
/// Returns true if \p F contains only cold code.
|
||||
bool isFunctionColdInCallGraph(const Function *F, BlockFrequencyInfo &BFI);
|
||||
/// Returns true if \p F contains hot code with regard to a given hot
|
||||
/// percentile cutoff value.
|
||||
bool isFunctionHotInCallGraphNthPercentile(int PercentileCutoff,
|
||||
const Function *F,
|
||||
BlockFrequencyInfo &BFI);
|
||||
/// Returns true if count \p C is considered hot.
|
||||
bool isHotCount(uint64_t C);
|
||||
/// Returns true if count \p C is considered cold.
|
||||
bool isColdCount(uint64_t C);
|
||||
/// Returns true if count \p C is considered hot with regard to a given
|
||||
/// hot percentile cutoff value.
|
||||
bool isHotCountNthPercentile(int PercentileCutoff, uint64_t C);
|
||||
/// Returns true if BasicBlock \p BB is considered hot.
|
||||
bool isHotBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if BasicBlock \p BB is considered cold.
|
||||
bool isColdBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if BasicBlock \p BB is considered hot with regard to a given
|
||||
/// hot percentile cutoff value.
|
||||
bool isHotBlockNthPercentile(int PercentileCutoff,
|
||||
const BasicBlock *BB, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if CallSite \p CS is considered hot.
|
||||
bool isHotCallSite(const CallSite &CS, BlockFrequencyInfo *BFI);
|
||||
/// Returns true if Callsite \p CS is considered cold.
|
||||
|
@ -365,7 +365,7 @@ typename Tr::RegionNodeT *RegionBase<Tr>::getBBNode(BlockT *BB) const {
|
||||
auto Deconst = const_cast<RegionBase<Tr> *>(this);
|
||||
typename BBNodeMapT::value_type V = {
|
||||
BB,
|
||||
llvm::make_unique<RegionNodeT>(static_cast<RegionT *>(Deconst), BB)};
|
||||
std::make_unique<RegionNodeT>(static_cast<RegionT *>(Deconst), BB)};
|
||||
at = BBNodeMap.insert(std::move(V)).first;
|
||||
}
|
||||
return at->second.get();
|
||||
|
@ -468,6 +468,8 @@ template <> struct DenseMapInfo<ExitLimitQuery> {
|
||||
/// can't do much with the SCEV objects directly, they must ask this class
|
||||
/// for services.
|
||||
class ScalarEvolution {
|
||||
friend class ScalarEvolutionsTest;
|
||||
|
||||
public:
|
||||
/// An enum describing the relationship between a SCEV and a loop.
|
||||
enum LoopDisposition {
|
||||
@ -777,10 +779,10 @@ class ScalarEvolution {
|
||||
/// to (i.e. a "conservative over-approximation") of the value returend by
|
||||
/// getBackedgeTakenCount. If such a value cannot be computed, it returns the
|
||||
/// SCEVCouldNotCompute object.
|
||||
const SCEV *getMaxBackedgeTakenCount(const Loop *L);
|
||||
const SCEV *getConstantMaxBackedgeTakenCount(const Loop *L);
|
||||
|
||||
/// Return true if the backedge taken count is either the value returned by
|
||||
/// getMaxBackedgeTakenCount or zero.
|
||||
/// getConstantMaxBackedgeTakenCount or zero.
|
||||
bool isBackedgeTakenCountMaxOrZero(const Loop *L);
|
||||
|
||||
/// Return true if the specified loop has an analyzable loop-invariant
|
||||
|
@ -77,9 +77,13 @@ namespace llvm {
|
||||
/// Phis that complete an IV chain. Reuse
|
||||
DenseSet<AssertingVH<PHINode>> ChainedPhis;
|
||||
|
||||
/// 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.
|
||||
/// When true, SCEVExpander tries to expand expressions in "canonical" form.
|
||||
/// When false, expressions are expanded in a more literal form.
|
||||
///
|
||||
/// In "canonical" form addrecs are expanded as arithmetic based on a
|
||||
/// canonical induction variable. Note that CanonicalMode doesn't guarantee
|
||||
/// that all expressions are expanded in "canonical" form. For some
|
||||
/// expressions literal mode can be preferred.
|
||||
bool CanonicalMode;
|
||||
|
||||
/// When invoked from LSR, the expander is in "strength reduction" mode. The
|
||||
@ -275,8 +279,16 @@ namespace llvm {
|
||||
|
||||
/// 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();
|
||||
void clearInsertPoint() { Builder.ClearInsertionPoint(); }
|
||||
|
||||
/// Set location information used by debugging information.
|
||||
void SetCurrentDebugLocation(DebugLoc L) {
|
||||
Builder.SetCurrentDebugLocation(std::move(L));
|
||||
}
|
||||
|
||||
/// Get location information used by debugging information.
|
||||
const DebugLoc &getCurrentDebugLocation() const {
|
||||
return Builder.getCurrentDebugLocation();
|
||||
}
|
||||
|
||||
/// Return true if the specified instruction was inserted by the code
|
||||
|
@ -30,11 +30,12 @@ struct VecDesc {
|
||||
unsigned VectorizationFactor;
|
||||
};
|
||||
|
||||
enum LibFunc {
|
||||
enum LibFunc : unsigned {
|
||||
#define TLI_DEFINE_ENUM
|
||||
#include "llvm/Analysis/TargetLibraryInfo.def"
|
||||
|
||||
NumLibFuncs
|
||||
NumLibFuncs,
|
||||
NotLibFunc
|
||||
};
|
||||
|
||||
/// Implementation of the target library information.
|
||||
@ -48,7 +49,7 @@ class TargetLibraryInfoImpl {
|
||||
|
||||
unsigned char AvailableArray[(NumLibFuncs+3)/4];
|
||||
llvm::DenseMap<unsigned, std::string> CustomNames;
|
||||
static StringRef const StandardNames[NumLibFuncs];
|
||||
static StringLiteral const StandardNames[NumLibFuncs];
|
||||
bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param;
|
||||
|
||||
enum AvailabilityState {
|
||||
@ -359,7 +360,6 @@ class TargetLibraryAnalysis : public AnalysisInfoMixin<TargetLibraryAnalysis> {
|
||||
TargetLibraryAnalysis(TargetLibraryInfoImpl PresetInfoImpl)
|
||||
: PresetInfoImpl(std::move(PresetInfoImpl)) {}
|
||||
|
||||
TargetLibraryInfo run(Module &M, ModuleAnalysisManager &);
|
||||
TargetLibraryInfo run(Function &F, FunctionAnalysisManager &);
|
||||
|
||||
private:
|
||||
@ -385,8 +385,13 @@ class TargetLibraryInfoWrapperPass : public ImmutablePass {
|
||||
explicit TargetLibraryInfoWrapperPass(const Triple &T);
|
||||
explicit TargetLibraryInfoWrapperPass(const TargetLibraryInfoImpl &TLI);
|
||||
|
||||
TargetLibraryInfo &getTLI() { return TLI; }
|
||||
const TargetLibraryInfo &getTLI() const { return TLI; }
|
||||
TargetLibraryInfo &getTLI(const Function &F LLVM_ATTRIBUTE_UNUSED) {
|
||||
return TLI;
|
||||
}
|
||||
const TargetLibraryInfo &
|
||||
getTLI(const Function &F LLVM_ATTRIBUTE_UNUSED) const {
|
||||
return TLI;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -368,6 +368,20 @@ class TargetTransformInfo {
|
||||
/// optimize away.
|
||||
unsigned getFlatAddressSpace() const;
|
||||
|
||||
/// Return any intrinsic address operand indexes which may be rewritten if
|
||||
/// they use a flat address space pointer.
|
||||
///
|
||||
/// \returns true if the intrinsic was handled.
|
||||
bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
|
||||
Intrinsic::ID IID) const;
|
||||
|
||||
/// Rewrite intrinsic call \p II such that \p OldV will be replaced with \p
|
||||
/// NewV, which has a different address space. This should happen for every
|
||||
/// operand index that collectFlatAddressOperands returned for the intrinsic.
|
||||
/// \returns true if the intrinsic /// was handled.
|
||||
bool rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
|
||||
Value *OldV, Value *NewV) const;
|
||||
|
||||
/// Test whether calls to a function lower to actual program function
|
||||
/// calls.
|
||||
///
|
||||
@ -469,12 +483,17 @@ class TargetTransformInfo {
|
||||
bool Force;
|
||||
/// Allow using trip count upper bound to unroll loops.
|
||||
bool UpperBound;
|
||||
/// Allow peeling off loop iterations for loops with low dynamic tripcount.
|
||||
/// Allow peeling off loop iterations.
|
||||
bool AllowPeeling;
|
||||
/// Allow unrolling of all the iterations of the runtime loop remainder.
|
||||
bool UnrollRemainder;
|
||||
/// Allow unroll and jam. Used to enable unroll and jam for the target.
|
||||
bool UnrollAndJam;
|
||||
/// Allow peeling basing on profile. Uses to enable peeling off all
|
||||
/// iterations basing on provided profile.
|
||||
/// If the value is true the peeling cost model can decide to peel only
|
||||
/// some iterations and in this case it will set this to false.
|
||||
bool PeelProfiledIterations;
|
||||
/// Threshold for unroll and jam, for inner loop size. The 'Threshold'
|
||||
/// value above is used during unroll and jam for the outer loop size.
|
||||
/// This value is used in the same manner to limit the size of the inner
|
||||
@ -555,15 +574,15 @@ class TargetTransformInfo {
|
||||
/// modes that operate across loop iterations.
|
||||
bool shouldFavorBackedgeIndex(const Loop *L) const;
|
||||
|
||||
/// Return true if the target supports masked load.
|
||||
bool isLegalMaskedStore(Type *DataType) const;
|
||||
/// Return true if the target supports masked store.
|
||||
bool isLegalMaskedLoad(Type *DataType) const;
|
||||
bool isLegalMaskedStore(Type *DataType, MaybeAlign Alignment) const;
|
||||
/// Return true if the target supports masked load.
|
||||
bool isLegalMaskedLoad(Type *DataType, MaybeAlign Alignment) const;
|
||||
|
||||
/// Return true if the target supports nontemporal store.
|
||||
bool isLegalNTStore(Type *DataType, unsigned Alignment) const;
|
||||
bool isLegalNTStore(Type *DataType, Align Alignment) const;
|
||||
/// Return true if the target supports nontemporal load.
|
||||
bool isLegalNTLoad(Type *DataType, unsigned Alignment) const;
|
||||
bool isLegalNTLoad(Type *DataType, Align Alignment) const;
|
||||
|
||||
/// Return true if the target supports masked scatter.
|
||||
bool isLegalMaskedScatter(Type *DataType) const;
|
||||
@ -622,12 +641,6 @@ class TargetTransformInfo {
|
||||
/// Return true if this type is legal.
|
||||
bool isTypeLegal(Type *Ty) const;
|
||||
|
||||
/// Returns the target's jmp_buf alignment in bytes.
|
||||
unsigned getJumpBufAlignment() const;
|
||||
|
||||
/// Returns the target's jmp_buf size in bytes.
|
||||
unsigned getJumpBufSize() const;
|
||||
|
||||
/// Return true if switches should be turned into lookup tables for the
|
||||
/// target.
|
||||
bool shouldBuildLookupTables() const;
|
||||
@ -775,10 +788,23 @@ class TargetTransformInfo {
|
||||
/// Additional properties of an operand's values.
|
||||
enum OperandValueProperties { OP_None = 0, OP_PowerOf2 = 1 };
|
||||
|
||||
/// \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.
|
||||
unsigned getNumberOfRegisters(bool Vector) const;
|
||||
/// \return the number of registers in the target-provided register class.
|
||||
unsigned getNumberOfRegisters(unsigned ClassID) const;
|
||||
|
||||
/// \return the target-provided register class ID for the provided type,
|
||||
/// accounting for type promotion and other type-legalization techniques that the target might apply.
|
||||
/// However, it specifically does not account for the scalarization or splitting of vector types.
|
||||
/// Should a vector type require scalarization or splitting into multiple underlying vector registers,
|
||||
/// that type should be mapped to a register class containing no registers.
|
||||
/// Specifically, this is designed to provide a simple, high-level view of the register allocation
|
||||
/// later performed by the backend. These register classes don't necessarily map onto the
|
||||
/// register classes used by the backend.
|
||||
/// FIXME: It's not currently possible to determine how many registers
|
||||
/// are used by the provided type.
|
||||
unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const;
|
||||
|
||||
/// \return the target-provided register class name
|
||||
const char* getRegisterClassName(unsigned ClassID) const;
|
||||
|
||||
/// \return The width of the largest scalar or vector register type.
|
||||
unsigned getRegisterBitWidth(bool Vector) const;
|
||||
@ -824,18 +850,20 @@ class TargetTransformInfo {
|
||||
/// \return The associativity of the cache level, if available.
|
||||
llvm::Optional<unsigned> getCacheAssociativity(CacheLevel Level) const;
|
||||
|
||||
/// \return How much before a load we should place the prefetch instruction.
|
||||
/// This is currently measured in number of instructions.
|
||||
/// \return How much before a load we should place the prefetch
|
||||
/// instruction. This is currently measured in number of
|
||||
/// instructions.
|
||||
unsigned getPrefetchDistance() const;
|
||||
|
||||
/// \return Some HW prefetchers can handle accesses up to a certain constant
|
||||
/// stride. This is the minimum stride in bytes where it makes sense to start
|
||||
/// adding SW prefetches. The default is 1, i.e. prefetch with any stride.
|
||||
/// \return Some HW prefetchers can handle accesses up to a certain
|
||||
/// constant stride. This is the minimum stride in bytes where it
|
||||
/// makes sense to start adding SW prefetches. The default is 1,
|
||||
/// i.e. prefetch with any stride.
|
||||
unsigned getMinPrefetchStride() const;
|
||||
|
||||
/// \return The maximum number of iterations to prefetch ahead. If the
|
||||
/// required number of iterations is more than this number, no prefetching is
|
||||
/// performed.
|
||||
/// \return The maximum number of iterations to prefetch ahead. If
|
||||
/// the required number of iterations is more than this number, no
|
||||
/// prefetching is performed.
|
||||
unsigned getMaxPrefetchIterationsAhead() const;
|
||||
|
||||
/// \return The maximum interleave factor that any transform should try to
|
||||
@ -1155,6 +1183,10 @@ class TargetTransformInfo::Concept {
|
||||
virtual bool isSourceOfDivergence(const Value *V) = 0;
|
||||
virtual bool isAlwaysUniform(const Value *V) = 0;
|
||||
virtual unsigned getFlatAddressSpace() = 0;
|
||||
virtual bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
|
||||
Intrinsic::ID IID) const = 0;
|
||||
virtual bool rewriteIntrinsicWithAddressSpace(
|
||||
IntrinsicInst *II, Value *OldV, Value *NewV) const = 0;
|
||||
virtual bool isLoweredToCall(const Function *F) = 0;
|
||||
virtual void getUnrollingPreferences(Loop *L, ScalarEvolution &,
|
||||
UnrollingPreferences &UP) = 0;
|
||||
@ -1177,10 +1209,10 @@ class TargetTransformInfo::Concept {
|
||||
TargetLibraryInfo *LibInfo) = 0;
|
||||
virtual bool shouldFavorPostInc() const = 0;
|
||||
virtual bool shouldFavorBackedgeIndex(const Loop *L) const = 0;
|
||||
virtual bool isLegalMaskedStore(Type *DataType) = 0;
|
||||
virtual bool isLegalMaskedLoad(Type *DataType) = 0;
|
||||
virtual bool isLegalNTStore(Type *DataType, unsigned Alignment) = 0;
|
||||
virtual bool isLegalNTLoad(Type *DataType, unsigned Alignment) = 0;
|
||||
virtual bool isLegalMaskedStore(Type *DataType, MaybeAlign Alignment) = 0;
|
||||
virtual bool isLegalMaskedLoad(Type *DataType, MaybeAlign Alignment) = 0;
|
||||
virtual bool isLegalNTStore(Type *DataType, Align Alignment) = 0;
|
||||
virtual bool isLegalNTLoad(Type *DataType, Align Alignment) = 0;
|
||||
virtual bool isLegalMaskedScatter(Type *DataType) = 0;
|
||||
virtual bool isLegalMaskedGather(Type *DataType) = 0;
|
||||
virtual bool isLegalMaskedCompressStore(Type *DataType) = 0;
|
||||
@ -1196,8 +1228,6 @@ class TargetTransformInfo::Concept {
|
||||
virtual bool isProfitableToHoist(Instruction *I) = 0;
|
||||
virtual bool useAA() = 0;
|
||||
virtual bool isTypeLegal(Type *Ty) = 0;
|
||||
virtual unsigned getJumpBufAlignment() = 0;
|
||||
virtual unsigned getJumpBufSize() = 0;
|
||||
virtual bool shouldBuildLookupTables() = 0;
|
||||
virtual bool shouldBuildLookupTablesForConstant(Constant *C) = 0;
|
||||
virtual bool useColdCCForColdCall(Function &F) = 0;
|
||||
@ -1228,19 +1258,35 @@ class TargetTransformInfo::Concept {
|
||||
Type *Ty) = 0;
|
||||
virtual int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
|
||||
Type *Ty) = 0;
|
||||
virtual unsigned getNumberOfRegisters(bool Vector) = 0;
|
||||
virtual unsigned getNumberOfRegisters(unsigned ClassID) const = 0;
|
||||
virtual unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const = 0;
|
||||
virtual const char* getRegisterClassName(unsigned ClassID) const = 0;
|
||||
virtual unsigned getRegisterBitWidth(bool Vector) const = 0;
|
||||
virtual unsigned getMinVectorRegisterBitWidth() = 0;
|
||||
virtual bool shouldMaximizeVectorBandwidth(bool OptSize) const = 0;
|
||||
virtual unsigned getMinimumVF(unsigned ElemWidth) const = 0;
|
||||
virtual bool shouldConsiderAddressTypePromotion(
|
||||
const Instruction &I, bool &AllowPromotionWithoutCommonHeader) = 0;
|
||||
virtual unsigned getCacheLineSize() = 0;
|
||||
virtual llvm::Optional<unsigned> getCacheSize(CacheLevel Level) = 0;
|
||||
virtual llvm::Optional<unsigned> getCacheAssociativity(CacheLevel Level) = 0;
|
||||
virtual unsigned getPrefetchDistance() = 0;
|
||||
virtual unsigned getMinPrefetchStride() = 0;
|
||||
virtual unsigned getMaxPrefetchIterationsAhead() = 0;
|
||||
virtual unsigned getCacheLineSize() const = 0;
|
||||
virtual llvm::Optional<unsigned> getCacheSize(CacheLevel Level) const = 0;
|
||||
virtual llvm::Optional<unsigned> getCacheAssociativity(CacheLevel Level) const = 0;
|
||||
|
||||
/// \return How much before a load we should place the prefetch
|
||||
/// instruction. This is currently measured in number of
|
||||
/// instructions.
|
||||
virtual unsigned getPrefetchDistance() const = 0;
|
||||
|
||||
/// \return Some HW prefetchers can handle accesses up to a certain
|
||||
/// constant stride. This is the minimum stride in bytes where it
|
||||
/// makes sense to start adding SW prefetches. The default is 1,
|
||||
/// i.e. prefetch with any stride.
|
||||
virtual unsigned getMinPrefetchStride() const = 0;
|
||||
|
||||
/// \return The maximum number of iterations to prefetch ahead. If
|
||||
/// the required number of iterations is more than this number, no
|
||||
/// prefetching is performed.
|
||||
virtual unsigned getMaxPrefetchIterationsAhead() const = 0;
|
||||
|
||||
virtual unsigned getMaxInterleaveFactor(unsigned VF) = 0;
|
||||
virtual unsigned
|
||||
getArithmeticInstrCost(unsigned Opcode, Type *Ty, OperandValueKind Opd1Info,
|
||||
@ -1395,6 +1441,16 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
return Impl.getFlatAddressSpace();
|
||||
}
|
||||
|
||||
bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
|
||||
Intrinsic::ID IID) const override {
|
||||
return Impl.collectFlatAddressOperands(OpIndexes, IID);
|
||||
}
|
||||
|
||||
bool rewriteIntrinsicWithAddressSpace(
|
||||
IntrinsicInst *II, Value *OldV, Value *NewV) const override {
|
||||
return Impl.rewriteIntrinsicWithAddressSpace(II, OldV, NewV);
|
||||
}
|
||||
|
||||
bool isLoweredToCall(const Function *F) override {
|
||||
return Impl.isLoweredToCall(F);
|
||||
}
|
||||
@ -1440,16 +1496,16 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
bool shouldFavorBackedgeIndex(const Loop *L) const override {
|
||||
return Impl.shouldFavorBackedgeIndex(L);
|
||||
}
|
||||
bool isLegalMaskedStore(Type *DataType) override {
|
||||
return Impl.isLegalMaskedStore(DataType);
|
||||
bool isLegalMaskedStore(Type *DataType, MaybeAlign Alignment) override {
|
||||
return Impl.isLegalMaskedStore(DataType, Alignment);
|
||||
}
|
||||
bool isLegalMaskedLoad(Type *DataType) override {
|
||||
return Impl.isLegalMaskedLoad(DataType);
|
||||
bool isLegalMaskedLoad(Type *DataType, MaybeAlign Alignment) override {
|
||||
return Impl.isLegalMaskedLoad(DataType, Alignment);
|
||||
}
|
||||
bool isLegalNTStore(Type *DataType, unsigned Alignment) override {
|
||||
bool isLegalNTStore(Type *DataType, Align Alignment) override {
|
||||
return Impl.isLegalNTStore(DataType, Alignment);
|
||||
}
|
||||
bool isLegalNTLoad(Type *DataType, unsigned Alignment) override {
|
||||
bool isLegalNTLoad(Type *DataType, Align Alignment) override {
|
||||
return Impl.isLegalNTLoad(DataType, Alignment);
|
||||
}
|
||||
bool isLegalMaskedScatter(Type *DataType) override {
|
||||
@ -1490,8 +1546,6 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
}
|
||||
bool useAA() override { return Impl.useAA(); }
|
||||
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();
|
||||
}
|
||||
@ -1563,8 +1617,14 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
Type *Ty) override {
|
||||
return Impl.getIntImmCost(IID, Idx, Imm, Ty);
|
||||
}
|
||||
unsigned getNumberOfRegisters(bool Vector) override {
|
||||
return Impl.getNumberOfRegisters(Vector);
|
||||
unsigned getNumberOfRegisters(unsigned ClassID) const override {
|
||||
return Impl.getNumberOfRegisters(ClassID);
|
||||
}
|
||||
unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const override {
|
||||
return Impl.getRegisterClassForType(Vector, Ty);
|
||||
}
|
||||
const char* getRegisterClassName(unsigned ClassID) const override {
|
||||
return Impl.getRegisterClassName(ClassID);
|
||||
}
|
||||
unsigned getRegisterBitWidth(bool Vector) const override {
|
||||
return Impl.getRegisterBitWidth(Vector);
|
||||
@ -1583,22 +1643,36 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
return Impl.shouldConsiderAddressTypePromotion(
|
||||
I, AllowPromotionWithoutCommonHeader);
|
||||
}
|
||||
unsigned getCacheLineSize() override {
|
||||
unsigned getCacheLineSize() const override {
|
||||
return Impl.getCacheLineSize();
|
||||
}
|
||||
llvm::Optional<unsigned> getCacheSize(CacheLevel Level) override {
|
||||
llvm::Optional<unsigned> getCacheSize(CacheLevel Level) const override {
|
||||
return Impl.getCacheSize(Level);
|
||||
}
|
||||
llvm::Optional<unsigned> getCacheAssociativity(CacheLevel Level) override {
|
||||
llvm::Optional<unsigned> getCacheAssociativity(CacheLevel Level) const override {
|
||||
return Impl.getCacheAssociativity(Level);
|
||||
}
|
||||
unsigned getPrefetchDistance() override { return Impl.getPrefetchDistance(); }
|
||||
unsigned getMinPrefetchStride() override {
|
||||
|
||||
/// Return the preferred prefetch distance in terms of instructions.
|
||||
///
|
||||
unsigned getPrefetchDistance() const override {
|
||||
return Impl.getPrefetchDistance();
|
||||
}
|
||||
|
||||
/// Return the minimum stride necessary to trigger software
|
||||
/// prefetching.
|
||||
///
|
||||
unsigned getMinPrefetchStride() const override {
|
||||
return Impl.getMinPrefetchStride();
|
||||
}
|
||||
unsigned getMaxPrefetchIterationsAhead() override {
|
||||
|
||||
/// Return the maximum prefetch distance in terms of loop
|
||||
/// iterations.
|
||||
///
|
||||
unsigned getMaxPrefetchIterationsAhead() const override {
|
||||
return Impl.getMaxPrefetchIterationsAhead();
|
||||
}
|
||||
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) override {
|
||||
return Impl.getMaxInterleaveFactor(VF);
|
||||
}
|
||||
|
@ -156,6 +156,16 @@ class TargetTransformInfoImplBase {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
|
||||
Intrinsic::ID IID) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
|
||||
Value *OldV, Value *NewV) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isLoweredToCall(const Function *F) {
|
||||
assert(F && "A concrete function must be provided to this routine.");
|
||||
|
||||
@ -233,18 +243,18 @@ class TargetTransformInfoImplBase {
|
||||
|
||||
bool shouldFavorBackedgeIndex(const Loop *L) const { return false; }
|
||||
|
||||
bool isLegalMaskedStore(Type *DataType) { return false; }
|
||||
bool isLegalMaskedStore(Type *DataType, MaybeAlign Alignment) { return false; }
|
||||
|
||||
bool isLegalMaskedLoad(Type *DataType) { return false; }
|
||||
bool isLegalMaskedLoad(Type *DataType, MaybeAlign Alignment) { return false; }
|
||||
|
||||
bool isLegalNTStore(Type *DataType, unsigned Alignment) {
|
||||
bool isLegalNTStore(Type *DataType, Align Alignment) {
|
||||
// By default, assume nontemporal memory stores are available for stores
|
||||
// that are aligned and have a size that is a power of 2.
|
||||
unsigned DataSize = DL.getTypeStoreSize(DataType);
|
||||
return Alignment >= DataSize && isPowerOf2_32(DataSize);
|
||||
}
|
||||
|
||||
bool isLegalNTLoad(Type *DataType, unsigned Alignment) {
|
||||
bool isLegalNTLoad(Type *DataType, Align Alignment) {
|
||||
// By default, assume nontemporal memory loads are available for loads that
|
||||
// are aligned and have a size that is a power of 2.
|
||||
unsigned DataSize = DL.getTypeStoreSize(DataType);
|
||||
@ -284,10 +294,6 @@ class TargetTransformInfoImplBase {
|
||||
|
||||
bool isTypeLegal(Type *Ty) { return false; }
|
||||
|
||||
unsigned getJumpBufAlignment() { return 0; }
|
||||
|
||||
unsigned getJumpBufSize() { return 0; }
|
||||
|
||||
bool shouldBuildLookupTables() { return true; }
|
||||
bool shouldBuildLookupTablesForConstant(Constant *C) { return true; }
|
||||
|
||||
@ -348,7 +354,20 @@ class TargetTransformInfoImplBase {
|
||||
return TTI::TCC_Free;
|
||||
}
|
||||
|
||||
unsigned getNumberOfRegisters(bool Vector) { return 8; }
|
||||
unsigned getNumberOfRegisters(unsigned ClassID) const { return 8; }
|
||||
|
||||
unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const {
|
||||
return Vector ? 1 : 0;
|
||||
};
|
||||
|
||||
const char* getRegisterClassName(unsigned ClassID) const {
|
||||
switch (ClassID) {
|
||||
default:
|
||||
return "Generic::Unknown Register Class";
|
||||
case 0: return "Generic::ScalarRC";
|
||||
case 1: return "Generic::VectorRC";
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) const { return 32; }
|
||||
|
||||
@ -365,21 +384,20 @@ class TargetTransformInfoImplBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned getCacheLineSize() { return 0; }
|
||||
unsigned getCacheLineSize() const { return 0; }
|
||||
|
||||
llvm::Optional<unsigned> getCacheSize(TargetTransformInfo::CacheLevel Level) {
|
||||
llvm::Optional<unsigned> getCacheSize(TargetTransformInfo::CacheLevel Level) const {
|
||||
switch (Level) {
|
||||
case TargetTransformInfo::CacheLevel::L1D:
|
||||
LLVM_FALLTHROUGH;
|
||||
case TargetTransformInfo::CacheLevel::L2D:
|
||||
return llvm::Optional<unsigned>();
|
||||
}
|
||||
|
||||
llvm_unreachable("Unknown TargetTransformInfo::CacheLevel");
|
||||
}
|
||||
|
||||
llvm::Optional<unsigned> getCacheAssociativity(
|
||||
TargetTransformInfo::CacheLevel Level) {
|
||||
TargetTransformInfo::CacheLevel Level) const {
|
||||
switch (Level) {
|
||||
case TargetTransformInfo::CacheLevel::L1D:
|
||||
LLVM_FALLTHROUGH;
|
||||
@ -390,11 +408,9 @@ class TargetTransformInfoImplBase {
|
||||
llvm_unreachable("Unknown TargetTransformInfo::CacheLevel");
|
||||
}
|
||||
|
||||
unsigned getPrefetchDistance() { return 0; }
|
||||
|
||||
unsigned getMinPrefetchStride() { return 1; }
|
||||
|
||||
unsigned getMaxPrefetchIterationsAhead() { return UINT_MAX; }
|
||||
unsigned getPrefetchDistance() const { return 0; }
|
||||
unsigned getMinPrefetchStride() const { return 1; }
|
||||
unsigned getMaxPrefetchIterationsAhead() const { return UINT_MAX; }
|
||||
|
||||
unsigned getMaxInterleaveFactor(unsigned VF) { return 1; }
|
||||
|
||||
@ -830,6 +846,9 @@ class TargetTransformInfoImplCRTPBase : public TargetTransformInfoImplBase {
|
||||
if (isa<PHINode>(U))
|
||||
return TTI::TCC_Free; // Model all PHI nodes as free.
|
||||
|
||||
if (isa<ExtractValueInst>(U))
|
||||
return TTI::TCC_Free; // Model all ExtractValue nodes as free.
|
||||
|
||||
// Static alloca doesn't generate target instructions.
|
||||
if (auto *A = dyn_cast<AllocaInst>(U))
|
||||
if (A->isStaticAlloca())
|
||||
|
@ -50,6 +50,8 @@ void findDevirtualizableCallsForTypeCheckedLoad(
|
||||
SmallVectorImpl<Instruction *> &LoadedPtrs,
|
||||
SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses,
|
||||
const CallInst *CI, DominatorTree &DT);
|
||||
|
||||
Constant *getPointerAtOffset(Constant *I, uint64_t Offset, Module &M);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -32,7 +32,7 @@ Value *EmitGEPOffset(IRBuilderTy *Builder, const DataLayout &DL, User *GEP,
|
||||
Value *Result = Constant::getNullValue(IntPtrTy);
|
||||
|
||||
// If the GEP is inbounds, we know that none of the addressing operations will
|
||||
// overflow in an unsigned sense.
|
||||
// overflow in a signed sense.
|
||||
bool isInBounds = GEPOp->isInBounds() && !NoAssumptions;
|
||||
|
||||
// Build a mask for high order bits.
|
||||
@ -51,10 +51,7 @@ Value *EmitGEPOffset(IRBuilderTy *Builder, const DataLayout &DL, User *GEP,
|
||||
|
||||
// Handle a struct index, which adds its field offset to the pointer.
|
||||
if (StructType *STy = GTI.getStructTypeOrNull()) {
|
||||
if (OpC->getType()->isVectorTy())
|
||||
OpC = OpC->getSplatValue();
|
||||
|
||||
uint64_t OpValue = cast<ConstantInt>(OpC)->getZExtValue();
|
||||
uint64_t OpValue = OpC->getUniqueInteger().getZExtValue();
|
||||
Size = DL.getStructLayout(STy)->getElementOffset(OpValue);
|
||||
|
||||
if (Size)
|
||||
@ -63,20 +60,31 @@ Value *EmitGEPOffset(IRBuilderTy *Builder, const DataLayout &DL, User *GEP,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Splat the constant if needed.
|
||||
if (IntPtrTy->isVectorTy() && !OpC->getType()->isVectorTy())
|
||||
OpC = ConstantVector::getSplat(IntPtrTy->getVectorNumElements(), OpC);
|
||||
|
||||
Constant *Scale = ConstantInt::get(IntPtrTy, Size);
|
||||
Constant *OC = ConstantExpr::getIntegerCast(OpC, IntPtrTy, true /*SExt*/);
|
||||
Scale = ConstantExpr::getMul(OC, Scale, isInBounds/*NUW*/);
|
||||
Scale =
|
||||
ConstantExpr::getMul(OC, Scale, false /*NUW*/, isInBounds /*NSW*/);
|
||||
// Emit an add instruction.
|
||||
Result = Builder->CreateAdd(Result, Scale, GEP->getName()+".offs");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Splat the index if needed.
|
||||
if (IntPtrTy->isVectorTy() && !Op->getType()->isVectorTy())
|
||||
Op = Builder->CreateVectorSplat(IntPtrTy->getVectorNumElements(), Op);
|
||||
|
||||
// Convert to correct type.
|
||||
if (Op->getType() != IntPtrTy)
|
||||
Op = Builder->CreateIntCast(Op, IntPtrTy, true, Op->getName()+".c");
|
||||
if (Size != 1) {
|
||||
// We'll let instcombine(mul) convert this to a shl if possible.
|
||||
Op = Builder->CreateMul(Op, ConstantInt::get(IntPtrTy, Size),
|
||||
GEP->getName()+".idx", isInBounds /*NUW*/);
|
||||
GEP->getName() + ".idx", false /*NUW*/,
|
||||
isInBounds /*NSW*/);
|
||||
}
|
||||
|
||||
// Emit an add instruction.
|
||||
|
@ -242,19 +242,21 @@ class Value;
|
||||
/// This is a wrapper around Value::stripAndAccumulateConstantOffsets that
|
||||
/// creates and later unpacks the required APInt.
|
||||
inline Value *GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset,
|
||||
const DataLayout &DL) {
|
||||
const DataLayout &DL,
|
||||
bool AllowNonInbounds = true) {
|
||||
APInt OffsetAPInt(DL.getIndexTypeSizeInBits(Ptr->getType()), 0);
|
||||
Value *Base =
|
||||
Ptr->stripAndAccumulateConstantOffsets(DL, OffsetAPInt,
|
||||
/* AllowNonInbounds */ true);
|
||||
Ptr->stripAndAccumulateConstantOffsets(DL, OffsetAPInt, AllowNonInbounds);
|
||||
|
||||
Offset = OffsetAPInt.getSExtValue();
|
||||
return Base;
|
||||
}
|
||||
inline const Value *GetPointerBaseWithConstantOffset(const Value *Ptr,
|
||||
int64_t &Offset,
|
||||
const DataLayout &DL) {
|
||||
return GetPointerBaseWithConstantOffset(const_cast<Value *>(Ptr), Offset,
|
||||
DL);
|
||||
inline const Value *
|
||||
GetPointerBaseWithConstantOffset(const Value *Ptr, int64_t &Offset,
|
||||
const DataLayout &DL,
|
||||
bool AllowNonInbounds = true) {
|
||||
return GetPointerBaseWithConstantOffset(const_cast<Value *>(Ptr), Offset, DL,
|
||||
AllowNonInbounds);
|
||||
}
|
||||
|
||||
/// Returns true if the GEP is based on a pointer to a string (array of
|
||||
@ -307,20 +309,26 @@ class Value;
|
||||
uint64_t GetStringLength(const Value *V, unsigned CharSize = 8);
|
||||
|
||||
/// This function returns call pointer argument that is considered the same by
|
||||
/// aliasing rules. You CAN'T use it to replace one value with another.
|
||||
const Value *getArgumentAliasingToReturnedPointer(const CallBase *Call);
|
||||
inline Value *getArgumentAliasingToReturnedPointer(CallBase *Call) {
|
||||
/// aliasing rules. You CAN'T use it to replace one value with another. If
|
||||
/// \p MustPreserveNullness is true, the call must preserve the nullness of
|
||||
/// the pointer.
|
||||
const Value *getArgumentAliasingToReturnedPointer(const CallBase *Call,
|
||||
bool MustPreserveNullness);
|
||||
inline Value *
|
||||
getArgumentAliasingToReturnedPointer(CallBase *Call,
|
||||
bool MustPreserveNullness) {
|
||||
return const_cast<Value *>(getArgumentAliasingToReturnedPointer(
|
||||
const_cast<const CallBase *>(Call)));
|
||||
const_cast<const CallBase *>(Call), MustPreserveNullness));
|
||||
}
|
||||
|
||||
// {launder,strip}.invariant.group returns pointer that aliases its argument,
|
||||
// and it only captures pointer by returning it.
|
||||
// These intrinsics are not marked as nocapture, because returning is
|
||||
// considered as capture. The arguments are not marked as returned neither,
|
||||
// because it would make it useless.
|
||||
/// {launder,strip}.invariant.group returns pointer that aliases its argument,
|
||||
/// and it only captures pointer by returning it.
|
||||
/// These intrinsics are not marked as nocapture, because returning is
|
||||
/// considered as capture. The arguments are not marked as returned neither,
|
||||
/// because it would make it useless. If \p MustPreserveNullness is true,
|
||||
/// the intrinsic must preserve the nullness of the pointer.
|
||||
bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
|
||||
const CallBase *Call);
|
||||
const CallBase *Call, bool MustPreserveNullness);
|
||||
|
||||
/// This method strips off any GEP address adjustments and pointer casts from
|
||||
/// the specified value, returning the original object being addressed. Note
|
||||
@ -376,6 +384,13 @@ class Value;
|
||||
/// Return true if the only users of this pointer are lifetime markers.
|
||||
bool onlyUsedByLifetimeMarkers(const Value *V);
|
||||
|
||||
/// Return true if speculation of the given load must be suppressed to avoid
|
||||
/// ordering or interfering with an active sanitizer. If not suppressed,
|
||||
/// dereferenceability and alignment must be proven separately. Note: This
|
||||
/// is only needed for raw reasoning; if you use the interface below
|
||||
/// (isSafeToSpeculativelyExecute), this is handled internally.
|
||||
bool mustSuppressSpeculation(const LoadInst &LI);
|
||||
|
||||
/// Return true if the instruction does not have any effects besides
|
||||
/// calculating the result and does not have undefined behavior.
|
||||
///
|
||||
@ -605,12 +620,12 @@ class Value;
|
||||
SelectPatternResult matchSelectPattern(Value *V, Value *&LHS, Value *&RHS,
|
||||
Instruction::CastOps *CastOp = nullptr,
|
||||
unsigned Depth = 0);
|
||||
|
||||
inline SelectPatternResult
|
||||
matchSelectPattern(const Value *V, const Value *&LHS, const Value *&RHS,
|
||||
Instruction::CastOps *CastOp = nullptr) {
|
||||
Value *L = const_cast<Value*>(LHS);
|
||||
Value *R = const_cast<Value*>(RHS);
|
||||
auto Result = matchSelectPattern(const_cast<Value*>(V), L, R);
|
||||
matchSelectPattern(const Value *V, const Value *&LHS, const Value *&RHS) {
|
||||
Value *L = const_cast<Value *>(LHS);
|
||||
Value *R = const_cast<Value *>(RHS);
|
||||
auto Result = matchSelectPattern(const_cast<Value *>(V), L, R);
|
||||
LHS = L;
|
||||
RHS = R;
|
||||
return Result;
|
||||
@ -654,6 +669,12 @@ class Value;
|
||||
Optional<bool> isImpliedByDomCondition(const Value *Cond,
|
||||
const Instruction *ContextI,
|
||||
const DataLayout &DL);
|
||||
|
||||
/// If Ptr1 is provably equal to Ptr2 plus a constant offset, return that
|
||||
/// offset. For example, Ptr1 might be &A[42], and Ptr2 might be &A[40]. In
|
||||
/// this case offset would be -8.
|
||||
Optional<int64_t> isPointerOffset(const Value *Ptr1, const Value *Ptr2,
|
||||
const DataLayout &DL);
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_VALUETRACKING_H
|
||||
|
@ -15,18 +15,129 @@
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/Analysis/LoopAccessAnalysis.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Support/CheckedArithmetic.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Describes the type of Parameters
|
||||
enum class VFParamKind {
|
||||
Vector, // No semantic information.
|
||||
OMP_Linear, // declare simd linear(i)
|
||||
OMP_LinearRef, // declare simd linear(ref(i))
|
||||
OMP_LinearVal, // declare simd linear(val(i))
|
||||
OMP_LinearUVal, // declare simd linear(uval(i))
|
||||
OMP_LinearPos, // declare simd linear(i:c) uniform(c)
|
||||
OMP_LinearValPos, // declare simd linear(val(i:c)) uniform(c)
|
||||
OMP_LinearRefPos, // declare simd linear(ref(i:c)) uniform(c)
|
||||
OMP_LinearUValPos, // declare simd linear(uval(i:c)) uniform(c
|
||||
OMP_Uniform, // declare simd uniform(i)
|
||||
GlobalPredicate, // Global logical predicate that acts on all lanes
|
||||
// of the input and output mask concurrently. For
|
||||
// example, it is implied by the `M` token in the
|
||||
// Vector Function ABI mangled name.
|
||||
Unknown
|
||||
};
|
||||
|
||||
/// Describes the type of Instruction Set Architecture
|
||||
enum class VFISAKind {
|
||||
AdvancedSIMD, // AArch64 Advanced SIMD (NEON)
|
||||
SVE, // AArch64 Scalable Vector Extension
|
||||
SSE, // x86 SSE
|
||||
AVX, // x86 AVX
|
||||
AVX2, // x86 AVX2
|
||||
AVX512, // x86 AVX512
|
||||
Unknown // Unknown ISA
|
||||
};
|
||||
|
||||
/// Encapsulates information needed to describe a parameter.
|
||||
///
|
||||
/// The description of the parameter is not linked directly to
|
||||
/// OpenMP or any other vector function description. This structure
|
||||
/// is extendible to handle other paradigms that describe vector
|
||||
/// functions and their parameters.
|
||||
struct VFParameter {
|
||||
unsigned ParamPos; // Parameter Position in Scalar Function.
|
||||
VFParamKind ParamKind; // Kind of Parameter.
|
||||
int LinearStepOrPos = 0; // Step or Position of the Parameter.
|
||||
Align Alignment = Align(); // Optional aligment in bytes, defaulted to 1.
|
||||
|
||||
// Comparison operator.
|
||||
bool operator==(const VFParameter &Other) const {
|
||||
return std::tie(ParamPos, ParamKind, LinearStepOrPos, Alignment) ==
|
||||
std::tie(Other.ParamPos, Other.ParamKind, Other.LinearStepOrPos,
|
||||
Other.Alignment);
|
||||
}
|
||||
};
|
||||
|
||||
/// Contains the information about the kind of vectorization
|
||||
/// available.
|
||||
///
|
||||
/// This object in independent on the paradigm used to
|
||||
/// represent vector functions. in particular, it is not attached to
|
||||
/// any target-specific ABI.
|
||||
struct VFShape {
|
||||
unsigned VF; // Vectorization factor.
|
||||
bool IsScalable; // True if the function is a scalable function.
|
||||
VFISAKind ISA; // Instruction Set Architecture.
|
||||
SmallVector<VFParameter, 8> Parameters; // List of parameter informations.
|
||||
// Comparison operator.
|
||||
bool operator==(const VFShape &Other) const {
|
||||
return std::tie(VF, IsScalable, ISA, Parameters) ==
|
||||
std::tie(Other.VF, Other.IsScalable, Other.ISA, Other.Parameters);
|
||||
}
|
||||
};
|
||||
|
||||
/// Holds the VFShape for a specific scalar to vector function mapping.
|
||||
struct VFInfo {
|
||||
VFShape Shape; // Classification of the vector function.
|
||||
StringRef ScalarName; // Scalar Function Name.
|
||||
StringRef VectorName; // Vector Function Name associated to this VFInfo.
|
||||
|
||||
// Comparison operator.
|
||||
bool operator==(const VFInfo &Other) const {
|
||||
return std::tie(Shape, ScalarName, VectorName) ==
|
||||
std::tie(Shape, Other.ScalarName, Other.VectorName);
|
||||
}
|
||||
};
|
||||
|
||||
namespace VFABI {
|
||||
/// Function to contruct a VFInfo out of a mangled names in the
|
||||
/// following format:
|
||||
///
|
||||
/// <VFABI_name>{(<redirection>)}
|
||||
///
|
||||
/// where <VFABI_name> is the name of the vector function, mangled according
|
||||
/// to the rules described in the Vector Function ABI of the target vector
|
||||
/// extentsion (or <isa> from now on). The <VFABI_name> is in the following
|
||||
/// format:
|
||||
///
|
||||
/// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)]
|
||||
///
|
||||
/// This methods support demangling rules for the following <isa>:
|
||||
///
|
||||
/// * AArch64: https://developer.arm.com/docs/101129/latest
|
||||
///
|
||||
/// * x86 (libmvec): https://sourceware.org/glibc/wiki/libmvec and
|
||||
/// https://sourceware.org/glibc/wiki/libmvec?action=AttachFile&do=view&target=VectorABI.txt
|
||||
///
|
||||
///
|
||||
///
|
||||
/// \param MangledName -> input string in the format
|
||||
/// _ZGV<isa><mask><vlen><parameters>_<scalarname>[(<redirection>)].
|
||||
Optional<VFInfo> tryDemangleForVFABI(StringRef MangledName);
|
||||
|
||||
/// Retrieve the `VFParamKind` from a string token.
|
||||
VFParamKind getVFParamKindFromString(const StringRef Token);
|
||||
} // end namespace VFABI
|
||||
|
||||
template <typename T> class ArrayRef;
|
||||
class DemandedBits;
|
||||
class GetElementPtrInst;
|
||||
template <typename InstTy> class InterleaveGroup;
|
||||
class Loop;
|
||||
class ScalarEvolution;
|
||||
class TargetLibraryInfo;
|
||||
class TargetTransformInfo;
|
||||
class Type;
|
||||
class Value;
|
||||
@ -270,13 +381,12 @@ APInt possiblyDemandedEltsInMask(Value *Mask);
|
||||
/// the interleaved store group doesn't allow gaps.
|
||||
template <typename InstTy> class InterleaveGroup {
|
||||
public:
|
||||
InterleaveGroup(uint32_t Factor, bool Reverse, uint32_t Align)
|
||||
: Factor(Factor), Reverse(Reverse), Align(Align), InsertPos(nullptr) {}
|
||||
|
||||
InterleaveGroup(InstTy *Instr, int32_t Stride, uint32_t Align)
|
||||
: Align(Align), InsertPos(Instr) {
|
||||
assert(Align && "The alignment should be non-zero");
|
||||
InterleaveGroup(uint32_t Factor, bool Reverse, Align Alignment)
|
||||
: Factor(Factor), Reverse(Reverse), Alignment(Alignment),
|
||||
InsertPos(nullptr) {}
|
||||
|
||||
InterleaveGroup(InstTy *Instr, int32_t Stride, Align Alignment)
|
||||
: Alignment(Alignment), InsertPos(Instr) {
|
||||
Factor = std::abs(Stride);
|
||||
assert(Factor > 1 && "Invalid interleave factor");
|
||||
|
||||
@ -286,7 +396,7 @@ template <typename InstTy> class InterleaveGroup {
|
||||
|
||||
bool isReverse() const { return Reverse; }
|
||||
uint32_t getFactor() const { return Factor; }
|
||||
uint32_t getAlignment() const { return Align; }
|
||||
uint32_t getAlignment() const { return Alignment.value(); }
|
||||
uint32_t getNumMembers() const { return Members.size(); }
|
||||
|
||||
/// Try to insert a new member \p Instr with index \p Index and
|
||||
@ -294,9 +404,7 @@ template <typename InstTy> class InterleaveGroup {
|
||||
/// negative if it is the new leader.
|
||||
///
|
||||
/// \returns false if the instruction doesn't belong to the group.
|
||||
bool insertMember(InstTy *Instr, int32_t Index, uint32_t NewAlign) {
|
||||
assert(NewAlign && "The new member's alignment should be non-zero");
|
||||
|
||||
bool insertMember(InstTy *Instr, int32_t Index, Align NewAlign) {
|
||||
// Make sure the key fits in an int32_t.
|
||||
Optional<int32_t> MaybeKey = checkedAdd(Index, SmallestKey);
|
||||
if (!MaybeKey)
|
||||
@ -328,7 +436,7 @@ template <typename InstTy> class InterleaveGroup {
|
||||
}
|
||||
|
||||
// It's always safe to select the minimum alignment.
|
||||
Align = std::min(Align, NewAlign);
|
||||
Alignment = std::min(Alignment, NewAlign);
|
||||
Members[Key] = Instr;
|
||||
return true;
|
||||
}
|
||||
@ -387,7 +495,7 @@ template <typename InstTy> class InterleaveGroup {
|
||||
private:
|
||||
uint32_t Factor; // Interleave Factor.
|
||||
bool Reverse;
|
||||
uint32_t Align;
|
||||
Align Alignment;
|
||||
DenseMap<int32_t, InstTy *> Members;
|
||||
int32_t SmallestKey = 0;
|
||||
int32_t LargestKey = 0;
|
||||
@ -504,8 +612,8 @@ class InterleavedAccessInfo {
|
||||
struct StrideDescriptor {
|
||||
StrideDescriptor() = default;
|
||||
StrideDescriptor(int64_t Stride, const SCEV *Scev, uint64_t Size,
|
||||
unsigned Align)
|
||||
: Stride(Stride), Scev(Scev), Size(Size), Align(Align) {}
|
||||
Align Alignment)
|
||||
: Stride(Stride), Scev(Scev), Size(Size), Alignment(Alignment) {}
|
||||
|
||||
// The access's stride. It is negative for a reverse access.
|
||||
int64_t Stride = 0;
|
||||
@ -517,7 +625,7 @@ class InterleavedAccessInfo {
|
||||
uint64_t Size = 0;
|
||||
|
||||
// The alignment of this access.
|
||||
unsigned Align = 0;
|
||||
Align Alignment;
|
||||
};
|
||||
|
||||
/// A type for holding instructions and their stride descriptors.
|
||||
@ -528,11 +636,11 @@ class InterleavedAccessInfo {
|
||||
///
|
||||
/// \returns the newly created interleave group.
|
||||
InterleaveGroup<Instruction> *
|
||||
createInterleaveGroup(Instruction *Instr, int Stride, unsigned Align) {
|
||||
createInterleaveGroup(Instruction *Instr, int Stride, Align Alignment) {
|
||||
assert(!InterleaveGroupMap.count(Instr) &&
|
||||
"Already in an interleaved access group");
|
||||
InterleaveGroupMap[Instr] =
|
||||
new InterleaveGroup<Instruction>(Instr, Stride, Align);
|
||||
new InterleaveGroup<Instruction>(Instr, Stride, Alignment);
|
||||
InterleaveGroups.insert(InterleaveGroupMap[Instr]);
|
||||
return InterleaveGroupMap[Instr];
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \
|
||||
defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE || \
|
||||
defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO || \
|
||||
defined HANDLE_DW_RLE || \
|
||||
defined HANDLE_DW_RLE || defined HANDLE_DW_LLE || \
|
||||
(defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \
|
||||
defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \
|
||||
defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX || \
|
||||
@ -26,7 +26,17 @@
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_TAG
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR)
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND)
|
||||
#endif
|
||||
|
||||
// Note that DW_KIND is not a DWARF concept, but rather a way for us to
|
||||
// generate a list of tags that belong together.
|
||||
#ifndef DW_KIND_NONE
|
||||
#define DW_KIND_NONE 0
|
||||
#endif
|
||||
|
||||
#ifndef DW_KIND_TYPE
|
||||
#define DW_KIND_TYPE 1
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_AT
|
||||
@ -81,6 +91,10 @@
|
||||
#define HANDLE_DW_RLE(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_LLE
|
||||
#define HANDLE_DW_LLE(ID, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_DW_CFA
|
||||
#define HANDLE_DW_CFA(ID, NAME)
|
||||
#endif
|
||||
@ -109,94 +123,94 @@
|
||||
#define HANDLE_DW_END(ID, NAME)
|
||||
#endif
|
||||
|
||||
HANDLE_DW_TAG(0x0000, null, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0001, array_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0002, class_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0003, entry_point, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0004, enumeration_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0005, formal_parameter, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0008, imported_declaration, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x000a, label, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x000b, lexical_block, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x000d, member, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x000f, pointer_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0010, reference_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0011, compile_unit, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0012, string_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0013, structure_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0015, subroutine_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0016, typedef, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0017, union_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0018, unspecified_parameters, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0019, variant, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x001a, common_block, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x001b, common_inclusion, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x001c, inheritance, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x001d, inlined_subroutine, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x001e, module, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x001f, ptr_to_member_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0020, set_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0021, subrange_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0022, with_stmt, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0023, access_declaration, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0024, base_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0025, catch_block, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0026, const_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0027, constant, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0028, enumerator, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0029, file_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x002a, friend, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x002b, namelist, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x002c, namelist_item, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x002d, packed_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x002e, subprogram, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x002f, template_type_parameter, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0030, template_value_parameter, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0031, thrown_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0032, try_block, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0033, variant_part, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0034, variable, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0035, volatile_type, 2, DWARF)
|
||||
HANDLE_DW_TAG(0x0000, null, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0001, array_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0002, class_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0003, entry_point, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0004, enumeration_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0005, formal_parameter, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0008, imported_declaration, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x000a, label, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x000b, lexical_block, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x000d, member, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x000f, pointer_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0010, reference_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0011, compile_unit, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0012, string_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0013, structure_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0015, subroutine_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0016, typedef, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0017, union_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0018, unspecified_parameters, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0019, variant, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x001a, common_block, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x001b, common_inclusion, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x001c, inheritance, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x001d, inlined_subroutine, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x001e, module, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x001f, ptr_to_member_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0020, set_type, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0021, subrange_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0022, with_stmt, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0023, access_declaration, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0024, base_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0025, catch_block, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0026, const_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0027, constant, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0028, enumerator, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0029, file_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x002a, friend, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x002b, namelist, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x002c, namelist_item, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x002d, packed_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x002e, subprogram, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x002f, template_type_parameter, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0030, template_value_parameter, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0031, thrown_type, 2, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0032, try_block, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0033, variant_part, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0034, variable, 2, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0035, volatile_type, 2, DWARF, DW_KIND_TYPE)
|
||||
// New in DWARF v3:
|
||||
HANDLE_DW_TAG(0x0036, dwarf_procedure, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x0037, restrict_type, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x0038, interface_type, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x0039, namespace, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x003a, imported_module, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x003b, unspecified_type, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x003c, partial_unit, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x003d, imported_unit, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x003f, condition, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x0040, shared_type, 3, DWARF)
|
||||
HANDLE_DW_TAG(0x0036, dwarf_procedure, 3, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0037, restrict_type, 3, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0038, interface_type, 3, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0039, namespace, 3, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x003a, imported_module, 3, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x003b, unspecified_type, 3, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x003c, partial_unit, 3, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x003d, imported_unit, 3, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x003f, condition, 3, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0040, shared_type, 3, DWARF, DW_KIND_TYPE)
|
||||
// New in DWARF v4:
|
||||
HANDLE_DW_TAG(0x0041, type_unit, 4, DWARF)
|
||||
HANDLE_DW_TAG(0x0042, rvalue_reference_type, 4, DWARF)
|
||||
HANDLE_DW_TAG(0x0043, template_alias, 4, DWARF)
|
||||
HANDLE_DW_TAG(0x0041, type_unit, 4, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0042, rvalue_reference_type, 4, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0043, template_alias, 4, DWARF, DW_KIND_NONE)
|
||||
// New in DWARF v5:
|
||||
HANDLE_DW_TAG(0x0044, coarray_type, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x0045, generic_subrange, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x0046, dynamic_type, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x0047, atomic_type, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x0048, call_site, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x0049, call_site_parameter, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x004a, skeleton_unit, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x004b, immutable_type, 5, DWARF)
|
||||
HANDLE_DW_TAG(0x0044, coarray_type, 5, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0045, generic_subrange, 5, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0046, dynamic_type, 5, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0047, atomic_type, 5, DWARF, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0x0048, call_site, 5, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x0049, call_site_parameter, 5, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x004a, skeleton_unit, 5, DWARF, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x004b, immutable_type, 5, DWARF, DW_KIND_TYPE)
|
||||
// Vendor extensions:
|
||||
HANDLE_DW_TAG(0x4081, MIPS_loop, 0, MIPS)
|
||||
HANDLE_DW_TAG(0x4101, format_label, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4102, function_template, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4103, class_template, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4106, GNU_template_template_param, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4107, GNU_template_parameter_pack, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4108, GNU_formal_parameter_pack, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4109, GNU_call_site, 0, GNU)
|
||||
HANDLE_DW_TAG(0x410a, GNU_call_site_parameter, 0, GNU)
|
||||
HANDLE_DW_TAG(0x4200, APPLE_property, 0, APPLE)
|
||||
HANDLE_DW_TAG(0xb000, BORLAND_property, 0, BORLAND)
|
||||
HANDLE_DW_TAG(0xb001, BORLAND_Delphi_string, 0, BORLAND)
|
||||
HANDLE_DW_TAG(0xb002, BORLAND_Delphi_dynamic_array, 0, BORLAND)
|
||||
HANDLE_DW_TAG(0xb003, BORLAND_Delphi_set, 0, BORLAND)
|
||||
HANDLE_DW_TAG(0xb004, BORLAND_Delphi_variant, 0, BORLAND)
|
||||
HANDLE_DW_TAG(0x4081, MIPS_loop, 0, MIPS, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4101, format_label, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4102, function_template, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4103, class_template, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4106, GNU_template_template_param, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4107, GNU_template_parameter_pack, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4108, GNU_formal_parameter_pack, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4109, GNU_call_site, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x410a, GNU_call_site_parameter, 0, GNU, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0x4200, APPLE_property, 0, APPLE, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0xb000, BORLAND_property, 0, BORLAND, DW_KIND_NONE)
|
||||
HANDLE_DW_TAG(0xb001, BORLAND_Delphi_string, 0, BORLAND, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0xb002, BORLAND_Delphi_dynamic_array, 0, BORLAND, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0xb003, BORLAND_Delphi_set, 0, BORLAND, DW_KIND_TYPE)
|
||||
HANDLE_DW_TAG(0xb004, BORLAND_Delphi_variant, 0, BORLAND, DW_KIND_TYPE)
|
||||
|
||||
// Attributes.
|
||||
HANDLE_DW_AT(0x01, sibling, 2, DWARF)
|
||||
@ -815,6 +829,17 @@ HANDLE_DW_RLE(0x05, base_address)
|
||||
HANDLE_DW_RLE(0x06, start_end)
|
||||
HANDLE_DW_RLE(0x07, start_length)
|
||||
|
||||
// DWARF v5 Loc List Entry encoding values.
|
||||
HANDLE_DW_LLE(0x00, end_of_list)
|
||||
HANDLE_DW_LLE(0x01, base_addressx)
|
||||
HANDLE_DW_LLE(0x02, startx_endx)
|
||||
HANDLE_DW_LLE(0x03, startx_length)
|
||||
HANDLE_DW_LLE(0x04, offset_pair)
|
||||
HANDLE_DW_LLE(0x05, default_location)
|
||||
HANDLE_DW_LLE(0x06, base_address)
|
||||
HANDLE_DW_LLE(0x07, start_end)
|
||||
HANDLE_DW_LLE(0x08, start_length)
|
||||
|
||||
// Call frame instruction encodings.
|
||||
HANDLE_DW_CFA(0x00, nop)
|
||||
HANDLE_DW_CFA(0x40, advance_loc)
|
||||
@ -929,6 +954,7 @@ HANDLE_DW_IDX(0x05, type_hash)
|
||||
#undef HANDLE_DW_LNCT
|
||||
#undef HANDLE_DW_MACRO
|
||||
#undef HANDLE_DW_RLE
|
||||
#undef HANDLE_DW_LLE
|
||||
#undef HANDLE_DW_CFA
|
||||
#undef HANDLE_DW_CFA_PRED
|
||||
#undef HANDLE_DW_APPLE_PROPERTY
|
||||
|
@ -46,6 +46,11 @@ enum LLVMConstants : uint32_t {
|
||||
DW_VIRTUALITY_invalid = ~0U, // Virtuality for invalid results.
|
||||
DW_MACINFO_invalid = ~0U, // Macinfo type for invalid results.
|
||||
|
||||
// Special values for an initial length field.
|
||||
DW_LENGTH_lo_reserved = 0xfffffff0, // Lower bound of the reserved range.
|
||||
DW_LENGTH_DWARF64 = 0xffffffff, // Indicator of 64-bit DWARF format.
|
||||
DW_LENGTH_hi_reserved = 0xffffffff, // Upper bound of the reserved range.
|
||||
|
||||
// Other constants.
|
||||
DWARF_VERSION = 4, // Default dwarf version we output.
|
||||
DW_PUBTYPES_VERSION = 2, // Section version number for .debug_pubtypes.
|
||||
@ -75,7 +80,7 @@ const uint64_t DW64_CIE_ID = UINT64_MAX;
|
||||
const uint32_t DW_INVALID_OFFSET = UINT32_MAX;
|
||||
|
||||
enum Tag : uint16_t {
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR) DW_TAG_##NAME = ID,
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND) DW_TAG_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
DW_TAG_lo_user = 0x4080,
|
||||
DW_TAG_hi_user = 0xffff,
|
||||
@ -84,29 +89,12 @@ enum Tag : uint16_t {
|
||||
|
||||
inline bool isType(Tag T) {
|
||||
switch (T) {
|
||||
case DW_TAG_array_type:
|
||||
case DW_TAG_class_type:
|
||||
case DW_TAG_interface_type:
|
||||
case DW_TAG_enumeration_type:
|
||||
case DW_TAG_pointer_type:
|
||||
case DW_TAG_reference_type:
|
||||
case DW_TAG_rvalue_reference_type:
|
||||
case DW_TAG_string_type:
|
||||
case DW_TAG_structure_type:
|
||||
case DW_TAG_subroutine_type:
|
||||
case DW_TAG_union_type:
|
||||
case DW_TAG_ptr_to_member_type:
|
||||
case DW_TAG_set_type:
|
||||
case DW_TAG_subrange_type:
|
||||
case DW_TAG_base_type:
|
||||
case DW_TAG_const_type:
|
||||
case DW_TAG_file_type:
|
||||
case DW_TAG_packed_type:
|
||||
case DW_TAG_volatile_type:
|
||||
case DW_TAG_typedef:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND) \
|
||||
case DW_TAG_##NAME: \
|
||||
return (KIND == DW_KIND_TYPE);
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,9 +117,10 @@ enum LocationAtom {
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
DW_OP_lo_user = 0xe0,
|
||||
DW_OP_hi_user = 0xff,
|
||||
DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata.
|
||||
DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata.
|
||||
DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata.
|
||||
DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata.
|
||||
DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata.
|
||||
DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata.
|
||||
DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata.
|
||||
};
|
||||
|
||||
enum TypeKind : uint8_t {
|
||||
@ -192,6 +181,59 @@ enum SourceLanguage {
|
||||
DW_LANG_hi_user = 0xffff
|
||||
};
|
||||
|
||||
inline bool isCPlusPlus(SourceLanguage S) {
|
||||
// Deliberately enumerate all the language options so we get a warning when
|
||||
// new language options are added (-Wswitch) that'll hopefully help keep this
|
||||
// switch up-to-date when new C++ versions are added.
|
||||
switch (S) {
|
||||
case DW_LANG_C_plus_plus:
|
||||
case DW_LANG_C_plus_plus_03:
|
||||
case DW_LANG_C_plus_plus_11:
|
||||
case DW_LANG_C_plus_plus_14:
|
||||
return true;
|
||||
case DW_LANG_C89:
|
||||
case DW_LANG_C:
|
||||
case DW_LANG_Ada83:
|
||||
case DW_LANG_Cobol74:
|
||||
case DW_LANG_Cobol85:
|
||||
case DW_LANG_Fortran77:
|
||||
case DW_LANG_Fortran90:
|
||||
case DW_LANG_Pascal83:
|
||||
case DW_LANG_Modula2:
|
||||
case DW_LANG_Java:
|
||||
case DW_LANG_C99:
|
||||
case DW_LANG_Ada95:
|
||||
case DW_LANG_Fortran95:
|
||||
case DW_LANG_PLI:
|
||||
case DW_LANG_ObjC:
|
||||
case DW_LANG_ObjC_plus_plus:
|
||||
case DW_LANG_UPC:
|
||||
case DW_LANG_D:
|
||||
case DW_LANG_Python:
|
||||
case DW_LANG_OpenCL:
|
||||
case DW_LANG_Go:
|
||||
case DW_LANG_Modula3:
|
||||
case DW_LANG_Haskell:
|
||||
case DW_LANG_OCaml:
|
||||
case DW_LANG_Rust:
|
||||
case DW_LANG_C11:
|
||||
case DW_LANG_Swift:
|
||||
case DW_LANG_Julia:
|
||||
case DW_LANG_Dylan:
|
||||
case DW_LANG_Fortran03:
|
||||
case DW_LANG_Fortran08:
|
||||
case DW_LANG_RenderScript:
|
||||
case DW_LANG_BLISS:
|
||||
case DW_LANG_Mips_Assembler:
|
||||
case DW_LANG_GOOGLE_RenderScript:
|
||||
case DW_LANG_BORLAND_Delphi:
|
||||
case DW_LANG_lo_user:
|
||||
case DW_LANG_hi_user:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("Invalid source language");
|
||||
}
|
||||
|
||||
enum CaseSensitivity {
|
||||
// Identifier case codes
|
||||
DW_ID_case_sensitive = 0x00,
|
||||
@ -267,11 +309,17 @@ enum MacroEntryType {
|
||||
};
|
||||
|
||||
/// DWARF v5 range list entry encoding values.
|
||||
enum RangeListEntries {
|
||||
enum RnglistEntries {
|
||||
#define HANDLE_DW_RLE(ID, NAME) DW_RLE_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
};
|
||||
|
||||
/// DWARF v5 loc list entry encoding values.
|
||||
enum LoclistEntries {
|
||||
#define HANDLE_DW_LLE(ID, NAME) DW_LLE_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
};
|
||||
|
||||
/// Call frame instruction encodings.
|
||||
enum CallFrameInfo {
|
||||
#define HANDLE_DW_CFA(ID, NAME) DW_CFA_##NAME = ID,
|
||||
@ -307,19 +355,6 @@ enum Constants {
|
||||
DW_EH_PE_indirect = 0x80
|
||||
};
|
||||
|
||||
/// Constants for location lists in DWARF v5.
|
||||
enum LocationListEntry : unsigned char {
|
||||
DW_LLE_end_of_list = 0x00,
|
||||
DW_LLE_base_addressx = 0x01,
|
||||
DW_LLE_startx_endx = 0x02,
|
||||
DW_LLE_startx_length = 0x03,
|
||||
DW_LLE_offset_pair = 0x04,
|
||||
DW_LLE_default_location = 0x05,
|
||||
DW_LLE_base_address = 0x06,
|
||||
DW_LLE_start_end = 0x07,
|
||||
DW_LLE_start_length = 0x08
|
||||
};
|
||||
|
||||
/// Constants for the DW_APPLE_PROPERTY_attributes attribute.
|
||||
/// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind!
|
||||
enum ApplePropertyAttributes {
|
||||
@ -434,6 +469,7 @@ StringRef LNStandardString(unsigned Standard);
|
||||
StringRef LNExtendedString(unsigned Encoding);
|
||||
StringRef MacinfoString(unsigned Encoding);
|
||||
StringRef RangeListEncodingString(unsigned Encoding);
|
||||
StringRef LocListEncodingString(unsigned Encoding);
|
||||
StringRef CallFrameString(unsigned Encoding, Triple::ArchType Arch);
|
||||
StringRef ApplePropertyString(unsigned);
|
||||
StringRef UnitTypeString(unsigned);
|
||||
@ -525,6 +561,17 @@ struct FormParams {
|
||||
explicit operator bool() const { return Version && AddrSize; }
|
||||
};
|
||||
|
||||
/// Get the byte size of the unit length field depending on the DWARF format.
|
||||
inline uint8_t getUnitLengthFieldByteSize(DwarfFormat Format) {
|
||||
switch (Format) {
|
||||
case DwarfFormat::DWARF32:
|
||||
return 4;
|
||||
case DwarfFormat::DWARF64:
|
||||
return 12;
|
||||
}
|
||||
llvm_unreachable("Invalid Format value");
|
||||
}
|
||||
|
||||
/// Get the fixed byte size for a given form.
|
||||
///
|
||||
/// If the form has a fixed byte size, then an Optional with a value will be
|
||||
|
@ -1356,6 +1356,72 @@ enum : unsigned {
|
||||
NT_GNU_BUILD_ATTRIBUTE_FUNC = 0x101,
|
||||
};
|
||||
|
||||
// Core note types
|
||||
enum : unsigned {
|
||||
NT_PRSTATUS = 1,
|
||||
NT_FPREGSET = 2,
|
||||
NT_PRPSINFO = 3,
|
||||
NT_TASKSTRUCT = 4,
|
||||
NT_AUXV = 6,
|
||||
NT_PSTATUS = 10,
|
||||
NT_FPREGS = 12,
|
||||
NT_PSINFO = 13,
|
||||
NT_LWPSTATUS = 16,
|
||||
NT_LWPSINFO = 17,
|
||||
NT_WIN32PSTATUS = 18,
|
||||
|
||||
NT_PPC_VMX = 0x100,
|
||||
NT_PPC_VSX = 0x102,
|
||||
NT_PPC_TAR = 0x103,
|
||||
NT_PPC_PPR = 0x104,
|
||||
NT_PPC_DSCR = 0x105,
|
||||
NT_PPC_EBB = 0x106,
|
||||
NT_PPC_PMU = 0x107,
|
||||
NT_PPC_TM_CGPR = 0x108,
|
||||
NT_PPC_TM_CFPR = 0x109,
|
||||
NT_PPC_TM_CVMX = 0x10a,
|
||||
NT_PPC_TM_CVSX = 0x10b,
|
||||
NT_PPC_TM_SPR = 0x10c,
|
||||
NT_PPC_TM_CTAR = 0x10d,
|
||||
NT_PPC_TM_CPPR = 0x10e,
|
||||
NT_PPC_TM_CDSCR = 0x10f,
|
||||
|
||||
NT_386_TLS = 0x200,
|
||||
NT_386_IOPERM = 0x201,
|
||||
NT_X86_XSTATE = 0x202,
|
||||
|
||||
NT_S390_HIGH_GPRS = 0x300,
|
||||
NT_S390_TIMER = 0x301,
|
||||
NT_S390_TODCMP = 0x302,
|
||||
NT_S390_TODPREG = 0x303,
|
||||
NT_S390_CTRS = 0x304,
|
||||
NT_S390_PREFIX = 0x305,
|
||||
NT_S390_LAST_BREAK = 0x306,
|
||||
NT_S390_SYSTEM_CALL = 0x307,
|
||||
NT_S390_TDB = 0x308,
|
||||
NT_S390_VXRS_LOW = 0x309,
|
||||
NT_S390_VXRS_HIGH = 0x30a,
|
||||
NT_S390_GS_CB = 0x30b,
|
||||
NT_S390_GS_BC = 0x30c,
|
||||
|
||||
NT_ARM_VFP = 0x400,
|
||||
NT_ARM_TLS = 0x401,
|
||||
NT_ARM_HW_BREAK = 0x402,
|
||||
NT_ARM_HW_WATCH = 0x403,
|
||||
NT_ARM_SVE = 0x405,
|
||||
NT_ARM_PAC_MASK = 0x406,
|
||||
|
||||
NT_FILE = 0x46494c45,
|
||||
NT_PRXFPREG = 0x46e62b7f,
|
||||
NT_SIGINFO = 0x53494749,
|
||||
};
|
||||
|
||||
// LLVM-specific notes.
|
||||
enum {
|
||||
NT_LLVM_HWASAN_GLOBALS = 3,
|
||||
};
|
||||
|
||||
// GNU note types
|
||||
enum {
|
||||
NT_GNU_ABI_TAG = 1,
|
||||
NT_GNU_HWCAP = 2,
|
||||
|
@ -124,8 +124,11 @@ ELF_RELOC(R_AARCH64_COPY, 0x400)
|
||||
ELF_RELOC(R_AARCH64_GLOB_DAT, 0x401)
|
||||
ELF_RELOC(R_AARCH64_JUMP_SLOT, 0x402)
|
||||
ELF_RELOC(R_AARCH64_RELATIVE, 0x403)
|
||||
ELF_RELOC(R_AARCH64_TLS_DTPREL64, 0x404)
|
||||
ELF_RELOC(R_AARCH64_TLS_DTPMOD64, 0x405)
|
||||
// 0x404 and 0x405 are now R_AARCH64_TLS_IMPDEF1 and R_AARCH64_TLS_IMPDEF2
|
||||
// We follow GNU and define TLS_IMPDEF1 as TLS_DTPMOD64 and TLS_IMPDEF2 as
|
||||
// TLS_DTPREL64
|
||||
ELF_RELOC(R_AARCH64_TLS_DTPMOD64, 0x404)
|
||||
ELF_RELOC(R_AARCH64_TLS_DTPREL64, 0x405)
|
||||
ELF_RELOC(R_AARCH64_TLS_TPREL64, 0x406)
|
||||
ELF_RELOC(R_AARCH64_TLSDESC, 0x407)
|
||||
ELF_RELOC(R_AARCH64_IRELATIVE, 0x408)
|
||||
|
@ -581,6 +581,11 @@ struct section_64 {
|
||||
uint32_t reserved3;
|
||||
};
|
||||
|
||||
inline bool isVirtualSection(uint8_t type) {
|
||||
return (type == MachO::S_ZEROFILL || type == MachO::S_GB_ZEROFILL ||
|
||||
type == MachO::S_THREAD_LOCAL_ZEROFILL);
|
||||
}
|
||||
|
||||
struct fvmlib {
|
||||
uint32_t name;
|
||||
uint32_t minor_version;
|
||||
|
@ -49,6 +49,7 @@ struct file_magic {
|
||||
xcoff_object_64, ///< 64-bit XCOFF object file
|
||||
wasm_object, ///< WebAssembly Object file
|
||||
pdb, ///< Windows PDB debug info file
|
||||
tapi_file, ///< Text-based Dynamic Library Stub file
|
||||
};
|
||||
|
||||
bool is_object() const { return V != unknown; }
|
||||
|
@ -18,12 +18,15 @@
|
||||
#ifndef LLVM_BINARYFORMAT_MINIDUMP_H
|
||||
#define LLVM_BINARYFORMAT_MINIDUMP_H
|
||||
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace minidump {
|
||||
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
|
||||
/// The minidump header is the first part of a minidump file. It identifies the
|
||||
/// file as a minidump file, and gives the location of the stream directory.
|
||||
struct Header {
|
||||
@ -67,6 +70,50 @@ struct MemoryDescriptor {
|
||||
};
|
||||
static_assert(sizeof(MemoryDescriptor) == 16, "");
|
||||
|
||||
struct MemoryInfoListHeader {
|
||||
support::ulittle32_t SizeOfHeader;
|
||||
support::ulittle32_t SizeOfEntry;
|
||||
support::ulittle64_t NumberOfEntries;
|
||||
|
||||
MemoryInfoListHeader() = default;
|
||||
MemoryInfoListHeader(uint32_t SizeOfHeader, uint32_t SizeOfEntry,
|
||||
uint64_t NumberOfEntries)
|
||||
: SizeOfHeader(SizeOfHeader), SizeOfEntry(SizeOfEntry),
|
||||
NumberOfEntries(NumberOfEntries) {}
|
||||
};
|
||||
static_assert(sizeof(MemoryInfoListHeader) == 16, "");
|
||||
|
||||
enum class MemoryProtection : uint32_t {
|
||||
#define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) NAME = CODE,
|
||||
#include "llvm/BinaryFormat/MinidumpConstants.def"
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xffffffffu),
|
||||
};
|
||||
|
||||
enum class MemoryState : uint32_t {
|
||||
#define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) NAME = CODE,
|
||||
#include "llvm/BinaryFormat/MinidumpConstants.def"
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xffffffffu),
|
||||
};
|
||||
|
||||
enum class MemoryType : uint32_t {
|
||||
#define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) NAME = CODE,
|
||||
#include "llvm/BinaryFormat/MinidumpConstants.def"
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xffffffffu),
|
||||
};
|
||||
|
||||
struct MemoryInfo {
|
||||
support::ulittle64_t BaseAddress;
|
||||
support::ulittle64_t AllocationBase;
|
||||
support::little_t<MemoryProtection> AllocationProtect;
|
||||
support::ulittle32_t Reserved0;
|
||||
support::ulittle64_t RegionSize;
|
||||
support::little_t<MemoryState> State;
|
||||
support::little_t<MemoryProtection> Protect;
|
||||
support::little_t<MemoryType> Type;
|
||||
support::ulittle32_t Reserved1;
|
||||
};
|
||||
static_assert(sizeof(MemoryInfo) == 48, "");
|
||||
|
||||
/// Specifies the location and type of a single stream in the minidump file. The
|
||||
/// minidump stream directory is an array of entries of this type, with its size
|
||||
/// given by Header.NumberOfStreams.
|
||||
@ -180,6 +227,27 @@ struct Thread {
|
||||
};
|
||||
static_assert(sizeof(Thread) == 48, "");
|
||||
|
||||
struct Exception {
|
||||
static constexpr size_t MaxParameters = 15;
|
||||
|
||||
support::ulittle32_t ExceptionCode;
|
||||
support::ulittle32_t ExceptionFlags;
|
||||
support::ulittle64_t ExceptionRecord;
|
||||
support::ulittle64_t ExceptionAddress;
|
||||
support::ulittle32_t NumberParameters;
|
||||
support::ulittle32_t UnusedAlignment;
|
||||
support::ulittle64_t ExceptionInformation[MaxParameters];
|
||||
};
|
||||
static_assert(sizeof(Exception) == 152, "");
|
||||
|
||||
struct ExceptionStream {
|
||||
support::ulittle32_t ThreadId;
|
||||
support::ulittle32_t UnusedAlignment;
|
||||
Exception ExceptionRecord;
|
||||
LocationDescriptor ThreadContext;
|
||||
};
|
||||
static_assert(sizeof(ExceptionStream) == 168, "");
|
||||
|
||||
} // namespace minidump
|
||||
|
||||
template <> struct DenseMapInfo<minidump::StreamType> {
|
||||
|
@ -6,8 +6,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if !(defined HANDLE_MDMP_STREAM_TYPE || defined HANDLE_MDMP_ARCH || \
|
||||
defined HANDLE_MDMP_PLATFORM)
|
||||
#if !(defined(HANDLE_MDMP_STREAM_TYPE) || defined(HANDLE_MDMP_ARCH) || \
|
||||
defined(HANDLE_MDMP_PLATFORM) || defined(HANDLE_MDMP_PROTECT) || \
|
||||
defined(HANDLE_MDMP_MEMSTATE) || defined(HANDLE_MDMP_MEMTYPE))
|
||||
#error "Missing HANDLE_MDMP definition"
|
||||
#endif
|
||||
|
||||
@ -23,6 +24,18 @@
|
||||
#define HANDLE_MDMP_PLATFORM(CODE, NAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MDMP_PROTECT
|
||||
#define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MDMP_MEMSTATE
|
||||
#define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME)
|
||||
#endif
|
||||
|
||||
#ifndef HANDLE_MDMP_MEMTYPE
|
||||
#define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME)
|
||||
#endif
|
||||
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0003, ThreadList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0004, ModuleList)
|
||||
HANDLE_MDMP_STREAM_TYPE(0x0005, MemoryList)
|
||||
@ -102,6 +115,30 @@ HANDLE_MDMP_PLATFORM(0x8203, Android) // Android
|
||||
HANDLE_MDMP_PLATFORM(0x8204, PS3) // PS3
|
||||
HANDLE_MDMP_PLATFORM(0x8205, NaCl) // Native Client (NaCl)
|
||||
|
||||
HANDLE_MDMP_PROTECT(0x01, NoAccess, PAGE_NO_ACCESS)
|
||||
HANDLE_MDMP_PROTECT(0x02, ReadOnly, PAGE_READ_ONLY)
|
||||
HANDLE_MDMP_PROTECT(0x04, ReadWrite, PAGE_READ_WRITE)
|
||||
HANDLE_MDMP_PROTECT(0x08, WriteCopy, PAGE_WRITE_COPY)
|
||||
HANDLE_MDMP_PROTECT(0x10, Execute, PAGE_EXECUTE)
|
||||
HANDLE_MDMP_PROTECT(0x20, ExecuteRead, PAGE_EXECUTE_READ)
|
||||
HANDLE_MDMP_PROTECT(0x40, ExecuteReadWrite, PAGE_EXECUTE_READ_WRITE)
|
||||
HANDLE_MDMP_PROTECT(0x80, ExeciteWriteCopy, PAGE_EXECUTE_WRITE_COPY)
|
||||
HANDLE_MDMP_PROTECT(0x100, Guard, PAGE_GUARD)
|
||||
HANDLE_MDMP_PROTECT(0x200, NoCache, PAGE_NOCACHE)
|
||||
HANDLE_MDMP_PROTECT(0x400, WriteCombine, PAGE_WRITECOMBINE)
|
||||
HANDLE_MDMP_PROTECT(0x40000000, TargetsInvalid, PAGE_TARGETS_INVALID)
|
||||
|
||||
HANDLE_MDMP_MEMSTATE(0x01000, Commit, MEM_COMMIT)
|
||||
HANDLE_MDMP_MEMSTATE(0x02000, Reserve, MEM_RESERVE)
|
||||
HANDLE_MDMP_MEMSTATE(0x10000, Free, MEM_FREE)
|
||||
|
||||
HANDLE_MDMP_MEMTYPE(0x0020000, Private, MEM_PRIVATE)
|
||||
HANDLE_MDMP_MEMTYPE(0x0040000, Mapped, MEM_MAPPED)
|
||||
HANDLE_MDMP_MEMTYPE(0x1000000, Image, MEM_IMAGE)
|
||||
|
||||
#undef HANDLE_MDMP_STREAM_TYPE
|
||||
#undef HANDLE_MDMP_ARCH
|
||||
#undef HANDLE_MDMP_PLATFORM
|
||||
#undef HANDLE_MDMP_PROTECT
|
||||
#undef HANDLE_MDMP_MEMSTATE
|
||||
#undef HANDLE_MDMP_MEMTYPE
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace wasm {
|
||||
@ -251,9 +252,21 @@ enum : unsigned {
|
||||
WASM_OPCODE_F32_CONST = 0x43,
|
||||
WASM_OPCODE_F64_CONST = 0x44,
|
||||
WASM_OPCODE_I32_ADD = 0x6a,
|
||||
};
|
||||
|
||||
// Opcodes used in synthetic functions.
|
||||
enum : unsigned {
|
||||
WASM_OPCODE_IF = 0x04,
|
||||
WASM_OPCODE_ELSE = 0x05,
|
||||
WASM_OPCODE_DROP = 0x1a,
|
||||
WASM_OPCODE_MISC_PREFIX = 0xfc,
|
||||
WASM_OPCODE_MEMORY_INIT = 0x08,
|
||||
WASM_OPCODE_DATA_DROP = 0x09,
|
||||
WASM_OPCODE_ATOMICS_PREFIX = 0xfe,
|
||||
WASM_OPCODE_ATOMIC_NOTIFY = 0x00,
|
||||
WASM_OPCODE_I32_ATOMIC_WAIT = 0x01,
|
||||
WASM_OPCODE_I32_ATOMIC_STORE = 0x17,
|
||||
WASM_OPCODE_I32_RMW_CMPXCHG = 0x48,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
@ -318,6 +331,7 @@ const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN = 0x4;
|
||||
const unsigned WASM_SYMBOL_UNDEFINED = 0x10;
|
||||
const unsigned WASM_SYMBOL_EXPORTED = 0x20;
|
||||
const unsigned WASM_SYMBOL_EXPLICIT_NAME = 0x40;
|
||||
const unsigned WASM_SYMBOL_NO_STRIP = 0x80;
|
||||
|
||||
#define WASM_RELOC(name, value) name = value,
|
||||
|
||||
|
@ -19,12 +19,13 @@ namespace llvm {
|
||||
namespace XCOFF {
|
||||
|
||||
// Constants used in the XCOFF definition.
|
||||
enum { SectionNameSize = 8, SymbolNameSize = 8 };
|
||||
enum { FileNamePadSize = 6, NameSize = 8, SymbolTableEntrySize = 18 };
|
||||
|
||||
enum ReservedSectionNum { N_DEBUG = -2, N_ABS = -1, N_UNDEF = 0 };
|
||||
|
||||
// x_smclas field of x_csect from system header: /usr/include/syms.h
|
||||
/// Storage Mapping Class definitions.
|
||||
enum StorageMappingClass {
|
||||
enum StorageMappingClass : uint8_t {
|
||||
// READ ONLY CLASSES
|
||||
XMC_PR = 0, ///< Program Code
|
||||
XMC_RO = 1, ///< Read Only Constant
|
||||
@ -139,6 +140,117 @@ enum StorageClass : uint8_t {
|
||||
C_TCSYM = 134 // Reserved
|
||||
};
|
||||
|
||||
enum SymbolType {
|
||||
XTY_ER = 0, ///< External reference.
|
||||
XTY_SD = 1, ///< Csect definition for initialized storage.
|
||||
XTY_LD = 2, ///< Label definition.
|
||||
///< Defines an entry point to an initialized csect.
|
||||
XTY_CM = 3 ///< Common csect definition. For uninitialized storage.
|
||||
};
|
||||
|
||||
// Relocation types, defined in `/usr/include/reloc.h`.
|
||||
enum RelocationType : uint8_t {
|
||||
R_POS = 0x00, ///< Positive relocation. Provides the address of the referenced
|
||||
///< symbol.
|
||||
R_RL = 0x0c, ///< Positive indirect load relocation. Modifiable instruction.
|
||||
R_RLA = 0x0d, ///< Positive load address relocation. Modifiable instruction.
|
||||
|
||||
R_NEG = 0x01, ///< Negative relocation. Provides the negative of the address
|
||||
///< of the referenced symbol.
|
||||
R_REL = 0x02, ///< Relative to self relocation. Provides a displacement value
|
||||
///< between the address of the referenced symbol and the
|
||||
///< address being relocated.
|
||||
|
||||
R_TOC = 0x03, ///< Relative to the TOC relocation. Provides a displacement
|
||||
///< that is the difference between the address of the
|
||||
///< referenced symbol and the TOC anchor csect.
|
||||
R_TRL = 0x12, ///< TOC relative indirect load relocation. Similar to R_TOC,
|
||||
///< but not modifiable instruction.
|
||||
|
||||
R_TRLA =
|
||||
0x13, ///< Relative to the TOC or to the thread-local storage base
|
||||
///< relocation. Compilers are not permitted to generate this
|
||||
///< relocation type. It is the result of a reversible
|
||||
///< transformation by the linker of an R_TOC relation that turned a
|
||||
///< load instruction into an add-immediate instruction.
|
||||
|
||||
R_GL = 0x05, ///< Global linkage-external TOC address relocation. Provides the
|
||||
///< address of the external TOC associated with a defined
|
||||
///< external symbol.
|
||||
R_TCL = 0x06, ///< Local object TOC address relocation. Provides the address
|
||||
///< of the local TOC entry of a defined external symbol.
|
||||
|
||||
R_REF = 0x0f, ///< A non-relocating relocation. Used to prevent the binder
|
||||
///< from garbage collecting a csect (such as code used for
|
||||
///< dynamic initialization of non-local statics) for which
|
||||
///< another csect has an implicit dependency.
|
||||
|
||||
R_BA = 0x08, ///< Branch absolute relocation. Provides the address of the
|
||||
///< referenced symbol. References a non-modifiable instruction.
|
||||
R_BR = 0x0a, ///< Branch relative to self relocation. Provides the
|
||||
///< displacement that is the difference between the address of
|
||||
///< the referenced symbol and the address of the referenced
|
||||
///< branch instruction. References a non-modifiable instruction.
|
||||
R_RBA = 0x18, ///< Branch absolute relocation. Similar to R_BA but
|
||||
///< references a modifiable instruction.
|
||||
R_RBR = 0x1a, ///< Branch relative to self relocation. Similar to the R_BR
|
||||
///< relocation type, but references a modifiable instruction.
|
||||
|
||||
R_TLS = 0x20, ///< General-dynamic reference to TLS symbol.
|
||||
R_TLS_IE = 0x21, ///< Initial-exec reference to TLS symbol.
|
||||
R_TLS_LD = 0x22, ///< Local-dynamic reference to TLS symbol.
|
||||
R_TLS_LE = 0x23, ///< Local-exec reference to TLS symbol.
|
||||
R_TLSM = 0x24, ///< Module reference to TLS. Provides a handle for the module
|
||||
///< containing the referenced symbol.
|
||||
R_TLSML = 0x25, ///< Module reference to the local TLS storage.
|
||||
|
||||
R_TOCU = 0x30, ///< Relative to TOC upper. Specifies the high-order 16 bits of
|
||||
///< a large code model TOC-relative relocation.
|
||||
R_TOCL = 0x31 ///< Relative to TOC lower. Specifies the low-order 16 bits of a
|
||||
///< large code model TOC-relative relocation.
|
||||
};
|
||||
|
||||
struct FileHeader32 {
|
||||
uint16_t Magic;
|
||||
uint16_t NumberOfSections;
|
||||
int32_t TimeStamp;
|
||||
uint32_t SymbolTableFileOffset;
|
||||
int32_t NumberOfSymbolTableEntries;
|
||||
uint16_t AuxiliaryHeaderSize;
|
||||
uint16_t Flags;
|
||||
};
|
||||
|
||||
struct SectionHeader32 {
|
||||
char Name[XCOFF::NameSize];
|
||||
uint32_t PhysicalAddress;
|
||||
uint32_t VirtualAddress;
|
||||
uint32_t Size;
|
||||
uint32_t FileOffsetToData;
|
||||
uint32_t FileOffsetToRelocations;
|
||||
uint32_t FileOffsetToLineNumbers;
|
||||
uint16_t NumberOfRelocations;
|
||||
uint16_t NumberOfLineNumbers;
|
||||
int32_t Flags;
|
||||
};
|
||||
|
||||
enum CFileStringType : uint8_t {
|
||||
XFT_FN = 0, ///< Specifies the source-file name.
|
||||
XFT_CT = 1, ///< Specifies the compiler time stamp.
|
||||
XFT_CV = 2, ///< Specifies the compiler version number.
|
||||
XFT_CD = 128 ///< Specifies compiler-defined information.
|
||||
};
|
||||
|
||||
enum CFileLangId : uint8_t {
|
||||
TB_C = 0, ///< C language.
|
||||
TB_CPLUSPLUS = 9 ///< C++ language.
|
||||
};
|
||||
|
||||
enum CFileCpuId : uint8_t {
|
||||
TCPU_PPC64 = 2, ///< PowerPC common architecture 64-bit mode.
|
||||
TCPU_COM = 3, ///< POWER and PowerPC architecture common.
|
||||
TCPU_970 = 19 ///< PPC970 - PowerPC 64-bit architecture.
|
||||
};
|
||||
|
||||
} // end namespace XCOFF
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -30,6 +30,7 @@ enum CurStreamTypeType {
|
||||
LLVMIRBitstream,
|
||||
ClangSerializedASTBitstream,
|
||||
ClangSerializedDiagnosticsBitstream,
|
||||
LLVMBitstreamRemarks
|
||||
};
|
||||
|
||||
struct BCDumpOptions {
|
||||
|
@ -391,7 +391,7 @@ enum CastOpcodes {
|
||||
/// have no fixed relation to the LLVM IR enum values. Changing these will
|
||||
/// break compatibility with old files.
|
||||
enum UnaryOpcodes {
|
||||
UNOP_NEG = 0
|
||||
UNOP_FNEG = 0
|
||||
};
|
||||
|
||||
/// BinaryOpcodes - These are values used in the bitcode files to encode which
|
||||
|
@ -168,6 +168,11 @@ class BitCodeAbbrev {
|
||||
SmallVector<BitCodeAbbrevOp, 32> OperandList;
|
||||
|
||||
public:
|
||||
BitCodeAbbrev() = default;
|
||||
|
||||
explicit BitCodeAbbrev(std::initializer_list<BitCodeAbbrevOp> OperandList)
|
||||
: OperandList(OperandList) {}
|
||||
|
||||
unsigned getNumOperandInfos() const {
|
||||
return static_cast<unsigned>(OperandList.size());
|
||||
}
|
||||
|
@ -379,6 +379,7 @@ class BitstreamCursor : SimpleBitstreamCursor {
|
||||
using SimpleBitstreamCursor::ReadVBR;
|
||||
using SimpleBitstreamCursor::ReadVBR64;
|
||||
using SimpleBitstreamCursor::SizeInBytes;
|
||||
using SimpleBitstreamCursor::skipToEnd;
|
||||
|
||||
/// Return the number of bits used to encode an abbrev #.
|
||||
unsigned getAbbrevIDWidth() const { return CurCodeSize; }
|
||||
|
@ -101,8 +101,6 @@
|
||||
///
|
||||
/// An Apple Accelerator Table can be serialized by calling emitAppleAccelTable
|
||||
/// function.
|
||||
///
|
||||
/// TODO: Add DWARF v5 emission code.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
@ -111,6 +111,10 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// of each call to runOnMachineFunction().
|
||||
MCSymbol *CurrentFnSym = nullptr;
|
||||
|
||||
/// The symbol for the current function descriptor on AIX. This is created
|
||||
/// at the beginning of each call to SetupMachineFunction().
|
||||
MCSymbol *CurrentFnDescSym = nullptr;
|
||||
|
||||
/// The symbol used to represent the start of the current function for the
|
||||
/// purpose of calculating its size (e.g. using the .size directive). By
|
||||
/// default, this is equal to CurrentFnSym.
|
||||
@ -304,7 +308,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
|
||||
/// This should be called when a new MachineFunction is being processed from
|
||||
/// runOnMachineFunction.
|
||||
void SetupMachineFunction(MachineFunction &MF);
|
||||
virtual void SetupMachineFunction(MachineFunction &MF);
|
||||
|
||||
/// This method emits the body and trailer for a function.
|
||||
void EmitFunctionBody();
|
||||
@ -342,12 +346,11 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// so, emit it and return true, otherwise do nothing and return false.
|
||||
bool EmitSpecialLLVMGlobal(const GlobalVariable *GV);
|
||||
|
||||
/// Emit an alignment directive to the specified power of two boundary. For
|
||||
/// example, if you pass in 3 here, you will get an 8 byte alignment. If a
|
||||
/// Emit an alignment directive to the specified power of two boundary. If a
|
||||
/// global value is specified, and if that global has an explicit alignment
|
||||
/// requested, it will override the alignment request if required for
|
||||
/// correctness.
|
||||
void EmitAlignment(unsigned NumBits, const GlobalObject *GV = nullptr) const;
|
||||
void EmitAlignment(Align Alignment, const GlobalObject *GV = nullptr) const;
|
||||
|
||||
/// Lower the specified LLVM Constant to an MCExpr.
|
||||
virtual const MCExpr *lowerConstant(const Constant *CV);
|
||||
@ -400,7 +403,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// 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;
|
||||
virtual void EmitBasicBlockStart(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Targets can override this to emit stuff at the end of a basic block.
|
||||
virtual void EmitBasicBlockEnd(const MachineBasicBlock &MBB);
|
||||
@ -415,6 +418,10 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
|
||||
virtual void EmitFunctionEntryLabel();
|
||||
|
||||
virtual void EmitFunctionDescriptor() {
|
||||
llvm_unreachable("Function descriptor is target-specific.");
|
||||
}
|
||||
|
||||
virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV);
|
||||
|
||||
/// Targets can override this to change how global constants that are part of
|
||||
@ -635,6 +642,10 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
/// supported by the target.
|
||||
void EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const;
|
||||
|
||||
/// Return the alignment for the specified \p GV.
|
||||
static Align getGVAlignment(const GlobalValue *GV, const DataLayout &DL,
|
||||
Align InAlign = Align::None());
|
||||
|
||||
private:
|
||||
/// Private state for PrintSpecial()
|
||||
// Assign a unique ID to this machine instruction.
|
||||
|
@ -190,6 +190,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
protected:
|
||||
explicit BasicTTIImplBase(const TargetMachine *TM, const DataLayout &DL)
|
||||
: BaseT(DL) {}
|
||||
virtual ~BasicTTIImplBase() = default;
|
||||
|
||||
using TargetTransformInfoImplBase::DL;
|
||||
|
||||
@ -215,6 +216,16 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool collectFlatAddressOperands(SmallVectorImpl<int> &OpIndexes,
|
||||
Intrinsic::ID IID) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rewriteIntrinsicWithAddressSpace(IntrinsicInst *II,
|
||||
Value *OldV, Value *NewV) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isLegalAddImmediate(int64_t imm) {
|
||||
return getTLI()->isLegalAddImmediate(imm);
|
||||
}
|
||||
@ -317,7 +328,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
unsigned getEstimatedNumberOfCaseClusters(const SwitchInst &SI,
|
||||
unsigned &JumpTableSize) {
|
||||
/// Try to find the estimated number of clusters. Note that the number of
|
||||
/// clusters identified in this function could be different from the actural
|
||||
/// clusters identified in this function could be different from the actual
|
||||
/// numbers found in lowering. This function ignore switches that are
|
||||
/// lowered with a mix of jump table / bit test / BTree. This function was
|
||||
/// initially intended to be used when estimating the cost of switch in
|
||||
@ -371,10 +382,6 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return N;
|
||||
}
|
||||
|
||||
unsigned getJumpBufAlignment() { return getTLI()->getJumpBufAlignment(); }
|
||||
|
||||
unsigned getJumpBufSize() { return getTLI()->getJumpBufSize(); }
|
||||
|
||||
bool shouldBuildLookupTables() {
|
||||
const TargetLoweringBase *TLI = getTLI();
|
||||
return TLI->isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) ||
|
||||
@ -508,13 +515,44 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
return BaseT::getInstructionLatency(I);
|
||||
}
|
||||
|
||||
virtual Optional<unsigned>
|
||||
getCacheSize(TargetTransformInfo::CacheLevel Level) const {
|
||||
return Optional<unsigned>(
|
||||
getST()->getCacheSize(static_cast<unsigned>(Level)));
|
||||
}
|
||||
|
||||
virtual Optional<unsigned>
|
||||
getCacheAssociativity(TargetTransformInfo::CacheLevel Level) const {
|
||||
Optional<unsigned> TargetResult =
|
||||
getST()->getCacheAssociativity(static_cast<unsigned>(Level));
|
||||
|
||||
if (TargetResult)
|
||||
return TargetResult;
|
||||
|
||||
return BaseT::getCacheAssociativity(Level);
|
||||
}
|
||||
|
||||
virtual unsigned getCacheLineSize() const {
|
||||
return getST()->getCacheLineSize();
|
||||
}
|
||||
|
||||
virtual unsigned getPrefetchDistance() const {
|
||||
return getST()->getPrefetchDistance();
|
||||
}
|
||||
|
||||
virtual unsigned getMinPrefetchStride() const {
|
||||
return getST()->getMinPrefetchStride();
|
||||
}
|
||||
|
||||
virtual unsigned getMaxPrefetchIterationsAhead() const {
|
||||
return getST()->getMaxPrefetchIterationsAhead();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Vector TTI Implementations
|
||||
/// @{
|
||||
|
||||
unsigned getNumberOfRegisters(bool Vector) { return Vector ? 0 : 1; }
|
||||
|
||||
unsigned getRegisterBitWidth(bool Vector) const { return 32; }
|
||||
|
||||
/// Estimate the overhead of scalarizing an instruction. Insert and Extract
|
||||
@ -1111,9 +1149,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
OpPropsBW);
|
||||
// For non-rotates (X != Y) we must add shift-by-zero handling costs.
|
||||
if (X != Y) {
|
||||
Type *CondTy = Type::getInt1Ty(RetTy->getContext());
|
||||
if (RetVF > 1)
|
||||
CondTy = VectorType::get(CondTy, RetVF);
|
||||
Type *CondTy = RetTy->getWithNewBitWidth(1);
|
||||
Cost += ConcreteTTI->getCmpSelInstrCost(BinaryOperator::ICmp, RetTy,
|
||||
CondTy, nullptr);
|
||||
Cost += ConcreteTTI->getCmpSelInstrCost(BinaryOperator::Select, RetTy,
|
||||
@ -1131,7 +1167,6 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
unsigned getIntrinsicInstrCost(
|
||||
Intrinsic::ID IID, Type *RetTy, ArrayRef<Type *> Tys, FastMathFlags FMF,
|
||||
unsigned ScalarizationCostPassed = std::numeric_limits<unsigned>::max()) {
|
||||
unsigned RetVF = (RetTy->isVectorTy() ? RetTy->getVectorNumElements() : 1);
|
||||
auto *ConcreteTTI = static_cast<T *>(this);
|
||||
|
||||
SmallVector<unsigned, 2> ISDs;
|
||||
@ -1288,9 +1323,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
/*IsUnsigned=*/false);
|
||||
case Intrinsic::sadd_sat:
|
||||
case Intrinsic::ssub_sat: {
|
||||
Type *CondTy = Type::getInt1Ty(RetTy->getContext());
|
||||
if (RetVF > 1)
|
||||
CondTy = VectorType::get(CondTy, RetVF);
|
||||
Type *CondTy = RetTy->getWithNewBitWidth(1);
|
||||
|
||||
Type *OpTy = StructType::create({RetTy, CondTy});
|
||||
Intrinsic::ID OverflowOp = IID == Intrinsic::sadd_sat
|
||||
@ -1310,9 +1343,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
}
|
||||
case Intrinsic::uadd_sat:
|
||||
case Intrinsic::usub_sat: {
|
||||
Type *CondTy = Type::getInt1Ty(RetTy->getContext());
|
||||
if (RetVF > 1)
|
||||
CondTy = VectorType::get(CondTy, RetVF);
|
||||
Type *CondTy = RetTy->getWithNewBitWidth(1);
|
||||
|
||||
Type *OpTy = StructType::create({RetTy, CondTy});
|
||||
Intrinsic::ID OverflowOp = IID == Intrinsic::uadd_sat
|
||||
@ -1329,9 +1360,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
case Intrinsic::smul_fix:
|
||||
case Intrinsic::umul_fix: {
|
||||
unsigned ExtSize = RetTy->getScalarSizeInBits() * 2;
|
||||
Type *ExtTy = Type::getIntNTy(RetTy->getContext(), ExtSize);
|
||||
if (RetVF > 1)
|
||||
ExtTy = VectorType::get(ExtTy, RetVF);
|
||||
Type *ExtTy = RetTy->getWithNewBitWidth(ExtSize);
|
||||
|
||||
unsigned ExtOp =
|
||||
IID == Intrinsic::smul_fix ? Instruction::SExt : Instruction::ZExt;
|
||||
@ -1395,9 +1424,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
Type *MulTy = RetTy->getContainedType(0);
|
||||
Type *OverflowTy = RetTy->getContainedType(1);
|
||||
unsigned ExtSize = MulTy->getScalarSizeInBits() * 2;
|
||||
Type *ExtTy = Type::getIntNTy(RetTy->getContext(), ExtSize);
|
||||
if (MulTy->isVectorTy())
|
||||
ExtTy = VectorType::get(ExtTy, MulTy->getVectorNumElements() );
|
||||
Type *ExtTy = MulTy->getWithNewBitWidth(ExtSize);
|
||||
|
||||
unsigned ExtOp =
|
||||
IID == Intrinsic::smul_fix ? Instruction::SExt : Instruction::ZExt;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/CodeGen/TargetCallingConv.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Support/Alignment.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -43,6 +44,7 @@ class CCValAssign {
|
||||
AExtUpper, // The value is in the upper bits of the location and should be
|
||||
// extended with undefined upper bits when retrieved.
|
||||
BCvt, // The value is bit-converted in the location.
|
||||
Trunc, // The value is truncated in the location.
|
||||
VExt, // The value is vector-widened in the location.
|
||||
// FIXME: Not implemented yet. Code that uses AExt to mean
|
||||
// vector-widen should be fixed to use VExt instead.
|
||||
@ -197,7 +199,7 @@ class CCState {
|
||||
LLVMContext &Context;
|
||||
|
||||
unsigned StackOffset;
|
||||
unsigned MaxStackArgAlign;
|
||||
Align MaxStackArgAlign;
|
||||
SmallVector<uint32_t, 16> UsedRegs;
|
||||
SmallVector<CCValAssign, 4> PendingLocs;
|
||||
SmallVector<ISD::ArgFlagsTy, 4> PendingArgFlags;
|
||||
@ -421,19 +423,19 @@ class CCState {
|
||||
|
||||
/// AllocateStack - Allocate a chunk of stack space with the specified size
|
||||
/// and alignment.
|
||||
unsigned AllocateStack(unsigned Size, unsigned Align) {
|
||||
assert(Align && ((Align - 1) & Align) == 0); // Align is power of 2.
|
||||
StackOffset = alignTo(StackOffset, Align);
|
||||
unsigned AllocateStack(unsigned Size, unsigned Alignment) {
|
||||
const Align CheckedAlignment(Alignment);
|
||||
StackOffset = alignTo(StackOffset, CheckedAlignment);
|
||||
unsigned Result = StackOffset;
|
||||
StackOffset += Size;
|
||||
MaxStackArgAlign = std::max(Align, MaxStackArgAlign);
|
||||
ensureMaxAlignment(Align);
|
||||
MaxStackArgAlign = std::max(CheckedAlignment, MaxStackArgAlign);
|
||||
ensureMaxAlignment(CheckedAlignment);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void ensureMaxAlignment(unsigned Align) {
|
||||
void ensureMaxAlignment(Align Alignment) {
|
||||
if (!AnalyzingMustTailForwardedRegs)
|
||||
MF.getFrameInfo().ensureMaxAlignment(Align);
|
||||
MF.getFrameInfo().ensureMaxAlignment(Alignment.value());
|
||||
}
|
||||
|
||||
/// Version of AllocateStack with extra register to be shadowed.
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/ScheduleDAGMutation.h"
|
||||
#include "llvm/Support/Automaton.h"
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@ -76,26 +77,26 @@ using DFAStateInput = int64_t;
|
||||
|
||||
class DFAPacketizer {
|
||||
private:
|
||||
using UnsignPair = std::pair<unsigned, DFAInput>;
|
||||
|
||||
const InstrItineraryData *InstrItins;
|
||||
int CurrentState = 0;
|
||||
const DFAStateInput (*DFAStateInputTable)[2];
|
||||
const unsigned *DFAStateEntryTable;
|
||||
|
||||
// CachedTable is a map from <FromState, Input> to ToState.
|
||||
DenseMap<UnsignPair, unsigned> CachedTable;
|
||||
|
||||
// Read the DFA transition table and update CachedTable.
|
||||
void ReadTable(unsigned state);
|
||||
Automaton<DFAInput> A;
|
||||
|
||||
public:
|
||||
DFAPacketizer(const InstrItineraryData *I, const DFAStateInput (*SIT)[2],
|
||||
const unsigned *SET);
|
||||
DFAPacketizer(const InstrItineraryData *InstrItins, Automaton<uint64_t> a) :
|
||||
InstrItins(InstrItins), A(std::move(a)) {
|
||||
// Start off with resource tracking disabled.
|
||||
A.enableTranscription(false);
|
||||
}
|
||||
|
||||
// Reset the current state to make all resources available.
|
||||
void clearResources() {
|
||||
CurrentState = 0;
|
||||
A.reset();
|
||||
}
|
||||
|
||||
// Set whether this packetizer should track not just whether instructions
|
||||
// can be packetized, but also which functional units each instruction ends up
|
||||
// using after packetization.
|
||||
void setTrackResources(bool Track) {
|
||||
A.enableTranscription(Track);
|
||||
}
|
||||
|
||||
// Return the DFAInput for an instruction class.
|
||||
@ -120,6 +121,15 @@ class DFAPacketizer {
|
||||
// current state to reflect that change.
|
||||
void reserveResources(MachineInstr &MI);
|
||||
|
||||
// Return the resources used by the InstIdx'th instruction added to this
|
||||
// packet. The resources are returned as a bitvector of functional units.
|
||||
//
|
||||
// Note that a bundle may be packed in multiple valid ways. This function
|
||||
// returns one arbitary valid packing.
|
||||
//
|
||||
// Requires setTrackResources(true) to have been called.
|
||||
unsigned getUsedResources(unsigned InstIdx);
|
||||
|
||||
const InstrItineraryData *getInstrItins() const { return InstrItins; }
|
||||
};
|
||||
|
||||
@ -134,7 +144,7 @@ class VLIWPacketizerList {
|
||||
protected:
|
||||
MachineFunction &MF;
|
||||
const TargetInstrInfo *TII;
|
||||
AliasAnalysis *AA;
|
||||
AAResults *AA;
|
||||
|
||||
// The VLIW Scheduler.
|
||||
DefaultVLIWScheduler *VLIWScheduler;
|
||||
@ -146,9 +156,9 @@ class VLIWPacketizerList {
|
||||
std::map<MachineInstr*, SUnit*> MIToSUnit;
|
||||
|
||||
public:
|
||||
// The AliasAnalysis parameter can be nullptr.
|
||||
// The AAResults parameter can be nullptr.
|
||||
VLIWPacketizerList(MachineFunction &MF, MachineLoopInfo &MLI,
|
||||
AliasAnalysis *AA);
|
||||
AAResults *AA);
|
||||
|
||||
virtual ~VLIWPacketizerList();
|
||||
|
||||
|
@ -550,6 +550,14 @@ template <class T> class IntrusiveBackList : IntrusiveBackListBase {
|
||||
return *static_cast<T *>(Last ? Last->Next.getPointer() : nullptr);
|
||||
}
|
||||
|
||||
void takeNodes(IntrusiveBackList<T> &Other) {
|
||||
for (auto &N : Other) {
|
||||
N.Next.setPointerAndInt(&N, true);
|
||||
push_back(N);
|
||||
}
|
||||
Other.Last = nullptr;
|
||||
}
|
||||
|
||||
class const_iterator;
|
||||
class iterator
|
||||
: public iterator_facade_base<iterator, std::forward_iterator_tag, T> {
|
||||
@ -685,6 +693,10 @@ class DIEValueList {
|
||||
return addValue(Alloc, DIEValue(Attribute, Form, std::forward<T>(Value)));
|
||||
}
|
||||
|
||||
/// Take ownership of the nodes in \p Other, and append them to the back of
|
||||
/// the list.
|
||||
void takeValues(DIEValueList &Other) { List.takeNodes(Other.List); }
|
||||
|
||||
value_range values() {
|
||||
return make_range(value_iterator(List.begin()), value_iterator(List.end()));
|
||||
}
|
||||
|
@ -93,9 +93,9 @@ class FastISel {
|
||||
|
||||
SmallVector<Value *, 16> OutVals;
|
||||
SmallVector<ISD::ArgFlagsTy, 16> OutFlags;
|
||||
SmallVector<unsigned, 16> OutRegs;
|
||||
SmallVector<Register, 16> OutRegs;
|
||||
SmallVector<ISD::InputArg, 4> Ins;
|
||||
SmallVector<unsigned, 4> InRegs;
|
||||
SmallVector<Register, 4> InRegs;
|
||||
|
||||
CallLoweringInfo()
|
||||
: RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false),
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/LegacyDivergenceAnalysis.h"
|
||||
#include "llvm/CodeGen/ISDOpcodes.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
@ -37,6 +36,7 @@ namespace llvm {
|
||||
class Argument;
|
||||
class BasicBlock;
|
||||
class BranchProbabilityInfo;
|
||||
class LegacyDivergenceAnalysis;
|
||||
class Function;
|
||||
class Instruction;
|
||||
class MachineFunction;
|
||||
|
@ -45,18 +45,62 @@ class CallLowering {
|
||||
public:
|
||||
struct ArgInfo {
|
||||
SmallVector<Register, 4> Regs;
|
||||
// If the argument had to be split into multiple parts according to the
|
||||
// target calling convention, then this contains the original vregs
|
||||
// if the argument was an incoming arg.
|
||||
SmallVector<Register, 2> OrigRegs;
|
||||
Type *Ty;
|
||||
ISD::ArgFlagsTy Flags;
|
||||
SmallVector<ISD::ArgFlagsTy, 4> Flags;
|
||||
bool IsFixed;
|
||||
|
||||
ArgInfo(ArrayRef<Register> Regs, Type *Ty,
|
||||
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy{}, bool IsFixed = true)
|
||||
: Regs(Regs.begin(), Regs.end()), Ty(Ty), Flags(Flags),
|
||||
IsFixed(IsFixed) {
|
||||
ArrayRef<ISD::ArgFlagsTy> Flags = ArrayRef<ISD::ArgFlagsTy>(),
|
||||
bool IsFixed = true)
|
||||
: Regs(Regs.begin(), Regs.end()), Ty(Ty),
|
||||
Flags(Flags.begin(), Flags.end()), IsFixed(IsFixed) {
|
||||
if (!Regs.empty() && Flags.empty())
|
||||
this->Flags.push_back(ISD::ArgFlagsTy());
|
||||
// FIXME: We should have just one way of saying "no register".
|
||||
assert((Ty->isVoidTy() == (Regs.empty() || Regs[0] == 0)) &&
|
||||
"only void types should have no register");
|
||||
}
|
||||
|
||||
ArgInfo() : Ty(nullptr), IsFixed(false) {}
|
||||
};
|
||||
|
||||
struct CallLoweringInfo {
|
||||
/// Calling convention to be used for the call.
|
||||
CallingConv::ID CallConv = CallingConv::C;
|
||||
|
||||
/// Destination of the call. It should be either a register, globaladdress,
|
||||
/// or externalsymbol.
|
||||
MachineOperand Callee = MachineOperand::CreateImm(0);
|
||||
|
||||
/// Descriptor for the return type of the function.
|
||||
ArgInfo OrigRet;
|
||||
|
||||
/// List of descriptors of the arguments passed to the function.
|
||||
SmallVector<ArgInfo, 8> OrigArgs;
|
||||
|
||||
/// Valid if the call has a swifterror inout parameter, and contains the
|
||||
/// vreg that the swifterror should be copied into after the call.
|
||||
Register SwiftErrorVReg = 0;
|
||||
|
||||
MDNode *KnownCallees = nullptr;
|
||||
|
||||
/// True if the call must be tail call optimized.
|
||||
bool IsMustTailCall = false;
|
||||
|
||||
/// True if the call passes all target-independent checks for tail call
|
||||
/// optimization.
|
||||
bool IsTailCall = false;
|
||||
|
||||
/// True if the call was lowered as a tail call. This is consumed by the
|
||||
/// legalizer. This allows the legalizer to lower libcalls as tail calls.
|
||||
bool LoweredTailCall = false;
|
||||
|
||||
/// True if the call is to a vararg function.
|
||||
bool IsVarArg = false;
|
||||
};
|
||||
|
||||
/// Argument handling is mostly uniform between the four places that
|
||||
@ -72,9 +116,9 @@ class CallLowering {
|
||||
|
||||
virtual ~ValueHandler() = default;
|
||||
|
||||
/// Returns true if the handler is dealing with formal arguments,
|
||||
/// not with return values etc.
|
||||
virtual bool isArgumentHandler() const { return false; }
|
||||
/// Returns true if the handler is dealing with incoming arguments,
|
||||
/// i.e. those that move values from some physical location to vregs.
|
||||
virtual bool isIncomingArgumentHandler() const = 0;
|
||||
|
||||
/// Materialize a VReg containing the address of the specified
|
||||
/// stack-based object. This is either based on a FrameIndex or
|
||||
@ -112,8 +156,8 @@ class CallLowering {
|
||||
|
||||
virtual bool assignArg(unsigned ValNo, MVT ValVT, MVT LocVT,
|
||||
CCValAssign::LocInfo LocInfo, const ArgInfo &Info,
|
||||
CCState &State) {
|
||||
return AssignFn(ValNo, ValVT, LocVT, LocInfo, Info.Flags, State);
|
||||
ISD::ArgFlagsTy Flags, CCState &State) {
|
||||
return AssignFn(ValNo, ValVT, LocVT, LocInfo, Flags, State);
|
||||
}
|
||||
|
||||
MachineIRBuilder &MIRBuilder;
|
||||
@ -162,12 +206,42 @@ class CallLowering {
|
||||
/// \p Callback to move them to the assigned locations.
|
||||
///
|
||||
/// \return True if everything has succeeded, false otherwise.
|
||||
bool handleAssignments(MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args,
|
||||
bool handleAssignments(MachineIRBuilder &MIRBuilder,
|
||||
SmallVectorImpl<ArgInfo> &Args,
|
||||
ValueHandler &Handler) const;
|
||||
bool handleAssignments(CCState &CCState,
|
||||
SmallVectorImpl<CCValAssign> &ArgLocs,
|
||||
MachineIRBuilder &MIRBuilder, ArrayRef<ArgInfo> Args,
|
||||
MachineIRBuilder &MIRBuilder,
|
||||
SmallVectorImpl<ArgInfo> &Args,
|
||||
ValueHandler &Handler) const;
|
||||
|
||||
/// Analyze passed or returned values from a call, supplied in \p ArgInfo,
|
||||
/// incorporating info about the passed values into \p CCState.
|
||||
///
|
||||
/// Used to check if arguments are suitable for tail call lowering.
|
||||
bool analyzeArgInfo(CCState &CCState, SmallVectorImpl<ArgInfo> &Args,
|
||||
CCAssignFn &AssignFnFixed,
|
||||
CCAssignFn &AssignFnVarArg) const;
|
||||
|
||||
/// \returns True if the calling convention for a callee and its caller pass
|
||||
/// results in the same way. Typically used for tail call eligibility checks.
|
||||
///
|
||||
/// \p Info is the CallLoweringInfo for the call.
|
||||
/// \p MF is the MachineFunction for the caller.
|
||||
/// \p InArgs contains the results of the call.
|
||||
/// \p CalleeAssignFnFixed is the CCAssignFn to be used for the callee for
|
||||
/// fixed arguments.
|
||||
/// \p CalleeAssignFnVarArg is similar, but for varargs.
|
||||
/// \p CallerAssignFnFixed is the CCAssignFn to be used for the caller for
|
||||
/// fixed arguments.
|
||||
/// \p CallerAssignFnVarArg is similar, but for varargs.
|
||||
bool resultsCompatible(CallLoweringInfo &Info, MachineFunction &MF,
|
||||
SmallVectorImpl<ArgInfo> &InArgs,
|
||||
CCAssignFn &CalleeAssignFnFixed,
|
||||
CCAssignFn &CalleeAssignFnVarArg,
|
||||
CCAssignFn &CallerAssignFnFixed,
|
||||
CCAssignFn &CallerAssignFnVarArg) const;
|
||||
|
||||
public:
|
||||
CallLowering(const TargetLowering *TLI) : TLI(TLI) {}
|
||||
virtual ~CallLowering() = default;
|
||||
@ -223,37 +297,10 @@ class CallLowering {
|
||||
/// This hook must be implemented to lower the given call instruction,
|
||||
/// including argument and return value marshalling.
|
||||
///
|
||||
/// \p CallConv is the calling convention to be used for the call.
|
||||
///
|
||||
/// \p Callee is the destination of the call. It should be either a register,
|
||||
/// globaladdress, or externalsymbol.
|
||||
///
|
||||
/// \p OrigRet is a descriptor for the return type of the function.
|
||||
///
|
||||
/// \p OrigArgs is a list of descriptors of the arguments passed to the
|
||||
/// function.
|
||||
///
|
||||
/// \p SwiftErrorVReg is non-zero if the call has a swifterror inout
|
||||
/// parameter, and contains the vreg that the swifterror should be copied into
|
||||
/// after the call.
|
||||
///
|
||||
/// \return true if the lowering succeeded, false otherwise.
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
|
||||
const MachineOperand &Callee, const ArgInfo &OrigRet,
|
||||
ArrayRef<ArgInfo> OrigArgs,
|
||||
Register SwiftErrorVReg) const {
|
||||
if (!supportSwiftError()) {
|
||||
assert(SwiftErrorVReg == 0 && "trying to use unsupported swifterror");
|
||||
return lowerCall(MIRBuilder, CallConv, Callee, OrigRet, OrigArgs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This hook behaves as the extended lowerCall function, but for targets that
|
||||
/// do not support swifterror value promotion.
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder, CallingConv::ID CallConv,
|
||||
const MachineOperand &Callee, const ArgInfo &OrigRet,
|
||||
ArrayRef<ArgInfo> OrigArgs) const {
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder,
|
||||
CallLoweringInfo &Info) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@ class MachineIRBuilder;
|
||||
class MachineRegisterInfo;
|
||||
class MachineInstr;
|
||||
class MachineOperand;
|
||||
class GISelKnownBits;
|
||||
class MachineDominatorTree;
|
||||
|
||||
struct PreferredTuple {
|
||||
LLT Ty; // The result type of the extend.
|
||||
@ -35,12 +37,17 @@ struct PreferredTuple {
|
||||
};
|
||||
|
||||
class CombinerHelper {
|
||||
protected:
|
||||
MachineIRBuilder &Builder;
|
||||
MachineRegisterInfo &MRI;
|
||||
GISelChangeObserver &Observer;
|
||||
GISelKnownBits *KB;
|
||||
MachineDominatorTree *MDT;
|
||||
|
||||
public:
|
||||
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B);
|
||||
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B,
|
||||
GISelKnownBits *KB = nullptr,
|
||||
MachineDominatorTree *MDT = nullptr);
|
||||
|
||||
/// MachineRegisterInfo::replaceRegWith() and inform the observer of the changes
|
||||
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const;
|
||||
@ -56,18 +63,132 @@ class CombinerHelper {
|
||||
bool matchCombineCopy(MachineInstr &MI);
|
||||
void applyCombineCopy(MachineInstr &MI);
|
||||
|
||||
/// Returns true if \p DefMI precedes \p UseMI or they are the same
|
||||
/// instruction. Both must be in the same basic block.
|
||||
bool isPredecessor(MachineInstr &DefMI, MachineInstr &UseMI);
|
||||
|
||||
/// Returns true if \p DefMI dominates \p UseMI. By definition an
|
||||
/// instruction dominates itself.
|
||||
///
|
||||
/// If we haven't been provided with a MachineDominatorTree during
|
||||
/// construction, this function returns a conservative result that tracks just
|
||||
/// a single basic block.
|
||||
bool dominates(MachineInstr &DefMI, MachineInstr &UseMI);
|
||||
|
||||
/// If \p MI is extend that consumes the result of a load, try to combine it.
|
||||
/// Returns true if MI changed.
|
||||
bool tryCombineExtendingLoads(MachineInstr &MI);
|
||||
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo);
|
||||
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo);
|
||||
|
||||
bool matchCombineBr(MachineInstr &MI);
|
||||
bool tryCombineBr(MachineInstr &MI);
|
||||
/// Combine \p MI into a pre-indexed or post-indexed load/store operation if
|
||||
/// legal and the surrounding code makes it useful.
|
||||
bool tryCombineIndexedLoadStore(MachineInstr &MI);
|
||||
|
||||
bool matchElideBrByInvertingCond(MachineInstr &MI);
|
||||
void applyElideBrByInvertingCond(MachineInstr &MI);
|
||||
bool tryElideBrByInvertingCond(MachineInstr &MI);
|
||||
|
||||
/// If \p MI is G_CONCAT_VECTORS, try to combine it.
|
||||
/// Returns true if MI changed.
|
||||
/// Right now, we support:
|
||||
/// - concat_vector(undef, undef) => undef
|
||||
/// - concat_vector(build_vector(A, B), build_vector(C, D)) =>
|
||||
/// build_vector(A, B, C, D)
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_CONCAT_VECTORS.
|
||||
bool tryCombineConcatVectors(MachineInstr &MI);
|
||||
/// Check if the G_CONCAT_VECTORS \p MI is undef or if it
|
||||
/// can be flattened into a build_vector.
|
||||
/// In the first case \p IsUndef will be true.
|
||||
/// In the second case \p Ops will contain the operands needed
|
||||
/// to produce the flattened build_vector.
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_CONCAT_VECTORS.
|
||||
bool matchCombineConcatVectors(MachineInstr &MI, bool &IsUndef,
|
||||
SmallVectorImpl<Register> &Ops);
|
||||
/// Replace \p MI with a flattened build_vector with \p Ops or an
|
||||
/// implicit_def if IsUndef is true.
|
||||
void applyCombineConcatVectors(MachineInstr &MI, bool IsUndef,
|
||||
const ArrayRef<Register> Ops);
|
||||
|
||||
/// Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
|
||||
/// Returns true if MI changed.
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_SHUFFLE_VECTOR.
|
||||
bool tryCombineShuffleVector(MachineInstr &MI);
|
||||
/// Check if the G_SHUFFLE_VECTOR \p MI can be replaced by a
|
||||
/// concat_vectors.
|
||||
/// \p Ops will contain the operands needed to produce the flattened
|
||||
/// concat_vectors.
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_SHUFFLE_VECTOR.
|
||||
bool matchCombineShuffleVector(MachineInstr &MI,
|
||||
SmallVectorImpl<Register> &Ops);
|
||||
/// Replace \p MI with a concat_vectors with \p Ops.
|
||||
void applyCombineShuffleVector(MachineInstr &MI,
|
||||
const ArrayRef<Register> Ops);
|
||||
|
||||
/// Optimize memcpy intrinsics et al, e.g. constant len calls.
|
||||
/// /p MaxLen if non-zero specifies the max length of a mem libcall to inline.
|
||||
///
|
||||
/// For example (pre-indexed):
|
||||
///
|
||||
/// $addr = G_GEP $base, $offset
|
||||
/// [...]
|
||||
/// $val = G_LOAD $addr
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
///
|
||||
/// -->
|
||||
///
|
||||
/// $val, $addr = G_INDEXED_LOAD $base, $offset, 1 (IsPre)
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
///
|
||||
/// or (post-indexed):
|
||||
///
|
||||
/// G_STORE $val, $base
|
||||
/// [...]
|
||||
/// $addr = G_GEP $base, $offset
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
///
|
||||
/// -->
|
||||
///
|
||||
/// $addr = G_INDEXED_STORE $val, $base, $offset
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0);
|
||||
|
||||
/// Try to transform \p MI by using all of the above
|
||||
/// combine functions. Returns true if changed.
|
||||
bool tryCombine(MachineInstr &MI);
|
||||
|
||||
private:
|
||||
// Memcpy family optimization helpers.
|
||||
bool optimizeMemcpy(MachineInstr &MI, Register Dst, Register Src,
|
||||
unsigned KnownLen, unsigned DstAlign, unsigned SrcAlign,
|
||||
bool IsVolatile);
|
||||
bool optimizeMemmove(MachineInstr &MI, Register Dst, Register Src,
|
||||
unsigned KnownLen, unsigned DstAlign, unsigned SrcAlign,
|
||||
bool IsVolatile);
|
||||
bool optimizeMemset(MachineInstr &MI, Register Dst, Register Val,
|
||||
unsigned KnownLen, unsigned DstAlign, bool IsVolatile);
|
||||
|
||||
/// Given a non-indexed load or store instruction \p MI, find an offset that
|
||||
/// can be usefully and legally folded into it as a post-indexing operation.
|
||||
///
|
||||
/// \returns true if a candidate is found.
|
||||
bool findPostIndexCandidate(MachineInstr &MI, Register &Addr, Register &Base,
|
||||
Register &Offset);
|
||||
|
||||
/// Given a non-indexed load or store instruction \p MI, find an offset that
|
||||
/// can be usefully and legally folded into it as a pre-indexing operation.
|
||||
///
|
||||
/// \returns true if a candidate is found.
|
||||
bool findPreIndexCandidate(MachineInstr &MI, Register &Addr, Register &Base,
|
||||
Register &Offset);
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
|
@ -27,9 +27,11 @@ class MachineRegisterInfo;
|
||||
class CombinerInfo {
|
||||
public:
|
||||
CombinerInfo(bool AllowIllegalOps, bool ShouldLegalizeIllegal,
|
||||
LegalizerInfo *LInfo)
|
||||
LegalizerInfo *LInfo, bool OptEnabled, bool OptSize,
|
||||
bool MinSize)
|
||||
: IllegalOpsAllowed(AllowIllegalOps),
|
||||
LegalizeIllegalOps(ShouldLegalizeIllegal), LInfo(LInfo) {
|
||||
LegalizeIllegalOps(ShouldLegalizeIllegal), LInfo(LInfo),
|
||||
EnableOpt(OptEnabled), EnableOptSize(OptSize), EnableMinSize(MinSize) {
|
||||
assert(((AllowIllegalOps || !LegalizeIllegalOps) || LInfo) &&
|
||||
"Expecting legalizerInfo when illegalops not allowed");
|
||||
}
|
||||
@ -43,6 +45,15 @@ class CombinerInfo {
|
||||
bool LegalizeIllegalOps; // TODO: Make use of this.
|
||||
const LegalizerInfo *LInfo;
|
||||
|
||||
/// Whether optimizations should be enabled. This is to distinguish between
|
||||
/// uses of the combiner unconditionally and only when optimizations are
|
||||
/// specifically enabled/
|
||||
bool EnableOpt;
|
||||
/// Whether we're optimizing for size.
|
||||
bool EnableOptSize;
|
||||
/// Whether we're optimizing for minsize (-Oz).
|
||||
bool EnableMinSize;
|
||||
|
||||
/// Attempt to combine instructions using MI as the root.
|
||||
///
|
||||
/// Use Observer to report the creation, modification, and erasure of
|
||||
|
@ -54,6 +54,17 @@ class ConstantFoldingMIRBuilder : public MachineIRBuilder {
|
||||
return buildConstant(Dst, MaybeCst->getSExtValue());
|
||||
break;
|
||||
}
|
||||
case TargetOpcode::G_SEXT_INREG: {
|
||||
assert(DstOps.size() == 1 && "Invalid dst ops");
|
||||
assert(SrcOps.size() == 2 && "Invalid src ops");
|
||||
const DstOp &Dst = DstOps[0];
|
||||
const SrcOp &Src0 = SrcOps[0];
|
||||
const SrcOp &Src1 = SrcOps[1];
|
||||
if (auto MaybeCst =
|
||||
ConstantFoldExtOp(Opc, Src0.getReg(), Src1.getImm(), *getMRI()))
|
||||
return buildConstant(Dst, MaybeCst->getSExtValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps);
|
||||
}
|
||||
|
111
include/llvm/CodeGen/GlobalISel/GISelKnownBits.h
Normal file
111
include/llvm/CodeGen/GlobalISel/GISelKnownBits.h
Normal file
@ -0,0 +1,111 @@
|
||||
//===- llvm/CodeGen/GlobalISel/GISelKnownBits.h ---------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// Provides analysis for querying information about KnownBits during GISel
|
||||
/// passes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_KNOWNBITSINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_KNOWNBITSINFO_H
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class TargetLowering;
|
||||
class DataLayout;
|
||||
|
||||
class GISelKnownBits : public GISelChangeObserver {
|
||||
MachineFunction &MF;
|
||||
MachineRegisterInfo &MRI;
|
||||
const TargetLowering &TL;
|
||||
const DataLayout &DL;
|
||||
|
||||
public:
|
||||
GISelKnownBits(MachineFunction &MF);
|
||||
virtual ~GISelKnownBits() = default;
|
||||
void setMF(MachineFunction &MF);
|
||||
virtual void computeKnownBitsImpl(Register R, KnownBits &Known,
|
||||
const APInt &DemandedElts,
|
||||
unsigned Depth = 0);
|
||||
|
||||
// KnownBitsAPI
|
||||
KnownBits getKnownBits(Register R);
|
||||
// Calls getKnownBits for first operand def of MI.
|
||||
KnownBits getKnownBits(MachineInstr &MI);
|
||||
APInt getKnownZeroes(Register R);
|
||||
APInt getKnownOnes(Register R);
|
||||
|
||||
/// \return true if 'V & Mask' is known to be zero in DemandedElts. We use
|
||||
/// this predicate to simplify operations downstream.
|
||||
/// Mask is known to be zero for bits that V cannot have.
|
||||
bool maskedValueIsZero(Register Val, const APInt &Mask) {
|
||||
return Mask.isSubsetOf(getKnownBits(Val).Zero);
|
||||
}
|
||||
|
||||
/// \return true if the sign bit of Op is known to be zero. We use this
|
||||
/// predicate to simplify operations downstream.
|
||||
bool signBitIsZero(Register Op);
|
||||
|
||||
// FIXME: Is this the right place for G_FRAME_INDEX? Should it be in
|
||||
// TargetLowering?
|
||||
void computeKnownBitsForFrameIndex(Register R, KnownBits &Known,
|
||||
const APInt &DemandedElts,
|
||||
unsigned Depth = 0);
|
||||
static Align inferAlignmentForFrameIdx(int FrameIdx, int Offset,
|
||||
const MachineFunction &MF);
|
||||
static void computeKnownBitsForAlignment(KnownBits &Known,
|
||||
MaybeAlign Alignment);
|
||||
|
||||
// Try to infer alignment for MI.
|
||||
static MaybeAlign inferPtrAlignment(const MachineInstr &MI);
|
||||
|
||||
// Observer API. No-op for non-caching implementation.
|
||||
void erasingInstr(MachineInstr &MI) override{};
|
||||
void createdInstr(MachineInstr &MI) override{};
|
||||
void changingInstr(MachineInstr &MI) override{};
|
||||
void changedInstr(MachineInstr &MI) override{};
|
||||
|
||||
protected:
|
||||
unsigned getMaxDepth() const { return 6; }
|
||||
};
|
||||
|
||||
/// To use KnownBitsInfo analysis in a pass,
|
||||
/// KnownBitsInfo &Info = getAnalysis<GISelKnownBitsInfoAnalysis>().get(MF);
|
||||
/// Add to observer if the Info is caching.
|
||||
/// WrapperObserver.addObserver(Info);
|
||||
|
||||
/// Eventually add other features such as caching/ser/deserializing
|
||||
/// to MIR etc. Those implementations can derive from GISelKnownBits
|
||||
/// and override computeKnownBitsImpl.
|
||||
class GISelKnownBitsAnalysis : public MachineFunctionPass {
|
||||
std::unique_ptr<GISelKnownBits> Info;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
GISelKnownBitsAnalysis() : MachineFunctionPass(ID) {
|
||||
initializeGISelKnownBitsAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
GISelKnownBits &get(MachineFunction &MF) {
|
||||
if (!Info)
|
||||
Info = std::make_unique<GISelKnownBits>(MF);
|
||||
return *Info.get();
|
||||
}
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
void releaseMemory() override { Info.reset(); }
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif // ifdef
|
@ -213,8 +213,8 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool translateStore(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate an LLVM string intrinsic (memcpy, memset, ...).
|
||||
bool translateMemfunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
|
||||
unsigned ID);
|
||||
bool translateMemFunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
|
||||
Intrinsic::ID ID);
|
||||
|
||||
void getStackGuard(Register DstReg, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
@ -243,6 +243,10 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool valueIsSplit(const Value &V,
|
||||
SmallVectorImpl<uint64_t> *Offsets = nullptr);
|
||||
|
||||
/// Common code for translating normal calls or invokes.
|
||||
bool translateCallSite(const ImmutableCallSite &CS,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate call instruction.
|
||||
/// \pre \p U is a call instruction.
|
||||
bool translateCall(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
@ -514,6 +518,10 @@ class IRTranslator : public MachineFunctionPass {
|
||||
// function has the optnone attribute.
|
||||
bool EnableOpts = false;
|
||||
|
||||
/// True when the block contains a tail call. This allows the IRTranslator to
|
||||
/// stop translating such blocks early.
|
||||
bool HasTailCall = false;
|
||||
|
||||
/// Switch analysis and optimization.
|
||||
class GISelSwitchLowering : public SwitchCG::SwitchLowering {
|
||||
public:
|
||||
|
@ -31,6 +31,7 @@ namespace llvm {
|
||||
|
||||
class APInt;
|
||||
class APFloat;
|
||||
class GISelKnownBits;
|
||||
class MachineInstr;
|
||||
class MachineInstrBuilder;
|
||||
class MachineFunction;
|
||||
@ -148,6 +149,13 @@ enum {
|
||||
/// - AddrSpaceN+1 ...
|
||||
GIM_CheckMemoryAddressSpace,
|
||||
|
||||
/// Check the minimum alignment of the memory access for the given machine
|
||||
/// memory operand.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - MMOIdx - MMO index
|
||||
/// - MinAlign - Minimum acceptable alignment
|
||||
GIM_CheckMemoryAlignment,
|
||||
|
||||
/// Check the size of the memory access for the given machine memory operand
|
||||
/// against the size of an operand.
|
||||
/// - InsnID - Instruction ID
|
||||
@ -201,11 +209,22 @@ enum {
|
||||
/// - Expected Intrinsic ID
|
||||
GIM_CheckIntrinsicID,
|
||||
|
||||
/// Check the operand is a specific predicate
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected predicate
|
||||
GIM_CheckCmpPredicate,
|
||||
|
||||
/// Check the specified operand is an MBB
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_CheckIsMBB,
|
||||
|
||||
/// Check the specified operand is an Imm
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_CheckIsImm,
|
||||
|
||||
/// Check if the specified operand is safe to fold into the current
|
||||
/// instruction.
|
||||
/// - InsnID - Instruction ID
|
||||
@ -365,7 +384,20 @@ class InstructionSelector {
|
||||
/// if returns true:
|
||||
/// for I in all mutated/inserted instructions:
|
||||
/// !isPreISelGenericOpcode(I.getOpcode())
|
||||
virtual bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const = 0;
|
||||
virtual bool select(MachineInstr &I) = 0;
|
||||
|
||||
CodeGenCoverage *CoverageInfo = nullptr;
|
||||
GISelKnownBits *KnownBits = nullptr;
|
||||
MachineFunction *MF = nullptr;
|
||||
|
||||
/// Setup per-MF selector state.
|
||||
virtual void setupMF(MachineFunction &mf,
|
||||
GISelKnownBits &KB,
|
||||
CodeGenCoverage &covinfo) {
|
||||
CoverageInfo = &covinfo;
|
||||
KnownBits = &KB;
|
||||
MF = &mf;
|
||||
}
|
||||
|
||||
protected:
|
||||
using ComplexRendererFns =
|
||||
|
@ -98,7 +98,7 @@ bool InstructionSelector::executeMatchTable(
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
if (TRI.isPhysicalRegister(MO.getReg())) {
|
||||
if (Register::isPhysicalRegister(MO.getReg())) {
|
||||
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
|
||||
dbgs() << CurrentIdx << ": Is a physical register\n");
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
@ -409,6 +409,30 @@ bool InstructionSelector::executeMatchTable(
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckMemoryAlignment: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
int64_t MMOIdx = MatchTable[CurrentIdx++];
|
||||
unsigned MinAlign = MatchTable[CurrentIdx++];
|
||||
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
|
||||
if (State.MIs[InsnID]->getNumMemOperands() <= MMOIdx) {
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
MachineMemOperand *MMO
|
||||
= *(State.MIs[InsnID]->memoperands_begin() + MMOIdx);
|
||||
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
|
||||
dbgs() << CurrentIdx << ": GIM_CheckMemoryAlignment"
|
||||
<< "(MIs[" << InsnID << "]->memoperands() + " << MMOIdx
|
||||
<< ")->getAlignment() >= " << MinAlign << ")\n");
|
||||
if (MMO->getAlignment() < MinAlign && handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
case GIM_CheckMemorySizeEqualTo: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
int64_t MMOIdx = MatchTable[CurrentIdx++];
|
||||
@ -638,7 +662,21 @@ bool InstructionSelector::executeMatchTable(
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case GIM_CheckCmpPredicate: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
int64_t OpIdx = MatchTable[CurrentIdx++];
|
||||
int64_t Value = MatchTable[CurrentIdx++];
|
||||
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
|
||||
dbgs() << CurrentIdx << ": GIM_CheckCmpPredicate(MIs["
|
||||
<< InsnID << "]->getOperand(" << OpIdx
|
||||
<< "), Value=" << Value << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
|
||||
if (!MO.isPredicate() || MO.getPredicate() != Value)
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckIsMBB: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
int64_t OpIdx = MatchTable[CurrentIdx++];
|
||||
@ -652,7 +690,19 @@ bool InstructionSelector::executeMatchTable(
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GIM_CheckIsImm: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
int64_t OpIdx = MatchTable[CurrentIdx++];
|
||||
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
|
||||
dbgs() << CurrentIdx << ": GIM_CheckIsImm(MIs[" << InsnID
|
||||
<< "]->getOperand(" << OpIdx << "))\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (!State.MIs[InsnID]->getOperand(OpIdx).isImm()) {
|
||||
if (handleReject() == RejectAndGiveUp)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GIM_CheckIsSafeToFold: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
|
||||
@ -792,11 +842,13 @@ bool InstructionSelector::executeMatchTable(
|
||||
case GIR_AddRegister: {
|
||||
int64_t InsnID = MatchTable[CurrentIdx++];
|
||||
int64_t RegNum = MatchTable[CurrentIdx++];
|
||||
uint64_t RegFlags = MatchTable[CurrentIdx++];
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[InsnID].addReg(RegNum);
|
||||
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
|
||||
dbgs() << CurrentIdx << ": GIR_AddRegister(OutMIs["
|
||||
<< InsnID << "], " << RegNum << ")\n");
|
||||
OutMIs[InsnID].addReg(RegNum, RegFlags);
|
||||
DEBUG_WITH_TYPE(
|
||||
TgtInstructionSelector::getName(),
|
||||
dbgs() << CurrentIdx << ": GIR_AddRegister(OutMIs["
|
||||
<< InsnID << "], " << RegNum << ", " << RegFlags << ")\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,7 @@ class LegalizationArtifactCombiner {
|
||||
|
||||
bool tryCombineAnyExt(MachineInstr &MI,
|
||||
SmallVectorImpl<MachineInstr *> &DeadInsts) {
|
||||
if (MI.getOpcode() != TargetOpcode::G_ANYEXT)
|
||||
return false;
|
||||
assert(MI.getOpcode() == TargetOpcode::G_ANYEXT);
|
||||
|
||||
Builder.setInstr(MI);
|
||||
Register DstReg = MI.getOperand(0).getReg();
|
||||
@ -93,9 +92,7 @@ class LegalizationArtifactCombiner {
|
||||
|
||||
bool tryCombineZExt(MachineInstr &MI,
|
||||
SmallVectorImpl<MachineInstr *> &DeadInsts) {
|
||||
|
||||
if (MI.getOpcode() != TargetOpcode::G_ZEXT)
|
||||
return false;
|
||||
assert(MI.getOpcode() == TargetOpcode::G_ZEXT);
|
||||
|
||||
Builder.setInstr(MI);
|
||||
Register DstReg = MI.getOperand(0).getReg();
|
||||
@ -136,32 +133,24 @@ class LegalizationArtifactCombiner {
|
||||
|
||||
bool tryCombineSExt(MachineInstr &MI,
|
||||
SmallVectorImpl<MachineInstr *> &DeadInsts) {
|
||||
|
||||
if (MI.getOpcode() != TargetOpcode::G_SEXT)
|
||||
return false;
|
||||
assert(MI.getOpcode() == TargetOpcode::G_SEXT);
|
||||
|
||||
Builder.setInstr(MI);
|
||||
Register DstReg = MI.getOperand(0).getReg();
|
||||
Register SrcReg = lookThroughCopyInstrs(MI.getOperand(1).getReg());
|
||||
|
||||
// sext(trunc x) - > ashr (shl (aext/copy/trunc x), c), c
|
||||
// sext(trunc x) - > (sext_inreg (aext/copy/trunc x), c)
|
||||
Register TruncSrc;
|
||||
if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
|
||||
LLT DstTy = MRI.getType(DstReg);
|
||||
// Guess on the RHS shift amount type, which should be re-legalized if
|
||||
// applicable.
|
||||
if (isInstUnsupported({TargetOpcode::G_SHL, {DstTy, DstTy}}) ||
|
||||
isInstUnsupported({TargetOpcode::G_ASHR, {DstTy, DstTy}}) ||
|
||||
isConstantUnsupported(DstTy))
|
||||
if (isInstUnsupported({TargetOpcode::G_SEXT_INREG, {DstTy}}))
|
||||
return false;
|
||||
LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;);
|
||||
LLT SrcTy = MRI.getType(SrcReg);
|
||||
unsigned ShAmt = DstTy.getScalarSizeInBits() - SrcTy.getScalarSizeInBits();
|
||||
auto MIBShAmt = Builder.buildConstant(DstTy, ShAmt);
|
||||
auto MIBShl = Builder.buildInstr(
|
||||
TargetOpcode::G_SHL, {DstTy},
|
||||
{Builder.buildAnyExtOrTrunc(DstTy, TruncSrc), MIBShAmt});
|
||||
Builder.buildInstr(TargetOpcode::G_ASHR, {DstReg}, {MIBShl, MIBShAmt});
|
||||
uint64_t SizeInBits = SrcTy.getScalarSizeInBits();
|
||||
Builder.buildInstr(
|
||||
TargetOpcode::G_SEXT_INREG, {DstReg},
|
||||
{Builder.buildAnyExtOrTrunc(DstTy, TruncSrc), SizeInBits});
|
||||
markInstAndDefDead(MI, *MRI.getVRegDef(SrcReg), DeadInsts);
|
||||
return true;
|
||||
}
|
||||
@ -172,9 +161,8 @@ class LegalizationArtifactCombiner {
|
||||
bool tryFoldImplicitDef(MachineInstr &MI,
|
||||
SmallVectorImpl<MachineInstr *> &DeadInsts) {
|
||||
unsigned Opcode = MI.getOpcode();
|
||||
if (Opcode != TargetOpcode::G_ANYEXT && Opcode != TargetOpcode::G_ZEXT &&
|
||||
Opcode != TargetOpcode::G_SEXT)
|
||||
return false;
|
||||
assert(Opcode == TargetOpcode::G_ANYEXT || Opcode == TargetOpcode::G_ZEXT ||
|
||||
Opcode == TargetOpcode::G_SEXT);
|
||||
|
||||
if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF,
|
||||
MI.getOperand(1).getReg(), MRI)) {
|
||||
@ -203,21 +191,38 @@ class LegalizationArtifactCombiner {
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned getMergeOpcode(LLT OpTy, LLT DestTy) {
|
||||
static unsigned canFoldMergeOpcode(unsigned MergeOp, unsigned ConvertOp,
|
||||
LLT OpTy, LLT DestTy) {
|
||||
if (OpTy.isVector() && DestTy.isVector())
|
||||
return TargetOpcode::G_CONCAT_VECTORS;
|
||||
return MergeOp == TargetOpcode::G_CONCAT_VECTORS;
|
||||
|
||||
if (OpTy.isVector() && !DestTy.isVector())
|
||||
return TargetOpcode::G_BUILD_VECTOR;
|
||||
if (OpTy.isVector() && !DestTy.isVector()) {
|
||||
if (MergeOp == TargetOpcode::G_BUILD_VECTOR)
|
||||
return true;
|
||||
|
||||
return TargetOpcode::G_MERGE_VALUES;
|
||||
if (MergeOp == TargetOpcode::G_CONCAT_VECTORS) {
|
||||
if (ConvertOp == 0)
|
||||
return true;
|
||||
|
||||
const unsigned OpEltSize = OpTy.getElementType().getSizeInBits();
|
||||
|
||||
// Don't handle scalarization with a cast that isn't in the same
|
||||
// direction as the vector cast. This could be handled, but it would
|
||||
// require more intermediate unmerges.
|
||||
if (ConvertOp == TargetOpcode::G_TRUNC)
|
||||
return DestTy.getSizeInBits() <= OpEltSize;
|
||||
return DestTy.getSizeInBits() >= OpEltSize;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return MergeOp == TargetOpcode::G_MERGE_VALUES;
|
||||
}
|
||||
|
||||
bool tryCombineMerges(MachineInstr &MI,
|
||||
SmallVectorImpl<MachineInstr *> &DeadInsts) {
|
||||
|
||||
if (MI.getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
|
||||
return false;
|
||||
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
|
||||
|
||||
unsigned NumDefs = MI.getNumOperands() - 1;
|
||||
MachineInstr *SrcDef =
|
||||
@ -237,16 +242,14 @@ class LegalizationArtifactCombiner {
|
||||
MergeI = getDefIgnoringCopies(SrcDef->getOperand(1).getReg(), MRI);
|
||||
}
|
||||
|
||||
// FIXME: Handle scalarizing concat_vectors (scalar result type with vector
|
||||
// source)
|
||||
unsigned MergingOpcode = getMergeOpcode(OpTy, DestTy);
|
||||
if (!MergeI || MergeI->getOpcode() != MergingOpcode)
|
||||
if (!MergeI || !canFoldMergeOpcode(MergeI->getOpcode(),
|
||||
ConvertOp, OpTy, DestTy))
|
||||
return false;
|
||||
|
||||
const unsigned NumMergeRegs = MergeI->getNumOperands() - 1;
|
||||
|
||||
if (NumMergeRegs < NumDefs) {
|
||||
if (ConvertOp != 0 || NumDefs % NumMergeRegs != 0)
|
||||
if (NumDefs % NumMergeRegs != 0)
|
||||
return false;
|
||||
|
||||
Builder.setInstr(MI);
|
||||
@ -264,7 +267,22 @@ class LegalizationArtifactCombiner {
|
||||
++j, ++DefIdx)
|
||||
DstRegs.push_back(MI.getOperand(DefIdx).getReg());
|
||||
|
||||
Builder.buildUnmerge(DstRegs, MergeI->getOperand(Idx + 1).getReg());
|
||||
if (ConvertOp) {
|
||||
SmallVector<Register, 2> TmpRegs;
|
||||
// This is a vector that is being scalarized and casted. Extract to
|
||||
// the element type, and do the conversion on the scalars.
|
||||
LLT MergeEltTy
|
||||
= MRI.getType(MergeI->getOperand(0).getReg()).getElementType();
|
||||
for (unsigned j = 0; j < NumMergeRegs; ++j)
|
||||
TmpRegs.push_back(MRI.createGenericVirtualRegister(MergeEltTy));
|
||||
|
||||
Builder.buildUnmerge(TmpRegs, MergeI->getOperand(Idx + 1).getReg());
|
||||
|
||||
for (unsigned j = 0; j < NumMergeRegs; ++j)
|
||||
Builder.buildInstr(ConvertOp, {DstRegs[j]}, {TmpRegs[j]});
|
||||
} else {
|
||||
Builder.buildUnmerge(DstRegs, MergeI->getOperand(Idx + 1).getReg());
|
||||
}
|
||||
}
|
||||
|
||||
} else if (NumMergeRegs > NumDefs) {
|
||||
|
@ -200,6 +200,13 @@ class LegalizerHelper {
|
||||
LegalizeResult moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT MoreTy);
|
||||
|
||||
LegalizeResult fewerElementsVectorUnmergeValues(MachineInstr &MI,
|
||||
unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
LegalizeResult fewerElementsVectorBuildVector(MachineInstr &MI,
|
||||
unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
|
||||
LegalizeResult
|
||||
reduceLoadStoreWidth(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy);
|
||||
|
||||
@ -219,9 +226,17 @@ class LegalizerHelper {
|
||||
LegalizeResult lowerU64ToF32BitOps(MachineInstr &MI);
|
||||
LegalizeResult lowerUITOFP(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult lowerSITOFP(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult lowerFPTOUI(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult lowerMinMax(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult lowerFCopySign(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult lowerFMinNumMaxNum(MachineInstr &MI);
|
||||
LegalizeResult lowerFMad(MachineInstr &MI);
|
||||
LegalizeResult lowerUnmergeValues(MachineInstr &MI);
|
||||
LegalizeResult lowerShuffleVector(MachineInstr &MI);
|
||||
LegalizeResult lowerDynStackAlloc(MachineInstr &MI);
|
||||
LegalizeResult lowerExtract(MachineInstr &MI);
|
||||
LegalizeResult lowerInsert(MachineInstr &MI);
|
||||
LegalizeResult lowerSADDO_SSUBO(MachineInstr &MI);
|
||||
|
||||
private:
|
||||
MachineRegisterInfo &MRI;
|
||||
@ -236,6 +251,11 @@ createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
|
||||
const CallLowering::ArgInfo &Result,
|
||||
ArrayRef<CallLowering::ArgInfo> Args);
|
||||
|
||||
/// Create a libcall to memcpy et al.
|
||||
LegalizerHelper::LegalizeResult createMemLibcall(MachineIRBuilder &MIRBuilder,
|
||||
MachineRegisterInfo &MRI,
|
||||
MachineInstr &MI);
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
|
@ -331,6 +331,8 @@ class LegalizeRuleSet {
|
||||
/// individually handled.
|
||||
SmallBitVector TypeIdxsCovered{MCOI::OPERAND_LAST_GENERIC -
|
||||
MCOI::OPERAND_FIRST_GENERIC + 2};
|
||||
SmallBitVector ImmIdxsCovered{MCOI::OPERAND_LAST_GENERIC_IMM -
|
||||
MCOI::OPERAND_FIRST_GENERIC_IMM + 2};
|
||||
#endif
|
||||
|
||||
unsigned typeIdx(unsigned TypeIdx) {
|
||||
@ -342,9 +344,21 @@ class LegalizeRuleSet {
|
||||
#endif
|
||||
return TypeIdx;
|
||||
}
|
||||
void markAllTypeIdxsAsCovered() {
|
||||
|
||||
unsigned immIdx(unsigned ImmIdx) {
|
||||
assert(ImmIdx <= (MCOI::OPERAND_LAST_GENERIC_IMM -
|
||||
MCOI::OPERAND_FIRST_GENERIC_IMM) &&
|
||||
"Imm Index is out of bounds");
|
||||
#ifndef NDEBUG
|
||||
ImmIdxsCovered.set(ImmIdx);
|
||||
#endif
|
||||
return ImmIdx;
|
||||
}
|
||||
|
||||
void markAllIdxsAsCovered() {
|
||||
#ifndef NDEBUG
|
||||
TypeIdxsCovered.set();
|
||||
ImmIdxsCovered.set();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -403,6 +417,15 @@ class LegalizeRuleSet {
|
||||
return actionIf(Action, typePairInSet(typeIdx(0), typeIdx(1), Types),
|
||||
Mutation);
|
||||
}
|
||||
/// Use the given action when type index 0 is any type in the given list and
|
||||
/// imm index 0 is anything. Action should not be an action that requires
|
||||
/// mutation.
|
||||
LegalizeRuleSet &actionForTypeWithAnyImm(LegalizeAction Action,
|
||||
std::initializer_list<LLT> Types) {
|
||||
using namespace LegalityPredicates;
|
||||
immIdx(0); // Inform verifier imm idx 0 is handled.
|
||||
return actionIf(Action, typeInSet(typeIdx(0), Types));
|
||||
}
|
||||
/// Use the given action when type indexes 0 and 1 are both in the given list.
|
||||
/// That is, the type pair is in the cartesian product of the list.
|
||||
/// Action should not be an action that requires mutation.
|
||||
@ -454,7 +477,7 @@ class LegalizeRuleSet {
|
||||
LegalizeRuleSet &legalIf(LegalityPredicate Predicate) {
|
||||
// We have no choice but conservatively assume that the free-form
|
||||
// user-provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Legal, Predicate);
|
||||
}
|
||||
/// The instruction is legal when type index 0 is any type in the given list.
|
||||
@ -466,6 +489,12 @@ class LegalizeRuleSet {
|
||||
LegalizeRuleSet &legalFor(std::initializer_list<std::pair<LLT, LLT>> Types) {
|
||||
return actionFor(LegalizeAction::Legal, Types);
|
||||
}
|
||||
/// The instruction is legal when type index 0 is any type in the given list
|
||||
/// and imm index 0 is anything.
|
||||
LegalizeRuleSet &legalForTypeWithAnyImm(std::initializer_list<LLT> Types) {
|
||||
markAllIdxsAsCovered();
|
||||
return actionForTypeWithAnyImm(LegalizeAction::Legal, Types);
|
||||
}
|
||||
/// The instruction is legal when type indexes 0 and 1 along with the memory
|
||||
/// size and minimum alignment is any type and size tuple in the given list.
|
||||
LegalizeRuleSet &legalForTypesWithMemDesc(
|
||||
@ -497,7 +526,7 @@ class LegalizeRuleSet {
|
||||
|
||||
LegalizeRuleSet &alwaysLegal() {
|
||||
using namespace LegalizeMutations;
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Legal, always);
|
||||
}
|
||||
|
||||
@ -506,7 +535,7 @@ class LegalizeRuleSet {
|
||||
using namespace LegalizeMutations;
|
||||
// We have no choice but conservatively assume that predicate-less lowering
|
||||
// properly handles all type indices by design:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Lower, always);
|
||||
}
|
||||
/// The instruction is lowered if predicate is true. Keep type index 0 as the
|
||||
@ -515,7 +544,7 @@ class LegalizeRuleSet {
|
||||
using namespace LegalizeMutations;
|
||||
// We have no choice but conservatively assume that lowering with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Lower, Predicate);
|
||||
}
|
||||
/// The instruction is lowered if predicate is true.
|
||||
@ -523,7 +552,7 @@ class LegalizeRuleSet {
|
||||
LegalizeMutation Mutation) {
|
||||
// We have no choice but conservatively assume that lowering with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Lower, Predicate, Mutation);
|
||||
}
|
||||
/// The instruction is lowered when type index 0 is any type in the given
|
||||
@ -571,7 +600,7 @@ class LegalizeRuleSet {
|
||||
LegalizeRuleSet &libcallIf(LegalityPredicate Predicate) {
|
||||
// We have no choice but conservatively assume that a libcall with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Libcall, Predicate);
|
||||
}
|
||||
LegalizeRuleSet &libcallFor(std::initializer_list<LLT> Types) {
|
||||
@ -597,7 +626,7 @@ class LegalizeRuleSet {
|
||||
LegalizeMutation Mutation) {
|
||||
// We have no choice but conservatively assume that an action with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::WidenScalar, Predicate, Mutation);
|
||||
}
|
||||
/// Narrow the scalar to the one selected by the mutation if the predicate is
|
||||
@ -606,7 +635,7 @@ class LegalizeRuleSet {
|
||||
LegalizeMutation Mutation) {
|
||||
// We have no choice but conservatively assume that an action with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::NarrowScalar, Predicate, Mutation);
|
||||
}
|
||||
|
||||
@ -616,7 +645,7 @@ class LegalizeRuleSet {
|
||||
LegalizeMutation Mutation) {
|
||||
// We have no choice but conservatively assume that an action with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::MoreElements, Predicate, Mutation);
|
||||
}
|
||||
/// Remove elements to reach the type selected by the mutation if the
|
||||
@ -625,7 +654,7 @@ class LegalizeRuleSet {
|
||||
LegalizeMutation Mutation) {
|
||||
// We have no choice but conservatively assume that an action with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::FewerElements, Predicate, Mutation);
|
||||
}
|
||||
|
||||
@ -640,11 +669,15 @@ class LegalizeRuleSet {
|
||||
return actionIf(LegalizeAction::Unsupported,
|
||||
LegalityPredicates::memSizeInBytesNotPow2(0));
|
||||
}
|
||||
LegalizeRuleSet &lowerIfMemSizeNotPow2() {
|
||||
return actionIf(LegalizeAction::Lower,
|
||||
LegalityPredicates::memSizeInBytesNotPow2(0));
|
||||
}
|
||||
|
||||
LegalizeRuleSet &customIf(LegalityPredicate Predicate) {
|
||||
// We have no choice but conservatively assume that a custom action with a
|
||||
// free-form user provided Predicate properly handles all type indices:
|
||||
markAllTypeIdxsAsCovered();
|
||||
markAllIdxsAsCovered();
|
||||
return actionIf(LegalizeAction::Custom, Predicate);
|
||||
}
|
||||
LegalizeRuleSet &customFor(std::initializer_list<LLT> Types) {
|
||||
@ -882,6 +915,10 @@ class LegalizeRuleSet {
|
||||
/// LegalizeRuleSet in any way at all.
|
||||
/// \pre Type indices of the opcode form a dense [0, \p NumTypeIdxs) set.
|
||||
bool verifyTypeIdxsCoverage(unsigned NumTypeIdxs) const;
|
||||
/// Check if there is no imm index which is obviously not handled by the
|
||||
/// LegalizeRuleSet in any way at all.
|
||||
/// \pre Type indices of the opcode form a dense [0, \p NumTypeIdxs) set.
|
||||
bool verifyImmIdxsCoverage(unsigned NumImmIdxs) const;
|
||||
|
||||
/// Apply the ruleset to the given LegalityQuery.
|
||||
LegalizeActionStep apply(const LegalityQuery &Query) const;
|
||||
|
@ -21,7 +21,7 @@ namespace llvm {
|
||||
namespace MIPatternMatch {
|
||||
|
||||
template <typename Reg, typename Pattern>
|
||||
bool mi_match(Reg R, MachineRegisterInfo &MRI, Pattern &&P) {
|
||||
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) {
|
||||
return P.match(MRI, R);
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ template <typename SubPatternT> struct OneUse_match {
|
||||
SubPatternT SubPat;
|
||||
OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
|
||||
|
||||
bool match(MachineRegisterInfo &MRI, unsigned Reg) {
|
||||
bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
|
||||
return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
|
||||
}
|
||||
};
|
||||
@ -71,7 +71,7 @@ inline operand_type_match m_Reg() { return operand_type_match(); }
|
||||
/// Matching combinators.
|
||||
template <typename... Preds> struct And {
|
||||
template <typename MatchSrc>
|
||||
bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -83,14 +83,14 @@ struct And<Pred, Preds...> : And<Preds...> {
|
||||
: And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
|
||||
}
|
||||
template <typename MatchSrc>
|
||||
bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return P.match(MRI, src) && And<Preds...>::match(MRI, src);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Preds> struct Or {
|
||||
template <typename MatchSrc>
|
||||
bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@ -101,7 +101,7 @@ struct Or<Pred, Preds...> : Or<Preds...> {
|
||||
Or(Pred &&p, Preds &&... preds)
|
||||
: Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
|
||||
template <typename MatchSrc>
|
||||
bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
|
||||
}
|
||||
};
|
||||
@ -175,7 +175,8 @@ struct BinaryOp_match {
|
||||
RHS_P R;
|
||||
|
||||
BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
|
||||
template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
|
||||
if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
|
||||
@ -242,7 +243,8 @@ template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
|
||||
SrcTy L;
|
||||
|
||||
UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
|
||||
template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
|
||||
if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
|
||||
@ -323,7 +325,7 @@ struct CheckType {
|
||||
LLT Ty;
|
||||
CheckType(const LLT &Ty) : Ty(Ty) {}
|
||||
|
||||
bool match(MachineRegisterInfo &MRI, unsigned Reg) {
|
||||
bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
|
||||
return MRI.getType(Reg) == Ty;
|
||||
}
|
||||
};
|
||||
|
@ -122,14 +122,22 @@ class SrcOp {
|
||||
MachineInstrBuilder SrcMIB;
|
||||
Register Reg;
|
||||
CmpInst::Predicate Pred;
|
||||
int64_t Imm;
|
||||
};
|
||||
|
||||
public:
|
||||
enum class SrcType { Ty_Reg, Ty_MIB, Ty_Predicate };
|
||||
enum class SrcType { Ty_Reg, Ty_MIB, Ty_Predicate, Ty_Imm };
|
||||
SrcOp(Register R) : Reg(R), Ty(SrcType::Ty_Reg) {}
|
||||
SrcOp(const MachineOperand &Op) : Reg(Op.getReg()), Ty(SrcType::Ty_Reg) {}
|
||||
SrcOp(const MachineInstrBuilder &MIB) : SrcMIB(MIB), Ty(SrcType::Ty_MIB) {}
|
||||
SrcOp(const CmpInst::Predicate P) : Pred(P), Ty(SrcType::Ty_Predicate) {}
|
||||
/// Use of registers held in unsigned integer variables (or more rarely signed
|
||||
/// integers) is no longer permitted to avoid ambiguity with upcoming support
|
||||
/// for immediates.
|
||||
SrcOp(unsigned) = delete;
|
||||
SrcOp(int) = delete;
|
||||
SrcOp(uint64_t V) : Imm(V), Ty(SrcType::Ty_Imm) {}
|
||||
SrcOp(int64_t V) : Imm(V), Ty(SrcType::Ty_Imm) {}
|
||||
|
||||
void addSrcToMIB(MachineInstrBuilder &MIB) const {
|
||||
switch (Ty) {
|
||||
@ -142,12 +150,16 @@ class SrcOp {
|
||||
case SrcType::Ty_MIB:
|
||||
MIB.addUse(SrcMIB->getOperand(0).getReg());
|
||||
break;
|
||||
case SrcType::Ty_Imm:
|
||||
MIB.addImm(Imm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LLT getLLTTy(const MachineRegisterInfo &MRI) const {
|
||||
switch (Ty) {
|
||||
case SrcType::Ty_Predicate:
|
||||
case SrcType::Ty_Imm:
|
||||
llvm_unreachable("Not a register operand");
|
||||
case SrcType::Ty_Reg:
|
||||
return MRI.getType(Reg);
|
||||
@ -160,6 +172,7 @@ class SrcOp {
|
||||
Register getReg() const {
|
||||
switch (Ty) {
|
||||
case SrcType::Ty_Predicate:
|
||||
case SrcType::Ty_Imm:
|
||||
llvm_unreachable("Not a register operand");
|
||||
case SrcType::Ty_Reg:
|
||||
return Reg;
|
||||
@ -178,6 +191,15 @@ class SrcOp {
|
||||
}
|
||||
}
|
||||
|
||||
int64_t getImm() const {
|
||||
switch (Ty) {
|
||||
case SrcType::Ty_Imm:
|
||||
return Imm;
|
||||
default:
|
||||
llvm_unreachable("Not an immediate");
|
||||
}
|
||||
}
|
||||
|
||||
SrcType getSrcOpKind() const { return Ty; }
|
||||
|
||||
private:
|
||||
@ -348,6 +370,17 @@ class MachineIRBuilder {
|
||||
/// given. Convert "llvm.dbg.label Label" to "DBG_LABEL Label".
|
||||
MachineInstrBuilder buildDbgLabel(const MDNode *Label);
|
||||
|
||||
/// Build and insert \p Res = G_DYN_STACKALLOC \p Size, \p Align
|
||||
///
|
||||
/// G_DYN_STACKALLOC does a dynamic stack allocation and writes the address of
|
||||
/// the allocated memory into \p Res.
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res must be a generic virtual register with pointer type.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildDynStackAlloc(const DstOp &Res, const SrcOp &Size,
|
||||
unsigned Align);
|
||||
|
||||
/// Build and insert \p Res = G_FRAME_INDEX \p Idx
|
||||
///
|
||||
/// G_FRAME_INDEX materializes the address of an alloca value or other
|
||||
@ -489,11 +522,21 @@ class MachineIRBuilder {
|
||||
return buildInstr(TargetOpcode::G_PTRTOINT, {Dst}, {Src});
|
||||
}
|
||||
|
||||
/// Build and insert a G_INTTOPTR instruction.
|
||||
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src) {
|
||||
return buildInstr(TargetOpcode::G_INTTOPTR, {Dst}, {Src});
|
||||
}
|
||||
|
||||
/// Build and insert \p Dst = G_BITCAST \p Src
|
||||
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src) {
|
||||
return buildInstr(TargetOpcode::G_BITCAST, {Dst}, {Src});
|
||||
}
|
||||
|
||||
/// Build and insert \p Dst = G_ADDRSPACE_CAST \p Src
|
||||
MachineInstrBuilder buildAddrSpaceCast(const DstOp &Dst, const SrcOp &Src) {
|
||||
return buildInstr(TargetOpcode::G_ADDRSPACE_CAST, {Dst}, {Src});
|
||||
}
|
||||
|
||||
/// \return The opcode of the extension the target wants to use for boolean
|
||||
/// values.
|
||||
unsigned getBoolExtOp(bool IsVec, bool IsFP) const;
|
||||
@ -867,7 +910,8 @@ class MachineIRBuilder {
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildFCmp(CmpInst::Predicate Pred, const DstOp &Res,
|
||||
const SrcOp &Op0, const SrcOp &Op1);
|
||||
const SrcOp &Op0, const SrcOp &Op1,
|
||||
Optional<unsigned> Flags = None);
|
||||
|
||||
/// Build and insert a \p Res = G_SELECT \p Tst, \p Op0, \p Op1
|
||||
///
|
||||
@ -880,7 +924,8 @@ class MachineIRBuilder {
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst,
|
||||
const SrcOp &Op0, const SrcOp &Op1);
|
||||
const SrcOp &Op0, const SrcOp &Op1,
|
||||
Optional<unsigned> Flags = None);
|
||||
|
||||
/// Build and insert \p Res = G_INSERT_VECTOR_ELT \p Val,
|
||||
/// \p Elt, \p Idx
|
||||
@ -961,8 +1006,8 @@ class MachineIRBuilder {
|
||||
/// same type.
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildAtomicRMW(unsigned Opcode, Register OldValRes,
|
||||
Register Addr, Register Val,
|
||||
MachineInstrBuilder buildAtomicRMW(unsigned Opcode, const DstOp &OldValRes,
|
||||
const SrcOp &Addr, const SrcOp &Val,
|
||||
MachineMemOperand &MMO);
|
||||
|
||||
/// Build and insert `OldValRes<def> = G_ATOMICRMW_XCHG Addr, Val, MMO`.
|
||||
@ -1135,6 +1180,16 @@ class MachineIRBuilder {
|
||||
MachineInstrBuilder buildAtomicRMWUmin(Register OldValRes, Register Addr,
|
||||
Register Val, MachineMemOperand &MMO);
|
||||
|
||||
/// Build and insert `OldValRes<def> = G_ATOMICRMW_FADD Addr, Val, MMO`.
|
||||
MachineInstrBuilder buildAtomicRMWFAdd(
|
||||
const DstOp &OldValRes, const SrcOp &Addr, const SrcOp &Val,
|
||||
MachineMemOperand &MMO);
|
||||
|
||||
/// Build and insert `OldValRes<def> = G_ATOMICRMW_FSUB Addr, Val, MMO`.
|
||||
MachineInstrBuilder buildAtomicRMWFSub(
|
||||
const DstOp &OldValRes, const SrcOp &Addr, const SrcOp &Val,
|
||||
MachineMemOperand &MMO);
|
||||
|
||||
/// Build and insert `G_FENCE Ordering, Scope`.
|
||||
MachineInstrBuilder buildFence(unsigned Ordering, unsigned Scope);
|
||||
|
||||
@ -1210,6 +1265,12 @@ class MachineIRBuilder {
|
||||
return buildInstr(TargetOpcode::G_SMULH, {Dst}, {Src0, Src1}, Flags);
|
||||
}
|
||||
|
||||
MachineInstrBuilder buildFMul(const DstOp &Dst, const SrcOp &Src0,
|
||||
const SrcOp &Src1,
|
||||
Optional<unsigned> Flags = None) {
|
||||
return buildInstr(TargetOpcode::G_FMUL, {Dst}, {Src0, Src1}, Flags);
|
||||
}
|
||||
|
||||
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0,
|
||||
const SrcOp &Src1,
|
||||
Optional<unsigned> Flags = None) {
|
||||
@ -1300,8 +1361,9 @@ class MachineIRBuilder {
|
||||
|
||||
/// Build and insert \p Res = G_FADD \p Op0, \p Op1
|
||||
MachineInstrBuilder buildFAdd(const DstOp &Dst, const SrcOp &Src0,
|
||||
const SrcOp &Src1) {
|
||||
return buildInstr(TargetOpcode::G_FADD, {Dst}, {Src0, Src1});
|
||||
const SrcOp &Src1,
|
||||
Optional<unsigned> Flags = None) {
|
||||
return buildInstr(TargetOpcode::G_FADD, {Dst}, {Src0, Src1}, Flags);
|
||||
}
|
||||
|
||||
/// Build and insert \p Res = G_FSUB \p Op0, \p Op1
|
||||
@ -1316,14 +1378,23 @@ class MachineIRBuilder {
|
||||
return buildInstr(TargetOpcode::G_FMA, {Dst}, {Src0, Src1, Src2});
|
||||
}
|
||||
|
||||
/// Build and insert \p Res = G_FMAD \p Op0, \p Op1, \p Op2
|
||||
MachineInstrBuilder buildFMAD(const DstOp &Dst, const SrcOp &Src0,
|
||||
const SrcOp &Src1, const SrcOp &Src2,
|
||||
Optional<unsigned> Flags = None) {
|
||||
return buildInstr(TargetOpcode::G_FMAD, {Dst}, {Src0, Src1, Src2}, Flags);
|
||||
}
|
||||
|
||||
/// Build and insert \p Res = G_FNEG \p Op0
|
||||
MachineInstrBuilder buildFNeg(const DstOp &Dst, const SrcOp &Src0) {
|
||||
return buildInstr(TargetOpcode::G_FNEG, {Dst}, {Src0});
|
||||
MachineInstrBuilder buildFNeg(const DstOp &Dst, const SrcOp &Src0,
|
||||
Optional<unsigned> Flags = None) {
|
||||
return buildInstr(TargetOpcode::G_FNEG, {Dst}, {Src0}, Flags);
|
||||
}
|
||||
|
||||
/// Build and insert \p Res = G_FABS \p Op0
|
||||
MachineInstrBuilder buildFAbs(const DstOp &Dst, const SrcOp &Src0) {
|
||||
return buildInstr(TargetOpcode::G_FABS, {Dst}, {Src0});
|
||||
MachineInstrBuilder buildFAbs(const DstOp &Dst, const SrcOp &Src0,
|
||||
Optional<unsigned> Flags = None) {
|
||||
return buildInstr(TargetOpcode::G_FABS, {Dst}, {Src0}, Flags);
|
||||
}
|
||||
|
||||
/// Build and insert \p Dst = G_FCANONICALIZE \p Src0
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user