mirror of
https://github.com/opnsense/src.git
synced 2026-06-04 14:26:03 -04:00
Vendor import of llvm trunk r301441:
https://llvm.org/svn/llvm-project/llvm/trunk@301441
This commit is contained in:
parent
d99dafe2e4
commit
12f3ca4cdb
623 changed files with 150986 additions and 64519 deletions
|
|
@ -222,6 +222,13 @@ if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 )
|
|||
endif( LLVM_BUILD_32_BITS )
|
||||
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 )
|
||||
|
||||
# If building on a GNU specific 32-bit system, make sure off_t is 64 bits
|
||||
# so that off_t can stored offset > 2GB
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 4 )
|
||||
add_definitions( -D_LARGEFILE_SOURCE )
|
||||
add_definitions( -D_FILE_OFFSET_BITS=64 )
|
||||
endif()
|
||||
|
||||
if( XCODE )
|
||||
# For Xcode enable several build settings that correspond to
|
||||
# many warnings that are on by default in Clang but are
|
||||
|
|
|
|||
|
|
@ -82,9 +82,8 @@ handler as follows:
|
|||
=============== ============= ===============================================
|
||||
Usage Code Sequence Description
|
||||
=============== ============= ===============================================
|
||||
llvm.trap s_endpgm Causes wavefront to be terminated.
|
||||
llvm.debugtrap s_nop No operation. Compiler warning generated that
|
||||
there is no trap handler installed.
|
||||
llvm.trap s_endpgm Causes wavefront to be terminated.
|
||||
llvm.debugtrap Nothing. Compiler warning generated that there is no trap handler installed.
|
||||
=============== ============= ===============================================
|
||||
|
||||
Assembler
|
||||
|
|
|
|||
|
|
@ -171,6 +171,8 @@ Linux PowerPC GCC, Clang
|
|||
Solaris V9 (Ultrasparc) GCC
|
||||
FreeBSD x86\ :sup:`1` GCC, Clang
|
||||
FreeBSD amd64 GCC, Clang
|
||||
NetBSD x86\ :sup:`1` GCC, Clang
|
||||
NetBSD amd64 GCC, Clang
|
||||
MacOS X\ :sup:`2` PowerPC GCC
|
||||
MacOS X x86 GCC, Clang
|
||||
Cygwin/Win32 x86\ :sup:`1, 3` GCC
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ Here are the steps you can follow to do so:
|
|||
* slaves are added to ``buildbot/osuosl/master/config/slaves.py``
|
||||
* builders are added to ``buildbot/osuosl/master/config/builders.py``
|
||||
|
||||
Please make sure your builder name and its builddir are unique through the file.
|
||||
|
||||
It is possible to whitelist email addresses to unconditionally receive notifications
|
||||
on build failure; for this you'll need to add an ``InformativeMailNotifier`` to
|
||||
``buildbot/osuosl/master/config/status.py``. This is particularly useful for the
|
||||
|
|
|
|||
|
|
@ -87,10 +87,16 @@ Some important things to remember about fuzz targets:
|
|||
* Usually, the narrower the target the better. E.g. if your target can parse several data formats, split it into several targets, one per format.
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
Fuzzer Usage
|
||||
------------
|
||||
|
||||
Next, build the libFuzzer library as a static archive, without any sanitizer
|
||||
Very recent versions of Clang (> April 20 2017) include libFuzzer,
|
||||
and no installation is necessary.
|
||||
In order to fuzz your binary, use the `-fsanitize=fuzzer` flag during the compilation::
|
||||
|
||||
clang -fsanitize=fuzzer,address mytarget.c
|
||||
|
||||
Otherwise, build the libFuzzer library as a static archive, without any sanitizer
|
||||
options. Note that the libFuzzer library contains the ``main()`` function:
|
||||
|
||||
.. code-block:: console
|
||||
|
|
@ -728,6 +734,7 @@ to crash on invalid inputs.
|
|||
Examples: regular expression matchers, text or binary format parsers, compression,
|
||||
network, crypto.
|
||||
|
||||
|
||||
Trophies
|
||||
========
|
||||
* GLIBC: https://sourceware.org/glibc/wiki/FuzzingLibc
|
||||
|
|
|
|||
|
|
@ -397,6 +397,12 @@ public:
|
|||
/// consider inserting before falling back to scientific
|
||||
/// notation. 0 means to always use scientific notation.
|
||||
///
|
||||
/// \param TruncateZero Indicate whether to remove the trailing zero in
|
||||
/// fraction part or not. Also setting this parameter to false forcing
|
||||
/// producing of output more similar to default printf behavior.
|
||||
/// Specifically the lower e is used as exponent delimiter and exponent
|
||||
/// always contains no less than two digits.
|
||||
///
|
||||
/// Number Precision MaxPadding Result
|
||||
/// ------ --------- ---------- ------
|
||||
/// 1.01E+4 5 2 10100
|
||||
|
|
@ -406,7 +412,7 @@ public:
|
|||
/// 1.01E-2 4 2 0.0101
|
||||
/// 1.01E-2 4 1 1.01E-2
|
||||
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
|
||||
unsigned FormatMaxPadding = 3) const;
|
||||
unsigned FormatMaxPadding = 3, bool TruncateZero = true) const;
|
||||
|
||||
/// If this value has an exact multiplicative inverse, store it in inv and
|
||||
/// return true.
|
||||
|
|
@ -649,7 +655,7 @@ public:
|
|||
bool isInteger() const;
|
||||
|
||||
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision,
|
||||
unsigned FormatMaxPadding) const;
|
||||
unsigned FormatMaxPadding, bool TruncateZero = true) const;
|
||||
|
||||
bool getExactInverse(APFloat *inv) const;
|
||||
|
||||
|
|
@ -1144,9 +1150,9 @@ public:
|
|||
APFloat &operator=(APFloat &&RHS) = default;
|
||||
|
||||
void toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision = 0,
|
||||
unsigned FormatMaxPadding = 3) const {
|
||||
unsigned FormatMaxPadding = 3, bool TruncateZero = true) const {
|
||||
APFLOAT_DISPATCH_ON_SEMANTICS(
|
||||
toString(Str, FormatPrecision, FormatMaxPadding));
|
||||
toString(Str, FormatPrecision, FormatMaxPadding, TruncateZero));
|
||||
}
|
||||
|
||||
void print(raw_ostream &) const;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ public:
|
|||
APINT_BITS_PER_WORD = APINT_WORD_SIZE * CHAR_BIT
|
||||
};
|
||||
|
||||
static const WordType WORD_MAX = ~WordType(0);
|
||||
|
||||
private:
|
||||
/// This union is used to store the integer value. When the
|
||||
/// integer bit-width <= 64, it uses VAL, otherwise it uses pVal.
|
||||
|
|
@ -90,6 +92,8 @@ private:
|
|||
|
||||
friend struct DenseMapAPIntKeyInfo;
|
||||
|
||||
friend class APSInt;
|
||||
|
||||
/// \brief Fast internal constructor
|
||||
///
|
||||
/// This constructor is used only internally for speed of construction of
|
||||
|
|
@ -134,15 +138,10 @@ private:
|
|||
/// zero'd out.
|
||||
APInt &clearUnusedBits() {
|
||||
// Compute how many bits are used in the final word
|
||||
unsigned wordBits = BitWidth % APINT_BITS_PER_WORD;
|
||||
if (wordBits == 0)
|
||||
// If all bits are used, we want to leave the value alone. This also
|
||||
// avoids the undefined behavior of >> when the shift is the same size as
|
||||
// the word size (64).
|
||||
return *this;
|
||||
unsigned WordBits = ((BitWidth-1) % APINT_BITS_PER_WORD) + 1;
|
||||
|
||||
// Mask out the high bits.
|
||||
uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - wordBits);
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - WordBits);
|
||||
if (isSingleWord())
|
||||
VAL &= mask;
|
||||
else
|
||||
|
|
@ -194,6 +193,9 @@ private:
|
|||
/// out-of-line slow case for lshr.
|
||||
void lshrSlowCase(unsigned ShiftAmt);
|
||||
|
||||
/// out-of-line slow case for ashr.
|
||||
void ashrSlowCase(unsigned ShiftAmt);
|
||||
|
||||
/// out-of-line slow case for operator=
|
||||
void AssignSlowCase(const APInt &RHS);
|
||||
|
||||
|
|
@ -230,6 +232,14 @@ private:
|
|||
/// out-of-line slow case for operator^=.
|
||||
void XorAssignSlowCase(const APInt& RHS);
|
||||
|
||||
/// Unsigned comparison. Returns -1, 0, or 1 if this APInt is less than, equal
|
||||
/// to, or greater than RHS.
|
||||
int compare(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// Signed comparison. Returns -1, 0, or 1 if this APInt is less than, equal
|
||||
/// to, or greater than RHS.
|
||||
int compareSigned(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
public:
|
||||
/// \name Constructors
|
||||
/// @{
|
||||
|
|
@ -363,7 +373,7 @@ public:
|
|||
/// This checks to see if the value has all bits of the APInt are set or not.
|
||||
bool isAllOnesValue() const {
|
||||
if (isSingleWord())
|
||||
return VAL == UINT64_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return VAL == WORD_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return countPopulationSlowCase() == BitWidth;
|
||||
}
|
||||
|
||||
|
|
@ -445,7 +455,7 @@ public:
|
|||
assert(numBits != 0 && "numBits must be non-zero");
|
||||
assert(numBits <= BitWidth && "numBits out of range");
|
||||
if (isSingleWord())
|
||||
return VAL == (UINT64_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
return VAL == (WORD_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
unsigned Ones = countTrailingOnesSlowCase();
|
||||
return (numBits == Ones) &&
|
||||
((Ones + countLeadingZerosSlowCase()) == BitWidth);
|
||||
|
|
@ -509,7 +519,7 @@ public:
|
|||
///
|
||||
/// \returns the all-ones value for an APInt of the specified bit-width.
|
||||
static APInt getAllOnesValue(unsigned numBits) {
|
||||
return APInt(numBits, UINT64_MAX, true);
|
||||
return APInt(numBits, WORD_MAX, true);
|
||||
}
|
||||
|
||||
/// \brief Get the '0' value.
|
||||
|
|
@ -886,7 +896,26 @@ public:
|
|||
/// \brief Arithmetic right-shift function.
|
||||
///
|
||||
/// Arithmetic right-shift this APInt by shiftAmt.
|
||||
APInt ashr(unsigned shiftAmt) const;
|
||||
APInt ashr(unsigned ShiftAmt) const {
|
||||
APInt R(*this);
|
||||
R.ashrInPlace(ShiftAmt);
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Arithmetic right-shift this APInt by ShiftAmt in place.
|
||||
void ashrInPlace(unsigned ShiftAmt) {
|
||||
assert(ShiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
int64_t SExtVAL = SignExtend64(VAL, BitWidth);
|
||||
if (ShiftAmt == BitWidth)
|
||||
VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // Fill with sign bit.
|
||||
else
|
||||
VAL = SExtVAL >> ShiftAmt;
|
||||
clearUnusedBits();
|
||||
return;
|
||||
}
|
||||
ashrSlowCase(ShiftAmt);
|
||||
}
|
||||
|
||||
/// \brief Logical right-shift function.
|
||||
///
|
||||
|
|
@ -928,7 +957,14 @@ public:
|
|||
/// \brief Arithmetic right-shift function.
|
||||
///
|
||||
/// Arithmetic right-shift this APInt by shiftAmt.
|
||||
APInt ashr(const APInt &shiftAmt) const;
|
||||
APInt ashr(const APInt &ShiftAmt) const {
|
||||
APInt R(*this);
|
||||
R.ashrInPlace(ShiftAmt);
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Arithmetic right-shift this APInt by shiftAmt in place.
|
||||
void ashrInPlace(const APInt &shiftAmt);
|
||||
|
||||
/// \brief Logical right-shift function.
|
||||
///
|
||||
|
|
@ -1079,7 +1115,7 @@ public:
|
|||
/// the validity of the less-than relationship.
|
||||
///
|
||||
/// \returns true if *this < RHS when both are considered unsigned.
|
||||
bool ult(const APInt &RHS) const LLVM_READONLY;
|
||||
bool ult(const APInt &RHS) const { return compare(RHS) < 0; }
|
||||
|
||||
/// \brief Unsigned less than comparison
|
||||
///
|
||||
|
|
@ -1098,7 +1134,7 @@ public:
|
|||
/// validity of the less-than relationship.
|
||||
///
|
||||
/// \returns true if *this < RHS when both are considered signed.
|
||||
bool slt(const APInt &RHS) const LLVM_READONLY;
|
||||
bool slt(const APInt &RHS) const { return compareSigned(RHS) < 0; }
|
||||
|
||||
/// \brief Signed less than comparison
|
||||
///
|
||||
|
|
@ -1117,7 +1153,7 @@ public:
|
|||
/// validity of the less-or-equal relationship.
|
||||
///
|
||||
/// \returns true if *this <= RHS when both are considered unsigned.
|
||||
bool ule(const APInt &RHS) const { return ult(RHS) || eq(RHS); }
|
||||
bool ule(const APInt &RHS) const { return compare(RHS) <= 0; }
|
||||
|
||||
/// \brief Unsigned less or equal comparison
|
||||
///
|
||||
|
|
@ -1133,7 +1169,7 @@ public:
|
|||
/// validity of the less-or-equal relationship.
|
||||
///
|
||||
/// \returns true if *this <= RHS when both are considered signed.
|
||||
bool sle(const APInt &RHS) const { return slt(RHS) || eq(RHS); }
|
||||
bool sle(const APInt &RHS) const { return compareSigned(RHS) <= 0; }
|
||||
|
||||
/// \brief Signed less or equal comparison
|
||||
///
|
||||
|
|
@ -1149,7 +1185,7 @@ public:
|
|||
/// the validity of the greater-than relationship.
|
||||
///
|
||||
/// \returns true if *this > RHS when both are considered unsigned.
|
||||
bool ugt(const APInt &RHS) const { return !ult(RHS) && !eq(RHS); }
|
||||
bool ugt(const APInt &RHS) const { return !ule(RHS); }
|
||||
|
||||
/// \brief Unsigned greater than comparison
|
||||
///
|
||||
|
|
@ -1168,7 +1204,7 @@ public:
|
|||
/// validity of the greater-than relationship.
|
||||
///
|
||||
/// \returns true if *this > RHS when both are considered signed.
|
||||
bool sgt(const APInt &RHS) const { return !slt(RHS) && !eq(RHS); }
|
||||
bool sgt(const APInt &RHS) const { return !sle(RHS); }
|
||||
|
||||
/// \brief Signed greater than comparison
|
||||
///
|
||||
|
|
@ -1286,7 +1322,7 @@ public:
|
|||
/// \brief Set every bit to 1.
|
||||
void setAllBits() {
|
||||
if (isSingleWord())
|
||||
VAL = UINT64_MAX;
|
||||
VAL = WORD_MAX;
|
||||
else
|
||||
// Set all the bits in all the words.
|
||||
memset(pVal, -1, getNumWords() * APINT_WORD_SIZE);
|
||||
|
|
@ -1316,7 +1352,7 @@ public:
|
|||
return;
|
||||
}
|
||||
if (loBit < APINT_BITS_PER_WORD && hiBit <= APINT_BITS_PER_WORD) {
|
||||
uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
|
||||
mask <<= loBit;
|
||||
if (isSingleWord())
|
||||
VAL |= mask;
|
||||
|
|
@ -1358,7 +1394,7 @@ public:
|
|||
/// \brief Toggle every bit to its opposite value.
|
||||
void flipAllBits() {
|
||||
if (isSingleWord()) {
|
||||
VAL ^= UINT64_MAX;
|
||||
VAL ^= WORD_MAX;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
flipAllBitsSlowCase();
|
||||
|
|
@ -1653,7 +1689,7 @@ public:
|
|||
/// referencing 2 in a space where 2 does no exist.
|
||||
unsigned nearestLogBase2() const {
|
||||
// Special case when we have a bitwidth of 1. If VAL is 1, then we
|
||||
// get 0. If VAL is 0, we get UINT64_MAX which gets truncated to
|
||||
// get 0. If VAL is 0, we get WORD_MAX which gets truncated to
|
||||
// UINT32_MAX.
|
||||
if (BitWidth == 1)
|
||||
return VAL - 1;
|
||||
|
|
|
|||
|
|
@ -125,7 +125,10 @@ public:
|
|||
return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false);
|
||||
}
|
||||
APSInt& operator>>=(unsigned Amt) {
|
||||
*this = *this >> Amt;
|
||||
if (IsUnsigned)
|
||||
lshrInPlace(Amt);
|
||||
else
|
||||
ashrInPlace(Amt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +182,7 @@ public:
|
|||
return APSInt(static_cast<const APInt&>(*this) << Bits, IsUnsigned);
|
||||
}
|
||||
APSInt& operator<<=(unsigned Amt) {
|
||||
*this = *this << Amt;
|
||||
static_cast<APInt&>(*this) <<= Amt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -285,12 +288,12 @@ public:
|
|||
/// \brief Compare underlying values of two numbers.
|
||||
static int compareValues(const APSInt &I1, const APSInt &I2) {
|
||||
if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned())
|
||||
return I1 == I2 ? 0 : I1 > I2 ? 1 : -1;
|
||||
return I1.IsUnsigned ? I1.compare(I2) : I1.compareSigned(I2);
|
||||
|
||||
// Check for a bit-width mismatch.
|
||||
if (I1.getBitWidth() > I2.getBitWidth())
|
||||
return compareValues(I1, I2.extend(I1.getBitWidth()));
|
||||
else if (I2.getBitWidth() > I1.getBitWidth())
|
||||
if (I2.getBitWidth() > I1.getBitWidth())
|
||||
return compareValues(I1.extend(I2.getBitWidth()), I2);
|
||||
|
||||
// We have a signedness mismatch. Check for negative values and do an
|
||||
|
|
@ -305,7 +308,7 @@ public:
|
|||
return 1;
|
||||
}
|
||||
|
||||
return I1.eq(I2) ? 0 : I1.ugt(I2) ? 1 : -1;
|
||||
return I1.compare(I2);
|
||||
}
|
||||
|
||||
static APSInt get(int64_t X) { return APSInt(APInt(64, X), false); }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#define LLVM_ADT_BITVECTOR_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
|
@ -35,9 +34,8 @@ class BitVector {
|
|||
static_assert(BITWORD_SIZE == 64 || BITWORD_SIZE == 32,
|
||||
"Unsupported word size");
|
||||
|
||||
BitWord *Bits; // Actual bits.
|
||||
unsigned Size; // Size of bitvector in bits.
|
||||
unsigned Capacity; // Number of BitWords allocated in the Bits array.
|
||||
MutableArrayRef<BitWord> Bits; // Actual bits.
|
||||
unsigned Size; // Size of bitvector in bits.
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
|
|
@ -77,16 +75,14 @@ public:
|
|||
|
||||
|
||||
/// BitVector default ctor - Creates an empty bitvector.
|
||||
BitVector() : Size(0), Capacity(0) {
|
||||
Bits = nullptr;
|
||||
}
|
||||
BitVector() : Size(0) {}
|
||||
|
||||
/// BitVector ctor - Creates a bitvector of specified number of bits. All
|
||||
/// bits are initialized to the specified value.
|
||||
explicit BitVector(unsigned s, bool t = false) : Size(s) {
|
||||
Capacity = NumBitWords(s);
|
||||
Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord));
|
||||
init_words(Bits, Capacity, t);
|
||||
size_t Capacity = NumBitWords(s);
|
||||
Bits = allocate(Capacity);
|
||||
init_words(Bits, t);
|
||||
if (t)
|
||||
clear_unused_bits();
|
||||
}
|
||||
|
|
@ -94,25 +90,21 @@ public:
|
|||
/// BitVector copy ctor.
|
||||
BitVector(const BitVector &RHS) : Size(RHS.size()) {
|
||||
if (Size == 0) {
|
||||
Bits = nullptr;
|
||||
Capacity = 0;
|
||||
Bits = MutableArrayRef<BitWord>();
|
||||
return;
|
||||
}
|
||||
|
||||
Capacity = NumBitWords(RHS.size());
|
||||
Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord));
|
||||
std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord));
|
||||
size_t Capacity = NumBitWords(RHS.size());
|
||||
Bits = allocate(Capacity);
|
||||
std::memcpy(Bits.data(), RHS.Bits.data(), Capacity * sizeof(BitWord));
|
||||
}
|
||||
|
||||
BitVector(BitVector &&RHS)
|
||||
: Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) {
|
||||
RHS.Bits = nullptr;
|
||||
RHS.Size = RHS.Capacity = 0;
|
||||
BitVector(BitVector &&RHS) : Bits(RHS.Bits), Size(RHS.Size) {
|
||||
RHS.Bits = MutableArrayRef<BitWord>();
|
||||
RHS.Size = 0;
|
||||
}
|
||||
|
||||
~BitVector() {
|
||||
std::free(Bits);
|
||||
}
|
||||
~BitVector() { std::free(Bits.data()); }
|
||||
|
||||
/// empty - Tests whether there are no bits in this bitvector.
|
||||
bool empty() const { return Size == 0; }
|
||||
|
|
@ -163,6 +155,22 @@ public:
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// find_last - Returns the index of the last set bit, -1 if none of the bits
|
||||
/// are set.
|
||||
int find_last() const {
|
||||
if (Size == 0)
|
||||
return -1;
|
||||
|
||||
unsigned N = NumBitWords(size());
|
||||
assert(N > 0);
|
||||
|
||||
unsigned i = N - 1;
|
||||
while (i > 0 && Bits[i] == BitWord(0))
|
||||
--i;
|
||||
|
||||
return int((i + 1) * BITWORD_SIZE - countLeadingZeros(Bits[i])) - 1;
|
||||
}
|
||||
|
||||
/// find_first_unset - Returns the index of the first unset bit, -1 if all
|
||||
/// of the bits are set.
|
||||
int find_first_unset() const {
|
||||
|
|
@ -174,6 +182,30 @@ public:
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// find_last_unset - Returns the index of the last unset bit, -1 if all of
|
||||
/// the bits are set.
|
||||
int find_last_unset() const {
|
||||
if (Size == 0)
|
||||
return -1;
|
||||
|
||||
const unsigned N = NumBitWords(size());
|
||||
assert(N > 0);
|
||||
|
||||
unsigned i = N - 1;
|
||||
BitWord W = Bits[i];
|
||||
|
||||
// The last word in the BitVector has some unused bits, so we need to set
|
||||
// them all to 1 first. Set them all to 1 so they don't get treated as
|
||||
// valid unset bits.
|
||||
unsigned UnusedCount = BITWORD_SIZE - size() % BITWORD_SIZE;
|
||||
W |= maskLeadingOnes<BitWord>(UnusedCount);
|
||||
|
||||
while (W == ~BitWord(0) && --i > 0)
|
||||
W = Bits[i];
|
||||
|
||||
return int((i + 1) * BITWORD_SIZE - countLeadingOnes(W)) - 1;
|
||||
}
|
||||
|
||||
/// find_next - Returns the index of the next set bit following the
|
||||
/// "Prev" bit. Returns -1 if the next set bit is not found.
|
||||
int find_next(unsigned Prev) const {
|
||||
|
|
@ -228,10 +260,10 @@ public:
|
|||
|
||||
/// resize - Grow or shrink the bitvector.
|
||||
void resize(unsigned N, bool t = false) {
|
||||
if (N > Capacity * BITWORD_SIZE) {
|
||||
unsigned OldCapacity = Capacity;
|
||||
if (N > getBitCapacity()) {
|
||||
unsigned OldCapacity = Bits.size();
|
||||
grow(N);
|
||||
init_words(&Bits[OldCapacity], (Capacity-OldCapacity), t);
|
||||
init_words(Bits.drop_front(OldCapacity), t);
|
||||
}
|
||||
|
||||
// Set any old unused bits that are now included in the BitVector. This
|
||||
|
|
@ -248,19 +280,19 @@ public:
|
|||
}
|
||||
|
||||
void reserve(unsigned N) {
|
||||
if (N > Capacity * BITWORD_SIZE)
|
||||
if (N > getBitCapacity())
|
||||
grow(N);
|
||||
}
|
||||
|
||||
// Set, reset, flip
|
||||
BitVector &set() {
|
||||
init_words(Bits, Capacity, true);
|
||||
init_words(Bits, true);
|
||||
clear_unused_bits();
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitVector &set(unsigned Idx) {
|
||||
assert(Bits && "Bits never allocated");
|
||||
assert(Bits.data() && "Bits never allocated");
|
||||
Bits[Idx / BITWORD_SIZE] |= BitWord(1) << (Idx % BITWORD_SIZE);
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -295,7 +327,7 @@ public:
|
|||
}
|
||||
|
||||
BitVector &reset() {
|
||||
init_words(Bits, Capacity, false);
|
||||
init_words(Bits, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -562,21 +594,21 @@ public:
|
|||
|
||||
Size = RHS.size();
|
||||
unsigned RHSWords = NumBitWords(Size);
|
||||
if (Size <= Capacity * BITWORD_SIZE) {
|
||||
if (Size <= getBitCapacity()) {
|
||||
if (Size)
|
||||
std::memcpy(Bits, RHS.Bits, RHSWords * sizeof(BitWord));
|
||||
std::memcpy(Bits.data(), RHS.Bits.data(), RHSWords * sizeof(BitWord));
|
||||
clear_unused_bits();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Grow the bitvector to have enough elements.
|
||||
Capacity = RHSWords;
|
||||
assert(Capacity > 0 && "negative capacity?");
|
||||
BitWord *NewBits = (BitWord *)std::malloc(Capacity * sizeof(BitWord));
|
||||
std::memcpy(NewBits, RHS.Bits, Capacity * sizeof(BitWord));
|
||||
unsigned NewCapacity = RHSWords;
|
||||
assert(NewCapacity > 0 && "negative capacity?");
|
||||
auto NewBits = allocate(NewCapacity);
|
||||
std::memcpy(NewBits.data(), RHS.Bits.data(), NewCapacity * sizeof(BitWord));
|
||||
|
||||
// Destroy the old bits.
|
||||
std::free(Bits);
|
||||
std::free(Bits.data());
|
||||
Bits = NewBits;
|
||||
|
||||
return *this;
|
||||
|
|
@ -585,13 +617,12 @@ public:
|
|||
const BitVector &operator=(BitVector &&RHS) {
|
||||
if (this == &RHS) return *this;
|
||||
|
||||
std::free(Bits);
|
||||
std::free(Bits.data());
|
||||
Bits = RHS.Bits;
|
||||
Size = RHS.Size;
|
||||
Capacity = RHS.Capacity;
|
||||
|
||||
RHS.Bits = nullptr;
|
||||
RHS.Size = RHS.Capacity = 0;
|
||||
RHS.Bits = MutableArrayRef<BitWord>();
|
||||
RHS.Size = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -599,7 +630,6 @@ public:
|
|||
void swap(BitVector &RHS) {
|
||||
std::swap(Bits, RHS.Bits);
|
||||
std::swap(Size, RHS.Size);
|
||||
std::swap(Capacity, RHS.Capacity);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
@ -659,14 +689,14 @@ private:
|
|||
|
||||
uint32_t NumWords = NumBitWords(Size);
|
||||
|
||||
auto Src = ArrayRef<BitWord>(Bits, NumWords).drop_back(Count);
|
||||
auto Dest = MutableArrayRef<BitWord>(Bits, NumWords).drop_front(Count);
|
||||
auto Src = Bits.take_front(NumWords).drop_back(Count);
|
||||
auto Dest = Bits.take_front(NumWords).drop_front(Count);
|
||||
|
||||
// Since we always move Word-sized chunks of data with src and dest both
|
||||
// aligned to a word-boundary, we don't need to worry about endianness
|
||||
// here.
|
||||
std::memmove(Dest.begin(), Src.begin(), Dest.size() * sizeof(BitWord));
|
||||
std::memset(Bits, 0, Count * sizeof(BitWord));
|
||||
std::memset(Bits.data(), 0, Count * sizeof(BitWord));
|
||||
clear_unused_bits();
|
||||
}
|
||||
|
||||
|
|
@ -679,14 +709,19 @@ private:
|
|||
|
||||
uint32_t NumWords = NumBitWords(Size);
|
||||
|
||||
auto Src = ArrayRef<BitWord>(Bits, NumWords).drop_front(Count);
|
||||
auto Dest = MutableArrayRef<BitWord>(Bits, NumWords).drop_back(Count);
|
||||
auto Src = Bits.take_front(NumWords).drop_front(Count);
|
||||
auto Dest = Bits.take_front(NumWords).drop_back(Count);
|
||||
assert(Dest.size() == Src.size());
|
||||
|
||||
std::memmove(Dest.begin(), Src.begin(), Dest.size() * sizeof(BitWord));
|
||||
std::memset(Dest.end(), 0, Count * sizeof(BitWord));
|
||||
}
|
||||
|
||||
MutableArrayRef<BitWord> allocate(size_t NumWords) {
|
||||
BitWord *RawBits = (BitWord *)std::malloc(NumWords * sizeof(BitWord));
|
||||
return MutableArrayRef<BitWord>(RawBits, NumWords);
|
||||
}
|
||||
|
||||
int next_unset_in_word(int WordIndex, BitWord Word) const {
|
||||
unsigned Result = WordIndex * BITWORD_SIZE + countTrailingOnes(Word);
|
||||
return Result < size() ? Result : -1;
|
||||
|
|
@ -700,8 +735,8 @@ private:
|
|||
void set_unused_bits(bool t = true) {
|
||||
// Set high words first.
|
||||
unsigned UsedWords = NumBitWords(Size);
|
||||
if (Capacity > UsedWords)
|
||||
init_words(&Bits[UsedWords], (Capacity-UsedWords), t);
|
||||
if (Bits.size() > UsedWords)
|
||||
init_words(Bits.drop_front(UsedWords), t);
|
||||
|
||||
// Then set any stray high bits of the last used word.
|
||||
unsigned ExtraBits = Size % BITWORD_SIZE;
|
||||
|
|
@ -720,16 +755,17 @@ private:
|
|||
}
|
||||
|
||||
void grow(unsigned NewSize) {
|
||||
Capacity = std::max(NumBitWords(NewSize), Capacity * 2);
|
||||
assert(Capacity > 0 && "realloc-ing zero space");
|
||||
Bits = (BitWord *)std::realloc(Bits, Capacity * sizeof(BitWord));
|
||||
|
||||
size_t NewCapacity = std::max<size_t>(NumBitWords(NewSize), Bits.size() * 2);
|
||||
assert(NewCapacity > 0 && "realloc-ing zero space");
|
||||
BitWord *NewBits =
|
||||
(BitWord *)std::realloc(Bits.data(), NewCapacity * sizeof(BitWord));
|
||||
Bits = MutableArrayRef<BitWord>(NewBits, NewCapacity);
|
||||
clear_unused_bits();
|
||||
}
|
||||
|
||||
void init_words(BitWord *B, unsigned NumWords, bool t) {
|
||||
if (NumWords > 0)
|
||||
memset(B, 0 - (int)t, NumWords*sizeof(BitWord));
|
||||
void init_words(MutableArrayRef<BitWord> B, bool t) {
|
||||
if (B.size() > 0)
|
||||
memset(B.data(), 0 - (int)t, B.size() * sizeof(BitWord));
|
||||
}
|
||||
|
||||
template<bool AddBits, bool InvertMask>
|
||||
|
|
@ -761,7 +797,8 @@ private:
|
|||
|
||||
public:
|
||||
/// Return the size (in bytes) of the bit vector.
|
||||
size_t getMemorySize() const { return Capacity * sizeof(BitWord); }
|
||||
size_t getMemorySize() const { return Bits.size() * sizeof(BitWord); }
|
||||
size_t getBitCapacity() const { return Bits.size() * BITWORD_SIZE; }
|
||||
};
|
||||
|
||||
static inline size_t capacity_in_bytes(const BitVector &X) {
|
||||
|
|
|
|||
|
|
@ -117,9 +117,7 @@ private:
|
|||
}
|
||||
|
||||
// Return the size.
|
||||
size_t getSmallSize() const {
|
||||
return getSmallRawBits() >> SmallNumDataBits;
|
||||
}
|
||||
size_t getSmallSize() const { return getSmallRawBits() >> SmallNumDataBits; }
|
||||
|
||||
void setSmallSize(size_t Size) {
|
||||
setSmallRawBits(getSmallBits() | (Size << SmallNumDataBits));
|
||||
|
|
@ -216,6 +214,16 @@ public:
|
|||
return getPointer()->find_first();
|
||||
}
|
||||
|
||||
int find_last() const {
|
||||
if (isSmall()) {
|
||||
uintptr_t Bits = getSmallBits();
|
||||
if (Bits == 0)
|
||||
return -1;
|
||||
return NumBaseBits - countLeadingZeros(Bits);
|
||||
}
|
||||
return getPointer()->find_last();
|
||||
}
|
||||
|
||||
/// Returns the index of the first unset bit, -1 if all of the bits are set.
|
||||
int find_first_unset() const {
|
||||
if (isSmall()) {
|
||||
|
|
@ -228,6 +236,17 @@ public:
|
|||
return getPointer()->find_first_unset();
|
||||
}
|
||||
|
||||
int find_last_unset() const {
|
||||
if (isSmall()) {
|
||||
if (count() == getSmallSize())
|
||||
return -1;
|
||||
|
||||
uintptr_t Bits = getSmallBits();
|
||||
return NumBaseBits - countLeadingOnes(Bits);
|
||||
}
|
||||
return getPointer()->find_last_unset();
|
||||
}
|
||||
|
||||
/// Returns the index of the next set bit following the "Prev" bit.
|
||||
/// Returns -1 if the next set bit is not found.
|
||||
int find_next(unsigned Prev) const {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,36 @@ static inline std::string toHex(StringRef Input) {
|
|||
return Output;
|
||||
}
|
||||
|
||||
static inline uint8_t hexFromNibbles(char MSB, char LSB) {
|
||||
unsigned U1 = hexDigitValue(MSB);
|
||||
unsigned U2 = hexDigitValue(LSB);
|
||||
assert(U1 != -1U && U2 != -1U);
|
||||
|
||||
return static_cast<uint8_t>((U1 << 4) | U2);
|
||||
}
|
||||
|
||||
/// Convert hexadecimal string \p Input to its binary representation.
|
||||
/// The return string is half the size of \p Input.
|
||||
static inline std::string fromHex(StringRef Input) {
|
||||
if (Input.empty())
|
||||
return std::string();
|
||||
|
||||
std::string Output;
|
||||
Output.reserve((Input.size() + 1) / 2);
|
||||
if (Input.size() % 2 == 1) {
|
||||
Output.push_back(hexFromNibbles('0', Input.front()));
|
||||
Input = Input.drop_front();
|
||||
}
|
||||
|
||||
assert(Input.size() % 2 == 0);
|
||||
while (!Input.empty()) {
|
||||
uint8_t Hex = hexFromNibbles(Input[0], Input[1]);
|
||||
Output.push_back(Hex);
|
||||
Input = Input.drop_front(2);
|
||||
}
|
||||
return Output;
|
||||
}
|
||||
|
||||
static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
||||
char Buffer[21];
|
||||
char *BufPtr = std::end(Buffer);
|
||||
|
|
|
|||
|
|
@ -140,7 +140,8 @@ public:
|
|||
Myriad,
|
||||
AMD,
|
||||
Mesa,
|
||||
LastVendorType = Mesa
|
||||
SUSE,
|
||||
LastVendorType = SUSE
|
||||
};
|
||||
enum OSType {
|
||||
UnknownOS,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class Function;
|
|||
class Instruction;
|
||||
class DominatorTree;
|
||||
class AssumptionCache;
|
||||
struct KnownBits;
|
||||
|
||||
class DemandedBits {
|
||||
public:
|
||||
|
|
@ -58,8 +59,7 @@ private:
|
|||
void determineLiveOperandBits(const Instruction *UserI,
|
||||
const Instruction *I, unsigned OperandNo,
|
||||
const APInt &AOut, APInt &AB,
|
||||
APInt &KnownZero, APInt &KnownOne,
|
||||
APInt &KnownZero2, APInt &KnownOne2);
|
||||
KnownBits &Known, KnownBits &Known2);
|
||||
|
||||
bool Analyzed;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,32 @@ namespace llvm {
|
|||
class Type;
|
||||
class Value;
|
||||
|
||||
struct SimplifyQuery {
|
||||
const DataLayout &DL;
|
||||
const TargetLibraryInfo *TLI = nullptr;
|
||||
const DominatorTree *DT = nullptr;
|
||||
AssumptionCache *AC = nullptr;
|
||||
const Instruction *CxtI = nullptr;
|
||||
SimplifyQuery(const DataLayout &DL) : DL(DL) {}
|
||||
|
||||
SimplifyQuery(const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
const DominatorTree *DT, AssumptionCache *AC = nullptr,
|
||||
const Instruction *CXTI = nullptr)
|
||||
: DL(DL), TLI(TLI), DT(DT), AC(AC), CxtI(CXTI) {}
|
||||
SimplifyQuery getWithInstruction(Instruction *I) const {
|
||||
SimplifyQuery Copy(*this);
|
||||
Copy.CxtI = I;
|
||||
return Copy;
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: the explicit multiple argument versions of these functions are
|
||||
// deprecated.
|
||||
// Please use the SimplifyQuery versions in new code.
|
||||
|
||||
/// Given operands for an Add, fold the result or return null.
|
||||
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -56,6 +81,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a Sub, fold the result or return null.
|
||||
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -64,6 +91,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FAdd, fold the result or return null.
|
||||
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -72,6 +101,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FSub, fold the result or return null.
|
||||
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -80,6 +111,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FMul, fold the result or return null.
|
||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -88,6 +121,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a Mul, fold the result or return null.
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifyMulInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -95,6 +129,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an SDiv, fold the result or return null.
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifySDivInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -102,6 +137,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a UDiv, fold the result or return null.
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifyUDivInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -109,6 +145,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FDiv, fold the result or return null.
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -117,6 +155,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an SRem, fold the result or return null.
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifySRemInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -124,6 +163,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a URem, fold the result or return null.
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifyURemInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -131,6 +171,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FRem, fold the result or return null.
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -139,6 +181,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a Shl, fold the result or return null.
|
||||
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -147,6 +191,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a LShr, fold the result or return null.
|
||||
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -155,6 +201,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a AShr, fold the result or return nulll.
|
||||
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -163,6 +211,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an And, fold the result or return null.
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifyAndInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -170,6 +219,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an Or, fold the result or return null.
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifyOrInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -177,6 +227,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an Xor, fold the result or return null.
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const SimplifyQuery &Q);
|
||||
Value *SimplifyXorInst(Value *LHS, Value *RHS, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -184,6 +235,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an ICmpInst, fold the result or return null.
|
||||
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -192,6 +245,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an FCmpInst, fold the result or return null.
|
||||
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF, const SimplifyQuery &Q);
|
||||
Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -200,6 +255,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a SelectInst, fold the result or return null.
|
||||
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -207,7 +264,9 @@ namespace llvm {
|
|||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a GetElementPtrInst, fold the result or return null.
|
||||
/// Given operands for a GetElementPtrInst, fold the result or return null.
|
||||
Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -216,6 +275,9 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an InsertValueInst, fold the result or return null.
|
||||
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||
ArrayRef<unsigned> Idxs,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||
ArrayRef<unsigned> Idxs, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -224,6 +286,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an ExtractValueInst, fold the result or return null.
|
||||
Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -232,6 +296,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for an ExtractElementInst, fold the result or return null.
|
||||
Value *SimplifyExtractElementInst(Value *Vec, Value *Idx,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyExtractElementInst(Value *Vec, Value *Idx,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -240,6 +306,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a CastInst, fold the result or return null.
|
||||
Value *SimplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -248,6 +316,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a ShuffleVectorInst, fold the result or return null.
|
||||
Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
||||
Type *RetTy, const SimplifyQuery &Q);
|
||||
Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
||||
Type *RetTy, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -259,6 +329,8 @@ namespace llvm {
|
|||
|
||||
|
||||
/// Given operands for a CmpInst, fold the result or return null.
|
||||
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -267,6 +339,8 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given operands for a BinaryOperator, fold the result or return null.
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const SimplifyQuery &Q);
|
||||
Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -278,7 +352,9 @@ namespace llvm {
|
|||
/// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the
|
||||
/// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp.
|
||||
Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const FastMathFlags &FMF, const DataLayout &DL,
|
||||
FastMathFlags FMF, const SimplifyQuery &Q);
|
||||
Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
AssumptionCache *AC = nullptr,
|
||||
|
|
@ -286,6 +362,8 @@ namespace llvm {
|
|||
|
||||
/// Given a function and iterators over arguments, fold the result or return
|
||||
/// null.
|
||||
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
||||
User::op_iterator ArgEnd, const SimplifyQuery &Q);
|
||||
Value *SimplifyCall(Value *V, User::op_iterator ArgBegin,
|
||||
User::op_iterator ArgEnd, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
|
|
@ -294,6 +372,7 @@ namespace llvm {
|
|||
const Instruction *CxtI = nullptr);
|
||||
|
||||
/// Given a function and set of arguments, fold the result or return null.
|
||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args, const SimplifyQuery &Q);
|
||||
Value *SimplifyCall(Value *V, ArrayRef<Value *> Args, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
@ -302,6 +381,8 @@ namespace llvm {
|
|||
|
||||
/// See if we can compute a simplified version of this instruction. If not,
|
||||
/// return null.
|
||||
Value *SimplifyInstruction(Instruction *I, const SimplifyQuery &Q,
|
||||
OptimizationRemarkEmitter *ORE = nullptr);
|
||||
Value *SimplifyInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI = nullptr,
|
||||
const DominatorTree *DT = nullptr,
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ public:
|
|||
/// True if terminator in the block can branch to another block that is
|
||||
/// outside of the current loop.
|
||||
bool isLoopExiting(const BlockT *BB) const {
|
||||
for (const auto Succ : children<const BlockT*>(BB)) {
|
||||
for (const auto &Succ : children<const BlockT*>(BB)) {
|
||||
if (!contains(Succ))
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ template<class BlockT, class LoopT>
|
|||
void LoopBase<BlockT, LoopT>::
|
||||
getExitingBlocks(SmallVectorImpl<BlockT *> &ExitingBlocks) const {
|
||||
for (const auto BB : blocks())
|
||||
for (const auto Succ : children<BlockT*>(BB))
|
||||
for (const auto &Succ : children<BlockT*>(BB))
|
||||
if (!contains(Succ)) {
|
||||
// Not in current loop? It must be an exit block.
|
||||
ExitingBlocks.push_back(BB);
|
||||
|
|
@ -61,7 +61,7 @@ template<class BlockT, class LoopT>
|
|||
void LoopBase<BlockT, LoopT>::
|
||||
getExitBlocks(SmallVectorImpl<BlockT*> &ExitBlocks) const {
|
||||
for (const auto BB : blocks())
|
||||
for (const auto Succ : children<BlockT*>(BB))
|
||||
for (const auto &Succ : children<BlockT*>(BB))
|
||||
if (!contains(Succ))
|
||||
// Not in current loop? It must be an exit block.
|
||||
ExitBlocks.push_back(Succ);
|
||||
|
|
@ -83,7 +83,7 @@ template<class BlockT, class LoopT>
|
|||
void LoopBase<BlockT, LoopT>::
|
||||
getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const {
|
||||
for (const auto BB : blocks())
|
||||
for (const auto Succ : children<BlockT*>(BB))
|
||||
for (const auto &Succ : children<BlockT*>(BB))
|
||||
if (!contains(Succ))
|
||||
// Not in current loop? It must be an exit block.
|
||||
ExitEdges.emplace_back(BB, Succ);
|
||||
|
|
|
|||
|
|
@ -708,10 +708,24 @@ class RegionInfoBase {
|
|||
/// The top level region.
|
||||
RegionT *TopLevelRegion;
|
||||
|
||||
private:
|
||||
/// Map every BB to the smallest region, that contains BB.
|
||||
BBtoRegionMap BBtoRegion;
|
||||
|
||||
protected:
|
||||
/// \brief Update refences to a RegionInfoT held by the RegionT managed here
|
||||
///
|
||||
/// This is a post-move helper. Regions hold references to the owning
|
||||
/// RegionInfo object. After a move these need to be fixed.
|
||||
template<typename TheRegionT>
|
||||
void updateRegionTree(RegionInfoT &RI, TheRegionT *R) {
|
||||
if (!R)
|
||||
return;
|
||||
R->RI = &RI;
|
||||
for (auto &SubR : *R)
|
||||
updateRegionTree(RI, SubR.get());
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Wipe this region tree's state without releasing any resources.
|
||||
///
|
||||
/// This is essentially a post-move helper only. It leaves the object in an
|
||||
|
|
@ -879,10 +893,12 @@ public:
|
|||
|
||||
~RegionInfo() override;
|
||||
|
||||
RegionInfo(RegionInfo &&Arg)
|
||||
: Base(std::move(static_cast<Base &>(Arg))) {}
|
||||
RegionInfo(RegionInfo &&Arg) : Base(std::move(static_cast<Base &>(Arg))) {
|
||||
updateRegionTree(*this, TopLevelRegion);
|
||||
}
|
||||
RegionInfo &operator=(RegionInfo &&RHS) {
|
||||
Base::operator=(std::move(static_cast<Base &>(RHS)));
|
||||
updateRegionTree(*this, TopLevelRegion);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -877,6 +877,47 @@ private:
|
|||
bool ControlsExit,
|
||||
bool AllowPredicates = false);
|
||||
|
||||
// Helper functions for computeExitLimitFromCond to avoid exponential time
|
||||
// complexity.
|
||||
|
||||
class ExitLimitCache {
|
||||
// It may look like we need key on the whole (L, TBB, FBB, ControlsExit,
|
||||
// AllowPredicates) tuple, but recursive calls to
|
||||
// computeExitLimitFromCondCached from computeExitLimitFromCondImpl only
|
||||
// vary the in \c ExitCond and \c ControlsExit parameters. We remember the
|
||||
// initial values of the other values to assert our assumption.
|
||||
SmallDenseMap<PointerIntPair<Value *, 1>, ExitLimit> TripCountMap;
|
||||
|
||||
const Loop *L;
|
||||
BasicBlock *TBB;
|
||||
BasicBlock *FBB;
|
||||
bool AllowPredicates;
|
||||
|
||||
public:
|
||||
ExitLimitCache(const Loop *L, BasicBlock *TBB, BasicBlock *FBB,
|
||||
bool AllowPredicates)
|
||||
: L(L), TBB(TBB), FBB(FBB), AllowPredicates(AllowPredicates) {}
|
||||
|
||||
Optional<ExitLimit> find(const Loop *L, Value *ExitCond, BasicBlock *TBB,
|
||||
BasicBlock *FBB, bool ControlsExit,
|
||||
bool AllowPredicates);
|
||||
|
||||
void insert(const Loop *L, Value *ExitCond, BasicBlock *TBB,
|
||||
BasicBlock *FBB, bool ControlsExit, bool AllowPredicates,
|
||||
const ExitLimit &EL);
|
||||
};
|
||||
|
||||
typedef ExitLimitCache ExitLimitCacheTy;
|
||||
ExitLimit computeExitLimitFromCondCached(ExitLimitCacheTy &Cache,
|
||||
const Loop *L, Value *ExitCond,
|
||||
BasicBlock *TBB, BasicBlock *FBB,
|
||||
bool ControlsExit,
|
||||
bool AllowPredicates);
|
||||
ExitLimit computeExitLimitFromCondImpl(ExitLimitCacheTy &Cache, const Loop *L,
|
||||
Value *ExitCond, BasicBlock *TBB,
|
||||
BasicBlock *FBB, bool ControlsExit,
|
||||
bool AllowPredicates);
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will
|
||||
/// execute if its exit condition were a conditional branch of the ICmpInst
|
||||
/// ExitCond, TBB, and FBB. If AllowPredicates is set, this call will try
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ template <typename T> class ArrayRef;
|
|||
class DominatorTree;
|
||||
class GEPOperator;
|
||||
class Instruction;
|
||||
struct KnownBits;
|
||||
class Loop;
|
||||
class LoopInfo;
|
||||
class OptimizationRemarkEmitter;
|
||||
|
|
@ -49,7 +50,7 @@ template <typename T> class ArrayRef;
|
|||
/// where V is a vector, the known zero and known one values are the
|
||||
/// same width as the vector element, and the bit is set only if it is true
|
||||
/// for all of the elements in the vector.
|
||||
void computeKnownBits(const Value *V, APInt &KnownZero, APInt &KnownOne,
|
||||
void computeKnownBits(const Value *V, KnownBits &Known,
|
||||
const DataLayout &DL, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
|
|
|
|||
|
|
@ -793,6 +793,9 @@ class DIEUnit {
|
|||
uint32_t Length; /// The length in bytes of all of the DIEs in this unit.
|
||||
const uint16_t Version; /// The Dwarf version number for this unit.
|
||||
const uint8_t AddrSize; /// The size in bytes of an address for this unit.
|
||||
protected:
|
||||
~DIEUnit() = default;
|
||||
|
||||
public:
|
||||
DIEUnit(uint16_t Version, uint8_t AddrSize, dwarf::Tag UnitTag);
|
||||
DIEUnit(const DIEUnit &RHS) = delete;
|
||||
|
|
@ -808,6 +811,10 @@ public:
|
|||
this->Section = Section;
|
||||
}
|
||||
|
||||
virtual const MCSymbol *getCrossSectionRelativeBaseAddress() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Return the section that this DIEUnit will be emitted into.
|
||||
///
|
||||
/// \returns Section pointer which can be NULL.
|
||||
|
|
@ -822,7 +829,11 @@ public:
|
|||
const DIE &getUnitDie() const { return Die; }
|
||||
};
|
||||
|
||||
|
||||
struct BasicDIEUnit final : DIEUnit {
|
||||
BasicDIEUnit(uint16_t Version, uint8_t AddrSize, dwarf::Tag UnitTag)
|
||||
: DIEUnit(Version, AddrSize, UnitTag) {}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// DIELoc - Represents an expression location.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -18,20 +18,52 @@
|
|||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
class MachineInstr;
|
||||
class MachineInstrBuilder;
|
||||
class MachineFunction;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class RegisterBankInfo;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// Container class for CodeGen predicate results.
|
||||
/// This is convenient because std::bitset does not have a constructor
|
||||
/// with an initializer list of set bits.
|
||||
///
|
||||
/// Each InstructionSelector subclass should define a PredicateBitset class with:
|
||||
/// const unsigned MAX_SUBTARGET_PREDICATES = 192;
|
||||
/// using PredicateBitset = PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
|
||||
/// and updating the constant to suit the target. Tablegen provides a suitable
|
||||
/// definition for the predicates in use in <Target>GenGlobalISel.inc when
|
||||
/// GET_GLOBALISEL_PREDICATE_BITSET is defined.
|
||||
template <std::size_t MaxPredicates>
|
||||
class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
|
||||
public:
|
||||
// Cannot inherit constructors because it's not supported by VC++..
|
||||
PredicateBitsetImpl() = default;
|
||||
|
||||
PredicateBitsetImpl(const std::bitset<MaxPredicates> &B)
|
||||
: std::bitset<MaxPredicates>(B) {}
|
||||
|
||||
PredicateBitsetImpl(std::initializer_list<unsigned> Init) {
|
||||
for (auto I : Init)
|
||||
std::bitset<MaxPredicates>::set(I);
|
||||
}
|
||||
};
|
||||
|
||||
/// Provides the logic to select generic machine instructions.
|
||||
class InstructionSelector {
|
||||
public:
|
||||
virtual ~InstructionSelector() {}
|
||||
|
||||
/// This is executed before selecting a function.
|
||||
virtual void beginFunction(const MachineFunction &MF) {}
|
||||
|
||||
/// Select the (possibly generic) instruction \p I to only use target-specific
|
||||
/// opcodes. It is OK to insert multiple instructions, but they cannot be
|
||||
/// generic pre-isel instructions.
|
||||
|
|
@ -46,6 +78,8 @@ public:
|
|||
virtual bool select(MachineInstr &I) const = 0;
|
||||
|
||||
protected:
|
||||
typedef std::function<void(MachineInstrBuilder &)> ComplexRendererFn;
|
||||
|
||||
InstructionSelector();
|
||||
|
||||
/// Mutate the newly-selected instruction \p I to constrain its (possibly
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ public:
|
|||
MO_CFIIndex, ///< MCCFIInstruction index.
|
||||
MO_IntrinsicID, ///< Intrinsic ID for ISel
|
||||
MO_Predicate, ///< Generic predicate for ISel
|
||||
MO_Placeholder, ///< Placeholder for GlobalISel ComplexPattern result.
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -768,11 +767,6 @@ public:
|
|||
return Op;
|
||||
}
|
||||
|
||||
static MachineOperand CreatePlaceholder() {
|
||||
MachineOperand Op(MachineOperand::MO_Placeholder);
|
||||
return Op;
|
||||
}
|
||||
|
||||
friend class MachineInstr;
|
||||
friend class MachineRegisterInfo;
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -654,6 +654,15 @@ public:
|
|||
return getNode(ISD::BUILD_VECTOR, DL, VT, Ops);
|
||||
}
|
||||
|
||||
/// Return an ISD::BUILD_VECTOR node. The number of elements in VT,
|
||||
/// which must be a vector type, must match the number of operands in Ops.
|
||||
/// The operands must have the same type as (or, for integers, a type wider
|
||||
/// than) VT's element type.
|
||||
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef<SDUse> Ops) {
|
||||
// VerifySDNode (via InsertNode) checks BUILD_VECTOR later.
|
||||
return getNode(ISD::BUILD_VECTOR, DL, VT, Ops);
|
||||
}
|
||||
|
||||
/// Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all
|
||||
/// elements. VT must be a vector type. Op's type must be the same as (or,
|
||||
/// for integers, a type wider than) VT's element type.
|
||||
|
|
@ -968,7 +977,7 @@ public:
|
|||
bool IsExpanding = false);
|
||||
SDValue getMaskedStore(SDValue Chain, const SDLoc &dl, SDValue Val,
|
||||
SDValue Ptr, SDValue Mask, EVT MemVT,
|
||||
MachineMemOperand *MMO, bool IsTruncating = false,
|
||||
MachineMemOperand *MMO, bool IsTruncating = false,
|
||||
bool IsCompressing = false);
|
||||
SDValue getMaskedGather(SDVTList VTs, EVT VT, const SDLoc &dl,
|
||||
ArrayRef<SDValue> Ops, MachineMemOperand *MMO);
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ enum class TrampolineType : uint16_t { TrampIncremental, BranchIsland };
|
|||
// These values correspond to the CV_SourceChksum_t enumeration.
|
||||
enum class FileChecksumKind : uint8_t { None, MD5, SHA1, SHA256 };
|
||||
|
||||
enum LineFlags : uint32_t {
|
||||
enum LineFlags : uint16_t {
|
||||
HaveColumns = 1, // CV_LINES_HAVE_COLUMNS
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public:
|
|||
BinaryStreamReader Reader(Stream);
|
||||
if (auto EC = Reader.readObject(BlockHeader))
|
||||
return EC;
|
||||
bool HasColumn = Header->Flags & LineFlags::HaveColumns;
|
||||
bool HasColumn = Header->Flags & uint32_t(LineFlags::HaveColumns);
|
||||
uint32_t LineInfoSize =
|
||||
BlockHeader->NumLines *
|
||||
(sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ namespace llvm {
|
|||
class DWARFCompileUnit : public DWARFUnit {
|
||||
public:
|
||||
DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
|
||||
StringRef SOS, StringRef AOS, StringRef LS, bool LE,
|
||||
bool IsDWO, const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS,
|
||||
StringRef SS, StringRef SOS, StringRef AOS, StringRef LS,
|
||||
bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFUnitIndex::Entry *Entry)
|
||||
: DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO,
|
||||
UnitSection, Entry) {}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ class raw_ostream;
|
|||
// entire size of the debug info sections.
|
||||
typedef DenseMap<uint64_t, std::pair<uint8_t, int64_t>> RelocAddrMap;
|
||||
|
||||
/// Reads a value from data extractor and applies a relocation to the result if
|
||||
/// one exists for the given offset.
|
||||
uint64_t getRelocatedValue(const DataExtractor &Data, uint32_t Size,
|
||||
uint32_t *Off, const RelocAddrMap *Relocs);
|
||||
|
||||
/// DWARFContext
|
||||
/// This data structure is the top level entity that deals with dwarf debug
|
||||
/// information parsing. The actual data is supplied through pure virtual
|
||||
|
|
@ -216,7 +221,7 @@ public:
|
|||
virtual StringRef getEHFrameSection() = 0;
|
||||
virtual const DWARFSection &getLineSection() = 0;
|
||||
virtual StringRef getStringSection() = 0;
|
||||
virtual StringRef getRangeSection() = 0;
|
||||
virtual const DWARFSection& getRangeSection() = 0;
|
||||
virtual StringRef getMacinfoSection() = 0;
|
||||
virtual StringRef getPubNamesSection() = 0;
|
||||
virtual StringRef getPubTypesSection() = 0;
|
||||
|
|
@ -231,7 +236,7 @@ public:
|
|||
virtual const DWARFSection &getLocDWOSection() = 0;
|
||||
virtual StringRef getStringDWOSection() = 0;
|
||||
virtual StringRef getStringOffsetDWOSection() = 0;
|
||||
virtual StringRef getRangeDWOSection() = 0;
|
||||
virtual const DWARFSection &getRangeDWOSection() = 0;
|
||||
virtual StringRef getAddrSection() = 0;
|
||||
virtual const DWARFSection& getAppleNamesSection() = 0;
|
||||
virtual const DWARFSection& getAppleTypesSection() = 0;
|
||||
|
|
@ -271,7 +276,7 @@ class DWARFContextInMemory : public DWARFContext {
|
|||
StringRef EHFrameSection;
|
||||
DWARFSection LineSection;
|
||||
StringRef StringSection;
|
||||
StringRef RangeSection;
|
||||
DWARFSection RangeSection;
|
||||
StringRef MacinfoSection;
|
||||
StringRef PubNamesSection;
|
||||
StringRef PubTypesSection;
|
||||
|
|
@ -286,7 +291,7 @@ class DWARFContextInMemory : public DWARFContext {
|
|||
DWARFSection LocDWOSection;
|
||||
StringRef StringDWOSection;
|
||||
StringRef StringOffsetDWOSection;
|
||||
StringRef RangeDWOSection;
|
||||
DWARFSection RangeDWOSection;
|
||||
StringRef AddrSection;
|
||||
DWARFSection AppleNamesSection;
|
||||
DWARFSection AppleTypesSection;
|
||||
|
|
@ -319,7 +324,7 @@ public:
|
|||
StringRef getEHFrameSection() override { return EHFrameSection; }
|
||||
const DWARFSection &getLineSection() override { return LineSection; }
|
||||
StringRef getStringSection() override { return StringSection; }
|
||||
StringRef getRangeSection() override { return RangeSection; }
|
||||
const DWARFSection &getRangeSection() override { return RangeSection; }
|
||||
StringRef getMacinfoSection() override { return MacinfoSection; }
|
||||
StringRef getPubNamesSection() override { return PubNamesSection; }
|
||||
StringRef getPubTypesSection() override { return PubTypesSection; }
|
||||
|
|
@ -346,7 +351,7 @@ public:
|
|||
return StringOffsetDWOSection;
|
||||
}
|
||||
|
||||
StringRef getRangeDWOSection() override { return RangeDWOSection; }
|
||||
const DWARFSection &getRangeDWOSection() override { return RangeDWOSection; }
|
||||
|
||||
StringRef getAddrSection() override {
|
||||
return AddrSection;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#define LLVM_DEBUGINFO_DWARF_DWARFDEBUGRANGELIST_H
|
||||
|
||||
#include "llvm/Support/DataExtractor.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
|
@ -71,7 +73,7 @@ public:
|
|||
|
||||
void clear();
|
||||
void dump(raw_ostream &OS) const;
|
||||
bool extract(DataExtractor data, uint32_t *offset_ptr);
|
||||
bool extract(DataExtractor data, uint32_t *offset_ptr, const RelocAddrMap& Relocs);
|
||||
const std::vector<RangeListEntry> &getEntries() { return Entries; }
|
||||
|
||||
/// getAbsoluteRanges - Returns absolute address ranges defined by this range
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ private:
|
|||
|
||||
public:
|
||||
DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
|
||||
StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO,
|
||||
const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS,
|
||||
StringRef SS, StringRef SOS, StringRef AOS, StringRef LS,
|
||||
bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFUnitIndex::Entry *Entry)
|
||||
: DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO,
|
||||
UnitSection, Entry) {}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ protected:
|
|||
~DWARFUnitSectionBase() = default;
|
||||
|
||||
virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
|
||||
StringRef SOS, StringRef AOS, StringRef LS,
|
||||
bool isLittleEndian, bool isDWO) = 0;
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS,
|
||||
StringRef SS, StringRef SOS, StringRef AOS,
|
||||
StringRef LS, bool isLittleEndian, bool isDWO) = 0;
|
||||
};
|
||||
|
||||
const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context,
|
||||
|
|
@ -88,9 +88,9 @@ public:
|
|||
|
||||
private:
|
||||
void parseImpl(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
|
||||
StringRef SOS, StringRef AOS, StringRef LS, bool LE,
|
||||
bool IsDWO) override {
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS,
|
||||
StringRef SS, StringRef SOS, StringRef AOS, StringRef LS,
|
||||
bool LE, bool IsDWO) override {
|
||||
if (Parsed)
|
||||
return;
|
||||
const auto &Index = getDWARFUnitIndex(Context, UnitType::Section);
|
||||
|
|
@ -115,7 +115,7 @@ class DWARFUnit {
|
|||
const DWARFSection &InfoSection;
|
||||
|
||||
const DWARFDebugAbbrev *Abbrev;
|
||||
StringRef RangeSection;
|
||||
const DWARFSection *RangeSection;
|
||||
uint32_t RangeSectionBase;
|
||||
StringRef LineSection;
|
||||
StringRef StringSection;
|
||||
|
|
@ -171,7 +171,7 @@ protected:
|
|||
|
||||
public:
|
||||
DWARFUnit(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS,
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS,
|
||||
StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO,
|
||||
const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFUnitIndex::Entry *IndexEntry = nullptr);
|
||||
|
|
@ -192,7 +192,7 @@ public:
|
|||
// Recursively update address to Die map.
|
||||
void updateAddressDieMap(DWARFDie Die);
|
||||
|
||||
void setRangesSection(StringRef RS, uint32_t Base) {
|
||||
void setRangesSection(const DWARFSection *RS, uint32_t Base) {
|
||||
RangeSection = RS;
|
||||
RangeSectionBase = Base;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,8 @@ public:
|
|||
uint32_t getVirtualBaseDispIndex() const override;
|
||||
uint32_t getVirtualBaseOffset() const override;
|
||||
uint32_t getVirtualTableShapeId() const override;
|
||||
std::unique_ptr<PDBSymbolTypeVTable> getVirtualBaseTableType() const override;
|
||||
std::unique_ptr<PDBSymbolTypeBuiltin>
|
||||
getVirtualBaseTableType() const override;
|
||||
PDB_DataKind getDataKind() const override;
|
||||
PDB_SymType getSymTag() const override;
|
||||
PDB_UniqueId getGuid() const override;
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public:
|
|||
virtual Variant getValue() const = 0;
|
||||
virtual uint32_t getVirtualBaseDispIndex() const = 0;
|
||||
virtual uint32_t getVirtualBaseOffset() const = 0;
|
||||
virtual std::unique_ptr<PDBSymbolTypeVTable>
|
||||
virtual std::unique_ptr<PDBSymbolTypeBuiltin>
|
||||
getVirtualBaseTableType() const = 0;
|
||||
virtual uint32_t getVirtualTableShapeId() const = 0;
|
||||
virtual PDB_DataKind getDataKind() const = 0;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ public:
|
|||
iterator_range<codeview::ModuleSubstreamArray::Iterator>
|
||||
lines(bool *HadError) const;
|
||||
|
||||
bool hasLineInfo() const;
|
||||
|
||||
Error commit();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ public:
|
|||
uint32_t getVirtualBaseDispIndex() const override;
|
||||
uint32_t getVirtualBaseOffset() const override;
|
||||
uint32_t getVirtualTableShapeId() const override;
|
||||
std::unique_ptr<PDBSymbolTypeVTable> getVirtualBaseTableType() const override;
|
||||
std::unique_ptr<PDBSymbolTypeBuiltin>
|
||||
getVirtualBaseTableType() const override;
|
||||
PDB_DataKind getDataKind() const override;
|
||||
PDB_SymType getSymTag() const override;
|
||||
PDB_UniqueId getGuid() const override;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
|
@ -32,40 +33,63 @@ class PDBSymbolTypeVTable;
|
|||
|
||||
class ClassLayout;
|
||||
class BaseClassLayout;
|
||||
class StorageItemBase;
|
||||
class LayoutItemBase;
|
||||
class UDTLayoutBase;
|
||||
|
||||
class StorageItemBase {
|
||||
class LayoutItemBase {
|
||||
public:
|
||||
StorageItemBase(const UDTLayoutBase &Parent, const PDBSymbol &Symbol,
|
||||
const std::string &Name, uint32_t OffsetInParent,
|
||||
uint32_t Size);
|
||||
virtual ~StorageItemBase() {}
|
||||
LayoutItemBase(const UDTLayoutBase *Parent, const PDBSymbol *Symbol,
|
||||
const std::string &Name, uint32_t OffsetInParent,
|
||||
uint32_t Size, bool IsElided);
|
||||
virtual ~LayoutItemBase() {}
|
||||
|
||||
virtual uint32_t deepPaddingSize() const;
|
||||
uint32_t deepPaddingSize() const;
|
||||
virtual uint32_t immediatePadding() const { return 0; }
|
||||
virtual uint32_t tailPadding() const;
|
||||
|
||||
const UDTLayoutBase &getParent() const { return Parent; }
|
||||
const UDTLayoutBase *getParent() const { return Parent; }
|
||||
StringRef getName() const { return Name; }
|
||||
uint32_t getOffsetInParent() const { return OffsetInParent; }
|
||||
uint32_t getSize() const { return SizeOf; }
|
||||
const PDBSymbol &getSymbol() const { return Symbol; }
|
||||
uint32_t getLayoutSize() const { return LayoutSize; }
|
||||
const PDBSymbol *getSymbol() const { return Symbol; }
|
||||
const BitVector &usedBytes() const { return UsedBytes; }
|
||||
bool isElided() const { return IsElided; }
|
||||
virtual bool isVBPtr() const { return false; }
|
||||
|
||||
uint32_t containsOffset(uint32_t Off) const {
|
||||
uint32_t Begin = getOffsetInParent();
|
||||
uint32_t End = Begin + getSize();
|
||||
return (Off >= Begin && Off < End);
|
||||
}
|
||||
|
||||
protected:
|
||||
const UDTLayoutBase &Parent;
|
||||
const PDBSymbol &Symbol;
|
||||
const PDBSymbol *Symbol = nullptr;
|
||||
const UDTLayoutBase *Parent = nullptr;
|
||||
BitVector UsedBytes;
|
||||
std::string Name;
|
||||
uint32_t OffsetInParent = 0;
|
||||
uint32_t SizeOf = 0;
|
||||
uint32_t LayoutSize = 0;
|
||||
bool IsElided = false;
|
||||
};
|
||||
|
||||
class DataMemberLayoutItem : public StorageItemBase {
|
||||
class VBPtrLayoutItem : public LayoutItemBase {
|
||||
public:
|
||||
VBPtrLayoutItem(const UDTLayoutBase &Parent,
|
||||
std::unique_ptr<PDBSymbolTypeBuiltin> Sym, uint32_t Offset,
|
||||
uint32_t Size);
|
||||
virtual bool isVBPtr() const { return true; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<PDBSymbolTypeBuiltin> Type;
|
||||
};
|
||||
|
||||
class DataMemberLayoutItem : public LayoutItemBase {
|
||||
public:
|
||||
DataMemberLayoutItem(const UDTLayoutBase &Parent,
|
||||
std::unique_ptr<PDBSymbolData> DataMember);
|
||||
|
||||
virtual uint32_t deepPaddingSize() const;
|
||||
|
||||
const PDBSymbolData &getDataMember();
|
||||
bool hasUDTLayout() const;
|
||||
const ClassLayout &getUDTLayout() const;
|
||||
|
|
@ -75,77 +99,73 @@ private:
|
|||
std::unique_ptr<ClassLayout> UdtLayout;
|
||||
};
|
||||
|
||||
class VTableLayoutItem : public StorageItemBase {
|
||||
class VTableLayoutItem : public LayoutItemBase {
|
||||
public:
|
||||
VTableLayoutItem(const UDTLayoutBase &Parent,
|
||||
std::unique_ptr<PDBSymbolTypeVTable> VTable);
|
||||
ArrayRef<PDBSymbolFunc *> funcs() const { return VTableFuncs; }
|
||||
|
||||
uint32_t getElementSize() const { return ElementSize; }
|
||||
|
||||
void setFunction(uint32_t Index, PDBSymbolFunc &Func) {
|
||||
VTableFuncs[Index] = &Func;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t ElementSize = 0;
|
||||
std::unique_ptr<PDBSymbolTypeVTableShape> Shape;
|
||||
std::unique_ptr<PDBSymbolTypeVTable> VTable;
|
||||
std::vector<PDBSymbolFunc *> VTableFuncs;
|
||||
};
|
||||
|
||||
class UDTLayoutBase {
|
||||
class UDTLayoutBase : public LayoutItemBase {
|
||||
template <typename T> using UniquePtrVector = std::vector<std::unique_ptr<T>>;
|
||||
|
||||
public:
|
||||
UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name,
|
||||
uint32_t Size);
|
||||
UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym,
|
||||
const std::string &Name, uint32_t OffsetInParent, uint32_t Size,
|
||||
bool IsElided);
|
||||
|
||||
uint32_t shallowPaddingSize() const;
|
||||
uint32_t deepPaddingSize() const;
|
||||
uint32_t tailPadding() const override;
|
||||
|
||||
const BitVector &usedBytes() const { return UsedBytes; }
|
||||
ArrayRef<LayoutItemBase *> layout_items() const { return LayoutItems; }
|
||||
|
||||
uint32_t getClassSize() const { return SizeOf; }
|
||||
ArrayRef<BaseClassLayout *> bases() const { return AllBases; }
|
||||
ArrayRef<BaseClassLayout *> regular_bases() const { return NonVirtualBases; }
|
||||
ArrayRef<BaseClassLayout *> virtual_bases() const { return VirtualBases; }
|
||||
|
||||
ArrayRef<std::unique_ptr<StorageItemBase>> layout_items() const {
|
||||
return ChildStorage;
|
||||
}
|
||||
|
||||
VTableLayoutItem *findVTableAtOffset(uint32_t RelativeOffset);
|
||||
|
||||
StringRef getUDTName() const { return Name; }
|
||||
|
||||
ArrayRef<BaseClassLayout *> bases() const { return BaseClasses; }
|
||||
ArrayRef<std::unique_ptr<PDBSymbolTypeBaseClass>> vbases() const {
|
||||
return VirtualBases;
|
||||
}
|
||||
uint32_t directVirtualBaseCount() const { return DirectVBaseCount; }
|
||||
|
||||
ArrayRef<std::unique_ptr<PDBSymbolFunc>> funcs() const { return Funcs; }
|
||||
|
||||
ArrayRef<std::unique_ptr<PDBSymbol>> other_items() const { return Other; }
|
||||
|
||||
const PDBSymbol &getSymbolBase() const { return SymbolBase; }
|
||||
|
||||
protected:
|
||||
bool hasVBPtrAtOffset(uint32_t Off) const;
|
||||
void initializeChildren(const PDBSymbol &Sym);
|
||||
|
||||
void addChildToLayout(std::unique_ptr<StorageItemBase> Child);
|
||||
void addVirtualOverride(PDBSymbolFunc &Func);
|
||||
void addVirtualIntro(PDBSymbolFunc &Func);
|
||||
void addChildToLayout(std::unique_ptr<LayoutItemBase> Child);
|
||||
|
||||
const PDBSymbol &SymbolBase;
|
||||
std::string Name;
|
||||
uint32_t SizeOf = 0;
|
||||
uint32_t DirectVBaseCount = 0;
|
||||
|
||||
BitVector UsedBytes;
|
||||
UniquePtrVector<PDBSymbol> Other;
|
||||
UniquePtrVector<PDBSymbolFunc> Funcs;
|
||||
UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBases;
|
||||
UniquePtrVector<StorageItemBase> ChildStorage;
|
||||
std::vector<std::list<StorageItemBase *>> ChildrenPerByte;
|
||||
std::vector<BaseClassLayout *> BaseClasses;
|
||||
UniquePtrVector<LayoutItemBase> ChildStorage;
|
||||
std::vector<LayoutItemBase *> LayoutItems;
|
||||
|
||||
std::vector<BaseClassLayout *> AllBases;
|
||||
ArrayRef<BaseClassLayout *> NonVirtualBases;
|
||||
ArrayRef<BaseClassLayout *> VirtualBases;
|
||||
|
||||
VTableLayoutItem *VTable = nullptr;
|
||||
VBPtrLayoutItem *VBPtr = nullptr;
|
||||
};
|
||||
|
||||
class BaseClassLayout : public UDTLayoutBase {
|
||||
public:
|
||||
BaseClassLayout(const UDTLayoutBase &Parent, uint32_t OffsetInParent,
|
||||
bool Elide, std::unique_ptr<PDBSymbolTypeBaseClass> Base);
|
||||
|
||||
const PDBSymbolTypeBaseClass &getBase() const { return *Base; }
|
||||
bool isVirtualBase() const { return IsVirtualBase; }
|
||||
bool isEmptyBase() { return SizeOf == 1 && LayoutSize == 0; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<PDBSymbolTypeBaseClass> Base;
|
||||
bool IsVirtualBase;
|
||||
};
|
||||
|
||||
class ClassLayout : public UDTLayoutBase {
|
||||
|
|
@ -156,24 +176,13 @@ public:
|
|||
ClassLayout(ClassLayout &&Other) = default;
|
||||
|
||||
const PDBSymbolTypeUDT &getClass() const { return UDT; }
|
||||
uint32_t immediatePadding() const override;
|
||||
|
||||
private:
|
||||
BitVector ImmediateUsedBytes;
|
||||
std::unique_ptr<PDBSymbolTypeUDT> OwnedStorage;
|
||||
const PDBSymbolTypeUDT &UDT;
|
||||
};
|
||||
|
||||
class BaseClassLayout : public UDTLayoutBase, public StorageItemBase {
|
||||
public:
|
||||
BaseClassLayout(const UDTLayoutBase &Parent,
|
||||
std::unique_ptr<PDBSymbolTypeBaseClass> Base);
|
||||
|
||||
const PDBSymbolTypeBaseClass &getBase() const { return *Base; }
|
||||
bool isVirtualBase() const { return IsVirtualBase; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<PDBSymbolTypeBaseClass> Base;
|
||||
bool IsVirtualBase;
|
||||
};
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ public:
|
|||
// key of the deserializers map to save us from duplicating the string in
|
||||
// the serializer. This should be changed to use a stringpool if we switch
|
||||
// to a map type that may move keys in memory.
|
||||
std::lock_guard<std::mutex> Lock(DeserializersMutex);
|
||||
std::lock_guard<std::recursive_mutex> Lock(DeserializersMutex);
|
||||
auto I =
|
||||
Deserializers.insert(Deserializers.begin(),
|
||||
std::make_pair(std::move(Name),
|
||||
|
|
@ -358,7 +358,7 @@ public:
|
|||
|
||||
{
|
||||
assert(KeyName != nullptr && "No keyname pointer");
|
||||
std::lock_guard<std::mutex> Lock(SerializersMutex);
|
||||
std::lock_guard<std::recursive_mutex> Lock(SerializersMutex);
|
||||
// FIXME: Move capture Serialize once we have C++14.
|
||||
Serializers[ErrorInfoT::classID()] =
|
||||
[KeyName, Serialize](ChannelT &C, const ErrorInfoBase &EIB) -> Error {
|
||||
|
|
@ -372,7 +372,8 @@ public:
|
|||
}
|
||||
|
||||
static Error serialize(ChannelT &C, Error &&Err) {
|
||||
std::lock_guard<std::mutex> Lock(SerializersMutex);
|
||||
std::lock_guard<std::recursive_mutex> Lock(SerializersMutex);
|
||||
|
||||
if (!Err)
|
||||
return serializeSeq(C, std::string());
|
||||
|
||||
|
|
@ -386,7 +387,7 @@ public:
|
|||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, Error &Err) {
|
||||
std::lock_guard<std::mutex> Lock(DeserializersMutex);
|
||||
std::lock_guard<std::recursive_mutex> Lock(DeserializersMutex);
|
||||
|
||||
std::string Key;
|
||||
if (auto Err = deserializeSeq(C, Key))
|
||||
|
|
@ -406,8 +407,6 @@ public:
|
|||
private:
|
||||
|
||||
static Error serializeAsStringError(ChannelT &C, const ErrorInfoBase &EIB) {
|
||||
assert(EIB.dynamicClassID() != StringError::classID() &&
|
||||
"StringError serialization not registered");
|
||||
std::string ErrMsg;
|
||||
{
|
||||
raw_string_ostream ErrMsgStream(ErrMsg);
|
||||
|
|
@ -417,17 +416,17 @@ private:
|
|||
inconvertibleErrorCode()));
|
||||
}
|
||||
|
||||
static std::mutex SerializersMutex;
|
||||
static std::mutex DeserializersMutex;
|
||||
static std::recursive_mutex SerializersMutex;
|
||||
static std::recursive_mutex DeserializersMutex;
|
||||
static std::map<const void*, WrappedErrorSerializer> Serializers;
|
||||
static std::map<std::string, WrappedErrorDeserializer> Deserializers;
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
std::mutex SerializationTraits<ChannelT, Error>::SerializersMutex;
|
||||
std::recursive_mutex SerializationTraits<ChannelT, Error>::SerializersMutex;
|
||||
|
||||
template <typename ChannelT>
|
||||
std::mutex SerializationTraits<ChannelT, Error>::DeserializersMutex;
|
||||
std::recursive_mutex SerializationTraits<ChannelT, Error>::DeserializersMutex;
|
||||
|
||||
template <typename ChannelT>
|
||||
std::map<const void*,
|
||||
|
|
@ -439,27 +438,39 @@ std::map<std::string,
|
|||
typename SerializationTraits<ChannelT, Error>::WrappedErrorDeserializer>
|
||||
SerializationTraits<ChannelT, Error>::Deserializers;
|
||||
|
||||
/// Registers a serializer and deserializer for the given error type on the
|
||||
/// given channel type.
|
||||
template <typename ChannelT, typename ErrorInfoT, typename SerializeFtor,
|
||||
typename DeserializeFtor>
|
||||
void registerErrorSerialization(std::string Name, SerializeFtor &&Serialize,
|
||||
DeserializeFtor &&Deserialize) {
|
||||
SerializationTraits<ChannelT, Error>::template registerErrorType<ErrorInfoT>(
|
||||
std::move(Name),
|
||||
std::forward<SerializeFtor>(Serialize),
|
||||
std::forward<DeserializeFtor>(Deserialize));
|
||||
}
|
||||
|
||||
/// Registers serialization/deserialization for StringError.
|
||||
template <typename ChannelT>
|
||||
void registerStringError() {
|
||||
static bool AlreadyRegistered = false;
|
||||
if (!AlreadyRegistered) {
|
||||
SerializationTraits<ChannelT, Error>::
|
||||
template registerErrorType<StringError>(
|
||||
"StringError",
|
||||
[](ChannelT &C, const StringError &SE) {
|
||||
return serializeSeq(C, SE.getMessage());
|
||||
},
|
||||
[](ChannelT &C, Error &Err) {
|
||||
ErrorAsOutParameter EAO(&Err);
|
||||
std::string Msg;
|
||||
if (auto E2 = deserializeSeq(C, Msg))
|
||||
return E2;
|
||||
Err =
|
||||
make_error<StringError>(std::move(Msg),
|
||||
orcError(
|
||||
OrcErrorCode::UnknownErrorCodeFromRemote));
|
||||
return Error::success();
|
||||
});
|
||||
registerErrorSerialization<ChannelT, StringError>(
|
||||
"StringError",
|
||||
[](ChannelT &C, const StringError &SE) {
|
||||
return serializeSeq(C, SE.getMessage());
|
||||
},
|
||||
[](ChannelT &C, Error &Err) -> Error {
|
||||
ErrorAsOutParameter EAO(&Err);
|
||||
std::string Msg;
|
||||
if (auto E2 = deserializeSeq(C, Msg))
|
||||
return E2;
|
||||
Err =
|
||||
make_error<StringError>(std::move(Msg),
|
||||
orcError(
|
||||
OrcErrorCode::UnknownErrorCodeFromRemote));
|
||||
return Error::success();
|
||||
});
|
||||
AlreadyRegistered = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ public:
|
|||
unsigned getSlotIndex(unsigned Slot) const;
|
||||
|
||||
/// \brief Return the attributes at the given slot.
|
||||
AttributeList getSlotAttributes(unsigned Slot) const;
|
||||
AttributeSet getSlotAttributes(unsigned Slot) const;
|
||||
|
||||
void dump() const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public:
|
|||
///
|
||||
/// NB! The returned set does *not* contain **all** possible values of X for
|
||||
/// which "X BinOpC Y" does not wrap -- some viable values of X may be
|
||||
/// missing, so you cannot use this to contrain X's range. E.g. in the last
|
||||
/// missing, so you cannot use this to constrain X's range. E.g. in the last
|
||||
/// example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2), but (-2)
|
||||
/// is not in the set returned.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -157,6 +157,10 @@ public:
|
|||
/// This should only be used for debugging as it aborts the program if the
|
||||
/// verification fails.
|
||||
void verifyDomTree() const;
|
||||
|
||||
// Pop up a GraphViz/gv window with the Dominator Tree rendered using `dot`.
|
||||
void viewGraph(const Twine &Name, const Twine &Title);
|
||||
void viewGraph();
|
||||
};
|
||||
|
||||
//===-------------------------------------
|
||||
|
|
|
|||
|
|
@ -629,6 +629,8 @@ def int_amdgcn_readfirstlane :
|
|||
GCCBuiltin<"__builtin_amdgcn_readfirstlane">,
|
||||
Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem, IntrConvergent]>;
|
||||
|
||||
// The lane argument must be uniform across the currently active threads of the
|
||||
// current wave. Otherwise, the result is undefined.
|
||||
def int_amdgcn_readlane :
|
||||
GCCBuiltin<"__builtin_amdgcn_readlane">,
|
||||
Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>;
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ public:
|
|||
/// exist, add a prototype for the function and return it. This function
|
||||
/// guarantees to return a constant of pointer to the specified function type
|
||||
/// or a ConstantExpr BitCast of that type if the named function has a
|
||||
/// different type. This version of the method takes a null terminated list of
|
||||
/// different type. This version of the method takes a list of
|
||||
/// function arguments, which makes it easier for clients to use.
|
||||
template<typename... ArgsTy>
|
||||
Constant *getOrInsertFunction(StringRef Name,
|
||||
|
|
|
|||
|
|
@ -482,6 +482,17 @@ public:
|
|||
static_cast<const Value *>(this)->stripPointerCasts());
|
||||
}
|
||||
|
||||
/// \brief Strip off pointer casts, all-zero GEPs, aliases and barriers.
|
||||
///
|
||||
/// Returns the original uncasted value. If this is called on a non-pointer
|
||||
/// value, it returns 'this'. This function should be used only in
|
||||
/// Alias analysis.
|
||||
const Value *stripPointerCastsAndBarriers() const;
|
||||
Value *stripPointerCastsAndBarriers() {
|
||||
return const_cast<Value *>(
|
||||
static_cast<const Value *>(this)->stripPointerCastsAndBarriers());
|
||||
}
|
||||
|
||||
/// \brief Strip off pointer casts and all-zero GEPs.
|
||||
///
|
||||
/// Returns the original uncasted value. If this is called on a non-pointer
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public:
|
|||
int DwarfVersion = 0;
|
||||
|
||||
std::string ABIName;
|
||||
std::string SplitDwarfFile;
|
||||
|
||||
/// Additional paths to search for `.include` directives when using the
|
||||
/// integrated assembler.
|
||||
|
|
|
|||
|
|
@ -14,9 +14,19 @@
|
|||
#ifndef LLVM_OBJECT_ELF_H
|
||||
#define LLVM_OBJECT_ELF_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Object/ELFTypes.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
|
|
@ -41,27 +51,27 @@ template <class ELFT>
|
|||
class ELFFile {
|
||||
public:
|
||||
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
typedef typename ELFT::Ehdr Elf_Ehdr;
|
||||
typedef typename ELFT::Shdr Elf_Shdr;
|
||||
typedef typename ELFT::Sym Elf_Sym;
|
||||
typedef typename ELFT::Dyn Elf_Dyn;
|
||||
typedef typename ELFT::Phdr Elf_Phdr;
|
||||
typedef typename ELFT::Rel Elf_Rel;
|
||||
typedef typename ELFT::Rela Elf_Rela;
|
||||
typedef typename ELFT::Verdef Elf_Verdef;
|
||||
typedef typename ELFT::Verdaux Elf_Verdaux;
|
||||
typedef typename ELFT::Verneed Elf_Verneed;
|
||||
typedef typename ELFT::Vernaux Elf_Vernaux;
|
||||
typedef typename ELFT::Versym Elf_Versym;
|
||||
typedef typename ELFT::Hash Elf_Hash;
|
||||
typedef typename ELFT::GnuHash Elf_GnuHash;
|
||||
typedef typename ELFT::DynRange Elf_Dyn_Range;
|
||||
typedef typename ELFT::ShdrRange Elf_Shdr_Range;
|
||||
typedef typename ELFT::SymRange Elf_Sym_Range;
|
||||
typedef typename ELFT::RelRange Elf_Rel_Range;
|
||||
typedef typename ELFT::RelaRange Elf_Rela_Range;
|
||||
typedef typename ELFT::PhdrRange Elf_Phdr_Range;
|
||||
using uintX_t = typename ELFT::uint;
|
||||
using Elf_Ehdr = typename ELFT::Ehdr;
|
||||
using Elf_Shdr = typename ELFT::Shdr;
|
||||
using Elf_Sym = typename ELFT::Sym;
|
||||
using Elf_Dyn = typename ELFT::Dyn;
|
||||
using Elf_Phdr = typename ELFT::Phdr;
|
||||
using Elf_Rel = typename ELFT::Rel;
|
||||
using Elf_Rela = typename ELFT::Rela;
|
||||
using Elf_Verdef = typename ELFT::Verdef;
|
||||
using Elf_Verdaux = typename ELFT::Verdaux;
|
||||
using Elf_Verneed = typename ELFT::Verneed;
|
||||
using Elf_Vernaux = typename ELFT::Vernaux;
|
||||
using Elf_Versym = typename ELFT::Versym;
|
||||
using Elf_Hash = typename ELFT::Hash;
|
||||
using Elf_GnuHash = typename ELFT::GnuHash;
|
||||
using Elf_Dyn_Range = typename ELFT::DynRange;
|
||||
using Elf_Shdr_Range = typename ELFT::ShdrRange;
|
||||
using Elf_Sym_Range = typename ELFT::SymRange;
|
||||
using Elf_Rel_Range = typename ELFT::RelRange;
|
||||
using Elf_Rela_Range = typename ELFT::RelaRange;
|
||||
using Elf_Phdr_Range = typename ELFT::PhdrRange;
|
||||
|
||||
const uint8_t *base() const {
|
||||
return reinterpret_cast<const uint8_t *>(Buf.data());
|
||||
|
|
@ -70,7 +80,6 @@ public:
|
|||
size_t getBufSize() const { return Buf.size(); }
|
||||
|
||||
private:
|
||||
|
||||
StringRef Buf;
|
||||
|
||||
public:
|
||||
|
|
@ -161,10 +170,10 @@ public:
|
|||
Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr *Sec) const;
|
||||
};
|
||||
|
||||
typedef ELFFile<ELFType<support::little, false>> ELF32LEFile;
|
||||
typedef ELFFile<ELFType<support::little, true>> ELF64LEFile;
|
||||
typedef ELFFile<ELFType<support::big, false>> ELF32BEFile;
|
||||
typedef ELFFile<ELFType<support::big, true>> ELF64BEFile;
|
||||
using ELF32LEFile = ELFFile<ELFType<support::little, false>>;
|
||||
using ELF64LEFile = ELFFile<ELFType<support::little, true>>;
|
||||
using ELF32BEFile = ELFFile<ELFType<support::big, false>>;
|
||||
using ELF64BEFile = ELFFile<ELFType<support::big, true>>;
|
||||
|
||||
template <class ELFT>
|
||||
inline Expected<const typename ELFT::Shdr *>
|
||||
|
|
@ -194,7 +203,7 @@ ELFFile<ELFT>::getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
|
|||
ArrayRef<Elf_Word> ShndxTable) const {
|
||||
uint32_t Index = Sym->st_shndx;
|
||||
if (Index == ELF::SHN_XINDEX) {
|
||||
auto ErrorOrIndex = object::getExtendedSymbolTableIndex<ELFT>(
|
||||
auto ErrorOrIndex = getExtendedSymbolTableIndex<ELFT>(
|
||||
Sym, Syms.begin(), ShndxTable);
|
||||
if (!ErrorOrIndex)
|
||||
return ErrorOrIndex.takeError();
|
||||
|
|
@ -519,7 +528,8 @@ inline unsigned hashSysV(StringRef SymbolName) {
|
|||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
} // end namespace object
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_ELF_H
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Object/SymbolicFile.h"
|
||||
#include "llvm/Support/ARMAttributeParser.h"
|
||||
#include "llvm/Support/ARMBuildAttributes.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
|
@ -42,13 +43,11 @@ namespace llvm {
|
|||
namespace object {
|
||||
|
||||
class elf_symbol_iterator;
|
||||
class ELFSymbolRef;
|
||||
class ELFRelocationRef;
|
||||
|
||||
class ELFObjectFileBase : public ObjectFile {
|
||||
friend class ELFSymbolRef;
|
||||
friend class ELFSectionRef;
|
||||
friend class ELFRelocationRef;
|
||||
friend class ELFSectionRef;
|
||||
friend class ELFSymbolRef;
|
||||
|
||||
protected:
|
||||
ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source);
|
||||
|
|
@ -65,7 +64,8 @@ protected:
|
|||
virtual ErrorOr<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0;
|
||||
|
||||
public:
|
||||
typedef iterator_range<elf_symbol_iterator> elf_symbol_iterator_range;
|
||||
using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>;
|
||||
|
||||
virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0;
|
||||
|
||||
elf_symbol_iterator_range symbols() const;
|
||||
|
|
@ -201,14 +201,14 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
|
|||
public:
|
||||
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
|
||||
|
||||
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
|
||||
using uintX_t = typename ELFFile<ELFT>::uintX_t;
|
||||
|
||||
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
|
||||
typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
|
||||
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
typedef typename ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
|
||||
using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym;
|
||||
using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr;
|
||||
using Elf_Ehdr = typename ELFFile<ELFT>::Elf_Ehdr;
|
||||
using Elf_Rel = typename ELFFile<ELFT>::Elf_Rel;
|
||||
using Elf_Rela = typename ELFFile<ELFT>::Elf_Rela;
|
||||
using Elf_Dyn = typename ELFFile<ELFT>::Elf_Dyn;
|
||||
|
||||
protected:
|
||||
ELFFile<ELFT> EF;
|
||||
|
|
@ -398,10 +398,10 @@ public:
|
|||
bool isRelocatableObject() const override;
|
||||
};
|
||||
|
||||
typedef ELFObjectFile<ELFType<support::little, false>> ELF32LEObjectFile;
|
||||
typedef ELFObjectFile<ELFType<support::little, true>> ELF64LEObjectFile;
|
||||
typedef ELFObjectFile<ELFType<support::big, false>> ELF32BEObjectFile;
|
||||
typedef ELFObjectFile<ELFType<support::big, true>> ELF64BEObjectFile;
|
||||
using ELF32LEObjectFile = ELFObjectFile<ELFType<support::little, false>>;
|
||||
using ELF64LEObjectFile = ELFObjectFile<ELFType<support::little, true>>;
|
||||
using ELF32BEObjectFile = ELFObjectFile<ELFType<support::big, false>>;
|
||||
using ELF64BEObjectFile = ELFObjectFile<ELFType<support::big, true>>;
|
||||
|
||||
template <class ELFT>
|
||||
void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const {
|
||||
|
|
|
|||
|
|
@ -11,10 +11,15 @@
|
|||
#define LLVM_OBJECT_ELFTYPES_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
|
|
@ -45,58 +50,58 @@ public:
|
|||
static const endianness TargetEndianness = E;
|
||||
static const bool Is64Bits = Is64;
|
||||
|
||||
typedef typename std::conditional<Is64, uint64_t, uint32_t>::type uint;
|
||||
typedef Elf_Ehdr_Impl<ELFType<E, Is64>> Ehdr;
|
||||
typedef Elf_Shdr_Impl<ELFType<E, Is64>> Shdr;
|
||||
typedef Elf_Sym_Impl<ELFType<E, Is64>> Sym;
|
||||
typedef Elf_Dyn_Impl<ELFType<E, Is64>> Dyn;
|
||||
typedef Elf_Phdr_Impl<ELFType<E, Is64>> Phdr;
|
||||
typedef Elf_Rel_Impl<ELFType<E, Is64>, false> Rel;
|
||||
typedef Elf_Rel_Impl<ELFType<E, Is64>, true> Rela;
|
||||
typedef Elf_Verdef_Impl<ELFType<E, Is64>> Verdef;
|
||||
typedef Elf_Verdaux_Impl<ELFType<E, Is64>> Verdaux;
|
||||
typedef Elf_Verneed_Impl<ELFType<E, Is64>> Verneed;
|
||||
typedef Elf_Vernaux_Impl<ELFType<E, Is64>> Vernaux;
|
||||
typedef Elf_Versym_Impl<ELFType<E, Is64>> Versym;
|
||||
typedef Elf_Hash_Impl<ELFType<E, Is64>> Hash;
|
||||
typedef Elf_GnuHash_Impl<ELFType<E, Is64>> GnuHash;
|
||||
typedef Elf_Chdr_Impl<ELFType<E, Is64>> Chdr;
|
||||
typedef ArrayRef<Dyn> DynRange;
|
||||
typedef ArrayRef<Shdr> ShdrRange;
|
||||
typedef ArrayRef<Sym> SymRange;
|
||||
typedef ArrayRef<Rel> RelRange;
|
||||
typedef ArrayRef<Rela> RelaRange;
|
||||
typedef ArrayRef<Phdr> PhdrRange;
|
||||
using uint = typename std::conditional<Is64, uint64_t, uint32_t>::type;
|
||||
using Ehdr = Elf_Ehdr_Impl<ELFType<E, Is64>>;
|
||||
using Shdr = Elf_Shdr_Impl<ELFType<E, Is64>>;
|
||||
using Sym = Elf_Sym_Impl<ELFType<E, Is64>>;
|
||||
using Dyn = Elf_Dyn_Impl<ELFType<E, Is64>>;
|
||||
using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>;
|
||||
using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>;
|
||||
using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>;
|
||||
using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>;
|
||||
using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>;
|
||||
using Verneed = Elf_Verneed_Impl<ELFType<E, Is64>>;
|
||||
using Vernaux = Elf_Vernaux_Impl<ELFType<E, Is64>>;
|
||||
using Versym = Elf_Versym_Impl<ELFType<E, Is64>>;
|
||||
using Hash = Elf_Hash_Impl<ELFType<E, Is64>>;
|
||||
using GnuHash = Elf_GnuHash_Impl<ELFType<E, Is64>>;
|
||||
using Chdr = Elf_Chdr_Impl<ELFType<E, Is64>>;
|
||||
using DynRange = ArrayRef<Dyn>;
|
||||
using ShdrRange = ArrayRef<Shdr>;
|
||||
using SymRange = ArrayRef<Sym>;
|
||||
using RelRange = ArrayRef<Rel>;
|
||||
using RelaRange = ArrayRef<Rela>;
|
||||
using PhdrRange = ArrayRef<Phdr>;
|
||||
|
||||
typedef packed<uint16_t> Half;
|
||||
typedef packed<uint32_t> Word;
|
||||
typedef packed<int32_t> Sword;
|
||||
typedef packed<uint64_t> Xword;
|
||||
typedef packed<int64_t> Sxword;
|
||||
typedef packed<uint> Addr;
|
||||
typedef packed<uint> Off;
|
||||
using Half = packed<uint16_t>;
|
||||
using Word = packed<uint32_t>;
|
||||
using Sword = packed<int32_t>;
|
||||
using Xword = packed<uint64_t>;
|
||||
using Sxword = packed<int64_t>;
|
||||
using Addr = packed<uint>;
|
||||
using Off = packed<uint>;
|
||||
};
|
||||
|
||||
typedef ELFType<support::little, false> ELF32LE;
|
||||
typedef ELFType<support::big, false> ELF32BE;
|
||||
typedef ELFType<support::little, true> ELF64LE;
|
||||
typedef ELFType<support::big, true> ELF64BE;
|
||||
using ELF32LE = ELFType<support::little, false>;
|
||||
using ELF32BE = ELFType<support::big, false>;
|
||||
using ELF64LE = ELFType<support::little, true>;
|
||||
using ELF64BE = ELFType<support::big, true>;
|
||||
|
||||
// Use an alignment of 2 for the typedefs since that is the worst case for
|
||||
// ELF files in archives.
|
||||
|
||||
// Templates to choose Elf_Addr and Elf_Off depending on is64Bits.
|
||||
template <endianness target_endianness> struct ELFDataTypeTypedefHelperCommon {
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
uint16_t, target_endianness, 2> Elf_Half;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
uint32_t, target_endianness, 2> Elf_Word;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
int32_t, target_endianness, 2> Elf_Sword;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
uint64_t, target_endianness, 2> Elf_Xword;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
int64_t, target_endianness, 2> Elf_Sxword;
|
||||
using Elf_Half = support::detail::packed_endian_specific_integral<
|
||||
uint16_t, target_endianness, 2>;
|
||||
using Elf_Word = support::detail::packed_endian_specific_integral<
|
||||
uint32_t, target_endianness, 2>;
|
||||
using Elf_Sword = support::detail::packed_endian_specific_integral<
|
||||
int32_t, target_endianness, 2>;
|
||||
using Elf_Xword = support::detail::packed_endian_specific_integral<
|
||||
uint64_t, target_endianness, 2>;
|
||||
using Elf_Sxword = support::detail::packed_endian_specific_integral<
|
||||
int64_t, target_endianness, 2>;
|
||||
};
|
||||
|
||||
template <class ELFT> struct ELFDataTypeTypedefHelper;
|
||||
|
|
@ -105,34 +110,34 @@ template <class ELFT> struct ELFDataTypeTypedefHelper;
|
|||
template <endianness TargetEndianness>
|
||||
struct ELFDataTypeTypedefHelper<ELFType<TargetEndianness, false>>
|
||||
: ELFDataTypeTypedefHelperCommon<TargetEndianness> {
|
||||
typedef uint32_t value_type;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2> Elf_Addr;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2> Elf_Off;
|
||||
using value_type = uint32_t;
|
||||
using Elf_Addr = support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2>;
|
||||
using Elf_Off = support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2>;
|
||||
};
|
||||
|
||||
/// ELF 64bit types.
|
||||
template <endianness TargetEndianness>
|
||||
struct ELFDataTypeTypedefHelper<ELFType<TargetEndianness, true>>
|
||||
: ELFDataTypeTypedefHelperCommon<TargetEndianness> {
|
||||
typedef uint64_t value_type;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2> Elf_Addr;
|
||||
typedef support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2> Elf_Off;
|
||||
using value_type = uint64_t;
|
||||
using Elf_Addr = support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2>;
|
||||
using Elf_Off = support::detail::packed_endian_specific_integral<
|
||||
value_type, TargetEndianness, 2>;
|
||||
};
|
||||
|
||||
// I really don't like doing this, but the alternative is copypasta.
|
||||
|
||||
#define LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) \
|
||||
typedef typename ELFT::Addr Elf_Addr; \
|
||||
typedef typename ELFT::Off Elf_Off; \
|
||||
typedef typename ELFT::Half Elf_Half; \
|
||||
typedef typename ELFT::Word Elf_Word; \
|
||||
typedef typename ELFT::Sword Elf_Sword; \
|
||||
typedef typename ELFT::Xword Elf_Xword; \
|
||||
typedef typename ELFT::Sxword Elf_Sxword;
|
||||
using Elf_Addr = typename ELFT::Addr; \
|
||||
using Elf_Off = typename ELFT::Off; \
|
||||
using Elf_Half = typename ELFT::Half; \
|
||||
using Elf_Word = typename ELFT::Word; \
|
||||
using Elf_Sword = typename ELFT::Sword; \
|
||||
using Elf_Xword = typename ELFT::Xword; \
|
||||
using Elf_Sxword = typename ELFT::Sxword;
|
||||
|
||||
#define LLD_ELF_COMMA ,
|
||||
#define LLVM_ELF_IMPORT_TYPES(E, W) \
|
||||
|
|
@ -222,6 +227,7 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
|
|||
uint64_t getValue() const { return st_value; }
|
||||
void setBinding(unsigned char b) { setBindingAndType(b, getType()); }
|
||||
void setType(unsigned char t) { setBindingAndType(getBinding(), t); }
|
||||
|
||||
void setBindingAndType(unsigned char b, unsigned char t) {
|
||||
st_info = (b << 4) + (t & 0x0f);
|
||||
}
|
||||
|
|
@ -238,22 +244,29 @@ struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> {
|
|||
}
|
||||
|
||||
bool isAbsolute() const { return st_shndx == ELF::SHN_ABS; }
|
||||
|
||||
bool isCommon() const {
|
||||
return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON;
|
||||
}
|
||||
|
||||
bool isDefined() const { return !isUndefined(); }
|
||||
|
||||
bool isProcessorSpecific() const {
|
||||
return st_shndx >= ELF::SHN_LOPROC && st_shndx <= ELF::SHN_HIPROC;
|
||||
}
|
||||
|
||||
bool isOSSpecific() const {
|
||||
return st_shndx >= ELF::SHN_LOOS && st_shndx <= ELF::SHN_HIOS;
|
||||
}
|
||||
|
||||
bool isReserved() const {
|
||||
// ELF::SHN_HIRESERVE is 0xffff so st_shndx <= ELF::SHN_HIRESERVE is always
|
||||
// true and some compilers warn about it.
|
||||
return st_shndx >= ELF::SHN_LORESERVE;
|
||||
}
|
||||
|
||||
bool isUndefined() const { return st_shndx == ELF::SHN_UNDEF; }
|
||||
|
||||
bool isExternal() const {
|
||||
return getBinding() != ELF::STB_LOCAL;
|
||||
}
|
||||
|
|
@ -277,14 +290,12 @@ struct Elf_Versym_Impl {
|
|||
Elf_Half vs_index; // Version index with flags (e.g. VERSYM_HIDDEN)
|
||||
};
|
||||
|
||||
template <class ELFT> struct Elf_Verdaux_Impl;
|
||||
|
||||
/// Elf_Verdef: This is the structure of entries in the SHT_GNU_verdef section
|
||||
/// (.gnu.version_d). This structure is identical for ELF32 and ELF64.
|
||||
template <class ELFT>
|
||||
struct Elf_Verdef_Impl {
|
||||
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
|
||||
typedef Elf_Verdaux_Impl<ELFT> Elf_Verdaux;
|
||||
using Elf_Verdaux = Elf_Verdaux_Impl<ELFT>;
|
||||
Elf_Half vd_version; // Version of this structure (e.g. VER_DEF_CURRENT)
|
||||
Elf_Half vd_flags; // Bitwise flags (VER_DEF_*)
|
||||
Elf_Half vd_ndx; // Version index, used in .gnu.version entries
|
||||
|
|
@ -361,10 +372,10 @@ template <class ELFT>
|
|||
struct Elf_Dyn_Impl : Elf_Dyn_Base<ELFT> {
|
||||
using Elf_Dyn_Base<ELFT>::d_tag;
|
||||
using Elf_Dyn_Base<ELFT>::d_un;
|
||||
typedef typename std::conditional<ELFT::Is64Bits,
|
||||
int64_t, int32_t>::type intX_t;
|
||||
typedef typename std::conditional<ELFT::Is64Bits,
|
||||
uint64_t, uint32_t>::type uintX_t;
|
||||
using intX_t = typename std::conditional<ELFT::Is64Bits,
|
||||
int64_t, int32_t>::type;
|
||||
using uintX_t = typename std::conditional<ELFT::Is64Bits,
|
||||
uint64_t, uint32_t>::type;
|
||||
intX_t getTag() const { return d_tag; }
|
||||
uintX_t getVal() const { return d_un.d_val; }
|
||||
uintX_t getPtr() const { return d_un.d_ptr; }
|
||||
|
|
@ -430,6 +441,7 @@ struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> {
|
|||
return (t << 32) | ((t >> 8) & 0xff000000) | ((t >> 24) & 0x00ff0000) |
|
||||
((t >> 40) & 0x0000ff00) | ((t >> 56) & 0x000000ff);
|
||||
}
|
||||
|
||||
void setRInfo(uint64_t R, bool IsMips64EL) {
|
||||
if (IsMips64EL)
|
||||
r_info = (R >> 32) | ((R & 0xff000000) << 8) | ((R & 0x00ff0000) << 24) |
|
||||
|
|
@ -483,15 +495,15 @@ struct Elf_Ehdr_Impl {
|
|||
Elf_Half e_shnum; // Number of entries in the section header table
|
||||
Elf_Half e_shstrndx; // Section header table index of section name
|
||||
// string table
|
||||
|
||||
bool checkMagic() const {
|
||||
return (memcmp(e_ident, ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0;
|
||||
}
|
||||
|
||||
unsigned char getFileClass() const { return e_ident[ELF::EI_CLASS]; }
|
||||
unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; }
|
||||
};
|
||||
|
||||
template <class ELFT> struct Elf_Phdr_Impl;
|
||||
|
||||
template <endianness TargetEndianness>
|
||||
struct Elf_Phdr_Impl<ELFType<TargetEndianness, false>> {
|
||||
LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
|
||||
|
|
@ -582,7 +594,7 @@ struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> {
|
|||
template <class ELFT>
|
||||
struct Elf_Mips_RegInfo;
|
||||
|
||||
template <llvm::support::endianness TargetEndianness>
|
||||
template <support::endianness TargetEndianness>
|
||||
struct Elf_Mips_RegInfo<ELFType<TargetEndianness, false>> {
|
||||
LLVM_ELF_IMPORT_TYPES(TargetEndianness, false)
|
||||
Elf_Word ri_gprmask; // bit-mask of used general registers
|
||||
|
|
@ -590,7 +602,7 @@ struct Elf_Mips_RegInfo<ELFType<TargetEndianness, false>> {
|
|||
Elf_Addr ri_gp_value; // gp register value
|
||||
};
|
||||
|
||||
template <llvm::support::endianness TargetEndianness>
|
||||
template <support::endianness TargetEndianness>
|
||||
struct Elf_Mips_RegInfo<ELFType<TargetEndianness, true>> {
|
||||
LLVM_ELF_IMPORT_TYPES(TargetEndianness, true)
|
||||
Elf_Word ri_gprmask; // bit-mask of used general registers
|
||||
|
|
@ -609,7 +621,7 @@ template <class ELFT> struct Elf_Mips_Options {
|
|||
Elf_Word info; // Kind-specific information
|
||||
|
||||
Elf_Mips_RegInfo<ELFT> &getRegInfo() {
|
||||
assert(kind == llvm::ELF::ODK_REGINFO);
|
||||
assert(kind == ELF::ODK_REGINFO);
|
||||
return *reinterpret_cast<Elf_Mips_RegInfo<ELFT> *>(
|
||||
(uint8_t *)this + sizeof(Elf_Mips_Options));
|
||||
}
|
||||
|
|
@ -637,4 +649,4 @@ template <class ELFT> struct Elf_Mips_ABIFlags {
|
|||
} // end namespace object.
|
||||
} // end namespace llvm.
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_ELFTYPES_H
|
||||
|
|
|
|||
|
|
@ -25,23 +25,31 @@
|
|||
#define LLVM_OBJECT_IRSYMTAB_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/Object/SymbolicFile.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace irsymtab {
|
||||
|
||||
namespace storage {
|
||||
|
||||
// The data structures in this namespace define the low-level serialization
|
||||
// format. Clients that just want to read a symbol table should use the
|
||||
// irsymtab::Reader class.
|
||||
|
||||
typedef support::ulittle32_t Word;
|
||||
using Word = support::ulittle32_t;
|
||||
|
||||
/// A reference to a string in the string table.
|
||||
struct Str {
|
||||
Word Offset, Size;
|
||||
|
||||
StringRef get(StringRef Strtab) const {
|
||||
return {Strtab.data() + Offset, Size};
|
||||
}
|
||||
|
|
@ -50,6 +58,7 @@ struct Str {
|
|||
/// A reference to a range of objects in the symbol table.
|
||||
template <typename T> struct Range {
|
||||
Word Offset, Size;
|
||||
|
||||
ArrayRef<T> get(StringRef Symtab) const {
|
||||
return {reinterpret_cast<const T *>(Symtab.data() + Offset), Size};
|
||||
}
|
||||
|
|
@ -122,7 +131,7 @@ struct Header {
|
|||
Str COFFLinkerOpts;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace storage
|
||||
|
||||
/// Fills in Symtab and Strtab with a valid symbol and string table for Mods.
|
||||
Error build(ArrayRef<Module *> Mods, SmallVector<char, 0> &Symtab,
|
||||
|
|
@ -152,18 +161,22 @@ struct Symbol {
|
|||
int getComdatIndex() const { return ComdatIndex; }
|
||||
|
||||
using S = storage::Symbol;
|
||||
|
||||
GlobalValue::VisibilityTypes getVisibility() const {
|
||||
return GlobalValue::VisibilityTypes((Flags >> S::FB_visibility) & 3);
|
||||
}
|
||||
|
||||
bool isUndefined() const { return (Flags >> S::FB_undefined) & 1; }
|
||||
bool isWeak() const { return (Flags >> S::FB_weak) & 1; }
|
||||
bool isCommon() const { return (Flags >> S::FB_common) & 1; }
|
||||
bool isIndirect() const { return (Flags >> S::FB_indirect) & 1; }
|
||||
bool isUsed() const { return (Flags >> S::FB_used) & 1; }
|
||||
bool isTLS() const { return (Flags >> S::FB_tls) & 1; }
|
||||
|
||||
bool canBeOmittedFromSymbolTable() const {
|
||||
return (Flags >> S::FB_may_omit) & 1;
|
||||
}
|
||||
|
||||
bool isGlobal() const { return (Flags >> S::FB_global) & 1; }
|
||||
bool isFormatSpecific() const { return (Flags >> S::FB_format_specific) & 1; }
|
||||
bool isUnnamedAddr() const { return (Flags >> S::FB_unnamed_addr) & 1; }
|
||||
|
|
@ -173,6 +186,7 @@ struct Symbol {
|
|||
assert(isCommon());
|
||||
return CommonSize;
|
||||
}
|
||||
|
||||
uint32_t getCommonAlignment() const {
|
||||
assert(isCommon());
|
||||
return CommonAlign;
|
||||
|
|
@ -197,9 +211,11 @@ class Reader {
|
|||
ArrayRef<storage::Uncommon> Uncommons;
|
||||
|
||||
StringRef str(storage::Str S) const { return S.get(Strtab); }
|
||||
|
||||
template <typename T> ArrayRef<T> range(storage::Range<T> R) const {
|
||||
return R.get(Symtab);
|
||||
}
|
||||
|
||||
const storage::Header &header() const {
|
||||
return *reinterpret_cast<const storage::Header *>(Symtab.data());
|
||||
}
|
||||
|
|
@ -215,7 +231,7 @@ public:
|
|||
Uncommons = range(header().Uncommons);
|
||||
}
|
||||
|
||||
typedef iterator_range<object::content_iterator<SymbolRef>> symbol_range;
|
||||
using symbol_range = iterator_range<object::content_iterator<SymbolRef>>;
|
||||
|
||||
/// Returns the symbol table for the entire bitcode file.
|
||||
/// The symbols enumerated by this method are ephemeral, but they can be
|
||||
|
|
@ -298,8 +314,7 @@ inline Reader::symbol_range Reader::module_symbols(unsigned I) const {
|
|||
SymbolRef(MEnd, MEnd, nullptr, this)};
|
||||
}
|
||||
|
||||
}
|
||||
} // end namespace irsymtab
|
||||
} // end namespace llvm
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_IRSYMTAB_H
|
||||
|
|
|
|||
|
|
@ -16,10 +16,25 @@
|
|||
#define LLVM_OBJECT_MACHO_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Object/SymbolicFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/MachO.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
|
|
@ -28,11 +43,10 @@ namespace object {
|
|||
/// data in code entry in the table in a Mach-O object file.
|
||||
class DiceRef {
|
||||
DataRefImpl DicePimpl;
|
||||
const ObjectFile *OwningObject;
|
||||
const ObjectFile *OwningObject = nullptr;
|
||||
|
||||
public:
|
||||
DiceRef() : OwningObject(nullptr) { }
|
||||
|
||||
DiceRef() = default;
|
||||
DiceRef(DataRefImpl DiceP, const ObjectFile *Owner);
|
||||
|
||||
bool operator==(const DiceRef &Other) const;
|
||||
|
|
@ -47,7 +61,7 @@ public:
|
|||
DataRefImpl getRawDataRefImpl() const;
|
||||
const ObjectFile *getObjectFile() const;
|
||||
};
|
||||
typedef content_iterator<DiceRef> dice_iterator;
|
||||
using dice_iterator = content_iterator<DiceRef>;
|
||||
|
||||
/// ExportEntry encapsulates the current-state-of-the-walk used when doing a
|
||||
/// non-recursive walk of the trie data structure. This allows you to iterate
|
||||
|
|
@ -71,6 +85,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class MachOObjectFile;
|
||||
|
||||
void moveToFirst();
|
||||
void moveToEnd();
|
||||
uint64_t readULEB128(const uint8_t *&p);
|
||||
|
|
@ -80,25 +95,26 @@ private:
|
|||
// Represents a node in the mach-o exports trie.
|
||||
struct NodeState {
|
||||
NodeState(const uint8_t *Ptr);
|
||||
|
||||
const uint8_t *Start;
|
||||
const uint8_t *Current;
|
||||
uint64_t Flags;
|
||||
uint64_t Address;
|
||||
uint64_t Other;
|
||||
const char *ImportName;
|
||||
unsigned ChildCount;
|
||||
unsigned NextChildIndex;
|
||||
unsigned ParentStringLength;
|
||||
bool IsExportNode;
|
||||
uint64_t Flags = 0;
|
||||
uint64_t Address = 0;
|
||||
uint64_t Other = 0;
|
||||
const char *ImportName = nullptr;
|
||||
unsigned ChildCount = 0;
|
||||
unsigned NextChildIndex = 0;
|
||||
unsigned ParentStringLength = 0;
|
||||
bool IsExportNode = false;
|
||||
};
|
||||
|
||||
ArrayRef<uint8_t> Trie;
|
||||
SmallString<256> CumulativeString;
|
||||
SmallVector<NodeState, 16> Stack;
|
||||
bool Malformed;
|
||||
bool Done;
|
||||
bool Malformed = false;
|
||||
bool Done = false;
|
||||
};
|
||||
typedef content_iterator<ExportEntry> export_iterator;
|
||||
using export_iterator = content_iterator<ExportEntry>;
|
||||
|
||||
// Segment info so SegIndex/SegOffset pairs in a Mach-O Bind or Rebase entry
|
||||
// can be checked and translated. Only the SegIndex/SegOffset pairs from
|
||||
|
|
@ -106,7 +122,7 @@ typedef content_iterator<ExportEntry> export_iterator;
|
|||
// address() methods below.
|
||||
class BindRebaseSegInfo {
|
||||
public:
|
||||
BindRebaseSegInfo(const object::MachOObjectFile *Obj);
|
||||
BindRebaseSegInfo(const MachOObjectFile *Obj);
|
||||
|
||||
// Used to check a Mach-O Bind or Rebase entry for errors when iterating.
|
||||
const char *checkSegAndOffset(int32_t SegIndex, uint64_t SegOffset,
|
||||
|
|
@ -130,6 +146,7 @@ private:
|
|||
int32_t SegmentIndex;
|
||||
};
|
||||
const SectionInfo &findSection(int32_t SegIndex, uint64_t SegOffset);
|
||||
|
||||
SmallVector<SectionInfo, 32> Sections;
|
||||
int32_t MaxSegIndex;
|
||||
};
|
||||
|
|
@ -159,6 +176,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class MachOObjectFile;
|
||||
|
||||
void moveToFirst();
|
||||
void moveToEnd();
|
||||
uint64_t readULEB128(const char **error);
|
||||
|
|
@ -167,15 +185,15 @@ private:
|
|||
const MachOObjectFile *O;
|
||||
ArrayRef<uint8_t> Opcodes;
|
||||
const uint8_t *Ptr;
|
||||
uint64_t SegmentOffset;
|
||||
int32_t SegmentIndex;
|
||||
uint64_t RemainingLoopCount;
|
||||
uint64_t AdvanceAmount;
|
||||
uint8_t RebaseType;
|
||||
uint64_t SegmentOffset = 0;
|
||||
int32_t SegmentIndex = -1;
|
||||
uint64_t RemainingLoopCount = 0;
|
||||
uint64_t AdvanceAmount = 0;
|
||||
uint8_t RebaseType = 0;
|
||||
uint8_t PointerSize;
|
||||
bool Done;
|
||||
bool Done = false;
|
||||
};
|
||||
typedef content_iterator<MachORebaseEntry> rebase_iterator;
|
||||
using rebase_iterator = content_iterator<MachORebaseEntry>;
|
||||
|
||||
/// MachOBindEntry encapsulates the current state in the decompression of
|
||||
/// binding opcodes. This allows you to iterate through the compressed table of
|
||||
|
|
@ -209,6 +227,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class MachOObjectFile;
|
||||
|
||||
void moveToFirst();
|
||||
void moveToEnd();
|
||||
uint64_t readULEB128(const char **error);
|
||||
|
|
@ -218,21 +237,21 @@ private:
|
|||
const MachOObjectFile *O;
|
||||
ArrayRef<uint8_t> Opcodes;
|
||||
const uint8_t *Ptr;
|
||||
uint64_t SegmentOffset;
|
||||
int32_t SegmentIndex;
|
||||
uint64_t SegmentOffset = 0;
|
||||
int32_t SegmentIndex = -1;
|
||||
StringRef SymbolName;
|
||||
bool LibraryOrdinalSet;
|
||||
int Ordinal;
|
||||
uint32_t Flags;
|
||||
int64_t Addend;
|
||||
uint64_t RemainingLoopCount;
|
||||
uint64_t AdvanceAmount;
|
||||
uint8_t BindType;
|
||||
bool LibraryOrdinalSet = false;
|
||||
int Ordinal = 0;
|
||||
uint32_t Flags = 0;
|
||||
int64_t Addend = 0;
|
||||
uint64_t RemainingLoopCount = 0;
|
||||
uint64_t AdvanceAmount = 0;
|
||||
uint8_t BindType = 0;
|
||||
uint8_t PointerSize;
|
||||
Kind TableKind;
|
||||
bool Done;
|
||||
bool Done = false;
|
||||
};
|
||||
typedef content_iterator<MachOBindEntry> bind_iterator;
|
||||
using bind_iterator = content_iterator<MachOBindEntry>;
|
||||
|
||||
class MachOObjectFile : public ObjectFile {
|
||||
public:
|
||||
|
|
@ -240,8 +259,8 @@ public:
|
|||
const char *Ptr; // Where in memory the load command is.
|
||||
MachO::load_command C; // The command itself.
|
||||
};
|
||||
typedef SmallVector<LoadCommandInfo, 4> LoadCommandList;
|
||||
typedef LoadCommandList::const_iterator load_command_iterator;
|
||||
using LoadCommandList = SmallVector<LoadCommandInfo, 4>;
|
||||
using load_command_iterator = LoadCommandList::const_iterator;
|
||||
|
||||
static Expected<std::unique_ptr<MachOObjectFile>>
|
||||
create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
|
||||
|
|
@ -563,7 +582,7 @@ public:
|
|||
case MachO::PLATFORM_BRIDGEOS: return "bridgeos";
|
||||
default:
|
||||
std::string ret;
|
||||
llvm::raw_string_ostream ss(ret);
|
||||
raw_string_ostream ss(ret);
|
||||
ss << format_hex(platform, 8, true);
|
||||
return ss.str();
|
||||
}
|
||||
|
|
@ -576,7 +595,7 @@ public:
|
|||
case MachO::TOOL_LD: return "ld";
|
||||
default:
|
||||
std::string ret;
|
||||
llvm::raw_string_ostream ss(ret);
|
||||
raw_string_ostream ss(ret);
|
||||
ss << format_hex(tools, 8, true);
|
||||
return ss.str();
|
||||
}
|
||||
|
|
@ -595,7 +614,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits,
|
||||
Error &Err, uint32_t UniversalCputype = 0,
|
||||
uint32_t UniversalIndex = 0);
|
||||
|
|
@ -606,23 +624,23 @@ private:
|
|||
MachO::mach_header_64 Header64;
|
||||
MachO::mach_header Header;
|
||||
};
|
||||
typedef SmallVector<const char*, 1> SectionList;
|
||||
using SectionList = SmallVector<const char*, 1>;
|
||||
SectionList Sections;
|
||||
typedef SmallVector<const char*, 1> LibraryList;
|
||||
using LibraryList = SmallVector<const char*, 1>;
|
||||
LibraryList Libraries;
|
||||
LoadCommandList LoadCommands;
|
||||
typedef SmallVector<StringRef, 1> LibraryShortName;
|
||||
using LibraryShortName = SmallVector<StringRef, 1>;
|
||||
using BuildToolList = SmallVector<const char*, 1>;
|
||||
BuildToolList BuildTools;
|
||||
mutable LibraryShortName LibrariesShortNames;
|
||||
std::unique_ptr<BindRebaseSegInfo> BindRebaseSectionTable;
|
||||
const char *SymtabLoadCmd;
|
||||
const char *DysymtabLoadCmd;
|
||||
const char *DataInCodeLoadCmd;
|
||||
const char *LinkOptHintsLoadCmd;
|
||||
const char *DyldInfoLoadCmd;
|
||||
const char *UuidLoadCmd;
|
||||
bool HasPageZeroSegment;
|
||||
const char *SymtabLoadCmd = nullptr;
|
||||
const char *DysymtabLoadCmd = nullptr;
|
||||
const char *DataInCodeLoadCmd = nullptr;
|
||||
const char *LinkOptHintsLoadCmd = nullptr;
|
||||
const char *DyldInfoLoadCmd = nullptr;
|
||||
const char *UuidLoadCmd = nullptr;
|
||||
bool HasPageZeroSegment = false;
|
||||
};
|
||||
|
||||
/// DiceRef
|
||||
|
|
@ -679,7 +697,7 @@ inline const ObjectFile *DiceRef::getObjectFile() const {
|
|||
return OwningObject;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // end namespace object
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_MACHO_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===- ModuleSummaryIndexObjectFile.h - Summary index file implementation -=//
|
||||
//===- ModuleSummaryIndexObjectFile.h - Summary index file implementation -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -14,14 +14,22 @@
|
|||
#ifndef LLVM_OBJECT_MODULESUMMARYINDEXOBJECTFILE_H
|
||||
#define LLVM_OBJECT_MODULESUMMARYINDEXOBJECTFILE_H
|
||||
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/SymbolicFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ModuleSummaryIndex;
|
||||
class Module;
|
||||
|
||||
namespace object {
|
||||
|
||||
class ObjectFile;
|
||||
|
||||
/// This class is used to read just the module summary index related
|
||||
|
|
@ -41,15 +49,18 @@ public:
|
|||
void moveSymbolNext(DataRefImpl &Symb) const override {
|
||||
llvm_unreachable("not implemented");
|
||||
}
|
||||
|
||||
std::error_code printSymbolName(raw_ostream &OS,
|
||||
DataRefImpl Symb) const override {
|
||||
llvm_unreachable("not implemented");
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
uint32_t getSymbolFlags(DataRefImpl Symb) const override {
|
||||
llvm_unreachable("not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
basic_symbol_iterator symbol_begin() const override {
|
||||
llvm_unreachable("not implemented");
|
||||
return basic_symbol_iterator(BasicSymbolRef());
|
||||
|
|
@ -85,7 +96,8 @@ public:
|
|||
static Expected<std::unique_ptr<ModuleSummaryIndexObjectFile>>
|
||||
create(MemoryBufferRef Object);
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace object
|
||||
|
||||
/// Parse the module summary index out of an IR file and return the module
|
||||
/// summary index object if found, or nullptr if not. If Identifier is
|
||||
|
|
@ -94,6 +106,7 @@ public:
|
|||
/// containing minimized bitcode just for the thin link.
|
||||
Expected<std::unique_ptr<ModuleSummaryIndex>>
|
||||
getModuleSummaryIndexForFile(StringRef Path, StringRef Identifier = "");
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_OBJECT_MODULESUMMARYINDEXOBJECTFILE_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===- ModuleSymbolTable.h - symbol table for in-memory IR ----------------===//
|
||||
//===- ModuleSymbolTable.h - symbol table for in-memory IR ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -16,22 +16,24 @@
|
|||
#ifndef LLVM_OBJECT_MODULESYMBOLTABLE_H
|
||||
#define LLVM_OBJECT_MODULESYMBOLTABLE_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/Object/SymbolicFile.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GlobalValue;
|
||||
class RecordStreamer;
|
||||
|
||||
class ModuleSymbolTable {
|
||||
public:
|
||||
typedef std::pair<std::string, uint32_t> AsmSymbol;
|
||||
typedef PointerUnion<GlobalValue *, AsmSymbol *> Symbol;
|
||||
using AsmSymbol = std::pair<std::string, uint32_t>;
|
||||
using Symbol = PointerUnion<GlobalValue *, AsmSymbol *>;
|
||||
|
||||
private:
|
||||
Module *FirstMod = nullptr;
|
||||
|
|
@ -57,6 +59,6 @@ public:
|
|||
function_ref<void(StringRef, object::BasicSymbolRef::Flags)> AsmSymbol);
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_MODULESYMBOLTABLE_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-- RelocVisitor.h - Visitor for object file relocations -*- C++ -*-===//
|
||||
//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -16,34 +16,38 @@
|
|||
#ifndef LLVM_OBJECT_RELOCVISITOR_H
|
||||
#define LLVM_OBJECT_RELOCVISITOR_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Object/ELFObjectFile.h"
|
||||
#include "llvm/Object/MachO.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MachO.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
|
||||
struct RelocToApply {
|
||||
// The computed value after applying the relevant relocations.
|
||||
int64_t Value;
|
||||
int64_t Value = 0;
|
||||
|
||||
// The width of the value; how many bytes to touch when applying the
|
||||
// relocation.
|
||||
char Width;
|
||||
char Width = 0;
|
||||
|
||||
RelocToApply() = default;
|
||||
RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
|
||||
RelocToApply() : Value(0), Width(0) {}
|
||||
};
|
||||
|
||||
/// @brief Base class for object file relocation visitors.
|
||||
class RelocVisitor {
|
||||
public:
|
||||
explicit RelocVisitor(const ObjectFile &Obj)
|
||||
: ObjToVisit(Obj), HasError(false) {}
|
||||
explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {}
|
||||
|
||||
// TODO: Should handle multiple applied relocations via either passing in the
|
||||
// previously computed value or just count paired relocations as a single
|
||||
|
|
@ -64,22 +68,22 @@ public:
|
|||
|
||||
private:
|
||||
const ObjectFile &ObjToVisit;
|
||||
bool HasError;
|
||||
bool HasError = false;
|
||||
|
||||
RelocToApply visitELF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
|
||||
if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
|
||||
switch (ObjToVisit.getArch()) {
|
||||
case Triple::x86_64:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_X86_64_NONE:
|
||||
case ELF::R_X86_64_NONE:
|
||||
return visitELF_X86_64_NONE(R);
|
||||
case llvm::ELF::R_X86_64_64:
|
||||
case ELF::R_X86_64_64:
|
||||
return visitELF_X86_64_64(R, Value);
|
||||
case llvm::ELF::R_X86_64_PC32:
|
||||
case ELF::R_X86_64_PC32:
|
||||
return visitELF_X86_64_PC32(R, Value);
|
||||
case llvm::ELF::R_X86_64_32:
|
||||
case ELF::R_X86_64_32:
|
||||
return visitELF_X86_64_32(R, Value);
|
||||
case llvm::ELF::R_X86_64_32S:
|
||||
case ELF::R_X86_64_32S:
|
||||
return visitELF_X86_64_32S(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -88,9 +92,9 @@ private:
|
|||
case Triple::aarch64:
|
||||
case Triple::aarch64_be:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_AARCH64_ABS32:
|
||||
case ELF::R_AARCH64_ABS32:
|
||||
return visitELF_AARCH64_ABS32(R, Value);
|
||||
case llvm::ELF::R_AARCH64_ABS64:
|
||||
case ELF::R_AARCH64_ABS64:
|
||||
return visitELF_AARCH64_ABS64(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -99,9 +103,9 @@ private:
|
|||
case Triple::bpfel:
|
||||
case Triple::bpfeb:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_BPF_64_64:
|
||||
case ELF::R_BPF_64_64:
|
||||
return visitELF_BPF_64_64(R, Value);
|
||||
case llvm::ELF::R_BPF_64_32:
|
||||
case ELF::R_BPF_64_32:
|
||||
return visitELF_BPF_64_32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -110,9 +114,9 @@ private:
|
|||
case Triple::mips64el:
|
||||
case Triple::mips64:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_MIPS_32:
|
||||
case ELF::R_MIPS_32:
|
||||
return visitELF_MIPS64_32(R, Value);
|
||||
case llvm::ELF::R_MIPS_64:
|
||||
case ELF::R_MIPS_64:
|
||||
return visitELF_MIPS64_64(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -121,9 +125,9 @@ private:
|
|||
case Triple::ppc64le:
|
||||
case Triple::ppc64:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_PPC64_ADDR32:
|
||||
case ELF::R_PPC64_ADDR32:
|
||||
return visitELF_PPC64_ADDR32(R, Value);
|
||||
case llvm::ELF::R_PPC64_ADDR64:
|
||||
case ELF::R_PPC64_ADDR64:
|
||||
return visitELF_PPC64_ADDR64(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -131,9 +135,9 @@ private:
|
|||
}
|
||||
case Triple::systemz:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_390_32:
|
||||
case ELF::R_390_32:
|
||||
return visitELF_390_32(R, Value);
|
||||
case llvm::ELF::R_390_64:
|
||||
case ELF::R_390_64:
|
||||
return visitELF_390_64(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -141,11 +145,11 @@ private:
|
|||
}
|
||||
case Triple::sparcv9:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_SPARC_32:
|
||||
case llvm::ELF::R_SPARC_UA32:
|
||||
case ELF::R_SPARC_32:
|
||||
case ELF::R_SPARC_UA32:
|
||||
return visitELF_SPARCV9_32(R, Value);
|
||||
case llvm::ELF::R_SPARC_64:
|
||||
case llvm::ELF::R_SPARC_UA64:
|
||||
case ELF::R_SPARC_64:
|
||||
case ELF::R_SPARC_UA64:
|
||||
return visitELF_SPARCV9_64(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -153,9 +157,9 @@ private:
|
|||
}
|
||||
case Triple::amdgcn:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_AMDGPU_ABS32:
|
||||
case ELF::R_AMDGPU_ABS32:
|
||||
return visitELF_AMDGPU_ABS32(R, Value);
|
||||
case llvm::ELF::R_AMDGPU_ABS64:
|
||||
case ELF::R_AMDGPU_ABS64:
|
||||
return visitELF_AMDGPU_ABS64(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -169,11 +173,11 @@ private:
|
|||
switch (ObjToVisit.getArch()) {
|
||||
case Triple::x86:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_386_NONE:
|
||||
case ELF::R_386_NONE:
|
||||
return visitELF_386_NONE(R);
|
||||
case llvm::ELF::R_386_32:
|
||||
case ELF::R_386_32:
|
||||
return visitELF_386_32(R, Value);
|
||||
case llvm::ELF::R_386_PC32:
|
||||
case ELF::R_386_PC32:
|
||||
return visitELF_386_PC32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -181,7 +185,7 @@ private:
|
|||
}
|
||||
case Triple::ppc:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_PPC_ADDR32:
|
||||
case ELF::R_PPC_ADDR32:
|
||||
return visitELF_PPC_ADDR32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -193,12 +197,12 @@ private:
|
|||
default:
|
||||
HasError = true;
|
||||
return RelocToApply();
|
||||
case llvm::ELF::R_ARM_ABS32:
|
||||
case ELF::R_ARM_ABS32:
|
||||
return visitELF_ARM_ABS32(R, Value);
|
||||
}
|
||||
case Triple::lanai:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_LANAI_32:
|
||||
case ELF::R_LANAI_32:
|
||||
return visitELF_Lanai_32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -207,7 +211,7 @@ private:
|
|||
case Triple::mipsel:
|
||||
case Triple::mips:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_MIPS_32:
|
||||
case ELF::R_MIPS_32:
|
||||
return visitELF_MIPS_32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -215,8 +219,8 @@ private:
|
|||
}
|
||||
case Triple::sparc:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_SPARC_32:
|
||||
case llvm::ELF::R_SPARC_UA32:
|
||||
case ELF::R_SPARC_32:
|
||||
case ELF::R_SPARC_UA32:
|
||||
return visitELF_SPARC_32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -224,7 +228,7 @@ private:
|
|||
}
|
||||
case Triple::hexagon:
|
||||
switch (RelocType) {
|
||||
case llvm::ELF::R_HEX_32:
|
||||
case ELF::R_HEX_32:
|
||||
return visitELF_HEX_32(R, Value);
|
||||
default:
|
||||
HasError = true;
|
||||
|
|
@ -483,6 +487,7 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // end namespace object
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_OBJECT_RELOCVISITOR_H
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===-------- StackMapParser.h - StackMap Parsing Support -------*- C++ -*-===//
|
||||
//===- StackMapParser.h - StackMap Parsing Support --------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -11,7 +11,11 @@
|
|||
#define LLVM_CODEGEN_STACKMAPPARSER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -19,12 +23,11 @@ namespace llvm {
|
|||
template <support::endianness Endianness>
|
||||
class StackMapV2Parser {
|
||||
public:
|
||||
|
||||
template <typename AccessorT>
|
||||
class AccessorIterator {
|
||||
public:
|
||||
|
||||
AccessorIterator(AccessorT A) : A(A) {}
|
||||
|
||||
AccessorIterator& operator++() { A = A.next(); return *this; }
|
||||
AccessorIterator operator++(int) {
|
||||
auto tmp = *this;
|
||||
|
|
@ -48,8 +51,8 @@ public:
|
|||
/// Accessor for function records.
|
||||
class FunctionAccessor {
|
||||
friend class StackMapV2Parser;
|
||||
public:
|
||||
|
||||
public:
|
||||
/// Get the function address.
|
||||
uint64_t getFunctionAddress() const {
|
||||
return read<uint64_t>(P);
|
||||
|
|
@ -80,13 +83,12 @@ public:
|
|||
/// Accessor for constants.
|
||||
class ConstantAccessor {
|
||||
friend class StackMapV2Parser;
|
||||
public:
|
||||
|
||||
public:
|
||||
/// Return the value of this constant.
|
||||
uint64_t getValue() const { return read<uint64_t>(P); }
|
||||
|
||||
private:
|
||||
|
||||
ConstantAccessor(const uint8_t *P) : P(P) {}
|
||||
|
||||
const static int ConstantAccessorSize = sizeof(uint64_t);
|
||||
|
|
@ -98,20 +100,16 @@ public:
|
|||
const uint8_t *P;
|
||||
};
|
||||
|
||||
// Forward-declare RecordAccessor so we can friend it below.
|
||||
class RecordAccessor;
|
||||
|
||||
enum class LocationKind : uint8_t {
|
||||
Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5
|
||||
};
|
||||
|
||||
|
||||
/// Accessor for location records.
|
||||
class LocationAccessor {
|
||||
friend class StackMapV2Parser;
|
||||
friend class RecordAccessor;
|
||||
public:
|
||||
|
||||
public:
|
||||
/// Get the Kind for this location.
|
||||
LocationKind getKind() const {
|
||||
return LocationKind(P[KindOffset]);
|
||||
|
|
@ -144,7 +142,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
LocationAccessor(const uint8_t *P) : P(P) {}
|
||||
|
||||
LocationAccessor next() const {
|
||||
|
|
@ -163,8 +160,8 @@ public:
|
|||
class LiveOutAccessor {
|
||||
friend class StackMapV2Parser;
|
||||
friend class RecordAccessor;
|
||||
public:
|
||||
|
||||
public:
|
||||
/// Get the Dwarf register number for this live-out.
|
||||
uint16_t getDwarfRegNum() const {
|
||||
return read<uint16_t>(P + DwarfRegNumOffset);
|
||||
|
|
@ -176,7 +173,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
LiveOutAccessor(const uint8_t *P) : P(P) {}
|
||||
|
||||
LiveOutAccessor next() const {
|
||||
|
|
@ -194,10 +190,10 @@ public:
|
|||
/// Accessor for stackmap records.
|
||||
class RecordAccessor {
|
||||
friend class StackMapV2Parser;
|
||||
public:
|
||||
|
||||
typedef AccessorIterator<LocationAccessor> location_iterator;
|
||||
typedef AccessorIterator<LiveOutAccessor> liveout_iterator;
|
||||
public:
|
||||
using location_iterator = AccessorIterator<LocationAccessor>;
|
||||
using liveout_iterator = AccessorIterator<LiveOutAccessor>;
|
||||
|
||||
/// Get the patchpoint/stackmap ID for this record.
|
||||
uint64_t getID() const {
|
||||
|
|
@ -254,7 +250,6 @@ public:
|
|||
return liveout_iterator(getLiveOut(0));
|
||||
}
|
||||
|
||||
|
||||
/// End iterator for live-outs.
|
||||
liveout_iterator liveouts_end() const {
|
||||
return liveout_iterator(getLiveOut(getNumLiveOuts()));
|
||||
|
|
@ -266,7 +261,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
RecordAccessor(const uint8_t *P) : P(P) {}
|
||||
|
||||
unsigned getNumLiveOutsOffset() const {
|
||||
|
|
@ -316,9 +310,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
typedef AccessorIterator<FunctionAccessor> function_iterator;
|
||||
typedef AccessorIterator<ConstantAccessor> constant_iterator;
|
||||
typedef AccessorIterator<RecordAccessor> record_iterator;
|
||||
using function_iterator = AccessorIterator<FunctionAccessor>;
|
||||
using constant_iterator = AccessorIterator<ConstantAccessor>;
|
||||
using record_iterator = AccessorIterator<RecordAccessor>;
|
||||
|
||||
/// Get the version number of this stackmap. (Always returns 2).
|
||||
unsigned getVersion() const { return 2; }
|
||||
|
|
@ -413,7 +407,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
static T read(const uint8_t *P) {
|
||||
return support::endian::read<T, Endianness, 1>(P);
|
||||
|
|
@ -441,6 +434,6 @@ private:
|
|||
std::vector<unsigned> StackMapRecordOffsets;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_STACKMAPPARSER_H
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef LLVM_OBJECT_WASM_H
|
||||
#define LLVM_OBJECT_WASM_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
|
@ -47,10 +49,10 @@ public:
|
|||
|
||||
class WasmSection {
|
||||
public:
|
||||
WasmSection() : Type(0), Offset(0) {}
|
||||
WasmSection() = default;
|
||||
|
||||
uint32_t Type; // Section type (See below)
|
||||
uint32_t Offset; // Offset with in the file
|
||||
uint32_t Type = 0; // Section type (See below)
|
||||
uint32_t Offset = 0; // Offset with in the file
|
||||
StringRef Name; // Section name (User-defined sections only)
|
||||
ArrayRef<uint8_t> Content; // Section content
|
||||
std::vector<wasm::WasmRelocation> Relocations; // Relocations for this section
|
||||
|
|
@ -74,12 +76,15 @@ public:
|
|||
const std::vector<wasm::WasmLimits>& memories() const { return Memories; }
|
||||
const std::vector<wasm::WasmGlobal>& globals() const { return Globals; }
|
||||
const std::vector<wasm::WasmExport>& exports() const { return Exports; }
|
||||
|
||||
const std::vector<wasm::WasmElemSegment>& elements() const {
|
||||
return ElemSegments;
|
||||
}
|
||||
|
||||
const std::vector<wasm::WasmDataSegment>& dataSegments() const {
|
||||
return DataSegments;
|
||||
}
|
||||
|
||||
const std::vector<wasm::WasmFunction>& functions() const { return Functions; }
|
||||
const ArrayRef<uint8_t>& code() const { return CodeSection; }
|
||||
uint32_t startFunction() const { return StartFunction; }
|
||||
|
|
@ -178,7 +183,7 @@ private:
|
|||
std::vector<WasmSymbol> Symbols;
|
||||
std::vector<wasm::WasmFunction> Functions;
|
||||
ArrayRef<uint8_t> CodeSection;
|
||||
uint32_t StartFunction;
|
||||
uint32_t StartFunction = -1;
|
||||
};
|
||||
|
||||
} // end namespace object
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ struct Relocation {
|
|||
RelocType Type;
|
||||
uint32_t Index;
|
||||
yaml::Hex32 Offset;
|
||||
yaml::Hex32 Addend;
|
||||
int32_t Addend;
|
||||
};
|
||||
|
||||
struct DataSegment {
|
||||
|
|
|
|||
|
|
@ -79,14 +79,6 @@ inline StringRef getInstrProfValueRangeProfFuncName() {
|
|||
return INSTR_PROF_VALUE_RANGE_PROF_FUNC_STR;
|
||||
}
|
||||
|
||||
/// Return the name of the section containing function coverage mapping
|
||||
/// data.
|
||||
std::string getInstrProfCoverageSectionName(const Module *M = nullptr);
|
||||
/// Similar to the above, but used by host tool (e.g, coverage) which has
|
||||
/// object format information. The section name returned is not prefixed
|
||||
/// with segment name.
|
||||
std::string getInstrProfCoverageSectionNameInObject(bool isCoff);
|
||||
|
||||
/// Return the name prefix of variables containing instrumented function names.
|
||||
inline StringRef getInstrProfNameVarPrefix() { return "__profn_"; }
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,13 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
BranchProbability &operator*=(uint32_t RHS) {
|
||||
assert(N != UnknownN &&
|
||||
"Unknown probability cannot participate in arithmetics.");
|
||||
N = (uint64_t(N) * RHS > D) ? D : N * RHS;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BranchProbability &operator/=(uint32_t RHS) {
|
||||
assert(N != UnknownN &&
|
||||
"Unknown probability cannot participate in arithmetics.");
|
||||
|
|
@ -135,6 +142,11 @@ public:
|
|||
return Prob *= RHS;
|
||||
}
|
||||
|
||||
BranchProbability operator*(uint32_t RHS) const {
|
||||
BranchProbability Prob(*this);
|
||||
return Prob *= RHS;
|
||||
}
|
||||
|
||||
BranchProbability operator/(uint32_t RHS) const {
|
||||
BranchProbability Prob(*this);
|
||||
return Prob /= RHS;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,9 @@ inline perms &operator&=(perms &l, perms r) {
|
|||
return l;
|
||||
}
|
||||
inline perms operator~(perms x) {
|
||||
return static_cast<perms>(~static_cast<unsigned short>(x));
|
||||
// Avoid UB by explicitly truncating the (unsigned) ~ result.
|
||||
return static_cast<perms>(
|
||||
static_cast<unsigned short>(~static_cast<unsigned short>(x)));
|
||||
}
|
||||
|
||||
class UniqueID {
|
||||
|
|
|
|||
|
|
@ -286,13 +286,13 @@ protected:
|
|||
NodeRef NewBBSucc = *GraphT::child_begin(NewBB);
|
||||
|
||||
std::vector<NodeRef> PredBlocks;
|
||||
for (const auto Pred : children<Inverse<N>>(NewBB))
|
||||
for (const auto &Pred : children<Inverse<N>>(NewBB))
|
||||
PredBlocks.push_back(Pred);
|
||||
|
||||
assert(!PredBlocks.empty() && "No predblocks?");
|
||||
|
||||
bool NewBBDominatesNewBBSucc = true;
|
||||
for (const auto Pred : children<Inverse<N>>(NewBBSucc)) {
|
||||
for (const auto &Pred : children<Inverse<N>>(NewBBSucc)) {
|
||||
if (Pred != NewBB && !dominates(NewBBSucc, Pred) &&
|
||||
isReachableFromEntry(Pred)) {
|
||||
NewBBDominatesNewBBSucc = false;
|
||||
|
|
|
|||
43
include/llvm/Support/KnownBits.h
Normal file
43
include/llvm/Support/KnownBits.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//===- llvm/Support/KnownBits.h - Stores known zeros/ones -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains a class for representing known zeros and ones used by
|
||||
// computeKnownBits.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_KNOWNBITS_H
|
||||
#define LLVM_SUPPORT_KNOWNBITS_H
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// For now this is a simple wrapper around two APInts.
|
||||
struct KnownBits {
|
||||
APInt Zero;
|
||||
APInt One;
|
||||
|
||||
// Default construct Zero and One.
|
||||
KnownBits() {}
|
||||
|
||||
/// Create a known bits object of BitWidth bits initialized to unknown.
|
||||
KnownBits(unsigned BitWidth) : Zero(BitWidth, 0), One(BitWidth, 0) {}
|
||||
|
||||
/// Get the bit width of this value.
|
||||
unsigned getBitWidth() const {
|
||||
assert(Zero.getBitWidth() == One.getBitWidth() &&
|
||||
"Zero and One should have the same width!");
|
||||
return Zero.getBitWidth();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
@ -606,7 +606,7 @@ public:
|
|||
template <typename T>
|
||||
void bitSetCase(T &Val, const char* Str, const T ConstVal) {
|
||||
if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
|
||||
Val = Val | ConstVal;
|
||||
Val = static_cast<T>(Val | ConstVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -614,7 +614,7 @@ public:
|
|||
template <typename T>
|
||||
void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
|
||||
if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
|
||||
Val = Val | ConstVal;
|
||||
Val = static_cast<T>(Val | ConstVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,21 +30,13 @@ def s64 : LLT;
|
|||
// Definitions that inherit from this may also inherit from
|
||||
// GIComplexPatternEquiv to enable the import of SelectionDAG patterns involving
|
||||
// those ComplexPatterns.
|
||||
class GIComplexOperandMatcher<LLT type, dag operands, string matcherfn> {
|
||||
class GIComplexOperandMatcher<LLT type, string matcherfn> {
|
||||
// The expected type of the root of the match.
|
||||
//
|
||||
// TODO: We should probably support, any-type, any-scalar, and multiple types
|
||||
// in the future.
|
||||
LLT Type = type;
|
||||
|
||||
// The operands that result from a successful match
|
||||
// Should be of the form '(ops ty1, ty2, ...)' where ty1/ty2 are definitions
|
||||
// that inherit from Operand.
|
||||
//
|
||||
// FIXME: Which definition is used for ty1/ty2 doesn't actually matter at the
|
||||
// moment. Only the number of operands is used.
|
||||
dag Operands = operands;
|
||||
|
||||
// The function that determines whether the operand matches. It should be of
|
||||
// the form:
|
||||
// bool select(const MatchOperand &Root, MatchOperand &Result1)
|
||||
|
|
|
|||
|
|
@ -1108,7 +1108,7 @@ public:
|
|||
|
||||
|
||||
/// Return the noop instruction to use for a noop.
|
||||
virtual void getNoopForMachoTarget(MCInst &NopInst) const;
|
||||
virtual void getNoop(MCInst &NopInst) const;
|
||||
|
||||
/// Return true for post-incremented instructions.
|
||||
virtual bool isPostIncrement(const MachineInstr &MI) const {
|
||||
|
|
|
|||
|
|
@ -236,6 +236,12 @@ public:
|
|||
return getPointerTy(DL, DL.getAllocaAddrSpace());
|
||||
}
|
||||
|
||||
/// Return the type for operands of fence.
|
||||
/// TODO: Let fence operands be of i32 type and remove this.
|
||||
virtual MVT getFenceOperandTy(const DataLayout &DL) const {
|
||||
return getPointerTy(DL);
|
||||
}
|
||||
|
||||
/// EVT is not used in-tree, but is used by out-of-tree target.
|
||||
/// A documentation for this function would be nice...
|
||||
virtual MVT getScalarShiftAmountTy(const DataLayout &, EVT) const;
|
||||
|
|
@ -2268,7 +2274,8 @@ protected:
|
|||
|
||||
/// Return true if the value types that can be represented by the specified
|
||||
/// register class are all legal.
|
||||
bool isLegalRC(const TargetRegisterClass *RC) const;
|
||||
bool isLegalRC(const TargetRegisterInfo &TRI,
|
||||
const TargetRegisterClass &RC) const;
|
||||
|
||||
/// Replace/modify any TargetFrameIndex operands with a targte-dependent
|
||||
/// sequence of memory operands that is recognized by PrologEpilogInserter.
|
||||
|
|
@ -2388,30 +2395,39 @@ public:
|
|||
New = N;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check to see if the specified operand of the specified instruction is a
|
||||
/// constant integer. If so, check to see if there are any bits set in the
|
||||
/// constant that are not demanded. If so, shrink the constant and return
|
||||
/// true.
|
||||
bool ShrinkDemandedConstant(SDValue Op, const APInt &Demanded);
|
||||
|
||||
/// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. This
|
||||
/// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be
|
||||
/// generalized for targets with other types of implicit widening casts.
|
||||
bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded,
|
||||
const SDLoc &dl);
|
||||
|
||||
/// Helper for SimplifyDemandedBits that can simplify an operation with
|
||||
/// multiple uses. This function uses TLI.SimplifyDemandedBits to
|
||||
/// simplify Operand \p OpIdx of \p User and then updated \p User with
|
||||
/// the simplified version. No other uses of \p OpIdx are updated.
|
||||
/// If \p User is the only user of \p OpIdx, this function behaves exactly
|
||||
/// like TLI.SimplifyDemandedBits except that it also updates the DAG by
|
||||
/// calling DCI.CommitTargetLoweringOpt.
|
||||
bool SimplifyDemandedBits(SDNode *User, unsigned OpIdx,
|
||||
const APInt &Demanded, DAGCombinerInfo &DCI);
|
||||
};
|
||||
|
||||
/// Check to see if the specified operand of the specified instruction is a
|
||||
/// constant integer. If so, check to see if there are any bits set in the
|
||||
/// constant that are not demanded. If so, shrink the constant and return
|
||||
/// true.
|
||||
bool ShrinkDemandedConstant(SDValue Op, const APInt &Demanded,
|
||||
TargetLoweringOpt &TLO) const;
|
||||
|
||||
// Target hook to do target-specific const optimization, which is called by
|
||||
// ShrinkDemandedConstant. This function should return true if the target
|
||||
// doesn't want ShrinkDemandedConstant to further optimize the constant.
|
||||
virtual bool targetShrinkDemandedConstant(SDValue Op, const APInt &Demanded,
|
||||
TargetLoweringOpt &TLO) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. This
|
||||
/// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be
|
||||
/// generalized for targets with other types of implicit widening casts.
|
||||
bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded,
|
||||
TargetLoweringOpt &TLO) const;
|
||||
|
||||
/// Helper for SimplifyDemandedBits that can simplify an operation with
|
||||
/// multiple uses. This function simplifies operand \p OpIdx of \p User and
|
||||
/// then updates \p User with the simplified version. No other uses of
|
||||
/// \p OpIdx are updated. If \p User is the only user of \p OpIdx, this
|
||||
/// function behaves exactly like function SimplifyDemandedBits declared
|
||||
/// below except that it also updates the DAG by calling
|
||||
/// DCI.CommitTargetLoweringOpt.
|
||||
bool SimplifyDemandedBits(SDNode *User, unsigned OpIdx, const APInt &Demanded,
|
||||
DAGCombinerInfo &DCI, TargetLoweringOpt &TLO) const;
|
||||
|
||||
/// Look at Op. At this point, we know that only the DemandedMask bits of the
|
||||
/// result of Op are ever used downstream. If we can use this information to
|
||||
/// simplify Op, create a new simplified DAG node and return true, returning
|
||||
|
|
|
|||
|
|
@ -40,13 +40,12 @@ class TargetRegisterClass {
|
|||
public:
|
||||
typedef const MCPhysReg* iterator;
|
||||
typedef const MCPhysReg* const_iterator;
|
||||
typedef const MVT::SimpleValueType* vt_iterator;
|
||||
typedef const TargetRegisterClass* const * sc_iterator;
|
||||
|
||||
// Instance variables filled by tablegen, do not use!
|
||||
const MCRegisterClass *MC;
|
||||
const uint16_t SpillSize, SpillAlignment;
|
||||
const vt_iterator VTs;
|
||||
const MVT::SimpleValueType *VTs;
|
||||
const uint32_t *SubClassMask;
|
||||
const uint16_t *SuperRegIndices;
|
||||
const LaneBitmask LaneMask;
|
||||
|
|
@ -93,13 +92,6 @@ public:
|
|||
return MC->contains(Reg1, Reg2);
|
||||
}
|
||||
|
||||
/// Return the size of the register in bytes, which is also the size
|
||||
/// of a stack slot allocated to hold a spilled copy of this register.
|
||||
unsigned getSize() const { return SpillSize; }
|
||||
|
||||
/// Return the minimum required alignment for a register of this class.
|
||||
unsigned getAlignment() const { return SpillAlignment; }
|
||||
|
||||
/// Return the cost of copying a value between two registers in this class.
|
||||
/// A negative number means the register class is very expensive
|
||||
/// to copy e.g. status flag register classes.
|
||||
|
|
@ -109,26 +101,6 @@ public:
|
|||
/// registers.
|
||||
bool isAllocatable() const { return MC->isAllocatable(); }
|
||||
|
||||
/// Return true if this TargetRegisterClass has the ValueType vt.
|
||||
bool hasType(MVT vt) const {
|
||||
for(int i = 0; VTs[i] != MVT::Other; ++i)
|
||||
if (MVT(VTs[i]) == vt)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// vt_begin / vt_end - Loop over all of the value types that can be
|
||||
/// represented by values in this register class.
|
||||
vt_iterator vt_begin() const {
|
||||
return VTs;
|
||||
}
|
||||
|
||||
vt_iterator vt_end() const {
|
||||
vt_iterator I = VTs;
|
||||
while (*I != MVT::Other) ++I;
|
||||
return I;
|
||||
}
|
||||
|
||||
/// Return true if the specified TargetRegisterClass
|
||||
/// is a proper sub-class of this TargetRegisterClass.
|
||||
bool hasSubClass(const TargetRegisterClass *RC) const {
|
||||
|
|
@ -246,6 +218,7 @@ struct RegClassWeight {
|
|||
class TargetRegisterInfo : public MCRegisterInfo {
|
||||
public:
|
||||
typedef const TargetRegisterClass * const * regclass_iterator;
|
||||
typedef const MVT::SimpleValueType* vt_iterator;
|
||||
private:
|
||||
const TargetRegisterInfoDesc *InfoDesc; // Extra desc array for codegen
|
||||
const char *const *SubRegIndexNames; // Names of subreg indexes.
|
||||
|
|
@ -327,6 +300,44 @@ public:
|
|||
return Index | (1u << 31);
|
||||
}
|
||||
|
||||
/// Return the size in bits of a register from class RC.
|
||||
unsigned getRegSizeInBits(const TargetRegisterClass &RC) const {
|
||||
return RC.SpillSize * 8;
|
||||
}
|
||||
|
||||
/// Return the size in bytes of the stack slot allocated to hold a spilled
|
||||
/// copy of a register from class RC.
|
||||
unsigned getSpillSize(const TargetRegisterClass &RC) const {
|
||||
return RC.SpillSize;
|
||||
}
|
||||
|
||||
/// Return the minimum required alignment for a spill slot for a register
|
||||
/// of this class.
|
||||
unsigned getSpillAlignment(const TargetRegisterClass &RC) const {
|
||||
return RC.SpillAlignment;
|
||||
}
|
||||
|
||||
/// Return true if the given TargetRegisterClass has the ValueType T.
|
||||
bool isTypeLegalForClass(const TargetRegisterClass &RC, MVT T) const {
|
||||
for (int i = 0; RC.VTs[i] != MVT::Other; ++i)
|
||||
if (MVT(RC.VTs[i]) == T)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Loop over all of the value types that can be represented by values
|
||||
// in the given register class.
|
||||
vt_iterator legalclasstypes_begin(const TargetRegisterClass &RC) const {
|
||||
return RC.VTs;
|
||||
}
|
||||
|
||||
vt_iterator legalclasstypes_end(const TargetRegisterClass &RC) const {
|
||||
vt_iterator I = RC.VTs;
|
||||
while (*I != MVT::Other)
|
||||
++I;
|
||||
return I;
|
||||
}
|
||||
|
||||
/// Returns the Register Class of a physical register of the given type,
|
||||
/// picking the most sub register class of the right type that contains this
|
||||
/// physreg.
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false,
|
|||
bool Recover = false,
|
||||
bool UseAfterScope = false);
|
||||
ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false,
|
||||
bool Recover = false);
|
||||
bool Recover = false,
|
||||
bool UseGlobalsGC = true);
|
||||
|
||||
// Insert MemorySanitizer instrumentation (detection of uninitialized reads)
|
||||
FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#ifndef LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H
|
||||
#define LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H
|
||||
|
||||
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
|
@ -98,7 +99,7 @@ public:
|
|||
|
||||
// Glue for old PM.
|
||||
bool runImpl(Function &F, TargetTransformInfo &TTI, DominatorTree &DT,
|
||||
BasicBlock &Entry);
|
||||
BlockFrequencyInfo *BFI, BasicBlock &Entry);
|
||||
|
||||
void releaseMemory() {
|
||||
ConstantVec.clear();
|
||||
|
|
@ -112,6 +113,7 @@ private:
|
|||
|
||||
const TargetTransformInfo *TTI;
|
||||
DominatorTree *DT;
|
||||
BlockFrequencyInfo *BFI;
|
||||
BasicBlock *Entry;
|
||||
|
||||
/// Keeps track of constant candidates found in the function.
|
||||
|
|
@ -124,8 +126,8 @@ private:
|
|||
SmallVector<consthoist::ConstantInfo, 8> ConstantVec;
|
||||
|
||||
Instruction *findMatInsertPt(Instruction *Inst, unsigned Idx = ~0U) const;
|
||||
Instruction *findConstantInsertionPoint(
|
||||
const consthoist::ConstantInfo &ConstInfo) const;
|
||||
SmallPtrSet<Instruction *, 8>
|
||||
findConstantInsertionPoint(const consthoist::ConstantInfo &ConstInfo) const;
|
||||
void collectConstantCandidates(ConstCandMapType &ConstCandMap,
|
||||
Instruction *Inst, unsigned Idx,
|
||||
ConstantInt *ConstInt);
|
||||
|
|
|
|||
|
|
@ -924,8 +924,8 @@ static AliasResult aliasSameBasePointerGEPs(const GEPOperator *GEP1,
|
|||
uint64_t V2Size,
|
||||
const DataLayout &DL) {
|
||||
|
||||
assert(GEP1->getPointerOperand()->stripPointerCasts() ==
|
||||
GEP2->getPointerOperand()->stripPointerCasts() &&
|
||||
assert(GEP1->getPointerOperand()->stripPointerCastsAndBarriers() ==
|
||||
GEP2->getPointerOperand()->stripPointerCastsAndBarriers() &&
|
||||
GEP1->getPointerOperandType() == GEP2->getPointerOperandType() &&
|
||||
"Expected GEPs with the same pointer operand");
|
||||
|
||||
|
|
@ -1184,8 +1184,8 @@ AliasResult BasicAAResult::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size,
|
|||
// If we know the two GEPs are based off of the exact same pointer (and not
|
||||
// just the same underlying object), see if that tells us anything about
|
||||
// the resulting pointers.
|
||||
if (GEP1->getPointerOperand()->stripPointerCasts() ==
|
||||
GEP2->getPointerOperand()->stripPointerCasts() &&
|
||||
if (GEP1->getPointerOperand()->stripPointerCastsAndBarriers() ==
|
||||
GEP2->getPointerOperand()->stripPointerCastsAndBarriers() &&
|
||||
GEP1->getPointerOperandType() == GEP2->getPointerOperandType()) {
|
||||
AliasResult R = aliasSameBasePointerGEPs(GEP1, V1Size, GEP2, V2Size, DL);
|
||||
// If we couldn't find anything interesting, don't abandon just yet.
|
||||
|
|
@ -1500,8 +1500,8 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, uint64_t V1Size,
|
|||
return NoAlias;
|
||||
|
||||
// Strip off any casts if they exist.
|
||||
V1 = V1->stripPointerCasts();
|
||||
V2 = V2->stripPointerCasts();
|
||||
V1 = V1->stripPointerCastsAndBarriers();
|
||||
V2 = V2->stripPointerCastsAndBarriers();
|
||||
|
||||
// If V1 or V2 is undef, the result is NoAlias because we can always pick a
|
||||
// value for undef that aliases nothing in the program.
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
|
|
@ -687,21 +688,21 @@ Constant *SymbolicallyEvaluateBinop(unsigned Opc, Constant *Op0, Constant *Op1,
|
|||
|
||||
if (Opc == Instruction::And) {
|
||||
unsigned BitWidth = DL.getTypeSizeInBits(Op0->getType()->getScalarType());
|
||||
APInt KnownZero0(BitWidth, 0), KnownOne0(BitWidth, 0);
|
||||
APInt KnownZero1(BitWidth, 0), KnownOne1(BitWidth, 0);
|
||||
computeKnownBits(Op0, KnownZero0, KnownOne0, DL);
|
||||
computeKnownBits(Op1, KnownZero1, KnownOne1, DL);
|
||||
if ((KnownOne1 | KnownZero0).isAllOnesValue()) {
|
||||
KnownBits Known0(BitWidth);
|
||||
KnownBits Known1(BitWidth);
|
||||
computeKnownBits(Op0, Known0, DL);
|
||||
computeKnownBits(Op1, Known1, DL);
|
||||
if ((Known1.One | Known0.Zero).isAllOnesValue()) {
|
||||
// All the bits of Op0 that the 'and' could be masking are already zero.
|
||||
return Op0;
|
||||
}
|
||||
if ((KnownOne0 | KnownZero1).isAllOnesValue()) {
|
||||
if ((Known0.One | Known1.Zero).isAllOnesValue()) {
|
||||
// All the bits of Op1 that the 'and' could be masking are already zero.
|
||||
return Op1;
|
||||
}
|
||||
|
||||
APInt KnownZero = KnownZero0 | KnownZero1;
|
||||
APInt KnownOne = KnownOne0 & KnownOne1;
|
||||
APInt KnownZero = Known0.Zero | Known1.Zero;
|
||||
APInt KnownOne = Known0.One & Known1.One;
|
||||
if ((KnownZero | KnownOne).isAllOnesValue()) {
|
||||
return ConstantInt::get(Op0->getType(), KnownOne);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
|
|
@ -72,8 +73,7 @@ static bool isAlwaysLive(Instruction *I) {
|
|||
|
||||
void DemandedBits::determineLiveOperandBits(
|
||||
const Instruction *UserI, const Instruction *I, unsigned OperandNo,
|
||||
const APInt &AOut, APInt &AB, APInt &KnownZero, APInt &KnownOne,
|
||||
APInt &KnownZero2, APInt &KnownOne2) {
|
||||
const APInt &AOut, APInt &AB, KnownBits &Known, KnownBits &Known2) {
|
||||
unsigned BitWidth = AB.getBitWidth();
|
||||
|
||||
// We're called once per operand, but for some instructions, we need to
|
||||
|
|
@ -85,15 +85,13 @@ void DemandedBits::determineLiveOperandBits(
|
|||
auto ComputeKnownBits =
|
||||
[&](unsigned BitWidth, const Value *V1, const Value *V2) {
|
||||
const DataLayout &DL = I->getModule()->getDataLayout();
|
||||
KnownZero = APInt(BitWidth, 0);
|
||||
KnownOne = APInt(BitWidth, 0);
|
||||
computeKnownBits(const_cast<Value *>(V1), KnownZero, KnownOne, DL, 0,
|
||||
Known = KnownBits(BitWidth);
|
||||
computeKnownBits(const_cast<Value *>(V1), Known, DL, 0,
|
||||
&AC, UserI, &DT);
|
||||
|
||||
if (V2) {
|
||||
KnownZero2 = APInt(BitWidth, 0);
|
||||
KnownOne2 = APInt(BitWidth, 0);
|
||||
computeKnownBits(const_cast<Value *>(V2), KnownZero2, KnownOne2, DL,
|
||||
Known2 = KnownBits(BitWidth);
|
||||
computeKnownBits(const_cast<Value *>(V2), Known2, DL,
|
||||
0, &AC, UserI, &DT);
|
||||
}
|
||||
};
|
||||
|
|
@ -120,7 +118,7 @@ void DemandedBits::determineLiveOperandBits(
|
|||
// known to be one.
|
||||
ComputeKnownBits(BitWidth, I, nullptr);
|
||||
AB = APInt::getHighBitsSet(BitWidth,
|
||||
std::min(BitWidth, KnownOne.countLeadingZeros()+1));
|
||||
std::min(BitWidth, Known.One.countLeadingZeros()+1));
|
||||
}
|
||||
break;
|
||||
case Intrinsic::cttz:
|
||||
|
|
@ -130,7 +128,7 @@ void DemandedBits::determineLiveOperandBits(
|
|||
// known to be one.
|
||||
ComputeKnownBits(BitWidth, I, nullptr);
|
||||
AB = APInt::getLowBitsSet(BitWidth,
|
||||
std::min(BitWidth, KnownOne.countTrailingZeros()+1));
|
||||
std::min(BitWidth, Known.One.countTrailingZeros()+1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -200,11 +198,11 @@ void DemandedBits::determineLiveOperandBits(
|
|||
// dead).
|
||||
if (OperandNo == 0) {
|
||||
ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
|
||||
AB &= ~KnownZero2;
|
||||
AB &= ~Known2.Zero;
|
||||
} else {
|
||||
if (!isa<Instruction>(UserI->getOperand(0)))
|
||||
ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
|
||||
AB &= ~(KnownZero & ~KnownZero2);
|
||||
AB &= ~(Known.Zero & ~Known2.Zero);
|
||||
}
|
||||
break;
|
||||
case Instruction::Or:
|
||||
|
|
@ -216,11 +214,11 @@ void DemandedBits::determineLiveOperandBits(
|
|||
// dead).
|
||||
if (OperandNo == 0) {
|
||||
ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
|
||||
AB &= ~KnownOne2;
|
||||
AB &= ~Known2.One;
|
||||
} else {
|
||||
if (!isa<Instruction>(UserI->getOperand(0)))
|
||||
ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
|
||||
AB &= ~(KnownOne & ~KnownOne2);
|
||||
AB &= ~(Known.One & ~Known2.One);
|
||||
}
|
||||
break;
|
||||
case Instruction::Xor:
|
||||
|
|
@ -318,7 +316,7 @@ void DemandedBits::performAnalysis() {
|
|||
if (!UserI->getType()->isIntegerTy())
|
||||
Visited.insert(UserI);
|
||||
|
||||
APInt KnownZero, KnownOne, KnownZero2, KnownOne2;
|
||||
KnownBits Known, Known2;
|
||||
// Compute the set of alive bits for each operand. These are anded into the
|
||||
// existing set, if any, and if that changes the set of alive bits, the
|
||||
// operand is added to the work-list.
|
||||
|
|
@ -335,8 +333,7 @@ void DemandedBits::performAnalysis() {
|
|||
// Bits of each operand that are used to compute alive bits of the
|
||||
// output are alive, all others are dead.
|
||||
determineLiveOperandBits(UserI, I, OI.getOperandNo(), AOut, AB,
|
||||
KnownZero, KnownOne,
|
||||
KnownZero2, KnownOne2);
|
||||
Known, Known2);
|
||||
}
|
||||
|
||||
// If we've added to the set of alive bits (or the operand has not
|
||||
|
|
|
|||
|
|
@ -80,6 +80,22 @@ struct DOTGraphTraits<PostDominatorTree*>
|
|||
};
|
||||
}
|
||||
|
||||
void DominatorTree::viewGraph(const Twine &Name, const Twine &Title) {
|
||||
#ifndef NDEBUG
|
||||
ViewGraph(this, Name, false, Title);
|
||||
#else
|
||||
errs() << "DomTree dump not available, build with DEBUG\n";
|
||||
#endif // NDEBUG
|
||||
}
|
||||
|
||||
void DominatorTree::viewGraph() {
|
||||
#ifndef NDEBUG
|
||||
this->viewGraph("domtree", "Dominator Tree for function");
|
||||
#else
|
||||
errs() << "DomTree dump not available, build with DEBUG\n";
|
||||
#endif // NDEBUG
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct DominatorTreeWrapperPassAnalysisGraphTraits {
|
||||
static DominatorTree *getGraph(DominatorTreeWrapperPass *DTWP) {
|
||||
|
|
|
|||
|
|
@ -253,18 +253,8 @@ bool IVUsers::AddUsersImpl(Instruction *I,
|
|||
const SCEV *OriginalISE = ISE;
|
||||
|
||||
auto NormalizePred = [&](const SCEVAddRecExpr *AR) {
|
||||
// We only allow affine AddRecs to be normalized, otherwise we would not
|
||||
// be able to correctly denormalize.
|
||||
// e.g. {1,+,3,+,2} == {-2,+,1,+,2} + {3,+,2}
|
||||
// Normalized form: {-2,+,1,+,2}
|
||||
// Denormalized form: {1,+,3,+,2}
|
||||
//
|
||||
// However, denormalization would use a different step expression than
|
||||
// normalization (see getPostIncExpr), generating the wrong final
|
||||
// expression: {-2,+,1,+,2} + {1,+,2} => {-1,+,3,+,2}
|
||||
auto *L = AR->getLoop();
|
||||
bool Result =
|
||||
AR->isAffine() && IVUseShouldUsePostIncValue(User, I, L, DT);
|
||||
bool Result = IVUseShouldUsePostIncValue(User, I, L, DT);
|
||||
if (Result)
|
||||
NewUse.PostIncLoops.insert(L);
|
||||
return Result;
|
||||
|
|
|
|||
|
|
@ -1556,7 +1556,6 @@ InlineParams llvm::getInlineParams(int Threshold) {
|
|||
// Set the ColdCallSiteThreshold knob from the -inline-cold-callsite-threshold.
|
||||
Params.ColdCallSiteThreshold = ColdCallSiteThreshold;
|
||||
|
||||
// Set the OptMinSizeThreshold and OptSizeThreshold params only if the
|
||||
// Set the OptMinSizeThreshold and OptSizeThreshold params only if the
|
||||
// -inlinehint-threshold commandline option is not explicitly given. If that
|
||||
// option is present, then its value applies even for callees with size and
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -70,6 +70,7 @@
|
|||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
|
|
@ -534,10 +535,9 @@ static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT,
|
|||
VectorType *VecTy = dyn_cast<VectorType>(V->getType());
|
||||
if (!VecTy) {
|
||||
unsigned BitWidth = V->getType()->getIntegerBitWidth();
|
||||
APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0);
|
||||
computeKnownBits(V, KnownZero, KnownOne, DL, 0, AC,
|
||||
dyn_cast<Instruction>(V), DT);
|
||||
return KnownZero.isAllOnesValue();
|
||||
KnownBits Known(BitWidth);
|
||||
computeKnownBits(V, Known, DL, 0, AC, dyn_cast<Instruction>(V), DT);
|
||||
return Known.Zero.isAllOnesValue();
|
||||
}
|
||||
|
||||
// Per-component check doesn't work with zeroinitializer
|
||||
|
|
@ -556,9 +556,9 @@ static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT,
|
|||
if (isa<UndefValue>(Elem))
|
||||
return true;
|
||||
|
||||
APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0);
|
||||
computeKnownBits(Elem, KnownZero, KnownOne, DL);
|
||||
if (KnownZero.isAllOnesValue())
|
||||
KnownBits Known(BitWidth);
|
||||
computeKnownBits(Elem, Known, DL);
|
||||
if (Known.Zero.isAllOnesValue())
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#define DEBUG_TYPE "memoryssa"
|
||||
using namespace llvm;
|
||||
namespace llvm {
|
||||
|
||||
// This is the marker algorithm from "Simple and Efficient Construction of
|
||||
// Static Single Assignment Form"
|
||||
// The simple, non-marker algorithm places phi nodes at any join
|
||||
|
|
@ -211,8 +211,8 @@ void MemorySSAUpdater::insertUse(MemoryUse *MU) {
|
|||
}
|
||||
|
||||
// Set every incoming edge {BB, MP->getBlock()} of MemoryPhi MP to NewDef.
|
||||
void setMemoryPhiValueForBlock(MemoryPhi *MP, const BasicBlock *BB,
|
||||
MemoryAccess *NewDef) {
|
||||
static void setMemoryPhiValueForBlock(MemoryPhi *MP, const BasicBlock *BB,
|
||||
MemoryAccess *NewDef) {
|
||||
// Replace any operand with us an incoming block with the new defining
|
||||
// access.
|
||||
int i = MP->getBasicBlockIndex(BB);
|
||||
|
|
@ -415,6 +415,7 @@ static MemoryAccess *onlySingleValue(MemoryPhi *MP) {
|
|||
}
|
||||
return MA;
|
||||
}
|
||||
|
||||
void MemorySSAUpdater::removeMemoryAccess(MemoryAccess *MA) {
|
||||
assert(!MSSA->isLiveOnEntryDef(MA) &&
|
||||
"Trying to remove the live on entry def");
|
||||
|
|
@ -490,5 +491,3 @@ MemoryUseOrDef *MemorySSAUpdater::createMemoryAccessAfter(
|
|||
++InsertPt->getIterator());
|
||||
return NewAccess;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
|
|
@ -4575,10 +4576,10 @@ uint32_t ScalarEvolution::GetMinTrailingZerosImpl(const SCEV *S) {
|
|||
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S)) {
|
||||
// For a SCEVUnknown, ask ValueTracking.
|
||||
unsigned BitWidth = getTypeSizeInBits(U->getType());
|
||||
APInt Zeros(BitWidth, 0), Ones(BitWidth, 0);
|
||||
computeKnownBits(U->getValue(), Zeros, Ones, getDataLayout(), 0, &AC,
|
||||
KnownBits Known(BitWidth);
|
||||
computeKnownBits(U->getValue(), Known, getDataLayout(), 0, &AC,
|
||||
nullptr, &DT);
|
||||
return Zeros.countTrailingOnes();
|
||||
return Known.Zero.countTrailingOnes();
|
||||
}
|
||||
|
||||
// SCEVUDivExpr
|
||||
|
|
@ -4757,11 +4758,12 @@ ScalarEvolution::getRange(const SCEV *S,
|
|||
const DataLayout &DL = getDataLayout();
|
||||
if (SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED) {
|
||||
// For a SCEVUnknown, ask ValueTracking.
|
||||
APInt Zeros(BitWidth, 0), Ones(BitWidth, 0);
|
||||
computeKnownBits(U->getValue(), Zeros, Ones, DL, 0, &AC, nullptr, &DT);
|
||||
if (Ones != ~Zeros + 1)
|
||||
KnownBits Known(BitWidth);
|
||||
computeKnownBits(U->getValue(), Known, DL, 0, &AC, nullptr, &DT);
|
||||
if (Known.One != ~Known.Zero + 1)
|
||||
ConservativeResult =
|
||||
ConservativeResult.intersectWith(ConstantRange(Ones, ~Zeros + 1));
|
||||
ConservativeResult.intersectWith(ConstantRange(Known.One,
|
||||
~Known.Zero + 1));
|
||||
} else {
|
||||
assert(SignHint == ScalarEvolution::HINT_RANGE_SIGNED &&
|
||||
"generalize as needed!");
|
||||
|
|
@ -5292,13 +5294,13 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
|
|||
unsigned LZ = A.countLeadingZeros();
|
||||
unsigned TZ = A.countTrailingZeros();
|
||||
unsigned BitWidth = A.getBitWidth();
|
||||
APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0);
|
||||
computeKnownBits(BO->LHS, KnownZero, KnownOne, getDataLayout(),
|
||||
KnownBits Known(BitWidth);
|
||||
computeKnownBits(BO->LHS, Known, getDataLayout(),
|
||||
0, &AC, nullptr, &DT);
|
||||
|
||||
APInt EffectiveMask =
|
||||
APInt::getLowBitsSet(BitWidth, BitWidth - LZ - TZ).shl(TZ);
|
||||
if ((LZ != 0 || TZ != 0) && !((~A & ~KnownZero) & EffectiveMask)) {
|
||||
if ((LZ != 0 || TZ != 0) && !((~A & ~Known.Zero) & EffectiveMask)) {
|
||||
const SCEV *MulCount = getConstant(APInt::getOneBitSet(BitWidth, TZ));
|
||||
const SCEV *LHS = getSCEV(BO->LHS);
|
||||
const SCEV *ShiftedLHS = nullptr;
|
||||
|
|
@ -5328,12 +5330,28 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
|
|||
break;
|
||||
|
||||
case Instruction::Or:
|
||||
// Use ValueTracking to check whether this is actually an add.
|
||||
if (haveNoCommonBitsSet(BO->LHS, BO->RHS, getDataLayout(), &AC,
|
||||
nullptr, &DT)) {
|
||||
// There aren't any common bits set, so the add can't wrap.
|
||||
auto Flags = SCEV::NoWrapFlags(SCEV::FlagNUW | SCEV::FlagNSW);
|
||||
return getAddExpr(getSCEV(BO->LHS), getSCEV(BO->RHS), Flags);
|
||||
// If the RHS of the Or is a constant, we may have something like:
|
||||
// X*4+1 which got turned into X*4|1. Handle this as an Add so loop
|
||||
// optimizations will transparently handle this case.
|
||||
//
|
||||
// In order for this transformation to be safe, the LHS must be of the
|
||||
// form X*(2^n) and the Or constant must be less than 2^n.
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->RHS)) {
|
||||
const SCEV *LHS = getSCEV(BO->LHS);
|
||||
const APInt &CIVal = CI->getValue();
|
||||
if (GetMinTrailingZeros(LHS) >=
|
||||
(CIVal.getBitWidth() - CIVal.countLeadingZeros())) {
|
||||
// Build a plain add SCEV.
|
||||
const SCEV *S = getAddExpr(LHS, getSCEV(CI));
|
||||
// If the LHS of the add was an addrec and it has no-wrap flags,
|
||||
// transfer the no-wrap flags, since an or won't introduce a wrap.
|
||||
if (const SCEVAddRecExpr *NewAR = dyn_cast<SCEVAddRecExpr>(S)) {
|
||||
const SCEVAddRecExpr *OldAR = cast<SCEVAddRecExpr>(LHS);
|
||||
const_cast<SCEVAddRecExpr *>(NewAR)->setNoWrapFlags(
|
||||
OldAR->getNoWrapFlags());
|
||||
}
|
||||
return S;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -6063,24 +6081,74 @@ ScalarEvolution::computeExitLimit(const Loop *L, BasicBlock *ExitingBlock,
|
|||
return getCouldNotCompute();
|
||||
}
|
||||
|
||||
ScalarEvolution::ExitLimit
|
||||
ScalarEvolution::computeExitLimitFromCond(const Loop *L,
|
||||
Value *ExitCond,
|
||||
BasicBlock *TBB,
|
||||
BasicBlock *FBB,
|
||||
bool ControlsExit,
|
||||
bool AllowPredicates) {
|
||||
ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCond(
|
||||
const Loop *L, Value *ExitCond, BasicBlock *TBB, BasicBlock *FBB,
|
||||
bool ControlsExit, bool AllowPredicates) {
|
||||
ScalarEvolution::ExitLimitCacheTy Cache(L, TBB, FBB, AllowPredicates);
|
||||
return computeExitLimitFromCondCached(Cache, L, ExitCond, TBB, FBB,
|
||||
ControlsExit, AllowPredicates);
|
||||
}
|
||||
|
||||
Optional<ScalarEvolution::ExitLimit>
|
||||
ScalarEvolution::ExitLimitCache::find(const Loop *L, Value *ExitCond,
|
||||
BasicBlock *TBB, BasicBlock *FBB,
|
||||
bool ControlsExit, bool AllowPredicates) {
|
||||
(void)this->L;
|
||||
(void)this->TBB;
|
||||
(void)this->FBB;
|
||||
(void)this->AllowPredicates;
|
||||
|
||||
assert(this->L == L && this->TBB == TBB && this->FBB == FBB &&
|
||||
this->AllowPredicates == AllowPredicates &&
|
||||
"Variance in assumed invariant key components!");
|
||||
auto Itr = TripCountMap.find({ExitCond, ControlsExit});
|
||||
if (Itr == TripCountMap.end())
|
||||
return None;
|
||||
return Itr->second;
|
||||
}
|
||||
|
||||
void ScalarEvolution::ExitLimitCache::insert(const Loop *L, Value *ExitCond,
|
||||
BasicBlock *TBB, BasicBlock *FBB,
|
||||
bool ControlsExit,
|
||||
bool AllowPredicates,
|
||||
const ExitLimit &EL) {
|
||||
assert(this->L == L && this->TBB == TBB && this->FBB == FBB &&
|
||||
this->AllowPredicates == AllowPredicates &&
|
||||
"Variance in assumed invariant key components!");
|
||||
|
||||
auto InsertResult = TripCountMap.insert({{ExitCond, ControlsExit}, EL});
|
||||
assert(InsertResult.second && "Expected successful insertion!");
|
||||
(void)InsertResult;
|
||||
}
|
||||
|
||||
ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondCached(
|
||||
ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, BasicBlock *TBB,
|
||||
BasicBlock *FBB, bool ControlsExit, bool AllowPredicates) {
|
||||
|
||||
if (auto MaybeEL =
|
||||
Cache.find(L, ExitCond, TBB, FBB, ControlsExit, AllowPredicates))
|
||||
return *MaybeEL;
|
||||
|
||||
ExitLimit EL = computeExitLimitFromCondImpl(Cache, L, ExitCond, TBB, FBB,
|
||||
ControlsExit, AllowPredicates);
|
||||
Cache.insert(L, ExitCond, TBB, FBB, ControlsExit, AllowPredicates, EL);
|
||||
return EL;
|
||||
}
|
||||
|
||||
ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondImpl(
|
||||
ExitLimitCacheTy &Cache, const Loop *L, Value *ExitCond, BasicBlock *TBB,
|
||||
BasicBlock *FBB, bool ControlsExit, bool AllowPredicates) {
|
||||
// Check if the controlling expression for this loop is an And or Or.
|
||||
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(ExitCond)) {
|
||||
if (BO->getOpcode() == Instruction::And) {
|
||||
// Recurse on the operands of the and.
|
||||
bool EitherMayExit = L->contains(TBB);
|
||||
ExitLimit EL0 = computeExitLimitFromCond(L, BO->getOperand(0), TBB, FBB,
|
||||
ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL1 = computeExitLimitFromCond(L, BO->getOperand(1), TBB, FBB,
|
||||
ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL0 = computeExitLimitFromCondCached(
|
||||
Cache, L, BO->getOperand(0), TBB, FBB, ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL1 = computeExitLimitFromCondCached(
|
||||
Cache, L, BO->getOperand(1), TBB, FBB, ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
const SCEV *BECount = getCouldNotCompute();
|
||||
const SCEV *MaxBECount = getCouldNotCompute();
|
||||
if (EitherMayExit) {
|
||||
|
|
@ -6124,12 +6192,12 @@ ScalarEvolution::computeExitLimitFromCond(const Loop *L,
|
|||
if (BO->getOpcode() == Instruction::Or) {
|
||||
// Recurse on the operands of the or.
|
||||
bool EitherMayExit = L->contains(FBB);
|
||||
ExitLimit EL0 = computeExitLimitFromCond(L, BO->getOperand(0), TBB, FBB,
|
||||
ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL1 = computeExitLimitFromCond(L, BO->getOperand(1), TBB, FBB,
|
||||
ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL0 = computeExitLimitFromCondCached(
|
||||
Cache, L, BO->getOperand(0), TBB, FBB, ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
ExitLimit EL1 = computeExitLimitFromCondCached(
|
||||
Cache, L, BO->getOperand(1), TBB, FBB, ControlsExit && !EitherMayExit,
|
||||
AllowPredicates);
|
||||
const SCEV *BECount = getCouldNotCompute();
|
||||
const SCEV *MaxBECount = getCouldNotCompute();
|
||||
if (EitherMayExit) {
|
||||
|
|
@ -10221,84 +10289,75 @@ void ScalarEvolution::forgetMemoizedResults(const SCEV *S) {
|
|||
RemoveSCEVFromBackedgeMap(PredicatedBackedgeTakenCounts);
|
||||
}
|
||||
|
||||
typedef DenseMap<const Loop *, std::string> VerifyMap;
|
||||
|
||||
/// replaceSubString - Replaces all occurrences of From in Str with To.
|
||||
static void replaceSubString(std::string &Str, StringRef From, StringRef To) {
|
||||
size_t Pos = 0;
|
||||
while ((Pos = Str.find(From, Pos)) != std::string::npos) {
|
||||
Str.replace(Pos, From.size(), To.data(), To.size());
|
||||
Pos += To.size();
|
||||
}
|
||||
}
|
||||
|
||||
/// getLoopBackedgeTakenCounts - Helper method for verifyAnalysis.
|
||||
static void
|
||||
getLoopBackedgeTakenCounts(Loop *L, VerifyMap &Map, ScalarEvolution &SE) {
|
||||
std::string &S = Map[L];
|
||||
if (S.empty()) {
|
||||
raw_string_ostream OS(S);
|
||||
SE.getBackedgeTakenCount(L)->print(OS);
|
||||
|
||||
// false and 0 are semantically equivalent. This can happen in dead loops.
|
||||
replaceSubString(OS.str(), "false", "0");
|
||||
// Remove wrap flags, their use in SCEV is highly fragile.
|
||||
// FIXME: Remove this when SCEV gets smarter about them.
|
||||
replaceSubString(OS.str(), "<nw>", "");
|
||||
replaceSubString(OS.str(), "<nsw>", "");
|
||||
replaceSubString(OS.str(), "<nuw>", "");
|
||||
}
|
||||
|
||||
for (auto *R : reverse(*L))
|
||||
getLoopBackedgeTakenCounts(R, Map, SE); // recurse.
|
||||
}
|
||||
|
||||
void ScalarEvolution::verify() const {
|
||||
ScalarEvolution &SE = *const_cast<ScalarEvolution *>(this);
|
||||
|
||||
// Gather stringified backedge taken counts for all loops using SCEV's caches.
|
||||
// FIXME: It would be much better to store actual values instead of strings,
|
||||
// but SCEV pointers will change if we drop the caches.
|
||||
VerifyMap BackedgeDumpsOld, BackedgeDumpsNew;
|
||||
for (LoopInfo::reverse_iterator I = LI.rbegin(), E = LI.rend(); I != E; ++I)
|
||||
getLoopBackedgeTakenCounts(*I, BackedgeDumpsOld, SE);
|
||||
|
||||
// Gather stringified backedge taken counts for all loops using a fresh
|
||||
// ScalarEvolution object.
|
||||
ScalarEvolution SE2(F, TLI, AC, DT, LI);
|
||||
for (LoopInfo::reverse_iterator I = LI.rbegin(), E = LI.rend(); I != E; ++I)
|
||||
getLoopBackedgeTakenCounts(*I, BackedgeDumpsNew, SE2);
|
||||
|
||||
// Now compare whether they're the same with and without caches. This allows
|
||||
// verifying that no pass changed the cache.
|
||||
assert(BackedgeDumpsOld.size() == BackedgeDumpsNew.size() &&
|
||||
"New loops suddenly appeared!");
|
||||
SmallVector<Loop *, 8> LoopStack(LI.begin(), LI.end());
|
||||
|
||||
for (VerifyMap::iterator OldI = BackedgeDumpsOld.begin(),
|
||||
OldE = BackedgeDumpsOld.end(),
|
||||
NewI = BackedgeDumpsNew.begin();
|
||||
OldI != OldE; ++OldI, ++NewI) {
|
||||
assert(OldI->first == NewI->first && "Loop order changed!");
|
||||
// Map's SCEV expressions from one ScalarEvolution "universe" to another.
|
||||
struct SCEVMapper : public SCEVRewriteVisitor<SCEVMapper> {
|
||||
const SCEV *visitConstant(const SCEVConstant *Constant) {
|
||||
return SE.getConstant(Constant->getAPInt());
|
||||
}
|
||||
const SCEV *visitUnknown(const SCEVUnknown *Expr) {
|
||||
return SE.getUnknown(Expr->getValue());
|
||||
}
|
||||
|
||||
// Compare the stringified SCEVs. We don't care if undef backedgetaken count
|
||||
// changes.
|
||||
// FIXME: We currently ignore SCEV changes from/to CouldNotCompute. This
|
||||
// means that a pass is buggy or SCEV has to learn a new pattern but is
|
||||
// usually not harmful.
|
||||
if (OldI->second != NewI->second &&
|
||||
OldI->second.find("undef") == std::string::npos &&
|
||||
NewI->second.find("undef") == std::string::npos &&
|
||||
OldI->second != "***COULDNOTCOMPUTE***" &&
|
||||
NewI->second != "***COULDNOTCOMPUTE***") {
|
||||
dbgs() << "SCEVValidator: SCEV for loop '"
|
||||
<< OldI->first->getHeader()->getName()
|
||||
<< "' changed from '" << OldI->second
|
||||
<< "' to '" << NewI->second << "'!\n";
|
||||
const SCEV *visitCouldNotCompute(const SCEVCouldNotCompute *Expr) {
|
||||
return SE.getCouldNotCompute();
|
||||
}
|
||||
SCEVMapper(ScalarEvolution &SE) : SCEVRewriteVisitor<SCEVMapper>(SE) {}
|
||||
};
|
||||
|
||||
SCEVMapper SCM(SE2);
|
||||
|
||||
while (!LoopStack.empty()) {
|
||||
auto *L = LoopStack.pop_back_val();
|
||||
LoopStack.insert(LoopStack.end(), L->begin(), L->end());
|
||||
|
||||
auto *CurBECount = SCM.visit(
|
||||
const_cast<ScalarEvolution *>(this)->getBackedgeTakenCount(L));
|
||||
auto *NewBECount = SE2.getBackedgeTakenCount(L);
|
||||
|
||||
if (CurBECount == SE2.getCouldNotCompute() ||
|
||||
NewBECount == SE2.getCouldNotCompute()) {
|
||||
// NB! This situation is legal, but is very suspicious -- whatever pass
|
||||
// change the loop to make a trip count go from could not compute to
|
||||
// computable or vice-versa *should have* invalidated SCEV. However, we
|
||||
// choose not to assert here (for now) since we don't want false
|
||||
// positives.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (containsUndefs(CurBECount) || containsUndefs(NewBECount)) {
|
||||
// SCEV treats "undef" as an unknown but consistent value (i.e. it does
|
||||
// not propagate undef aggressively). This means we can (and do) fail
|
||||
// verification in cases where a transform makes the trip count of a loop
|
||||
// go from "undef" to "undef+1" (say). The transform is fine, since in
|
||||
// both cases the loop iterates "undef" times, but SCEV thinks we
|
||||
// increased the trip count of the loop by 1 incorrectly.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SE.getTypeSizeInBits(CurBECount->getType()) >
|
||||
SE.getTypeSizeInBits(NewBECount->getType()))
|
||||
NewBECount = SE2.getZeroExtendExpr(NewBECount, CurBECount->getType());
|
||||
else if (SE.getTypeSizeInBits(CurBECount->getType()) <
|
||||
SE.getTypeSizeInBits(NewBECount->getType()))
|
||||
CurBECount = SE2.getZeroExtendExpr(CurBECount, NewBECount->getType());
|
||||
|
||||
auto *ConstantDelta =
|
||||
dyn_cast<SCEVConstant>(SE2.getMinusSCEV(CurBECount, NewBECount));
|
||||
|
||||
if (ConstantDelta && ConstantDelta->getAPInt() != 0) {
|
||||
dbgs() << "Trip Count Changed!\n";
|
||||
dbgs() << "Old: " << *CurBECount << "\n";
|
||||
dbgs() << "New: " << *NewBECount << "\n";
|
||||
dbgs() << "Delta: " << *ConstantDelta << "\n";
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Verify more things.
|
||||
}
|
||||
|
||||
bool ScalarEvolution::invalidate(
|
||||
|
|
|
|||
|
|
@ -51,40 +51,47 @@ NormalizeDenormalizeRewriter::visitAddRecExpr(const SCEVAddRecExpr *AR) {
|
|||
transform(AR->operands(), std::back_inserter(Operands),
|
||||
[&](const SCEV *Op) { return visit(Op); });
|
||||
|
||||
// Conservatively use AnyWrap until/unless we need FlagNW.
|
||||
const SCEV *Result =
|
||||
SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap);
|
||||
switch (Kind) {
|
||||
case Normalize:
|
||||
// We want to normalize step expression, because otherwise we might not be
|
||||
// able to denormalize to the original expression.
|
||||
if (!Pred(AR))
|
||||
return SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap);
|
||||
|
||||
// Normalization and denormalization are fancy names for decrementing and
|
||||
// incrementing a SCEV expression with respect to a set of loops. Since
|
||||
// Pred(AR) has returned true, we know we need to normalize or denormalize AR
|
||||
// with respect to its loop.
|
||||
|
||||
if (Kind == Denormalize) {
|
||||
// Denormalization / "partial increment" is essentially the same as \c
|
||||
// SCEVAddRecExpr::getPostIncExpr. Here we use an explicit loop to make the
|
||||
// symmetry with Normalization clear.
|
||||
for (int i = 0, e = Operands.size() - 1; i < e; i++)
|
||||
Operands[i] = SE.getAddExpr(Operands[i], Operands[i + 1]);
|
||||
} else {
|
||||
assert(Kind == Normalize && "Only two possibilities!");
|
||||
|
||||
// Normalization / "partial decrement" is a bit more subtle. Since
|
||||
// incrementing a SCEV expression (in general) changes the step of the SCEV
|
||||
// expression as well, we cannot use the step of the current expression.
|
||||
// Instead, we have to use the step of the very expression we're trying to
|
||||
// compute!
|
||||
//
|
||||
// Here is an example what will happen if we don't normalize step:
|
||||
// ORIGINAL ISE:
|
||||
// {(100 /u {1,+,1}<%bb16>),+,(100 /u {1,+,1}<%bb16>)}<%bb25>
|
||||
// NORMALIZED ISE:
|
||||
// {((-1 * (100 /u {1,+,1}<%bb16>)) + (100 /u {0,+,1}<%bb16>)),+,
|
||||
// (100 /u {0,+,1}<%bb16>)}<%bb25>
|
||||
// DENORMALIZED BACK ISE:
|
||||
// {((2 * (100 /u {1,+,1}<%bb16>)) + (-1 * (100 /u {2,+,1}<%bb16>))),+,
|
||||
// (100 /u {1,+,1}<%bb16>)}<%bb25>
|
||||
// Note that the initial value changes after normalization +
|
||||
// denormalization, which isn't correct.
|
||||
if (Pred(AR)) {
|
||||
const SCEV *TransformedStep = visit(AR->getStepRecurrence(SE));
|
||||
Result = SE.getMinusSCEV(Result, TransformedStep);
|
||||
}
|
||||
break;
|
||||
case Denormalize:
|
||||
// Here we want to normalize step expressions for the same reasons, as
|
||||
// stated above.
|
||||
if (Pred(AR)) {
|
||||
const SCEV *TransformedStep = visit(AR->getStepRecurrence(SE));
|
||||
Result = SE.getAddExpr(Result, TransformedStep);
|
||||
}
|
||||
break;
|
||||
// We solve the issue by recursively building up the result, starting from
|
||||
// the "least significant" operand in the add recurrence:
|
||||
//
|
||||
// Base case:
|
||||
// Single operand add recurrence. It's its own normalization.
|
||||
//
|
||||
// N-operand case:
|
||||
// {S_{N-1},+,S_{N-2},+,...,+,S_0} = S
|
||||
//
|
||||
// Since the step recurrence of S is {S_{N-2},+,...,+,S_0}, we know its
|
||||
// normalization by induction. We subtract the normalized step
|
||||
// recurrence from S_{N-1} to get the normalization of S.
|
||||
|
||||
for (int i = Operands.size() - 2; i >= 0; i--)
|
||||
Operands[i] = SE.getMinusSCEV(Operands[i], Operands[i + 1]);
|
||||
}
|
||||
return Result;
|
||||
|
||||
return SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap);
|
||||
}
|
||||
|
||||
const SCEV *llvm::normalizeForPostIncUse(const SCEV *S,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -726,54 +726,50 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
|
|||
}
|
||||
|
||||
void ModuleBitcodeWriter::writeAttributeGroupTable() {
|
||||
const std::vector<AttributeList> &AttrGrps = VE.getAttributeGroups();
|
||||
const std::vector<ValueEnumerator::IndexAndAttrSet> &AttrGrps =
|
||||
VE.getAttributeGroups();
|
||||
if (AttrGrps.empty()) return;
|
||||
|
||||
Stream.EnterSubblock(bitc::PARAMATTR_GROUP_BLOCK_ID, 3);
|
||||
|
||||
SmallVector<uint64_t, 64> Record;
|
||||
for (unsigned i = 0, e = AttrGrps.size(); i != e; ++i) {
|
||||
AttributeList AS = AttrGrps[i];
|
||||
for (unsigned i = 0, e = AS.getNumSlots(); i != e; ++i) {
|
||||
AttributeList A = AS.getSlotAttributes(i);
|
||||
for (ValueEnumerator::IndexAndAttrSet Pair : AttrGrps) {
|
||||
unsigned AttrListIndex = Pair.first;
|
||||
AttributeSet AS = Pair.second;
|
||||
Record.push_back(VE.getAttributeGroupID(Pair));
|
||||
Record.push_back(AttrListIndex);
|
||||
|
||||
Record.push_back(VE.getAttributeGroupID(A));
|
||||
Record.push_back(AS.getSlotIndex(i));
|
||||
for (Attribute Attr : AS) {
|
||||
if (Attr.isEnumAttribute()) {
|
||||
Record.push_back(0);
|
||||
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
|
||||
} else if (Attr.isIntAttribute()) {
|
||||
Record.push_back(1);
|
||||
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
|
||||
Record.push_back(Attr.getValueAsInt());
|
||||
} else {
|
||||
StringRef Kind = Attr.getKindAsString();
|
||||
StringRef Val = Attr.getValueAsString();
|
||||
|
||||
for (AttributeList::iterator I = AS.begin(0), E = AS.end(0); I != E;
|
||||
++I) {
|
||||
Attribute Attr = *I;
|
||||
if (Attr.isEnumAttribute()) {
|
||||
Record.push_back(Val.empty() ? 3 : 4);
|
||||
Record.append(Kind.begin(), Kind.end());
|
||||
Record.push_back(0);
|
||||
if (!Val.empty()) {
|
||||
Record.append(Val.begin(), Val.end());
|
||||
Record.push_back(0);
|
||||
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
|
||||
} else if (Attr.isIntAttribute()) {
|
||||
Record.push_back(1);
|
||||
Record.push_back(getAttrKindEncoding(Attr.getKindAsEnum()));
|
||||
Record.push_back(Attr.getValueAsInt());
|
||||
} else {
|
||||
StringRef Kind = Attr.getKindAsString();
|
||||
StringRef Val = Attr.getValueAsString();
|
||||
|
||||
Record.push_back(Val.empty() ? 3 : 4);
|
||||
Record.append(Kind.begin(), Kind.end());
|
||||
Record.push_back(0);
|
||||
if (!Val.empty()) {
|
||||
Record.append(Val.begin(), Val.end());
|
||||
Record.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Stream.EmitRecord(bitc::PARAMATTR_GRP_CODE_ENTRY, Record);
|
||||
Record.clear();
|
||||
}
|
||||
|
||||
Stream.EmitRecord(bitc::PARAMATTR_GRP_CODE_ENTRY, Record);
|
||||
Record.clear();
|
||||
}
|
||||
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
void ModuleBitcodeWriter::writeAttributeTable() {
|
||||
const std::vector<AttributeList> &Attrs = VE.getAttributes();
|
||||
const std::vector<AttributeList> &Attrs = VE.getAttributeLists();
|
||||
if (Attrs.empty()) return;
|
||||
|
||||
Stream.EnterSubblock(bitc::PARAMATTR_BLOCK_ID, 3);
|
||||
|
|
@ -782,7 +778,8 @@ void ModuleBitcodeWriter::writeAttributeTable() {
|
|||
for (unsigned i = 0, e = Attrs.size(); i != e; ++i) {
|
||||
const AttributeList &A = Attrs[i];
|
||||
for (unsigned i = 0, e = A.getNumSlots(); i != e; ++i)
|
||||
Record.push_back(VE.getAttributeGroupID(A.getSlotAttributes(i)));
|
||||
Record.push_back(
|
||||
VE.getAttributeGroupID({A.getSlotIndex(i), A.getSlotAttributes(i)}));
|
||||
|
||||
Stream.EmitRecord(bitc::PARAMATTR_CODE_ENTRY, Record);
|
||||
Record.clear();
|
||||
|
|
@ -1270,7 +1267,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
|||
Vals.push_back(F.getCallingConv());
|
||||
Vals.push_back(F.isDeclaration());
|
||||
Vals.push_back(getEncodedLinkage(F));
|
||||
Vals.push_back(VE.getAttributeID(F.getAttributes()));
|
||||
Vals.push_back(VE.getAttributeListID(F.getAttributes()));
|
||||
Vals.push_back(Log2_32(F.getAlignment())+1);
|
||||
Vals.push_back(F.hasSection() ? SectionMap[F.getSection()] : 0);
|
||||
Vals.push_back(getEncodedVisibility(F));
|
||||
|
|
@ -2616,7 +2613,7 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
|
|||
|
||||
Code = bitc::FUNC_CODE_INST_INVOKE;
|
||||
|
||||
Vals.push_back(VE.getAttributeID(II->getAttributes()));
|
||||
Vals.push_back(VE.getAttributeListID(II->getAttributes()));
|
||||
Vals.push_back(II->getCallingConv() | 1 << 13);
|
||||
Vals.push_back(VE.getValueID(II->getNormalDest()));
|
||||
Vals.push_back(VE.getValueID(II->getUnwindDest()));
|
||||
|
|
@ -2808,7 +2805,7 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
|
|||
|
||||
Code = bitc::FUNC_CODE_INST_CALL;
|
||||
|
||||
Vals.push_back(VE.getAttributeID(CI.getAttributes()));
|
||||
Vals.push_back(VE.getAttributeListID(CI.getAttributes()));
|
||||
|
||||
unsigned Flags = getOptimizationFlags(&I);
|
||||
Vals.push_back(CI.getCallingConv() << bitc::CALL_CCONV |
|
||||
|
|
|
|||
|
|
@ -891,19 +891,19 @@ void ValueEnumerator::EnumerateAttributes(AttributeList PAL) {
|
|||
if (PAL.isEmpty()) return; // null is always 0.
|
||||
|
||||
// Do a lookup.
|
||||
unsigned &Entry = AttributeMap[PAL];
|
||||
unsigned &Entry = AttributeListMap[PAL];
|
||||
if (Entry == 0) {
|
||||
// Never saw this before, add it.
|
||||
Attribute.push_back(PAL);
|
||||
Entry = Attribute.size();
|
||||
AttributeLists.push_back(PAL);
|
||||
Entry = AttributeLists.size();
|
||||
}
|
||||
|
||||
// Do lookups for all attribute groups.
|
||||
for (unsigned i = 0, e = PAL.getNumSlots(); i != e; ++i) {
|
||||
AttributeList AS = PAL.getSlotAttributes(i);
|
||||
unsigned &Entry = AttributeGroupMap[AS];
|
||||
IndexAndAttrSet Pair = {PAL.getSlotIndex(i), PAL.getSlotAttributes(i)};
|
||||
unsigned &Entry = AttributeGroupMap[Pair];
|
||||
if (Entry == 0) {
|
||||
AttributeGroups.push_back(AS);
|
||||
AttributeGroups.push_back(Pair);
|
||||
Entry = AttributeGroups.size();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ public:
|
|||
// For each value, we remember its Value* and occurrence frequency.
|
||||
typedef std::vector<std::pair<const Value*, unsigned> > ValueList;
|
||||
|
||||
/// Attribute groups as encoded in bitcode are almost AttributeSets, but they
|
||||
/// include the AttributeList index, so we have to track that in our map.
|
||||
typedef std::pair<unsigned, AttributeSet> IndexAndAttrSet;
|
||||
|
||||
UseListOrderStack UseListOrders;
|
||||
|
||||
private:
|
||||
|
|
@ -102,13 +106,13 @@ private:
|
|||
|
||||
bool ShouldPreserveUseListOrder;
|
||||
|
||||
typedef DenseMap<AttributeList, unsigned> AttributeGroupMapType;
|
||||
typedef DenseMap<IndexAndAttrSet, unsigned> AttributeGroupMapType;
|
||||
AttributeGroupMapType AttributeGroupMap;
|
||||
std::vector<AttributeList> AttributeGroups;
|
||||
std::vector<IndexAndAttrSet> AttributeGroups;
|
||||
|
||||
typedef DenseMap<AttributeList, unsigned> AttributeMapType;
|
||||
AttributeMapType AttributeMap;
|
||||
std::vector<AttributeList> Attribute;
|
||||
typedef DenseMap<AttributeList, unsigned> AttributeListMapType;
|
||||
AttributeListMapType AttributeListMap;
|
||||
std::vector<AttributeList> AttributeLists;
|
||||
|
||||
/// GlobalBasicBlockIDs - This map memoizes the basic block ID's referenced by
|
||||
/// the "getGlobalBasicBlockID" method.
|
||||
|
|
@ -166,16 +170,17 @@ public:
|
|||
unsigned getInstructionID(const Instruction *I) const;
|
||||
void setInstructionID(const Instruction *I);
|
||||
|
||||
unsigned getAttributeID(AttributeList PAL) const {
|
||||
unsigned getAttributeListID(AttributeList PAL) const {
|
||||
if (PAL.isEmpty()) return 0; // Null maps to zero.
|
||||
AttributeMapType::const_iterator I = AttributeMap.find(PAL);
|
||||
assert(I != AttributeMap.end() && "Attribute not in ValueEnumerator!");
|
||||
AttributeListMapType::const_iterator I = AttributeListMap.find(PAL);
|
||||
assert(I != AttributeListMap.end() && "Attribute not in ValueEnumerator!");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
unsigned getAttributeGroupID(AttributeList PAL) const {
|
||||
if (PAL.isEmpty()) return 0; // Null maps to zero.
|
||||
AttributeGroupMapType::const_iterator I = AttributeGroupMap.find(PAL);
|
||||
unsigned getAttributeGroupID(IndexAndAttrSet Group) const {
|
||||
if (!Group.second.hasAttributes())
|
||||
return 0; // Null maps to zero.
|
||||
AttributeGroupMapType::const_iterator I = AttributeGroupMap.find(Group);
|
||||
assert(I != AttributeGroupMap.end() && "Attribute not in ValueEnumerator!");
|
||||
return I->second;
|
||||
}
|
||||
|
|
@ -206,8 +211,8 @@ public:
|
|||
const std::vector<const BasicBlock*> &getBasicBlocks() const {
|
||||
return BasicBlocks;
|
||||
}
|
||||
const std::vector<AttributeList> &getAttributes() const { return Attribute; }
|
||||
const std::vector<AttributeList> &getAttributeGroups() const {
|
||||
const std::vector<AttributeList> &getAttributeLists() const { return AttributeLists; }
|
||||
const std::vector<IndexAndAttrSet> &getAttributeGroups() const {
|
||||
return AttributeGroups;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -964,10 +964,8 @@ unsigned AggressiveAntiDepBreaker::BreakAntiDependencies(
|
|||
// sure to update that as well.
|
||||
const SUnit *SU = MISUnitMap[Q.second.Operand->getParent()];
|
||||
if (!SU) continue;
|
||||
for (DbgValueVector::iterator DVI = DbgValues.begin(),
|
||||
DVE = DbgValues.end(); DVI != DVE; ++DVI)
|
||||
if (DVI->second == Q.second.Operand->getParent())
|
||||
UpdateDbgValue(*DVI->first, AntiDepReg, NewReg);
|
||||
UpdateDbgValues(DbgValues, Q.second.Operand->getParent(),
|
||||
AntiDepReg, NewReg);
|
||||
}
|
||||
|
||||
// We just went back in time and modified history; the
|
||||
|
|
|
|||
|
|
@ -60,6 +60,25 @@ public:
|
|||
if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == OldReg)
|
||||
MI.getOperand(0).setReg(NewReg);
|
||||
}
|
||||
|
||||
/// Update all DBG_VALUE instructions that may be affected by the dependency
|
||||
/// breaker's update of ParentMI to use NewReg.
|
||||
void UpdateDbgValues(const DbgValueVector &DbgValues, MachineInstr *ParentMI,
|
||||
unsigned OldReg, unsigned NewReg) {
|
||||
// The following code is dependent on the order in which the DbgValues are
|
||||
// constructed in ScheduleDAGInstrs::buildSchedGraph.
|
||||
MachineInstr *PrevDbgMI = nullptr;
|
||||
for (const auto &DV : make_range(DbgValues.crbegin(), DbgValues.crend())) {
|
||||
MachineInstr *PrevMI = DV.second;
|
||||
if ((PrevMI == ParentMI) || (PrevMI == PrevDbgMI)) {
|
||||
MachineInstr *DbgMI = DV.first;
|
||||
UpdateDbgValue(*DbgMI, OldReg, NewReg);
|
||||
PrevDbgMI = DbgMI;
|
||||
} else if (PrevDbgMI) {
|
||||
break; // If no match and already found a DBG_VALUE, we're done.
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -825,41 +825,25 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
|||
OS << Name << ":";
|
||||
}
|
||||
OS << V->getName();
|
||||
|
||||
const DIExpression *Expr = MI->getDebugExpression();
|
||||
auto Fragment = Expr->getFragmentInfo();
|
||||
if (Fragment)
|
||||
OS << " [fragment offset=" << Fragment->OffsetInBits
|
||||
<< " size=" << Fragment->SizeInBits << "]";
|
||||
OS << " <- ";
|
||||
|
||||
// The second operand is only an offset if it's an immediate.
|
||||
bool Deref = false;
|
||||
bool MemLoc = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
|
||||
int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0;
|
||||
for (unsigned i = 0; i < Expr->getNumElements(); ++i) {
|
||||
uint64_t Op = Expr->getElement(i);
|
||||
if (Op == dwarf::DW_OP_LLVM_fragment) {
|
||||
// There can't be any operands after this in a valid expression
|
||||
break;
|
||||
} else if (Deref) {
|
||||
// We currently don't support extra Offsets or derefs after the first
|
||||
// one. Bail out early instead of emitting an incorrect comment.
|
||||
OS << " [complex expression]";
|
||||
AP.OutStreamer->emitRawComment(OS.str());
|
||||
return true;
|
||||
} else if (Op == dwarf::DW_OP_deref) {
|
||||
Deref = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t ExtraOffset = Expr->getElement(i++);
|
||||
if (Op == dwarf::DW_OP_plus)
|
||||
Offset += ExtraOffset;
|
||||
else {
|
||||
assert(Op == dwarf::DW_OP_minus);
|
||||
Offset -= ExtraOffset;
|
||||
const DIExpression *Expr = MI->getDebugExpression();
|
||||
if (Expr->getNumElements()) {
|
||||
OS << '[';
|
||||
bool NeedSep = false;
|
||||
for (auto Op : Expr->expr_ops()) {
|
||||
if (NeedSep)
|
||||
OS << ", ";
|
||||
else
|
||||
NeedSep = true;
|
||||
OS << dwarf::OperationEncodingString(Op.getOp());
|
||||
for (unsigned I = 0; I < Op.getNumArgs(); ++I)
|
||||
OS << ' ' << Op.getArg(I);
|
||||
}
|
||||
OS << "] ";
|
||||
}
|
||||
|
||||
// Register or immediate value. Register 0 means undef.
|
||||
|
|
@ -890,7 +874,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
|||
const TargetFrameLowering *TFI = AP.MF->getSubtarget().getFrameLowering();
|
||||
Offset += TFI->getFrameIndexReference(*AP.MF,
|
||||
MI->getOperand(0).getIndex(), Reg);
|
||||
Deref = true;
|
||||
MemLoc = true;
|
||||
}
|
||||
if (Reg == 0) {
|
||||
// Suppress offset, it is not meaningful here.
|
||||
|
|
@ -899,12 +883,12 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
|||
AP.OutStreamer->emitRawComment(OS.str());
|
||||
return true;
|
||||
}
|
||||
if (MemLoc || Deref)
|
||||
if (MemLoc)
|
||||
OS << '[';
|
||||
OS << PrintReg(Reg, AP.MF->getSubtarget().getRegisterInfo());
|
||||
}
|
||||
|
||||
if (MemLoc || Deref)
|
||||
if (MemLoc)
|
||||
OS << '+' << Offset << ']';
|
||||
|
||||
// NOTE: Want this comment at start of line, don't emit with AddComment.
|
||||
|
|
@ -936,6 +920,16 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) {
|
|||
if (needsCFIMoves() == CFI_M_None)
|
||||
return;
|
||||
|
||||
// If there is no "real" instruction following this CFI instruction, skip
|
||||
// emitting it; it would be beyond the end of the function's FDE range.
|
||||
auto *MBB = MI.getParent();
|
||||
auto I = std::next(MI.getIterator());
|
||||
while (I != MBB->end() && I->isTransient())
|
||||
++I;
|
||||
if (I == MBB->instr_end() &&
|
||||
MBB->getReverseIterator() == MBB->getParent()->rbegin())
|
||||
return;
|
||||
|
||||
const std::vector<MCCFIInstruction> &Instrs = MF->getFrameInstructions();
|
||||
unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
|
||||
const MCCFIInstruction &CFI = Instrs[CFIIndex];
|
||||
|
|
@ -1046,15 +1040,23 @@ void AsmPrinter::EmitFunctionBody() {
|
|||
// If the function is empty and the object file uses .subsections_via_symbols,
|
||||
// then we need to emit *something* to the function body to prevent the
|
||||
// labels from collapsing together. Just emit a noop.
|
||||
if ((MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode)) {
|
||||
// Similarly, don't emit empty functions on Windows either. It can lead to
|
||||
// duplicate entries (two functions with the same RVA) in the Guard CF Table
|
||||
// after linking, causing the kernel not to load the binary:
|
||||
// https://developercommunity.visualstudio.com/content/problem/45366/vc-linker-creates-invalid-dll-with-clang-cl.html
|
||||
// FIXME: Hide this behind some API in e.g. MCAsmInfo or MCTargetStreamer.
|
||||
const Triple &TT = TM.getTargetTriple();
|
||||
if (!HasAnyRealCode && (MAI->hasSubsectionsViaSymbols() ||
|
||||
(TT.isOSWindows() && TT.isOSBinFormatCOFF()))) {
|
||||
MCInst Noop;
|
||||
MF->getSubtarget().getInstrInfo()->getNoopForMachoTarget(Noop);
|
||||
OutStreamer->AddComment("avoids zero-length function");
|
||||
MF->getSubtarget().getInstrInfo()->getNoop(Noop);
|
||||
|
||||
// Targets can opt-out of emitting the noop here by leaving the opcode
|
||||
// unspecified.
|
||||
if (Noop.getOpcode())
|
||||
if (Noop.getOpcode()) {
|
||||
OutStreamer->AddComment("avoids zero-length function");
|
||||
OutStreamer->EmitInstruction(Noop, getSubtargetInfo());
|
||||
}
|
||||
}
|
||||
|
||||
const Function *F = MF->getFunction();
|
||||
|
|
|
|||
|
|
@ -144,6 +144,9 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
|||
" we don't have an asm parser for this target\n");
|
||||
Parser->setAssemblerDialect(Dialect);
|
||||
Parser->setTargetParser(*TAP.get());
|
||||
if (Dialect == InlineAsm::AD_Intel)
|
||||
// We need this flag to be able to parse numbers like "0bH"
|
||||
Parser->setParsingInlineAsm(true);
|
||||
if (MF) {
|
||||
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
||||
TAP->SetFrameRegister(TRI->getFrameRegister(*MF));
|
||||
|
|
|
|||
|
|
@ -655,20 +655,12 @@ void DIEEntry::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const {
|
|||
case dwarf::DW_FORM_ref_addr: {
|
||||
// Get the absolute offset for this DIE within the debug info/types section.
|
||||
unsigned Addr = Entry->getDebugSectionOffset();
|
||||
if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) {
|
||||
const DwarfDebug *DD = AP->getDwarfDebug();
|
||||
if (DD)
|
||||
assert(!DD->useSplitDwarf() &&
|
||||
"TODO: dwo files can't have relocations.");
|
||||
const DIEUnit *Unit = Entry->getUnit();
|
||||
assert(Unit && "CUDie should belong to a CU.");
|
||||
MCSection *Section = Unit->getSection();
|
||||
if (Section) {
|
||||
const MCSymbol *SectionSym = Section->getBeginSymbol();
|
||||
AP->EmitLabelPlusOffset(SectionSym, Addr, SizeOf(AP, Form), true);
|
||||
return;
|
||||
}
|
||||
if (const MCSymbol *SectionSym =
|
||||
Entry->getUnit()->getCrossSectionRelativeBaseAddress()) {
|
||||
AP->EmitLabelPlusOffset(SectionSym, Addr, SizeOf(AP, Form), true);
|
||||
return;
|
||||
}
|
||||
|
||||
AP->OutStreamer->EmitIntValue(Addr, SizeOf(AP, Form));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class DwarfFile;
|
|||
class MCSymbol;
|
||||
class LexicalScope;
|
||||
|
||||
class DwarfCompileUnit : public DwarfUnit {
|
||||
class DwarfCompileUnit final : public DwarfUnit {
|
||||
/// A numeric ID unique among all CUs in the module
|
||||
unsigned UniqueID;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,14 +90,6 @@ DwarfAccelTables("dwarf-accel-tables", cl::Hidden,
|
|||
clEnumVal(Disable, "Disabled")),
|
||||
cl::init(Default));
|
||||
|
||||
static cl::opt<DefaultOnOff>
|
||||
SplitDwarf("split-dwarf", cl::Hidden,
|
||||
cl::desc("Output DWARF5 split debug info."),
|
||||
cl::values(clEnumVal(Default, "Default for platform"),
|
||||
clEnumVal(Enable, "Enabled"),
|
||||
clEnumVal(Disable, "Disabled")),
|
||||
cl::init(Default));
|
||||
|
||||
static cl::opt<DefaultOnOff>
|
||||
DwarfPubSections("generate-dwarf-pub-sections", cl::Hidden,
|
||||
cl::desc("Generate DWARF pubnames and pubtypes sections"),
|
||||
|
|
@ -253,11 +245,8 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
|
|||
|
||||
HasAppleExtensionAttributes = tuneForLLDB();
|
||||
|
||||
// Handle split DWARF. Off by default for now.
|
||||
if (SplitDwarf == Default)
|
||||
HasSplitDwarf = false;
|
||||
else
|
||||
HasSplitDwarf = SplitDwarf == Enable;
|
||||
// Handle split DWARF.
|
||||
HasSplitDwarf = !Asm->TM.Options.MCOptions.SplitDwarfFile.empty();
|
||||
|
||||
// Pubnames/pubtypes on by default for GDB.
|
||||
if (DwarfPubSections == Default)
|
||||
|
|
@ -412,7 +401,7 @@ DwarfDebug::constructDwarfCompileUnit(const DICompileUnit *DIUnit) {
|
|||
if (useSplitDwarf()) {
|
||||
NewCU.setSkeleton(constructSkeletonCU(NewCU));
|
||||
NewCU.addString(Die, dwarf::DW_AT_GNU_dwo_name,
|
||||
DIUnit->getSplitDebugFilename());
|
||||
Asm->TM.Options.MCOptions.SplitDwarfFile);
|
||||
}
|
||||
|
||||
// LTO with assembly output shares a single line table amongst multiple CUs.
|
||||
|
|
@ -1885,7 +1874,7 @@ void DwarfDebug::emitDebugMacinfo() {
|
|||
void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die,
|
||||
std::unique_ptr<DwarfCompileUnit> NewU) {
|
||||
NewU->addString(Die, dwarf::DW_AT_GNU_dwo_name,
|
||||
U.getCUNode()->getSplitDebugFilename());
|
||||
Asm->TM.Options.MCOptions.SplitDwarfFile);
|
||||
|
||||
if (!CompilationDir.empty())
|
||||
NewU->addString(Die, dwarf::DW_AT_comp_dir, CompilationDir);
|
||||
|
|
|
|||
|
|
@ -117,8 +117,9 @@ bool DwarfExpression::addMachineReg(const TargetRegisterInfo &TRI,
|
|||
// Otherwise, attempt to find a covering set of sub-register numbers.
|
||||
// For example, Q0 on ARM is a composition of D0+D1.
|
||||
unsigned CurPos = 0;
|
||||
// The size of the register in bits, assuming 8 bits per byte.
|
||||
unsigned RegSize = TRI.getMinimalPhysRegClass(MachineReg)->getSize() * 8;
|
||||
// The size of the register in bits.
|
||||
const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(MachineReg);
|
||||
unsigned RegSize = TRI.getRegSizeInBits(*RC);
|
||||
// Keep track of the bits in the register we already emitted, so we
|
||||
// can avoid emitting redundant aliasing subregs.
|
||||
SmallBitVector Coverage(RegSize, false);
|
||||
|
|
@ -198,8 +199,10 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
|
|||
unsigned MachineReg,
|
||||
unsigned FragmentOffsetInBits) {
|
||||
auto Fragment = ExprCursor.getFragmentInfo();
|
||||
if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U))
|
||||
if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U)) {
|
||||
LocationKind = Unknown;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasComplexExpression = false;
|
||||
auto Op = ExprCursor.peek();
|
||||
|
|
@ -212,6 +215,7 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
|
|||
// operation to multiple DW_OP_pieces.
|
||||
if (HasComplexExpression && DwarfRegs.size() > 1) {
|
||||
DwarfRegs.clear();
|
||||
LocationKind = Unknown;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +237,7 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
|
|||
return Op.getOp() == dwarf::DW_OP_stack_value;
|
||||
})) {
|
||||
DwarfRegs.clear();
|
||||
LocationKind = Unknown;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +348,6 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
|
|||
emitUnsigned(Op->getArg(0));
|
||||
break;
|
||||
case dwarf::DW_OP_stack_value:
|
||||
assert(LocationKind == Unknown || LocationKind == Implicit);
|
||||
LocationKind = Implicit;
|
||||
break;
|
||||
case dwarf::DW_OP_swap:
|
||||
|
|
|
|||
|
|
@ -1595,3 +1595,11 @@ void DwarfTypeUnit::addGlobalType(const DIType *Ty, const DIE &Die,
|
|||
const DIScope *Context) {
|
||||
getCU().addGlobalTypeUnitType(Ty, Context);
|
||||
}
|
||||
|
||||
const MCSymbol *DwarfUnit::getCrossSectionRelativeBaseAddress() const {
|
||||
if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections())
|
||||
return nullptr;
|
||||
if (isDwoUnit())
|
||||
return nullptr;
|
||||
return getSection()->getBeginSymbol();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,8 +104,6 @@ protected:
|
|||
bool applySubprogramDefinitionAttributes(const DISubprogram *SP, DIE &SPDie);
|
||||
|
||||
public:
|
||||
virtual ~DwarfUnit();
|
||||
|
||||
// Accessors.
|
||||
AsmPrinter* getAsmPrinter() const { return Asm; }
|
||||
uint16_t getLanguage() const { return CUNode->getSourceLanguage(); }
|
||||
|
|
@ -289,6 +287,8 @@ public:
|
|||
void constructTypeDIE(DIE &Buffer, const DICompositeType *CTy);
|
||||
|
||||
protected:
|
||||
~DwarfUnit();
|
||||
|
||||
/// Create new static data member DIE.
|
||||
DIE *getOrCreateStaticMemberDIE(const DIDerivedType *DT);
|
||||
|
||||
|
|
@ -335,9 +335,10 @@ private:
|
|||
void setIndexTyDie(DIE *D) { IndexTyDie = D; }
|
||||
|
||||
virtual bool isDwoUnit() const = 0;
|
||||
const MCSymbol *getCrossSectionRelativeBaseAddress() const override;
|
||||
};
|
||||
|
||||
class DwarfTypeUnit : public DwarfUnit {
|
||||
class DwarfTypeUnit final : public DwarfUnit {
|
||||
uint64_t TypeSignature;
|
||||
const DIE *Ty;
|
||||
DwarfCompileUnit &CU;
|
||||
|
|
|
|||
|
|
@ -648,10 +648,8 @@ BreakAntiDependencies(const std::vector<SUnit>& SUnits,
|
|||
// as well.
|
||||
const SUnit *SU = MISUnitMap[Q->second->getParent()];
|
||||
if (!SU) continue;
|
||||
for (DbgValueVector::iterator DVI = DbgValues.begin(),
|
||||
DVE = DbgValues.end(); DVI != DVE; ++DVI)
|
||||
if (DVI->second == Q->second->getParent())
|
||||
UpdateDbgValue(*DVI->first, AntiDepReg, NewReg);
|
||||
UpdateDbgValues(DbgValues, Q->second->getParent(),
|
||||
AntiDepReg, NewReg);
|
||||
}
|
||||
|
||||
// We just went back in time and modified history; the
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
|
|||
}
|
||||
}
|
||||
|
||||
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
|
||||
|
||||
// Now that selection is complete, there are no more generic vregs. Verify
|
||||
// that the size of the now-constrained vreg is unchanged and that it has a
|
||||
// register class.
|
||||
|
|
@ -165,7 +167,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
|
|||
continue;
|
||||
|
||||
if (VRegToType.second.isValid() &&
|
||||
VRegToType.second.getSizeInBits() > (RC->getSize() * 8)) {
|
||||
VRegToType.second.getSizeInBits() > TRI.getRegSizeInBits(*RC)) {
|
||||
reportGISelFailure(MF, TPC, MORE, "gisel-select",
|
||||
"VReg has explicit size different from class size",
|
||||
*MI);
|
||||
|
|
|
|||
|
|
@ -76,6 +76,12 @@ void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts,
|
|||
|
||||
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
|
||||
switch (Opcode) {
|
||||
case TargetOpcode::G_SDIV:
|
||||
assert(Size == 32 && "Unsupported size");
|
||||
return RTLIB::SDIV_I32;
|
||||
case TargetOpcode::G_UDIV:
|
||||
assert(Size == 32 && "Unsupported size");
|
||||
return RTLIB::UDIV_I32;
|
||||
case TargetOpcode::G_FADD:
|
||||
assert((Size == 32 || Size == 64) && "Unsupported size");
|
||||
return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32;
|
||||
|
|
@ -87,31 +93,43 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
|
|||
llvm_unreachable("Unknown libcall function");
|
||||
}
|
||||
|
||||
static LegalizerHelper::LegalizeResult
|
||||
simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size,
|
||||
Type *OpType) {
|
||||
auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
|
||||
auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
|
||||
auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
|
||||
const char *Name = TLI.getLibcallName(Libcall);
|
||||
MIRBuilder.getMF().getFrameInfo().setHasCalls(true);
|
||||
CLI.lowerCall(MIRBuilder, TLI.getLibcallCallingConv(Libcall),
|
||||
MachineOperand::CreateES(Name),
|
||||
{MI.getOperand(0).getReg(), OpType},
|
||||
{{MI.getOperand(1).getReg(), OpType},
|
||||
{MI.getOperand(2).getReg(), OpType}});
|
||||
MI.eraseFromParent();
|
||||
return LegalizerHelper::Legalized;
|
||||
}
|
||||
|
||||
LegalizerHelper::LegalizeResult
|
||||
LegalizerHelper::libcall(MachineInstr &MI) {
|
||||
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
|
||||
unsigned Size = Ty.getSizeInBits();
|
||||
auto &Ctx = MIRBuilder.getMF().getFunction()->getContext();
|
||||
MIRBuilder.setInstr(MI);
|
||||
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
return UnableToLegalize;
|
||||
case TargetOpcode::G_SDIV:
|
||||
case TargetOpcode::G_UDIV: {
|
||||
Type *Ty = Type::getInt32Ty(Ctx);
|
||||
return simpleLibcall(MI, MIRBuilder, Size, Ty);
|
||||
}
|
||||
case TargetOpcode::G_FADD:
|
||||
case TargetOpcode::G_FPOW:
|
||||
case TargetOpcode::G_FREM: {
|
||||
auto &Ctx = MIRBuilder.getMF().getFunction()->getContext();
|
||||
Type *Ty = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx);
|
||||
auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
|
||||
auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
|
||||
auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
|
||||
const char *Name = TLI.getLibcallName(Libcall);
|
||||
MIRBuilder.getMF().getFrameInfo().setHasCalls(true);
|
||||
CLI.lowerCall(
|
||||
MIRBuilder, TLI.getLibcallCallingConv(Libcall),
|
||||
MachineOperand::CreateES(Name), {MI.getOperand(0).getReg(), Ty},
|
||||
{{MI.getOperand(1).getReg(), Ty}, {MI.getOperand(2).getReg(), Ty}});
|
||||
MI.eraseFromParent();
|
||||
return Legalized;
|
||||
return simpleLibcall(MI, MIRBuilder, Size, Ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ bool RegisterBank::verify(const TargetRegisterInfo &TRI) const {
|
|||
|
||||
// Verify that the Size of the register bank is big enough to cover
|
||||
// all the register classes it covers.
|
||||
assert((getSize() >= SubRC.getSize() * 8) &&
|
||||
assert(getSize() >= TRI.getRegSizeInBits(SubRC) &&
|
||||
"Size is not big enough for all the subclasses!");
|
||||
assert(covers(SubRC) && "Not all subclasses are covered");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ unsigned RegisterBankInfo::getSizeInBits(unsigned Reg,
|
|||
RC = MRI.getRegClass(Reg);
|
||||
}
|
||||
assert(RC && "Unable to deduce the register class");
|
||||
return RC->getSize() * 8;
|
||||
return TRI.getRegSizeInBits(*RC);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -925,9 +925,6 @@ void MIPrinter::print(const MachineOperand &Op, const TargetRegisterInfo *TRI,
|
|||
<< CmpInst::getPredicateName(Pred) << ')';
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_Placeholder:
|
||||
OS << "<placeholder>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -287,8 +287,6 @@ bool MachineOperand::isIdenticalTo(const MachineOperand &Other) const {
|
|||
return getIntrinsicID() == Other.getIntrinsicID();
|
||||
case MachineOperand::MO_Predicate:
|
||||
return getPredicate() == Other.getPredicate();
|
||||
case MachineOperand::MO_Placeholder:
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("Invalid machine operand type");
|
||||
}
|
||||
|
|
@ -337,8 +335,6 @@ hash_code llvm::hash_value(const MachineOperand &MO) {
|
|||
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIntrinsicID());
|
||||
case MachineOperand::MO_Predicate:
|
||||
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getPredicate());
|
||||
case MachineOperand::MO_Placeholder:
|
||||
return hash_combine();
|
||||
}
|
||||
llvm_unreachable("Invalid machine operand type");
|
||||
}
|
||||
|
|
@ -515,9 +511,6 @@ void MachineOperand::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
|||
<< CmpInst::getPredicateName(Pred) << '>';
|
||||
break;
|
||||
}
|
||||
case MachineOperand::MO_Placeholder:
|
||||
OS << "<placeholder>";
|
||||
break;
|
||||
}
|
||||
if (unsigned TF = getTargetFlags())
|
||||
OS << "[TF=" << TF << ']';
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ bool MachineLICM::runOnMachineFunction(MachineFunction &MF) {
|
|||
/// Return true if instruction stores to the specified frame.
|
||||
static bool InstructionStoresToFI(const MachineInstr *MI, int FI) {
|
||||
// If we lost memory operands, conservatively assume that the instruction
|
||||
// writes to all slots.
|
||||
// writes to all slots.
|
||||
if (MI->memoperands_empty())
|
||||
return true;
|
||||
for (const MachineMemOperand *MemOp : MI->memoperands()) {
|
||||
|
|
@ -708,7 +708,7 @@ void MachineLICM::SinkIntoLoop() {
|
|||
for (MachineBasicBlock::instr_iterator I = Preheader->instr_begin();
|
||||
I != Preheader->instr_end(); ++I) {
|
||||
// We need to ensure that we can safely move this instruction into the loop.
|
||||
// As such, it must not have side-effects, e.g. such as a call has.
|
||||
// As such, it must not have side-effects, e.g. such as a call has.
|
||||
if (IsLoopInvariantInst(*I) && !HasLoopPHIUse(&*I))
|
||||
Candidates.push_back(&*I);
|
||||
}
|
||||
|
|
@ -837,9 +837,9 @@ MachineLICM::calcRegisterCost(const MachineInstr *MI, bool ConsiderSeen,
|
|||
/// constant pool.
|
||||
static bool mayLoadFromGOTOrConstantPool(MachineInstr &MI) {
|
||||
assert (MI.mayLoad() && "Expected MI that loads!");
|
||||
|
||||
|
||||
// If we lost memory operands, conservatively assume that the instruction
|
||||
// reads from everything..
|
||||
// reads from everything..
|
||||
if (MI.memoperands_empty())
|
||||
return true;
|
||||
|
||||
|
|
@ -1337,7 +1337,7 @@ bool MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
|
|||
Preheader->splice(Preheader->getFirstTerminator(),MI->getParent(),MI);
|
||||
|
||||
// Since we are moving the instruction out of its basic block, we do not
|
||||
// retain its debug location. Doing so would degrade the debugging
|
||||
// retain its debug location. Doing so would degrade the debugging
|
||||
// experience and adversely affect the accuracy of profiling information.
|
||||
MI->setDebugLoc(DebugLoc());
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue