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:
Dimitry Andric 2019-10-23 17:51:42 +00:00
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
2118 changed files with 120930 additions and 48978 deletions

View File

@ -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,

View File

@ -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.

View File

@ -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.
*

View 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);

View File

@ -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);

View File

@ -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
*/

View File

@ -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,

View File

@ -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

View File

@ -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)) {}

View File

@ -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;

View File

@ -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;
}
};

View File

@ -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; }

View 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

View File

@ -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>

View File

@ -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.

View File

@ -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);
}

View File

@ -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()));

View File

@ -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),

View File

@ -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())

View File

@ -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);

View File

@ -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) {

View File

@ -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

View File

@ -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)

View File

@ -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>

View File

@ -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);
}

View File

@ -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

View File

@ -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.

View File

@ -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); }

View File

@ -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;
}

View File

@ -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.
///

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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
View 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

View File

@ -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)

View 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

View File

@ -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;
};

View File

@ -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

View File

@ -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.
///

View File

@ -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);
}
};

View File

@ -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

View File

@ -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);

View File

@ -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

View 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

View File

@ -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;

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
};

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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())

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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; }

View File

@ -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> {

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -30,6 +30,7 @@ enum CurStreamTypeType {
LLVMIRBitstream,
ClangSerializedASTBitstream,
ClangSerializedDiagnosticsBitstream,
LLVMBitstreamRemarks
};
struct BCDumpOptions {

View File

@ -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

View File

@ -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());
}

View File

@ -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; }

View File

@ -101,8 +101,6 @@
///
/// An Apple Accelerator Table can be serialized by calling emitAppleAccelTable
/// function.
///
/// TODO: Add DWARF v5 emission code.
namespace llvm {

View File

@ -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.

View File

@ -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;

View File

@ -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.

View File

@ -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();

View File

@ -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()));
}

View File

@ -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),

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View 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

View File

@ -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:

View File

@ -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 =

View File

@ -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;
}

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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;
}
};

View File

@ -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