Merge llvm, clang, lld and lldb trunk r300890, and update build glue.
This commit is contained in:
commit
6bc11b1414
@ -2130,6 +2130,16 @@ LLVMValueRef LLVMMDNodeInContext(LLVMContextRef C, LLVMValueRef *Vals,
|
||||
*/
|
||||
LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count);
|
||||
|
||||
/**
|
||||
* Obtain a Metadata as a Value.
|
||||
*/
|
||||
LLVMValueRef LLVMMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD);
|
||||
|
||||
/**
|
||||
* Obtain a Value as a Metadata.
|
||||
*/
|
||||
LLVMMetadataRef LLVMValueAsMetadata(LLVMValueRef Val);
|
||||
|
||||
/**
|
||||
* Obtain the underlying string from a MDString value.
|
||||
*
|
||||
|
@ -82,6 +82,13 @@ typedef struct LLVMOpaqueValue *LLVMValueRef;
|
||||
*/
|
||||
typedef struct LLVMOpaqueBasicBlock *LLVMBasicBlockRef;
|
||||
|
||||
/**
|
||||
* Represents an LLVM Metadata.
|
||||
*
|
||||
* This models llvm::Metadata.
|
||||
*/
|
||||
typedef struct LLVMOpaqueMetadata *LLVMMetadataRef;
|
||||
|
||||
/**
|
||||
* Represents an LLVM basic block builder.
|
||||
*
|
||||
@ -89,6 +96,13 @@ typedef struct LLVMOpaqueBasicBlock *LLVMBasicBlockRef;
|
||||
*/
|
||||
typedef struct LLVMOpaqueBuilder *LLVMBuilderRef;
|
||||
|
||||
/**
|
||||
* Represents an LLVM debug info builder.
|
||||
*
|
||||
* This models llvm::DIBuilder.
|
||||
*/
|
||||
typedef struct LLVMOpaqueDIBuilder *LLVMDIBuilderRef;
|
||||
|
||||
/**
|
||||
* Interface used to provide a module to JIT or interpreter.
|
||||
* This is now just a synonym for llvm::Module, but we have to keep using the
|
||||
|
@ -189,17 +189,17 @@ private:
|
||||
void initSlowCase(const APInt &that);
|
||||
|
||||
/// out-of-line slow case for shl
|
||||
APInt shlSlowCase(unsigned shiftAmt) const;
|
||||
void shlSlowCase(unsigned ShiftAmt);
|
||||
|
||||
/// out-of-line slow case for lshr.
|
||||
void lshrSlowCase(unsigned ShiftAmt);
|
||||
|
||||
/// out-of-line slow case for operator=
|
||||
APInt &AssignSlowCase(const APInt &RHS);
|
||||
void AssignSlowCase(const APInt &RHS);
|
||||
|
||||
/// out-of-line slow case for operator==
|
||||
bool EqualSlowCase(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for operator==
|
||||
bool EqualSlowCase(uint64_t Val) const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for countLeadingZeros
|
||||
unsigned countLeadingZerosSlowCase() const LLVM_READONLY;
|
||||
|
||||
@ -209,6 +209,12 @@ private:
|
||||
/// out-of-line slow case for countPopulation
|
||||
unsigned countPopulationSlowCase() const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for intersects.
|
||||
bool intersectsSlowCase(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for isSubsetOf.
|
||||
bool isSubsetOfSlowCase(const APInt &RHS) const LLVM_READONLY;
|
||||
|
||||
/// out-of-line slow case for setBits.
|
||||
void setBitsSlowCase(unsigned loBit, unsigned hiBit);
|
||||
|
||||
@ -216,13 +222,13 @@ private:
|
||||
void flipAllBitsSlowCase();
|
||||
|
||||
/// out-of-line slow case for operator&=.
|
||||
APInt& AndAssignSlowCase(const APInt& RHS);
|
||||
void AndAssignSlowCase(const APInt& RHS);
|
||||
|
||||
/// out-of-line slow case for operator|=.
|
||||
APInt& OrAssignSlowCase(const APInt& RHS);
|
||||
void OrAssignSlowCase(const APInt& RHS);
|
||||
|
||||
/// out-of-line slow case for operator^=.
|
||||
APInt& XorAssignSlowCase(const APInt& RHS);
|
||||
void XorAssignSlowCase(const APInt& RHS);
|
||||
|
||||
public:
|
||||
/// \name Constructors
|
||||
@ -330,6 +336,20 @@ public:
|
||||
/// This tests the high bit of the APInt to determine if it is unset.
|
||||
bool isNonNegative() const { return !isNegative(); }
|
||||
|
||||
/// \brief Determine if sign bit of this APInt is set.
|
||||
///
|
||||
/// This tests the high bit of this APInt to determine if it is set.
|
||||
///
|
||||
/// \returns true if this APInt has its sign bit set, false otherwise.
|
||||
bool isSignBitSet() const { return (*this)[BitWidth-1]; }
|
||||
|
||||
/// \brief Determine if sign bit of this APInt is clear.
|
||||
///
|
||||
/// This tests the high bit of this APInt to determine if it is clear.
|
||||
///
|
||||
/// \returns true if this APInt has its sign bit clear, false otherwise.
|
||||
bool isSignBitClear() const { return !isSignBitSet(); }
|
||||
|
||||
/// \brief Determine if this APInt Value is positive.
|
||||
///
|
||||
/// This tests if the value of this APInt is positive (> 0). Note
|
||||
@ -396,10 +416,10 @@ public:
|
||||
return countPopulationSlowCase() == 1;
|
||||
}
|
||||
|
||||
/// \brief Check if the APInt's value is returned by getSignBit.
|
||||
/// \brief Check if the APInt's value is returned by getSignMask.
|
||||
///
|
||||
/// \returns true if this is the value returned by getSignBit.
|
||||
bool isSignBit() const { return isMinSignedValue(); }
|
||||
/// \returns true if this is the value returned by getSignMask.
|
||||
bool isSignMask() const { return isMinSignedValue(); }
|
||||
|
||||
/// \brief Convert APInt to a boolean value.
|
||||
///
|
||||
@ -409,8 +429,7 @@ public:
|
||||
/// If this value is smaller than the specified limit, return it, otherwise
|
||||
/// return the limit value. This causes the value to saturate to the limit.
|
||||
uint64_t getLimitedValue(uint64_t Limit = UINT64_MAX) const {
|
||||
return (getActiveBits() > 64 || getZExtValue() > Limit) ? Limit
|
||||
: getZExtValue();
|
||||
return ugt(Limit) ? Limit : getZExtValue();
|
||||
}
|
||||
|
||||
/// \brief Check if the APInt consists of a repeated bit pattern.
|
||||
@ -427,8 +446,9 @@ public:
|
||||
assert(numBits <= BitWidth && "numBits out of range");
|
||||
if (isSingleWord())
|
||||
return VAL == (UINT64_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
unsigned Ones = countTrailingOnes();
|
||||
return (numBits == Ones) && ((Ones + countLeadingZeros()) == BitWidth);
|
||||
unsigned Ones = countTrailingOnesSlowCase();
|
||||
return (numBits == Ones) &&
|
||||
((Ones + countLeadingZerosSlowCase()) == BitWidth);
|
||||
}
|
||||
|
||||
/// \returns true if this APInt is a non-empty sequence of ones starting at
|
||||
@ -437,8 +457,8 @@ public:
|
||||
bool isMask() const {
|
||||
if (isSingleWord())
|
||||
return isMask_64(VAL);
|
||||
unsigned Ones = countTrailingOnes();
|
||||
return (Ones > 0) && ((Ones + countLeadingZeros()) == BitWidth);
|
||||
unsigned Ones = countTrailingOnesSlowCase();
|
||||
return (Ones > 0) && ((Ones + countLeadingZerosSlowCase()) == BitWidth);
|
||||
}
|
||||
|
||||
/// \brief Return true if this APInt value contains a sequence of ones with
|
||||
@ -446,8 +466,9 @@ public:
|
||||
bool isShiftedMask() const {
|
||||
if (isSingleWord())
|
||||
return isShiftedMask_64(VAL);
|
||||
unsigned Ones = countPopulation();
|
||||
return (Ones + countTrailingZeros() + countLeadingZeros()) == BitWidth;
|
||||
unsigned Ones = countPopulationSlowCase();
|
||||
unsigned LeadZ = countLeadingZerosSlowCase();
|
||||
return (Ones + LeadZ + countTrailingZeros()) == BitWidth;
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -476,11 +497,11 @@ public:
|
||||
return API;
|
||||
}
|
||||
|
||||
/// \brief Get the SignBit for a specific bit width.
|
||||
/// \brief Get the SignMask for a specific bit width.
|
||||
///
|
||||
/// This is just a wrapper function of getSignedMinValue(), and it helps code
|
||||
/// readability when we want to get a SignBit.
|
||||
static APInt getSignBit(unsigned BitWidth) {
|
||||
/// readability when we want to get a SignMask.
|
||||
static APInt getSignMask(unsigned BitWidth) {
|
||||
return getSignedMinValue(BitWidth);
|
||||
}
|
||||
|
||||
@ -674,29 +695,22 @@ public:
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
return AssignSlowCase(RHS);
|
||||
AssignSlowCase(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Move assignment operator.
|
||||
APInt &operator=(APInt &&that) {
|
||||
if (!isSingleWord()) {
|
||||
// The MSVC STL shipped in 2013 requires that self move assignment be a
|
||||
// no-op. Otherwise algorithms like stable_sort will produce answers
|
||||
// where half of the output is left in a moved-from state.
|
||||
if (this == &that)
|
||||
return *this;
|
||||
assert(this != &that && "Self-move not supported");
|
||||
if (!isSingleWord())
|
||||
delete[] pVal;
|
||||
}
|
||||
|
||||
// Use memcpy so that type based alias analysis sees both VAL and pVal
|
||||
// as modified.
|
||||
memcpy(&VAL, &that.VAL, sizeof(uint64_t));
|
||||
|
||||
// If 'this == &that', avoid zeroing our own bitwidth by storing to 'that'
|
||||
// first.
|
||||
unsigned ThatBitWidth = that.BitWidth;
|
||||
BitWidth = that.BitWidth;
|
||||
that.BitWidth = 0;
|
||||
BitWidth = ThatBitWidth;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -727,11 +741,11 @@ public:
|
||||
/// \returns *this after ANDing with RHS.
|
||||
APInt &operator&=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
if (isSingleWord())
|
||||
VAL &= RHS.VAL;
|
||||
return *this;
|
||||
}
|
||||
return AndAssignSlowCase(RHS);
|
||||
else
|
||||
AndAssignSlowCase(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Bitwise AND assignment operator.
|
||||
@ -757,11 +771,11 @@ public:
|
||||
/// \returns *this after ORing with RHS.
|
||||
APInt &operator|=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
if (isSingleWord())
|
||||
VAL |= RHS.VAL;
|
||||
return *this;
|
||||
}
|
||||
return OrAssignSlowCase(RHS);
|
||||
else
|
||||
OrAssignSlowCase(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Bitwise OR assignment operator.
|
||||
@ -787,11 +801,11 @@ public:
|
||||
/// \returns *this after XORing with RHS.
|
||||
APInt &operator^=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
if (isSingleWord())
|
||||
VAL ^= RHS.VAL;
|
||||
return *this;
|
||||
}
|
||||
return XorAssignSlowCase(RHS);
|
||||
else
|
||||
XorAssignSlowCase(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Bitwise XOR assignment operator.
|
||||
@ -836,9 +850,17 @@ public:
|
||||
///
|
||||
/// Shifts *this left by shiftAmt and assigns the result to *this.
|
||||
///
|
||||
/// \returns *this after shifting left by shiftAmt
|
||||
APInt &operator<<=(unsigned shiftAmt) {
|
||||
*this = shl(shiftAmt);
|
||||
/// \returns *this after shifting left by ShiftAmt
|
||||
APInt &operator<<=(unsigned ShiftAmt) {
|
||||
assert(ShiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
if (ShiftAmt == BitWidth)
|
||||
VAL = 0;
|
||||
else
|
||||
VAL <<= ShiftAmt;
|
||||
return clearUnusedBits();
|
||||
}
|
||||
shlSlowCase(ShiftAmt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -875,20 +897,26 @@ public:
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Logical right-shift this APInt by shiftAmt in place.
|
||||
void lshrInPlace(unsigned shiftAmt);
|
||||
/// Logical right-shift this APInt by ShiftAmt in place.
|
||||
void lshrInPlace(unsigned ShiftAmt) {
|
||||
assert(ShiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
if (ShiftAmt == BitWidth)
|
||||
VAL = 0;
|
||||
else
|
||||
VAL >>= ShiftAmt;
|
||||
return;
|
||||
}
|
||||
lshrSlowCase(ShiftAmt);
|
||||
}
|
||||
|
||||
/// \brief Left-shift function.
|
||||
///
|
||||
/// Left-shift this APInt by shiftAmt.
|
||||
APInt shl(unsigned shiftAmt) const {
|
||||
assert(shiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
if (shiftAmt >= BitWidth)
|
||||
return APInt(BitWidth, 0); // avoid undefined shift results
|
||||
return APInt(BitWidth, VAL << shiftAmt);
|
||||
}
|
||||
return shlSlowCase(shiftAmt);
|
||||
APInt R(*this);
|
||||
R <<= shiftAmt;
|
||||
return R;
|
||||
}
|
||||
|
||||
/// \brief Rotate left by rotateAmt.
|
||||
@ -905,7 +933,14 @@ public:
|
||||
/// \brief Logical right-shift function.
|
||||
///
|
||||
/// Logical right-shift this APInt by shiftAmt.
|
||||
APInt lshr(const APInt &shiftAmt) const;
|
||||
APInt lshr(const APInt &ShiftAmt) const {
|
||||
APInt R(*this);
|
||||
R.lshrInPlace(ShiftAmt);
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Logical right-shift this APInt by ShiftAmt in place.
|
||||
void lshrInPlace(const APInt &ShiftAmt);
|
||||
|
||||
/// \brief Left-shift function.
|
||||
///
|
||||
@ -1003,9 +1038,7 @@ public:
|
||||
///
|
||||
/// \returns true if *this == Val
|
||||
bool operator==(uint64_t Val) const {
|
||||
if (isSingleWord())
|
||||
return VAL == Val;
|
||||
return EqualSlowCase(Val);
|
||||
return (isSingleWord() || getActiveBits() <= 64) && getZExtValue() == Val;
|
||||
}
|
||||
|
||||
/// \brief Equality comparison.
|
||||
@ -1055,7 +1088,8 @@ public:
|
||||
///
|
||||
/// \returns true if *this < RHS when considered unsigned.
|
||||
bool ult(uint64_t RHS) const {
|
||||
return getActiveBits() > 64 ? false : getZExtValue() < RHS;
|
||||
// Only need to check active bits if not a single word.
|
||||
return (isSingleWord() || getActiveBits() <= 64) && getZExtValue() < RHS;
|
||||
}
|
||||
|
||||
/// \brief Signed less than comparison
|
||||
@ -1073,7 +1107,8 @@ public:
|
||||
///
|
||||
/// \returns true if *this < RHS when considered signed.
|
||||
bool slt(int64_t RHS) const {
|
||||
return getMinSignedBits() > 64 ? isNegative() : getSExtValue() < RHS;
|
||||
return (!isSingleWord() && getMinSignedBits() > 64) ? isNegative()
|
||||
: getSExtValue() < RHS;
|
||||
}
|
||||
|
||||
/// \brief Unsigned less or equal comparison
|
||||
@ -1123,7 +1158,8 @@ public:
|
||||
///
|
||||
/// \returns true if *this > RHS when considered unsigned.
|
||||
bool ugt(uint64_t RHS) const {
|
||||
return getActiveBits() > 64 ? true : getZExtValue() > RHS;
|
||||
// Only need to check active bits if not a single word.
|
||||
return (!isSingleWord() && getActiveBits() > 64) || getZExtValue() > RHS;
|
||||
}
|
||||
|
||||
/// \brief Signed greather than comparison
|
||||
@ -1141,7 +1177,8 @@ public:
|
||||
///
|
||||
/// \returns true if *this > RHS when considered signed.
|
||||
bool sgt(int64_t RHS) const {
|
||||
return getMinSignedBits() > 64 ? !isNegative() : getSExtValue() > RHS;
|
||||
return (!isSingleWord() && getMinSignedBits() > 64) ? !isNegative()
|
||||
: getSExtValue() > RHS;
|
||||
}
|
||||
|
||||
/// \brief Unsigned greater or equal comparison
|
||||
@ -1179,9 +1216,18 @@ public:
|
||||
/// This operation tests if there are any pairs of corresponding bits
|
||||
/// between this APInt and RHS that are both set.
|
||||
bool intersects(const APInt &RHS) const {
|
||||
APInt temp(*this);
|
||||
temp &= RHS;
|
||||
return temp != 0;
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return (VAL & RHS.VAL) != 0;
|
||||
return intersectsSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// This operation checks that all bits set in this APInt are also set in RHS.
|
||||
bool isSubsetOf(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return (VAL & ~RHS.VAL) == 0;
|
||||
return isSubsetOfSlowCase(RHS);
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -1404,8 +1450,7 @@ public:
|
||||
/// int64_t. Otherwise an assertion will result.
|
||||
int64_t getSExtValue() const {
|
||||
if (isSingleWord())
|
||||
return int64_t(VAL << (APINT_BITS_PER_WORD - BitWidth)) >>
|
||||
(APINT_BITS_PER_WORD - BitWidth);
|
||||
return SignExtend64(VAL, BitWidth);
|
||||
assert(getMinSignedBits() <= 64 && "Too many bits for int64_t");
|
||||
return int64_t(pVal[0]);
|
||||
}
|
||||
@ -1759,13 +1804,13 @@ public:
|
||||
WordType *remainder, WordType *scratch,
|
||||
unsigned parts);
|
||||
|
||||
/// Shift a bignum left COUNT bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on COUNT.
|
||||
static void tcShiftLeft(WordType *, unsigned parts, unsigned count);
|
||||
/// Shift a bignum left Count bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on Count.
|
||||
static void tcShiftLeft(WordType *, unsigned Words, unsigned Count);
|
||||
|
||||
/// Shift a bignum right COUNT bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on COUNT.
|
||||
static void tcShiftRight(WordType *, unsigned parts, unsigned count);
|
||||
/// Shift a bignum right Count bits. Shifted in bits are zero. There are no
|
||||
/// restrictions on Count.
|
||||
static void tcShiftRight(WordType *, unsigned Words, unsigned Count);
|
||||
|
||||
/// The obvious AND, OR and XOR and complement operations.
|
||||
static void tcAnd(WordType *, const WordType *, unsigned);
|
||||
@ -1959,7 +2004,7 @@ inline const APInt &umax(const APInt &A, const APInt &B) {
|
||||
/// \brief Compute GCD of two unsigned APInt values.
|
||||
///
|
||||
/// This function returns the greatest common divisor of the two APInt values
|
||||
/// using Euclid's algorithm.
|
||||
/// using Stein's algorithm.
|
||||
///
|
||||
/// \returns the greatest common divisor of A and B.
|
||||
APInt GreatestCommonDivisor(APInt A, APInt B);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef LLVM_ADT_BITVECTOR_H
|
||||
#define LLVM_ADT_BITVECTOR_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
@ -455,6 +457,105 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitVector &operator>>=(unsigned N) {
|
||||
assert(N <= Size);
|
||||
if (LLVM_UNLIKELY(empty() || N == 0))
|
||||
return *this;
|
||||
|
||||
unsigned NumWords = NumBitWords(Size);
|
||||
assert(NumWords >= 1);
|
||||
|
||||
wordShr(N / BITWORD_SIZE);
|
||||
|
||||
unsigned BitDistance = N % BITWORD_SIZE;
|
||||
if (BitDistance == 0)
|
||||
return *this;
|
||||
|
||||
// When the shift size is not a multiple of the word size, then we have
|
||||
// a tricky situation where each word in succession needs to extract some
|
||||
// of the bits from the next word and or them into this word while
|
||||
// shifting this word to make room for the new bits. This has to be done
|
||||
// for every word in the array.
|
||||
|
||||
// Since we're shifting each word right, some bits will fall off the end
|
||||
// of each word to the right, and empty space will be created on the left.
|
||||
// The final word in the array will lose bits permanently, so starting at
|
||||
// the beginning, work forwards shifting each word to the right, and
|
||||
// OR'ing in the bits from the end of the next word to the beginning of
|
||||
// the current word.
|
||||
|
||||
// Example:
|
||||
// Starting with {0xAABBCCDD, 0xEEFF0011, 0x22334455} and shifting right
|
||||
// by 4 bits.
|
||||
// Step 1: Word[0] >>= 4 ; 0x0ABBCCDD
|
||||
// Step 2: Word[0] |= 0x10000000 ; 0x1ABBCCDD
|
||||
// Step 3: Word[1] >>= 4 ; 0x0EEFF001
|
||||
// Step 4: Word[1] |= 0x50000000 ; 0x5EEFF001
|
||||
// Step 5: Word[2] >>= 4 ; 0x02334455
|
||||
// Result: { 0x1ABBCCDD, 0x5EEFF001, 0x02334455 }
|
||||
const BitWord Mask = maskTrailingOnes<BitWord>(BitDistance);
|
||||
const unsigned LSH = BITWORD_SIZE - BitDistance;
|
||||
|
||||
for (unsigned I = 0; I < NumWords - 1; ++I) {
|
||||
Bits[I] >>= BitDistance;
|
||||
Bits[I] |= (Bits[I + 1] & Mask) << LSH;
|
||||
}
|
||||
|
||||
Bits[NumWords - 1] >>= BitDistance;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitVector &operator<<=(unsigned N) {
|
||||
assert(N <= Size);
|
||||
if (LLVM_UNLIKELY(empty() || N == 0))
|
||||
return *this;
|
||||
|
||||
unsigned NumWords = NumBitWords(Size);
|
||||
assert(NumWords >= 1);
|
||||
|
||||
wordShl(N / BITWORD_SIZE);
|
||||
|
||||
unsigned BitDistance = N % BITWORD_SIZE;
|
||||
if (BitDistance == 0)
|
||||
return *this;
|
||||
|
||||
// When the shift size is not a multiple of the word size, then we have
|
||||
// a tricky situation where each word in succession needs to extract some
|
||||
// of the bits from the previous word and or them into this word while
|
||||
// shifting this word to make room for the new bits. This has to be done
|
||||
// for every word in the array. This is similar to the algorithm outlined
|
||||
// in operator>>=, but backwards.
|
||||
|
||||
// Since we're shifting each word left, some bits will fall off the end
|
||||
// of each word to the left, and empty space will be created on the right.
|
||||
// The first word in the array will lose bits permanently, so starting at
|
||||
// the end, work backwards shifting each word to the left, and OR'ing
|
||||
// in the bits from the end of the next word to the beginning of the
|
||||
// current word.
|
||||
|
||||
// Example:
|
||||
// Starting with {0xAABBCCDD, 0xEEFF0011, 0x22334455} and shifting left
|
||||
// by 4 bits.
|
||||
// Step 1: Word[2] <<= 4 ; 0x23344550
|
||||
// Step 2: Word[2] |= 0x0000000E ; 0x2334455E
|
||||
// Step 3: Word[1] <<= 4 ; 0xEFF00110
|
||||
// Step 4: Word[1] |= 0x0000000A ; 0xEFF0011A
|
||||
// Step 5: Word[0] <<= 4 ; 0xABBCCDD0
|
||||
// Result: { 0xABBCCDD0, 0xEFF0011A, 0x2334455E }
|
||||
const BitWord Mask = maskLeadingOnes<BitWord>(BitDistance);
|
||||
const unsigned RSH = BITWORD_SIZE - BitDistance;
|
||||
|
||||
for (int I = NumWords - 1; I > 0; --I) {
|
||||
Bits[I] <<= BitDistance;
|
||||
Bits[I] |= (Bits[I - 1] & Mask) >> RSH;
|
||||
}
|
||||
Bits[0] <<= BitDistance;
|
||||
clear_unused_bits();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assignment operator.
|
||||
const BitVector &operator=(const BitVector &RHS) {
|
||||
if (this == &RHS) return *this;
|
||||
@ -538,6 +639,54 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief Perform a logical left shift of \p Count words by moving everything
|
||||
/// \p Count words to the right in memory.
|
||||
///
|
||||
/// While confusing, words are stored from least significant at Bits[0] to
|
||||
/// most significant at Bits[NumWords-1]. A logical shift left, however,
|
||||
/// moves the current least significant bit to a higher logical index, and
|
||||
/// fills the previous least significant bits with 0. Thus, we actually
|
||||
/// need to move the bytes of the memory to the right, not to the left.
|
||||
/// Example:
|
||||
/// Words = [0xBBBBAAAA, 0xDDDDFFFF, 0x00000000, 0xDDDD0000]
|
||||
/// represents a BitVector where 0xBBBBAAAA contain the least significant
|
||||
/// bits. So if we want to shift the BitVector left by 2 words, we need to
|
||||
/// turn this into 0x00000000 0x00000000 0xBBBBAAAA 0xDDDDFFFF by using a
|
||||
/// memmove which moves right, not left.
|
||||
void wordShl(uint32_t Count) {
|
||||
if (Count == 0)
|
||||
return;
|
||||
|
||||
uint32_t NumWords = NumBitWords(Size);
|
||||
|
||||
auto Src = ArrayRef<BitWord>(Bits, NumWords).drop_back(Count);
|
||||
auto Dest = MutableArrayRef<BitWord>(Bits, 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));
|
||||
clear_unused_bits();
|
||||
}
|
||||
|
||||
/// \brief Perform a logical right shift of \p Count words by moving those
|
||||
/// words to the left in memory. See wordShl for more information.
|
||||
///
|
||||
void wordShr(uint32_t Count) {
|
||||
if (Count == 0)
|
||||
return;
|
||||
|
||||
uint32_t NumWords = NumBitWords(Size);
|
||||
|
||||
auto Src = ArrayRef<BitWord>(Bits, NumWords).drop_front(Count);
|
||||
auto Dest = MutableArrayRef<BitWord>(Bits, 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));
|
||||
}
|
||||
|
||||
int next_unset_in_word(int WordIndex, BitWord Word) const {
|
||||
unsigned Result = WordIndex * BITWORD_SIZE + countTrailingOnes(Word);
|
||||
return Result < size() ? Result : -1;
|
||||
|
@ -508,6 +508,22 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallBitVector &operator<<=(unsigned N) {
|
||||
if (isSmall())
|
||||
setSmallBits(getSmallBits() << N);
|
||||
else
|
||||
getPointer()->operator<<=(N);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallBitVector &operator>>=(unsigned N) {
|
||||
if (isSmall())
|
||||
setSmallBits(getSmallBits() >> N);
|
||||
else
|
||||
getPointer()->operator>>=(N);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Assignment operator.
|
||||
const SmallBitVector &operator=(const SmallBitVector &RHS) {
|
||||
if (isSmall()) {
|
||||
|
@ -1164,9 +1164,8 @@ template <class BT> struct BlockEdgesAdder {
|
||||
void operator()(IrreducibleGraph &G, IrreducibleGraph::IrrNode &Irr,
|
||||
const LoopData *OuterLoop) {
|
||||
const BlockT *BB = BFI.RPOT[Irr.Node.Index];
|
||||
for (auto I = Successor::child_begin(BB), E = Successor::child_end(BB);
|
||||
I != E; ++I)
|
||||
G.addEdge(Irr, BFI.getNode(*I), OuterLoop);
|
||||
for (const auto Succ : children<const BlockT *>(BB))
|
||||
G.addEdge(Irr, BFI.getNode(Succ), OuterLoop);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1210,10 +1209,9 @@ BlockFrequencyInfoImpl<BT>::propagateMassToSuccessors(LoopData *OuterLoop,
|
||||
return false;
|
||||
} else {
|
||||
const BlockT *BB = getBlock(Node);
|
||||
for (auto SI = Successor::child_begin(BB), SE = Successor::child_end(BB);
|
||||
SI != SE; ++SI)
|
||||
if (!addToDist(Dist, OuterLoop, Node, getNode(*SI),
|
||||
getWeightFromBranchProb(BPI->getEdgeProbability(BB, SI))))
|
||||
for (const auto Succ : children<const BlockT *>(BB))
|
||||
if (!addToDist(Dist, OuterLoop, Node, getNode(Succ),
|
||||
getWeightFromBranchProb(BPI->getEdgeProbability(BB, Succ))))
|
||||
// Irreducible backedge.
|
||||
return false;
|
||||
}
|
||||
|
@ -174,12 +174,10 @@ ForwardDominanceFrontierBase<BlockT>::calculate(const DomTreeT &DT,
|
||||
// Visit each block only once.
|
||||
if (visited.insert(currentBB).second) {
|
||||
// Loop over CFG successors to calculate DFlocal[currentNode]
|
||||
for (auto SI = BlockTraits::child_begin(currentBB),
|
||||
SE = BlockTraits::child_end(currentBB);
|
||||
SI != SE; ++SI) {
|
||||
for (const auto Succ : children<BlockT *>(currentBB)) {
|
||||
// Does Node immediately dominate this successor?
|
||||
if (DT[*SI]->getIDom() != currentNode)
|
||||
S.insert(*SI);
|
||||
if (DT[Succ]->getIDom() != currentNode)
|
||||
S.insert(Succ);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,11 +158,8 @@ 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 {
|
||||
typedef GraphTraits<const BlockT*> BlockTraits;
|
||||
for (typename BlockTraits::ChildIteratorType SI =
|
||||
BlockTraits::child_begin(BB),
|
||||
SE = BlockTraits::child_end(BB); SI != SE; ++SI) {
|
||||
if (!contains(*SI))
|
||||
for (const auto Succ : children<const BlockT*>(BB)) {
|
||||
if (!contains(Succ))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -186,11 +183,8 @@ public:
|
||||
unsigned NumBackEdges = 0;
|
||||
BlockT *H = getHeader();
|
||||
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
for (typename InvBlockTraits::ChildIteratorType I =
|
||||
InvBlockTraits::child_begin(H),
|
||||
E = InvBlockTraits::child_end(H); I != E; ++I)
|
||||
if (contains(*I))
|
||||
for (const auto Pred : children<Inverse<BlockT*> >(H))
|
||||
if (contains(Pred))
|
||||
++NumBackEdges;
|
||||
|
||||
return NumBackEdges;
|
||||
@ -249,12 +243,9 @@ public:
|
||||
/// contains a branch back to the header.
|
||||
void getLoopLatches(SmallVectorImpl<BlockT *> &LoopLatches) const {
|
||||
BlockT *H = getHeader();
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
for (typename InvBlockTraits::ChildIteratorType I =
|
||||
InvBlockTraits::child_begin(H),
|
||||
E = InvBlockTraits::child_end(H); I != E; ++I)
|
||||
if (contains(*I))
|
||||
LoopLatches.push_back(*I);
|
||||
for (const auto Pred : children<Inverse<BlockT*>>(H))
|
||||
if (contains(Pred))
|
||||
LoopLatches.push_back(Pred);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -34,14 +34,11 @@ namespace llvm {
|
||||
template<class BlockT, class LoopT>
|
||||
void LoopBase<BlockT, LoopT>::
|
||||
getExitingBlocks(SmallVectorImpl<BlockT *> &ExitingBlocks) const {
|
||||
typedef GraphTraits<BlockT*> BlockTraits;
|
||||
for (block_iterator BI = block_begin(), BE = block_end(); BI != BE; ++BI)
|
||||
for (typename BlockTraits::ChildIteratorType I =
|
||||
BlockTraits::child_begin(*BI), E = BlockTraits::child_end(*BI);
|
||||
I != E; ++I)
|
||||
if (!contains(*I)) {
|
||||
for (const auto BB : blocks())
|
||||
for (const auto Succ : children<BlockT*>(BB))
|
||||
if (!contains(Succ)) {
|
||||
// Not in current loop? It must be an exit block.
|
||||
ExitingBlocks.push_back(*BI);
|
||||
ExitingBlocks.push_back(BB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -63,14 +60,11 @@ BlockT *LoopBase<BlockT, LoopT>::getExitingBlock() const {
|
||||
template<class BlockT, class LoopT>
|
||||
void LoopBase<BlockT, LoopT>::
|
||||
getExitBlocks(SmallVectorImpl<BlockT*> &ExitBlocks) const {
|
||||
typedef GraphTraits<BlockT*> BlockTraits;
|
||||
for (block_iterator BI = block_begin(), BE = block_end(); BI != BE; ++BI)
|
||||
for (typename BlockTraits::ChildIteratorType I =
|
||||
BlockTraits::child_begin(*BI), E = BlockTraits::child_end(*BI);
|
||||
I != E; ++I)
|
||||
if (!contains(*I))
|
||||
for (const auto BB : blocks())
|
||||
for (const auto Succ : children<BlockT*>(BB))
|
||||
if (!contains(Succ))
|
||||
// Not in current loop? It must be an exit block.
|
||||
ExitBlocks.push_back(*I);
|
||||
ExitBlocks.push_back(Succ);
|
||||
}
|
||||
|
||||
/// getExitBlock - If getExitBlocks would return exactly one block,
|
||||
@ -88,14 +82,11 @@ BlockT *LoopBase<BlockT, LoopT>::getExitBlock() const {
|
||||
template<class BlockT, class LoopT>
|
||||
void LoopBase<BlockT, LoopT>::
|
||||
getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const {
|
||||
typedef GraphTraits<BlockT*> BlockTraits;
|
||||
for (block_iterator BI = block_begin(), BE = block_end(); BI != BE; ++BI)
|
||||
for (typename BlockTraits::ChildIteratorType I =
|
||||
BlockTraits::child_begin(*BI), E = BlockTraits::child_end(*BI);
|
||||
I != E; ++I)
|
||||
if (!contains(*I))
|
||||
for (const auto BB : blocks())
|
||||
for (const auto Succ : children<BlockT*>(BB))
|
||||
if (!contains(Succ))
|
||||
// Not in current loop? It must be an exit block.
|
||||
ExitEdges.push_back(Edge(*BI, *I));
|
||||
ExitEdges.emplace_back(BB, Succ);
|
||||
}
|
||||
|
||||
/// getLoopPreheader - If there is a preheader for this loop, return it. A
|
||||
@ -134,15 +125,11 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
||||
|
||||
// Loop over the predecessors of the header node...
|
||||
BlockT *Header = getHeader();
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
for (typename InvBlockTraits::ChildIteratorType PI =
|
||||
InvBlockTraits::child_begin(Header),
|
||||
PE = InvBlockTraits::child_end(Header); PI != PE; ++PI) {
|
||||
typename InvBlockTraits::NodeRef N = *PI;
|
||||
if (!contains(N)) { // If the block is not in the loop...
|
||||
if (Out && Out != N)
|
||||
for (const auto Pred : children<Inverse<BlockT*>>(Header)) {
|
||||
if (!contains(Pred)) { // If the block is not in the loop...
|
||||
if (Out && Out != Pred)
|
||||
return nullptr; // Multiple predecessors outside the loop
|
||||
Out = N;
|
||||
Out = Pred;
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,17 +143,11 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPredecessor() const {
|
||||
template<class BlockT, class LoopT>
|
||||
BlockT *LoopBase<BlockT, LoopT>::getLoopLatch() const {
|
||||
BlockT *Header = getHeader();
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
typename InvBlockTraits::ChildIteratorType PI =
|
||||
InvBlockTraits::child_begin(Header);
|
||||
typename InvBlockTraits::ChildIteratorType PE =
|
||||
InvBlockTraits::child_end(Header);
|
||||
BlockT *Latch = nullptr;
|
||||
for (; PI != PE; ++PI) {
|
||||
typename InvBlockTraits::NodeRef N = *PI;
|
||||
if (contains(N)) {
|
||||
for (const auto Pred : children<Inverse<BlockT*>>(Header)) {
|
||||
if (contains(Pred)) {
|
||||
if (Latch) return nullptr;
|
||||
Latch = N;
|
||||
Latch = Pred;
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,11 +375,9 @@ static void discoverAndMapSubloop(LoopT *L, ArrayRef<BlockT*> Backedges,
|
||||
// within this subloop tree itself. Note that a predecessor may directly
|
||||
// reach another subloop that is not yet discovered to be a subloop of
|
||||
// this loop, which we must traverse.
|
||||
for (typename InvBlockTraits::ChildIteratorType PI =
|
||||
InvBlockTraits::child_begin(PredBB),
|
||||
PE = InvBlockTraits::child_end(PredBB); PI != PE; ++PI) {
|
||||
if (LI->getLoopFor(*PI) != Subloop)
|
||||
ReverseCFGWorklist.push_back(*PI);
|
||||
for (const auto Pred : children<Inverse<BlockT*>>(PredBB)) {
|
||||
if (LI->getLoopFor(Pred) != Subloop)
|
||||
ReverseCFGWorklist.push_back(Pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -482,13 +461,7 @@ analyze(const DominatorTreeBase<BlockT> &DomTree) {
|
||||
SmallVector<BlockT *, 4> Backedges;
|
||||
|
||||
// Check each predecessor of the potential loop header.
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
for (typename InvBlockTraits::ChildIteratorType PI =
|
||||
InvBlockTraits::child_begin(Header),
|
||||
PE = InvBlockTraits::child_end(Header); PI != PE; ++PI) {
|
||||
|
||||
BlockT *Backedge = *PI;
|
||||
|
||||
for (const auto Backedge : children<Inverse<BlockT*>>(Header)) {
|
||||
// If Header dominates predBB, this is a new loop. Collect the backedges.
|
||||
if (DomTree.dominates(Header, Backedge)
|
||||
&& DomTree.isReachableFromEntry(Backedge)) {
|
||||
|
@ -53,6 +53,11 @@ bool isMallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory similar to malloc or calloc.
|
||||
bool isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory (either malloc, calloc, or strdup like).
|
||||
bool isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
|
@ -1159,8 +1159,20 @@ public:
|
||||
const SCEV *getConstant(const APInt &Val);
|
||||
const SCEV *getConstant(Type *Ty, uint64_t V, bool isSigned = false);
|
||||
const SCEV *getTruncateExpr(const SCEV *Op, Type *Ty);
|
||||
|
||||
typedef SmallDenseMap<std::pair<const SCEV *, Type *>, const SCEV *, 8>
|
||||
ExtendCacheTy;
|
||||
const SCEV *getZeroExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getZeroExtendExprCached(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
const SCEV *getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
|
||||
const SCEV *getSignExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getSignExtendExprCached(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
const SCEV *getSignExtendExprImpl(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
const SCEV *getAnyExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
|
||||
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap,
|
||||
|
@ -46,6 +46,9 @@ namespace llvm {
|
||||
ArrayRef<uint8_t> Buffer;
|
||||
StringRef ModuleIdentifier;
|
||||
|
||||
// The string table used to interpret this module.
|
||||
StringRef Strtab;
|
||||
|
||||
// The bitstream location of the IDENTIFICATION_BLOCK.
|
||||
uint64_t IdentificationBit;
|
||||
|
||||
@ -70,6 +73,7 @@ namespace llvm {
|
||||
StringRef getBuffer() const {
|
||||
return StringRef((const char *)Buffer.begin(), Buffer.size());
|
||||
}
|
||||
StringRef getStrtab() const { return Strtab; }
|
||||
|
||||
StringRef getModuleIdentifier() const { return ModuleIdentifier; }
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_BITCODE_BITCODEWRITER_H
|
||||
|
||||
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
@ -26,12 +27,25 @@ namespace llvm {
|
||||
SmallVectorImpl<char> &Buffer;
|
||||
std::unique_ptr<BitstreamWriter> Stream;
|
||||
|
||||
StringTableBuilder StrtabBuilder{StringTableBuilder::RAW};
|
||||
bool WroteStrtab = false;
|
||||
|
||||
void writeBlob(unsigned Block, unsigned Record, StringRef Blob);
|
||||
|
||||
public:
|
||||
/// Create a BitcodeWriter that writes to Buffer.
|
||||
BitcodeWriter(SmallVectorImpl<char> &Buffer);
|
||||
|
||||
~BitcodeWriter();
|
||||
|
||||
/// Write the bitcode file's string table. This must be called exactly once
|
||||
/// after all modules have been written.
|
||||
void writeStrtab();
|
||||
|
||||
/// Copy the string table for another module into this bitcode file. This
|
||||
/// should be called after copying the module itself into the bitcode file.
|
||||
void copyStrtab(StringRef Strtab);
|
||||
|
||||
/// Write the specified module to the buffer specified at construction time.
|
||||
///
|
||||
/// If \c ShouldPreserveUseListOrder, encode the use-list order for each \a
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
namespace llvm {
|
||||
namespace bitc {
|
||||
// The only top-level block type defined is for a module.
|
||||
// The only top-level block types are MODULE, IDENTIFICATION and STRTAB.
|
||||
enum BlockIDs {
|
||||
// Blocks
|
||||
MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID,
|
||||
@ -52,7 +52,9 @@ enum BlockIDs {
|
||||
|
||||
OPERAND_BUNDLE_TAGS_BLOCK_ID,
|
||||
|
||||
METADATA_KIND_BLOCK_ID
|
||||
METADATA_KIND_BLOCK_ID,
|
||||
|
||||
STRTAB_BLOCK_ID,
|
||||
};
|
||||
|
||||
/// Identification block contains a string that describes the producer details,
|
||||
@ -232,6 +234,10 @@ enum GlobalValueSummarySymtabCodes {
|
||||
// llvm.type.checked.load intrinsic with all constant integer arguments.
|
||||
// [typeid, offset, n x arg]
|
||||
FS_TYPE_CHECKED_LOAD_CONST_VCALL = 15,
|
||||
// Assigns a GUID to a value ID. This normally appears only in combined
|
||||
// summaries, but it can also appear in per-module summaries for PGO data.
|
||||
// [valueid, guid]
|
||||
FS_VALUE_GUID = 16,
|
||||
};
|
||||
|
||||
enum MetadataCodes {
|
||||
@ -550,6 +556,10 @@ enum ComdatSelectionKindCodes {
|
||||
COMDAT_SELECTION_KIND_SAME_SIZE = 5,
|
||||
};
|
||||
|
||||
enum StrtabCodes {
|
||||
STRTAB_BLOB = 1,
|
||||
};
|
||||
|
||||
} // End bitc namespace
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -62,9 +62,6 @@ protected:
|
||||
const TargetRegisterInfo &TRI,
|
||||
const RegisterBankInfo &RBI) const;
|
||||
|
||||
Optional<int64_t> getConstantVRegVal(unsigned VReg,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
|
@ -60,5 +60,8 @@ void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
const char *PassName, StringRef Msg,
|
||||
const MachineInstr &MI);
|
||||
|
||||
Optional<int64_t> getConstantVRegVal(unsigned VReg,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
} // End namespace llvm.
|
||||
#endif
|
||||
|
@ -413,6 +413,11 @@ MachineInstrBuilder BuildMI(MachineBasicBlock &BB,
|
||||
unsigned Reg, unsigned Offset,
|
||||
const MDNode *Variable, const MDNode *Expr);
|
||||
|
||||
/// Clone a DBG_VALUE whose value has been spilled to FrameIndex.
|
||||
MachineInstr *buildDbgValueForSpill(MachineBasicBlock &BB,
|
||||
MachineBasicBlock::iterator I,
|
||||
const MachineInstr &Orig, int FrameIndex);
|
||||
|
||||
inline unsigned getDefRegState(bool B) {
|
||||
return B ? RegState::Define : 0;
|
||||
}
|
||||
|
@ -28,155 +28,246 @@ namespace llvm {
|
||||
/// type can be represented by an MVT.
|
||||
class MVT {
|
||||
public:
|
||||
enum SimpleValueType : int8_t {
|
||||
// Simple value types less than zero are considered extended value types.
|
||||
INVALID_SIMPLE_VALUE_TYPE = -1,
|
||||
enum SimpleValueType : uint8_t {
|
||||
// Simple value types that aren't explicitly part of this enumeration
|
||||
// are considered extended value types.
|
||||
INVALID_SIMPLE_VALUE_TYPE = 0,
|
||||
|
||||
// If you change this numbering, you must change the values in
|
||||
// ValueTypes.td as well!
|
||||
Other = 0, // This is a non-standard value
|
||||
i1 = 1, // This is a 1 bit integer value
|
||||
i8 = 2, // This is an 8 bit integer value
|
||||
i16 = 3, // This is a 16 bit integer value
|
||||
i32 = 4, // This is a 32 bit integer value
|
||||
i64 = 5, // This is a 64 bit integer value
|
||||
i128 = 6, // This is a 128 bit integer value
|
||||
Other = 1, // This is a non-standard value
|
||||
i1 = 2, // This is a 1 bit integer value
|
||||
i8 = 3, // This is an 8 bit integer value
|
||||
i16 = 4, // This is a 16 bit integer value
|
||||
i32 = 5, // This is a 32 bit integer value
|
||||
i64 = 6, // This is a 64 bit integer value
|
||||
i128 = 7, // This is a 128 bit integer value
|
||||
|
||||
FIRST_INTEGER_VALUETYPE = i1,
|
||||
LAST_INTEGER_VALUETYPE = i128,
|
||||
|
||||
f16 = 7, // This is a 16 bit floating point value
|
||||
f32 = 8, // This is a 32 bit floating point value
|
||||
f64 = 9, // This is a 64 bit floating point value
|
||||
f80 = 10, // This is a 80 bit floating point value
|
||||
f128 = 11, // This is a 128 bit floating point value
|
||||
ppcf128 = 12, // This is a PPC 128-bit floating point value
|
||||
f16 = 8, // This is a 16 bit floating point value
|
||||
f32 = 9, // This is a 32 bit floating point value
|
||||
f64 = 10, // This is a 64 bit floating point value
|
||||
f80 = 11, // This is a 80 bit floating point value
|
||||
f128 = 12, // This is a 128 bit floating point value
|
||||
ppcf128 = 13, // This is a PPC 128-bit floating point value
|
||||
|
||||
FIRST_FP_VALUETYPE = f16,
|
||||
LAST_FP_VALUETYPE = ppcf128,
|
||||
|
||||
v2i1 = 13, // 2 x i1
|
||||
v4i1 = 14, // 4 x i1
|
||||
v8i1 = 15, // 8 x i1
|
||||
v16i1 = 16, // 16 x i1
|
||||
v32i1 = 17, // 32 x i1
|
||||
v64i1 = 18, // 64 x i1
|
||||
v512i1 = 19, // 512 x i1
|
||||
v1024i1 = 20, // 1024 x i1
|
||||
v2i1 = 14, // 2 x i1
|
||||
v4i1 = 15, // 4 x i1
|
||||
v8i1 = 16, // 8 x i1
|
||||
v16i1 = 17, // 16 x i1
|
||||
v32i1 = 18, // 32 x i1
|
||||
v64i1 = 19, // 64 x i1
|
||||
v512i1 = 20, // 512 x i1
|
||||
v1024i1 = 21, // 1024 x i1
|
||||
|
||||
v1i8 = 21, // 1 x i8
|
||||
v2i8 = 22, // 2 x i8
|
||||
v4i8 = 23, // 4 x i8
|
||||
v8i8 = 24, // 8 x i8
|
||||
v16i8 = 25, // 16 x i8
|
||||
v32i8 = 26, // 32 x i8
|
||||
v64i8 = 27, // 64 x i8
|
||||
v128i8 = 28, //128 x i8
|
||||
v256i8 = 29, //256 x i8
|
||||
v1i8 = 22, // 1 x i8
|
||||
v2i8 = 23, // 2 x i8
|
||||
v4i8 = 24, // 4 x i8
|
||||
v8i8 = 25, // 8 x i8
|
||||
v16i8 = 26, // 16 x i8
|
||||
v32i8 = 27, // 32 x i8
|
||||
v64i8 = 28, // 64 x i8
|
||||
v128i8 = 29, //128 x i8
|
||||
v256i8 = 30, //256 x i8
|
||||
|
||||
v1i16 = 30, // 1 x i16
|
||||
v2i16 = 31, // 2 x i16
|
||||
v4i16 = 32, // 4 x i16
|
||||
v8i16 = 33, // 8 x i16
|
||||
v16i16 = 34, // 16 x i16
|
||||
v32i16 = 35, // 32 x i16
|
||||
v64i16 = 36, // 64 x i16
|
||||
v128i16 = 37, //128 x i16
|
||||
v1i16 = 31, // 1 x i16
|
||||
v2i16 = 32, // 2 x i16
|
||||
v4i16 = 33, // 4 x i16
|
||||
v8i16 = 34, // 8 x i16
|
||||
v16i16 = 35, // 16 x i16
|
||||
v32i16 = 36, // 32 x i16
|
||||
v64i16 = 37, // 64 x i16
|
||||
v128i16 = 38, //128 x i16
|
||||
|
||||
v1i32 = 38, // 1 x i32
|
||||
v2i32 = 39, // 2 x i32
|
||||
v4i32 = 40, // 4 x i32
|
||||
v8i32 = 41, // 8 x i32
|
||||
v16i32 = 42, // 16 x i32
|
||||
v32i32 = 43, // 32 x i32
|
||||
v64i32 = 44, // 64 x i32
|
||||
v1i32 = 39, // 1 x i32
|
||||
v2i32 = 40, // 2 x i32
|
||||
v4i32 = 41, // 4 x i32
|
||||
v8i32 = 42, // 8 x i32
|
||||
v16i32 = 43, // 16 x i32
|
||||
v32i32 = 44, // 32 x i32
|
||||
v64i32 = 45, // 64 x i32
|
||||
|
||||
v1i64 = 45, // 1 x i64
|
||||
v2i64 = 46, // 2 x i64
|
||||
v4i64 = 47, // 4 x i64
|
||||
v8i64 = 48, // 8 x i64
|
||||
v16i64 = 49, // 16 x i64
|
||||
v32i64 = 50, // 32 x i64
|
||||
v1i64 = 46, // 1 x i64
|
||||
v2i64 = 47, // 2 x i64
|
||||
v4i64 = 48, // 4 x i64
|
||||
v8i64 = 49, // 8 x i64
|
||||
v16i64 = 50, // 16 x i64
|
||||
v32i64 = 51, // 32 x i64
|
||||
|
||||
v1i128 = 51, // 1 x i128
|
||||
v1i128 = 52, // 1 x i128
|
||||
|
||||
// Scalable integer types
|
||||
nxv2i1 = 53, // n x 2 x i1
|
||||
nxv4i1 = 54, // n x 4 x i1
|
||||
nxv8i1 = 55, // n x 8 x i1
|
||||
nxv16i1 = 56, // n x 16 x i1
|
||||
nxv32i1 = 57, // n x 32 x i1
|
||||
|
||||
nxv1i8 = 58, // n x 1 x i8
|
||||
nxv2i8 = 59, // n x 2 x i8
|
||||
nxv4i8 = 60, // n x 4 x i8
|
||||
nxv8i8 = 61, // n x 8 x i8
|
||||
nxv16i8 = 62, // n x 16 x i8
|
||||
nxv32i8 = 63, // n x 32 x i8
|
||||
|
||||
nxv1i16 = 64, // n x 1 x i16
|
||||
nxv2i16 = 65, // n x 2 x i16
|
||||
nxv4i16 = 66, // n x 4 x i16
|
||||
nxv8i16 = 67, // n x 8 x i16
|
||||
nxv16i16 = 68, // n x 16 x i16
|
||||
nxv32i16 = 69, // n x 32 x i16
|
||||
|
||||
nxv1i32 = 70, // n x 1 x i32
|
||||
nxv2i32 = 71, // n x 2 x i32
|
||||
nxv4i32 = 72, // n x 4 x i32
|
||||
nxv8i32 = 73, // n x 8 x i32
|
||||
nxv16i32 = 74, // n x 16 x i32
|
||||
nxv32i32 = 75, // n x 32 x i32
|
||||
|
||||
nxv1i64 = 76, // n x 1 x i64
|
||||
nxv2i64 = 77, // n x 2 x i64
|
||||
nxv4i64 = 78, // n x 4 x i64
|
||||
nxv8i64 = 79, // n x 8 x i64
|
||||
nxv16i64 = 80, // n x 16 x i64
|
||||
nxv32i64 = 81, // n x 32 x i64
|
||||
|
||||
FIRST_INTEGER_VECTOR_VALUETYPE = v2i1,
|
||||
LAST_INTEGER_VECTOR_VALUETYPE = v1i128,
|
||||
LAST_INTEGER_VECTOR_VALUETYPE = nxv32i64,
|
||||
|
||||
v2f16 = 52, // 2 x f16
|
||||
v4f16 = 53, // 4 x f16
|
||||
v8f16 = 54, // 8 x f16
|
||||
v1f32 = 55, // 1 x f32
|
||||
v2f32 = 56, // 2 x f32
|
||||
v4f32 = 57, // 4 x f32
|
||||
v8f32 = 58, // 8 x f32
|
||||
v16f32 = 59, // 16 x f32
|
||||
v1f64 = 60, // 1 x f64
|
||||
v2f64 = 61, // 2 x f64
|
||||
v4f64 = 62, // 4 x f64
|
||||
v8f64 = 63, // 8 x f64
|
||||
FIRST_INTEGER_SCALABLE_VALUETYPE = nxv2i1,
|
||||
LAST_INTEGER_SCALABLE_VALUETYPE = nxv32i64,
|
||||
|
||||
v2f16 = 82, // 2 x f16
|
||||
v4f16 = 83, // 4 x f16
|
||||
v8f16 = 84, // 8 x f16
|
||||
v1f32 = 85, // 1 x f32
|
||||
v2f32 = 86, // 2 x f32
|
||||
v4f32 = 87, // 4 x f32
|
||||
v8f32 = 88, // 8 x f32
|
||||
v16f32 = 89, // 16 x f32
|
||||
v1f64 = 90, // 1 x f64
|
||||
v2f64 = 91, // 2 x f64
|
||||
v4f64 = 92, // 4 x f64
|
||||
v8f64 = 93, // 8 x f64
|
||||
|
||||
nxv2f16 = 94, // n x 2 x f16
|
||||
nxv4f16 = 95, // n x 4 x f16
|
||||
nxv8f16 = 96, // n x 8 x f16
|
||||
nxv1f32 = 97, // n x 1 x f32
|
||||
nxv2f32 = 98, // n x 2 x f32
|
||||
nxv4f32 = 99, // n x 4 x f32
|
||||
nxv8f32 = 100, // n x 8 x f32
|
||||
nxv16f32 = 101, // n x 16 x f32
|
||||
nxv1f64 = 102, // n x 1 x f64
|
||||
nxv2f64 = 103, // n x 2 x f64
|
||||
nxv4f64 = 104, // n x 4 x f64
|
||||
nxv8f64 = 105, // n x 8 x f64
|
||||
|
||||
FIRST_FP_VECTOR_VALUETYPE = v2f16,
|
||||
LAST_FP_VECTOR_VALUETYPE = v8f64,
|
||||
LAST_FP_VECTOR_VALUETYPE = nxv8f64,
|
||||
|
||||
FIRST_FP_SCALABLE_VALUETYPE = nxv2f16,
|
||||
LAST_FP_SCALABLE_VALUETYPE = nxv8f64,
|
||||
|
||||
FIRST_VECTOR_VALUETYPE = v2i1,
|
||||
LAST_VECTOR_VALUETYPE = v8f64,
|
||||
LAST_VECTOR_VALUETYPE = nxv8f64,
|
||||
|
||||
x86mmx = 64, // This is an X86 MMX value
|
||||
x86mmx = 106, // This is an X86 MMX value
|
||||
|
||||
Glue = 65, // This glues nodes together during pre-RA sched
|
||||
Glue = 107, // This glues nodes together during pre-RA sched
|
||||
|
||||
isVoid = 66, // This has no value
|
||||
isVoid = 108, // This has no value
|
||||
|
||||
Untyped = 67, // This value takes a register, but has
|
||||
// unspecified type. The register class
|
||||
// will be determined by the opcode.
|
||||
Untyped = 109, // This value takes a register, but has
|
||||
// unspecified type. The register class
|
||||
// will be determined by the opcode.
|
||||
|
||||
FIRST_VALUETYPE = 0, // This is always the beginning of the list.
|
||||
LAST_VALUETYPE = 68, // This always remains at the end of the list.
|
||||
FIRST_VALUETYPE = 1, // This is always the beginning of the list.
|
||||
LAST_VALUETYPE = 110, // This always remains at the end of the list.
|
||||
|
||||
// This is the current maximum for LAST_VALUETYPE.
|
||||
// MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors
|
||||
// This value must be a multiple of 32.
|
||||
MAX_ALLOWED_VALUETYPE = 96,
|
||||
MAX_ALLOWED_VALUETYPE = 128,
|
||||
|
||||
// A value of type llvm::TokenTy
|
||||
token = 120,
|
||||
token = 248,
|
||||
|
||||
// This is MDNode or MDString.
|
||||
Metadata = 121,
|
||||
Metadata = 249,
|
||||
|
||||
// An int value the size of the pointer of the current
|
||||
// target to any address space. This must only be used internal to
|
||||
// tblgen. Other than for overloading, we treat iPTRAny the same as iPTR.
|
||||
iPTRAny = 122,
|
||||
iPTRAny = 250,
|
||||
|
||||
// A vector with any length and element size. This is used
|
||||
// for intrinsics that have overloadings based on vector types.
|
||||
// This is only for tblgen's consumption!
|
||||
vAny = 123,
|
||||
vAny = 251,
|
||||
|
||||
// Any floating-point or vector floating-point value. This is used
|
||||
// for intrinsics that have overloadings based on floating-point types.
|
||||
// This is only for tblgen's consumption!
|
||||
fAny = 124,
|
||||
fAny = 252,
|
||||
|
||||
// An integer or vector integer value of any bit width. This is
|
||||
// used for intrinsics that have overloadings based on integer bit widths.
|
||||
// This is only for tblgen's consumption!
|
||||
iAny = 125,
|
||||
iAny = 253,
|
||||
|
||||
// An int value the size of the pointer of the current
|
||||
// target. This should only be used internal to tblgen!
|
||||
iPTR = 126,
|
||||
iPTR = 254,
|
||||
|
||||
// Any type. This is used for intrinsics that have overloadings.
|
||||
// This is only for tblgen's consumption!
|
||||
Any = 127
|
||||
Any = 255
|
||||
};
|
||||
|
||||
SimpleValueType SimpleTy;
|
||||
|
||||
|
||||
// A class to represent the number of elements in a vector
|
||||
//
|
||||
// For fixed-length vectors, the total number of elements is equal to 'Min'
|
||||
// For scalable vectors, the total number of elements is a multiple of 'Min'
|
||||
class ElementCount {
|
||||
public:
|
||||
unsigned Min;
|
||||
bool Scalable;
|
||||
|
||||
ElementCount(unsigned Min, bool Scalable)
|
||||
: Min(Min), Scalable(Scalable) {}
|
||||
|
||||
ElementCount operator*(unsigned RHS) {
|
||||
return { Min * RHS, Scalable };
|
||||
}
|
||||
|
||||
ElementCount& operator*=(unsigned RHS) {
|
||||
Min *= RHS;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ElementCount operator/(unsigned RHS) {
|
||||
return { Min / RHS, Scalable };
|
||||
}
|
||||
|
||||
ElementCount& operator/=(unsigned RHS) {
|
||||
Min /= RHS;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const ElementCount& RHS) {
|
||||
return Min == RHS.Min && Scalable == RHS.Scalable;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr MVT() : SimpleTy(INVALID_SIMPLE_VALUE_TYPE) {}
|
||||
constexpr MVT(SimpleValueType SVT) : SimpleTy(SVT) {}
|
||||
|
||||
@ -221,6 +312,15 @@ class MVT {
|
||||
SimpleTy <= MVT::LAST_VECTOR_VALUETYPE);
|
||||
}
|
||||
|
||||
/// Return true if this is a vector value type where the
|
||||
/// runtime length is machine dependent
|
||||
bool isScalableVector() const {
|
||||
return ((SimpleTy >= MVT::FIRST_INTEGER_SCALABLE_VALUETYPE &&
|
||||
SimpleTy <= MVT::LAST_INTEGER_SCALABLE_VALUETYPE) ||
|
||||
(SimpleTy >= MVT::FIRST_FP_SCALABLE_VALUETYPE &&
|
||||
SimpleTy <= MVT::LAST_FP_SCALABLE_VALUETYPE));
|
||||
}
|
||||
|
||||
/// Return true if this is a 16-bit vector type.
|
||||
bool is16BitVector() const {
|
||||
return (SimpleTy == MVT::v2i8 || SimpleTy == MVT::v1i16 ||
|
||||
@ -318,7 +418,12 @@ class MVT {
|
||||
case v32i1:
|
||||
case v64i1:
|
||||
case v512i1:
|
||||
case v1024i1: return i1;
|
||||
case v1024i1:
|
||||
case nxv2i1:
|
||||
case nxv4i1:
|
||||
case nxv8i1:
|
||||
case nxv16i1:
|
||||
case nxv32i1: return i1;
|
||||
case v1i8:
|
||||
case v2i8:
|
||||
case v4i8:
|
||||
@ -327,7 +432,13 @@ class MVT {
|
||||
case v32i8:
|
||||
case v64i8:
|
||||
case v128i8:
|
||||
case v256i8: return i8;
|
||||
case v256i8:
|
||||
case nxv1i8:
|
||||
case nxv2i8:
|
||||
case nxv4i8:
|
||||
case nxv8i8:
|
||||
case nxv16i8:
|
||||
case nxv32i8: return i8;
|
||||
case v1i16:
|
||||
case v2i16:
|
||||
case v4i16:
|
||||
@ -335,33 +446,63 @@ class MVT {
|
||||
case v16i16:
|
||||
case v32i16:
|
||||
case v64i16:
|
||||
case v128i16: return i16;
|
||||
case v128i16:
|
||||
case nxv1i16:
|
||||
case nxv2i16:
|
||||
case nxv4i16:
|
||||
case nxv8i16:
|
||||
case nxv16i16:
|
||||
case nxv32i16: return i16;
|
||||
case v1i32:
|
||||
case v2i32:
|
||||
case v4i32:
|
||||
case v8i32:
|
||||
case v16i32:
|
||||
case v32i32:
|
||||
case v64i32: return i32;
|
||||
case v64i32:
|
||||
case nxv1i32:
|
||||
case nxv2i32:
|
||||
case nxv4i32:
|
||||
case nxv8i32:
|
||||
case nxv16i32:
|
||||
case nxv32i32: return i32;
|
||||
case v1i64:
|
||||
case v2i64:
|
||||
case v4i64:
|
||||
case v8i64:
|
||||
case v16i64:
|
||||
case v32i64: return i64;
|
||||
case v32i64:
|
||||
case nxv1i64:
|
||||
case nxv2i64:
|
||||
case nxv4i64:
|
||||
case nxv8i64:
|
||||
case nxv16i64:
|
||||
case nxv32i64: return i64;
|
||||
case v1i128: return i128;
|
||||
case v2f16:
|
||||
case v4f16:
|
||||
case v8f16: return f16;
|
||||
case v8f16:
|
||||
case nxv2f16:
|
||||
case nxv4f16:
|
||||
case nxv8f16: return f16;
|
||||
case v1f32:
|
||||
case v2f32:
|
||||
case v4f32:
|
||||
case v8f32:
|
||||
case v16f32: return f32;
|
||||
case v16f32:
|
||||
case nxv1f32:
|
||||
case nxv2f32:
|
||||
case nxv4f32:
|
||||
case nxv8f32:
|
||||
case nxv16f32: return f32;
|
||||
case v1f64:
|
||||
case v2f64:
|
||||
case v4f64:
|
||||
case v8f64: return f64;
|
||||
case v8f64:
|
||||
case nxv1f64:
|
||||
case nxv2f64:
|
||||
case nxv4f64:
|
||||
case nxv8f64: return f64;
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,13 +523,24 @@ class MVT {
|
||||
case v32i8:
|
||||
case v32i16:
|
||||
case v32i32:
|
||||
case v32i64: return 32;
|
||||
case v32i64:
|
||||
case nxv32i1:
|
||||
case nxv32i8:
|
||||
case nxv32i16:
|
||||
case nxv32i32:
|
||||
case nxv32i64: return 32;
|
||||
case v16i1:
|
||||
case v16i8:
|
||||
case v16i16:
|
||||
case v16i32:
|
||||
case v16i64:
|
||||
case v16f32: return 16;
|
||||
case v16f32:
|
||||
case nxv16i1:
|
||||
case nxv16i8:
|
||||
case nxv16i16:
|
||||
case nxv16i32:
|
||||
case nxv16i64:
|
||||
case nxv16f32: return 16;
|
||||
case v8i1:
|
||||
case v8i8:
|
||||
case v8i16:
|
||||
@ -396,7 +548,15 @@ class MVT {
|
||||
case v8i64:
|
||||
case v8f16:
|
||||
case v8f32:
|
||||
case v8f64: return 8;
|
||||
case v8f64:
|
||||
case nxv8i1:
|
||||
case nxv8i8:
|
||||
case nxv8i16:
|
||||
case nxv8i32:
|
||||
case nxv8i64:
|
||||
case nxv8f16:
|
||||
case nxv8f32:
|
||||
case nxv8f64: return 8;
|
||||
case v4i1:
|
||||
case v4i8:
|
||||
case v4i16:
|
||||
@ -404,7 +564,15 @@ class MVT {
|
||||
case v4i64:
|
||||
case v4f16:
|
||||
case v4f32:
|
||||
case v4f64: return 4;
|
||||
case v4f64:
|
||||
case nxv4i1:
|
||||
case nxv4i8:
|
||||
case nxv4i16:
|
||||
case nxv4i32:
|
||||
case nxv4i64:
|
||||
case nxv4f16:
|
||||
case nxv4f32:
|
||||
case nxv4f64: return 4;
|
||||
case v2i1:
|
||||
case v2i8:
|
||||
case v2i16:
|
||||
@ -412,17 +580,35 @@ class MVT {
|
||||
case v2i64:
|
||||
case v2f16:
|
||||
case v2f32:
|
||||
case v2f64: return 2;
|
||||
case v2f64:
|
||||
case nxv2i1:
|
||||
case nxv2i8:
|
||||
case nxv2i16:
|
||||
case nxv2i32:
|
||||
case nxv2i64:
|
||||
case nxv2f16:
|
||||
case nxv2f32:
|
||||
case nxv2f64: return 2;
|
||||
case v1i8:
|
||||
case v1i16:
|
||||
case v1i32:
|
||||
case v1i64:
|
||||
case v1i128:
|
||||
case v1f32:
|
||||
case v1f64: return 1;
|
||||
case v1f64:
|
||||
case nxv1i8:
|
||||
case nxv1i16:
|
||||
case nxv1i32:
|
||||
case nxv1i64:
|
||||
case nxv1f32:
|
||||
case nxv1f64: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
MVT::ElementCount getVectorElementCount() const {
|
||||
return { getVectorNumElements(), isScalableVector() };
|
||||
}
|
||||
|
||||
unsigned getSizeInBits() const {
|
||||
switch (SimpleTy) {
|
||||
default:
|
||||
@ -443,16 +629,23 @@ class MVT {
|
||||
case Metadata:
|
||||
llvm_unreachable("Value type is metadata.");
|
||||
case i1 : return 1;
|
||||
case v2i1: return 2;
|
||||
case v4i1: return 4;
|
||||
case v2i1:
|
||||
case nxv2i1: return 2;
|
||||
case v4i1:
|
||||
case nxv4i1: return 4;
|
||||
case i8 :
|
||||
case v1i8:
|
||||
case v8i1: return 8;
|
||||
case v8i1:
|
||||
case nxv1i8:
|
||||
case nxv8i1: return 8;
|
||||
case i16 :
|
||||
case f16:
|
||||
case v16i1:
|
||||
case v2i8:
|
||||
case v1i16: return 16;
|
||||
case v1i16:
|
||||
case nxv16i1:
|
||||
case nxv2i8:
|
||||
case nxv1i16: return 16;
|
||||
case f32 :
|
||||
case i32 :
|
||||
case v32i1:
|
||||
@ -460,7 +653,13 @@ class MVT {
|
||||
case v2i16:
|
||||
case v2f16:
|
||||
case v1f32:
|
||||
case v1i32: return 32;
|
||||
case v1i32:
|
||||
case nxv32i1:
|
||||
case nxv4i8:
|
||||
case nxv2i16:
|
||||
case nxv1i32:
|
||||
case nxv2f16:
|
||||
case nxv1f32: return 32;
|
||||
case x86mmx:
|
||||
case f64 :
|
||||
case i64 :
|
||||
@ -471,7 +670,14 @@ class MVT {
|
||||
case v1i64:
|
||||
case v4f16:
|
||||
case v2f32:
|
||||
case v1f64: return 64;
|
||||
case v1f64:
|
||||
case nxv8i8:
|
||||
case nxv4i16:
|
||||
case nxv2i32:
|
||||
case nxv1i64:
|
||||
case nxv4f16:
|
||||
case nxv2f32:
|
||||
case nxv1f64: return 64;
|
||||
case f80 : return 80;
|
||||
case f128:
|
||||
case ppcf128:
|
||||
@ -483,29 +689,50 @@ class MVT {
|
||||
case v1i128:
|
||||
case v8f16:
|
||||
case v4f32:
|
||||
case v2f64: return 128;
|
||||
case v2f64:
|
||||
case nxv16i8:
|
||||
case nxv8i16:
|
||||
case nxv4i32:
|
||||
case nxv2i64:
|
||||
case nxv8f16:
|
||||
case nxv4f32:
|
||||
case nxv2f64: return 128;
|
||||
case v32i8:
|
||||
case v16i16:
|
||||
case v8i32:
|
||||
case v4i64:
|
||||
case v8f32:
|
||||
case v4f64: return 256;
|
||||
case v4f64:
|
||||
case nxv32i8:
|
||||
case nxv16i16:
|
||||
case nxv8i32:
|
||||
case nxv4i64:
|
||||
case nxv8f32:
|
||||
case nxv4f64: return 256;
|
||||
case v512i1:
|
||||
case v64i8:
|
||||
case v32i16:
|
||||
case v16i32:
|
||||
case v8i64:
|
||||
case v16f32:
|
||||
case v8f64: return 512;
|
||||
case v8f64:
|
||||
case nxv32i16:
|
||||
case nxv16i32:
|
||||
case nxv8i64:
|
||||
case nxv16f32:
|
||||
case nxv8f64: return 512;
|
||||
case v1024i1:
|
||||
case v128i8:
|
||||
case v64i16:
|
||||
case v32i32:
|
||||
case v16i64: return 1024;
|
||||
case v16i64:
|
||||
case nxv32i32:
|
||||
case nxv16i64: return 1024;
|
||||
case v256i8:
|
||||
case v128i16:
|
||||
case v64i32:
|
||||
case v32i64: return 2048;
|
||||
case v32i64:
|
||||
case nxv32i64: return 2048;
|
||||
}
|
||||
}
|
||||
|
||||
@ -659,6 +886,83 @@ class MVT {
|
||||
return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
|
||||
}
|
||||
|
||||
static MVT getScalableVectorVT(MVT VT, unsigned NumElements) {
|
||||
switch(VT.SimpleTy) {
|
||||
default:
|
||||
break;
|
||||
case MVT::i1:
|
||||
if (NumElements == 2) return MVT::nxv2i1;
|
||||
if (NumElements == 4) return MVT::nxv4i1;
|
||||
if (NumElements == 8) return MVT::nxv8i1;
|
||||
if (NumElements == 16) return MVT::nxv16i1;
|
||||
if (NumElements == 32) return MVT::nxv32i1;
|
||||
break;
|
||||
case MVT::i8:
|
||||
if (NumElements == 1) return MVT::nxv1i8;
|
||||
if (NumElements == 2) return MVT::nxv2i8;
|
||||
if (NumElements == 4) return MVT::nxv4i8;
|
||||
if (NumElements == 8) return MVT::nxv8i8;
|
||||
if (NumElements == 16) return MVT::nxv16i8;
|
||||
if (NumElements == 32) return MVT::nxv32i8;
|
||||
break;
|
||||
case MVT::i16:
|
||||
if (NumElements == 1) return MVT::nxv1i16;
|
||||
if (NumElements == 2) return MVT::nxv2i16;
|
||||
if (NumElements == 4) return MVT::nxv4i16;
|
||||
if (NumElements == 8) return MVT::nxv8i16;
|
||||
if (NumElements == 16) return MVT::nxv16i16;
|
||||
if (NumElements == 32) return MVT::nxv32i16;
|
||||
break;
|
||||
case MVT::i32:
|
||||
if (NumElements == 1) return MVT::nxv1i32;
|
||||
if (NumElements == 2) return MVT::nxv2i32;
|
||||
if (NumElements == 4) return MVT::nxv4i32;
|
||||
if (NumElements == 8) return MVT::nxv8i32;
|
||||
if (NumElements == 16) return MVT::nxv16i32;
|
||||
if (NumElements == 32) return MVT::nxv32i32;
|
||||
break;
|
||||
case MVT::i64:
|
||||
if (NumElements == 1) return MVT::nxv1i64;
|
||||
if (NumElements == 2) return MVT::nxv2i64;
|
||||
if (NumElements == 4) return MVT::nxv4i64;
|
||||
if (NumElements == 8) return MVT::nxv8i64;
|
||||
if (NumElements == 16) return MVT::nxv16i64;
|
||||
if (NumElements == 32) return MVT::nxv32i64;
|
||||
break;
|
||||
case MVT::f16:
|
||||
if (NumElements == 2) return MVT::nxv2f16;
|
||||
if (NumElements == 4) return MVT::nxv4f16;
|
||||
if (NumElements == 8) return MVT::nxv8f16;
|
||||
break;
|
||||
case MVT::f32:
|
||||
if (NumElements == 1) return MVT::nxv1f32;
|
||||
if (NumElements == 2) return MVT::nxv2f32;
|
||||
if (NumElements == 4) return MVT::nxv4f32;
|
||||
if (NumElements == 8) return MVT::nxv8f32;
|
||||
if (NumElements == 16) return MVT::nxv16f32;
|
||||
break;
|
||||
case MVT::f64:
|
||||
if (NumElements == 1) return MVT::nxv1f64;
|
||||
if (NumElements == 2) return MVT::nxv2f64;
|
||||
if (NumElements == 4) return MVT::nxv4f64;
|
||||
if (NumElements == 8) return MVT::nxv8f64;
|
||||
break;
|
||||
}
|
||||
return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
|
||||
}
|
||||
|
||||
static MVT getVectorVT(MVT VT, unsigned NumElements, bool IsScalable) {
|
||||
if (IsScalable)
|
||||
return getScalableVectorVT(VT, NumElements);
|
||||
return getVectorVT(VT, NumElements);
|
||||
}
|
||||
|
||||
static MVT getVectorVT(MVT VT, MVT::ElementCount EC) {
|
||||
if (EC.Scalable)
|
||||
return getScalableVectorVT(VT, EC.Min);
|
||||
return getVectorVT(VT, EC.Min);
|
||||
}
|
||||
|
||||
/// Return the value type corresponding to the specified type. This returns
|
||||
/// all pointers as iPTR. If HandleUnknown is true, unknown types are
|
||||
/// returned as Other, otherwise they are invalid.
|
||||
@ -709,6 +1013,14 @@ class MVT {
|
||||
MVT::FIRST_FP_VECTOR_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_FP_VECTOR_VALUETYPE + 1));
|
||||
}
|
||||
static mvt_range integer_scalable_vector_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_INTEGER_SCALABLE_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_INTEGER_SCALABLE_VALUETYPE + 1));
|
||||
}
|
||||
static mvt_range fp_scalable_vector_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_FP_SCALABLE_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_FP_SCALABLE_VALUETYPE + 1));
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ namespace llvm {
|
||||
bool operator!=(EVT VT) const {
|
||||
if (V.SimpleTy != VT.V.SimpleTy)
|
||||
return true;
|
||||
if (V.SimpleTy < 0)
|
||||
if (V.SimpleTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
|
||||
return LLVMTy != VT.LLVMTy;
|
||||
return false;
|
||||
}
|
||||
@ -60,31 +60,48 @@ namespace llvm {
|
||||
/// bits.
|
||||
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth) {
|
||||
MVT M = MVT::getIntegerVT(BitWidth);
|
||||
if (M.SimpleTy >= 0)
|
||||
if (M.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE)
|
||||
return M;
|
||||
return getExtendedIntegerVT(Context, BitWidth);
|
||||
}
|
||||
|
||||
/// Returns the EVT that represents a vector NumElements in length, where
|
||||
/// each element is of type VT.
|
||||
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements) {
|
||||
MVT M = MVT::getVectorVT(VT.V, NumElements);
|
||||
if (M.SimpleTy >= 0)
|
||||
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements,
|
||||
bool IsScalable = false) {
|
||||
MVT M = MVT::getVectorVT(VT.V, NumElements, IsScalable);
|
||||
if (M.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE)
|
||||
return M;
|
||||
|
||||
assert(!IsScalable && "We don't support extended scalable types yet");
|
||||
return getExtendedVectorVT(Context, VT, NumElements);
|
||||
}
|
||||
|
||||
/// Returns the EVT that represents a vector EC.Min elements in length,
|
||||
/// where each element is of type VT.
|
||||
static EVT getVectorVT(LLVMContext &Context, EVT VT, MVT::ElementCount EC) {
|
||||
MVT M = MVT::getVectorVT(VT.V, EC);
|
||||
if (M.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE)
|
||||
return M;
|
||||
assert (!EC.Scalable && "We don't support extended scalable types yet");
|
||||
return getExtendedVectorVT(Context, VT, EC.Min);
|
||||
}
|
||||
|
||||
/// Return a vector with the same number of elements as this vector, but
|
||||
/// with the element type converted to an integer type with the same
|
||||
/// bitwidth.
|
||||
EVT changeVectorElementTypeToInteger() const {
|
||||
if (!isSimple())
|
||||
if (!isSimple()) {
|
||||
assert (!isScalableVector() &&
|
||||
"We don't support extended scalable types yet");
|
||||
return changeExtendedVectorElementTypeToInteger();
|
||||
}
|
||||
MVT EltTy = getSimpleVT().getVectorElementType();
|
||||
unsigned BitWidth = EltTy.getSizeInBits();
|
||||
MVT IntTy = MVT::getIntegerVT(BitWidth);
|
||||
MVT VecTy = MVT::getVectorVT(IntTy, getVectorNumElements());
|
||||
assert(VecTy.SimpleTy >= 0 &&
|
||||
MVT VecTy = MVT::getVectorVT(IntTy, getVectorNumElements(),
|
||||
isScalableVector());
|
||||
assert(VecTy.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE &&
|
||||
"Simple vector VT not representable by simple integer vector VT!");
|
||||
return VecTy;
|
||||
}
|
||||
@ -104,7 +121,7 @@ namespace llvm {
|
||||
|
||||
/// Test if the given EVT is simple (as opposed to being extended).
|
||||
bool isSimple() const {
|
||||
return V.SimpleTy >= 0;
|
||||
return V.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE;
|
||||
}
|
||||
|
||||
/// Test if the given EVT is extended (as opposed to being simple).
|
||||
@ -132,6 +149,17 @@ namespace llvm {
|
||||
return isSimple() ? V.isVector() : isExtendedVector();
|
||||
}
|
||||
|
||||
/// Return true if this is a vector type where the runtime
|
||||
/// length is machine dependent
|
||||
bool isScalableVector() const {
|
||||
// FIXME: We don't support extended scalable types yet, because the
|
||||
// matching IR type doesn't exist. Once it has been added, this can
|
||||
// be changed to call isExtendedScalableVector.
|
||||
if (!isSimple())
|
||||
return false;
|
||||
return V.isScalableVector();
|
||||
}
|
||||
|
||||
/// Return true if this is a 16-bit vector type.
|
||||
bool is16BitVector() const {
|
||||
return isSimple() ? V.is16BitVector() : isExtended16BitVector();
|
||||
@ -247,6 +275,17 @@ namespace llvm {
|
||||
return getExtendedVectorNumElements();
|
||||
}
|
||||
|
||||
// Given a (possibly scalable) vector type, return the ElementCount
|
||||
MVT::ElementCount getVectorElementCount() const {
|
||||
assert((isVector()) && "Invalid vector type!");
|
||||
if (isSimple())
|
||||
return V.getVectorElementCount();
|
||||
|
||||
assert(!isScalableVector() &&
|
||||
"We don't support extended scalable types yet");
|
||||
return {getExtendedVectorNumElements(), false};
|
||||
}
|
||||
|
||||
/// Return the size of the specified value type in bits.
|
||||
unsigned getSizeInBits() const {
|
||||
if (isSimple())
|
||||
@ -301,7 +340,17 @@ namespace llvm {
|
||||
EVT widenIntegerVectorElementType(LLVMContext &Context) const {
|
||||
EVT EltVT = getVectorElementType();
|
||||
EltVT = EVT::getIntegerVT(Context, 2 * EltVT.getSizeInBits());
|
||||
return EVT::getVectorVT(Context, EltVT, getVectorNumElements());
|
||||
return EVT::getVectorVT(Context, EltVT, getVectorElementCount());
|
||||
}
|
||||
|
||||
// Return a VT for a vector type with the same element type but
|
||||
// half the number of elements. The type returned may be an
|
||||
// extended type.
|
||||
EVT getHalfNumVectorElementsVT(LLVMContext &Context) const {
|
||||
EVT EltVT = getVectorElementType();
|
||||
auto EltCnt = getVectorElementCount();
|
||||
assert(!(EltCnt.Min & 1) && "Splitting vector, but not in half!");
|
||||
return EVT::getVectorVT(Context, EltVT, EltCnt / 2);
|
||||
}
|
||||
|
||||
/// Returns true if the given vector is a power of 2.
|
||||
@ -316,7 +365,8 @@ namespace llvm {
|
||||
if (!isPow2VectorType()) {
|
||||
unsigned NElts = getVectorNumElements();
|
||||
unsigned Pow2NElts = 1 << Log2_32_Ceil(NElts);
|
||||
return EVT::getVectorVT(Context, getVectorElementType(), Pow2NElts);
|
||||
return EVT::getVectorVT(Context, getVectorElementType(), Pow2NElts,
|
||||
isScalableVector());
|
||||
}
|
||||
else {
|
||||
return *this;
|
||||
|
@ -19,101 +19,147 @@ class ValueType<int size, int value> {
|
||||
int Value = value;
|
||||
}
|
||||
|
||||
def OtherVT: ValueType<0 , 0>; // "Other" value
|
||||
def i1 : ValueType<1 , 1>; // One bit boolean value
|
||||
def i8 : ValueType<8 , 2>; // 8-bit integer value
|
||||
def i16 : ValueType<16 , 3>; // 16-bit integer value
|
||||
def i32 : ValueType<32 , 4>; // 32-bit integer value
|
||||
def i64 : ValueType<64 , 5>; // 64-bit integer value
|
||||
def i128 : ValueType<128, 6>; // 128-bit integer value
|
||||
def f16 : ValueType<16 , 7>; // 16-bit floating point value
|
||||
def f32 : ValueType<32 , 8>; // 32-bit floating point value
|
||||
def f64 : ValueType<64 , 9>; // 64-bit floating point value
|
||||
def f80 : ValueType<80 , 10>; // 80-bit floating point value
|
||||
def f128 : ValueType<128, 11>; // 128-bit floating point value
|
||||
def ppcf128: ValueType<128, 12>; // PPC 128-bit floating point value
|
||||
def OtherVT: ValueType<0 , 1>; // "Other" value
|
||||
def i1 : ValueType<1 , 2>; // One bit boolean value
|
||||
def i8 : ValueType<8 , 3>; // 8-bit integer value
|
||||
def i16 : ValueType<16 , 4>; // 16-bit integer value
|
||||
def i32 : ValueType<32 , 5>; // 32-bit integer value
|
||||
def i64 : ValueType<64 , 6>; // 64-bit integer value
|
||||
def i128 : ValueType<128, 7>; // 128-bit integer value
|
||||
def f16 : ValueType<16 , 8>; // 16-bit floating point value
|
||||
def f32 : ValueType<32 , 9>; // 32-bit floating point value
|
||||
def f64 : ValueType<64 , 10>; // 64-bit floating point value
|
||||
def f80 : ValueType<80 , 11>; // 80-bit floating point value
|
||||
def f128 : ValueType<128, 12>; // 128-bit floating point value
|
||||
def ppcf128: ValueType<128, 13>; // PPC 128-bit floating point value
|
||||
|
||||
def v2i1 : ValueType<2 , 13>; // 2 x i1 vector value
|
||||
def v4i1 : ValueType<4 , 14>; // 4 x i1 vector value
|
||||
def v8i1 : ValueType<8 , 15>; // 8 x i1 vector value
|
||||
def v16i1 : ValueType<16, 16>; // 16 x i1 vector value
|
||||
def v32i1 : ValueType<32 , 17>; // 32 x i1 vector value
|
||||
def v64i1 : ValueType<64 , 18>; // 64 x i1 vector value
|
||||
def v512i1 : ValueType<512, 19>; // 512 x i1 vector value
|
||||
def v1024i1: ValueType<1024,20>; //1024 x i1 vector value
|
||||
def v2i1 : ValueType<2 , 14>; // 2 x i1 vector value
|
||||
def v4i1 : ValueType<4 , 15>; // 4 x i1 vector value
|
||||
def v8i1 : ValueType<8 , 16>; // 8 x i1 vector value
|
||||
def v16i1 : ValueType<16, 17>; // 16 x i1 vector value
|
||||
def v32i1 : ValueType<32 , 18>; // 32 x i1 vector value
|
||||
def v64i1 : ValueType<64 , 19>; // 64 x i1 vector value
|
||||
def v512i1 : ValueType<512, 20>; // 512 x i1 vector value
|
||||
def v1024i1: ValueType<1024,21>; //1024 x i1 vector value
|
||||
|
||||
def v1i8 : ValueType<16, 21>; // 1 x i8 vector value
|
||||
def v2i8 : ValueType<16 , 22>; // 2 x i8 vector value
|
||||
def v4i8 : ValueType<32 , 23>; // 4 x i8 vector value
|
||||
def v8i8 : ValueType<64 , 24>; // 8 x i8 vector value
|
||||
def v16i8 : ValueType<128, 25>; // 16 x i8 vector value
|
||||
def v32i8 : ValueType<256, 26>; // 32 x i8 vector value
|
||||
def v64i8 : ValueType<512, 27>; // 64 x i8 vector value
|
||||
def v128i8 : ValueType<1024,28>; //128 x i8 vector value
|
||||
def v256i8 : ValueType<2048,29>; //256 x i8 vector value
|
||||
def v1i8 : ValueType<16, 22>; // 1 x i8 vector value
|
||||
def v2i8 : ValueType<16 , 23>; // 2 x i8 vector value
|
||||
def v4i8 : ValueType<32 , 24>; // 4 x i8 vector value
|
||||
def v8i8 : ValueType<64 , 25>; // 8 x i8 vector value
|
||||
def v16i8 : ValueType<128, 26>; // 16 x i8 vector value
|
||||
def v32i8 : ValueType<256, 27>; // 32 x i8 vector value
|
||||
def v64i8 : ValueType<512, 28>; // 64 x i8 vector value
|
||||
def v128i8 : ValueType<1024,29>; //128 x i8 vector value
|
||||
def v256i8 : ValueType<2048,30>; //256 x i8 vector value
|
||||
|
||||
def v1i16 : ValueType<16 , 30>; // 1 x i16 vector value
|
||||
def v2i16 : ValueType<32 , 31>; // 2 x i16 vector value
|
||||
def v4i16 : ValueType<64 , 32>; // 4 x i16 vector value
|
||||
def v8i16 : ValueType<128, 33>; // 8 x i16 vector value
|
||||
def v16i16 : ValueType<256, 34>; // 16 x i16 vector value
|
||||
def v32i16 : ValueType<512, 35>; // 32 x i16 vector value
|
||||
def v64i16 : ValueType<1024,36>; // 64 x i16 vector value
|
||||
def v128i16: ValueType<2048,37>; //128 x i16 vector value
|
||||
def v1i16 : ValueType<16 , 31>; // 1 x i16 vector value
|
||||
def v2i16 : ValueType<32 , 32>; // 2 x i16 vector value
|
||||
def v4i16 : ValueType<64 , 33>; // 4 x i16 vector value
|
||||
def v8i16 : ValueType<128, 34>; // 8 x i16 vector value
|
||||
def v16i16 : ValueType<256, 35>; // 16 x i16 vector value
|
||||
def v32i16 : ValueType<512, 36>; // 32 x i16 vector value
|
||||
def v64i16 : ValueType<1024,37>; // 64 x i16 vector value
|
||||
def v128i16: ValueType<2048,38>; //128 x i16 vector value
|
||||
|
||||
def v1i32 : ValueType<32 , 38>; // 1 x i32 vector value
|
||||
def v2i32 : ValueType<64 , 39>; // 2 x i32 vector value
|
||||
def v4i32 : ValueType<128, 40>; // 4 x i32 vector value
|
||||
def v8i32 : ValueType<256, 41>; // 8 x i32 vector value
|
||||
def v16i32 : ValueType<512, 42>; // 16 x i32 vector value
|
||||
def v32i32 : ValueType<1024,43>; // 32 x i32 vector value
|
||||
def v64i32 : ValueType<2048,44>; // 32 x i32 vector value
|
||||
def v1i32 : ValueType<32 , 39>; // 1 x i32 vector value
|
||||
def v2i32 : ValueType<64 , 40>; // 2 x i32 vector value
|
||||
def v4i32 : ValueType<128, 41>; // 4 x i32 vector value
|
||||
def v8i32 : ValueType<256, 42>; // 8 x i32 vector value
|
||||
def v16i32 : ValueType<512, 43>; // 16 x i32 vector value
|
||||
def v32i32 : ValueType<1024,44>; // 32 x i32 vector value
|
||||
def v64i32 : ValueType<2048,45>; // 32 x i32 vector value
|
||||
|
||||
def v1i64 : ValueType<64 , 45>; // 1 x i64 vector value
|
||||
def v2i64 : ValueType<128, 46>; // 2 x i64 vector value
|
||||
def v4i64 : ValueType<256, 47>; // 4 x i64 vector value
|
||||
def v8i64 : ValueType<512, 48>; // 8 x i64 vector value
|
||||
def v16i64 : ValueType<1024,49>; // 16 x i64 vector value
|
||||
def v32i64 : ValueType<2048,50>; // 32 x i64 vector value
|
||||
def v1i64 : ValueType<64 , 46>; // 1 x i64 vector value
|
||||
def v2i64 : ValueType<128, 47>; // 2 x i64 vector value
|
||||
def v4i64 : ValueType<256, 48>; // 4 x i64 vector value
|
||||
def v8i64 : ValueType<512, 49>; // 8 x i64 vector value
|
||||
def v16i64 : ValueType<1024,50>; // 16 x i64 vector value
|
||||
def v32i64 : ValueType<2048,51>; // 32 x i64 vector value
|
||||
|
||||
def v1i128 : ValueType<128, 51>; // 1 x i128 vector value
|
||||
def v1i128 : ValueType<128, 52>; // 1 x i128 vector value
|
||||
|
||||
def v2f16 : ValueType<32 , 52>; // 2 x f16 vector value
|
||||
def v4f16 : ValueType<64 , 53>; // 4 x f16 vector value
|
||||
def v8f16 : ValueType<128, 54>; // 8 x f16 vector value
|
||||
def v1f32 : ValueType<32 , 55>; // 1 x f32 vector value
|
||||
def v2f32 : ValueType<64 , 56>; // 2 x f32 vector value
|
||||
def v4f32 : ValueType<128, 57>; // 4 x f32 vector value
|
||||
def v8f32 : ValueType<256, 58>; // 8 x f32 vector value
|
||||
def v16f32 : ValueType<512, 59>; // 16 x f32 vector value
|
||||
def v1f64 : ValueType<64, 60>; // 1 x f64 vector value
|
||||
def v2f64 : ValueType<128, 61>; // 2 x f64 vector value
|
||||
def v4f64 : ValueType<256, 62>; // 4 x f64 vector value
|
||||
def v8f64 : ValueType<512, 63>; // 8 x f64 vector value
|
||||
def nxv2i1 : ValueType<2, 53>; // n x 2 x i1 vector value
|
||||
def nxv4i1 : ValueType<4, 54>; // n x 4 x i1 vector value
|
||||
def nxv8i1 : ValueType<8, 55>; // n x 8 x i1 vector value
|
||||
def nxv16i1 : ValueType<16, 56>; // n x 16 x i1 vector value
|
||||
def nxv32i1 : ValueType<32, 57>; // n x 32 x i1 vector value
|
||||
|
||||
def nxv1i8 : ValueType<8, 58>; // n x 1 x i8 vector value
|
||||
def nxv2i8 : ValueType<16, 59>; // n x 2 x i8 vector value
|
||||
def nxv4i8 : ValueType<32, 60>; // n x 4 x i8 vector value
|
||||
def nxv8i8 : ValueType<64, 61>; // n x 8 x i8 vector value
|
||||
def nxv16i8 : ValueType<128, 62>; // n x 16 x i8 vector value
|
||||
def nxv32i8 : ValueType<256, 63>; // n x 32 x i8 vector value
|
||||
|
||||
def x86mmx : ValueType<64 , 64>; // X86 MMX value
|
||||
def FlagVT : ValueType<0 , 65>; // Pre-RA sched glue
|
||||
def isVoid : ValueType<0 , 66>; // Produces no value
|
||||
def untyped: ValueType<8 , 67>; // Produces an untyped value
|
||||
def token : ValueType<0 , 120>; // TokenTy
|
||||
def MetadataVT: ValueType<0, 121>; // Metadata
|
||||
def nxv1i16 : ValueType<16, 64>; // n x 1 x i16 vector value
|
||||
def nxv2i16 : ValueType<32, 65>; // n x 2 x i16 vector value
|
||||
def nxv4i16 : ValueType<64, 66>; // n x 4 x i16 vector value
|
||||
def nxv8i16 : ValueType<128, 67>; // n x 8 x i16 vector value
|
||||
def nxv16i16: ValueType<256, 68>; // n x 16 x i16 vector value
|
||||
def nxv32i16: ValueType<512, 69>; // n x 32 x i16 vector value
|
||||
|
||||
def nxv1i32 : ValueType<32, 70>; // n x 1 x i32 vector value
|
||||
def nxv2i32 : ValueType<64, 71>; // n x 2 x i32 vector value
|
||||
def nxv4i32 : ValueType<128, 72>; // n x 4 x i32 vector value
|
||||
def nxv8i32 : ValueType<256, 73>; // n x 8 x i32 vector value
|
||||
def nxv16i32: ValueType<512, 74>; // n x 16 x i32 vector value
|
||||
def nxv32i32: ValueType<1024,75>; // n x 32 x i32 vector value
|
||||
|
||||
def nxv1i64 : ValueType<64, 76>; // n x 1 x i64 vector value
|
||||
def nxv2i64 : ValueType<128, 77>; // n x 2 x i64 vector value
|
||||
def nxv4i64 : ValueType<256, 78>; // n x 4 x i64 vector value
|
||||
def nxv8i64 : ValueType<512, 79>; // n x 8 x i64 vector value
|
||||
def nxv16i64: ValueType<1024,80>; // n x 16 x i64 vector value
|
||||
def nxv32i64: ValueType<2048,81>; // n x 32 x i64 vector value
|
||||
|
||||
def v2f16 : ValueType<32 , 82>; // 2 x f16 vector value
|
||||
def v4f16 : ValueType<64 , 83>; // 4 x f16 vector value
|
||||
def v8f16 : ValueType<128, 84>; // 8 x f16 vector value
|
||||
def v1f32 : ValueType<32 , 85>; // 1 x f32 vector value
|
||||
def v2f32 : ValueType<64 , 86>; // 2 x f32 vector value
|
||||
def v4f32 : ValueType<128, 87>; // 4 x f32 vector value
|
||||
def v8f32 : ValueType<256, 88>; // 8 x f32 vector value
|
||||
def v16f32 : ValueType<512, 89>; // 16 x f32 vector value
|
||||
def v1f64 : ValueType<64, 90>; // 1 x f64 vector value
|
||||
def v2f64 : ValueType<128, 91>; // 2 x f64 vector value
|
||||
def v4f64 : ValueType<256, 92>; // 4 x f64 vector value
|
||||
def v8f64 : ValueType<512, 93>; // 8 x f64 vector value
|
||||
|
||||
def nxv2f16 : ValueType<32 , 94>; // n x 2 x f16 vector value
|
||||
def nxv4f16 : ValueType<64 , 95>; // n x 4 x f16 vector value
|
||||
def nxv8f16 : ValueType<128, 96>; // n x 8 x f16 vector value
|
||||
def nxv1f32 : ValueType<32 , 97>; // n x 1 x f32 vector value
|
||||
def nxv2f32 : ValueType<64 , 98>; // n x 2 x f32 vector value
|
||||
def nxv4f32 : ValueType<128, 99>; // n x 4 x f32 vector value
|
||||
def nxv8f32 : ValueType<256, 100>; // n x 8 x f32 vector value
|
||||
def nxv16f32 : ValueType<512, 101>; // n x 16 x f32 vector value
|
||||
def nxv1f64 : ValueType<64, 102>; // n x 1 x f64 vector value
|
||||
def nxv2f64 : ValueType<128, 103>; // n x 2 x f64 vector value
|
||||
def nxv4f64 : ValueType<256, 104>; // n x 4 x f64 vector value
|
||||
def nxv8f64 : ValueType<512, 105>; // n x 8 x f64 vector value
|
||||
|
||||
def x86mmx : ValueType<64 , 106>; // X86 MMX value
|
||||
def FlagVT : ValueType<0 , 107>; // Pre-RA sched glue
|
||||
def isVoid : ValueType<0 , 108>; // Produces no value
|
||||
def untyped: ValueType<8 , 109>; // Produces an untyped value
|
||||
def token : ValueType<0 , 248>; // TokenTy
|
||||
def MetadataVT: ValueType<0, 249>; // Metadata
|
||||
|
||||
// Pseudo valuetype mapped to the current pointer size to any address space.
|
||||
// Should only be used in TableGen.
|
||||
def iPTRAny : ValueType<0, 122>;
|
||||
def iPTRAny : ValueType<0, 250>;
|
||||
|
||||
// Pseudo valuetype to represent "vector of any size"
|
||||
def vAny : ValueType<0 , 123>;
|
||||
def vAny : ValueType<0 , 251>;
|
||||
|
||||
// Pseudo valuetype to represent "float of any format"
|
||||
def fAny : ValueType<0 , 124>;
|
||||
def fAny : ValueType<0 , 252>;
|
||||
|
||||
// Pseudo valuetype to represent "integer of any bit width"
|
||||
def iAny : ValueType<0 , 125>;
|
||||
def iAny : ValueType<0 , 253>;
|
||||
|
||||
// Pseudo valuetype mapped to the current pointer size.
|
||||
def iPTR : ValueType<0 , 126>;
|
||||
def iPTR : ValueType<0 , 254>;
|
||||
|
||||
// Pseudo valuetype to represent "any type of any size".
|
||||
def Any : ValueType<0 , 127>;
|
||||
def Any : ValueType<0 , 255>;
|
||||
|
@ -247,16 +247,11 @@ public:
|
||||
/// DW_AT_call_line attribute in this DIE.
|
||||
/// \param CallColumn filled in with non-zero if successful, zero if there is
|
||||
/// no DW_AT_call_column attribute in this DIE.
|
||||
/// \param CallDiscriminator filled in with non-zero if successful, zero if
|
||||
/// there is no DW_AT_GNU_discriminator attribute in this DIE.
|
||||
void getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
|
||||
uint32_t &CallColumn) const;
|
||||
uint32_t &CallColumn, uint32_t &CallDiscriminator) const;
|
||||
|
||||
/// Get inlined chain for a given address, rooted at the current DIE.
|
||||
/// Returns empty chain if address is not contained in address range
|
||||
/// of current DIE.
|
||||
void
|
||||
getInlinedChainForAddress(const uint64_t Address,
|
||||
SmallVectorImpl<DWARFDie> &InlinedChain) const;
|
||||
|
||||
class attribute_iterator;
|
||||
|
||||
/// Get an iterator range to all attributes in the current DIE only.
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -134,6 +135,11 @@ class DWARFUnit {
|
||||
uint64_t BaseAddr;
|
||||
// The compile unit debug information entry items.
|
||||
std::vector<DWARFDebugInfoEntry> DieArray;
|
||||
|
||||
// Map from range's start address to end address and corresponding DIE.
|
||||
// IntervalMap does not support range removal, as a result, we use the
|
||||
// std::map::upper_bound for address range lookup.
|
||||
std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap;
|
||||
typedef iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>
|
||||
die_iterator_range;
|
||||
|
||||
@ -183,6 +189,9 @@ public:
|
||||
AddrOffsetSectionBase = Base;
|
||||
}
|
||||
|
||||
// Recursively update address to Die map.
|
||||
void updateAddressDieMap(DWARFDie Die);
|
||||
|
||||
void setRangesSection(StringRef RS, uint32_t Base) {
|
||||
RangeSection = RS;
|
||||
RangeSectionBase = Base;
|
||||
@ -339,10 +348,10 @@ private:
|
||||
/// it was actually constructed.
|
||||
bool parseDWO();
|
||||
|
||||
/// getSubprogramForAddress - Returns subprogram DIE with address range
|
||||
/// getSubroutineForAddress - Returns subprogram DIE with address range
|
||||
/// encompassing the provided address. The pointer is alive as long as parsed
|
||||
/// compile unit DIEs are not cleared.
|
||||
DWARFDie getSubprogramForAddress(uint64_t Address);
|
||||
DWARFDie getSubroutineForAddress(uint64_t Address);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -108,18 +108,16 @@ public:
|
||||
bool hasSExtAttr() const;
|
||||
|
||||
/// Add attributes to an argument.
|
||||
void addAttr(AttributeList AS);
|
||||
void addAttrs(AttrBuilder &B);
|
||||
|
||||
void addAttr(Attribute::AttrKind Kind) {
|
||||
addAttr(AttributeList::get(getContext(), getArgNo() + 1, Kind));
|
||||
}
|
||||
void addAttr(Attribute::AttrKind Kind);
|
||||
|
||||
void addAttr(Attribute Attr);
|
||||
|
||||
/// Remove attributes from an argument.
|
||||
void removeAttr(AttributeList AS);
|
||||
|
||||
void removeAttr(Attribute::AttrKind Kind) {
|
||||
removeAttr(AttributeList::get(getContext(), getArgNo() + 1, Kind));
|
||||
}
|
||||
void removeAttr(Attribute::AttrKind Kind);
|
||||
|
||||
/// Check if an argument has a given attribute.
|
||||
bool hasAttribute(Attribute::AttrKind Kind) const;
|
||||
|
@ -356,9 +356,6 @@ public:
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
AttributeList Attrs) const;
|
||||
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
AttributeSet AS) const;
|
||||
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B) const;
|
||||
|
||||
|
@ -41,17 +41,14 @@ namespace llvm {
|
||||
class MDNode;
|
||||
|
||||
/// This class represents a range of values.
|
||||
///
|
||||
class ConstantRange {
|
||||
APInt Lower, Upper;
|
||||
|
||||
public:
|
||||
/// Initialize a full (the default) or empty set for the specified bit width.
|
||||
///
|
||||
explicit ConstantRange(uint32_t BitWidth, bool isFullSet = true);
|
||||
|
||||
/// Initialize a range to hold the single specified value.
|
||||
///
|
||||
ConstantRange(APInt Value);
|
||||
|
||||
/// @brief Initialize a range of values explicitly. This will assert out if
|
||||
@ -119,46 +116,36 @@ public:
|
||||
bool getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS) const;
|
||||
|
||||
/// Return the lower value for this range.
|
||||
///
|
||||
const APInt &getLower() const { return Lower; }
|
||||
|
||||
/// Return the upper value for this range.
|
||||
///
|
||||
const APInt &getUpper() const { return Upper; }
|
||||
|
||||
/// Get the bit width of this ConstantRange.
|
||||
///
|
||||
uint32_t getBitWidth() const { return Lower.getBitWidth(); }
|
||||
|
||||
/// Return true if this set contains all of the elements possible
|
||||
/// for this data-type.
|
||||
///
|
||||
bool isFullSet() const;
|
||||
|
||||
/// Return true if this set contains no members.
|
||||
///
|
||||
bool isEmptySet() const;
|
||||
|
||||
/// Return true if this set wraps around the top of the range.
|
||||
/// For example: [100, 8).
|
||||
///
|
||||
bool isWrappedSet() const;
|
||||
|
||||
/// Return true if this set wraps around the INT_MIN of
|
||||
/// its bitwidth. For example: i8 [120, 140).
|
||||
///
|
||||
bool isSignWrappedSet() const;
|
||||
|
||||
/// Return true if the specified value is in the set.
|
||||
///
|
||||
bool contains(const APInt &Val) const;
|
||||
|
||||
/// Return true if the other range is a subset of this one.
|
||||
///
|
||||
bool contains(const ConstantRange &CR) const;
|
||||
|
||||
/// If this set contains a single element, return it, otherwise return null.
|
||||
///
|
||||
const APInt *getSingleElement() const {
|
||||
if (Upper == Lower + 1)
|
||||
return &Lower;
|
||||
@ -174,35 +161,27 @@ public:
|
||||
}
|
||||
|
||||
/// Return true if this set contains exactly one member.
|
||||
///
|
||||
bool isSingleElement() const { return getSingleElement() != nullptr; }
|
||||
|
||||
/// Return the number of elements in this set.
|
||||
///
|
||||
APInt getSetSize() const;
|
||||
|
||||
/// Compare set size of this range with the range CR.
|
||||
///
|
||||
bool isSizeStrictlySmallerThanOf(const ConstantRange &CR) const;
|
||||
|
||||
/// Return the largest unsigned value contained in the ConstantRange.
|
||||
///
|
||||
APInt getUnsignedMax() const;
|
||||
|
||||
/// Return the smallest unsigned value contained in the ConstantRange.
|
||||
///
|
||||
APInt getUnsignedMin() const;
|
||||
|
||||
/// Return the largest signed value contained in the ConstantRange.
|
||||
///
|
||||
APInt getSignedMax() const;
|
||||
|
||||
/// Return the smallest signed value contained in the ConstantRange.
|
||||
///
|
||||
APInt getSignedMin() const;
|
||||
|
||||
/// Return true if this range is equal to another range.
|
||||
///
|
||||
bool operator==(const ConstantRange &CR) const {
|
||||
return Lower == CR.Lower && Upper == CR.Upper;
|
||||
}
|
||||
@ -213,8 +192,8 @@ public:
|
||||
/// Subtract the specified constant from the endpoints of this constant range.
|
||||
ConstantRange subtract(const APInt &CI) const;
|
||||
|
||||
/// \brief Subtract the specified range from this range (aka relative
|
||||
/// complement of the sets).
|
||||
/// Subtract the specified range from this range (aka relative complement of
|
||||
/// the sets).
|
||||
ConstantRange difference(const ConstantRange &CR) const;
|
||||
|
||||
/// Return the range that results from the intersection of
|
||||
@ -223,7 +202,6 @@ public:
|
||||
/// smallest possible set size that does so. Because there may be two
|
||||
/// intersections with the same set size, A.intersectWith(B) might not
|
||||
/// be equal to B.intersectWith(A).
|
||||
///
|
||||
ConstantRange intersectWith(const ConstantRange &CR) const;
|
||||
|
||||
/// Return the range that results from the union of this range
|
||||
@ -231,7 +209,6 @@ public:
|
||||
/// elements of both sets, but may contain more. For example, [3, 9) union
|
||||
/// [12,15) is [3, 15), which includes 9, 10, and 11, which were not included
|
||||
/// in either set before.
|
||||
///
|
||||
ConstantRange unionWith(const ConstantRange &CR) const;
|
||||
|
||||
/// Return a new range representing the possible values resulting
|
||||
@ -331,15 +308,12 @@ public:
|
||||
ConstantRange lshr(const ConstantRange &Other) const;
|
||||
|
||||
/// Return a new range that is the logical not of the current set.
|
||||
///
|
||||
ConstantRange inverse() const;
|
||||
|
||||
/// Print out the bounds to a stream.
|
||||
///
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// Allow printing from a debugger easily.
|
||||
///
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
|
@ -778,6 +778,9 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
// Create wrappers for C Binding types (see CBindingWrapping.h).
|
||||
DEFINE_ISA_CONVERSION_FUNCTIONS(DIBuilder, LLVMDIBuilderRef)
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_IR_DIBUILDER_H
|
||||
|
@ -2232,6 +2232,9 @@ public:
|
||||
expr_op_iterator expr_op_end() const {
|
||||
return expr_op_iterator(elements_end());
|
||||
}
|
||||
iterator_range<expr_op_iterator> expr_ops() const {
|
||||
return {expr_op_begin(), expr_op_end()};
|
||||
}
|
||||
/// @}
|
||||
|
||||
bool isValid() const;
|
||||
@ -2240,7 +2243,7 @@ public:
|
||||
return MD->getMetadataID() == DIExpressionKind;
|
||||
}
|
||||
|
||||
/// Is the first element a DW_OP_deref?.
|
||||
/// Return whether the first element a DW_OP_deref.
|
||||
bool startsWithDeref() const {
|
||||
return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref;
|
||||
}
|
||||
|
@ -273,10 +273,11 @@ public:
|
||||
Value *getPointerOperand() { return getOperand(0); }
|
||||
const Value *getPointerOperand() const { return getOperand(0); }
|
||||
static unsigned getPointerOperandIndex() { return 0U; }
|
||||
Type *getPointerOperandType() const { return getPointerOperand()->getType(); }
|
||||
|
||||
/// Returns the address space of the pointer operand.
|
||||
unsigned getPointerAddressSpace() const {
|
||||
return getPointerOperand()->getType()->getPointerAddressSpace();
|
||||
return getPointerOperandType()->getPointerAddressSpace();
|
||||
}
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
@ -397,10 +398,11 @@ public:
|
||||
Value *getPointerOperand() { return getOperand(1); }
|
||||
const Value *getPointerOperand() const { return getOperand(1); }
|
||||
static unsigned getPointerOperandIndex() { return 1U; }
|
||||
Type *getPointerOperandType() const { return getPointerOperand()->getType(); }
|
||||
|
||||
/// Returns the address space of the pointer operand.
|
||||
unsigned getPointerAddressSpace() const {
|
||||
return getPointerOperand()->getType()->getPointerAddressSpace();
|
||||
return getPointerOperandType()->getPointerAddressSpace();
|
||||
}
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
@ -133,6 +134,14 @@ public:
|
||||
/// @}
|
||||
};
|
||||
|
||||
// Create wrappers for C Binding types (see CBindingWrapping.h).
|
||||
DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMMetadataRef)
|
||||
|
||||
// Specialized opaque metadata conversions.
|
||||
inline Metadata **unwrap(LLVMMetadataRef *MDs) {
|
||||
return reinterpret_cast<Metadata**>(MDs);
|
||||
}
|
||||
|
||||
#define HANDLE_METADATA(CLASS) class CLASS;
|
||||
#include "llvm/IR/Metadata.def"
|
||||
|
||||
|
@ -160,7 +160,6 @@ private:
|
||||
std::vector<ValueInfo> RefEdgeList;
|
||||
|
||||
protected:
|
||||
/// GlobalValueSummary constructor.
|
||||
GlobalValueSummary(SummaryKind K, GVFlags Flags, std::vector<ValueInfo> Refs)
|
||||
: Kind(K), Flags(Flags), OriginalName(0), RefEdgeList(std::move(Refs)) {}
|
||||
|
||||
@ -221,7 +220,6 @@ class AliasSummary : public GlobalValueSummary {
|
||||
GlobalValueSummary *AliaseeSummary;
|
||||
|
||||
public:
|
||||
/// Summary constructors.
|
||||
AliasSummary(GVFlags Flags, std::vector<ValueInfo> Refs)
|
||||
: GlobalValueSummary(AliasKind, Flags, std::move(Refs)) {}
|
||||
|
||||
@ -297,7 +295,6 @@ private:
|
||||
std::unique_ptr<TypeIdInfo> TIdInfo;
|
||||
|
||||
public:
|
||||
/// Summary constructors.
|
||||
FunctionSummary(GVFlags Flags, unsigned NumInsts, std::vector<ValueInfo> Refs,
|
||||
std::vector<EdgeTy> CGEdges,
|
||||
std::vector<GlobalValue::GUID> TypeTests,
|
||||
@ -418,7 +415,6 @@ template <> struct DenseMapInfo<FunctionSummary::ConstVCall> {
|
||||
class GlobalVarSummary : public GlobalValueSummary {
|
||||
|
||||
public:
|
||||
/// Summary constructors.
|
||||
GlobalVarSummary(GVFlags Flags, std::vector<ValueInfo> Refs)
|
||||
: GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)) {}
|
||||
|
||||
|
@ -267,15 +267,15 @@ inline cst_pred_ty<is_all_ones> m_AllOnes() {
|
||||
}
|
||||
inline api_pred_ty<is_all_ones> m_AllOnes(const APInt *&V) { return V; }
|
||||
|
||||
struct is_sign_bit {
|
||||
bool isValue(const APInt &C) { return C.isSignBit(); }
|
||||
struct is_sign_mask {
|
||||
bool isValue(const APInt &C) { return C.isSignMask(); }
|
||||
};
|
||||
|
||||
/// \brief Match an integer or vector with only the sign bit(s) set.
|
||||
inline cst_pred_ty<is_sign_bit> m_SignBit() {
|
||||
return cst_pred_ty<is_sign_bit>();
|
||||
inline cst_pred_ty<is_sign_mask> m_SignMask() {
|
||||
return cst_pred_ty<is_sign_mask>();
|
||||
}
|
||||
inline api_pred_ty<is_sign_bit> m_SignBit(const APInt *&V) { return V; }
|
||||
inline api_pred_ty<is_sign_mask> m_SignMask(const APInt *&V) { return V; }
|
||||
|
||||
struct is_power2 {
|
||||
bool isValue(const APInt &C) { return C.isPowerOf2(); }
|
||||
|
@ -61,9 +61,29 @@ public:
|
||||
/// that also works with less standard-compliant compilers
|
||||
void swap(Use &RHS);
|
||||
|
||||
/// Pointer traits for the UserRef PointerIntPair. This ensures we always
|
||||
/// use the LSB regardless of pointer alignment on different targets.
|
||||
struct UserRefPointerTraits {
|
||||
static inline void *getAsVoidPointer(User *P) { return P; }
|
||||
static inline User *getFromVoidPointer(void *P) {
|
||||
return (User *)P;
|
||||
}
|
||||
enum { NumLowBitsAvailable = 1 };
|
||||
};
|
||||
|
||||
// A type for the word following an array of hung-off Uses in memory, which is
|
||||
// a pointer back to their User with the bottom bit set.
|
||||
typedef PointerIntPair<User *, 1, unsigned> UserRef;
|
||||
typedef PointerIntPair<User *, 1, unsigned, UserRefPointerTraits> UserRef;
|
||||
|
||||
/// Pointer traits for the Prev PointerIntPair. This ensures we always use
|
||||
/// the two LSBs regardless of pointer alignment on different targets.
|
||||
struct PrevPointerTraits {
|
||||
static inline void *getAsVoidPointer(Use **P) { return P; }
|
||||
static inline Use **getFromVoidPointer(void *P) {
|
||||
return (Use **)P;
|
||||
}
|
||||
enum { NumLowBitsAvailable = 2 };
|
||||
};
|
||||
|
||||
private:
|
||||
/// Destructor - Only for zap()
|
||||
@ -115,7 +135,7 @@ private:
|
||||
|
||||
Value *Val;
|
||||
Use *Next;
|
||||
PointerIntPair<Use **, 2, PrevPtrTag> Prev;
|
||||
PointerIntPair<Use **, 2, PrevPtrTag, PrevPointerTraits> Prev;
|
||||
|
||||
void setPrev(Use **NewPrev) { Prev.setPointer(NewPrev); }
|
||||
|
||||
|
@ -65,8 +65,8 @@ protected:
|
||||
// Properties to be set by the target writer, used to configure asm printer.
|
||||
//
|
||||
|
||||
/// Pointer size in bytes. Default is 4.
|
||||
unsigned PointerSize = 4;
|
||||
/// Code pointer size in bytes. Default is 4.
|
||||
unsigned CodePointerSize = 4;
|
||||
|
||||
/// Size of the stack slot reserved for callee-saved registers, in bytes.
|
||||
/// Default is same as pointer size.
|
||||
@ -384,8 +384,8 @@ public:
|
||||
explicit MCAsmInfo();
|
||||
virtual ~MCAsmInfo();
|
||||
|
||||
/// Get the pointer size in bytes.
|
||||
unsigned getPointerSize() const { return PointerSize; }
|
||||
/// Get the code pointer size in bytes.
|
||||
unsigned getCodePointerSize() const { return CodePointerSize; }
|
||||
|
||||
/// Get the callee-saved register stack slot
|
||||
/// size in bytes.
|
||||
|
@ -128,6 +128,7 @@ public:
|
||||
virtual void emitArch(unsigned Arch);
|
||||
virtual void emitArchExtension(unsigned ArchExt);
|
||||
virtual void emitObjectArch(unsigned Arch);
|
||||
void emitTargetAttributes(const MCSubtargetInfo &STI);
|
||||
virtual void finishAttributeSection();
|
||||
virtual void emitInst(uint32_t Inst, char Suffix = '\0');
|
||||
|
||||
|
@ -86,6 +86,10 @@ public:
|
||||
FeatureBits = FeatureBits_;
|
||||
}
|
||||
|
||||
bool hasFeature(unsigned Feature) const {
|
||||
return FeatureBits[Feature];
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Initialize the scheduling model and feature bits.
|
||||
///
|
||||
|
@ -14,15 +14,20 @@
|
||||
#ifndef LLVM_OBJECT_ARCHIVE_H
|
||||
#define LLVM_OBJECT_ARCHIVE_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Support/Chrono.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
@ -32,25 +37,28 @@ class Archive;
|
||||
class ArchiveMemberHeader {
|
||||
public:
|
||||
friend class Archive;
|
||||
|
||||
ArchiveMemberHeader(Archive const *Parent, const char *RawHeaderPtr,
|
||||
uint64_t Size, Error *Err);
|
||||
// ArchiveMemberHeader() = default;
|
||||
|
||||
/// Get the name without looking up long names.
|
||||
Expected<llvm::StringRef> getRawName() const;
|
||||
Expected<StringRef> getRawName() const;
|
||||
|
||||
/// Get the name looking up long names.
|
||||
Expected<llvm::StringRef> getName(uint64_t Size) const;
|
||||
Expected<StringRef> getName(uint64_t Size) const;
|
||||
|
||||
/// Members are not larger than 4GB.
|
||||
Expected<uint32_t> getSize() const;
|
||||
|
||||
Expected<sys::fs::perms> getAccessMode() const;
|
||||
Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const;
|
||||
llvm::StringRef getRawLastModified() const {
|
||||
|
||||
StringRef getRawLastModified() const {
|
||||
return StringRef(ArMemHdr->LastModified,
|
||||
sizeof(ArMemHdr->LastModified)).rtrim(' ');
|
||||
}
|
||||
|
||||
Expected<unsigned> getUID() const;
|
||||
Expected<unsigned> getGID() const;
|
||||
|
||||
@ -75,11 +83,13 @@ private:
|
||||
|
||||
class Archive : public Binary {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
class Child {
|
||||
friend Archive;
|
||||
const Archive *Parent;
|
||||
friend ArchiveMemberHeader;
|
||||
|
||||
const Archive *Parent;
|
||||
ArchiveMemberHeader Header;
|
||||
/// \brief Includes header but not padding byte.
|
||||
StringRef Data;
|
||||
@ -103,17 +113,22 @@ public:
|
||||
Expected<StringRef> getName() const;
|
||||
Expected<std::string> getFullName() const;
|
||||
Expected<StringRef> getRawName() const { return Header.getRawName(); }
|
||||
|
||||
Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const {
|
||||
return Header.getLastModified();
|
||||
}
|
||||
|
||||
StringRef getRawLastModified() const {
|
||||
return Header.getRawLastModified();
|
||||
}
|
||||
|
||||
Expected<unsigned> getUID() const { return Header.getUID(); }
|
||||
Expected<unsigned> getGID() const { return Header.getGID(); }
|
||||
|
||||
Expected<sys::fs::perms> getAccessMode() const {
|
||||
return Header.getAccessMode();
|
||||
}
|
||||
|
||||
/// \return the size of the archive member without the header or padding.
|
||||
Expected<uint64_t> getSize() const;
|
||||
/// \return the size in the archive header for this member.
|
||||
@ -130,11 +145,12 @@ public:
|
||||
|
||||
class child_iterator {
|
||||
Child C;
|
||||
Error *E;
|
||||
Error *E = nullptr;
|
||||
|
||||
public:
|
||||
child_iterator() : C(Child(nullptr, nullptr, nullptr)), E(nullptr) {}
|
||||
child_iterator() : C(Child(nullptr, nullptr, nullptr)) {}
|
||||
child_iterator(const Child &C, Error *E) : C(C), E(E) {}
|
||||
|
||||
const Child *operator->() const { return &C; }
|
||||
const Child &operator*() const { return C; }
|
||||
|
||||
@ -171,14 +187,15 @@ public:
|
||||
uint32_t StringIndex; // Extra index to the string.
|
||||
|
||||
public:
|
||||
bool operator ==(const Symbol &other) const {
|
||||
return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
|
||||
}
|
||||
|
||||
Symbol(const Archive *p, uint32_t symi, uint32_t stri)
|
||||
: Parent(p)
|
||||
, SymbolIndex(symi)
|
||||
, StringIndex(stri) {}
|
||||
|
||||
bool operator ==(const Symbol &other) const {
|
||||
return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex);
|
||||
}
|
||||
|
||||
StringRef getName() const;
|
||||
Expected<Child> getMember() const;
|
||||
Symbol getNext() const;
|
||||
@ -186,8 +203,10 @@ public:
|
||||
|
||||
class symbol_iterator {
|
||||
Symbol symbol;
|
||||
|
||||
public:
|
||||
symbol_iterator(const Symbol &s) : symbol(s) {}
|
||||
|
||||
const Symbol *operator->() const { return &symbol; }
|
||||
const Symbol &operator*() const { return symbol; }
|
||||
|
||||
@ -264,7 +283,7 @@ private:
|
||||
mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // end namespace object
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_ARCHIVE_H
|
||||
|
@ -15,10 +15,11 @@
|
||||
#define LLVM_OBJECT_BINARY_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -29,9 +30,6 @@ namespace object {
|
||||
|
||||
class Binary {
|
||||
private:
|
||||
Binary() = delete;
|
||||
Binary(const Binary &other) = delete;
|
||||
|
||||
unsigned int TypeID;
|
||||
|
||||
protected:
|
||||
@ -80,6 +78,8 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
Binary() = delete;
|
||||
Binary(const Binary &other) = delete;
|
||||
virtual ~Binary();
|
||||
|
||||
StringRef getData() const;
|
||||
@ -173,7 +173,7 @@ OwningBinary<T>::OwningBinary(std::unique_ptr<T> Bin,
|
||||
std::unique_ptr<MemoryBuffer> Buf)
|
||||
: Bin(std::move(Bin)), Buf(std::move(Buf)) {}
|
||||
|
||||
template <typename T> OwningBinary<T>::OwningBinary() {}
|
||||
template <typename T> OwningBinary<T>::OwningBinary() = default;
|
||||
|
||||
template <typename T>
|
||||
OwningBinary<T>::OwningBinary(OwningBinary &&Other)
|
||||
@ -201,7 +201,9 @@ template <typename T> const T* OwningBinary<T>::getBinary() const {
|
||||
}
|
||||
|
||||
Expected<OwningBinary<Binary>> createBinary(StringRef Path);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace object
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_OBJECT_BINARY_H
|
||||
|
@ -14,28 +14,39 @@
|
||||
#ifndef LLVM_OBJECT_COFF_H
|
||||
#define LLVM_OBJECT_COFF_H
|
||||
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/COFF.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <typename T> class ArrayRef;
|
||||
|
||||
namespace object {
|
||||
class ImportDirectoryEntryRef;
|
||||
|
||||
class BaseRelocRef;
|
||||
class DelayImportDirectoryEntryRef;
|
||||
class ExportDirectoryEntryRef;
|
||||
class ImportDirectoryEntryRef;
|
||||
class ImportedSymbolRef;
|
||||
class BaseRelocRef;
|
||||
typedef content_iterator<ImportDirectoryEntryRef> import_directory_iterator;
|
||||
typedef content_iterator<DelayImportDirectoryEntryRef>
|
||||
delay_import_directory_iterator;
|
||||
typedef content_iterator<ExportDirectoryEntryRef> export_directory_iterator;
|
||||
typedef content_iterator<ImportedSymbolRef> imported_symbol_iterator;
|
||||
typedef content_iterator<BaseRelocRef> base_reloc_iterator;
|
||||
|
||||
using import_directory_iterator = content_iterator<ImportDirectoryEntryRef>;
|
||||
using delay_import_directory_iterator =
|
||||
content_iterator<DelayImportDirectoryEntryRef>;
|
||||
using export_directory_iterator = content_iterator<ExportDirectoryEntryRef>;
|
||||
using imported_symbol_iterator = content_iterator<ImportedSymbolRef>;
|
||||
using base_reloc_iterator = content_iterator<BaseRelocRef>;
|
||||
|
||||
/// The DOS compatible header at the front of all PE/COFF executables.
|
||||
struct dos_header {
|
||||
@ -190,10 +201,10 @@ struct import_lookup_table_entry {
|
||||
}
|
||||
};
|
||||
|
||||
typedef import_lookup_table_entry<support::little32_t>
|
||||
import_lookup_table_entry32;
|
||||
typedef import_lookup_table_entry<support::little64_t>
|
||||
import_lookup_table_entry64;
|
||||
using import_lookup_table_entry32 =
|
||||
import_lookup_table_entry<support::little32_t>;
|
||||
using import_lookup_table_entry64 =
|
||||
import_lookup_table_entry<support::little64_t>;
|
||||
|
||||
struct delay_import_directory_table_entry {
|
||||
// dumpbin reports this field as "Characteristics" instead of "Attributes".
|
||||
@ -226,8 +237,8 @@ union export_address_table_entry {
|
||||
support::ulittle32_t ForwarderRVA;
|
||||
};
|
||||
|
||||
typedef support::ulittle32_t export_name_pointer_table_entry;
|
||||
typedef support::ulittle16_t export_ordinal_table_entry;
|
||||
using export_name_pointer_table_entry = support::ulittle32_t;
|
||||
using export_ordinal_table_entry = support::ulittle16_t;
|
||||
|
||||
struct StringTableOffset {
|
||||
support::ulittle32_t Zeroes;
|
||||
@ -250,8 +261,8 @@ struct coff_symbol {
|
||||
uint8_t NumberOfAuxSymbols;
|
||||
};
|
||||
|
||||
typedef coff_symbol<support::ulittle16_t> coff_symbol16;
|
||||
typedef coff_symbol<support::ulittle32_t> coff_symbol32;
|
||||
using coff_symbol16 = coff_symbol<support::ulittle16_t>;
|
||||
using coff_symbol32 = coff_symbol<support::ulittle32_t>;
|
||||
|
||||
// Contains only common parts of coff_symbol16 and coff_symbol32.
|
||||
struct coff_symbol_generic {
|
||||
@ -264,9 +275,9 @@ struct coff_symbol_generic {
|
||||
|
||||
class COFFSymbolRef {
|
||||
public:
|
||||
COFFSymbolRef(const coff_symbol16 *CS) : CS16(CS), CS32(nullptr) {}
|
||||
COFFSymbolRef(const coff_symbol32 *CS) : CS16(nullptr), CS32(CS) {}
|
||||
COFFSymbolRef() : CS16(nullptr), CS32(nullptr) {}
|
||||
COFFSymbolRef() = default;
|
||||
COFFSymbolRef(const coff_symbol16 *CS) : CS16(CS) {}
|
||||
COFFSymbolRef(const coff_symbol32 *CS) : CS32(CS) {}
|
||||
|
||||
const void *getRawPtr() const {
|
||||
return CS16 ? static_cast<const void *>(CS16) : CS32;
|
||||
@ -396,8 +407,8 @@ public:
|
||||
private:
|
||||
bool isSet() const { return CS16 || CS32; }
|
||||
|
||||
const coff_symbol16 *CS16;
|
||||
const coff_symbol32 *CS32;
|
||||
const coff_symbol16 *CS16 = nullptr;
|
||||
const coff_symbol32 *CS32 = nullptr;
|
||||
};
|
||||
|
||||
struct coff_section {
|
||||
@ -418,6 +429,7 @@ struct coff_section {
|
||||
return (Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL) &&
|
||||
NumberOfRelocations == UINT16_MAX;
|
||||
}
|
||||
|
||||
uint32_t getAlignment() const {
|
||||
// The IMAGE_SCN_TYPE_NO_PAD bit is a legacy way of getting to
|
||||
// IMAGE_SCN_ALIGN_1BYTES.
|
||||
@ -508,6 +520,7 @@ struct coff_import_header {
|
||||
support::ulittle32_t SizeOfData;
|
||||
support::ulittle16_t OrdinalHint;
|
||||
support::ulittle16_t TypeInfo;
|
||||
|
||||
int getType() const { return TypeInfo & 0x3; }
|
||||
int getNameType() const { return (TypeInfo >> 2) & 0x7; }
|
||||
};
|
||||
@ -518,6 +531,7 @@ struct coff_import_directory_table_entry {
|
||||
support::ulittle32_t ForwarderChain;
|
||||
support::ulittle32_t NameRVA;
|
||||
support::ulittle32_t ImportAddressTableRVA;
|
||||
|
||||
bool isNull() const {
|
||||
return ImportLookupTableRVA == 0 && TimeDateStamp == 0 &&
|
||||
ForwarderChain == 0 && NameRVA == 0 && ImportAddressTableRVA == 0;
|
||||
@ -532,6 +546,7 @@ struct coff_tls_directory {
|
||||
IntTy AddressOfCallBacks;
|
||||
support::ulittle32_t SizeOfZeroFill;
|
||||
support::ulittle32_t Characteristics;
|
||||
|
||||
uint32_t getAlignment() const {
|
||||
// Bit [20:24] contains section alignment.
|
||||
uint32_t Shift = (Characteristics & 0x00F00000) >> 20;
|
||||
@ -541,8 +556,8 @@ struct coff_tls_directory {
|
||||
}
|
||||
};
|
||||
|
||||
typedef coff_tls_directory<support::little32_t> coff_tls_directory32;
|
||||
typedef coff_tls_directory<support::little64_t> coff_tls_directory64;
|
||||
using coff_tls_directory32 = coff_tls_directory<support::little32_t>;
|
||||
using coff_tls_directory64 = coff_tls_directory<support::little64_t>;
|
||||
|
||||
struct coff_load_configuration32 {
|
||||
support::ulittle32_t Characteristics;
|
||||
@ -603,6 +618,7 @@ struct coff_base_reloc_block_header {
|
||||
|
||||
struct coff_base_reloc_block_entry {
|
||||
support::ulittle16_t Data;
|
||||
|
||||
int getType() const { return Data >> 12; }
|
||||
int getOffset() const { return Data & ((1 << 12) - 1); }
|
||||
};
|
||||
@ -652,6 +668,7 @@ public:
|
||||
return reinterpret_cast<uintptr_t>(SymbolTable32);
|
||||
return uintptr_t(0);
|
||||
}
|
||||
|
||||
uint16_t getMachine() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->Machine;
|
||||
@ -659,6 +676,7 @@ public:
|
||||
return COFFBigObjHeader->Machine;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint16_t getSizeOfOptionalHeader() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->isImportLibrary() ? 0
|
||||
@ -668,6 +686,7 @@ public:
|
||||
return 0;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint16_t getCharacteristics() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->isImportLibrary() ? 0 : COFFHeader->Characteristics;
|
||||
@ -677,6 +696,7 @@ public:
|
||||
return 0;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint32_t getTimeDateStamp() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->TimeDateStamp;
|
||||
@ -684,6 +704,7 @@ public:
|
||||
return COFFBigObjHeader->TimeDateStamp;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint32_t getNumberOfSections() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->isImportLibrary() ? 0 : COFFHeader->NumberOfSections;
|
||||
@ -691,6 +712,7 @@ public:
|
||||
return COFFBigObjHeader->NumberOfSections;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint32_t getPointerToSymbolTable() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->isImportLibrary() ? 0
|
||||
@ -699,6 +721,7 @@ public:
|
||||
return COFFBigObjHeader->PointerToSymbolTable;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint32_t getRawNumberOfSymbols() const {
|
||||
if (COFFHeader)
|
||||
return COFFHeader->isImportLibrary() ? 0 : COFFHeader->NumberOfSymbols;
|
||||
@ -706,11 +729,13 @@ public:
|
||||
return COFFBigObjHeader->NumberOfSymbols;
|
||||
llvm_unreachable("no COFF header!");
|
||||
}
|
||||
|
||||
uint32_t getNumberOfSymbols() const {
|
||||
if (!SymbolTable16 && !SymbolTable32)
|
||||
return 0;
|
||||
return getRawNumberOfSymbols();
|
||||
}
|
||||
|
||||
protected:
|
||||
void moveSymbolNext(DataRefImpl &Symb) const override;
|
||||
Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
|
||||
@ -746,6 +771,7 @@ protected:
|
||||
|
||||
public:
|
||||
COFFObjectFile(MemoryBufferRef Object, std::error_code &EC);
|
||||
|
||||
basic_symbol_iterator symbol_begin() const override;
|
||||
basic_symbol_iterator symbol_end() const override;
|
||||
section_iterator section_begin() const override;
|
||||
@ -797,6 +823,7 @@ public:
|
||||
std::error_code getDataDirectory(uint32_t index,
|
||||
const data_directory *&Res) const;
|
||||
std::error_code getSection(int32_t index, const coff_section *&Res) const;
|
||||
|
||||
template <typename coff_symbol_type>
|
||||
std::error_code getSymbol(uint32_t Index,
|
||||
const coff_symbol_type *&Res) const {
|
||||
@ -821,6 +848,7 @@ public:
|
||||
}
|
||||
return object_error::parse_failed;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::error_code getAuxSymbol(uint32_t index, const T *&Res) const {
|
||||
ErrorOr<COFFSymbolRef> s = getSymbol(index);
|
||||
@ -829,6 +857,7 @@ public:
|
||||
Res = reinterpret_cast<const T *>(s->getRawPtr());
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code getSymbolName(COFFSymbolRef Symbol, StringRef &Res) const;
|
||||
std::error_code getSymbolName(const coff_symbol_generic *Symbol,
|
||||
StringRef &Res) const;
|
||||
@ -885,7 +914,7 @@ public:
|
||||
// The iterator for the import directory table.
|
||||
class ImportDirectoryEntryRef {
|
||||
public:
|
||||
ImportDirectoryEntryRef() : OwningObject(nullptr) {}
|
||||
ImportDirectoryEntryRef() = default;
|
||||
ImportDirectoryEntryRef(const coff_import_directory_table_entry *Table,
|
||||
uint32_t I, const COFFObjectFile *Owner)
|
||||
: ImportTable(Table), Index(I), OwningObject(Owner) {}
|
||||
@ -911,12 +940,12 @@ public:
|
||||
private:
|
||||
const coff_import_directory_table_entry *ImportTable;
|
||||
uint32_t Index;
|
||||
const COFFObjectFile *OwningObject;
|
||||
const COFFObjectFile *OwningObject = nullptr;
|
||||
};
|
||||
|
||||
class DelayImportDirectoryEntryRef {
|
||||
public:
|
||||
DelayImportDirectoryEntryRef() : OwningObject(nullptr) {}
|
||||
DelayImportDirectoryEntryRef() = default;
|
||||
DelayImportDirectoryEntryRef(const delay_import_directory_table_entry *T,
|
||||
uint32_t I, const COFFObjectFile *Owner)
|
||||
: Table(T), Index(I), OwningObject(Owner) {}
|
||||
@ -936,13 +965,13 @@ public:
|
||||
private:
|
||||
const delay_import_directory_table_entry *Table;
|
||||
uint32_t Index;
|
||||
const COFFObjectFile *OwningObject;
|
||||
const COFFObjectFile *OwningObject = nullptr;
|
||||
};
|
||||
|
||||
// The iterator for the export directory table entry.
|
||||
class ExportDirectoryEntryRef {
|
||||
public:
|
||||
ExportDirectoryEntryRef() : OwningObject(nullptr) {}
|
||||
ExportDirectoryEntryRef() = default;
|
||||
ExportDirectoryEntryRef(const export_directory_table_entry *Table, uint32_t I,
|
||||
const COFFObjectFile *Owner)
|
||||
: ExportTable(Table), Index(I), OwningObject(Owner) {}
|
||||
@ -962,12 +991,12 @@ public:
|
||||
private:
|
||||
const export_directory_table_entry *ExportTable;
|
||||
uint32_t Index;
|
||||
const COFFObjectFile *OwningObject;
|
||||
const COFFObjectFile *OwningObject = nullptr;
|
||||
};
|
||||
|
||||
class ImportedSymbolRef {
|
||||
public:
|
||||
ImportedSymbolRef() : OwningObject(nullptr) {}
|
||||
ImportedSymbolRef() = default;
|
||||
ImportedSymbolRef(const import_lookup_table_entry32 *Entry, uint32_t I,
|
||||
const COFFObjectFile *Owner)
|
||||
: Entry32(Entry), Entry64(nullptr), Index(I), OwningObject(Owner) {}
|
||||
@ -987,12 +1016,12 @@ private:
|
||||
const import_lookup_table_entry32 *Entry32;
|
||||
const import_lookup_table_entry64 *Entry64;
|
||||
uint32_t Index;
|
||||
const COFFObjectFile *OwningObject;
|
||||
const COFFObjectFile *OwningObject = nullptr;
|
||||
};
|
||||
|
||||
class BaseRelocRef {
|
||||
public:
|
||||
BaseRelocRef() : OwningObject(nullptr) {}
|
||||
BaseRelocRef() = default;
|
||||
BaseRelocRef(const coff_base_reloc_block_header *Header,
|
||||
const COFFObjectFile *Owner)
|
||||
: Header(Header), Index(0), OwningObject(Owner) {}
|
||||
@ -1006,7 +1035,7 @@ public:
|
||||
private:
|
||||
const coff_base_reloc_block_header *Header;
|
||||
uint32_t Index;
|
||||
const COFFObjectFile *OwningObject;
|
||||
const COFFObjectFile *OwningObject = nullptr;
|
||||
};
|
||||
|
||||
// Corresponds to `_FPO_DATA` structure in the PE/COFF spec.
|
||||
@ -1034,6 +1063,7 @@ struct FpoData {
|
||||
};
|
||||
|
||||
} // end namespace object
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_COFF_H
|
||||
|
@ -41,9 +41,9 @@ typedef support::ulittle32_t Word;
|
||||
|
||||
/// A reference to a string in the string table.
|
||||
struct Str {
|
||||
Word Offset;
|
||||
Word Offset, Size;
|
||||
StringRef get(StringRef Strtab) const {
|
||||
return Strtab.data() + Offset;
|
||||
return {Strtab.data() + Offset, Size};
|
||||
}
|
||||
};
|
||||
|
||||
@ -59,6 +59,9 @@ template <typename T> struct Range {
|
||||
/// table.
|
||||
struct Module {
|
||||
Word Begin, End;
|
||||
|
||||
/// The index of the first Uncommon for this Module.
|
||||
Word UncBegin;
|
||||
};
|
||||
|
||||
/// This is equivalent to an IR comdat.
|
||||
@ -82,7 +85,8 @@ struct Symbol {
|
||||
Word Flags;
|
||||
enum FlagBits {
|
||||
FB_visibility, // 2 bits
|
||||
FB_undefined = FB_visibility + 2,
|
||||
FB_has_uncommon = FB_visibility + 2,
|
||||
FB_undefined,
|
||||
FB_weak,
|
||||
FB_common,
|
||||
FB_indirect,
|
||||
@ -94,10 +98,6 @@ struct Symbol {
|
||||
FB_unnamed_addr,
|
||||
FB_executable,
|
||||
};
|
||||
|
||||
/// The index into the Uncommon table, or -1 if this symbol does not have an
|
||||
/// Uncommon.
|
||||
Word UncommonIndex;
|
||||
};
|
||||
|
||||
/// This data structure contains rarely used symbol fields and is optionally
|
||||
@ -249,15 +249,9 @@ public:
|
||||
/// Reader::module_symbols().
|
||||
class Reader::SymbolRef : public Symbol {
|
||||
const storage::Symbol *SymI, *SymE;
|
||||
const storage::Uncommon *UncI;
|
||||
const Reader *R;
|
||||
|
||||
public:
|
||||
SymbolRef(const storage::Symbol *SymI, const storage::Symbol *SymE,
|
||||
const Reader *R)
|
||||
: SymI(SymI), SymE(SymE), R(R) {
|
||||
read();
|
||||
}
|
||||
|
||||
void read() {
|
||||
if (SymI == SymE)
|
||||
return;
|
||||
@ -267,16 +261,24 @@ public:
|
||||
ComdatIndex = SymI->ComdatIndex;
|
||||
Flags = SymI->Flags;
|
||||
|
||||
uint32_t UncI = SymI->UncommonIndex;
|
||||
if (UncI != -1u) {
|
||||
const storage::Uncommon &Unc = R->Uncommons[UncI];
|
||||
CommonSize = Unc.CommonSize;
|
||||
CommonAlign = Unc.CommonAlign;
|
||||
COFFWeakExternFallbackName = R->str(Unc.COFFWeakExternFallbackName);
|
||||
if (Flags & (1 << storage::Symbol::FB_has_uncommon)) {
|
||||
CommonSize = UncI->CommonSize;
|
||||
CommonAlign = UncI->CommonAlign;
|
||||
COFFWeakExternFallbackName = R->str(UncI->COFFWeakExternFallbackName);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SymbolRef(const storage::Symbol *SymI, const storage::Symbol *SymE,
|
||||
const storage::Uncommon *UncI, const Reader *R)
|
||||
: SymI(SymI), SymE(SymE), UncI(UncI), R(R) {
|
||||
read();
|
||||
}
|
||||
|
||||
void moveNext() {
|
||||
++SymI;
|
||||
if (Flags & (1 << storage::Symbol::FB_has_uncommon))
|
||||
++UncI;
|
||||
read();
|
||||
}
|
||||
|
||||
@ -284,15 +286,16 @@ public:
|
||||
};
|
||||
|
||||
inline Reader::symbol_range Reader::symbols() const {
|
||||
return {SymbolRef(Symbols.begin(), Symbols.end(), this),
|
||||
SymbolRef(Symbols.end(), Symbols.end(), this)};
|
||||
return {SymbolRef(Symbols.begin(), Symbols.end(), Uncommons.begin(), this),
|
||||
SymbolRef(Symbols.end(), Symbols.end(), nullptr, this)};
|
||||
}
|
||||
|
||||
inline Reader::symbol_range Reader::module_symbols(unsigned I) const {
|
||||
const storage::Module &M = Modules[I];
|
||||
const storage::Symbol *MBegin = Symbols.begin() + M.Begin,
|
||||
*MEnd = Symbols.begin() + M.End;
|
||||
return {SymbolRef(MBegin, MEnd, this), SymbolRef(MEnd, MEnd, this)};
|
||||
return {SymbolRef(MBegin, MEnd, Uncommons.begin() + M.UncBegin, this),
|
||||
SymbolRef(MEnd, MEnd, nullptr, this)};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,39 +14,46 @@
|
||||
#ifndef LLVM_OBJECT_OBJECTFILE_H
|
||||
#define LLVM_OBJECT_OBJECTFILE_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Object/Error.h"
|
||||
#include "llvm/Object/SymbolicFile.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ARMAttributeParser;
|
||||
|
||||
namespace object {
|
||||
|
||||
class ObjectFile;
|
||||
class COFFObjectFile;
|
||||
class MachOObjectFile;
|
||||
class WasmObjectFile;
|
||||
|
||||
class ObjectFile;
|
||||
class SectionRef;
|
||||
class SymbolRef;
|
||||
class symbol_iterator;
|
||||
class SectionRef;
|
||||
typedef content_iterator<SectionRef> section_iterator;
|
||||
class WasmObjectFile;
|
||||
|
||||
using section_iterator = content_iterator<SectionRef>;
|
||||
|
||||
/// This is a value type class that represents a single relocation in the list
|
||||
/// of relocations in the object file.
|
||||
class RelocationRef {
|
||||
DataRefImpl RelocationPimpl;
|
||||
const ObjectFile *OwningObject;
|
||||
const ObjectFile *OwningObject = nullptr;
|
||||
|
||||
public:
|
||||
RelocationRef() : OwningObject(nullptr) { }
|
||||
|
||||
RelocationRef() = default;
|
||||
RelocationRef(DataRefImpl RelocationP, const ObjectFile *Owner);
|
||||
|
||||
bool operator==(const RelocationRef &Other) const;
|
||||
@ -65,18 +72,19 @@ public:
|
||||
DataRefImpl getRawDataRefImpl() const;
|
||||
const ObjectFile *getObject() const;
|
||||
};
|
||||
typedef content_iterator<RelocationRef> relocation_iterator;
|
||||
|
||||
using relocation_iterator = content_iterator<RelocationRef>;
|
||||
|
||||
/// This is a value type class that represents a single section in the list of
|
||||
/// sections in the object file.
|
||||
class SectionRef {
|
||||
friend class SymbolRef;
|
||||
|
||||
DataRefImpl SectionPimpl;
|
||||
const ObjectFile *OwningObject;
|
||||
const ObjectFile *OwningObject = nullptr;
|
||||
|
||||
public:
|
||||
SectionRef() : OwningObject(nullptr) { }
|
||||
|
||||
SectionRef() = default;
|
||||
SectionRef(DataRefImpl SectionP, const ObjectFile *Owner);
|
||||
|
||||
bool operator==(const SectionRef &Other) const;
|
||||
@ -119,8 +127,6 @@ class SymbolRef : public BasicSymbolRef {
|
||||
friend class SectionRef;
|
||||
|
||||
public:
|
||||
SymbolRef() : BasicSymbolRef() {}
|
||||
|
||||
enum Type {
|
||||
ST_Unknown, // Type not specified
|
||||
ST_Data,
|
||||
@ -130,6 +136,7 @@ public:
|
||||
ST_Other
|
||||
};
|
||||
|
||||
SymbolRef() = default;
|
||||
SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner);
|
||||
SymbolRef(const BasicSymbolRef &B) : BasicSymbolRef(B) {
|
||||
assert(isa<ObjectFile>(BasicSymbolRef::getObject()));
|
||||
@ -179,8 +186,6 @@ public:
|
||||
/// to create.
|
||||
class ObjectFile : public SymbolicFile {
|
||||
virtual void anchor();
|
||||
ObjectFile() = delete;
|
||||
ObjectFile(const ObjectFile &other) = delete;
|
||||
|
||||
protected:
|
||||
ObjectFile(unsigned int Type, MemoryBufferRef Source);
|
||||
@ -198,6 +203,7 @@ protected:
|
||||
// Implementations assume that the DataRefImpl is valid and has not been
|
||||
// modified externally. It's UB otherwise.
|
||||
friend class SymbolRef;
|
||||
|
||||
virtual Expected<StringRef> getSymbolName(DataRefImpl Symb) const = 0;
|
||||
std::error_code printSymbolName(raw_ostream &OS,
|
||||
DataRefImpl Symb) const override;
|
||||
@ -211,6 +217,7 @@ protected:
|
||||
|
||||
// Same as above for SectionRef.
|
||||
friend class SectionRef;
|
||||
|
||||
virtual void moveSectionNext(DataRefImpl &Sec) const = 0;
|
||||
virtual std::error_code getSectionName(DataRefImpl Sec,
|
||||
StringRef &Res) const = 0;
|
||||
@ -242,12 +249,15 @@ protected:
|
||||
uint64_t getSymbolValue(DataRefImpl Symb) const;
|
||||
|
||||
public:
|
||||
ObjectFile() = delete;
|
||||
ObjectFile(const ObjectFile &other) = delete;
|
||||
|
||||
uint64_t getCommonSymbolSize(DataRefImpl Symb) const {
|
||||
assert(getSymbolFlags(Symb) & SymbolRef::SF_Common);
|
||||
return getCommonSymbolSizeImpl(Symb);
|
||||
}
|
||||
|
||||
typedef iterator_range<symbol_iterator> symbol_iterator_range;
|
||||
using symbol_iterator_range = iterator_range<symbol_iterator>;
|
||||
symbol_iterator_range symbols() const {
|
||||
return symbol_iterator_range(symbol_begin(), symbol_end());
|
||||
}
|
||||
@ -255,7 +265,7 @@ public:
|
||||
virtual section_iterator section_begin() const = 0;
|
||||
virtual section_iterator section_end() const = 0;
|
||||
|
||||
typedef iterator_range<section_iterator> section_iterator_range;
|
||||
using section_iterator_range = iterator_range<section_iterator>;
|
||||
section_iterator_range sections() const {
|
||||
return section_iterator_range(section_begin(), section_end());
|
||||
}
|
||||
@ -297,7 +307,6 @@ public:
|
||||
return createObjectFile(Object, sys::fs::file_magic::unknown);
|
||||
}
|
||||
|
||||
|
||||
static inline bool classof(const Binary *v) {
|
||||
return v->isObject();
|
||||
}
|
||||
@ -354,7 +363,6 @@ inline const ObjectFile *SymbolRef::getObject() const {
|
||||
return cast<ObjectFile>(O);
|
||||
}
|
||||
|
||||
|
||||
/// SectionRef
|
||||
inline SectionRef::SectionRef(DataRefImpl SectionP,
|
||||
const ObjectFile *Owner)
|
||||
@ -479,8 +487,8 @@ inline const ObjectFile *RelocationRef::getObject() const {
|
||||
return OwningObject;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace object
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_OBJECTFILE_H
|
||||
|
@ -14,10 +14,19 @@
|
||||
#ifndef LLVM_OBJECT_SYMBOLICFILE_H
|
||||
#define LLVM_OBJECT_SYMBOLICFILE_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Object/Binary.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <cinttypes>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
namespace object {
|
||||
@ -29,6 +38,7 @@ union DataRefImpl {
|
||||
uint32_t a, b;
|
||||
} d;
|
||||
uintptr_t p;
|
||||
|
||||
DataRefImpl() { std::memset(this, 0, sizeof(DataRefImpl)); }
|
||||
};
|
||||
|
||||
@ -87,7 +97,7 @@ class SymbolicFile;
|
||||
/// symbols in the object file.
|
||||
class BasicSymbolRef {
|
||||
DataRefImpl SymbolPimpl;
|
||||
const SymbolicFile *OwningObject;
|
||||
const SymbolicFile *OwningObject = nullptr;
|
||||
|
||||
public:
|
||||
enum Flags : unsigned {
|
||||
@ -108,7 +118,7 @@ public:
|
||||
// (IR only)
|
||||
};
|
||||
|
||||
BasicSymbolRef() : OwningObject(nullptr) { }
|
||||
BasicSymbolRef() = default;
|
||||
BasicSymbolRef(DataRefImpl SymbolP, const SymbolicFile *Owner);
|
||||
|
||||
bool operator==(const BasicSymbolRef &Other) const;
|
||||
@ -125,12 +135,12 @@ public:
|
||||
const SymbolicFile *getObject() const;
|
||||
};
|
||||
|
||||
typedef content_iterator<BasicSymbolRef> basic_symbol_iterator;
|
||||
using basic_symbol_iterator = content_iterator<BasicSymbolRef>;
|
||||
|
||||
class SymbolicFile : public Binary {
|
||||
public:
|
||||
~SymbolicFile() override;
|
||||
SymbolicFile(unsigned int Type, MemoryBufferRef Source);
|
||||
~SymbolicFile() override;
|
||||
|
||||
// virtual interface.
|
||||
virtual void moveSymbolNext(DataRefImpl &Symb) const = 0;
|
||||
@ -145,7 +155,7 @@ public:
|
||||
virtual basic_symbol_iterator symbol_end() const = 0;
|
||||
|
||||
// convenience wrappers.
|
||||
typedef iterator_range<basic_symbol_iterator> basic_symbol_iterator_range;
|
||||
using basic_symbol_iterator_range = iterator_range<basic_symbol_iterator>;
|
||||
basic_symbol_iterator_range symbols() const {
|
||||
return basic_symbol_iterator_range(symbol_begin(), symbol_end());
|
||||
}
|
||||
@ -199,7 +209,7 @@ inline const SymbolicFile *BasicSymbolRef::getObject() const {
|
||||
return OwningObject;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // end namespace object
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_OBJECT_SYMBOLICFILE_H
|
||||
|
@ -236,7 +236,7 @@ template <> struct MappingTraits<DWARFYAML::InitialLength> {
|
||||
static void mapping(IO &IO, DWARFYAML::InitialLength &DWARF);
|
||||
};
|
||||
|
||||
#define HANDLE_DW_TAG(unused, name) \
|
||||
#define HANDLE_DW_TAG(unused, name, unused2, unused3) \
|
||||
io.enumCase(value, "DW_TAG_" #name, dwarf::DW_TAG_##name);
|
||||
|
||||
template <> struct ScalarEnumerationTraits<dwarf::Tag> {
|
||||
@ -266,7 +266,7 @@ template <> struct ScalarEnumerationTraits<dwarf::LineNumberExtendedOps> {
|
||||
}
|
||||
};
|
||||
|
||||
#define HANDLE_DW_AT(unused, name) \
|
||||
#define HANDLE_DW_AT(unused, name, unused2, unused3) \
|
||||
io.enumCase(value, "DW_AT_" #name, dwarf::DW_AT_##name);
|
||||
|
||||
template <> struct ScalarEnumerationTraits<dwarf::Attribute> {
|
||||
@ -276,7 +276,7 @@ template <> struct ScalarEnumerationTraits<dwarf::Attribute> {
|
||||
}
|
||||
};
|
||||
|
||||
#define HANDLE_DW_FORM(unused, name) \
|
||||
#define HANDLE_DW_FORM(unused, name, unused2, unused3) \
|
||||
io.enumCase(value, "DW_FORM_" #name, dwarf::DW_FORM_##name);
|
||||
|
||||
template <> struct ScalarEnumerationTraits<dwarf::Form> {
|
||||
|
@ -93,11 +93,7 @@ template <typename PassName> Pass *callTargetMachineCtor(TargetMachine *TM) {
|
||||
/// static RegisterPass<YourPassClassName> tmp("passopt", "My Pass Name");
|
||||
///
|
||||
/// This statement will cause your pass to be created by calling the default
|
||||
/// constructor exposed by the pass. If you have a different constructor that
|
||||
/// must be called, create a global constructor function (which takes the
|
||||
/// arguments you need and returns a Pass*) and register your pass like this:
|
||||
///
|
||||
/// static RegisterPass<PassClassName> tmp("passopt", "My Name");
|
||||
/// constructor exposed by the pass.
|
||||
///
|
||||
template <typename passName> struct RegisterPass : public PassInfo {
|
||||
// Register Pass using default constructor...
|
||||
|
@ -78,33 +78,33 @@ ARM_ARCH("armv7-a", AK_ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7,
|
||||
FK_NEON, ARM::AEK_DSP)
|
||||
ARM_ARCH("armv7ve", AK_ARMV7VE, "7VE", "v7ve", ARMBuildAttrs::CPUArch::v7,
|
||||
FK_NEON, (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT |
|
||||
ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP))
|
||||
ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
|
||||
ARM_ARCH("armv7-r", AK_ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7,
|
||||
FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP))
|
||||
FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
|
||||
ARM_ARCH("armv7-m", AK_ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7,
|
||||
FK_NONE, ARM::AEK_HWDIV)
|
||||
FK_NONE, ARM::AEK_HWDIVTHUMB)
|
||||
ARM_ARCH("armv7e-m", AK_ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M,
|
||||
FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP))
|
||||
FK_NONE, (ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP))
|
||||
ARM_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A,
|
||||
FK_CRYPTO_NEON_FP_ARMV8,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC))
|
||||
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC))
|
||||
ARM_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a",
|
||||
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC))
|
||||
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC))
|
||||
ARM_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a",
|
||||
ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
|
||||
ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS))
|
||||
ARM_ARCH("armv8-r", AK_ARMV8R, "8-R", "v8r", ARMBuildAttrs::CPUArch::v8_R,
|
||||
FK_NEON_FP_ARMV8,
|
||||
(ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIV |
|
||||
(ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB |
|
||||
ARM::AEK_DSP | ARM::AEK_CRC))
|
||||
ARM_ARCH("armv8-m.base", AK_ARMV8MBaseline, "8-M.Baseline", "v8m.base",
|
||||
ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIV)
|
||||
ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIVTHUMB)
|
||||
ARM_ARCH("armv8-m.main", AK_ARMV8MMainline, "8-M.Mainline", "v8m.main",
|
||||
ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIV)
|
||||
ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIVTHUMB)
|
||||
// Non-standard Arch names.
|
||||
ARM_ARCH("iwmmxt", AK_IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE,
|
||||
FK_NONE, ARM::AEK_NONE)
|
||||
@ -128,7 +128,7 @@ ARM_ARCH_EXT_NAME("crc", ARM::AEK_CRC, "+crc", "-crc")
|
||||
ARM_ARCH_EXT_NAME("crypto", ARM::AEK_CRYPTO, "+crypto","-crypto")
|
||||
ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp")
|
||||
ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr)
|
||||
ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV), nullptr, nullptr)
|
||||
ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB), nullptr, nullptr)
|
||||
ARM_ARCH_EXT_NAME("mp", ARM::AEK_MP, nullptr, nullptr)
|
||||
ARM_ARCH_EXT_NAME("simd", ARM::AEK_SIMD, nullptr, nullptr)
|
||||
ARM_ARCH_EXT_NAME("sec", ARM::AEK_SEC, nullptr, nullptr)
|
||||
@ -147,9 +147,9 @@ ARM_ARCH_EXT_NAME("xscale", ARM::AEK_XSCALE, nullptr, nullptr)
|
||||
#endif
|
||||
ARM_HW_DIV_NAME("invalid", ARM::AEK_INVALID)
|
||||
ARM_HW_DIV_NAME("none", ARM::AEK_NONE)
|
||||
ARM_HW_DIV_NAME("thumb", ARM::AEK_HWDIV)
|
||||
ARM_HW_DIV_NAME("thumb", ARM::AEK_HWDIVTHUMB)
|
||||
ARM_HW_DIV_NAME("arm", ARM::AEK_HWDIVARM)
|
||||
ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV))
|
||||
ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
|
||||
#undef ARM_HW_DIV_NAME
|
||||
|
||||
#ifndef ARM_CPU_NAME
|
||||
@ -205,20 +205,20 @@ ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP))
|
||||
ARM_CPU_NAME("cortex-a7", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV))
|
||||
ARM::AEK_HWDIVTHUMB))
|
||||
ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, true, ARM::AEK_SEC)
|
||||
ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP))
|
||||
ARM_CPU_NAME("cortex-a12", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV))
|
||||
ARM::AEK_HWDIVTHUMB))
|
||||
ARM_CPU_NAME("cortex-a15", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV))
|
||||
ARM::AEK_HWDIVTHUMB))
|
||||
ARM_CPU_NAME("cortex-a17", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM |
|
||||
ARM::AEK_HWDIV))
|
||||
ARM::AEK_HWDIVTHUMB))
|
||||
ARM_CPU_NAME("krait", AK_ARMV7A, FK_NEON_VFPV4, false,
|
||||
(ARM::AEK_HWDIVARM | ARM::AEK_HWDIV))
|
||||
(ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
|
||||
ARM_CPU_NAME("cortex-r4", AK_ARMV7R, FK_NONE, true, ARM::AEK_NONE)
|
||||
ARM_CPU_NAME("cortex-r4f", AK_ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE)
|
||||
ARM_CPU_NAME("cortex-r5", AK_ARMV7R, FK_VFPV3_D16, false,
|
||||
@ -249,7 +249,7 @@ ARM_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC)
|
||||
ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, ARM::AEK_NONE)
|
||||
ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, ARM::AEK_NONE)
|
||||
ARM_CPU_NAME("swift", AK_ARMV7S, FK_NEON_VFPV4, true,
|
||||
(ARM::AEK_HWDIVARM | ARM::AEK_HWDIV))
|
||||
(ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB))
|
||||
// Invalid CPU
|
||||
ARM_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, ARM::AEK_INVALID)
|
||||
#undef ARM_CPU_NAME
|
||||
|
@ -47,7 +47,9 @@ template <class T, size_t Align = alignof(T)> class ArrayRecycler {
|
||||
FreeList *Entry = Bucket[Idx];
|
||||
if (!Entry)
|
||||
return nullptr;
|
||||
__asan_unpoison_memory_region(Entry, Capacity::get(Idx).getSize());
|
||||
Bucket[Idx] = Entry->Next;
|
||||
__msan_allocated_memory(Entry, Capacity::get(Idx).getSize());
|
||||
return reinterpret_cast<T*>(Entry);
|
||||
}
|
||||
|
||||
@ -59,6 +61,7 @@ template <class T, size_t Align = alignof(T)> class ArrayRecycler {
|
||||
Bucket.resize(size_t(Idx) + 1);
|
||||
Entry->Next = Bucket[Idx];
|
||||
Bucket[Idx] = Entry;
|
||||
__asan_poison_memory_region(Ptr, Capacity::get(Idx).getSize());
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -162,6 +162,11 @@ public:
|
||||
return ThisValue;
|
||||
}
|
||||
|
||||
ValueType &operator*() {
|
||||
assert(Array && !HasError);
|
||||
return ThisValue;
|
||||
}
|
||||
|
||||
IterType &operator+=(unsigned N) {
|
||||
for (unsigned I = 0; I < N; ++I) {
|
||||
// We are done with the current record, discard it so that we are
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,15 @@ enum LLVMConstants : uint32_t {
|
||||
DWARF_VERSION = 4, // Default dwarf version we output.
|
||||
DW_PUBTYPES_VERSION = 2, // Section version number for .debug_pubtypes.
|
||||
DW_PUBNAMES_VERSION = 2, // Section version number for .debug_pubnames.
|
||||
DW_ARANGES_VERSION = 2 // Section version number for .debug_aranges.
|
||||
DW_ARANGES_VERSION = 2, // Section version number for .debug_aranges.
|
||||
// Identifiers we use to distinguish vendor extensions.
|
||||
DWARF_VENDOR_DWARF = 0, // Defined in v2 or later of the DWARF standard.
|
||||
DWARF_VENDOR_APPLE = 1,
|
||||
DWARF_VENDOR_BORLAND = 2,
|
||||
DWARF_VENDOR_GNU = 3,
|
||||
DWARF_VENDOR_GOOGLE = 4,
|
||||
DWARF_VENDOR_LLVM = 5,
|
||||
DWARF_VENDOR_MIPS = 6
|
||||
};
|
||||
|
||||
// Special ID values that distinguish a CIE from a FDE in DWARF CFI.
|
||||
@ -55,7 +63,7 @@ const uint32_t DW_CIE_ID = UINT32_MAX;
|
||||
const uint64_t DW64_CIE_ID = UINT64_MAX;
|
||||
|
||||
enum Tag : uint16_t {
|
||||
#define HANDLE_DW_TAG(ID, NAME) DW_TAG_##NAME = ID,
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR) DW_TAG_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_TAG_lo_user = 0x4080,
|
||||
DW_TAG_hi_user = 0xffff,
|
||||
@ -92,20 +100,20 @@ inline bool isType(Tag T) {
|
||||
|
||||
/// Attributes.
|
||||
enum Attribute : uint16_t {
|
||||
#define HANDLE_DW_AT(ID, NAME) DW_AT_##NAME = ID,
|
||||
#define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR) DW_AT_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_AT_lo_user = 0x2000,
|
||||
DW_AT_hi_user = 0x3fff,
|
||||
};
|
||||
|
||||
enum Form : uint16_t {
|
||||
#define HANDLE_DW_FORM(ID, NAME) DW_FORM_##NAME = ID,
|
||||
#define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR) DW_FORM_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_FORM_lo_user = 0x1f00, ///< Not specified by DWARF.
|
||||
};
|
||||
|
||||
enum LocationAtom {
|
||||
#define HANDLE_DW_OP(ID, NAME) DW_OP_##NAME = ID,
|
||||
#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR) DW_OP_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_OP_lo_user = 0xe0,
|
||||
DW_OP_hi_user = 0xff,
|
||||
@ -113,7 +121,7 @@ enum LocationAtom {
|
||||
};
|
||||
|
||||
enum TypeKind {
|
||||
#define HANDLE_DW_ATE(ID, NAME) DW_ATE_##NAME = ID,
|
||||
#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR) DW_ATE_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_ATE_lo_user = 0x80,
|
||||
DW_ATE_hi_user = 0xff
|
||||
@ -164,7 +172,7 @@ enum DefaultedMemberAttribute {
|
||||
};
|
||||
|
||||
enum SourceLanguage {
|
||||
#define HANDLE_DW_LANG(ID, NAME) DW_LANG_##NAME = ID,
|
||||
#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) DW_LANG_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_LANG_lo_user = 0x8000,
|
||||
DW_LANG_hi_user = 0xffff
|
||||
@ -220,8 +228,8 @@ enum LineNumberExtendedOps {
|
||||
DW_LNE_hi_user = 0xff
|
||||
};
|
||||
|
||||
enum LinerNumberEntryFormat {
|
||||
#define HANDLE_DW_LNCT(ID, NAME) DW_DEFAULTED_##NAME = ID,
|
||||
enum LineNumberEntryFormat {
|
||||
#define HANDLE_DW_LNCT(ID, NAME) DW_LNCT_##NAME = ID,
|
||||
#include "llvm/Support/Dwarf.def"
|
||||
DW_LNCT_lo_user = 0x2000,
|
||||
DW_LNCT_hi_user = 0x3fff,
|
||||
@ -406,6 +414,40 @@ unsigned getAttributeEncoding(StringRef EncodingString);
|
||||
unsigned getMacinfo(StringRef MacinfoString);
|
||||
/// @}
|
||||
|
||||
/// \defgroup DwarfConstantsVersioning Dwarf version for constants
|
||||
///
|
||||
/// For constants defined by DWARF, returns the DWARF version when the constant
|
||||
/// was first defined. For vendor extensions, if there is a version-related
|
||||
/// policy for when to emit it, returns a version number for that policy.
|
||||
/// Otherwise returns 0.
|
||||
///
|
||||
/// @{
|
||||
unsigned TagVersion(Tag T);
|
||||
unsigned AttributeVersion(Attribute A);
|
||||
unsigned FormVersion(Form F);
|
||||
unsigned OperationVersion(LocationAtom O);
|
||||
unsigned AttributeEncodingVersion(TypeKind E);
|
||||
unsigned LanguageVersion(SourceLanguage L);
|
||||
/// @}
|
||||
|
||||
/// \defgroup DwarfConstantsVendor Dwarf "vendor" for constants
|
||||
///
|
||||
/// These functions return an identifier describing "who" defined the constant,
|
||||
/// either the DWARF standard itself or the vendor who defined the extension.
|
||||
///
|
||||
/// @{
|
||||
unsigned TagVendor(Tag T);
|
||||
unsigned AttributeVendor(Attribute A);
|
||||
unsigned FormVendor(Form F);
|
||||
unsigned OperationVendor(LocationAtom O);
|
||||
unsigned AttributeEncodingVendor(TypeKind E);
|
||||
unsigned LanguageVendor(SourceLanguage L);
|
||||
/// @}
|
||||
|
||||
/// Tells whether the specified form is defined in the specified version,
|
||||
/// or is an extension if extensions are allowed.
|
||||
bool isValidFormForVersion(Form F, unsigned Version, bool ExtensionsOk = true);
|
||||
|
||||
/// \brief Returns the symbolic string representing Val when used as a value
|
||||
/// for attribute Attr.
|
||||
StringRef AttributeValueString(uint16_t Attr, unsigned Val);
|
||||
|
@ -276,32 +276,25 @@ protected:
|
||||
|
||||
// NewBB is split and now it has one successor. Update dominator tree to
|
||||
// reflect this change.
|
||||
template <class N, class GraphT>
|
||||
void Split(DominatorTreeBaseByGraphTraits<GraphT> &DT,
|
||||
typename GraphT::NodeRef NewBB) {
|
||||
template <class N>
|
||||
void Split(typename GraphTraits<N>::NodeRef NewBB) {
|
||||
using GraphT = GraphTraits<N>;
|
||||
using NodeRef = typename GraphT::NodeRef;
|
||||
assert(std::distance(GraphT::child_begin(NewBB),
|
||||
GraphT::child_end(NewBB)) == 1 &&
|
||||
"NewBB should have a single successor!");
|
||||
typename GraphT::NodeRef NewBBSucc = *GraphT::child_begin(NewBB);
|
||||
NodeRef NewBBSucc = *GraphT::child_begin(NewBB);
|
||||
|
||||
std::vector<typename GraphT::NodeRef> PredBlocks;
|
||||
typedef GraphTraits<Inverse<N>> InvTraits;
|
||||
for (typename InvTraits::ChildIteratorType
|
||||
PI = InvTraits::child_begin(NewBB),
|
||||
PE = InvTraits::child_end(NewBB);
|
||||
PI != PE; ++PI)
|
||||
PredBlocks.push_back(*PI);
|
||||
std::vector<NodeRef> PredBlocks;
|
||||
for (const auto Pred : children<Inverse<N>>(NewBB))
|
||||
PredBlocks.push_back(Pred);
|
||||
|
||||
assert(!PredBlocks.empty() && "No predblocks?");
|
||||
|
||||
bool NewBBDominatesNewBBSucc = true;
|
||||
for (typename InvTraits::ChildIteratorType
|
||||
PI = InvTraits::child_begin(NewBBSucc),
|
||||
E = InvTraits::child_end(NewBBSucc);
|
||||
PI != E; ++PI) {
|
||||
typename InvTraits::NodeRef ND = *PI;
|
||||
if (ND != NewBB && !DT.dominates(NewBBSucc, ND) &&
|
||||
DT.isReachableFromEntry(ND)) {
|
||||
for (const auto Pred : children<Inverse<N>>(NewBBSucc)) {
|
||||
if (Pred != NewBB && !dominates(NewBBSucc, Pred) &&
|
||||
isReachableFromEntry(Pred)) {
|
||||
NewBBDominatesNewBBSucc = false;
|
||||
break;
|
||||
}
|
||||
@ -312,7 +305,7 @@ protected:
|
||||
NodeT *NewBBIDom = nullptr;
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < PredBlocks.size(); ++i)
|
||||
if (DT.isReachableFromEntry(PredBlocks[i])) {
|
||||
if (isReachableFromEntry(PredBlocks[i])) {
|
||||
NewBBIDom = PredBlocks[i];
|
||||
break;
|
||||
}
|
||||
@ -324,18 +317,18 @@ protected:
|
||||
return;
|
||||
|
||||
for (i = i + 1; i < PredBlocks.size(); ++i) {
|
||||
if (DT.isReachableFromEntry(PredBlocks[i]))
|
||||
NewBBIDom = DT.findNearestCommonDominator(NewBBIDom, PredBlocks[i]);
|
||||
if (isReachableFromEntry(PredBlocks[i]))
|
||||
NewBBIDom = findNearestCommonDominator(NewBBIDom, PredBlocks[i]);
|
||||
}
|
||||
|
||||
// Create the new dominator tree node... and set the idom of NewBB.
|
||||
DomTreeNodeBase<NodeT> *NewBBNode = DT.addNewBlock(NewBB, NewBBIDom);
|
||||
DomTreeNodeBase<NodeT> *NewBBNode = addNewBlock(NewBB, NewBBIDom);
|
||||
|
||||
// If NewBB strictly dominates other blocks, then it is now the immediate
|
||||
// dominator of NewBBSucc. Update the dominator tree as appropriate.
|
||||
if (NewBBDominatesNewBBSucc) {
|
||||
DomTreeNodeBase<NodeT> *NewBBSuccNode = DT.getNode(NewBBSucc);
|
||||
DT.changeImmediateDominator(NewBBSuccNode, NewBBNode);
|
||||
DomTreeNodeBase<NodeT> *NewBBSuccNode = getNode(NewBBSucc);
|
||||
changeImmediateDominator(NewBBSuccNode, NewBBNode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,7 +372,7 @@ public:
|
||||
if (DomTreeNodes.size() != OtherDomTreeNodes.size())
|
||||
return true;
|
||||
|
||||
for (const auto &DomTreeNode : this->DomTreeNodes) {
|
||||
for (const auto &DomTreeNode : DomTreeNodes) {
|
||||
NodeT *BB = DomTreeNode.first;
|
||||
typename DomTreeNodeMapType::const_iterator OI =
|
||||
OtherDomTreeNodes.find(BB);
|
||||
@ -663,10 +656,9 @@ public:
|
||||
/// tree to reflect this change.
|
||||
void splitBlock(NodeT *NewBB) {
|
||||
if (this->IsPostDominators)
|
||||
this->Split<Inverse<NodeT *>, GraphTraits<Inverse<NodeT *>>>(*this,
|
||||
NewBB);
|
||||
Split<Inverse<NodeT *>>(NewBB);
|
||||
else
|
||||
this->Split<NodeT *, GraphTraits<NodeT *>>(*this, NewBB);
|
||||
Split<NodeT *>(NewBB);
|
||||
}
|
||||
|
||||
/// print - Convert to human readable form
|
||||
@ -677,7 +669,7 @@ public:
|
||||
o << "Inorder PostDominator Tree: ";
|
||||
else
|
||||
o << "Inorder Dominator Tree: ";
|
||||
if (!this->DFSInfoValid)
|
||||
if (!DFSInfoValid)
|
||||
o << "DFSNumbers invalid: " << SlowQueries << " slow queries.";
|
||||
o << "\n";
|
||||
|
||||
@ -712,12 +704,12 @@ protected:
|
||||
// immediate dominator.
|
||||
NodeT *IDom = getIDom(BB);
|
||||
|
||||
assert(IDom || this->DomTreeNodes[nullptr]);
|
||||
assert(IDom || DomTreeNodes[nullptr]);
|
||||
DomTreeNodeBase<NodeT> *IDomNode = getNodeForBlock(IDom);
|
||||
|
||||
// Add a new tree node for this NodeT, and link it as a child of
|
||||
// IDomNode
|
||||
return (this->DomTreeNodes[BB] = IDomNode->addChild(
|
||||
return (DomTreeNodes[BB] = IDomNode->addChild(
|
||||
llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))).get();
|
||||
}
|
||||
|
||||
@ -780,7 +772,7 @@ public:
|
||||
template <class FT> void recalculate(FT &F) {
|
||||
typedef GraphTraits<FT *> TraitsTy;
|
||||
reset();
|
||||
this->Vertex.push_back(nullptr);
|
||||
Vertex.push_back(nullptr);
|
||||
|
||||
if (!this->IsPostDominators) {
|
||||
// Initialize root
|
||||
|
@ -143,10 +143,9 @@ public:
|
||||
|
||||
void writeNodes() {
|
||||
// Loop over the graph, printing it out...
|
||||
for (node_iterator I = GTraits::nodes_begin(G), E = GTraits::nodes_end(G);
|
||||
I != E; ++I)
|
||||
if (!isNodeHidden(*I))
|
||||
writeNode(*I);
|
||||
for (const auto Node : nodes<GraphType>(G))
|
||||
if (!isNodeHidden(Node))
|
||||
writeNode(Node);
|
||||
}
|
||||
|
||||
bool isNodeHidden(NodeRef Node) {
|
||||
|
@ -39,100 +39,123 @@ class raw_ostream;
|
||||
|
||||
class LLT {
|
||||
public:
|
||||
enum TypeKind : uint16_t {
|
||||
Invalid,
|
||||
Scalar,
|
||||
Pointer,
|
||||
Vector,
|
||||
};
|
||||
|
||||
/// Get a low-level scalar or aggregate "bag of bits".
|
||||
static LLT scalar(unsigned SizeInBits) {
|
||||
assert(SizeInBits > 0 && "invalid scalar size");
|
||||
return LLT{Scalar, 1, SizeInBits};
|
||||
return LLT{/*isPointer=*/false, /*isVector=*/false, /*NumElements=*/0,
|
||||
SizeInBits, /*AddressSpace=*/0};
|
||||
}
|
||||
|
||||
/// Get a low-level pointer in the given address space (defaulting to 0).
|
||||
static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits) {
|
||||
return LLT{Pointer, AddressSpace, SizeInBits};
|
||||
assert(SizeInBits > 0 && "invalid pointer size");
|
||||
return LLT{/*isPointer=*/true, /*isVector=*/false, /*NumElements=*/0,
|
||||
SizeInBits, AddressSpace};
|
||||
}
|
||||
|
||||
/// Get a low-level vector of some number of elements and element width.
|
||||
/// \p NumElements must be at least 2.
|
||||
static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits) {
|
||||
assert(NumElements > 1 && "invalid number of vector elements");
|
||||
return LLT{Vector, NumElements, ScalarSizeInBits};
|
||||
assert(ScalarSizeInBits > 0 && "invalid vector element size");
|
||||
return LLT{/*isPointer=*/false, /*isVector=*/true, NumElements,
|
||||
ScalarSizeInBits, /*AddressSpace=*/0};
|
||||
}
|
||||
|
||||
/// Get a low-level vector of some number of elements and element type.
|
||||
static LLT vector(uint16_t NumElements, LLT ScalarTy) {
|
||||
assert(NumElements > 1 && "invalid number of vector elements");
|
||||
assert(ScalarTy.isScalar() && "invalid vector element type");
|
||||
return LLT{Vector, NumElements, ScalarTy.getSizeInBits()};
|
||||
assert(!ScalarTy.isVector() && "invalid vector element type");
|
||||
return LLT{ScalarTy.isPointer(), /*isVector=*/true, NumElements,
|
||||
ScalarTy.getSizeInBits(),
|
||||
ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
|
||||
}
|
||||
|
||||
explicit LLT(TypeKind Kind, uint16_t NumElements, unsigned SizeInBits)
|
||||
: SizeInBits(SizeInBits), ElementsOrAddrSpace(NumElements), Kind(Kind) {
|
||||
assert((Kind != Vector || ElementsOrAddrSpace > 1) &&
|
||||
"invalid number of vector elements");
|
||||
explicit LLT(bool isPointer, bool isVector, uint16_t NumElements,
|
||||
unsigned SizeInBits, unsigned AddressSpace) {
|
||||
init(isPointer, isVector, NumElements, SizeInBits, AddressSpace);
|
||||
}
|
||||
|
||||
explicit LLT() : SizeInBits(0), ElementsOrAddrSpace(0), Kind(Invalid) {}
|
||||
explicit LLT() : IsPointer(false), IsVector(false), RawData(0) {}
|
||||
|
||||
explicit LLT(MVT VT);
|
||||
|
||||
bool isValid() const { return Kind != Invalid; }
|
||||
bool isValid() const { return RawData != 0; }
|
||||
|
||||
bool isScalar() const { return Kind == Scalar; }
|
||||
bool isScalar() const { return isValid() && !IsPointer && !IsVector; }
|
||||
|
||||
bool isPointer() const { return Kind == Pointer; }
|
||||
bool isPointer() const { return isValid() && IsPointer && !IsVector; }
|
||||
|
||||
bool isVector() const { return Kind == Vector; }
|
||||
bool isVector() const { return isValid() && IsVector; }
|
||||
|
||||
/// Returns the number of elements in a vector LLT. Must only be called on
|
||||
/// vector types.
|
||||
uint16_t getNumElements() const {
|
||||
assert(isVector() && "cannot get number of elements on scalar/aggregate");
|
||||
return ElementsOrAddrSpace;
|
||||
assert(IsVector && "cannot get number of elements on scalar/aggregate");
|
||||
if (!IsPointer)
|
||||
return getFieldValue(VectorElementsFieldInfo);
|
||||
else
|
||||
return getFieldValue(PointerVectorElementsFieldInfo);
|
||||
}
|
||||
|
||||
/// Returns the total size of the type. Must only be called on sized types.
|
||||
unsigned getSizeInBits() const {
|
||||
if (isPointer() || isScalar())
|
||||
return SizeInBits;
|
||||
return SizeInBits * ElementsOrAddrSpace;
|
||||
return getScalarSizeInBits();
|
||||
return getScalarSizeInBits() * getNumElements();
|
||||
}
|
||||
|
||||
unsigned getScalarSizeInBits() const {
|
||||
return SizeInBits;
|
||||
assert(RawData != 0 && "Invalid Type");
|
||||
if (!IsVector) {
|
||||
if (!IsPointer)
|
||||
return getFieldValue(ScalarSizeFieldInfo);
|
||||
else
|
||||
return getFieldValue(PointerSizeFieldInfo);
|
||||
} else {
|
||||
if (!IsPointer)
|
||||
return getFieldValue(VectorSizeFieldInfo);
|
||||
else
|
||||
return getFieldValue(PointerVectorSizeFieldInfo);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getAddressSpace() const {
|
||||
assert(isPointer() && "cannot get address space of non-pointer type");
|
||||
return ElementsOrAddrSpace;
|
||||
assert(RawData != 0 && "Invalid Type");
|
||||
assert(IsPointer && "cannot get address space of non-pointer type");
|
||||
if (!IsVector)
|
||||
return getFieldValue(PointerAddressSpaceFieldInfo);
|
||||
else
|
||||
return getFieldValue(PointerVectorAddressSpaceFieldInfo);
|
||||
}
|
||||
|
||||
/// Returns the vector's element type. Only valid for vector types.
|
||||
LLT getElementType() const {
|
||||
assert(isVector() && "cannot get element type of scalar/aggregate");
|
||||
return scalar(SizeInBits);
|
||||
if (IsPointer)
|
||||
return pointer(getAddressSpace(), getScalarSizeInBits());
|
||||
else
|
||||
return scalar(getScalarSizeInBits());
|
||||
}
|
||||
|
||||
/// Get a low-level type with half the size of the original, by halving the
|
||||
/// size of the scalar type involved. For example `s32` will become `s16`,
|
||||
/// `<2 x s32>` will become `<2 x s16>`.
|
||||
LLT halfScalarSize() const {
|
||||
assert(!isPointer() && getScalarSizeInBits() > 1 &&
|
||||
assert(!IsPointer && getScalarSizeInBits() > 1 &&
|
||||
getScalarSizeInBits() % 2 == 0 && "cannot half size of this type");
|
||||
return LLT{Kind, ElementsOrAddrSpace, SizeInBits / 2};
|
||||
return LLT{/*isPointer=*/false, IsVector ? true : false,
|
||||
IsVector ? getNumElements() : (uint16_t)0,
|
||||
getScalarSizeInBits() / 2, /*AddressSpace=*/0};
|
||||
}
|
||||
|
||||
/// Get a low-level type with twice the size of the original, by doubling the
|
||||
/// size of the scalar type involved. For example `s32` will become `s64`,
|
||||
/// `<2 x s32>` will become `<2 x s64>`.
|
||||
LLT doubleScalarSize() const {
|
||||
assert(!isPointer() && "cannot change size of this type");
|
||||
return LLT{Kind, ElementsOrAddrSpace, SizeInBits * 2};
|
||||
assert(!IsPointer && "cannot change size of this type");
|
||||
return LLT{/*isPointer=*/false, IsVector ? true : false,
|
||||
IsVector ? getNumElements() : (uint16_t)0,
|
||||
getScalarSizeInBits() * 2, /*AddressSpace=*/0};
|
||||
}
|
||||
|
||||
/// Get a low-level type with half the size of the original, by halving the
|
||||
@ -140,13 +163,13 @@ public:
|
||||
/// a vector type with an even number of elements. For example `<4 x s32>`
|
||||
/// will become `<2 x s32>`, `<2 x s32>` will become `s32`.
|
||||
LLT halfElements() const {
|
||||
assert(isVector() && ElementsOrAddrSpace % 2 == 0 &&
|
||||
"cannot half odd vector");
|
||||
if (ElementsOrAddrSpace == 2)
|
||||
return scalar(SizeInBits);
|
||||
assert(isVector() && getNumElements() % 2 == 0 && "cannot half odd vector");
|
||||
if (getNumElements() == 2)
|
||||
return scalar(getScalarSizeInBits());
|
||||
|
||||
return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace / 2),
|
||||
SizeInBits};
|
||||
return LLT{/*isPointer=*/false, /*isVector=*/true,
|
||||
(uint16_t)(getNumElements() / 2), getScalarSizeInBits(),
|
||||
/*AddressSpace=*/0};
|
||||
}
|
||||
|
||||
/// Get a low-level type with twice the size of the original, by doubling the
|
||||
@ -154,25 +177,105 @@ public:
|
||||
/// a vector type. For example `<2 x s32>` will become `<4 x s32>`. Doubling
|
||||
/// the number of elements in sN produces <2 x sN>.
|
||||
LLT doubleElements() const {
|
||||
assert(!isPointer() && "cannot double elements in pointer");
|
||||
return LLT{Vector, static_cast<uint16_t>(ElementsOrAddrSpace * 2),
|
||||
SizeInBits};
|
||||
return LLT{IsPointer ? true : false, /*isVector=*/true,
|
||||
(uint16_t)(getNumElements() * 2), getScalarSizeInBits(),
|
||||
IsPointer ? getAddressSpace() : 0};
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
bool operator==(const LLT &RHS) const {
|
||||
return Kind == RHS.Kind && SizeInBits == RHS.SizeInBits &&
|
||||
ElementsOrAddrSpace == RHS.ElementsOrAddrSpace;
|
||||
return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
|
||||
RHS.RawData == RawData;
|
||||
}
|
||||
|
||||
bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
|
||||
|
||||
friend struct DenseMapInfo<LLT>;
|
||||
|
||||
private:
|
||||
unsigned SizeInBits;
|
||||
uint16_t ElementsOrAddrSpace;
|
||||
TypeKind Kind;
|
||||
/// LLT is packed into 64 bits as follows:
|
||||
/// isPointer : 1
|
||||
/// isVector : 1
|
||||
/// with 62 bits remaining for Kind-specific data, packed in bitfields
|
||||
/// as described below. As there isn't a simple portable way to pack bits
|
||||
/// into bitfields, here the different fields in the packed structure is
|
||||
/// described in static const *Field variables. Each of these variables
|
||||
/// is a 2-element array, with the first element describing the bitfield size
|
||||
/// and the second element describing the bitfield offset.
|
||||
typedef int BitFieldInfo[2];
|
||||
///
|
||||
/// This is how the bitfields are packed per Kind:
|
||||
/// * Invalid:
|
||||
/// gets encoded as RawData == 0, as that is an invalid encoding, since for
|
||||
/// valid encodings, SizeInBits/SizeOfElement must be larger than 0.
|
||||
/// * Non-pointer scalar (isPointer == 0 && isVector == 0):
|
||||
/// SizeInBits: 32;
|
||||
static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 0};
|
||||
/// * Pointer (isPointer == 1 && isVector == 0):
|
||||
/// SizeInBits: 16;
|
||||
/// AddressSpace: 23;
|
||||
static const constexpr BitFieldInfo PointerSizeFieldInfo{16, 0};
|
||||
static const constexpr BitFieldInfo PointerAddressSpaceFieldInfo{
|
||||
23, PointerSizeFieldInfo[0] + PointerSizeFieldInfo[1]};
|
||||
/// * Vector-of-non-pointer (isPointer == 0 && isVector == 1):
|
||||
/// NumElements: 16;
|
||||
/// SizeOfElement: 32;
|
||||
static const constexpr BitFieldInfo VectorElementsFieldInfo{16, 0};
|
||||
static const constexpr BitFieldInfo VectorSizeFieldInfo{
|
||||
32, VectorElementsFieldInfo[0] + VectorElementsFieldInfo[1]};
|
||||
/// * Vector-of-pointer (isPointer == 1 && isVector == 1):
|
||||
/// NumElements: 16;
|
||||
/// SizeOfElement: 16;
|
||||
/// AddressSpace: 23;
|
||||
static const constexpr BitFieldInfo PointerVectorElementsFieldInfo{16, 0};
|
||||
static const constexpr BitFieldInfo PointerVectorSizeFieldInfo{
|
||||
16,
|
||||
PointerVectorElementsFieldInfo[1] + PointerVectorElementsFieldInfo[0]};
|
||||
static const constexpr BitFieldInfo PointerVectorAddressSpaceFieldInfo{
|
||||
23, PointerVectorSizeFieldInfo[1] + PointerVectorSizeFieldInfo[0]};
|
||||
|
||||
uint64_t IsPointer : 1;
|
||||
uint64_t IsVector : 1;
|
||||
uint64_t RawData : 62;
|
||||
|
||||
static uint64_t getMask(const BitFieldInfo FieldInfo) {
|
||||
const int FieldSizeInBits = FieldInfo[0];
|
||||
return (((uint64_t)1) << FieldSizeInBits) - 1;
|
||||
}
|
||||
static uint64_t maskAndShift(uint64_t Val, uint64_t Mask, uint8_t Shift) {
|
||||
assert(Val <= Mask && "Value too large for field");
|
||||
return (Val & Mask) << Shift;
|
||||
}
|
||||
static uint64_t maskAndShift(uint64_t Val, const BitFieldInfo FieldInfo) {
|
||||
return maskAndShift(Val, getMask(FieldInfo), FieldInfo[1]);
|
||||
}
|
||||
uint64_t getFieldValue(const BitFieldInfo FieldInfo) const {
|
||||
return getMask(FieldInfo) & (RawData >> FieldInfo[1]);
|
||||
}
|
||||
|
||||
void init(bool IsPointer, bool IsVector, uint16_t NumElements,
|
||||
unsigned SizeInBits, unsigned AddressSpace) {
|
||||
this->IsPointer = IsPointer;
|
||||
this->IsVector = IsVector;
|
||||
if (!IsVector) {
|
||||
if (!IsPointer)
|
||||
RawData = maskAndShift(SizeInBits, ScalarSizeFieldInfo);
|
||||
else
|
||||
RawData = maskAndShift(SizeInBits, PointerSizeFieldInfo) |
|
||||
maskAndShift(AddressSpace, PointerAddressSpaceFieldInfo);
|
||||
} else {
|
||||
assert(NumElements > 1 && "invalid number of vector elements");
|
||||
if (!IsPointer)
|
||||
RawData = maskAndShift(NumElements, VectorElementsFieldInfo) |
|
||||
maskAndShift(SizeInBits, VectorSizeFieldInfo);
|
||||
else
|
||||
RawData =
|
||||
maskAndShift(NumElements, PointerVectorElementsFieldInfo) |
|
||||
maskAndShift(SizeInBits, PointerVectorSizeFieldInfo) |
|
||||
maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
|
||||
@ -182,14 +285,18 @@ inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
|
||||
|
||||
template<> struct DenseMapInfo<LLT> {
|
||||
static inline LLT getEmptyKey() {
|
||||
return LLT{LLT::Invalid, 0, -1u};
|
||||
LLT Invalid;
|
||||
Invalid.IsPointer = true;
|
||||
return Invalid;
|
||||
}
|
||||
static inline LLT getTombstoneKey() {
|
||||
return LLT{LLT::Invalid, 0, -2u};
|
||||
LLT Invalid;
|
||||
Invalid.IsVector = true;
|
||||
return Invalid;
|
||||
}
|
||||
static inline unsigned getHashValue(const LLT &Ty) {
|
||||
uint64_t Val = ((uint64_t)Ty.SizeInBits << 32) |
|
||||
((uint64_t)Ty.ElementsOrAddrSpace << 16) | (uint64_t)Ty.Kind;
|
||||
uint64_t Val = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 |
|
||||
((uint64_t)Ty.IsVector);
|
||||
return DenseMapInfo<uint64_t>::getHashValue(Val);
|
||||
}
|
||||
static bool isEqual(const LLT &LHS, const LLT &RHS) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/Support/SwapByteOrder.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
@ -198,6 +199,21 @@ template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
return countTrailingZeros(Val, ZB_Undefined);
|
||||
}
|
||||
|
||||
/// \brief Create a bitmask with the N right-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskTrailingOnes(unsigned N) {
|
||||
static_assert(std::is_unsigned<T>::value, "Invalid type!");
|
||||
const unsigned Bits = CHAR_BIT * sizeof(T);
|
||||
assert(N <= Bits && "Invalid bit index");
|
||||
return N == 0 ? 0 : (T(-1) >> (Bits - N));
|
||||
}
|
||||
|
||||
/// \brief Create a bitmask with the N left-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T> T maskLeadingOnes(unsigned N) {
|
||||
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// \brief Get the index of the last set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
|
@ -42,13 +42,16 @@ class Recycler {
|
||||
|
||||
FreeNode *pop_val() {
|
||||
auto *Val = FreeList;
|
||||
__asan_unpoison_memory_region(Val, Size);
|
||||
FreeList = FreeList->Next;
|
||||
__msan_allocated_memory(Val, Size);
|
||||
return Val;
|
||||
}
|
||||
|
||||
void push(FreeNode *N) {
|
||||
N->Next = FreeList;
|
||||
FreeList = N;
|
||||
__asan_poison_memory_region(N, Size);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -57,7 +57,7 @@ namespace llvm {
|
||||
|
||||
/// isValid - returns the error encountered during regex compilation, or
|
||||
/// matching, if any.
|
||||
bool isValid(std::string &Error);
|
||||
bool isValid(std::string &Error) const;
|
||||
|
||||
/// getNumMatches - In a valid regex, return the number of parenthesized
|
||||
/// matches it contains. The number filled in by match will include this
|
||||
|
@ -75,7 +75,7 @@ enum ArchExtKind : unsigned {
|
||||
AEK_CRC = 0x2,
|
||||
AEK_CRYPTO = 0x4,
|
||||
AEK_FP = 0x8,
|
||||
AEK_HWDIV = 0x10,
|
||||
AEK_HWDIVTHUMB = 0x10,
|
||||
AEK_HWDIVARM = 0x20,
|
||||
AEK_MP = 0x40,
|
||||
AEK_SIMD = 0x80,
|
||||
|
@ -27,6 +27,8 @@ class StringToOffsetTable {
|
||||
std::string AggregateString;
|
||||
|
||||
public:
|
||||
bool Empty() const { return StringOffset.empty(); }
|
||||
|
||||
unsigned GetOrAddStringOffset(StringRef Str, bool appendZero = true) {
|
||||
auto IterBool =
|
||||
StringOffset.insert(std::make_pair(Str, AggregateString.size()));
|
||||
|
@ -230,6 +230,12 @@ public:
|
||||
return MVT::getIntegerVT(DL.getPointerSizeInBits(AS));
|
||||
}
|
||||
|
||||
/// Return the type for frame index, which is determined by
|
||||
/// the alloca address space specified through the data layout.
|
||||
MVT getFrameIndexTy(const DataLayout &DL) const {
|
||||
return getPointerTy(DL, DL.getAllocaAddrSpace());
|
||||
}
|
||||
|
||||
/// 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;
|
||||
@ -2807,7 +2813,7 @@ public:
|
||||
/// Return true if the target may be able emit the call instruction as a tail
|
||||
/// call. This is used by optimization passes to determine if it's profitable
|
||||
/// to duplicate return instructions to enable tailcall optimization.
|
||||
virtual bool mayBeEmittedAsTailCall(CallInst *) const {
|
||||
virtual bool mayBeEmittedAsTailCall(const CallInst *) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -65,14 +65,6 @@ template <typename T> class ArrayRef;
|
||||
/// Blocks containing EHPads, allocas, invokes, or vastarts are not valid.
|
||||
static bool isBlockValidForExtraction(const BasicBlock &BB);
|
||||
|
||||
/// \brief Create a code extractor for a single basic block.
|
||||
///
|
||||
/// In this formation, we don't require a dominator tree. The given basic
|
||||
/// block is set up for extraction.
|
||||
CodeExtractor(BasicBlock *BB, bool AggregateArgs = false,
|
||||
BlockFrequencyInfo *BFI = nullptr,
|
||||
BranchProbabilityInfo *BPI = nullptr);
|
||||
|
||||
/// \brief Create a code extractor for a sequence of blocks.
|
||||
///
|
||||
/// Given a sequence of basic blocks where the first block in the sequence
|
||||
@ -91,14 +83,6 @@ template <typename T> class ArrayRef;
|
||||
BlockFrequencyInfo *BFI = nullptr,
|
||||
BranchProbabilityInfo *BPI = nullptr);
|
||||
|
||||
/// \brief Create a code extractor for a region node.
|
||||
///
|
||||
/// Behaves just like the generic code sequence constructor, but uses the
|
||||
/// block sequence of the region node passed in.
|
||||
CodeExtractor(DominatorTree &DT, const RegionNode &RN,
|
||||
bool AggregateArgs = false, BlockFrequencyInfo *BFI = nullptr,
|
||||
BranchProbabilityInfo *BPI = nullptr);
|
||||
|
||||
/// \brief Perform the extraction, returning the new function.
|
||||
///
|
||||
/// Returns zero when called on a CodeExtractor instance where isEligible
|
||||
|
@ -59,6 +59,7 @@ struct YAMLXRaySledEntry {
|
||||
yaml::Hex64 Function;
|
||||
SledEntry::FunctionKinds Kind;
|
||||
bool AlwaysInstrument;
|
||||
std::string FunctionName;
|
||||
};
|
||||
|
||||
/// The InstrumentationMap represents the computed function id's and indicated
|
||||
@ -115,6 +116,7 @@ template <> struct MappingTraits<xray::YAMLXRaySledEntry> {
|
||||
IO.mapRequired("function", Entry.Function);
|
||||
IO.mapRequired("kind", Entry.Kind);
|
||||
IO.mapRequired("always-instrument", Entry.AlwaysInstrument);
|
||||
IO.mapOptional("function-name", Entry.FunctionName);
|
||||
}
|
||||
|
||||
static constexpr bool flow = true;
|
||||
|
@ -808,7 +808,7 @@ ModRefInfo BasicAAResult::getModRefInfo(ImmutableCallSite CS,
|
||||
// well. Or alternatively, replace all of this with inaccessiblememonly once
|
||||
// that's implemented fully.
|
||||
auto *Inst = CS.getInstruction();
|
||||
if (isMallocLikeFn(Inst, &TLI) || isCallocLikeFn(Inst, &TLI)) {
|
||||
if (isMallocOrCallocLikeFn(Inst, &TLI)) {
|
||||
// Be conservative if the accessed pointer may alias the allocation -
|
||||
// fallback to the generic handling below.
|
||||
if (getBestAAResults().alias(MemoryLocation(Inst), Loc) == NoAlias)
|
||||
@ -925,9 +925,8 @@ static AliasResult aliasSameBasePointerGEPs(const GEPOperator *GEP1,
|
||||
const DataLayout &DL) {
|
||||
|
||||
assert(GEP1->getPointerOperand()->stripPointerCasts() ==
|
||||
GEP2->getPointerOperand()->stripPointerCasts() &&
|
||||
GEP1->getPointerOperand()->getType() ==
|
||||
GEP2->getPointerOperand()->getType() &&
|
||||
GEP2->getPointerOperand()->stripPointerCasts() &&
|
||||
GEP1->getPointerOperandType() == GEP2->getPointerOperandType() &&
|
||||
"Expected GEPs with the same pointer operand");
|
||||
|
||||
// Try to determine whether GEP1 and GEP2 index through arrays, into structs,
|
||||
@ -1186,9 +1185,8 @@ AliasResult BasicAAResult::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size,
|
||||
// just the same underlying object), see if that tells us anything about
|
||||
// the resulting pointers.
|
||||
if (GEP1->getPointerOperand()->stripPointerCasts() ==
|
||||
GEP2->getPointerOperand()->stripPointerCasts() &&
|
||||
GEP1->getPointerOperand()->getType() ==
|
||||
GEP2->getPointerOperand()->getType()) {
|
||||
GEP2->getPointerOperand()->stripPointerCasts() &&
|
||||
GEP1->getPointerOperandType() == GEP2->getPointerOperandType()) {
|
||||
AliasResult R = aliasSameBasePointerGEPs(GEP1, V1Size, GEP2, V2Size, DL);
|
||||
// If we couldn't find anything interesting, don't abandon just yet.
|
||||
if (R != MayAlias)
|
||||
|
@ -72,6 +72,32 @@ static const uint32_t UR_TAKEN_WEIGHT = 1;
|
||||
/// easily subsume it.
|
||||
static const uint32_t UR_NONTAKEN_WEIGHT = 1024*1024 - 1;
|
||||
|
||||
/// \brief Returns the branch probability for unreachable edge according to
|
||||
/// heuristic.
|
||||
///
|
||||
/// This is the branch probability being taken to a block that terminates
|
||||
/// (eventually) in unreachable. These are predicted as unlikely as possible.
|
||||
static BranchProbability getUnreachableProbability(uint64_t UnreachableCount) {
|
||||
assert(UnreachableCount > 0 && "UnreachableCount must be > 0");
|
||||
return BranchProbability::getBranchProbability(
|
||||
UR_TAKEN_WEIGHT,
|
||||
(UR_TAKEN_WEIGHT + UR_NONTAKEN_WEIGHT) * UnreachableCount);
|
||||
}
|
||||
|
||||
/// \brief Returns the branch probability for reachable edge according to
|
||||
/// heuristic.
|
||||
///
|
||||
/// This is the branch probability not being taken toward a block that
|
||||
/// terminates (eventually) in unreachable. Such a branch is essentially never
|
||||
/// taken. Set the weight to an absurdly high value so that nested loops don't
|
||||
/// easily subsume it.
|
||||
static BranchProbability getReachableProbability(uint64_t ReachableCount) {
|
||||
assert(ReachableCount > 0 && "ReachableCount must be > 0");
|
||||
return BranchProbability::getBranchProbability(
|
||||
UR_NONTAKEN_WEIGHT,
|
||||
(UR_TAKEN_WEIGHT + UR_NONTAKEN_WEIGHT) * ReachableCount);
|
||||
}
|
||||
|
||||
/// \brief Weight for a branch taken going into a cold block.
|
||||
///
|
||||
/// This is the weight for a branch taken toward a block marked
|
||||
@ -179,7 +205,11 @@ BranchProbabilityInfo::updatePostDominatedByColdCall(const BasicBlock *BB) {
|
||||
/// unreachable-terminated block as extremely unlikely.
|
||||
bool BranchProbabilityInfo::calcUnreachableHeuristics(const BasicBlock *BB) {
|
||||
const TerminatorInst *TI = BB->getTerminator();
|
||||
if (TI->getNumSuccessors() == 0)
|
||||
assert(TI->getNumSuccessors() > 1 && "expected more than one successor!");
|
||||
|
||||
// Return false here so that edge weights for InvokeInst could be decided
|
||||
// in calcInvokeHeuristics().
|
||||
if (isa<InvokeInst>(TI))
|
||||
return false;
|
||||
|
||||
SmallVector<unsigned, 4> UnreachableEdges;
|
||||
@ -191,14 +221,8 @@ bool BranchProbabilityInfo::calcUnreachableHeuristics(const BasicBlock *BB) {
|
||||
else
|
||||
ReachableEdges.push_back(I.getSuccessorIndex());
|
||||
|
||||
// Skip probabilities if this block has a single successor or if all were
|
||||
// reachable.
|
||||
if (TI->getNumSuccessors() == 1 || UnreachableEdges.empty())
|
||||
return false;
|
||||
|
||||
// Return false here so that edge weights for InvokeInst could be decided
|
||||
// in calcInvokeHeuristics().
|
||||
if (isa<InvokeInst>(TI))
|
||||
// Skip probabilities if all were reachable.
|
||||
if (UnreachableEdges.empty())
|
||||
return false;
|
||||
|
||||
if (ReachableEdges.empty()) {
|
||||
@ -208,12 +232,8 @@ bool BranchProbabilityInfo::calcUnreachableHeuristics(const BasicBlock *BB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto UnreachableProb = BranchProbability::getBranchProbability(
|
||||
UR_TAKEN_WEIGHT, (UR_TAKEN_WEIGHT + UR_NONTAKEN_WEIGHT) *
|
||||
uint64_t(UnreachableEdges.size()));
|
||||
auto ReachableProb = BranchProbability::getBranchProbability(
|
||||
UR_NONTAKEN_WEIGHT,
|
||||
(UR_TAKEN_WEIGHT + UR_NONTAKEN_WEIGHT) * uint64_t(ReachableEdges.size()));
|
||||
auto UnreachableProb = getUnreachableProbability(UnreachableEdges.size());
|
||||
auto ReachableProb = getReachableProbability(ReachableEdges.size());
|
||||
|
||||
for (unsigned SuccIdx : UnreachableEdges)
|
||||
setEdgeProbability(BB, SuccIdx, UnreachableProb);
|
||||
@ -224,11 +244,12 @@ bool BranchProbabilityInfo::calcUnreachableHeuristics(const BasicBlock *BB) {
|
||||
}
|
||||
|
||||
// Propagate existing explicit probabilities from either profile data or
|
||||
// 'expect' intrinsic processing.
|
||||
// 'expect' intrinsic processing. Examine metadata against unreachable
|
||||
// heuristic. The probability of the edge coming to unreachable block is
|
||||
// set to min of metadata and unreachable heuristic.
|
||||
bool BranchProbabilityInfo::calcMetadataWeights(const BasicBlock *BB) {
|
||||
const TerminatorInst *TI = BB->getTerminator();
|
||||
if (TI->getNumSuccessors() == 1)
|
||||
return false;
|
||||
assert(TI->getNumSuccessors() > 1 && "expected more than one successor!");
|
||||
if (!isa<BranchInst>(TI) && !isa<SwitchInst>(TI))
|
||||
return false;
|
||||
|
||||
@ -249,6 +270,8 @@ bool BranchProbabilityInfo::calcMetadataWeights(const BasicBlock *BB) {
|
||||
// be scaled to fit in 32 bits.
|
||||
uint64_t WeightSum = 0;
|
||||
SmallVector<uint32_t, 2> Weights;
|
||||
SmallVector<unsigned, 2> UnreachableIdxs;
|
||||
SmallVector<unsigned, 2> ReachableIdxs;
|
||||
Weights.reserve(TI->getNumSuccessors());
|
||||
for (unsigned i = 1, e = WeightsNode->getNumOperands(); i != e; ++i) {
|
||||
ConstantInt *Weight =
|
||||
@ -259,6 +282,10 @@ bool BranchProbabilityInfo::calcMetadataWeights(const BasicBlock *BB) {
|
||||
"Too many bits for uint32_t");
|
||||
Weights.push_back(Weight->getZExtValue());
|
||||
WeightSum += Weights.back();
|
||||
if (PostDominatedByUnreachable.count(TI->getSuccessor(i - 1)))
|
||||
UnreachableIdxs.push_back(i - 1);
|
||||
else
|
||||
ReachableIdxs.push_back(i - 1);
|
||||
}
|
||||
assert(Weights.size() == TI->getNumSuccessors() && "Checked above");
|
||||
|
||||
@ -267,20 +294,52 @@ bool BranchProbabilityInfo::calcMetadataWeights(const BasicBlock *BB) {
|
||||
uint64_t ScalingFactor =
|
||||
(WeightSum > UINT32_MAX) ? WeightSum / UINT32_MAX + 1 : 1;
|
||||
|
||||
WeightSum = 0;
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) {
|
||||
Weights[i] /= ScalingFactor;
|
||||
WeightSum += Weights[i];
|
||||
if (ScalingFactor > 1) {
|
||||
WeightSum = 0;
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) {
|
||||
Weights[i] /= ScalingFactor;
|
||||
WeightSum += Weights[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (WeightSum == 0) {
|
||||
if (WeightSum == 0 || ReachableIdxs.size() == 0) {
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
|
||||
setEdgeProbability(BB, i, {1, e});
|
||||
} else {
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
|
||||
setEdgeProbability(BB, i, {Weights[i], static_cast<uint32_t>(WeightSum)});
|
||||
Weights[i] = 1;
|
||||
WeightSum = TI->getNumSuccessors();
|
||||
}
|
||||
|
||||
// Set the probability.
|
||||
SmallVector<BranchProbability, 2> BP;
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
|
||||
BP.push_back({ Weights[i], static_cast<uint32_t>(WeightSum) });
|
||||
|
||||
// Examine the metadata against unreachable heuristic.
|
||||
// If the unreachable heuristic is more strong then we use it for this edge.
|
||||
if (UnreachableIdxs.size() > 0 && ReachableIdxs.size() > 0) {
|
||||
auto ToDistribute = BranchProbability::getZero();
|
||||
auto UnreachableProb = getUnreachableProbability(UnreachableIdxs.size());
|
||||
for (auto i : UnreachableIdxs)
|
||||
if (UnreachableProb < BP[i]) {
|
||||
ToDistribute += BP[i] - UnreachableProb;
|
||||
BP[i] = UnreachableProb;
|
||||
}
|
||||
|
||||
// If we modified the probability of some edges then we must distribute
|
||||
// the difference between reachable blocks.
|
||||
if (ToDistribute > BranchProbability::getZero()) {
|
||||
BranchProbability PerEdge = ToDistribute / ReachableIdxs.size();
|
||||
for (auto i : ReachableIdxs) {
|
||||
BP[i] += PerEdge;
|
||||
ToDistribute -= PerEdge;
|
||||
}
|
||||
// Tail goes to the first reachable edge.
|
||||
BP[ReachableIdxs[0]] += ToDistribute;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i)
|
||||
setEdgeProbability(BB, i, BP[i]);
|
||||
|
||||
assert(WeightSum <= UINT32_MAX &&
|
||||
"Expected weights to scale down to 32 bits");
|
||||
|
||||
@ -297,7 +356,11 @@ bool BranchProbabilityInfo::calcMetadataWeights(const BasicBlock *BB) {
|
||||
/// Return false, otherwise.
|
||||
bool BranchProbabilityInfo::calcColdCallHeuristics(const BasicBlock *BB) {
|
||||
const TerminatorInst *TI = BB->getTerminator();
|
||||
if (TI->getNumSuccessors() == 0)
|
||||
assert(TI->getNumSuccessors() > 1 && "expected more than one successor!");
|
||||
|
||||
// Return false here so that edge weights for InvokeInst could be decided
|
||||
// in calcInvokeHeuristics().
|
||||
if (isa<InvokeInst>(TI))
|
||||
return false;
|
||||
|
||||
// Determine which successors are post-dominated by a cold block.
|
||||
@ -309,13 +372,8 @@ bool BranchProbabilityInfo::calcColdCallHeuristics(const BasicBlock *BB) {
|
||||
else
|
||||
NormalEdges.push_back(I.getSuccessorIndex());
|
||||
|
||||
// Return false here so that edge weights for InvokeInst could be decided
|
||||
// in calcInvokeHeuristics().
|
||||
if (isa<InvokeInst>(TI))
|
||||
return false;
|
||||
|
||||
// Skip probabilities if this block has a single successor.
|
||||
if (TI->getNumSuccessors() == 1 || ColdEdges.empty())
|
||||
// Skip probabilities if no cold edges.
|
||||
if (ColdEdges.empty())
|
||||
return false;
|
||||
|
||||
if (NormalEdges.empty()) {
|
||||
@ -698,10 +756,13 @@ void BranchProbabilityInfo::calculate(const Function &F, const LoopInfo &LI) {
|
||||
DEBUG(dbgs() << "Computing probabilities for " << BB->getName() << "\n");
|
||||
updatePostDominatedByUnreachable(BB);
|
||||
updatePostDominatedByColdCall(BB);
|
||||
if (calcUnreachableHeuristics(BB))
|
||||
// If there is no at least two successors, no sense to set probability.
|
||||
if (BB->getTerminator()->getNumSuccessors() < 2)
|
||||
continue;
|
||||
if (calcMetadataWeights(BB))
|
||||
continue;
|
||||
if (calcUnreachableHeuristics(BB))
|
||||
continue;
|
||||
if (calcColdCallHeuristics(BB))
|
||||
continue;
|
||||
if (calcLoopBranchHeuristics(BB, LI))
|
||||
|
@ -400,8 +400,7 @@ template <typename CFLAA> class CFLGraphBuilder {
|
||||
// TODO: address other common library functions such as realloc(),
|
||||
// strdup(),
|
||||
// etc.
|
||||
if (isMallocLikeFn(Inst, &TLI) || isCallocLikeFn(Inst, &TLI) ||
|
||||
isFreeCall(Inst, &TLI))
|
||||
if (isMallocOrCallocLikeFn(Inst, &TLI) || isFreeCall(Inst, &TLI))
|
||||
return;
|
||||
|
||||
// TODO: Add support for noalias args/all the other fun function
|
||||
|
@ -75,20 +75,16 @@ static Value *SimplifyXorInst(Value *, Value *, const Query &, unsigned);
|
||||
static Value *SimplifyCastInst(unsigned, Value *, Type *,
|
||||
const Query &, unsigned);
|
||||
|
||||
/// For a boolean type, or a vector of boolean type, return false, or
|
||||
/// a vector with every element false, as appropriate for the type.
|
||||
/// For a boolean type or a vector of boolean type, return false or a vector
|
||||
/// with every element false.
|
||||
static Constant *getFalse(Type *Ty) {
|
||||
assert(Ty->getScalarType()->isIntegerTy(1) &&
|
||||
"Expected i1 type or a vector of i1!");
|
||||
return Constant::getNullValue(Ty);
|
||||
return ConstantInt::getFalse(Ty);
|
||||
}
|
||||
|
||||
/// For a boolean type, or a vector of boolean type, return true, or
|
||||
/// a vector with every element true, as appropriate for the type.
|
||||
/// For a boolean type or a vector of boolean type, return true or a vector
|
||||
/// with every element true.
|
||||
static Constant *getTrue(Type *Ty) {
|
||||
assert(Ty->getScalarType()->isIntegerTy(1) &&
|
||||
"Expected i1 type or a vector of i1!");
|
||||
return Constant::getAllOnesValue(Ty);
|
||||
return ConstantInt::getTrue(Ty);
|
||||
}
|
||||
|
||||
/// isSameCompare - Is V equivalent to the comparison "LHS Pred RHS"?
|
||||
@ -572,11 +568,11 @@ static Value *SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
match(Op1, m_Not(m_Specific(Op0))))
|
||||
return Constant::getAllOnesValue(Ty);
|
||||
|
||||
// add nsw/nuw (xor Y, signbit), signbit --> Y
|
||||
// add nsw/nuw (xor Y, signmask), signmask --> Y
|
||||
// The no-wrapping add guarantees that the top bit will be set by the add.
|
||||
// Therefore, the xor must be clearing the already set sign bit of Y.
|
||||
if ((isNSW || isNUW) && match(Op1, m_SignBit()) &&
|
||||
match(Op0, m_Xor(m_Value(Y), m_SignBit())))
|
||||
if ((isNSW || isNUW) && match(Op1, m_SignMask()) &&
|
||||
match(Op0, m_Xor(m_Value(Y), m_SignMask())))
|
||||
return Y;
|
||||
|
||||
/// i1 add -> xor.
|
||||
@ -1085,7 +1081,7 @@ static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
|
||||
if (!isSigned && match(Op0, m_UDiv(m_Value(X), m_ConstantInt(C1))) &&
|
||||
match(Op1, m_ConstantInt(C2))) {
|
||||
bool Overflow;
|
||||
C1->getValue().umul_ov(C2->getValue(), Overflow);
|
||||
(void)C1->getValue().umul_ov(C2->getValue(), Overflow);
|
||||
if (Overflow)
|
||||
return Constant::getNullValue(Op0->getType());
|
||||
}
|
||||
@ -2823,7 +2819,7 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS,
|
||||
return ConstantInt::getTrue(RHS->getContext());
|
||||
}
|
||||
}
|
||||
if (CIVal->isSignBit() && *CI2Val == 1) {
|
||||
if (CIVal->isSignMask() && *CI2Val == 1) {
|
||||
if (Pred == ICmpInst::ICMP_UGT)
|
||||
return ConstantInt::getFalse(RHS->getContext());
|
||||
if (Pred == ICmpInst::ICMP_ULE)
|
||||
@ -3800,6 +3796,8 @@ static Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
|
||||
Type *GEPTy = PointerType::get(LastType, AS);
|
||||
if (VectorType *VT = dyn_cast<VectorType>(Ops[0]->getType()))
|
||||
GEPTy = VectorType::get(GEPTy, VT->getNumElements());
|
||||
else if (VectorType *VT = dyn_cast<VectorType>(Ops[1]->getType()))
|
||||
GEPTy = VectorType::get(GEPTy, VT->getNumElements());
|
||||
|
||||
if (isa<UndefValue>(Ops[0]))
|
||||
return UndefValue::get(GEPTy);
|
||||
@ -4082,6 +4080,60 @@ Value *llvm::SimplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// For the given destination element of a shuffle, peek through shuffles to
|
||||
/// match a root vector source operand that contains that element in the same
|
||||
/// vector lane (ie, the same mask index), so we can eliminate the shuffle(s).
|
||||
static Value *foldIdentityShuffles(int DestElt, Value *Op0, Value *Op1,
|
||||
Constant *Mask, Value *RootVec, int RootElt,
|
||||
unsigned MaxRecurse) {
|
||||
if (!MaxRecurse--)
|
||||
return nullptr;
|
||||
|
||||
// Bail out if any mask value is undefined. That kind of shuffle may be
|
||||
// simplified further based on demanded bits or other folds.
|
||||
int MaskVal = ShuffleVectorInst::getMaskValue(Mask, RootElt);
|
||||
if (MaskVal == -1)
|
||||
return nullptr;
|
||||
|
||||
// The mask value chooses which source operand we need to look at next.
|
||||
Value *SourceOp;
|
||||
int InVecNumElts = Op0->getType()->getVectorNumElements();
|
||||
if (MaskVal < InVecNumElts) {
|
||||
RootElt = MaskVal;
|
||||
SourceOp = Op0;
|
||||
} else {
|
||||
RootElt = MaskVal - InVecNumElts;
|
||||
SourceOp = Op1;
|
||||
}
|
||||
|
||||
// If the source operand is a shuffle itself, look through it to find the
|
||||
// matching root vector.
|
||||
if (auto *SourceShuf = dyn_cast<ShuffleVectorInst>(SourceOp)) {
|
||||
return foldIdentityShuffles(
|
||||
DestElt, SourceShuf->getOperand(0), SourceShuf->getOperand(1),
|
||||
SourceShuf->getMask(), RootVec, RootElt, MaxRecurse);
|
||||
}
|
||||
|
||||
// TODO: Look through bitcasts? What if the bitcast changes the vector element
|
||||
// size?
|
||||
|
||||
// The source operand is not a shuffle. Initialize the root vector value for
|
||||
// this shuffle if that has not been done yet.
|
||||
if (!RootVec)
|
||||
RootVec = SourceOp;
|
||||
|
||||
// Give up as soon as a source operand does not match the existing root value.
|
||||
if (RootVec != SourceOp)
|
||||
return nullptr;
|
||||
|
||||
// The element must be coming from the same lane in the source vector
|
||||
// (although it may have crossed lanes in intermediate shuffles).
|
||||
if (RootElt != DestElt)
|
||||
return nullptr;
|
||||
|
||||
return RootVec;
|
||||
}
|
||||
|
||||
static Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
||||
Type *RetTy, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
@ -4126,7 +4178,28 @@ static Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
||||
OpShuf->getMask()->getSplatValue())
|
||||
return Op1;
|
||||
|
||||
return nullptr;
|
||||
// Don't fold a shuffle with undef mask elements. This may get folded in a
|
||||
// better way using demanded bits or other analysis.
|
||||
// TODO: Should we allow this?
|
||||
for (unsigned i = 0; i != MaskNumElts; ++i)
|
||||
if (ShuffleVectorInst::getMaskValue(Mask, i) == -1)
|
||||
return nullptr;
|
||||
|
||||
// Check if every element of this shuffle can be mapped back to the
|
||||
// corresponding element of a single root vector. If so, we don't need this
|
||||
// shuffle. This handles simple identity shuffles as well as chains of
|
||||
// shuffles that may widen/narrow and/or move elements across lanes and back.
|
||||
Value *RootVec = nullptr;
|
||||
for (unsigned i = 0; i != MaskNumElts; ++i) {
|
||||
// Note that recursion is limited for each vector element, so if any element
|
||||
// exceeds the limit, this will fail to simplify.
|
||||
RootVec = foldIdentityShuffles(i, Op0, Op1, Mask, RootVec, i, MaxRecurse);
|
||||
|
||||
// We can't replace a widening/narrowing shuffle with one of its operands.
|
||||
if (!RootVec || RootVec->getType() != RetTy)
|
||||
return nullptr;
|
||||
}
|
||||
return RootVec;
|
||||
}
|
||||
|
||||
/// Given operands for a ShuffleVectorInst, fold the result or return null.
|
||||
|
@ -37,6 +37,7 @@ enum AllocType : uint8_t {
|
||||
CallocLike = 1<<2, // allocates + bzero
|
||||
ReallocLike = 1<<3, // reallocates
|
||||
StrDupLike = 1<<4,
|
||||
MallocOrCallocLike = MallocLike | CallocLike,
|
||||
AllocLike = MallocLike | CallocLike | StrDupLike,
|
||||
AnyAlloc = AllocLike | ReallocLike
|
||||
};
|
||||
@ -77,8 +78,8 @@ static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = {
|
||||
// TODO: Handle "int posix_memalign(void **, size_t, size_t)"
|
||||
};
|
||||
|
||||
static Function *getCalledFunction(const Value *V, bool LookThroughBitCast,
|
||||
bool &IsNoBuiltin) {
|
||||
static const Function *getCalledFunction(const Value *V, bool LookThroughBitCast,
|
||||
bool &IsNoBuiltin) {
|
||||
// Don't care about intrinsics in this case.
|
||||
if (isa<IntrinsicInst>(V))
|
||||
return nullptr;
|
||||
@ -86,13 +87,13 @@ static Function *getCalledFunction(const Value *V, bool LookThroughBitCast,
|
||||
if (LookThroughBitCast)
|
||||
V = V->stripPointerCasts();
|
||||
|
||||
CallSite CS(const_cast<Value*>(V));
|
||||
ImmutableCallSite CS(V);
|
||||
if (!CS.getInstruction())
|
||||
return nullptr;
|
||||
|
||||
IsNoBuiltin = CS.isNoBuiltin();
|
||||
|
||||
Function *Callee = CS.getCalledFunction();
|
||||
const Function *Callee = CS.getCalledFunction();
|
||||
if (!Callee || !Callee->isDeclaration())
|
||||
return nullptr;
|
||||
return Callee;
|
||||
@ -219,6 +220,14 @@ bool llvm::isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
return getAllocationData(V, CallocLike, TLI, LookThroughBitCast).hasValue();
|
||||
}
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory similiar to malloc or calloc.
|
||||
bool llvm::isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast) {
|
||||
return getAllocationData(V, MallocOrCallocLike, TLI,
|
||||
LookThroughBitCast).hasValue();
|
||||
}
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory (either malloc, calloc, or strdup like).
|
||||
bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
|
@ -1291,7 +1291,6 @@ void MemorySSA::buildMemorySSA() {
|
||||
// could just look up the memory access for every possible instruction in the
|
||||
// stream.
|
||||
SmallPtrSet<BasicBlock *, 32> DefiningBlocks;
|
||||
SmallPtrSet<BasicBlock *, 32> DefUseBlocks;
|
||||
// Go through each block, figure out where defs occur, and chain together all
|
||||
// the accesses.
|
||||
for (BasicBlock &B : F) {
|
||||
@ -1316,8 +1315,6 @@ void MemorySSA::buildMemorySSA() {
|
||||
}
|
||||
if (InsertIntoDef)
|
||||
DefiningBlocks.insert(&B);
|
||||
if (Accesses)
|
||||
DefUseBlocks.insert(&B);
|
||||
}
|
||||
placePHINodes(DefiningBlocks, BBNumbers);
|
||||
|
||||
|
@ -1093,7 +1093,7 @@ static const SCEV *BinomialCoefficient(const SCEV *It, unsigned K,
|
||||
APInt Mult(W, i);
|
||||
unsigned TwoFactors = Mult.countTrailingZeros();
|
||||
T += TwoFactors;
|
||||
Mult = Mult.lshr(TwoFactors);
|
||||
Mult.lshrInPlace(TwoFactors);
|
||||
OddFactorial *= Mult;
|
||||
}
|
||||
|
||||
@ -1276,7 +1276,8 @@ static const SCEV *getUnsignedOverflowLimitForStep(const SCEV *Step,
|
||||
namespace {
|
||||
|
||||
struct ExtendOpTraitsBase {
|
||||
typedef const SCEV *(ScalarEvolution::*GetExtendExprTy)(const SCEV *, Type *);
|
||||
typedef const SCEV *(ScalarEvolution::*GetExtendExprTy)(
|
||||
const SCEV *, Type *, ScalarEvolution::ExtendCacheTy &Cache);
|
||||
};
|
||||
|
||||
// Used to make code generic over signed and unsigned overflow.
|
||||
@ -1305,8 +1306,9 @@ struct ExtendOpTraits<SCEVSignExtendExpr> : public ExtendOpTraitsBase {
|
||||
}
|
||||
};
|
||||
|
||||
const ExtendOpTraitsBase::GetExtendExprTy ExtendOpTraits<
|
||||
SCEVSignExtendExpr>::GetExtendExpr = &ScalarEvolution::getSignExtendExpr;
|
||||
const ExtendOpTraitsBase::GetExtendExprTy
|
||||
ExtendOpTraits<SCEVSignExtendExpr>::GetExtendExpr =
|
||||
&ScalarEvolution::getSignExtendExprCached;
|
||||
|
||||
template <>
|
||||
struct ExtendOpTraits<SCEVZeroExtendExpr> : public ExtendOpTraitsBase {
|
||||
@ -1321,8 +1323,9 @@ struct ExtendOpTraits<SCEVZeroExtendExpr> : public ExtendOpTraitsBase {
|
||||
}
|
||||
};
|
||||
|
||||
const ExtendOpTraitsBase::GetExtendExprTy ExtendOpTraits<
|
||||
SCEVZeroExtendExpr>::GetExtendExpr = &ScalarEvolution::getZeroExtendExpr;
|
||||
const ExtendOpTraitsBase::GetExtendExprTy
|
||||
ExtendOpTraits<SCEVZeroExtendExpr>::GetExtendExpr =
|
||||
&ScalarEvolution::getZeroExtendExprCached;
|
||||
}
|
||||
|
||||
// The recurrence AR has been shown to have no signed/unsigned wrap or something
|
||||
@ -1334,7 +1337,8 @@ const ExtendOpTraitsBase::GetExtendExprTy ExtendOpTraits<
|
||||
// "sext/zext(PostIncAR)"
|
||||
template <typename ExtendOpTy>
|
||||
static const SCEV *getPreStartForExtend(const SCEVAddRecExpr *AR, Type *Ty,
|
||||
ScalarEvolution *SE) {
|
||||
ScalarEvolution *SE,
|
||||
ScalarEvolution::ExtendCacheTy &Cache) {
|
||||
auto WrapType = ExtendOpTraits<ExtendOpTy>::WrapType;
|
||||
auto GetExtendExpr = ExtendOpTraits<ExtendOpTy>::GetExtendExpr;
|
||||
|
||||
@ -1381,9 +1385,9 @@ static const SCEV *getPreStartForExtend(const SCEVAddRecExpr *AR, Type *Ty,
|
||||
unsigned BitWidth = SE->getTypeSizeInBits(AR->getType());
|
||||
Type *WideTy = IntegerType::get(SE->getContext(), BitWidth * 2);
|
||||
const SCEV *OperandExtendedStart =
|
||||
SE->getAddExpr((SE->*GetExtendExpr)(PreStart, WideTy),
|
||||
(SE->*GetExtendExpr)(Step, WideTy));
|
||||
if ((SE->*GetExtendExpr)(Start, WideTy) == OperandExtendedStart) {
|
||||
SE->getAddExpr((SE->*GetExtendExpr)(PreStart, WideTy, Cache),
|
||||
(SE->*GetExtendExpr)(Step, WideTy, Cache));
|
||||
if ((SE->*GetExtendExpr)(Start, WideTy, Cache) == OperandExtendedStart) {
|
||||
if (PreAR && AR->getNoWrapFlags(WrapType)) {
|
||||
// If we know `AR` == {`PreStart`+`Step`,+,`Step`} is `WrapType` (FlagNSW
|
||||
// or FlagNUW) and that `PreStart` + `Step` is `WrapType` too, then
|
||||
@ -1408,15 +1412,17 @@ static const SCEV *getPreStartForExtend(const SCEVAddRecExpr *AR, Type *Ty,
|
||||
// Get the normalized zero or sign extended expression for this AddRec's Start.
|
||||
template <typename ExtendOpTy>
|
||||
static const SCEV *getExtendAddRecStart(const SCEVAddRecExpr *AR, Type *Ty,
|
||||
ScalarEvolution *SE) {
|
||||
ScalarEvolution *SE,
|
||||
ScalarEvolution::ExtendCacheTy &Cache) {
|
||||
auto GetExtendExpr = ExtendOpTraits<ExtendOpTy>::GetExtendExpr;
|
||||
|
||||
const SCEV *PreStart = getPreStartForExtend<ExtendOpTy>(AR, Ty, SE);
|
||||
const SCEV *PreStart = getPreStartForExtend<ExtendOpTy>(AR, Ty, SE, Cache);
|
||||
if (!PreStart)
|
||||
return (SE->*GetExtendExpr)(AR->getStart(), Ty);
|
||||
return (SE->*GetExtendExpr)(AR->getStart(), Ty, Cache);
|
||||
|
||||
return SE->getAddExpr((SE->*GetExtendExpr)(AR->getStepRecurrence(*SE), Ty),
|
||||
(SE->*GetExtendExpr)(PreStart, Ty));
|
||||
return SE->getAddExpr(
|
||||
(SE->*GetExtendExpr)(AR->getStepRecurrence(*SE), Ty, Cache),
|
||||
(SE->*GetExtendExpr)(PreStart, Ty, Cache));
|
||||
}
|
||||
|
||||
// Try to prove away overflow by looking at "nearby" add recurrences. A
|
||||
@ -1496,8 +1502,31 @@ bool ScalarEvolution::proveNoWrapByVaryingStart(const SCEV *Start,
|
||||
return false;
|
||||
}
|
||||
|
||||
const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
Type *Ty) {
|
||||
const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op, Type *Ty) {
|
||||
// Use the local cache to prevent exponential behavior of
|
||||
// getZeroExtendExprImpl.
|
||||
ExtendCacheTy Cache;
|
||||
return getZeroExtendExprCached(Op, Ty, Cache);
|
||||
}
|
||||
|
||||
/// Query \p Cache before calling getZeroExtendExprImpl. If there is no
|
||||
/// related entry in the \p Cache, call getZeroExtendExprImpl and save
|
||||
/// the result in the \p Cache.
|
||||
const SCEV *ScalarEvolution::getZeroExtendExprCached(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache) {
|
||||
auto It = Cache.find({Op, Ty});
|
||||
if (It != Cache.end())
|
||||
return It->second;
|
||||
const SCEV *ZExt = getZeroExtendExprImpl(Op, Ty, Cache);
|
||||
auto InsertResult = Cache.insert({{Op, Ty}, ZExt});
|
||||
assert(InsertResult.second && "Expect the key was not in the cache");
|
||||
(void)InsertResult;
|
||||
return ZExt;
|
||||
}
|
||||
|
||||
/// The real implementation of getZeroExtendExpr.
|
||||
const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache) {
|
||||
assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&
|
||||
"This is not an extending conversion!");
|
||||
assert(isSCEVable(Ty) &&
|
||||
@ -1507,11 +1536,11 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
// Fold if the operand is constant.
|
||||
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(Op))
|
||||
return getConstant(
|
||||
cast<ConstantInt>(ConstantExpr::getZExt(SC->getValue(), Ty)));
|
||||
cast<ConstantInt>(ConstantExpr::getZExt(SC->getValue(), Ty)));
|
||||
|
||||
// zext(zext(x)) --> zext(x)
|
||||
if (const SCEVZeroExtendExpr *SZ = dyn_cast<SCEVZeroExtendExpr>(Op))
|
||||
return getZeroExtendExpr(SZ->getOperand(), Ty);
|
||||
return getZeroExtendExprCached(SZ->getOperand(), Ty, Cache);
|
||||
|
||||
// Before doing any expensive analysis, check to see if we've already
|
||||
// computed a SCEV for this Op and Ty.
|
||||
@ -1555,8 +1584,8 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
// we don't need to do any further analysis.
|
||||
if (AR->hasNoUnsignedWrap())
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
|
||||
getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Cache),
|
||||
getZeroExtendExprCached(Step, Ty, Cache), L, AR->getNoWrapFlags());
|
||||
|
||||
// Check whether the backedge-taken count is SCEVCouldNotCompute.
|
||||
// Note that this serves two purposes: It filters out loops that are
|
||||
@ -1581,21 +1610,22 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
Type *WideTy = IntegerType::get(getContext(), BitWidth * 2);
|
||||
// Check whether Start+Step*MaxBECount has no unsigned overflow.
|
||||
const SCEV *ZMul = getMulExpr(CastedMaxBECount, Step);
|
||||
const SCEV *ZAdd = getZeroExtendExpr(getAddExpr(Start, ZMul), WideTy);
|
||||
const SCEV *WideStart = getZeroExtendExpr(Start, WideTy);
|
||||
const SCEV *ZAdd =
|
||||
getZeroExtendExprCached(getAddExpr(Start, ZMul), WideTy, Cache);
|
||||
const SCEV *WideStart = getZeroExtendExprCached(Start, WideTy, Cache);
|
||||
const SCEV *WideMaxBECount =
|
||||
getZeroExtendExpr(CastedMaxBECount, WideTy);
|
||||
const SCEV *OperandExtendedAdd =
|
||||
getAddExpr(WideStart,
|
||||
getMulExpr(WideMaxBECount,
|
||||
getZeroExtendExpr(Step, WideTy)));
|
||||
getZeroExtendExprCached(CastedMaxBECount, WideTy, Cache);
|
||||
const SCEV *OperandExtendedAdd = getAddExpr(
|
||||
WideStart, getMulExpr(WideMaxBECount, getZeroExtendExprCached(
|
||||
Step, WideTy, Cache)));
|
||||
if (ZAdd == OperandExtendedAdd) {
|
||||
// Cache knowledge of AR NUW, which is propagated to this AddRec.
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNUW);
|
||||
// Return the expression with the addrec on the outside.
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
|
||||
getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Cache),
|
||||
getZeroExtendExprCached(Step, Ty, Cache), L,
|
||||
AR->getNoWrapFlags());
|
||||
}
|
||||
// Similar to above, only this time treat the step value as signed.
|
||||
// This covers loops that count down.
|
||||
@ -1609,7 +1639,7 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNW);
|
||||
// Return the expression with the addrec on the outside.
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Cache),
|
||||
getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
}
|
||||
}
|
||||
@ -1641,8 +1671,9 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNUW);
|
||||
// Return the expression with the addrec on the outside.
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
|
||||
getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Cache),
|
||||
getZeroExtendExprCached(Step, Ty, Cache), L,
|
||||
AR->getNoWrapFlags());
|
||||
}
|
||||
} else if (isKnownNegative(Step)) {
|
||||
const SCEV *N = getConstant(APInt::getMaxValue(BitWidth) -
|
||||
@ -1657,7 +1688,7 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNW);
|
||||
// Return the expression with the addrec on the outside.
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Cache),
|
||||
getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
}
|
||||
}
|
||||
@ -1666,8 +1697,8 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
if (proveNoWrapByVaryingStart<SCEVZeroExtendExpr>(Start, Step, L)) {
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNUW);
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this),
|
||||
getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, Cache),
|
||||
getZeroExtendExprCached(Step, Ty, Cache), L, AR->getNoWrapFlags());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1678,7 +1709,7 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
// commute the zero extension with the addition operation.
|
||||
SmallVector<const SCEV *, 4> Ops;
|
||||
for (const auto *Op : SA->operands())
|
||||
Ops.push_back(getZeroExtendExpr(Op, Ty));
|
||||
Ops.push_back(getZeroExtendExprCached(Op, Ty, Cache));
|
||||
return getAddExpr(Ops, SCEV::FlagNUW);
|
||||
}
|
||||
}
|
||||
@ -1692,8 +1723,31 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op,
|
||||
return S;
|
||||
}
|
||||
|
||||
const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
Type *Ty) {
|
||||
const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op, Type *Ty) {
|
||||
// Use the local cache to prevent exponential behavior of
|
||||
// getSignExtendExprImpl.
|
||||
ExtendCacheTy Cache;
|
||||
return getSignExtendExprCached(Op, Ty, Cache);
|
||||
}
|
||||
|
||||
/// Query \p Cache before calling getSignExtendExprImpl. If there is no
|
||||
/// related entry in the \p Cache, call getSignExtendExprImpl and save
|
||||
/// the result in the \p Cache.
|
||||
const SCEV *ScalarEvolution::getSignExtendExprCached(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache) {
|
||||
auto It = Cache.find({Op, Ty});
|
||||
if (It != Cache.end())
|
||||
return It->second;
|
||||
const SCEV *SExt = getSignExtendExprImpl(Op, Ty, Cache);
|
||||
auto InsertResult = Cache.insert({{Op, Ty}, SExt});
|
||||
assert(InsertResult.second && "Expect the key was not in the cache");
|
||||
(void)InsertResult;
|
||||
return SExt;
|
||||
}
|
||||
|
||||
/// The real implementation of getSignExtendExpr.
|
||||
const SCEV *ScalarEvolution::getSignExtendExprImpl(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache) {
|
||||
assert(getTypeSizeInBits(Op->getType()) < getTypeSizeInBits(Ty) &&
|
||||
"This is not an extending conversion!");
|
||||
assert(isSCEVable(Ty) &&
|
||||
@ -1703,11 +1757,11 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
// Fold if the operand is constant.
|
||||
if (const SCEVConstant *SC = dyn_cast<SCEVConstant>(Op))
|
||||
return getConstant(
|
||||
cast<ConstantInt>(ConstantExpr::getSExt(SC->getValue(), Ty)));
|
||||
cast<ConstantInt>(ConstantExpr::getSExt(SC->getValue(), Ty)));
|
||||
|
||||
// sext(sext(x)) --> sext(x)
|
||||
if (const SCEVSignExtendExpr *SS = dyn_cast<SCEVSignExtendExpr>(Op))
|
||||
return getSignExtendExpr(SS->getOperand(), Ty);
|
||||
return getSignExtendExprCached(SS->getOperand(), Ty, Cache);
|
||||
|
||||
// sext(zext(x)) --> zext(x)
|
||||
if (const SCEVZeroExtendExpr *SZ = dyn_cast<SCEVZeroExtendExpr>(Op))
|
||||
@ -1746,8 +1800,8 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
const APInt &C2 = SC2->getAPInt();
|
||||
if (C1.isStrictlyPositive() && C2.isStrictlyPositive() &&
|
||||
C2.ugt(C1) && C2.isPowerOf2())
|
||||
return getAddExpr(getSignExtendExpr(SC1, Ty),
|
||||
getSignExtendExpr(SMul, Ty));
|
||||
return getAddExpr(getSignExtendExprCached(SC1, Ty, Cache),
|
||||
getSignExtendExprCached(SMul, Ty, Cache));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1758,7 +1812,7 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
// commute the sign extension with the addition operation.
|
||||
SmallVector<const SCEV *, 4> Ops;
|
||||
for (const auto *Op : SA->operands())
|
||||
Ops.push_back(getSignExtendExpr(Op, Ty));
|
||||
Ops.push_back(getSignExtendExprCached(Op, Ty, Cache));
|
||||
return getAddExpr(Ops, SCEV::FlagNSW);
|
||||
}
|
||||
}
|
||||
@ -1782,8 +1836,8 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
// we don't need to do any further analysis.
|
||||
if (AR->hasNoSignedWrap())
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
|
||||
getSignExtendExpr(Step, Ty), L, SCEV::FlagNSW);
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Cache),
|
||||
getSignExtendExprCached(Step, Ty, Cache), L, SCEV::FlagNSW);
|
||||
|
||||
// Check whether the backedge-taken count is SCEVCouldNotCompute.
|
||||
// Note that this serves two purposes: It filters out loops that are
|
||||
@ -1808,21 +1862,22 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
Type *WideTy = IntegerType::get(getContext(), BitWidth * 2);
|
||||
// Check whether Start+Step*MaxBECount has no signed overflow.
|
||||
const SCEV *SMul = getMulExpr(CastedMaxBECount, Step);
|
||||
const SCEV *SAdd = getSignExtendExpr(getAddExpr(Start, SMul), WideTy);
|
||||
const SCEV *WideStart = getSignExtendExpr(Start, WideTy);
|
||||
const SCEV *SAdd =
|
||||
getSignExtendExprCached(getAddExpr(Start, SMul), WideTy, Cache);
|
||||
const SCEV *WideStart = getSignExtendExprCached(Start, WideTy, Cache);
|
||||
const SCEV *WideMaxBECount =
|
||||
getZeroExtendExpr(CastedMaxBECount, WideTy);
|
||||
const SCEV *OperandExtendedAdd =
|
||||
getAddExpr(WideStart,
|
||||
getMulExpr(WideMaxBECount,
|
||||
getSignExtendExpr(Step, WideTy)));
|
||||
getZeroExtendExpr(CastedMaxBECount, WideTy);
|
||||
const SCEV *OperandExtendedAdd = getAddExpr(
|
||||
WideStart, getMulExpr(WideMaxBECount, getSignExtendExprCached(
|
||||
Step, WideTy, Cache)));
|
||||
if (SAdd == OperandExtendedAdd) {
|
||||
// Cache knowledge of AR NSW, which is propagated to this AddRec.
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNSW);
|
||||
// Return the expression with the addrec on the outside.
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
|
||||
getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Cache),
|
||||
getSignExtendExprCached(Step, Ty, Cache), L,
|
||||
AR->getNoWrapFlags());
|
||||
}
|
||||
// Similar to above, only this time treat the step value as unsigned.
|
||||
// This covers loops that count up with an unsigned step.
|
||||
@ -1843,7 +1898,7 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
|
||||
// Return the expression with the addrec on the outside.
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Cache),
|
||||
getZeroExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
}
|
||||
}
|
||||
@ -1875,8 +1930,9 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
// Cache knowledge of AR NSW, then propagate NSW to the wide AddRec.
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNSW);
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
|
||||
getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Cache),
|
||||
getSignExtendExprCached(Step, Ty, Cache), L,
|
||||
AR->getNoWrapFlags());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1890,18 +1946,18 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op,
|
||||
const APInt &C2 = SC2->getAPInt();
|
||||
if (C1.isStrictlyPositive() && C2.isStrictlyPositive() && C2.ugt(C1) &&
|
||||
C2.isPowerOf2()) {
|
||||
Start = getSignExtendExpr(Start, Ty);
|
||||
Start = getSignExtendExprCached(Start, Ty, Cache);
|
||||
const SCEV *NewAR = getAddRecExpr(getZero(AR->getType()), Step, L,
|
||||
AR->getNoWrapFlags());
|
||||
return getAddExpr(Start, getSignExtendExpr(NewAR, Ty));
|
||||
return getAddExpr(Start, getSignExtendExprCached(NewAR, Ty, Cache));
|
||||
}
|
||||
}
|
||||
|
||||
if (proveNoWrapByVaryingStart<SCEVSignExtendExpr>(Start, Step, L)) {
|
||||
const_cast<SCEVAddRecExpr *>(AR)->setNoWrapFlags(SCEV::FlagNSW);
|
||||
return getAddRecExpr(
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this),
|
||||
getSignExtendExpr(Step, Ty), L, AR->getNoWrapFlags());
|
||||
getExtendAddRecStart<SCEVSignExtendExpr>(AR, Ty, this, Cache),
|
||||
getSignExtendExprCached(Step, Ty, Cache), L, AR->getNoWrapFlags());
|
||||
}
|
||||
}
|
||||
|
||||
@ -3951,9 +4007,9 @@ static Optional<BinaryOp> MatchBinaryOp(Value *V, DominatorTree &DT) {
|
||||
|
||||
case Instruction::Xor:
|
||||
if (auto *RHSC = dyn_cast<ConstantInt>(Op->getOperand(1)))
|
||||
// If the RHS of the xor is a signbit, then this is just an add.
|
||||
// Instcombine turns add of signbit into xor as a strength reduction step.
|
||||
if (RHSC->getValue().isSignBit())
|
||||
// If the RHS of the xor is a signmask, then this is just an add.
|
||||
// Instcombine turns add of signmask into xor as a strength reduction step.
|
||||
if (RHSC->getValue().isSignMask())
|
||||
return BinaryOp(Instruction::Add, Op->getOperand(0), Op->getOperand(1));
|
||||
return BinaryOp(Op);
|
||||
|
||||
@ -5272,28 +5328,12 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
|
||||
break;
|
||||
|
||||
case Instruction::Or:
|
||||
// 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;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -5329,7 +5369,7 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
|
||||
// using an add, which is equivalent, and re-apply the zext.
|
||||
APInt Trunc = CI->getValue().trunc(Z0TySize);
|
||||
if (Trunc.zext(getTypeSizeInBits(UTy)) == CI->getValue() &&
|
||||
Trunc.isSignBit())
|
||||
Trunc.isSignMask())
|
||||
return getZeroExtendExpr(getAddExpr(Z0, getConstant(Trunc)),
|
||||
UTy);
|
||||
}
|
||||
|
@ -292,15 +292,15 @@ static void computeKnownBitsAddSub(bool Add, const Value *Op0, const Value *Op1,
|
||||
KnownOne = PossibleSumOne & Known;
|
||||
|
||||
// Are we still trying to solve for the sign bit?
|
||||
if (!Known.isNegative()) {
|
||||
if (!Known.isSignBitSet()) {
|
||||
if (NSW) {
|
||||
// Adding two non-negative numbers, or subtracting a negative number from
|
||||
// a non-negative one, can't wrap into negative.
|
||||
if (LHSKnownZero.isNegative() && KnownZero2.isNegative())
|
||||
if (LHSKnownZero.isSignBitSet() && KnownZero2.isSignBitSet())
|
||||
KnownZero.setSignBit();
|
||||
// Adding two negative numbers, or subtracting a non-negative number from
|
||||
// a negative one, can't wrap into non-negative.
|
||||
else if (LHSKnownOne.isNegative() && KnownOne2.isNegative())
|
||||
else if (LHSKnownOne.isSignBitSet() && KnownOne2.isSignBitSet())
|
||||
KnownOne.setSignBit();
|
||||
}
|
||||
}
|
||||
@ -322,10 +322,10 @@ static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
|
||||
// The product of a number with itself is non-negative.
|
||||
isKnownNonNegative = true;
|
||||
} else {
|
||||
bool isKnownNonNegativeOp1 = KnownZero.isNegative();
|
||||
bool isKnownNonNegativeOp0 = KnownZero2.isNegative();
|
||||
bool isKnownNegativeOp1 = KnownOne.isNegative();
|
||||
bool isKnownNegativeOp0 = KnownOne2.isNegative();
|
||||
bool isKnownNonNegativeOp1 = KnownZero.isSignBitSet();
|
||||
bool isKnownNonNegativeOp0 = KnownZero2.isSignBitSet();
|
||||
bool isKnownNegativeOp1 = KnownOne.isSignBitSet();
|
||||
bool isKnownNegativeOp0 = KnownOne2.isSignBitSet();
|
||||
// The product of two numbers with the same sign is non-negative.
|
||||
isKnownNonNegative = (isKnownNegativeOp1 && isKnownNegativeOp0) ||
|
||||
(isKnownNonNegativeOp1 && isKnownNonNegativeOp0);
|
||||
@ -361,9 +361,9 @@ static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
|
||||
// which case we prefer to follow the result of the direct computation,
|
||||
// though as the program is invoking undefined behaviour we can choose
|
||||
// whatever we like here.
|
||||
if (isKnownNonNegative && !KnownOne.isNegative())
|
||||
if (isKnownNonNegative && !KnownOne.isSignBitSet())
|
||||
KnownZero.setSignBit();
|
||||
else if (isKnownNegative && !KnownZero.isNegative())
|
||||
else if (isKnownNegative && !KnownZero.isSignBitSet())
|
||||
KnownOne.setSignBit();
|
||||
}
|
||||
|
||||
@ -661,8 +661,10 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero,
|
||||
computeKnownBits(A, RHSKnownZero, RHSKnownOne, Depth+1, Query(Q, I));
|
||||
// For those bits in RHS that are known, we can propagate them to known
|
||||
// bits in V shifted to the right by C.
|
||||
KnownZero |= RHSKnownZero.lshr(C->getZExtValue());
|
||||
KnownOne |= RHSKnownOne.lshr(C->getZExtValue());
|
||||
RHSKnownZero.lshrInPlace(C->getZExtValue());
|
||||
KnownZero |= RHSKnownZero;
|
||||
RHSKnownOne.lshrInPlace(C->getZExtValue());
|
||||
KnownOne |= RHSKnownOne;
|
||||
// assume(~(v << c) = a)
|
||||
} else if (match(Arg, m_c_ICmp(Pred, m_Not(m_Shl(m_V, m_ConstantInt(C))),
|
||||
m_Value(A))) &&
|
||||
@ -672,8 +674,10 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero,
|
||||
computeKnownBits(A, RHSKnownZero, RHSKnownOne, Depth+1, Query(Q, I));
|
||||
// For those bits in RHS that are known, we can propagate them inverted
|
||||
// to known bits in V shifted to the right by C.
|
||||
KnownZero |= RHSKnownOne.lshr(C->getZExtValue());
|
||||
KnownOne |= RHSKnownZero.lshr(C->getZExtValue());
|
||||
RHSKnownOne.lshrInPlace(C->getZExtValue());
|
||||
KnownZero |= RHSKnownOne;
|
||||
RHSKnownZero.lshrInPlace(C->getZExtValue());
|
||||
KnownOne |= RHSKnownZero;
|
||||
// assume(v >> c = a)
|
||||
} else if (match(Arg,
|
||||
m_c_ICmp(Pred, m_CombineOr(m_LShr(m_V, m_ConstantInt(C)),
|
||||
@ -707,7 +711,7 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero,
|
||||
APInt RHSKnownZero(BitWidth, 0), RHSKnownOne(BitWidth, 0);
|
||||
computeKnownBits(A, RHSKnownZero, RHSKnownOne, Depth+1, Query(Q, I));
|
||||
|
||||
if (RHSKnownZero.isNegative()) {
|
||||
if (RHSKnownZero.isSignBitSet()) {
|
||||
// We know that the sign bit is zero.
|
||||
KnownZero.setSignBit();
|
||||
}
|
||||
@ -718,7 +722,7 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero,
|
||||
APInt RHSKnownZero(BitWidth, 0), RHSKnownOne(BitWidth, 0);
|
||||
computeKnownBits(A, RHSKnownZero, RHSKnownOne, Depth+1, Query(Q, I));
|
||||
|
||||
if (RHSKnownOne.isAllOnesValue() || RHSKnownZero.isNegative()) {
|
||||
if (RHSKnownOne.isAllOnesValue() || RHSKnownZero.isSignBitSet()) {
|
||||
// We know that the sign bit is zero.
|
||||
KnownZero.setSignBit();
|
||||
}
|
||||
@ -729,7 +733,7 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero,
|
||||
APInt RHSKnownZero(BitWidth, 0), RHSKnownOne(BitWidth, 0);
|
||||
computeKnownBits(A, RHSKnownZero, RHSKnownOne, Depth+1, Query(Q, I));
|
||||
|
||||
if (RHSKnownOne.isNegative()) {
|
||||
if (RHSKnownOne.isSignBitSet()) {
|
||||
// We know that the sign bit is one.
|
||||
KnownOne.setSignBit();
|
||||
}
|
||||
@ -740,7 +744,7 @@ static void computeKnownBitsFromAssume(const Value *V, APInt &KnownZero,
|
||||
APInt RHSKnownZero(BitWidth, 0), RHSKnownOne(BitWidth, 0);
|
||||
computeKnownBits(A, RHSKnownZero, RHSKnownOne, Depth+1, Query(Q, I));
|
||||
|
||||
if (RHSKnownZero.isAllOnesValue() || RHSKnownOne.isNegative()) {
|
||||
if (RHSKnownZero.isAllOnesValue() || RHSKnownOne.isSignBitSet()) {
|
||||
// We know that the sign bit is one.
|
||||
KnownOne.setSignBit();
|
||||
}
|
||||
@ -990,23 +994,23 @@ static void computeKnownBitsFromOperator(const Operator *I, APInt &KnownZero,
|
||||
unsigned MaxHighZeros = 0;
|
||||
if (SPF == SPF_SMAX) {
|
||||
// If both sides are negative, the result is negative.
|
||||
if (KnownOne.isNegative() && KnownOne2.isNegative())
|
||||
if (KnownOne.isSignBitSet() && KnownOne2.isSignBitSet())
|
||||
// We can derive a lower bound on the result by taking the max of the
|
||||
// leading one bits.
|
||||
MaxHighOnes =
|
||||
std::max(KnownOne.countLeadingOnes(), KnownOne2.countLeadingOnes());
|
||||
// If either side is non-negative, the result is non-negative.
|
||||
else if (KnownZero.isNegative() || KnownZero2.isNegative())
|
||||
else if (KnownZero.isSignBitSet() || KnownZero2.isSignBitSet())
|
||||
MaxHighZeros = 1;
|
||||
} else if (SPF == SPF_SMIN) {
|
||||
// If both sides are non-negative, the result is non-negative.
|
||||
if (KnownZero.isNegative() && KnownZero2.isNegative())
|
||||
if (KnownZero.isSignBitSet() && KnownZero2.isSignBitSet())
|
||||
// We can derive an upper bound on the result by taking the max of the
|
||||
// leading zero bits.
|
||||
MaxHighZeros = std::max(KnownZero.countLeadingOnes(),
|
||||
KnownZero2.countLeadingOnes());
|
||||
// If either side is negative, the result is negative.
|
||||
else if (KnownOne.isNegative() || KnownOne2.isNegative())
|
||||
else if (KnownOne.isSignBitSet() || KnownOne2.isSignBitSet())
|
||||
MaxHighOnes = 1;
|
||||
} else if (SPF == SPF_UMAX) {
|
||||
// We can derive a lower bound on the result by taking the max of the
|
||||
@ -1092,14 +1096,14 @@ static void computeKnownBitsFromOperator(const Operator *I, APInt &KnownZero,
|
||||
KZResult.setLowBits(ShiftAmt); // Low bits known 0.
|
||||
// If this shift has "nsw" keyword, then the result is either a poison
|
||||
// value or has the same sign bit as the first operand.
|
||||
if (NSW && KnownZero.isNegative())
|
||||
if (NSW && KnownZero.isSignBitSet())
|
||||
KZResult.setSignBit();
|
||||
return KZResult;
|
||||
};
|
||||
|
||||
auto KOF = [NSW](const APInt &KnownOne, unsigned ShiftAmt) {
|
||||
APInt KOResult = KnownOne << ShiftAmt;
|
||||
if (NSW && KnownOne.isNegative())
|
||||
if (NSW && KnownOne.isSignBitSet())
|
||||
KOResult.setSignBit();
|
||||
return KOResult;
|
||||
};
|
||||
@ -1111,10 +1115,11 @@ static void computeKnownBitsFromOperator(const Operator *I, APInt &KnownZero,
|
||||
}
|
||||
case Instruction::LShr: {
|
||||
// (ushr X, C1) & C2 == 0 iff (-1 >> C1) & C2 == 0
|
||||
auto KZF = [BitWidth](const APInt &KnownZero, unsigned ShiftAmt) {
|
||||
return KnownZero.lshr(ShiftAmt) |
|
||||
// High bits known zero.
|
||||
APInt::getHighBitsSet(BitWidth, ShiftAmt);
|
||||
auto KZF = [](const APInt &KnownZero, unsigned ShiftAmt) {
|
||||
APInt KZResult = KnownZero.lshr(ShiftAmt);
|
||||
// High bits known zero.
|
||||
KZResult.setHighBits(ShiftAmt);
|
||||
return KZResult;
|
||||
};
|
||||
|
||||
auto KOF = [](const APInt &KnownOne, unsigned ShiftAmt) {
|
||||
@ -1169,28 +1174,25 @@ static void computeKnownBitsFromOperator(const Operator *I, APInt &KnownZero,
|
||||
|
||||
// If the first operand is non-negative or has all low bits zero, then
|
||||
// the upper bits are all zero.
|
||||
if (KnownZero2.isNegative() || ((KnownZero2 & LowBits) == LowBits))
|
||||
if (KnownZero2.isSignBitSet() || ((KnownZero2 & LowBits) == LowBits))
|
||||
KnownZero |= ~LowBits;
|
||||
|
||||
// If the first operand is negative and not all low bits are zero, then
|
||||
// the upper bits are all one.
|
||||
if (KnownOne2.isNegative() && ((KnownOne2 & LowBits) != 0))
|
||||
if (KnownOne2.isSignBitSet() && ((KnownOne2 & LowBits) != 0))
|
||||
KnownOne |= ~LowBits;
|
||||
|
||||
assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The sign bit is the LHS's sign bit, except when the result of the
|
||||
// remainder is zero.
|
||||
if (KnownZero.isNonNegative()) {
|
||||
APInt LHSKnownZero(BitWidth, 0), LHSKnownOne(BitWidth, 0);
|
||||
computeKnownBits(I->getOperand(0), LHSKnownZero, LHSKnownOne, Depth + 1,
|
||||
Q);
|
||||
// If it's known zero, our sign bit is also zero.
|
||||
if (LHSKnownZero.isNegative())
|
||||
KnownZero.setSignBit();
|
||||
}
|
||||
computeKnownBits(I->getOperand(0), KnownZero2, KnownOne2, Depth + 1, Q);
|
||||
// If it's known zero, our sign bit is also zero.
|
||||
if (KnownZero2.isSignBitSet())
|
||||
KnownZero.setSignBit();
|
||||
|
||||
break;
|
||||
case Instruction::URem: {
|
||||
@ -1331,24 +1333,24 @@ static void computeKnownBitsFromOperator(const Operator *I, APInt &KnownZero,
|
||||
// (add non-negative, non-negative) --> non-negative
|
||||
// (add negative, negative) --> negative
|
||||
if (Opcode == Instruction::Add) {
|
||||
if (KnownZero2.isNegative() && KnownZero3.isNegative())
|
||||
if (KnownZero2.isSignBitSet() && KnownZero3.isSignBitSet())
|
||||
KnownZero.setSignBit();
|
||||
else if (KnownOne2.isNegative() && KnownOne3.isNegative())
|
||||
else if (KnownOne2.isSignBitSet() && KnownOne3.isSignBitSet())
|
||||
KnownOne.setSignBit();
|
||||
}
|
||||
|
||||
// (sub nsw non-negative, negative) --> non-negative
|
||||
// (sub nsw negative, non-negative) --> negative
|
||||
else if (Opcode == Instruction::Sub && LL == I) {
|
||||
if (KnownZero2.isNegative() && KnownOne3.isNegative())
|
||||
if (KnownZero2.isSignBitSet() && KnownOne3.isSignBitSet())
|
||||
KnownZero.setSignBit();
|
||||
else if (KnownOne2.isNegative() && KnownZero3.isNegative())
|
||||
else if (KnownOne2.isSignBitSet() && KnownZero3.isSignBitSet())
|
||||
KnownOne.setSignBit();
|
||||
}
|
||||
|
||||
// (mul nsw non-negative, non-negative) --> non-negative
|
||||
else if (Opcode == Instruction::Mul && KnownZero2.isNegative() &&
|
||||
KnownZero3.isNegative())
|
||||
else if (Opcode == Instruction::Mul && KnownZero2.isSignBitSet() &&
|
||||
KnownZero3.isSignBitSet())
|
||||
KnownZero.setSignBit();
|
||||
}
|
||||
|
||||
@ -1614,8 +1616,8 @@ void ComputeSignBit(const Value *V, bool &KnownZero, bool &KnownOne,
|
||||
APInt ZeroBits(BitWidth, 0);
|
||||
APInt OneBits(BitWidth, 0);
|
||||
computeKnownBits(V, ZeroBits, OneBits, Depth, Q);
|
||||
KnownOne = OneBits.isNegative();
|
||||
KnownZero = ZeroBits.isNegative();
|
||||
KnownOne = OneBits.isSignBitSet();
|
||||
KnownZero = ZeroBits.isSignBitSet();
|
||||
}
|
||||
|
||||
/// Return true if the given value is known to have exactly one
|
||||
@ -1638,9 +1640,9 @@ bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
|
||||
if (match(V, m_Shl(m_One(), m_Value())))
|
||||
return true;
|
||||
|
||||
// (signbit) >>l X is clearly a power of two if the one is not shifted off the
|
||||
// bottom. If it is shifted off the bottom then the result is undefined.
|
||||
if (match(V, m_LShr(m_SignBit(), m_Value())))
|
||||
// (signmask) >>l X is clearly a power of two if the one is not shifted off
|
||||
// the bottom. If it is shifted off the bottom then the result is undefined.
|
||||
if (match(V, m_LShr(m_SignMask(), m_Value())))
|
||||
return true;
|
||||
|
||||
// The remaining tests are all recursive, so bail out if we hit the limit.
|
||||
@ -2241,7 +2243,7 @@ static unsigned ComputeNumSignBitsImpl(const Value *V, unsigned Depth,
|
||||
|
||||
// If we are subtracting one from a positive number, there is no carry
|
||||
// out of the result.
|
||||
if (KnownZero.isNegative())
|
||||
if (KnownZero.isSignBitSet())
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
@ -2265,7 +2267,7 @@ static unsigned ComputeNumSignBitsImpl(const Value *V, unsigned Depth,
|
||||
|
||||
// If the input is known to be positive (the sign bit is known clear),
|
||||
// the output of the NEG has the same number of sign bits as the input.
|
||||
if (KnownZero.isNegative())
|
||||
if (KnownZero.isSignBitSet())
|
||||
return Tmp2;
|
||||
|
||||
// Otherwise, we treat this like a SUB.
|
||||
@ -2322,10 +2324,10 @@ static unsigned ComputeNumSignBitsImpl(const Value *V, unsigned Depth,
|
||||
|
||||
// If we know that the sign bit is either zero or one, determine the number of
|
||||
// identical bits in the top of the input value.
|
||||
if (KnownZero.isNegative())
|
||||
if (KnownZero.isSignBitSet())
|
||||
return std::max(FirstAnswer, KnownZero.countLeadingOnes());
|
||||
|
||||
if (KnownOne.isNegative())
|
||||
if (KnownOne.isSignBitSet())
|
||||
return std::max(FirstAnswer, KnownOne.countLeadingOnes());
|
||||
|
||||
// computeKnownBits gave us no extra information about the top bits.
|
||||
@ -3556,14 +3558,14 @@ OverflowResult llvm::computeOverflowForUnsignedMul(const Value *LHS,
|
||||
// We know the multiply operation doesn't overflow if the maximum values for
|
||||
// each operand will not overflow after we multiply them together.
|
||||
bool MaxOverflow;
|
||||
LHSMax.umul_ov(RHSMax, MaxOverflow);
|
||||
(void)LHSMax.umul_ov(RHSMax, MaxOverflow);
|
||||
if (!MaxOverflow)
|
||||
return OverflowResult::NeverOverflows;
|
||||
|
||||
// We know it always overflows if multiplying the smallest possible values for
|
||||
// the operands also results in overflow.
|
||||
bool MinOverflow;
|
||||
LHSKnownOne.umul_ov(RHSKnownOne, MinOverflow);
|
||||
(void)LHSKnownOne.umul_ov(RHSKnownOne, MinOverflow);
|
||||
if (MinOverflow)
|
||||
return OverflowResult::AlwaysOverflows;
|
||||
|
||||
|
@ -143,27 +143,24 @@ bool LLParser::ValidateEndOfModule() {
|
||||
FnAttrs.removeAttribute(Attribute::Alignment);
|
||||
}
|
||||
|
||||
AS = AS.addAttributes(
|
||||
Context, AttributeList::FunctionIndex,
|
||||
AttributeList::get(Context, AttributeList::FunctionIndex, FnAttrs));
|
||||
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
||||
AttributeSet::get(Context, FnAttrs));
|
||||
Fn->setAttributes(AS);
|
||||
} else if (CallInst *CI = dyn_cast<CallInst>(V)) {
|
||||
AttributeList AS = CI->getAttributes();
|
||||
AttrBuilder FnAttrs(AS.getFnAttributes());
|
||||
AS = AS.removeAttributes(Context, AttributeList::FunctionIndex);
|
||||
FnAttrs.merge(B);
|
||||
AS = AS.addAttributes(
|
||||
Context, AttributeList::FunctionIndex,
|
||||
AttributeList::get(Context, AttributeList::FunctionIndex, FnAttrs));
|
||||
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
||||
AttributeSet::get(Context, FnAttrs));
|
||||
CI->setAttributes(AS);
|
||||
} else if (InvokeInst *II = dyn_cast<InvokeInst>(V)) {
|
||||
AttributeList AS = II->getAttributes();
|
||||
AttrBuilder FnAttrs(AS.getFnAttributes());
|
||||
AS = AS.removeAttributes(Context, AttributeList::FunctionIndex);
|
||||
FnAttrs.merge(B);
|
||||
AS = AS.addAttributes(
|
||||
Context, AttributeList::FunctionIndex,
|
||||
AttributeList::get(Context, AttributeList::FunctionIndex, FnAttrs));
|
||||
AS = AS.addAttributes(Context, AttributeList::FunctionIndex,
|
||||
AttributeSet::get(Context, FnAttrs));
|
||||
II->setAttributes(AS);
|
||||
} else {
|
||||
llvm_unreachable("invalid object with forward attribute group reference");
|
||||
|
@ -372,15 +372,27 @@ Expected<std::string> readTriple(BitstreamCursor &Stream) {
|
||||
|
||||
class BitcodeReaderBase {
|
||||
protected:
|
||||
BitcodeReaderBase(BitstreamCursor Stream) : Stream(std::move(Stream)) {
|
||||
BitcodeReaderBase(BitstreamCursor Stream, StringRef Strtab)
|
||||
: Stream(std::move(Stream)), Strtab(Strtab) {
|
||||
this->Stream.setBlockInfo(&BlockInfo);
|
||||
}
|
||||
|
||||
BitstreamBlockInfo BlockInfo;
|
||||
BitstreamCursor Stream;
|
||||
StringRef Strtab;
|
||||
|
||||
/// In version 2 of the bitcode we store names of global values and comdats in
|
||||
/// a string table rather than in the VST.
|
||||
bool UseStrtab = false;
|
||||
|
||||
Expected<unsigned> parseVersionRecord(ArrayRef<uint64_t> Record);
|
||||
|
||||
/// If this module uses a string table, pop the reference to the string table
|
||||
/// and return the referenced string and the rest of the record. Otherwise
|
||||
/// just return the record itself.
|
||||
std::pair<StringRef, ArrayRef<uint64_t>>
|
||||
readNameFromStrtab(ArrayRef<uint64_t> Record);
|
||||
|
||||
bool readBlockInfo();
|
||||
|
||||
// Contains an arbitrary and optional string identifying the bitcode producer
|
||||
@ -402,11 +414,22 @@ BitcodeReaderBase::parseVersionRecord(ArrayRef<uint64_t> Record) {
|
||||
if (Record.size() < 1)
|
||||
return error("Invalid record");
|
||||
unsigned ModuleVersion = Record[0];
|
||||
if (ModuleVersion > 1)
|
||||
if (ModuleVersion > 2)
|
||||
return error("Invalid value");
|
||||
UseStrtab = ModuleVersion >= 2;
|
||||
return ModuleVersion;
|
||||
}
|
||||
|
||||
std::pair<StringRef, ArrayRef<uint64_t>>
|
||||
BitcodeReaderBase::readNameFromStrtab(ArrayRef<uint64_t> Record) {
|
||||
if (!UseStrtab)
|
||||
return {"", Record};
|
||||
// Invalid reference. Let the caller complain about the record being empty.
|
||||
if (Record[0] + Record[1] > Strtab.size())
|
||||
return {"", {}};
|
||||
return {StringRef(Strtab.data() + Record[0], Record[1]), Record.slice(2)};
|
||||
}
|
||||
|
||||
class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
|
||||
LLVMContext &Context;
|
||||
Module *TheModule = nullptr;
|
||||
@ -492,8 +515,8 @@ class BitcodeReader : public BitcodeReaderBase, public GVMaterializer {
|
||||
std::vector<std::string> BundleTags;
|
||||
|
||||
public:
|
||||
BitcodeReader(BitstreamCursor Stream, StringRef ProducerIdentification,
|
||||
LLVMContext &Context);
|
||||
BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
|
||||
StringRef ProducerIdentification, LLVMContext &Context);
|
||||
|
||||
Error materializeForwardReferencedFunctions();
|
||||
|
||||
@ -628,7 +651,10 @@ private:
|
||||
|
||||
Expected<Value *> recordValue(SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned NameIndex, Triple &TT);
|
||||
void setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta, Function *F,
|
||||
ArrayRef<uint64_t> Record);
|
||||
Error parseValueSymbolTable(uint64_t Offset = 0);
|
||||
Error parseGlobalValueSymbolTable();
|
||||
Error parseConstants();
|
||||
Error rememberAndSkipFunctionBodies();
|
||||
Error rememberAndSkipFunctionBody();
|
||||
@ -681,12 +707,15 @@ class ModuleSummaryIndexBitcodeReader : public BitcodeReaderBase {
|
||||
std::string SourceFileName;
|
||||
|
||||
public:
|
||||
ModuleSummaryIndexBitcodeReader(
|
||||
BitstreamCursor Stream, ModuleSummaryIndex &TheIndex);
|
||||
ModuleSummaryIndexBitcodeReader(BitstreamCursor Stream, StringRef Strtab,
|
||||
ModuleSummaryIndex &TheIndex);
|
||||
|
||||
Error parseModule(StringRef ModulePath);
|
||||
|
||||
private:
|
||||
void setValueGUID(uint64_t ValueID, StringRef ValueName,
|
||||
GlobalValue::LinkageTypes Linkage,
|
||||
StringRef SourceFileName);
|
||||
Error parseValueSymbolTable(
|
||||
uint64_t Offset,
|
||||
DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap);
|
||||
@ -716,10 +745,10 @@ std::error_code llvm::errorToErrorCodeAndEmitErrors(LLVMContext &Ctx,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
BitcodeReader::BitcodeReader(BitstreamCursor Stream,
|
||||
BitcodeReader::BitcodeReader(BitstreamCursor Stream, StringRef Strtab,
|
||||
StringRef ProducerIdentification,
|
||||
LLVMContext &Context)
|
||||
: BitcodeReaderBase(std::move(Stream)), Context(Context),
|
||||
: BitcodeReaderBase(std::move(Stream), Strtab), Context(Context),
|
||||
ValueList(Context) {
|
||||
this->ProducerIdentification = ProducerIdentification;
|
||||
}
|
||||
@ -1749,6 +1778,54 @@ static uint64_t jumpToValueSymbolTable(uint64_t Offset,
|
||||
return CurrentBit;
|
||||
}
|
||||
|
||||
void BitcodeReader::setDeferredFunctionInfo(unsigned FuncBitcodeOffsetDelta,
|
||||
Function *F,
|
||||
ArrayRef<uint64_t> Record) {
|
||||
// Note that we subtract 1 here because the offset is relative to one word
|
||||
// before the start of the identification or module block, which was
|
||||
// historically always the start of the regular bitcode header.
|
||||
uint64_t FuncWordOffset = Record[1] - 1;
|
||||
uint64_t FuncBitOffset = FuncWordOffset * 32;
|
||||
DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta;
|
||||
// Set the LastFunctionBlockBit to point to the last function block.
|
||||
// Later when parsing is resumed after function materialization,
|
||||
// we can simply skip that last function block.
|
||||
if (FuncBitOffset > LastFunctionBlockBit)
|
||||
LastFunctionBlockBit = FuncBitOffset;
|
||||
}
|
||||
|
||||
/// Read a new-style GlobalValue symbol table.
|
||||
Error BitcodeReader::parseGlobalValueSymbolTable() {
|
||||
unsigned FuncBitcodeOffsetDelta =
|
||||
Stream.getAbbrevIDWidth() + bitc::BlockIDWidth;
|
||||
|
||||
if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID))
|
||||
return error("Invalid record");
|
||||
|
||||
SmallVector<uint64_t, 64> Record;
|
||||
while (true) {
|
||||
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
||||
|
||||
switch (Entry.Kind) {
|
||||
case BitstreamEntry::SubBlock:
|
||||
case BitstreamEntry::Error:
|
||||
return error("Malformed block");
|
||||
case BitstreamEntry::EndBlock:
|
||||
return Error::success();
|
||||
case BitstreamEntry::Record:
|
||||
break;
|
||||
}
|
||||
|
||||
Record.clear();
|
||||
switch (Stream.readRecord(Entry.ID, Record)) {
|
||||
case bitc::VST_CODE_FNENTRY: // [valueid, offset]
|
||||
setDeferredFunctionInfo(FuncBitcodeOffsetDelta,
|
||||
cast<Function>(ValueList[Record[0]]), Record);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the value symbol table at either the current parsing location or
|
||||
/// at the given bit offset if provided.
|
||||
Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
|
||||
@ -1756,8 +1833,18 @@ Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
|
||||
// Pass in the Offset to distinguish between calling for the module-level
|
||||
// VST (where we want to jump to the VST offset) and the function-level
|
||||
// VST (where we don't).
|
||||
if (Offset > 0)
|
||||
if (Offset > 0) {
|
||||
CurrentBit = jumpToValueSymbolTable(Offset, Stream);
|
||||
// If this module uses a string table, read this as a module-level VST.
|
||||
if (UseStrtab) {
|
||||
if (Error Err = parseGlobalValueSymbolTable())
|
||||
return Err;
|
||||
Stream.JumpToBit(CurrentBit);
|
||||
return Error::success();
|
||||
}
|
||||
// Otherwise, the VST will be in a similar format to a function-level VST,
|
||||
// and will contain symbol names.
|
||||
}
|
||||
|
||||
// Compute the delta between the bitcode indices in the VST (the word offset
|
||||
// to the word-aligned ENTER_SUBBLOCK for the function block, and that
|
||||
@ -1818,23 +1905,10 @@ Error BitcodeReader::parseValueSymbolTable(uint64_t Offset) {
|
||||
return Err;
|
||||
Value *V = ValOrErr.get();
|
||||
|
||||
auto *F = dyn_cast<Function>(V);
|
||||
// Ignore function offsets emitted for aliases of functions in older
|
||||
// versions of LLVM.
|
||||
if (!F)
|
||||
break;
|
||||
|
||||
// Note that we subtract 1 here because the offset is relative to one word
|
||||
// before the start of the identification or module block, which was
|
||||
// historically always the start of the regular bitcode header.
|
||||
uint64_t FuncWordOffset = Record[1] - 1;
|
||||
uint64_t FuncBitOffset = FuncWordOffset * 32;
|
||||
DeferredFunctionInfo[F] = FuncBitOffset + FuncBitcodeOffsetDelta;
|
||||
// Set the LastFunctionBlockBit to point to the last function block.
|
||||
// Later when parsing is resumed after function materialization,
|
||||
// we can simply skip that last function block.
|
||||
if (FuncBitOffset > LastFunctionBlockBit)
|
||||
LastFunctionBlockBit = FuncBitOffset;
|
||||
if (auto *F = dyn_cast<Function>(V))
|
||||
setDeferredFunctionInfo(FuncBitcodeOffsetDelta, F, Record);
|
||||
break;
|
||||
}
|
||||
case bitc::VST_CODE_BBENTRY: {
|
||||
@ -2557,6 +2631,7 @@ Error BitcodeReader::globalCleanup() {
|
||||
|
||||
// Look for intrinsic functions which need to be upgraded at some point
|
||||
for (Function &F : *TheModule) {
|
||||
MDLoader->upgradeDebugIntrinsics(F);
|
||||
Function *NewFn;
|
||||
if (UpgradeIntrinsicFunction(&F, NewFn))
|
||||
UpgradedIntrinsics[&F] = NewFn;
|
||||
@ -2626,15 +2701,24 @@ bool BitcodeReaderBase::readBlockInfo() {
|
||||
}
|
||||
|
||||
Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
|
||||
// [selection_kind, name]
|
||||
if (Record.size() < 2)
|
||||
// v1: [selection_kind, name]
|
||||
// v2: [strtab_offset, strtab_size, selection_kind]
|
||||
StringRef Name;
|
||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||
|
||||
if (Record.size() < 1)
|
||||
return error("Invalid record");
|
||||
Comdat::SelectionKind SK = getDecodedComdatSelectionKind(Record[0]);
|
||||
std::string Name;
|
||||
unsigned ComdatNameSize = Record[1];
|
||||
Name.reserve(ComdatNameSize);
|
||||
for (unsigned i = 0; i != ComdatNameSize; ++i)
|
||||
Name += (char)Record[2 + i];
|
||||
std::string OldFormatName;
|
||||
if (!UseStrtab) {
|
||||
if (Record.size() < 2)
|
||||
return error("Invalid record");
|
||||
unsigned ComdatNameSize = Record[1];
|
||||
OldFormatName.reserve(ComdatNameSize);
|
||||
for (unsigned i = 0; i != ComdatNameSize; ++i)
|
||||
OldFormatName += (char)Record[2 + i];
|
||||
Name = OldFormatName;
|
||||
}
|
||||
Comdat *C = TheModule->getOrInsertComdat(Name);
|
||||
C->setSelectionKind(SK);
|
||||
ComdatList.push_back(C);
|
||||
@ -2642,9 +2726,13 @@ Error BitcodeReader::parseComdatRecord(ArrayRef<uint64_t> Record) {
|
||||
}
|
||||
|
||||
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
||||
// [pointer type, isconst, initid, linkage, alignment, section,
|
||||
// v1: [pointer type, isconst, initid, linkage, alignment, section,
|
||||
// visibility, threadlocal, unnamed_addr, externally_initialized,
|
||||
// dllstorageclass, comdat]
|
||||
// dllstorageclass, comdat] (name in VST)
|
||||
// v2: [strtab_offset, strtab_size, v1]
|
||||
StringRef Name;
|
||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||
|
||||
if (Record.size() < 6)
|
||||
return error("Invalid record");
|
||||
Type *Ty = getTypeByID(Record[0]);
|
||||
@ -2692,7 +2780,7 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
||||
ExternallyInitialized = Record[9];
|
||||
|
||||
GlobalVariable *NewGV =
|
||||
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "",
|
||||
new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, Name,
|
||||
nullptr, TLM, AddressSpace, ExternallyInitialized);
|
||||
NewGV->setAlignment(Alignment);
|
||||
if (!Section.empty())
|
||||
@ -2724,9 +2812,13 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
|
||||
}
|
||||
|
||||
Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
// [type, callingconv, isproto, linkage, paramattr, alignment, section,
|
||||
// v1: [type, callingconv, isproto, linkage, paramattr, alignment, section,
|
||||
// visibility, gc, unnamed_addr, prologuedata, dllstorageclass, comdat,
|
||||
// prefixdata]
|
||||
// prefixdata] (name in VST)
|
||||
// v2: [strtab_offset, strtab_size, v1]
|
||||
StringRef Name;
|
||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||
|
||||
if (Record.size() < 8)
|
||||
return error("Invalid record");
|
||||
Type *Ty = getTypeByID(Record[0]);
|
||||
@ -2742,7 +2834,7 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
return error("Invalid calling convention ID");
|
||||
|
||||
Function *Func =
|
||||
Function::Create(FTy, GlobalValue::ExternalLinkage, "", TheModule);
|
||||
Function::Create(FTy, GlobalValue::ExternalLinkage, Name, TheModule);
|
||||
|
||||
Func->setCallingConv(CC);
|
||||
bool isProto = Record[2];
|
||||
@ -2810,11 +2902,15 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
|
||||
|
||||
Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||
unsigned BitCode, ArrayRef<uint64_t> Record) {
|
||||
// ALIAS_OLD: [alias type, aliasee val#, linkage]
|
||||
// ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility,
|
||||
// dllstorageclass]
|
||||
// IFUNC: [alias type, addrspace, aliasee val#, linkage,
|
||||
// visibility, dllstorageclass]
|
||||
// v1 ALIAS_OLD: [alias type, aliasee val#, linkage] (name in VST)
|
||||
// v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility,
|
||||
// dllstorageclass] (name in VST)
|
||||
// v1 IFUNC: [alias type, addrspace, aliasee val#, linkage,
|
||||
// visibility, dllstorageclass] (name in VST)
|
||||
// v2: [strtab_offset, strtab_size, v1]
|
||||
StringRef Name;
|
||||
std::tie(Name, Record) = readNameFromStrtab(Record);
|
||||
|
||||
bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD;
|
||||
if (Record.size() < (3 + (unsigned)NewRecord))
|
||||
return error("Invalid record");
|
||||
@ -2839,10 +2935,10 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
|
||||
GlobalIndirectSymbol *NewGA;
|
||||
if (BitCode == bitc::MODULE_CODE_ALIAS ||
|
||||
BitCode == bitc::MODULE_CODE_ALIAS_OLD)
|
||||
NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "",
|
||||
NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name,
|
||||
TheModule);
|
||||
else
|
||||
NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), "",
|
||||
NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage), Name,
|
||||
nullptr, TheModule);
|
||||
// Old bitcode files didn't have visibility field.
|
||||
// Local linkage must have default visibility.
|
||||
@ -4570,8 +4666,8 @@ std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const {
|
||||
}
|
||||
|
||||
ModuleSummaryIndexBitcodeReader::ModuleSummaryIndexBitcodeReader(
|
||||
BitstreamCursor Cursor, ModuleSummaryIndex &TheIndex)
|
||||
: BitcodeReaderBase(std::move(Cursor)), TheIndex(TheIndex) {}
|
||||
BitstreamCursor Cursor, StringRef Strtab, ModuleSummaryIndex &TheIndex)
|
||||
: BitcodeReaderBase(std::move(Cursor), Strtab), TheIndex(TheIndex) {}
|
||||
|
||||
std::pair<GlobalValue::GUID, GlobalValue::GUID>
|
||||
ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) {
|
||||
@ -4580,12 +4676,32 @@ ModuleSummaryIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) {
|
||||
return VGI->second;
|
||||
}
|
||||
|
||||
void ModuleSummaryIndexBitcodeReader::setValueGUID(
|
||||
uint64_t ValueID, StringRef ValueName, GlobalValue::LinkageTypes Linkage,
|
||||
StringRef SourceFileName) {
|
||||
std::string GlobalId =
|
||||
GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName);
|
||||
auto ValueGUID = GlobalValue::getGUID(GlobalId);
|
||||
auto OriginalNameID = ValueGUID;
|
||||
if (GlobalValue::isLocalLinkage(Linkage))
|
||||
OriginalNameID = GlobalValue::getGUID(ValueName);
|
||||
if (PrintSummaryGUIDs)
|
||||
dbgs() << "GUID " << ValueGUID << "(" << OriginalNameID << ") is "
|
||||
<< ValueName << "\n";
|
||||
ValueIdToCallGraphGUIDMap[ValueID] =
|
||||
std::make_pair(ValueGUID, OriginalNameID);
|
||||
}
|
||||
|
||||
// Specialized value symbol table parser used when reading module index
|
||||
// blocks where we don't actually create global values. The parsed information
|
||||
// is saved in the bitcode reader for use when later parsing summaries.
|
||||
Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
|
||||
uint64_t Offset,
|
||||
DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap) {
|
||||
// With a strtab the VST is not required to parse the summary.
|
||||
if (UseStrtab)
|
||||
return Error::success();
|
||||
|
||||
assert(Offset > 0 && "Expected non-zero VST offset");
|
||||
uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream);
|
||||
|
||||
@ -4627,17 +4743,7 @@ Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
|
||||
assert(VLI != ValueIdToLinkageMap.end() &&
|
||||
"No linkage found for VST entry?");
|
||||
auto Linkage = VLI->second;
|
||||
std::string GlobalId =
|
||||
GlobalValue::getGlobalIdentifier(ValueName, Linkage, SourceFileName);
|
||||
auto ValueGUID = GlobalValue::getGUID(GlobalId);
|
||||
auto OriginalNameID = ValueGUID;
|
||||
if (GlobalValue::isLocalLinkage(Linkage))
|
||||
OriginalNameID = GlobalValue::getGUID(ValueName);
|
||||
if (PrintSummaryGUIDs)
|
||||
dbgs() << "GUID " << ValueGUID << "(" << OriginalNameID << ") is "
|
||||
<< ValueName << "\n";
|
||||
ValueIdToCallGraphGUIDMap[ValueID] =
|
||||
std::make_pair(ValueGUID, OriginalNameID);
|
||||
setValueGUID(ValueID, ValueName, Linkage, SourceFileName);
|
||||
ValueName.clear();
|
||||
break;
|
||||
}
|
||||
@ -4651,18 +4757,7 @@ Error ModuleSummaryIndexBitcodeReader::parseValueSymbolTable(
|
||||
assert(VLI != ValueIdToLinkageMap.end() &&
|
||||
"No linkage found for VST entry?");
|
||||
auto Linkage = VLI->second;
|
||||
std::string FunctionGlobalId = GlobalValue::getGlobalIdentifier(
|
||||
ValueName, VLI->second, SourceFileName);
|
||||
auto FunctionGUID = GlobalValue::getGUID(FunctionGlobalId);
|
||||
auto OriginalNameID = FunctionGUID;
|
||||
if (GlobalValue::isLocalLinkage(Linkage))
|
||||
OriginalNameID = GlobalValue::getGUID(ValueName);
|
||||
if (PrintSummaryGUIDs)
|
||||
dbgs() << "GUID " << FunctionGUID << "(" << OriginalNameID << ") is "
|
||||
<< ValueName << "\n";
|
||||
ValueIdToCallGraphGUIDMap[ValueID] =
|
||||
std::make_pair(FunctionGUID, OriginalNameID);
|
||||
|
||||
setValueGUID(ValueID, ValueName, Linkage, SourceFileName);
|
||||
ValueName.clear();
|
||||
break;
|
||||
}
|
||||
@ -4749,6 +4844,11 @@ Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) {
|
||||
switch (BitCode) {
|
||||
default:
|
||||
break; // Default behavior, ignore unknown content.
|
||||
case bitc::MODULE_CODE_VERSION: {
|
||||
if (Error Err = parseVersionRecord(Record).takeError())
|
||||
return Err;
|
||||
break;
|
||||
}
|
||||
/// MODULE_CODE_SOURCE_FILENAME: [namechar x N]
|
||||
case bitc::MODULE_CODE_SOURCE_FILENAME: {
|
||||
SmallString<128> ValueName;
|
||||
@ -4783,17 +4883,26 @@ Error ModuleSummaryIndexBitcodeReader::parseModule(StringRef ModulePath) {
|
||||
// was historically always the start of the regular bitcode header.
|
||||
VSTOffset = Record[0] - 1;
|
||||
break;
|
||||
// GLOBALVAR: [pointer type, isconst, initid, linkage, ...]
|
||||
// FUNCTION: [type, callingconv, isproto, linkage, ...]
|
||||
// ALIAS: [alias type, addrspace, aliasee val#, linkage, ...]
|
||||
// v1 GLOBALVAR: [pointer type, isconst, initid, linkage, ...]
|
||||
// v1 FUNCTION: [type, callingconv, isproto, linkage, ...]
|
||||
// v1 ALIAS: [alias type, addrspace, aliasee val#, linkage, ...]
|
||||
// v2: [strtab offset, strtab size, v1]
|
||||
case bitc::MODULE_CODE_GLOBALVAR:
|
||||
case bitc::MODULE_CODE_FUNCTION:
|
||||
case bitc::MODULE_CODE_ALIAS: {
|
||||
if (Record.size() <= 3)
|
||||
StringRef Name;
|
||||
ArrayRef<uint64_t> GVRecord;
|
||||
std::tie(Name, GVRecord) = readNameFromStrtab(Record);
|
||||
if (GVRecord.size() <= 3)
|
||||
return error("Invalid record");
|
||||
uint64_t RawLinkage = Record[3];
|
||||
uint64_t RawLinkage = GVRecord[3];
|
||||
GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage);
|
||||
ValueIdToLinkageMap[ValueId++] = Linkage;
|
||||
if (!UseStrtab) {
|
||||
ValueIdToLinkageMap[ValueId++] = Linkage;
|
||||
break;
|
||||
}
|
||||
|
||||
setValueGUID(ValueId++, Name, Linkage, SourceFileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -4904,6 +5013,12 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(
|
||||
switch (BitCode) {
|
||||
default: // Default behavior: ignore.
|
||||
break;
|
||||
case bitc::FS_VALUE_GUID: { // [valueid, refguid]
|
||||
uint64_t ValueID = Record[0];
|
||||
GlobalValue::GUID RefGUID = Record[1];
|
||||
ValueIdToCallGraphGUIDMap[ValueID] = std::make_pair(RefGUID, RefGUID);
|
||||
break;
|
||||
}
|
||||
// FS_PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid,
|
||||
// n x (valueid)]
|
||||
// FS_PERMODULE_PROFILE: [valueid, flags, instcount, numrefs,
|
||||
@ -5208,6 +5323,35 @@ const std::error_category &llvm::BitcodeErrorCategory() {
|
||||
return *ErrorCategory;
|
||||
}
|
||||
|
||||
static Expected<StringRef> readStrtab(BitstreamCursor &Stream) {
|
||||
if (Stream.EnterSubBlock(bitc::STRTAB_BLOCK_ID))
|
||||
return error("Invalid record");
|
||||
|
||||
StringRef Strtab;
|
||||
while (1) {
|
||||
BitstreamEntry Entry = Stream.advance();
|
||||
switch (Entry.Kind) {
|
||||
case BitstreamEntry::EndBlock:
|
||||
return Strtab;
|
||||
|
||||
case BitstreamEntry::Error:
|
||||
return error("Malformed block");
|
||||
|
||||
case BitstreamEntry::SubBlock:
|
||||
if (Stream.SkipBlock())
|
||||
return error("Malformed block");
|
||||
break;
|
||||
|
||||
case BitstreamEntry::Record:
|
||||
StringRef Blob;
|
||||
SmallVector<uint64_t, 1> Record;
|
||||
if (Stream.readRecord(Entry.ID, Record, &Blob) == bitc::STRTAB_BLOB)
|
||||
Strtab = Blob;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// External interface
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -5260,6 +5404,22 @@ llvm::getBitcodeModuleList(MemoryBufferRef Buffer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Entry.ID == bitc::STRTAB_BLOCK_ID) {
|
||||
Expected<StringRef> Strtab = readStrtab(Stream);
|
||||
if (!Strtab)
|
||||
return Strtab.takeError();
|
||||
// This string table is used by every preceding bitcode module that does
|
||||
// not have its own string table. A bitcode file may have multiple
|
||||
// string tables if it was created by binary concatenation, for example
|
||||
// with "llvm-cat -b".
|
||||
for (auto I = Modules.rbegin(), E = Modules.rend(); I != E; ++I) {
|
||||
if (!I->Strtab.empty())
|
||||
break;
|
||||
I->Strtab = *Strtab;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Stream.SkipBlock())
|
||||
return error("Malformed block");
|
||||
continue;
|
||||
@ -5296,8 +5456,8 @@ BitcodeModule::getModuleImpl(LLVMContext &Context, bool MaterializeAll,
|
||||
}
|
||||
|
||||
Stream.JumpToBit(ModuleBit);
|
||||
auto *R =
|
||||
new BitcodeReader(std::move(Stream), ProducerIdentification, Context);
|
||||
auto *R = new BitcodeReader(std::move(Stream), Strtab, ProducerIdentification,
|
||||
Context);
|
||||
|
||||
std::unique_ptr<Module> M =
|
||||
llvm::make_unique<Module>(ModuleIdentifier, Context);
|
||||
@ -5332,7 +5492,7 @@ Expected<std::unique_ptr<ModuleSummaryIndex>> BitcodeModule::getSummary() {
|
||||
Stream.JumpToBit(ModuleBit);
|
||||
|
||||
auto Index = llvm::make_unique<ModuleSummaryIndex>();
|
||||
ModuleSummaryIndexBitcodeReader R(std::move(Stream), *Index);
|
||||
ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, *Index);
|
||||
|
||||
if (Error Err = R.parseModule(ModuleIdentifier))
|
||||
return std::move(Err);
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||
@ -452,6 +453,7 @@ class MetadataLoader::MetadataLoaderImpl {
|
||||
bool StripTBAA = false;
|
||||
bool HasSeenOldLoopTags = false;
|
||||
bool NeedUpgradeToDIGlobalVariableExpression = false;
|
||||
bool NeedDeclareExpressionUpgrade = false;
|
||||
|
||||
/// True if metadata is being parsed for a module being ThinLTO imported.
|
||||
bool IsImporting = false;
|
||||
@ -511,6 +513,26 @@ class MetadataLoader::MetadataLoaderImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a leading DW_OP_deref from DIExpressions in a dbg.declare that
|
||||
/// describes a function argument.
|
||||
void upgradeDeclareExpressions(Function &F) {
|
||||
if (!NeedDeclareExpressionUpgrade)
|
||||
return;
|
||||
|
||||
for (auto &BB : F)
|
||||
for (auto &I : BB)
|
||||
if (auto *DDI = dyn_cast<DbgDeclareInst>(&I))
|
||||
if (auto *DIExpr = DDI->getExpression())
|
||||
if (DIExpr->startsWithDeref() &&
|
||||
dyn_cast_or_null<Argument>(DDI->getAddress())) {
|
||||
SmallVector<uint64_t, 8> Ops;
|
||||
Ops.append(std::next(DIExpr->elements_begin()),
|
||||
DIExpr->elements_end());
|
||||
auto *E = DIExpression::get(Context, Ops);
|
||||
DDI->setOperand(2, MetadataAsValue::get(Context, E));
|
||||
}
|
||||
}
|
||||
|
||||
void upgradeDebugInfo() {
|
||||
upgradeCUSubprograms();
|
||||
upgradeCUVariables();
|
||||
@ -565,6 +587,7 @@ public:
|
||||
|
||||
unsigned size() const { return MetadataList.size(); }
|
||||
void shrinkTo(unsigned N) { MetadataList.shrinkTo(N); }
|
||||
void upgradeDebugIntrinsics(Function &F) { upgradeDeclareExpressions(F); }
|
||||
};
|
||||
|
||||
static Error error(const Twine &Message) {
|
||||
@ -1520,12 +1543,32 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||
return error("Invalid record");
|
||||
|
||||
IsDistinct = Record[0] & 1;
|
||||
bool HasOpFragment = Record[0] & 2;
|
||||
uint64_t Version = Record[0] >> 1;
|
||||
auto Elts = MutableArrayRef<uint64_t>(Record).slice(1);
|
||||
if (!HasOpFragment)
|
||||
if (unsigned N = Elts.size())
|
||||
if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
|
||||
Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
|
||||
unsigned N = Elts.size();
|
||||
// Perform various upgrades.
|
||||
switch (Version) {
|
||||
case 0:
|
||||
if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
|
||||
Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
|
||||
LLVM_FALLTHROUGH;
|
||||
case 1:
|
||||
// Move DW_OP_deref to the end.
|
||||
if (N && Elts[0] == dwarf::DW_OP_deref) {
|
||||
auto End = Elts.end();
|
||||
if (Elts.size() >= 3 && *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment)
|
||||
End = std::prev(End, 3);
|
||||
std::move(std::next(Elts.begin()), End, Elts.begin());
|
||||
*std::prev(End) = dwarf::DW_OP_deref;
|
||||
}
|
||||
NeedDeclareExpressionUpgrade = true;
|
||||
LLVM_FALLTHROUGH;
|
||||
case 2:
|
||||
// Up-to-date!
|
||||
break;
|
||||
default:
|
||||
return error("Invalid record");
|
||||
}
|
||||
|
||||
MetadataList.assignValue(
|
||||
GET_OR_DISTINCT(DIExpression, (Context, makeArrayRef(Record).slice(1))),
|
||||
@ -1858,3 +1901,7 @@ bool MetadataLoader::isStrippingTBAA() { return Pimpl->isStrippingTBAA(); }
|
||||
|
||||
unsigned MetadataLoader::size() const { return Pimpl->size(); }
|
||||
void MetadataLoader::shrinkTo(unsigned N) { return Pimpl->shrinkTo(N); }
|
||||
|
||||
void MetadataLoader::upgradeDebugIntrinsics(Function &F) {
|
||||
return Pimpl->upgradeDebugIntrinsics(F);
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ public:
|
||||
|
||||
unsigned size() const;
|
||||
void shrinkTo(unsigned N);
|
||||
|
||||
/// Perform bitcode upgrades on llvm.dbg.* calls.
|
||||
void upgradeDebugIntrinsics(Function &F);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/UseListOrder.h"
|
||||
#include "llvm/IR/ValueSymbolTable.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
@ -76,26 +77,28 @@ protected:
|
||||
/// The stream created and owned by the client.
|
||||
BitstreamWriter &Stream;
|
||||
|
||||
/// Saves the offset of the VSTOffset record that must eventually be
|
||||
/// backpatched with the offset of the actual VST.
|
||||
uint64_t VSTOffsetPlaceholder = 0;
|
||||
|
||||
public:
|
||||
/// Constructs a BitcodeWriterBase object that writes to the provided
|
||||
/// \p Stream.
|
||||
BitcodeWriterBase(BitstreamWriter &Stream) : Stream(Stream) {}
|
||||
|
||||
protected:
|
||||
bool hasVSTOffsetPlaceholder() { return VSTOffsetPlaceholder != 0; }
|
||||
void writeValueSymbolTableForwardDecl();
|
||||
void writeBitcodeHeader();
|
||||
void writeModuleVersion();
|
||||
};
|
||||
|
||||
void BitcodeWriterBase::writeModuleVersion() {
|
||||
// VERSION: [version#]
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, ArrayRef<uint64_t>{2});
|
||||
}
|
||||
|
||||
/// Class to manage the bitcode writing for a module.
|
||||
class ModuleBitcodeWriter : public BitcodeWriterBase {
|
||||
/// Pointer to the buffer allocated by caller for bitcode writing.
|
||||
const SmallVectorImpl<char> &Buffer;
|
||||
|
||||
StringTableBuilder &StrtabBuilder;
|
||||
|
||||
/// The Module to write to bitcode.
|
||||
const Module &M;
|
||||
|
||||
@ -127,15 +130,20 @@ class ModuleBitcodeWriter : public BitcodeWriterBase {
|
||||
/// Tracks the last value id recorded in the GUIDToValueMap.
|
||||
unsigned GlobalValueId;
|
||||
|
||||
/// Saves the offset of the VSTOffset record that must eventually be
|
||||
/// backpatched with the offset of the actual VST.
|
||||
uint64_t VSTOffsetPlaceholder = 0;
|
||||
|
||||
public:
|
||||
/// Constructs a ModuleBitcodeWriter object for the given Module,
|
||||
/// writing to the provided \p Buffer.
|
||||
ModuleBitcodeWriter(const Module *M, SmallVectorImpl<char> &Buffer,
|
||||
StringTableBuilder &StrtabBuilder,
|
||||
BitstreamWriter &Stream, bool ShouldPreserveUseListOrder,
|
||||
const ModuleSummaryIndex *Index, bool GenerateHash,
|
||||
ModuleHash *ModHash = nullptr)
|
||||
: BitcodeWriterBase(Stream), Buffer(Buffer), M(*M),
|
||||
VE(*M, ShouldPreserveUseListOrder), Index(Index),
|
||||
: BitcodeWriterBase(Stream), Buffer(Buffer), StrtabBuilder(StrtabBuilder),
|
||||
M(*M), VE(*M, ShouldPreserveUseListOrder), Index(Index),
|
||||
GenerateHash(GenerateHash), ModHash(ModHash),
|
||||
BitcodeStartBit(Stream.GetCurrentBitNo()) {
|
||||
// Assign ValueIds to any callee values in the index that came from
|
||||
@ -169,6 +177,7 @@ private:
|
||||
void writeAttributeTable();
|
||||
void writeTypeTable();
|
||||
void writeComdats();
|
||||
void writeValueSymbolTableForwardDecl();
|
||||
void writeModuleInfo();
|
||||
void writeValueAsMetadata(const ValueAsMetadata *MD,
|
||||
SmallVectorImpl<uint64_t> &Record);
|
||||
@ -261,9 +270,9 @@ private:
|
||||
SmallVectorImpl<uint64_t> &Vals);
|
||||
void writeInstruction(const Instruction &I, unsigned InstID,
|
||||
SmallVectorImpl<unsigned> &Vals);
|
||||
void writeValueSymbolTable(
|
||||
const ValueSymbolTable &VST, bool IsModuleLevel = false,
|
||||
DenseMap<const Function *, uint64_t> *FunctionToBitcodeIndex = nullptr);
|
||||
void writeFunctionLevelValueSymbolTable(const ValueSymbolTable &VST);
|
||||
void writeGlobalValueSymbolTable(
|
||||
DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex);
|
||||
void writeUseList(UseListOrder &&Order);
|
||||
void writeUseListBlock(const Function *F);
|
||||
void
|
||||
@ -477,7 +486,6 @@ public:
|
||||
|
||||
private:
|
||||
void writeModStrings();
|
||||
void writeCombinedValueSymbolTable();
|
||||
void writeCombinedGlobalValueSummary();
|
||||
|
||||
/// Indicates whether the provided \p ModulePath should be written into
|
||||
@ -492,15 +500,15 @@ private:
|
||||
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
return VMI != GUIDToValueIdMap.end();
|
||||
}
|
||||
void assignValueId(GlobalValue::GUID ValGUID) {
|
||||
unsigned &ValueId = GUIDToValueIdMap[ValGUID];
|
||||
if (ValueId == 0)
|
||||
ValueId = ++GlobalValueId;
|
||||
}
|
||||
unsigned getValueId(GlobalValue::GUID ValGUID) {
|
||||
const auto &VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
// If this GUID doesn't have an entry, assign one.
|
||||
if (VMI == GUIDToValueIdMap.end()) {
|
||||
GUIDToValueIdMap[ValGUID] = ++GlobalValueId;
|
||||
return GlobalValueId;
|
||||
} else {
|
||||
return VMI->second;
|
||||
}
|
||||
auto VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
assert(VMI != GUIDToValueIdMap.end());
|
||||
return VMI->second;
|
||||
}
|
||||
std::map<GlobalValue::GUID, unsigned> &valueIds() { return GUIDToValueIdMap; }
|
||||
};
|
||||
@ -1047,13 +1055,10 @@ static unsigned getEncodedUnnamedAddr(const GlobalValue &GV) {
|
||||
void ModuleBitcodeWriter::writeComdats() {
|
||||
SmallVector<unsigned, 64> Vals;
|
||||
for (const Comdat *C : VE.getComdats()) {
|
||||
// COMDAT: [selection_kind, name]
|
||||
// COMDAT: [strtab offset, strtab size, selection_kind]
|
||||
Vals.push_back(StrtabBuilder.add(C->getName()));
|
||||
Vals.push_back(C->getName().size());
|
||||
Vals.push_back(getEncodedComdatSelectionKind(*C));
|
||||
size_t Size = C->getName().size();
|
||||
assert(isUInt<32>(Size));
|
||||
Vals.push_back(Size);
|
||||
for (char Chr : C->getName())
|
||||
Vals.push_back((unsigned char)Chr);
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_COMDAT, Vals, /*AbbrevToUse=*/0);
|
||||
Vals.clear();
|
||||
}
|
||||
@ -1062,7 +1067,7 @@ void ModuleBitcodeWriter::writeComdats() {
|
||||
/// Write a record that will eventually hold the word offset of the
|
||||
/// module-level VST. For now the offset is 0, which will be backpatched
|
||||
/// after the real VST is written. Saves the bit offset to backpatch.
|
||||
void BitcodeWriterBase::writeValueSymbolTableForwardDecl() {
|
||||
void ModuleBitcodeWriter::writeValueSymbolTableForwardDecl() {
|
||||
// Write a placeholder value in for the offset of the real VST,
|
||||
// which is written after the function blocks so that it can include
|
||||
// the offset of each function. The placeholder offset will be
|
||||
@ -1165,6 +1170,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
// Add an abbrev for common globals with no visibility or thread localness.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_GLOBALVAR));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
||||
Log2_32_Ceil(MaxGlobalType+1)));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddrSpace << 2
|
||||
@ -1188,15 +1195,42 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
SimpleGVarAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
}
|
||||
|
||||
// Emit the global variable information.
|
||||
SmallVector<unsigned, 64> Vals;
|
||||
// Emit the module's source file name.
|
||||
{
|
||||
StringEncoding Bits = getStringEncoding(M.getSourceFileName().data(),
|
||||
M.getSourceFileName().size());
|
||||
BitCodeAbbrevOp AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8);
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Char6);
|
||||
else if (Bits == SE_Fixed7)
|
||||
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7);
|
||||
|
||||
// MODULE_CODE_SOURCE_FILENAME: [namechar x N]
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_SOURCE_FILENAME));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
||||
Abbv->Add(AbbrevOpToUse);
|
||||
unsigned FilenameAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
for (const auto P : M.getSourceFileName())
|
||||
Vals.push_back((unsigned char)P);
|
||||
|
||||
// Emit the finished record.
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_SOURCE_FILENAME, Vals, FilenameAbbrev);
|
||||
Vals.clear();
|
||||
}
|
||||
|
||||
// Emit the global variable information.
|
||||
for (const GlobalVariable &GV : M.globals()) {
|
||||
unsigned AbbrevToUse = 0;
|
||||
|
||||
// GLOBALVAR: [type, isconst, initid,
|
||||
// GLOBALVAR: [strtab offset, strtab size, type, isconst, initid,
|
||||
// linkage, alignment, section, visibility, threadlocal,
|
||||
// unnamed_addr, externally_initialized, dllstorageclass,
|
||||
// comdat]
|
||||
Vals.push_back(StrtabBuilder.add(GV.getName()));
|
||||
Vals.push_back(GV.getName().size());
|
||||
Vals.push_back(VE.getTypeID(GV.getValueType()));
|
||||
Vals.push_back(GV.getType()->getAddressSpace() << 2 | 2 | GV.isConstant());
|
||||
Vals.push_back(GV.isDeclaration() ? 0 :
|
||||
@ -1226,9 +1260,12 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
// Emit the function proto information.
|
||||
for (const Function &F : M) {
|
||||
// FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment,
|
||||
// section, visibility, gc, unnamed_addr, prologuedata,
|
||||
// dllstorageclass, comdat, prefixdata, personalityfn]
|
||||
// FUNCTION: [strtab offset, strtab size, type, callingconv, isproto,
|
||||
// linkage, paramattrs, alignment, section, visibility, gc,
|
||||
// unnamed_addr, prologuedata, dllstorageclass, comdat,
|
||||
// prefixdata, personalityfn]
|
||||
Vals.push_back(StrtabBuilder.add(F.getName()));
|
||||
Vals.push_back(F.getName().size());
|
||||
Vals.push_back(VE.getTypeID(F.getFunctionType()));
|
||||
Vals.push_back(F.getCallingConv());
|
||||
Vals.push_back(F.isDeclaration());
|
||||
@ -1255,8 +1292,10 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
// Emit the alias information.
|
||||
for (const GlobalAlias &A : M.aliases()) {
|
||||
// ALIAS: [alias type, aliasee val#, linkage, visibility, dllstorageclass,
|
||||
// threadlocal, unnamed_addr]
|
||||
// ALIAS: [strtab offset, strtab size, alias type, aliasee val#, linkage,
|
||||
// visibility, dllstorageclass, threadlocal, unnamed_addr]
|
||||
Vals.push_back(StrtabBuilder.add(A.getName()));
|
||||
Vals.push_back(A.getName().size());
|
||||
Vals.push_back(VE.getTypeID(A.getValueType()));
|
||||
Vals.push_back(A.getType()->getAddressSpace());
|
||||
Vals.push_back(VE.getValueID(A.getAliasee()));
|
||||
@ -1272,7 +1311,10 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
|
||||
// Emit the ifunc information.
|
||||
for (const GlobalIFunc &I : M.ifuncs()) {
|
||||
// IFUNC: [ifunc type, address space, resolver val#, linkage, visibility]
|
||||
// IFUNC: [strtab offset, strtab size, ifunc type, address space, resolver
|
||||
// val#, linkage, visibility]
|
||||
Vals.push_back(StrtabBuilder.add(I.getName()));
|
||||
Vals.push_back(I.getName().size());
|
||||
Vals.push_back(VE.getTypeID(I.getValueType()));
|
||||
Vals.push_back(I.getType()->getAddressSpace());
|
||||
Vals.push_back(VE.getValueID(I.getResolver()));
|
||||
@ -1282,34 +1324,6 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
Vals.clear();
|
||||
}
|
||||
|
||||
// Emit the module's source file name.
|
||||
{
|
||||
StringEncoding Bits = getStringEncoding(M.getSourceFileName().data(),
|
||||
M.getSourceFileName().size());
|
||||
BitCodeAbbrevOp AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8);
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Char6);
|
||||
else if (Bits == SE_Fixed7)
|
||||
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7);
|
||||
|
||||
// MODULE_CODE_SOURCE_FILENAME: [namechar x N]
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::MODULE_CODE_SOURCE_FILENAME));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
||||
Abbv->Add(AbbrevOpToUse);
|
||||
unsigned FilenameAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
for (const auto P : M.getSourceFileName())
|
||||
Vals.push_back((unsigned char)P);
|
||||
|
||||
// Emit the finished record.
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_SOURCE_FILENAME, Vals, FilenameAbbrev);
|
||||
Vals.clear();
|
||||
}
|
||||
|
||||
// If we have a VST, write the VSTOFFSET record placeholder.
|
||||
if (M.getValueSymbolTable().empty())
|
||||
return;
|
||||
writeValueSymbolTableForwardDecl();
|
||||
}
|
||||
|
||||
@ -1757,9 +1771,8 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N,
|
||||
SmallVectorImpl<uint64_t> &Record,
|
||||
unsigned Abbrev) {
|
||||
Record.reserve(N->getElements().size() + 1);
|
||||
|
||||
const uint64_t HasOpFragmentFlag = 1 << 1;
|
||||
Record.push_back((uint64_t)N->isDistinct() | HasOpFragmentFlag);
|
||||
const uint64_t Version = 2 << 1;
|
||||
Record.push_back((uint64_t)N->isDistinct() | Version);
|
||||
Record.append(N->elements_begin(), N->elements_end());
|
||||
|
||||
Stream.EmitRecord(bitc::METADATA_EXPRESSION, Record, Abbrev);
|
||||
@ -2839,78 +2852,60 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
|
||||
Vals.clear();
|
||||
}
|
||||
|
||||
/// Emit names for globals/functions etc. \p IsModuleLevel is true when
|
||||
/// we are writing the module-level VST, where we are including a function
|
||||
/// bitcode index and need to backpatch the VST forward declaration record.
|
||||
void ModuleBitcodeWriter::writeValueSymbolTable(
|
||||
const ValueSymbolTable &VST, bool IsModuleLevel,
|
||||
DenseMap<const Function *, uint64_t> *FunctionToBitcodeIndex) {
|
||||
if (VST.empty()) {
|
||||
// writeValueSymbolTableForwardDecl should have returned early as
|
||||
// well. Ensure this handling remains in sync by asserting that
|
||||
// the placeholder offset is not set.
|
||||
assert(!IsModuleLevel || !hasVSTOffsetPlaceholder());
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsModuleLevel && hasVSTOffsetPlaceholder()) {
|
||||
// Get the offset of the VST we are writing, and backpatch it into
|
||||
// the VST forward declaration record.
|
||||
uint64_t VSTOffset = Stream.GetCurrentBitNo();
|
||||
// The BitcodeStartBit was the stream offset of the identification block.
|
||||
VSTOffset -= bitcodeStartBit();
|
||||
assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
|
||||
// Note that we add 1 here because the offset is relative to one word
|
||||
// before the start of the identification block, which was historically
|
||||
// always the start of the regular bitcode header.
|
||||
Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32 + 1);
|
||||
}
|
||||
/// Write a GlobalValue VST to the module. The purpose of this data structure is
|
||||
/// to allow clients to efficiently find the function body.
|
||||
void ModuleBitcodeWriter::writeGlobalValueSymbolTable(
|
||||
DenseMap<const Function *, uint64_t> &FunctionToBitcodeIndex) {
|
||||
// Get the offset of the VST we are writing, and backpatch it into
|
||||
// the VST forward declaration record.
|
||||
uint64_t VSTOffset = Stream.GetCurrentBitNo();
|
||||
// The BitcodeStartBit was the stream offset of the identification block.
|
||||
VSTOffset -= bitcodeStartBit();
|
||||
assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
|
||||
// Note that we add 1 here because the offset is relative to one word
|
||||
// before the start of the identification block, which was historically
|
||||
// always the start of the regular bitcode header.
|
||||
Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32 + 1);
|
||||
|
||||
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
|
||||
|
||||
// For the module-level VST, add abbrev Ids for the VST_CODE_FNENTRY
|
||||
// records, which are not used in the per-function VSTs.
|
||||
unsigned FnEntry8BitAbbrev;
|
||||
unsigned FnEntry7BitAbbrev;
|
||||
unsigned FnEntry6BitAbbrev;
|
||||
unsigned GUIDEntryAbbrev;
|
||||
if (IsModuleLevel && hasVSTOffsetPlaceholder()) {
|
||||
// 8-bit fixed-width VST_CODE_FNENTRY function strings.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
|
||||
FnEntry8BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
|
||||
unsigned FnEntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
// 7-bit fixed width VST_CODE_FNENTRY function strings.
|
||||
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7));
|
||||
FnEntry7BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
for (const Function &F : M) {
|
||||
uint64_t Record[2];
|
||||
|
||||
// 6-bit char6 VST_CODE_FNENTRY function strings.
|
||||
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_FNENTRY));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // value id
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // funcoffset
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Char6));
|
||||
FnEntry6BitAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
|
||||
// FIXME: Change the name of this record as it is now used by
|
||||
// the per-module index as well.
|
||||
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_ENTRY));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // refguid
|
||||
GUIDEntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
Record[0] = VE.getValueID(&F);
|
||||
|
||||
// Save the word offset of the function (from the start of the
|
||||
// actual bitcode written to the stream).
|
||||
uint64_t BitcodeIndex = FunctionToBitcodeIndex[&F] - bitcodeStartBit();
|
||||
assert((BitcodeIndex & 31) == 0 && "function block not 32-bit aligned");
|
||||
// Note that we add 1 here because the offset is relative to one word
|
||||
// before the start of the identification block, which was historically
|
||||
// always the start of the regular bitcode header.
|
||||
Record[1] = BitcodeIndex / 32 + 1;
|
||||
|
||||
Stream.EmitRecord(bitc::VST_CODE_FNENTRY, Record, FnEntryAbbrev);
|
||||
}
|
||||
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
/// Emit names for arguments, instructions and basic blocks in a function.
|
||||
void ModuleBitcodeWriter::writeFunctionLevelValueSymbolTable(
|
||||
const ValueSymbolTable &VST) {
|
||||
if (VST.empty())
|
||||
return;
|
||||
|
||||
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
|
||||
|
||||
// FIXME: Set up the abbrev, we know how many values there are!
|
||||
// FIXME: We know if the type names can use 7-bit ascii.
|
||||
SmallVector<uint64_t, 64> NameVals;
|
||||
@ -2923,38 +2918,13 @@ void ModuleBitcodeWriter::writeValueSymbolTable(
|
||||
unsigned AbbrevToUse = VST_ENTRY_8_ABBREV;
|
||||
NameVals.push_back(VE.getValueID(Name.getValue()));
|
||||
|
||||
Function *F = dyn_cast<Function>(Name.getValue());
|
||||
|
||||
// VST_CODE_ENTRY: [valueid, namechar x N]
|
||||
// VST_CODE_FNENTRY: [valueid, funcoffset, namechar x N]
|
||||
// VST_CODE_BBENTRY: [bbid, namechar x N]
|
||||
unsigned Code;
|
||||
if (isa<BasicBlock>(Name.getValue())) {
|
||||
Code = bitc::VST_CODE_BBENTRY;
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevToUse = VST_BBENTRY_6_ABBREV;
|
||||
} else if (F && !F->isDeclaration()) {
|
||||
// Must be the module-level VST, where we pass in the Index and
|
||||
// have a VSTOffsetPlaceholder. The function-level VST should not
|
||||
// contain any Function symbols.
|
||||
assert(FunctionToBitcodeIndex);
|
||||
assert(hasVSTOffsetPlaceholder());
|
||||
|
||||
// Save the word offset of the function (from the start of the
|
||||
// actual bitcode written to the stream).
|
||||
uint64_t BitcodeIndex = (*FunctionToBitcodeIndex)[F] - bitcodeStartBit();
|
||||
assert((BitcodeIndex & 31) == 0 && "function block not 32-bit aligned");
|
||||
// Note that we add 1 here because the offset is relative to one word
|
||||
// before the start of the identification block, which was historically
|
||||
// always the start of the regular bitcode header.
|
||||
NameVals.push_back(BitcodeIndex / 32 + 1);
|
||||
|
||||
Code = bitc::VST_CODE_FNENTRY;
|
||||
AbbrevToUse = FnEntry8BitAbbrev;
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevToUse = FnEntry6BitAbbrev;
|
||||
else if (Bits == SE_Fixed7)
|
||||
AbbrevToUse = FnEntry7BitAbbrev;
|
||||
} else {
|
||||
Code = bitc::VST_CODE_ENTRY;
|
||||
if (Bits == SE_Char6)
|
||||
@ -2970,47 +2940,7 @@ void ModuleBitcodeWriter::writeValueSymbolTable(
|
||||
Stream.EmitRecord(Code, NameVals, AbbrevToUse);
|
||||
NameVals.clear();
|
||||
}
|
||||
// Emit any GUID valueIDs created for indirect call edges into the
|
||||
// module-level VST.
|
||||
if (IsModuleLevel && hasVSTOffsetPlaceholder())
|
||||
for (const auto &GI : valueIds()) {
|
||||
NameVals.push_back(GI.second);
|
||||
NameVals.push_back(GI.first);
|
||||
Stream.EmitRecord(bitc::VST_CODE_COMBINED_ENTRY, NameVals,
|
||||
GUIDEntryAbbrev);
|
||||
NameVals.clear();
|
||||
}
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
/// Emit function names and summary offsets for the combined index
|
||||
/// used by ThinLTO.
|
||||
void IndexBitcodeWriter::writeCombinedValueSymbolTable() {
|
||||
assert(hasVSTOffsetPlaceholder() && "Expected non-zero VSTOffsetPlaceholder");
|
||||
// Get the offset of the VST we are writing, and backpatch it into
|
||||
// the VST forward declaration record.
|
||||
uint64_t VSTOffset = Stream.GetCurrentBitNo();
|
||||
assert((VSTOffset & 31) == 0 && "VST block not 32-bit aligned");
|
||||
Stream.BackpatchWord(VSTOffsetPlaceholder, VSTOffset / 32);
|
||||
|
||||
Stream.EnterSubblock(bitc::VALUE_SYMTAB_BLOCK_ID, 4);
|
||||
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::VST_CODE_COMBINED_ENTRY));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // refguid
|
||||
unsigned EntryAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
SmallVector<uint64_t, 64> NameVals;
|
||||
for (const auto &GVI : valueIds()) {
|
||||
// VST_CODE_COMBINED_ENTRY: [valueid, refguid]
|
||||
NameVals.push_back(GVI.second);
|
||||
NameVals.push_back(GVI.first);
|
||||
|
||||
// Emit the finished record.
|
||||
Stream.EmitRecord(bitc::VST_CODE_COMBINED_ENTRY, NameVals, EntryAbbrev);
|
||||
NameVals.clear();
|
||||
}
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
@ -3114,7 +3044,7 @@ void ModuleBitcodeWriter::writeFunction(
|
||||
|
||||
// Emit names for all the instructions etc.
|
||||
if (auto *Symtab = F.getValueSymbolTable())
|
||||
writeValueSymbolTable(*Symtab);
|
||||
writeFunctionLevelValueSymbolTable(*Symtab);
|
||||
|
||||
if (NeedsMetadataAttachment)
|
||||
writeFunctionMetadataAttachment(F);
|
||||
@ -3502,6 +3432,11 @@ void ModuleBitcodeWriter::writePerModuleGlobalValueSummary() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &GVI : valueIds()) {
|
||||
Stream.EmitRecord(bitc::FS_VALUE_GUID,
|
||||
ArrayRef<uint64_t>{GVI.second, GVI.first});
|
||||
}
|
||||
|
||||
// Abbrev for FS_PERMODULE.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE));
|
||||
@ -3594,6 +3529,39 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
||||
Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 3);
|
||||
Stream.EmitRecord(bitc::FS_VERSION, ArrayRef<uint64_t>{INDEX_VERSION});
|
||||
|
||||
// Create value IDs for undefined references.
|
||||
for (const auto &I : *this) {
|
||||
if (auto *VS = dyn_cast<GlobalVarSummary>(I.second)) {
|
||||
for (auto &RI : VS->refs())
|
||||
assignValueId(RI.getGUID());
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *FS = dyn_cast<FunctionSummary>(I.second);
|
||||
if (!FS)
|
||||
continue;
|
||||
for (auto &RI : FS->refs())
|
||||
assignValueId(RI.getGUID());
|
||||
|
||||
for (auto &EI : FS->calls()) {
|
||||
GlobalValue::GUID GUID = EI.first.getGUID();
|
||||
if (!hasValueId(GUID)) {
|
||||
// For SamplePGO, the indirect call targets for local functions will
|
||||
// have its original name annotated in profile. We try to find the
|
||||
// corresponding PGOFuncName as the GUID.
|
||||
GUID = Index.getGUIDFromOriginalID(GUID);
|
||||
if (GUID == 0 || !hasValueId(GUID))
|
||||
continue;
|
||||
}
|
||||
assignValueId(GUID);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &GVI : valueIds()) {
|
||||
Stream.EmitRecord(bitc::FS_VALUE_GUID,
|
||||
ArrayRef<uint64_t>{GVI.second, GVI.first});
|
||||
}
|
||||
|
||||
// Abbrev for FS_COMBINED.
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(bitc::FS_COMBINED));
|
||||
@ -3808,10 +3776,7 @@ void ModuleBitcodeWriter::write() {
|
||||
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
|
||||
size_t BlockStartPos = Buffer.size();
|
||||
|
||||
SmallVector<unsigned, 1> Vals;
|
||||
unsigned CurVersion = 1;
|
||||
Vals.push_back(CurVersion);
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals);
|
||||
writeModuleVersion();
|
||||
|
||||
// Emit blockinfo, which defines the standard abbreviations etc.
|
||||
writeBlockInfo();
|
||||
@ -3857,8 +3822,7 @@ void ModuleBitcodeWriter::write() {
|
||||
if (Index)
|
||||
writePerModuleGlobalValueSummary();
|
||||
|
||||
writeValueSymbolTable(M.getValueSymbolTable(),
|
||||
/* IsModuleLevel */ true, &FunctionToBitcodeIndex);
|
||||
writeGlobalValueSymbolTable(FunctionToBitcodeIndex);
|
||||
|
||||
writeModuleHash(BlockStartPos);
|
||||
|
||||
@ -3946,13 +3910,45 @@ BitcodeWriter::BitcodeWriter(SmallVectorImpl<char> &Buffer)
|
||||
writeBitcodeHeader(*Stream);
|
||||
}
|
||||
|
||||
BitcodeWriter::~BitcodeWriter() = default;
|
||||
BitcodeWriter::~BitcodeWriter() { assert(WroteStrtab); }
|
||||
|
||||
void BitcodeWriter::writeBlob(unsigned Block, unsigned Record, StringRef Blob) {
|
||||
Stream->EnterSubblock(Block, 3);
|
||||
|
||||
auto Abbv = std::make_shared<BitCodeAbbrev>();
|
||||
Abbv->Add(BitCodeAbbrevOp(Record));
|
||||
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
||||
auto AbbrevNo = Stream->EmitAbbrev(std::move(Abbv));
|
||||
|
||||
Stream->EmitRecordWithBlob(AbbrevNo, ArrayRef<uint64_t>{Record}, Blob);
|
||||
|
||||
Stream->ExitBlock();
|
||||
}
|
||||
|
||||
void BitcodeWriter::writeStrtab() {
|
||||
assert(!WroteStrtab);
|
||||
|
||||
std::vector<char> Strtab;
|
||||
StrtabBuilder.finalizeInOrder();
|
||||
Strtab.resize(StrtabBuilder.getSize());
|
||||
StrtabBuilder.write((uint8_t *)Strtab.data());
|
||||
|
||||
writeBlob(bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB,
|
||||
{Strtab.data(), Strtab.size()});
|
||||
|
||||
WroteStrtab = true;
|
||||
}
|
||||
|
||||
void BitcodeWriter::copyStrtab(StringRef Strtab) {
|
||||
writeBlob(bitc::STRTAB_BLOCK_ID, bitc::STRTAB_BLOB, Strtab);
|
||||
WroteStrtab = true;
|
||||
}
|
||||
|
||||
void BitcodeWriter::writeModule(const Module *M,
|
||||
bool ShouldPreserveUseListOrder,
|
||||
const ModuleSummaryIndex *Index,
|
||||
bool GenerateHash, ModuleHash *ModHash) {
|
||||
ModuleBitcodeWriter ModuleWriter(M, Buffer, *Stream,
|
||||
ModuleBitcodeWriter ModuleWriter(M, Buffer, StrtabBuilder, *Stream,
|
||||
ShouldPreserveUseListOrder, Index,
|
||||
GenerateHash, ModHash);
|
||||
ModuleWriter.write();
|
||||
@ -3976,6 +3972,7 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
|
||||
BitcodeWriter Writer(Buffer);
|
||||
Writer.writeModule(M, ShouldPreserveUseListOrder, Index, GenerateHash,
|
||||
ModHash);
|
||||
Writer.writeStrtab();
|
||||
|
||||
if (TT.isOSDarwin() || TT.isOSBinFormatMachO())
|
||||
emitDarwinBCHeaderAndTrailer(Buffer, TT);
|
||||
@ -3987,13 +3984,7 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out,
|
||||
void IndexBitcodeWriter::write() {
|
||||
Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3);
|
||||
|
||||
SmallVector<unsigned, 1> Vals;
|
||||
unsigned CurVersion = 1;
|
||||
Vals.push_back(CurVersion);
|
||||
Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals);
|
||||
|
||||
// If we have a VST, write the VSTOFFSET record placeholder.
|
||||
writeValueSymbolTableForwardDecl();
|
||||
writeModuleVersion();
|
||||
|
||||
// Write the module paths in the combined index.
|
||||
writeModStrings();
|
||||
@ -4001,10 +3992,6 @@ void IndexBitcodeWriter::write() {
|
||||
// Write the summary combined index records.
|
||||
writeCombinedGlobalValueSummary();
|
||||
|
||||
// Need a special VST writer for the combined index (we don't have a
|
||||
// real VST and real values when this is invoked).
|
||||
writeCombinedValueSymbolTable();
|
||||
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
|
@ -834,9 +834,9 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
||||
OS << " <- ";
|
||||
|
||||
// The second operand is only an offset if it's an immediate.
|
||||
bool Deref = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
|
||||
int64_t Offset = Deref ? MI->getOperand(1).getImm() : 0;
|
||||
|
||||
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) {
|
||||
@ -844,7 +844,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
||||
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
|
||||
// one. Bail out early instead of emitting an incorrect comment.
|
||||
OS << " [complex expression]";
|
||||
AP.OutStreamer->emitRawComment(OS.str());
|
||||
return true;
|
||||
@ -899,12 +899,12 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
||||
AP.OutStreamer->emitRawComment(OS.str());
|
||||
return true;
|
||||
}
|
||||
if (Deref)
|
||||
if (MemLoc || Deref)
|
||||
OS << '[';
|
||||
OS << PrintReg(Reg, AP.MF->getSubtarget().getRegisterInfo());
|
||||
}
|
||||
|
||||
if (Deref)
|
||||
if (MemLoc || Deref)
|
||||
OS << '+' << Offset << ']';
|
||||
|
||||
// NOTE: Want this comment at start of line, don't emit with AddComment.
|
||||
@ -1356,7 +1356,7 @@ bool AsmPrinter::doFinalization(Module &M) {
|
||||
OutContext.getOrCreateSymbol(StringRef("__morestack_addr"));
|
||||
OutStreamer->EmitLabel(AddrSymbol);
|
||||
|
||||
unsigned PtrSize = M.getDataLayout().getPointerSize(0);
|
||||
unsigned PtrSize = MAI->getCodePointerSize();
|
||||
OutStreamer->EmitSymbolValue(GetExternalSymbolSymbol("__morestack"),
|
||||
PtrSize);
|
||||
}
|
||||
@ -2246,7 +2246,7 @@ static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) {
|
||||
// chu[nk1 chu][nk2 chu] ... [nkN-1 chunkN]
|
||||
ExtraBits = Realigned.getRawData()[0] &
|
||||
(((uint64_t)-1) >> (64 - ExtraBitsSize));
|
||||
Realigned = Realigned.lshr(ExtraBitsSize);
|
||||
Realigned.lshrInPlace(ExtraBitsSize);
|
||||
} else
|
||||
ExtraBits = Realigned.getRawData()[BitWidth / 64];
|
||||
}
|
||||
@ -2781,7 +2781,7 @@ void AsmPrinter::emitXRayTable() {
|
||||
// before the function's end, we assume that this is happening after
|
||||
// the last return instruction.
|
||||
|
||||
auto WordSizeBytes = TM.getPointerSize();
|
||||
auto WordSizeBytes = MAI->getCodePointerSize();
|
||||
MCSymbol *Tmp = OutContext.createTempSymbol("xray_synthetic_", true);
|
||||
OutStreamer->EmitCodeAlignment(16);
|
||||
OutStreamer->EmitSymbolValue(Tmp, WordSizeBytes, false);
|
||||
|
@ -1136,7 +1136,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
|
||||
DITypeRef ElementTypeRef = Ty->getBaseType();
|
||||
TypeIndex ElementTypeIndex = getTypeIndex(ElementTypeRef);
|
||||
// IndexType is size_t, which depends on the bitness of the target.
|
||||
TypeIndex IndexType = Asm->MAI->getPointerSize() == 8
|
||||
TypeIndex IndexType = Asm->TM.getPointerSize() == 8
|
||||
? TypeIndex(SimpleTypeKind::UInt64Quad)
|
||||
: TypeIndex(SimpleTypeKind::UInt32Long);
|
||||
|
||||
@ -1342,8 +1342,8 @@ TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) {
|
||||
assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type);
|
||||
TypeIndex ClassTI = getTypeIndex(Ty->getClassType());
|
||||
TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType(), Ty->getClassType());
|
||||
PointerKind PK = Asm->MAI->getPointerSize() == 8 ? PointerKind::Near64
|
||||
: PointerKind::Near32;
|
||||
PointerKind PK = Asm->TM.getPointerSize() == 8 ? PointerKind::Near64
|
||||
: PointerKind::Near32;
|
||||
bool IsPMF = isa<DISubroutineType>(Ty->getBaseType());
|
||||
PointerMode PM = IsPMF ? PointerMode::PointerToMemberFunction
|
||||
: PointerMode::PointerToDataMember;
|
||||
@ -1458,7 +1458,8 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
|
||||
}
|
||||
|
||||
TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
|
||||
unsigned VSlotCount = Ty->getSizeInBits() / (8 * Asm->MAI->getPointerSize());
|
||||
unsigned VSlotCount =
|
||||
Ty->getSizeInBits() / (8 * Asm->MAI->getCodePointerSize());
|
||||
SmallVector<VFTableSlotKind, 4> Slots(VSlotCount, VFTableSlotKind::Near);
|
||||
|
||||
VFTableShapeRecord VFTSR(Slots);
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "dwarfdebug"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEAbbrevData Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -79,15 +81,22 @@ void DIEAbbrev::Emit(const AsmPrinter *AP) const {
|
||||
dwarf::AttributeString(AttrData.getAttribute()).data());
|
||||
|
||||
// Emit form type.
|
||||
#ifndef NDEBUG
|
||||
// Could be an assertion, but this way we can see the failing form code
|
||||
// easily, which helps track down where it came from.
|
||||
if (!dwarf::isValidFormForVersion(AttrData.getForm(),
|
||||
AP->getDwarfVersion())) {
|
||||
DEBUG(dbgs() << "Invalid form " << format("0x%x", AttrData.getForm())
|
||||
<< " for DWARF version " << AP->getDwarfVersion() << "\n");
|
||||
llvm_unreachable("Invalid form for specified DWARF version");
|
||||
}
|
||||
#endif
|
||||
AP->EmitULEB128(AttrData.getForm(),
|
||||
dwarf::FormEncodingString(AttrData.getForm()).data());
|
||||
|
||||
// Emit value for DW_FORM_implicit_const.
|
||||
if (AttrData.getForm() == dwarf::DW_FORM_implicit_const) {
|
||||
assert(AP->getDwarfVersion() >= 5 &&
|
||||
"DW_FORM_implicit_const is supported starting from DWARFv5");
|
||||
if (AttrData.getForm() == dwarf::DW_FORM_implicit_const)
|
||||
AP->EmitSLEB128(AttrData.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Mark end of abbreviation.
|
||||
@ -518,7 +527,7 @@ unsigned DIELabel::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
if (Form == dwarf::DW_FORM_data4) return 4;
|
||||
if (Form == dwarf::DW_FORM_sec_offset) return 4;
|
||||
if (Form == dwarf::DW_FORM_strp) return 4;
|
||||
return AP->getPointerSize();
|
||||
return AP->MAI->getCodePointerSize();
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
@ -540,7 +549,7 @@ unsigned DIEDelta::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
if (Form == dwarf::DW_FORM_data4) return 4;
|
||||
if (Form == dwarf::DW_FORM_sec_offset) return 4;
|
||||
if (Form == dwarf::DW_FORM_strp) return 4;
|
||||
return AP->getPointerSize();
|
||||
return AP->MAI->getCodePointerSize();
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD
|
||||
@ -682,7 +691,7 @@ unsigned DIEEntry::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
return getULEB128Size(Entry->getOffset());
|
||||
case dwarf::DW_FORM_ref_addr:
|
||||
if (AP->getDwarfVersion() == 2)
|
||||
return AP->getPointerSize();
|
||||
return AP->MAI->getCodePointerSize();
|
||||
switch (AP->OutStreamer->getContext().getDwarfFormat()) {
|
||||
case dwarf::DWARF32:
|
||||
return 4;
|
||||
@ -808,7 +817,7 @@ unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const {
|
||||
return 4;
|
||||
if (Form == dwarf::DW_FORM_sec_offset)
|
||||
return 4;
|
||||
return AP->getPointerSize();
|
||||
return AP->MAI->getCodePointerSize();
|
||||
}
|
||||
|
||||
/// EmitValue - Emit label value.
|
||||
|
@ -547,18 +547,19 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
|
||||
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
|
||||
for (auto &Fragment : DV.getFrameIndexExprs()) {
|
||||
unsigned FrameReg = 0;
|
||||
const DIExpression *Expr = Fragment.Expr;
|
||||
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
|
||||
int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg);
|
||||
DwarfExpr.addFragmentOffset(Fragment.Expr);
|
||||
DwarfExpr.addFragmentOffset(Expr);
|
||||
SmallVector<uint64_t, 8> Ops;
|
||||
Ops.push_back(dwarf::DW_OP_plus);
|
||||
Ops.push_back(Offset);
|
||||
Ops.push_back(dwarf::DW_OP_deref);
|
||||
Ops.append(Fragment.Expr->elements_begin(), Fragment.Expr->elements_end());
|
||||
DIExpressionCursor Expr(Ops);
|
||||
Ops.append(Expr->elements_begin(), Expr->elements_end());
|
||||
DIExpressionCursor Cursor(Ops);
|
||||
DwarfExpr.setMemoryLocationKind();
|
||||
DwarfExpr.addMachineRegExpression(
|
||||
*Asm->MF->getSubtarget().getRegisterInfo(), Expr, FrameReg);
|
||||
DwarfExpr.addExpression(std::move(Expr));
|
||||
*Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg);
|
||||
DwarfExpr.addExpression(std::move(Cursor));
|
||||
}
|
||||
addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize());
|
||||
|
||||
@ -779,12 +780,13 @@ void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute,
|
||||
const MachineLocation &Location) {
|
||||
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
|
||||
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
|
||||
if (Location.isIndirect())
|
||||
DwarfExpr.setMemoryLocationKind();
|
||||
|
||||
SmallVector<uint64_t, 8> Ops;
|
||||
if (Location.isIndirect()) {
|
||||
if (Location.isIndirect() && Location.getOffset()) {
|
||||
Ops.push_back(dwarf::DW_OP_plus);
|
||||
Ops.push_back(Location.getOffset());
|
||||
Ops.push_back(dwarf::DW_OP_deref);
|
||||
}
|
||||
DIExpressionCursor Cursor(Ops);
|
||||
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
|
||||
@ -807,12 +809,13 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
|
||||
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
|
||||
const DIExpression *DIExpr = DV.getSingleExpression();
|
||||
DwarfExpr.addFragmentOffset(DIExpr);
|
||||
if (Location.isIndirect())
|
||||
DwarfExpr.setMemoryLocationKind();
|
||||
|
||||
SmallVector<uint64_t, 8> Ops;
|
||||
if (Location.isIndirect()) {
|
||||
if (Location.isIndirect() && Location.getOffset()) {
|
||||
Ops.push_back(dwarf::DW_OP_plus);
|
||||
Ops.push_back(Location.getOffset());
|
||||
Ops.push_back(dwarf::DW_OP_deref);
|
||||
}
|
||||
Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
|
||||
DIExpressionCursor Cursor(Ops);
|
||||
|
@ -1517,13 +1517,12 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
|
||||
DwarfExpr.addUnsignedConstant(Value.getInt());
|
||||
} else if (Value.isLocation()) {
|
||||
MachineLocation Location = Value.getLoc();
|
||||
|
||||
if (Location.isIndirect())
|
||||
DwarfExpr.setMemoryLocationKind();
|
||||
SmallVector<uint64_t, 8> Ops;
|
||||
// FIXME: Should this condition be Location.isIndirect() instead?
|
||||
if (Location.getOffset()) {
|
||||
if (Location.isIndirect() && Location.getOffset()) {
|
||||
Ops.push_back(dwarf::DW_OP_plus);
|
||||
Ops.push_back(Location.getOffset());
|
||||
Ops.push_back(dwarf::DW_OP_deref);
|
||||
}
|
||||
Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
|
||||
DIExpressionCursor Cursor(Ops);
|
||||
@ -1578,7 +1577,7 @@ void DwarfDebug::emitDebugLoc() {
|
||||
// Start the dwarf loc section.
|
||||
Asm->OutStreamer->SwitchSection(
|
||||
Asm->getObjFileLowering().getDwarfLocSection());
|
||||
unsigned char Size = Asm->getDataLayout().getPointerSize();
|
||||
unsigned char Size = Asm->MAI->getCodePointerSize();
|
||||
for (const auto &List : DebugLocs.getLists()) {
|
||||
Asm->OutStreamer->EmitLabel(List.Label);
|
||||
const DwarfCompileUnit *CU = List.CU;
|
||||
@ -1708,7 +1707,7 @@ void DwarfDebug::emitDebugARanges() {
|
||||
Asm->OutStreamer->SwitchSection(
|
||||
Asm->getObjFileLowering().getDwarfARangesSection());
|
||||
|
||||
unsigned PtrSize = Asm->getDataLayout().getPointerSize();
|
||||
unsigned PtrSize = Asm->MAI->getCodePointerSize();
|
||||
|
||||
// Build a list of CUs used.
|
||||
std::vector<DwarfCompileUnit *> CUs;
|
||||
@ -1791,7 +1790,7 @@ void DwarfDebug::emitDebugRanges() {
|
||||
Asm->getObjFileLowering().getDwarfRangesSection());
|
||||
|
||||
// Size for our labels.
|
||||
unsigned char Size = Asm->getDataLayout().getPointerSize();
|
||||
unsigned char Size = Asm->MAI->getCodePointerSize();
|
||||
|
||||
// Grab the specific ranges for the compile units in the module.
|
||||
for (const auto &I : CUMap) {
|
||||
|
@ -23,9 +23,12 @@
|
||||
using namespace llvm;
|
||||
|
||||
void DwarfExpression::addReg(int DwarfReg, const char *Comment) {
|
||||
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
|
||||
if (DwarfReg < 32) {
|
||||
emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);
|
||||
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
|
||||
assert((LocationKind == Unknown || LocationKind == Register) &&
|
||||
"location description already locked down");
|
||||
LocationKind = Register;
|
||||
if (DwarfReg < 32) {
|
||||
emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);
|
||||
} else {
|
||||
emitOp(dwarf::DW_OP_regx, Comment);
|
||||
emitUnsigned(DwarfReg);
|
||||
@ -34,6 +37,7 @@ void DwarfExpression::addReg(int DwarfReg, const char *Comment) {
|
||||
|
||||
void DwarfExpression::addBReg(int DwarfReg, int Offset) {
|
||||
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
|
||||
assert(LocationKind != Register && "location description already locked down");
|
||||
if (DwarfReg < 32) {
|
||||
emitOp(dwarf::DW_OP_breg0 + DwarfReg);
|
||||
} else {
|
||||
@ -156,18 +160,23 @@ void DwarfExpression::addStackValue() {
|
||||
}
|
||||
|
||||
void DwarfExpression::addSignedConstant(int64_t Value) {
|
||||
assert(LocationKind == Implicit || LocationKind == Unknown);
|
||||
LocationKind = Implicit;
|
||||
emitOp(dwarf::DW_OP_consts);
|
||||
emitSigned(Value);
|
||||
addStackValue();
|
||||
}
|
||||
|
||||
void DwarfExpression::addUnsignedConstant(uint64_t Value) {
|
||||
assert(LocationKind == Implicit || LocationKind == Unknown);
|
||||
LocationKind = Implicit;
|
||||
emitOp(dwarf::DW_OP_constu);
|
||||
emitUnsigned(Value);
|
||||
addStackValue();
|
||||
}
|
||||
|
||||
void DwarfExpression::addUnsignedConstant(const APInt &Value) {
|
||||
assert(LocationKind == Implicit || LocationKind == Unknown);
|
||||
LocationKind = Implicit;
|
||||
|
||||
unsigned Size = Value.getBitWidth();
|
||||
const uint64_t *Data = Value.getRawData();
|
||||
|
||||
@ -178,7 +187,8 @@ void DwarfExpression::addUnsignedConstant(const APInt &Value) {
|
||||
addUnsignedConstant(*Data++);
|
||||
if (Offset == 0 && Size <= 64)
|
||||
break;
|
||||
addOpPiece(std::min(Size-Offset, 64u), Offset);
|
||||
addStackValue();
|
||||
addOpPiece(std::min(Size - Offset, 64u), Offset);
|
||||
Offset += 64;
|
||||
}
|
||||
}
|
||||
@ -206,7 +216,7 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
|
||||
}
|
||||
|
||||
// Handle simple register locations.
|
||||
if (!HasComplexExpression) {
|
||||
if (LocationKind != Memory && !HasComplexExpression) {
|
||||
for (auto &Reg : DwarfRegs) {
|
||||
if (Reg.DwarfRegNo >= 0)
|
||||
addReg(Reg.DwarfRegNo, Reg.Comment);
|
||||
@ -216,62 +226,65 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't emit locations that cannot be expressed without DW_OP_stack_value.
|
||||
if (DwarfVersion < 4)
|
||||
if (std::any_of(ExprCursor.begin(), ExprCursor.end(),
|
||||
[](DIExpression::ExprOperand Op) -> bool {
|
||||
return Op.getOp() == dwarf::DW_OP_stack_value;
|
||||
})) {
|
||||
DwarfRegs.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(DwarfRegs.size() == 1);
|
||||
auto Reg = DwarfRegs[0];
|
||||
bool FBReg = isFrameRegister(TRI, MachineReg);
|
||||
bool FBReg = isFrameRegister(TRI, MachineReg);
|
||||
int SignedOffset = 0;
|
||||
assert(Reg.Size == 0 && "subregister has same size as superregister");
|
||||
|
||||
// Pattern-match combinations for which more efficient representations exist.
|
||||
switch (Op->getOp()) {
|
||||
default: {
|
||||
if (FBReg)
|
||||
addFBReg(0);
|
||||
else
|
||||
addReg(Reg.DwarfRegNo, 0);
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_OP_plus:
|
||||
case dwarf::DW_OP_minus: {
|
||||
// [DW_OP_reg,Offset,DW_OP_plus, DW_OP_deref] --> [DW_OP_breg, Offset].
|
||||
// [DW_OP_reg,Offset,DW_OP_minus,DW_OP_deref] --> [DW_OP_breg,-Offset].
|
||||
auto N = ExprCursor.peekNext();
|
||||
if (N && N->getOp() == dwarf::DW_OP_deref) {
|
||||
int Offset = Op->getArg(0);
|
||||
int SignedOffset = (Op->getOp() == dwarf::DW_OP_plus) ? Offset : -Offset;
|
||||
if (FBReg)
|
||||
addFBReg(SignedOffset);
|
||||
else
|
||||
addBReg(Reg.DwarfRegNo, SignedOffset);
|
||||
|
||||
ExprCursor.consume(2);
|
||||
break;
|
||||
}
|
||||
addReg(Reg.DwarfRegNo, 0);
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_OP_deref:
|
||||
// [DW_OP_reg,DW_OP_deref] --> [DW_OP_breg].
|
||||
if (FBReg)
|
||||
addFBReg(0);
|
||||
else
|
||||
addBReg(Reg.DwarfRegNo, 0);
|
||||
// [Reg, Offset, DW_OP_plus] --> [DW_OP_breg, Offset].
|
||||
// [Reg, Offset, DW_OP_minus] --> [DW_OP_breg, -Offset].
|
||||
// If Reg is a subregister we need to mask it out before subtracting.
|
||||
if (Op && ((Op->getOp() == dwarf::DW_OP_plus) ||
|
||||
(Op->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) {
|
||||
int Offset = Op->getArg(0);
|
||||
SignedOffset = (Op->getOp() == dwarf::DW_OP_plus) ? Offset : -Offset;
|
||||
ExprCursor.take();
|
||||
break;
|
||||
}
|
||||
if (FBReg)
|
||||
addFBReg(SignedOffset);
|
||||
else
|
||||
addBReg(Reg.DwarfRegNo, SignedOffset);
|
||||
DwarfRegs.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Assuming a well-formed expression, match "DW_OP_deref* DW_OP_LLVM_fragment?".
|
||||
static bool isMemoryLocation(DIExpressionCursor ExprCursor) {
|
||||
while (ExprCursor) {
|
||||
auto Op = ExprCursor.take();
|
||||
switch (Op->getOp()) {
|
||||
case dwarf::DW_OP_deref:
|
||||
case dwarf::DW_OP_LLVM_fragment:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
|
||||
unsigned FragmentOffsetInBits) {
|
||||
// If we need to mask out a subregister, do it now, unless the next
|
||||
// operation would emit an OpPiece anyway.
|
||||
auto N = ExprCursor.peek();
|
||||
if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment))
|
||||
maskSubRegister();
|
||||
|
||||
while (ExprCursor) {
|
||||
auto Op = ExprCursor.take();
|
||||
|
||||
// If we need to mask out a subregister, do it now, unless the next
|
||||
// operation would emit an OpPiece anyway.
|
||||
if (SubRegisterSizeInBits && Op->getOp() != dwarf::DW_OP_LLVM_fragment)
|
||||
maskSubRegister();
|
||||
|
||||
switch (Op->getOp()) {
|
||||
case dwarf::DW_OP_LLVM_fragment: {
|
||||
unsigned SizeInBits = Op->getArg(1);
|
||||
@ -281,50 +294,74 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
|
||||
// location.
|
||||
assert(OffsetInBits >= FragmentOffset && "fragment offset not added?");
|
||||
|
||||
// If \a addMachineReg already emitted DW_OP_piece operations to represent
|
||||
// If addMachineReg already emitted DW_OP_piece operations to represent
|
||||
// a super-register by splicing together sub-registers, subtract the size
|
||||
// of the pieces that was already emitted.
|
||||
SizeInBits -= OffsetInBits - FragmentOffset;
|
||||
|
||||
// If \a addMachineReg requested a DW_OP_bit_piece to stencil out a
|
||||
// If addMachineReg requested a DW_OP_bit_piece to stencil out a
|
||||
// sub-register that is smaller than the current fragment's size, use it.
|
||||
if (SubRegisterSizeInBits)
|
||||
SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits);
|
||||
|
||||
|
||||
// Emit a DW_OP_stack_value for implicit location descriptions.
|
||||
if (LocationKind == Implicit)
|
||||
addStackValue();
|
||||
|
||||
// Emit the DW_OP_piece.
|
||||
addOpPiece(SizeInBits, SubRegisterOffsetInBits);
|
||||
setSubRegisterPiece(0, 0);
|
||||
break;
|
||||
// Reset the location description kind.
|
||||
LocationKind = Unknown;
|
||||
return;
|
||||
}
|
||||
case dwarf::DW_OP_plus:
|
||||
assert(LocationKind != Register);
|
||||
emitOp(dwarf::DW_OP_plus_uconst);
|
||||
emitUnsigned(Op->getArg(0));
|
||||
break;
|
||||
case dwarf::DW_OP_minus:
|
||||
// There is no OP_minus_uconst.
|
||||
assert(LocationKind != Register);
|
||||
// There is no DW_OP_minus_uconst.
|
||||
emitOp(dwarf::DW_OP_constu);
|
||||
emitUnsigned(Op->getArg(0));
|
||||
emitOp(dwarf::DW_OP_minus);
|
||||
break;
|
||||
case dwarf::DW_OP_deref:
|
||||
emitOp(dwarf::DW_OP_deref);
|
||||
case dwarf::DW_OP_deref: {
|
||||
assert(LocationKind != Register);
|
||||
if (LocationKind != Memory && isMemoryLocation(ExprCursor))
|
||||
// Turning this into a memory location description makes the deref
|
||||
// implicit.
|
||||
LocationKind = Memory;
|
||||
else
|
||||
emitOp(dwarf::DW_OP_deref);
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_OP_constu:
|
||||
assert(LocationKind != Register);
|
||||
emitOp(dwarf::DW_OP_constu);
|
||||
emitUnsigned(Op->getArg(0));
|
||||
break;
|
||||
case dwarf::DW_OP_stack_value:
|
||||
addStackValue();
|
||||
assert(LocationKind == Unknown || LocationKind == Implicit);
|
||||
LocationKind = Implicit;
|
||||
break;
|
||||
case dwarf::DW_OP_swap:
|
||||
assert(LocationKind != Register);
|
||||
emitOp(dwarf::DW_OP_swap);
|
||||
break;
|
||||
case dwarf::DW_OP_xderef:
|
||||
assert(LocationKind != Register);
|
||||
emitOp(dwarf::DW_OP_xderef);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unhandled opcode found in expression");
|
||||
}
|
||||
}
|
||||
|
||||
if (LocationKind == Implicit)
|
||||
// Turn this into an implicit location description.
|
||||
addStackValue();
|
||||
}
|
||||
|
||||
/// add masking operations to stencil out a subregister.
|
||||
|
@ -72,6 +72,8 @@ public:
|
||||
}
|
||||
/// Determine whether there are any operations left in this expression.
|
||||
operator bool() const { return Start != End; }
|
||||
DIExpression::expr_op_iterator begin() const { return Start; }
|
||||
DIExpression::expr_op_iterator end() const { return End; }
|
||||
|
||||
/// Retrieve the fragment information, if any.
|
||||
Optional<DIExpression::FragmentInfo> getFragmentInfo() const {
|
||||
@ -102,6 +104,9 @@ protected:
|
||||
unsigned SubRegisterSizeInBits = 0;
|
||||
unsigned SubRegisterOffsetInBits = 0;
|
||||
|
||||
/// The kind of location description being produced.
|
||||
enum { Unknown = 0, Register, Memory, Implicit } LocationKind = Unknown;
|
||||
|
||||
/// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed
|
||||
/// to represent a subregister.
|
||||
void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) {
|
||||
@ -122,7 +127,8 @@ protected:
|
||||
/// current function.
|
||||
virtual bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) = 0;
|
||||
|
||||
/// Emit a DW_OP_reg operation.
|
||||
/// Emit a DW_OP_reg operation. Note that this is only legal inside a DWARF
|
||||
/// register location description.
|
||||
void addReg(int DwarfReg, const char *Comment = nullptr);
|
||||
/// Emit a DW_OP_breg operation.
|
||||
void addBReg(int DwarfReg, int Offset);
|
||||
@ -185,11 +191,18 @@ public:
|
||||
/// Emit an unsigned constant.
|
||||
void addUnsignedConstant(const APInt &Value);
|
||||
|
||||
/// Lock this down to become a memory location description.
|
||||
void setMemoryLocationKind() {
|
||||
assert(LocationKind == Unknown);
|
||||
LocationKind = Memory;
|
||||
}
|
||||
|
||||
/// Emit a machine register location. As an optimization this may also consume
|
||||
/// the prefix of a DwarfExpression if a more efficient representation for
|
||||
/// combining the register location and the first operation exists.
|
||||
///
|
||||
/// \param FragmentOffsetInBits If this is one fragment out of a fragmented
|
||||
/// \param FragmentOffsetInBits If this is one fragment out of a
|
||||
/// fragmented
|
||||
/// location, this is the offset of the
|
||||
/// fragment inside the entire variable.
|
||||
/// \return false if no DWARF register exists
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/MC/MachineLocation.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCDwarf.h"
|
||||
#include "llvm/MC/MCSection.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
@ -73,8 +74,8 @@ bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
|
||||
|
||||
DwarfUnit::DwarfUnit(dwarf::Tag UnitTag, const DICompileUnit *Node,
|
||||
AsmPrinter *A, DwarfDebug *DW, DwarfFile *DWU)
|
||||
: DIEUnit(A->getDwarfVersion(), A->getPointerSize(), UnitTag), CUNode(Node),
|
||||
Asm(A), DD(DW), DU(DWU), IndexTyDie(nullptr) {
|
||||
: DIEUnit(A->getDwarfVersion(), A->MAI->getCodePointerSize(), UnitTag),
|
||||
CUNode(Node), Asm(A), DD(DW), DU(DWU), IndexTyDie(nullptr) {
|
||||
}
|
||||
|
||||
DwarfTypeUnit::DwarfTypeUnit(DwarfCompileUnit &CU, AsmPrinter *A,
|
||||
@ -471,12 +472,13 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
|
||||
// variable's location.
|
||||
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
|
||||
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
|
||||
if (Location.isIndirect())
|
||||
DwarfExpr.setMemoryLocationKind();
|
||||
|
||||
SmallVector<uint64_t, 9> Ops;
|
||||
if (Location.isIndirect()) {
|
||||
if (Location.isIndirect() && Location.getOffset()) {
|
||||
Ops.push_back(dwarf::DW_OP_plus);
|
||||
Ops.push_back(Location.getOffset());
|
||||
Ops.push_back(dwarf::DW_OP_deref);
|
||||
}
|
||||
// If we started with a pointer to the __Block_byref... struct, then
|
||||
// the first thing we need to do is dereference the pointer (DW_OP_deref).
|
||||
@ -1546,7 +1548,7 @@ void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) {
|
||||
Asm->OutStreamer->AddComment("DWARF Unit Type");
|
||||
Asm->EmitInt8(UT);
|
||||
Asm->OutStreamer->AddComment("Address Size (in bytes)");
|
||||
Asm->EmitInt8(Asm->getDataLayout().getPointerSize());
|
||||
Asm->EmitInt8(Asm->MAI->getCodePointerSize());
|
||||
}
|
||||
|
||||
// We share one abbreviations table across all units so it's always at the
|
||||
@ -1562,7 +1564,7 @@ void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) {
|
||||
|
||||
if (Version <= 4) {
|
||||
Asm->OutStreamer->AddComment("Address Size (in bytes)");
|
||||
Asm->EmitInt8(Asm->getDataLayout().getPointerSize());
|
||||
Asm->EmitInt8(Asm->MAI->getCodePointerSize());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,8 +570,14 @@ bool CodeGenPrepare::splitIndirectCriticalEdges(Function &F) {
|
||||
ValueToValueMapTy VMap;
|
||||
BasicBlock *DirectSucc = CloneBasicBlock(Target, VMap, ".clone", &F);
|
||||
|
||||
for (BasicBlock *Pred : OtherPreds)
|
||||
Pred->getTerminator()->replaceUsesOfWith(Target, DirectSucc);
|
||||
for (BasicBlock *Pred : OtherPreds) {
|
||||
// If the target is a loop to itself, then the terminator of the split
|
||||
// block needs to be updated.
|
||||
if (Pred == Target)
|
||||
BodyBlock->getTerminator()->replaceUsesOfWith(Target, DirectSucc);
|
||||
else
|
||||
Pred->getTerminator()->replaceUsesOfWith(Target, DirectSucc);
|
||||
}
|
||||
|
||||
// Ok, now fix up the PHIs. We know the two blocks only have PHIs, and that
|
||||
// they are clones, so the number of PHIs are the same.
|
||||
@ -5059,16 +5065,14 @@ bool CodeGenPrepare::optimizeLoadExt(LoadInst *Load) {
|
||||
if (!ShlC)
|
||||
return false;
|
||||
uint64_t ShiftAmt = ShlC->getLimitedValue(BitWidth - 1);
|
||||
auto ShlDemandBits = APInt::getAllOnesValue(BitWidth).lshr(ShiftAmt);
|
||||
DemandBits |= ShlDemandBits;
|
||||
DemandBits.setLowBits(BitWidth - ShiftAmt);
|
||||
break;
|
||||
}
|
||||
|
||||
case llvm::Instruction::Trunc: {
|
||||
EVT TruncVT = TLI->getValueType(*DL, I->getType());
|
||||
unsigned TruncBitWidth = TruncVT.getSizeInBits();
|
||||
auto TruncBits = APInt::getAllOnesValue(TruncBitWidth).zext(BitWidth);
|
||||
DemandBits |= TruncBits;
|
||||
DemandBits.setLowBits(TruncBitWidth);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -381,18 +381,19 @@ bool IRTranslator::translateInsertValue(const User &U,
|
||||
uint64_t Offset = 8 * DL->getIndexedOffsetInType(Src->getType(), Indices);
|
||||
|
||||
unsigned Res = getOrCreateVReg(U);
|
||||
const Value &Inserted = *U.getOperand(1);
|
||||
MIRBuilder.buildInsert(Res, getOrCreateVReg(*Src), getOrCreateVReg(Inserted),
|
||||
Offset);
|
||||
unsigned Inserted = getOrCreateVReg(*U.getOperand(1));
|
||||
MIRBuilder.buildInsert(Res, getOrCreateVReg(*Src), Inserted, Offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateSelect(const User &U,
|
||||
MachineIRBuilder &MIRBuilder) {
|
||||
MIRBuilder.buildSelect(getOrCreateVReg(U), getOrCreateVReg(*U.getOperand(0)),
|
||||
getOrCreateVReg(*U.getOperand(1)),
|
||||
getOrCreateVReg(*U.getOperand(2)));
|
||||
unsigned Res = getOrCreateVReg(U);
|
||||
unsigned Tst = getOrCreateVReg(*U.getOperand(0));
|
||||
unsigned Op0 = getOrCreateVReg(*U.getOperand(1));
|
||||
unsigned Op1 = getOrCreateVReg(*U.getOperand(2));
|
||||
MIRBuilder.buildSelect(Res, Tst, Op0, Op1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -984,9 +985,11 @@ bool IRTranslator::translateInsertElement(const User &U,
|
||||
ValToVReg[&U] = Elt;
|
||||
return true;
|
||||
}
|
||||
MIRBuilder.buildInsertVectorElement(
|
||||
getOrCreateVReg(U), getOrCreateVReg(*U.getOperand(0)),
|
||||
getOrCreateVReg(*U.getOperand(1)), getOrCreateVReg(*U.getOperand(2)));
|
||||
unsigned Res = getOrCreateVReg(U);
|
||||
unsigned Val = getOrCreateVReg(*U.getOperand(0));
|
||||
unsigned Elt = getOrCreateVReg(*U.getOperand(1));
|
||||
unsigned Idx = getOrCreateVReg(*U.getOperand(2));
|
||||
MIRBuilder.buildInsertVectorElement(Res, Val, Elt, Idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -999,9 +1002,10 @@ bool IRTranslator::translateExtractElement(const User &U,
|
||||
ValToVReg[&U] = Elt;
|
||||
return true;
|
||||
}
|
||||
MIRBuilder.buildExtractVectorElement(getOrCreateVReg(U),
|
||||
getOrCreateVReg(*U.getOperand(0)),
|
||||
getOrCreateVReg(*U.getOperand(1)));
|
||||
unsigned Res = getOrCreateVReg(U);
|
||||
unsigned Val = getOrCreateVReg(*U.getOperand(0));
|
||||
unsigned Idx = getOrCreateVReg(*U.getOperand(1));
|
||||
MIRBuilder.buildExtractVectorElement(Res, Val, Idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -68,23 +68,6 @@ bool InstructionSelector::constrainSelectedInstRegOperands(
|
||||
return true;
|
||||
}
|
||||
|
||||
Optional<int64_t>
|
||||
InstructionSelector::getConstantVRegVal(unsigned VReg,
|
||||
const MachineRegisterInfo &MRI) const {
|
||||
MachineInstr *MI = MRI.getVRegDef(VReg);
|
||||
if (MI->getOpcode() != TargetOpcode::G_CONSTANT)
|
||||
return None;
|
||||
|
||||
if (MI->getOperand(1).isImm())
|
||||
return MI->getOperand(1).getImm();
|
||||
|
||||
if (MI->getOperand(1).isCImm() &&
|
||||
MI->getOperand(1).getCImm()->getBitWidth() <= 64)
|
||||
return MI->getOperand(1).getCImm()->getSExtValue();
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
bool InstructionSelector::isOperandImmEqual(
|
||||
const MachineOperand &MO, int64_t Value,
|
||||
const MachineRegisterInfo &MRI) const {
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#define DEBUG_TYPE "legalizer"
|
||||
|
||||
using namespace llvm;
|
||||
@ -161,7 +163,7 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
|
||||
// convergence for performance reasons.
|
||||
bool Changed = false;
|
||||
MachineBasicBlock::iterator NextMI;
|
||||
for (auto &MBB : MF)
|
||||
for (auto &MBB : MF) {
|
||||
for (auto MI = MBB.begin(); MI != MBB.end(); MI = NextMI) {
|
||||
// Get the next Instruction before we try to legalize, because there's a
|
||||
// good chance MI will be deleted.
|
||||
@ -171,18 +173,21 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
|
||||
// and are assumed to be legal.
|
||||
if (!isPreISelGenericOpcode(MI->getOpcode()))
|
||||
continue;
|
||||
unsigned NumNewInsns = 0;
|
||||
SmallVector<MachineInstr *, 4> WorkList;
|
||||
Helper.MIRBuilder.recordInsertions(
|
||||
[&](MachineInstr *MI) { WorkList.push_back(MI); });
|
||||
Helper.MIRBuilder.recordInsertions([&](MachineInstr *MI) {
|
||||
++NumNewInsns;
|
||||
WorkList.push_back(MI);
|
||||
});
|
||||
WorkList.push_back(&*MI);
|
||||
|
||||
bool Changed = false;
|
||||
LegalizerHelper::LegalizeResult Res;
|
||||
unsigned Idx = 0;
|
||||
do {
|
||||
Res = Helper.legalizeInstrStep(*WorkList[Idx]);
|
||||
// Error out if we couldn't legalize this instruction. We may want to
|
||||
// fall
|
||||
// back to DAG ISel instead in the future.
|
||||
// fall back to DAG ISel instead in the future.
|
||||
if (Res == LegalizerHelper::UnableToLegalize) {
|
||||
Helper.MIRBuilder.stopRecordingInsertions();
|
||||
if (Res == LegalizerHelper::UnableToLegalize) {
|
||||
@ -194,10 +199,21 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
|
||||
}
|
||||
Changed |= Res == LegalizerHelper::Legalized;
|
||||
++Idx;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (NumNewInsns) {
|
||||
DEBUG(dbgs() << ".. .. Emitted " << NumNewInsns << " insns\n");
|
||||
for (auto I = WorkList.end() - NumNewInsns, E = WorkList.end();
|
||||
I != E; ++I)
|
||||
DEBUG(dbgs() << ".. .. New MI: "; (*I)->print(dbgs()));
|
||||
NumNewInsns = 0;
|
||||
}
|
||||
#endif
|
||||
} while (Idx < WorkList.size());
|
||||
|
||||
Helper.MIRBuilder.stopRecordingInsertions();
|
||||
}
|
||||
}
|
||||
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
@ -207,7 +223,11 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
|
||||
// good chance MI will be deleted.
|
||||
NextMI = std::next(MI);
|
||||
|
||||
Changed |= combineExtracts(*MI, MRI, TII);
|
||||
// combineExtracts erases MI.
|
||||
if (combineExtracts(*MI, MRI, TII)) {
|
||||
Changed = true;
|
||||
continue;
|
||||
}
|
||||
Changed |= combineMerges(*MI, MRI, TII);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#define DEBUG_TYPE "legalize-mir"
|
||||
#define DEBUG_TYPE "legalizer"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -35,24 +35,34 @@ LegalizerHelper::LegalizerHelper(MachineFunction &MF)
|
||||
|
||||
LegalizerHelper::LegalizeResult
|
||||
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
|
||||
DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
|
||||
|
||||
auto Action = LI.getAction(MI, MRI);
|
||||
switch (std::get<0>(Action)) {
|
||||
case LegalizerInfo::Legal:
|
||||
DEBUG(dbgs() << ".. Already legal\n");
|
||||
return AlreadyLegal;
|
||||
case LegalizerInfo::Libcall:
|
||||
DEBUG(dbgs() << ".. Convert to libcall\n");
|
||||
return libcall(MI);
|
||||
case LegalizerInfo::NarrowScalar:
|
||||
DEBUG(dbgs() << ".. Narrow scalar\n");
|
||||
return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action));
|
||||
case LegalizerInfo::WidenScalar:
|
||||
DEBUG(dbgs() << ".. Widen scalar\n");
|
||||
return widenScalar(MI, std::get<1>(Action), std::get<2>(Action));
|
||||
case LegalizerInfo::Lower:
|
||||
DEBUG(dbgs() << ".. Lower\n");
|
||||
return lower(MI, std::get<1>(Action), std::get<2>(Action));
|
||||
case LegalizerInfo::FewerElements:
|
||||
DEBUG(dbgs() << ".. Reduce number of elements\n");
|
||||
return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action));
|
||||
case LegalizerInfo::Custom:
|
||||
DEBUG(dbgs() << ".. Custom legalization\n");
|
||||
return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized
|
||||
: UnableToLegalize;
|
||||
default:
|
||||
DEBUG(dbgs() << ".. Unable to legalize\n");
|
||||
return UnableToLegalize;
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ MachineInstrBuilder MachineIRBuilder::buildInsertVectorElement(unsigned Res,
|
||||
LLT EltTy = MRI->getType(Elt);
|
||||
LLT IdxTy = MRI->getType(Idx);
|
||||
assert(ResTy.isVector() && ValTy.isVector() && "invalid operand type");
|
||||
assert(EltTy.isScalar() && IdxTy.isScalar() && "invalid operand type");
|
||||
assert(IdxTy.isScalar() && "invalid operand type");
|
||||
assert(ResTy.getNumElements() == ValTy.getNumElements() && "type mismatch");
|
||||
assert(ResTy.getElementType() == EltTy && "type mismatch");
|
||||
#endif
|
||||
@ -612,7 +612,8 @@ MachineInstrBuilder MachineIRBuilder::buildExtractVectorElement(unsigned Res,
|
||||
LLT ValTy = MRI->getType(Val);
|
||||
LLT IdxTy = MRI->getType(Idx);
|
||||
assert(ValTy.isVector() && "invalid operand type");
|
||||
assert(ResTy.isScalar() && IdxTy.isScalar() && "invalid operand type");
|
||||
assert((ResTy.isScalar() || ResTy.isPointer()) && "invalid operand type");
|
||||
assert(IdxTy.isScalar() && "invalid operand type");
|
||||
assert(ValTy.getElementType() == ResTy && "type mismatch");
|
||||
#endif
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/TargetPassConfig.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
|
||||
@ -93,3 +94,19 @@ void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
R << Msg << ": " << ore::MNV("Inst", MI);
|
||||
reportGISelFailure(MF, TPC, MORE, R);
|
||||
}
|
||||
|
||||
Optional<int64_t> llvm::getConstantVRegVal(unsigned VReg,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
MachineInstr *MI = MRI.getVRegDef(VReg);
|
||||
if (MI->getOpcode() != TargetOpcode::G_CONSTANT)
|
||||
return None;
|
||||
|
||||
if (MI->getOperand(1).isImm())
|
||||
return MI->getOperand(1).getImm();
|
||||
|
||||
if (MI->getOperand(1).isCImm() &&
|
||||
MI->getOperand(1).getCImm()->getBitWidth() <= 64)
|
||||
return MI->getOperand(1).getCImm()->getSExtValue();
|
||||
|
||||
return None;
|
||||
}
|
||||
|
@ -888,20 +888,10 @@ void InlineSpiller::spillAroundUses(unsigned Reg) {
|
||||
// Debug values are not allowed to affect codegen.
|
||||
if (MI->isDebugValue()) {
|
||||
// Modify DBG_VALUE now that the value is in a spill slot.
|
||||
bool IsIndirect = MI->isIndirectDebugValue();
|
||||
uint64_t Offset = IsIndirect ? MI->getOperand(1).getImm() : 0;
|
||||
const MDNode *Var = MI->getDebugVariable();
|
||||
const MDNode *Expr = MI->getDebugExpression();
|
||||
DebugLoc DL = MI->getDebugLoc();
|
||||
DEBUG(dbgs() << "Modifying debug info due to spill:" << "\t" << *MI);
|
||||
MachineBasicBlock *MBB = MI->getParent();
|
||||
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
BuildMI(*MBB, MBB->erase(MI), DL, TII.get(TargetOpcode::DBG_VALUE))
|
||||
.addFrameIndex(StackSlot)
|
||||
.addImm(Offset)
|
||||
.addMetadata(Var)
|
||||
.addMetadata(Expr);
|
||||
DEBUG(dbgs() << "Modifying debug info due to spill:\t" << *MI);
|
||||
buildDbgValueForSpill(*MBB, MI, *MI, StackSlot);
|
||||
MBB->erase(MI);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,10 @@ using namespace llvm;
|
||||
LLT llvm::getLLTForType(Type &Ty, const DataLayout &DL) {
|
||||
if (auto VTy = dyn_cast<VectorType>(&Ty)) {
|
||||
auto NumElements = VTy->getNumElements();
|
||||
auto ScalarSizeInBits = VTy->getElementType()->getPrimitiveSizeInBits();
|
||||
LLT ScalarTy = getLLTForType(*VTy->getElementType(), DL);
|
||||
if (NumElements == 1)
|
||||
return LLT::scalar(ScalarSizeInBits);
|
||||
return LLT::vector(NumElements, ScalarSizeInBits);
|
||||
return ScalarTy;
|
||||
return LLT::vector(NumElements, ScalarTy);
|
||||
} else if (auto PTy = dyn_cast<PointerType>(&Ty)) {
|
||||
return LLT::pointer(PTy->getAddressSpace(), DL.getTypeSizeInBits(&Ty));
|
||||
} else if (Ty.isSized()) {
|
||||
|
@ -2351,3 +2351,31 @@ MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
|
||||
BB.insert(I, MI);
|
||||
return MachineInstrBuilder(MF, MI);
|
||||
}
|
||||
|
||||
MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB,
|
||||
MachineBasicBlock::iterator I,
|
||||
const MachineInstr &Orig,
|
||||
int FrameIndex) {
|
||||
const MDNode *Var = Orig.getDebugVariable();
|
||||
auto *Expr = cast_or_null<DIExpression>(Orig.getDebugExpression());
|
||||
bool IsIndirect = Orig.isIndirectDebugValue();
|
||||
uint64_t Offset = IsIndirect ? Orig.getOperand(1).getImm() : 0;
|
||||
DebugLoc DL = Orig.getDebugLoc();
|
||||
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
// If the DBG_VALUE already was a memory location, add an extra
|
||||
// DW_OP_deref. Otherwise just turning this from a register into a
|
||||
// memory/indirect location is sufficient.
|
||||
if (IsIndirect) {
|
||||
SmallVector<uint64_t, 8> Ops;
|
||||
Ops.push_back(dwarf::DW_OP_deref);
|
||||
if (Expr)
|
||||
Ops.append(Expr->elements_begin(), Expr->elements_end());
|
||||
Expr = DIExpression::get(Expr->getContext(), Ops);
|
||||
}
|
||||
return BuildMI(BB, I, DL, Orig.getDesc())
|
||||
.addFrameIndex(FrameIndex)
|
||||
.addImm(Offset)
|
||||
.addMetadata(Var)
|
||||
.addMetadata(Expr);
|
||||
}
|
||||
|
@ -2030,6 +2030,8 @@ namespace {
|
||||
void MachineVerifier::verifyStackFrame() {
|
||||
unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
|
||||
unsigned FrameDestroyOpcode = TII->getCallFrameDestroyOpcode();
|
||||
if (FrameSetupOpcode == ~0u && FrameDestroyOpcode == ~0u)
|
||||
return;
|
||||
|
||||
SmallVector<StackStateOfBB, 8> SPState;
|
||||
SPState.resize(MF->getNumBlockIDs());
|
||||
|
@ -304,19 +304,7 @@ void RAFast::spillVirtReg(MachineBasicBlock::iterator MI,
|
||||
LiveDbgValueMap[LRI->VirtReg];
|
||||
for (unsigned li = 0, le = LRIDbgValues.size(); li != le; ++li) {
|
||||
MachineInstr *DBG = LRIDbgValues[li];
|
||||
const MDNode *Var = DBG->getDebugVariable();
|
||||
const MDNode *Expr = DBG->getDebugExpression();
|
||||
bool IsIndirect = DBG->isIndirectDebugValue();
|
||||
uint64_t Offset = IsIndirect ? DBG->getOperand(1).getImm() : 0;
|
||||
DebugLoc DL = DBG->getDebugLoc();
|
||||
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
MachineInstr *NewDV =
|
||||
BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::DBG_VALUE))
|
||||
.addFrameIndex(FI)
|
||||
.addImm(Offset)
|
||||
.addMetadata(Var)
|
||||
.addMetadata(Expr);
|
||||
MachineInstr *NewDV = buildDbgValueForSpill(*MBB, MI, *DBG, FI);
|
||||
assert(NewDV->getParent() == MBB && "dangling parent pointer");
|
||||
(void)NewDV;
|
||||
DEBUG(dbgs() << "Inserting debug info due to spill:" << "\n" << *NewDV);
|
||||
|
@ -550,7 +550,7 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack(
|
||||
|
||||
// Replace alloc with the new location.
|
||||
replaceDbgDeclare(Arg, BasePointer, BasePointer->getNextNode(), DIB,
|
||||
/*Deref=*/true, -Offset);
|
||||
/*Deref=*/false, -Offset);
|
||||
Arg->replaceAllUsesWith(NewArg);
|
||||
IRB.SetInsertPoint(cast<Instruction>(NewArg)->getNextNode());
|
||||
IRB.CreateMemCpy(Off, Arg, Size, Arg->getParamAlignment());
|
||||
@ -565,7 +565,7 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack(
|
||||
if (Size == 0)
|
||||
Size = 1; // Don't create zero-sized stack objects.
|
||||
|
||||
replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/true, -Offset);
|
||||
replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/false, -Offset);
|
||||
replaceDbgValueForAlloca(AI, BasePointer, DIB, -Offset);
|
||||
|
||||
// Replace uses of the alloca with the new location.
|
||||
@ -655,7 +655,7 @@ void SafeStack::moveDynamicAllocasToUnsafeStack(
|
||||
if (AI->hasName() && isa<Instruction>(NewAI))
|
||||
NewAI->takeName(AI);
|
||||
|
||||
replaceDbgDeclareForAlloca(AI, NewAI, DIB, /*Deref=*/true);
|
||||
replaceDbgDeclareForAlloca(AI, NewAI, DIB, /*Deref=*/false);
|
||||
AI->replaceAllUsesWith(NewAI);
|
||||
AI->eraseFromParent();
|
||||
}
|
||||
|
@ -2146,7 +2146,7 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
|
||||
if (N->getFlags()->hasNoUnsignedWrap())
|
||||
return N0;
|
||||
|
||||
if (DAG.MaskedValueIsZero(N1, ~APInt::getSignBit(BitWidth))) {
|
||||
if (DAG.MaskedValueIsZero(N1, ~APInt::getSignMask(BitWidth))) {
|
||||
// N1 is either 0 or the minimum signed value. If the sub is NSW, then
|
||||
// N1 must be 0 because negating the minimum signed value is undefined.
|
||||
if (N->getFlags()->hasNoSignedWrap())
|
||||
@ -3705,7 +3705,7 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
|
||||
|
||||
// fold (and (sign_extend_inreg x, i16 to i32), 1) -> (and x, 1)
|
||||
// fold (and (sra)) -> (and (srl)) when possible.
|
||||
if (!VT.isVector() && SimplifyDemandedBits(SDValue(N, 0)))
|
||||
if (SimplifyDemandedBits(SDValue(N, 0)))
|
||||
return SDValue(N, 0);
|
||||
|
||||
// fold (zext_inreg (extload x)) -> (zextload x)
|
||||
@ -4225,8 +4225,7 @@ SDValue DAGCombiner::visitOR(SDNode *N) {
|
||||
return Load;
|
||||
|
||||
// Simplify the operands using demanded-bits information.
|
||||
if (!VT.isVector() &&
|
||||
SimplifyDemandedBits(SDValue(N, 0)))
|
||||
if (SimplifyDemandedBits(SDValue(N, 0)))
|
||||
return SDValue(N, 0);
|
||||
|
||||
return SDValue();
|
||||
@ -5058,8 +5057,7 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
|
||||
return Tmp;
|
||||
|
||||
// Simplify the expression using non-local knowledge.
|
||||
if (!VT.isVector() &&
|
||||
SimplifyDemandedBits(SDValue(N, 0)))
|
||||
if (SimplifyDemandedBits(SDValue(N, 0)))
|
||||
return SDValue(N, 0);
|
||||
|
||||
return SDValue();
|
||||
@ -5350,7 +5348,7 @@ SDValue DAGCombiner::visitSHL(SDNode *N) {
|
||||
Shift = DAG.getNode(ISD::SHL, DL, VT, N0.getOperand(0),
|
||||
DAG.getConstant(c2 - c1, DL, N1.getValueType()));
|
||||
} else {
|
||||
Mask = Mask.lshr(c1 - c2);
|
||||
Mask.lshrInPlace(c1 - c2);
|
||||
SDLoc DL(N);
|
||||
Shift = DAG.getNode(ISD::SRL, DL, VT, N0.getOperand(0),
|
||||
DAG.getConstant(c1 - c2, DL, N1.getValueType()));
|
||||
@ -5660,7 +5658,7 @@ SDValue DAGCombiner::visitSRL(SDNode *N) {
|
||||
DAG.getConstant(ShiftAmt, DL0,
|
||||
getShiftAmountTy(SmallVT)));
|
||||
AddToWorklist(SmallShift.getNode());
|
||||
APInt Mask = APInt::getAllOnesValue(OpSizeInBits).lshr(ShiftAmt);
|
||||
APInt Mask = APInt::getLowBitsSet(OpSizeInBits, OpSizeInBits - ShiftAmt);
|
||||
SDLoc DL(N);
|
||||
return DAG.getNode(ISD::AND, DL, VT,
|
||||
DAG.getNode(ISD::ANY_EXTEND, DL, VT, SmallShift),
|
||||
@ -8300,11 +8298,11 @@ static SDValue foldBitcastedFPLogic(SDNode *N, SelectionDAG &DAG,
|
||||
switch (N0.getOpcode()) {
|
||||
case ISD::AND:
|
||||
FPOpcode = ISD::FABS;
|
||||
SignMask = ~APInt::getSignBit(SourceVT.getSizeInBits());
|
||||
SignMask = ~APInt::getSignMask(SourceVT.getSizeInBits());
|
||||
break;
|
||||
case ISD::XOR:
|
||||
FPOpcode = ISD::FNEG;
|
||||
SignMask = APInt::getSignBit(SourceVT.getSizeInBits());
|
||||
SignMask = APInt::getSignMask(SourceVT.getSizeInBits());
|
||||
break;
|
||||
// TODO: ISD::OR --> ISD::FNABS?
|
||||
default:
|
||||
@ -8415,7 +8413,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
|
||||
if (N0.getValueType() == MVT::ppcf128 && !LegalTypes) {
|
||||
assert(VT.getSizeInBits() == 128);
|
||||
SDValue SignBit = DAG.getConstant(
|
||||
APInt::getSignBit(VT.getSizeInBits() / 2), SDLoc(N0), MVT::i64);
|
||||
APInt::getSignMask(VT.getSizeInBits() / 2), SDLoc(N0), MVT::i64);
|
||||
SDValue FlipBit;
|
||||
if (N0.getOpcode() == ISD::FNEG) {
|
||||
FlipBit = SignBit;
|
||||
@ -8435,7 +8433,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
|
||||
AddToWorklist(FlipBits.getNode());
|
||||
return DAG.getNode(ISD::XOR, DL, VT, NewConv, FlipBits);
|
||||
}
|
||||
APInt SignBit = APInt::getSignBit(VT.getSizeInBits());
|
||||
APInt SignBit = APInt::getSignMask(VT.getSizeInBits());
|
||||
if (N0.getOpcode() == ISD::FNEG)
|
||||
return DAG.getNode(ISD::XOR, DL, VT,
|
||||
NewConv, DAG.getConstant(SignBit, DL, VT));
|
||||
@ -8483,7 +8481,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
|
||||
}
|
||||
|
||||
if (N0.getValueType() == MVT::ppcf128 && !LegalTypes) {
|
||||
APInt SignBit = APInt::getSignBit(VT.getSizeInBits() / 2);
|
||||
APInt SignBit = APInt::getSignMask(VT.getSizeInBits() / 2);
|
||||
SDValue Cst = DAG.getBitcast(VT, N0.getOperand(0));
|
||||
AddToWorklist(Cst.getNode());
|
||||
SDValue X = DAG.getBitcast(VT, N0.getOperand(1));
|
||||
@ -8504,7 +8502,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
|
||||
AddToWorklist(FlipBits.getNode());
|
||||
return DAG.getNode(ISD::XOR, SDLoc(N), VT, Cst, FlipBits);
|
||||
}
|
||||
APInt SignBit = APInt::getSignBit(VT.getSizeInBits());
|
||||
APInt SignBit = APInt::getSignMask(VT.getSizeInBits());
|
||||
X = DAG.getNode(ISD::AND, SDLoc(X), VT,
|
||||
X, DAG.getConstant(SignBit, SDLoc(X), VT));
|
||||
AddToWorklist(X.getNode());
|
||||
@ -8687,7 +8685,7 @@ ConstantFoldBITCASTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) {
|
||||
for (unsigned j = 0; j != NumOutputsPerInput; ++j) {
|
||||
APInt ThisVal = OpVal.trunc(DstBitSize);
|
||||
Ops.push_back(DAG.getConstant(ThisVal, DL, DstEltVT));
|
||||
OpVal = OpVal.lshr(DstBitSize);
|
||||
OpVal.lshrInPlace(DstBitSize);
|
||||
}
|
||||
|
||||
// For big endian targets, swap the order of the pieces of each element.
|
||||
@ -10315,11 +10313,11 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) {
|
||||
if (N0.getValueType().isVector()) {
|
||||
// For a vector, get a mask such as 0x80... per scalar element
|
||||
// and splat it.
|
||||
SignMask = APInt::getSignBit(N0.getScalarValueSizeInBits());
|
||||
SignMask = APInt::getSignMask(N0.getScalarValueSizeInBits());
|
||||
SignMask = APInt::getSplat(IntVT.getSizeInBits(), SignMask);
|
||||
} else {
|
||||
// For a scalar, just generate 0x80...
|
||||
SignMask = APInt::getSignBit(IntVT.getSizeInBits());
|
||||
SignMask = APInt::getSignMask(IntVT.getSizeInBits());
|
||||
}
|
||||
SDLoc DL0(N0);
|
||||
Int = DAG.getNode(ISD::XOR, DL0, IntVT, Int,
|
||||
@ -10420,11 +10418,11 @@ SDValue DAGCombiner::visitFABS(SDNode *N) {
|
||||
if (N0.getValueType().isVector()) {
|
||||
// For a vector, get a mask such as 0x7f... per scalar element
|
||||
// and splat it.
|
||||
SignMask = ~APInt::getSignBit(N0.getScalarValueSizeInBits());
|
||||
SignMask = ~APInt::getSignMask(N0.getScalarValueSizeInBits());
|
||||
SignMask = APInt::getSplat(IntVT.getSizeInBits(), SignMask);
|
||||
} else {
|
||||
// For a scalar, just generate 0x7f...
|
||||
SignMask = ~APInt::getSignBit(IntVT.getSizeInBits());
|
||||
SignMask = ~APInt::getSignMask(IntVT.getSizeInBits());
|
||||
}
|
||||
SDLoc DL(N0);
|
||||
Int = DAG.getNode(ISD::AND, DL, IntVT, Int,
|
||||
@ -12375,6 +12373,27 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) {
|
||||
return LHS.OffsetFromBase < RHS.OffsetFromBase;
|
||||
});
|
||||
|
||||
// Store Merge attempts to merge the lowest stores. This generally
|
||||
// works out as if successful, as the remaining stores are checked
|
||||
// after the first collection of stores is merged. However, in the
|
||||
// case that a non-mergeable store is found first, e.g., {p[-2],
|
||||
// p[0], p[1], p[2], p[3]}, we would fail and miss the subsequent
|
||||
// mergeable cases. To prevent this, we prune such stores from the
|
||||
// front of StoreNodes here.
|
||||
|
||||
unsigned StartIdx = 0;
|
||||
while ((StartIdx + 1 < StoreNodes.size()) &&
|
||||
StoreNodes[StartIdx].OffsetFromBase + ElementSizeBytes !=
|
||||
StoreNodes[StartIdx + 1].OffsetFromBase)
|
||||
++StartIdx;
|
||||
|
||||
// Bail if we don't have enough candidates to merge.
|
||||
if (StartIdx + 1 >= StoreNodes.size())
|
||||
return false;
|
||||
|
||||
if (StartIdx)
|
||||
StoreNodes.erase(StoreNodes.begin(), StoreNodes.begin() + StartIdx);
|
||||
|
||||
// Scan the memory operations on the chain and find the first non-consecutive
|
||||
// store memory address.
|
||||
unsigned NumConsecutiveStores = 0;
|
||||
@ -12485,39 +12504,52 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) {
|
||||
// When extracting multiple vector elements, try to store them
|
||||
// in one vector store rather than a sequence of scalar stores.
|
||||
if (IsExtractVecSrc) {
|
||||
LSBaseSDNode *FirstInChain = StoreNodes[0].MemNode;
|
||||
unsigned FirstStoreAS = FirstInChain->getAddressSpace();
|
||||
unsigned FirstStoreAlign = FirstInChain->getAlignment();
|
||||
unsigned NumStoresToMerge = 0;
|
||||
bool IsVec = MemVT.isVector();
|
||||
for (unsigned i = 0; i < NumConsecutiveStores; ++i) {
|
||||
StoreSDNode *St = cast<StoreSDNode>(StoreNodes[i].MemNode);
|
||||
unsigned StoreValOpcode = St->getValue().getOpcode();
|
||||
// This restriction could be loosened.
|
||||
// Bail out if any stored values are not elements extracted from a vector.
|
||||
// It should be possible to handle mixed sources, but load sources need
|
||||
// more careful handling (see the block of code below that handles
|
||||
// consecutive loads).
|
||||
if (StoreValOpcode != ISD::EXTRACT_VECTOR_ELT &&
|
||||
StoreValOpcode != ISD::EXTRACT_SUBVECTOR)
|
||||
return false;
|
||||
bool RV = false;
|
||||
while (StoreNodes.size() >= 2) {
|
||||
LSBaseSDNode *FirstInChain = StoreNodes[0].MemNode;
|
||||
unsigned FirstStoreAS = FirstInChain->getAddressSpace();
|
||||
unsigned FirstStoreAlign = FirstInChain->getAlignment();
|
||||
unsigned NumStoresToMerge = 0;
|
||||
bool IsVec = MemVT.isVector();
|
||||
for (unsigned i = 0; i < NumConsecutiveStores; ++i) {
|
||||
StoreSDNode *St = cast<StoreSDNode>(StoreNodes[i].MemNode);
|
||||
unsigned StoreValOpcode = St->getValue().getOpcode();
|
||||
// This restriction could be loosened.
|
||||
// Bail out if any stored values are not elements extracted from a
|
||||
// vector. It should be possible to handle mixed sources, but load
|
||||
// sources need more careful handling (see the block of code below that
|
||||
// handles consecutive loads).
|
||||
if (StoreValOpcode != ISD::EXTRACT_VECTOR_ELT &&
|
||||
StoreValOpcode != ISD::EXTRACT_SUBVECTOR)
|
||||
return false;
|
||||
|
||||
// Find a legal type for the vector store.
|
||||
unsigned Elts = i + 1;
|
||||
if (IsVec) {
|
||||
// When merging vector stores, get the total number of elements.
|
||||
Elts *= MemVT.getVectorNumElements();
|
||||
// Find a legal type for the vector store.
|
||||
unsigned Elts = i + 1;
|
||||
if (IsVec) {
|
||||
// When merging vector stores, get the total number of elements.
|
||||
Elts *= MemVT.getVectorNumElements();
|
||||
}
|
||||
EVT Ty =
|
||||
EVT::getVectorVT(*DAG.getContext(), MemVT.getScalarType(), Elts);
|
||||
bool IsFast;
|
||||
if (TLI.isTypeLegal(Ty) &&
|
||||
TLI.allowsMemoryAccess(Context, DL, Ty, FirstStoreAS,
|
||||
FirstStoreAlign, &IsFast) &&
|
||||
IsFast)
|
||||
NumStoresToMerge = i + 1;
|
||||
}
|
||||
EVT Ty = EVT::getVectorVT(*DAG.getContext(), MemVT.getScalarType(), Elts);
|
||||
bool IsFast;
|
||||
if (TLI.isTypeLegal(Ty) &&
|
||||
TLI.allowsMemoryAccess(Context, DL, Ty, FirstStoreAS,
|
||||
FirstStoreAlign, &IsFast) && IsFast)
|
||||
NumStoresToMerge = i + 1;
|
||||
}
|
||||
|
||||
return MergeStoresOfConstantsOrVecElts(StoreNodes, MemVT, NumStoresToMerge,
|
||||
false, true);
|
||||
bool Merged = MergeStoresOfConstantsOrVecElts(
|
||||
StoreNodes, MemVT, NumStoresToMerge, false, true);
|
||||
if (!Merged)
|
||||
break;
|
||||
// Remove merged stores for next iteration.
|
||||
StoreNodes.erase(StoreNodes.begin(),
|
||||
StoreNodes.begin() + NumStoresToMerge);
|
||||
RV = true;
|
||||
NumConsecutiveStores -= NumStoresToMerge;
|
||||
}
|
||||
return RV;
|
||||
}
|
||||
|
||||
// Below we handle the case of multiple consecutive stores that
|
||||
@ -15122,9 +15154,9 @@ SDValue DAGCombiner::XformToShuffleWithZero(SDNode *N) {
|
||||
|
||||
// Extract the sub element from the constant bit mask.
|
||||
if (DAG.getDataLayout().isBigEndian()) {
|
||||
Bits = Bits.lshr((Split - SubIdx - 1) * NumSubBits);
|
||||
Bits.lshrInPlace((Split - SubIdx - 1) * NumSubBits);
|
||||
} else {
|
||||
Bits = Bits.lshr(SubIdx * NumSubBits);
|
||||
Bits.lshrInPlace(SubIdx * NumSubBits);
|
||||
}
|
||||
|
||||
if (Split > 1)
|
||||
@ -16004,7 +16036,7 @@ SDValue DAGCombiner::buildSqrtEstimate(SDValue Op, SDNodeFlags *Flags) {
|
||||
|
||||
/// Return true if base is a frame index, which is known not to alias with
|
||||
/// anything but itself. Provides base object and offset as results.
|
||||
static bool FindBaseOffset(SDValue Ptr, SDValue &Base, int64_t &Offset,
|
||||
static bool findBaseOffset(SDValue Ptr, SDValue &Base, int64_t &Offset,
|
||||
const GlobalValue *&GV, const void *&CV) {
|
||||
// Assume it is a primitive operation.
|
||||
Base = Ptr; Offset = 0; GV = nullptr; CV = nullptr;
|
||||
@ -16057,53 +16089,56 @@ bool DAGCombiner::isAlias(LSBaseSDNode *Op0, LSBaseSDNode *Op1) const {
|
||||
return false;
|
||||
|
||||
// Gather base node and offset information.
|
||||
SDValue Base1, Base2;
|
||||
int64_t Offset1, Offset2;
|
||||
const GlobalValue *GV1, *GV2;
|
||||
const void *CV1, *CV2;
|
||||
bool isFrameIndex1 = FindBaseOffset(Op0->getBasePtr(),
|
||||
SDValue Base0, Base1;
|
||||
int64_t Offset0, Offset1;
|
||||
const GlobalValue *GV0, *GV1;
|
||||
const void *CV0, *CV1;
|
||||
bool IsFrameIndex0 = findBaseOffset(Op0->getBasePtr(),
|
||||
Base0, Offset0, GV0, CV0);
|
||||
bool IsFrameIndex1 = findBaseOffset(Op1->getBasePtr(),
|
||||
Base1, Offset1, GV1, CV1);
|
||||
bool isFrameIndex2 = FindBaseOffset(Op1->getBasePtr(),
|
||||
Base2, Offset2, GV2, CV2);
|
||||
|
||||
// If they have a same base address then check to see if they overlap.
|
||||
if (Base1 == Base2 || (GV1 && (GV1 == GV2)) || (CV1 && (CV1 == CV2)))
|
||||
return !((Offset1 + (Op0->getMemoryVT().getSizeInBits() >> 3)) <= Offset2 ||
|
||||
(Offset2 + (Op1->getMemoryVT().getSizeInBits() >> 3)) <= Offset1);
|
||||
// If they have the same base address, then check to see if they overlap.
|
||||
unsigned NumBytes0 = Op0->getMemoryVT().getSizeInBits() >> 3;
|
||||
unsigned NumBytes1 = Op1->getMemoryVT().getSizeInBits() >> 3;
|
||||
if (Base0 == Base1 || (GV0 && (GV0 == GV1)) || (CV0 && (CV0 == CV1)))
|
||||
return !((Offset0 + NumBytes0) <= Offset1 ||
|
||||
(Offset1 + NumBytes1) <= Offset0);
|
||||
|
||||
// It is possible for different frame indices to alias each other, mostly
|
||||
// when tail call optimization reuses return address slots for arguments.
|
||||
// To catch this case, look up the actual index of frame indices to compute
|
||||
// the real alias relationship.
|
||||
if (isFrameIndex1 && isFrameIndex2) {
|
||||
if (IsFrameIndex0 && IsFrameIndex1) {
|
||||
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
|
||||
Offset0 += MFI.getObjectOffset(cast<FrameIndexSDNode>(Base0)->getIndex());
|
||||
Offset1 += MFI.getObjectOffset(cast<FrameIndexSDNode>(Base1)->getIndex());
|
||||
Offset2 += MFI.getObjectOffset(cast<FrameIndexSDNode>(Base2)->getIndex());
|
||||
return !((Offset1 + (Op0->getMemoryVT().getSizeInBits() >> 3)) <= Offset2 ||
|
||||
(Offset2 + (Op1->getMemoryVT().getSizeInBits() >> 3)) <= Offset1);
|
||||
return !((Offset0 + NumBytes0) <= Offset1 ||
|
||||
(Offset1 + NumBytes1) <= Offset0);
|
||||
}
|
||||
|
||||
// Otherwise, if we know what the bases are, and they aren't identical, then
|
||||
// we know they cannot alias.
|
||||
if ((isFrameIndex1 || CV1 || GV1) && (isFrameIndex2 || CV2 || GV2))
|
||||
if ((IsFrameIndex0 || CV0 || GV0) && (IsFrameIndex1 || CV1 || GV1))
|
||||
return false;
|
||||
|
||||
// If we know required SrcValue1 and SrcValue2 have relatively large alignment
|
||||
// compared to the size and offset of the access, we may be able to prove they
|
||||
// do not alias. This check is conservative for now to catch cases created by
|
||||
// do not alias. This check is conservative for now to catch cases created by
|
||||
// splitting vector types.
|
||||
if ((Op0->getOriginalAlignment() == Op1->getOriginalAlignment()) &&
|
||||
(Op0->getSrcValueOffset() != Op1->getSrcValueOffset()) &&
|
||||
(Op0->getMemoryVT().getSizeInBits() >> 3 ==
|
||||
Op1->getMemoryVT().getSizeInBits() >> 3) &&
|
||||
(Op0->getOriginalAlignment() > (Op0->getMemoryVT().getSizeInBits() >> 3))) {
|
||||
int64_t OffAlign1 = Op0->getSrcValueOffset() % Op0->getOriginalAlignment();
|
||||
int64_t OffAlign2 = Op1->getSrcValueOffset() % Op1->getOriginalAlignment();
|
||||
int64_t SrcValOffset0 = Op0->getSrcValueOffset();
|
||||
int64_t SrcValOffset1 = Op1->getSrcValueOffset();
|
||||
unsigned OrigAlignment0 = Op0->getOriginalAlignment();
|
||||
unsigned OrigAlignment1 = Op1->getOriginalAlignment();
|
||||
if (OrigAlignment0 == OrigAlignment1 && SrcValOffset0 != SrcValOffset1 &&
|
||||
NumBytes0 == NumBytes1 && OrigAlignment0 > NumBytes0) {
|
||||
int64_t OffAlign0 = SrcValOffset0 % OrigAlignment0;
|
||||
int64_t OffAlign1 = SrcValOffset1 % OrigAlignment1;
|
||||
|
||||
// There is no overlap between these relatively aligned accesses of similar
|
||||
// size, return no alias.
|
||||
if ((OffAlign1 + (Op0->getMemoryVT().getSizeInBits() >> 3)) <= OffAlign2 ||
|
||||
(OffAlign2 + (Op1->getMemoryVT().getSizeInBits() >> 3)) <= OffAlign1)
|
||||
// size. Return no alias.
|
||||
if ((OffAlign0 + NumBytes0) <= OffAlign1 ||
|
||||
(OffAlign1 + NumBytes1) <= OffAlign0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -16115,19 +16150,17 @@ bool DAGCombiner::isAlias(LSBaseSDNode *Op0, LSBaseSDNode *Op1) const {
|
||||
CombinerAAOnlyFunc != DAG.getMachineFunction().getName())
|
||||
UseAA = false;
|
||||
#endif
|
||||
|
||||
if (UseAA &&
|
||||
Op0->getMemOperand()->getValue() && Op1->getMemOperand()->getValue()) {
|
||||
// Use alias analysis information.
|
||||
int64_t MinOffset = std::min(Op0->getSrcValueOffset(),
|
||||
Op1->getSrcValueOffset());
|
||||
int64_t Overlap1 = (Op0->getMemoryVT().getSizeInBits() >> 3) +
|
||||
Op0->getSrcValueOffset() - MinOffset;
|
||||
int64_t Overlap2 = (Op1->getMemoryVT().getSizeInBits() >> 3) +
|
||||
Op1->getSrcValueOffset() - MinOffset;
|
||||
int64_t MinOffset = std::min(SrcValOffset0, SrcValOffset1);
|
||||
int64_t Overlap0 = NumBytes0 + SrcValOffset0 - MinOffset;
|
||||
int64_t Overlap1 = NumBytes1 + SrcValOffset1 - MinOffset;
|
||||
AliasResult AAResult =
|
||||
AA.alias(MemoryLocation(Op0->getMemOperand()->getValue(), Overlap1,
|
||||
AA.alias(MemoryLocation(Op0->getMemOperand()->getValue(), Overlap0,
|
||||
UseTBAA ? Op0->getAAInfo() : AAMDNodes()),
|
||||
MemoryLocation(Op1->getMemOperand()->getValue(), Overlap2,
|
||||
MemoryLocation(Op1->getMemOperand()->getValue(), Overlap1,
|
||||
UseTBAA ? Op1->getAAInfo() : AAMDNodes()));
|
||||
if (AAResult == NoAlias)
|
||||
return false;
|
||||
|
@ -1164,9 +1164,11 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
|
||||
"Expected inlined-at fields to agree");
|
||||
if (Op->isReg()) {
|
||||
Op->setIsDebug(true);
|
||||
// A dbg.declare describes the address of a source variable, so lower it
|
||||
// into an indirect DBG_VALUE.
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(TargetOpcode::DBG_VALUE), false, Op->getReg(), 0,
|
||||
DI->getVariable(), DI->getExpression());
|
||||
TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true,
|
||||
Op->getReg(), 0, DI->getVariable(), DI->getExpression());
|
||||
} else
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(TargetOpcode::DBG_VALUE))
|
||||
|
@ -1343,7 +1343,7 @@ void SelectionDAGLegalize::getSignAsIntValue(FloatSignAsInt &State,
|
||||
// Convert to an integer of the same size.
|
||||
if (TLI.isTypeLegal(IVT)) {
|
||||
State.IntValue = DAG.getNode(ISD::BITCAST, DL, IVT, Value);
|
||||
State.SignMask = APInt::getSignBit(NumBits);
|
||||
State.SignMask = APInt::getSignMask(NumBits);
|
||||
State.SignBit = NumBits - 1;
|
||||
return;
|
||||
}
|
||||
@ -2984,7 +2984,7 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
|
||||
EVT NVT = Node->getValueType(0);
|
||||
APFloat apf(DAG.EVTToAPFloatSemantics(VT),
|
||||
APInt::getNullValue(VT.getSizeInBits()));
|
||||
APInt x = APInt::getSignBit(NVT.getSizeInBits());
|
||||
APInt x = APInt::getSignMask(NVT.getSizeInBits());
|
||||
(void)apf.convertFromAPInt(x, false, APFloat::rmNearestTiesToEven);
|
||||
Tmp1 = DAG.getConstantFP(apf, dl, VT);
|
||||
Tmp2 = DAG.getSetCC(dl, getSetCCResultType(VT),
|
||||
|
@ -72,7 +72,7 @@ bool DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
|
||||
case ISD::BUILD_PAIR: R = SoftenFloatRes_BUILD_PAIR(N); break;
|
||||
case ISD::ConstantFP: R = SoftenFloatRes_ConstantFP(N, ResNo); break;
|
||||
case ISD::EXTRACT_VECTOR_ELT:
|
||||
R = SoftenFloatRes_EXTRACT_VECTOR_ELT(N); break;
|
||||
R = SoftenFloatRes_EXTRACT_VECTOR_ELT(N, ResNo); break;
|
||||
case ISD::FABS: R = SoftenFloatRes_FABS(N, ResNo); break;
|
||||
case ISD::FMINNUM: R = SoftenFloatRes_FMINNUM(N); break;
|
||||
case ISD::FMAXNUM: R = SoftenFloatRes_FMAXNUM(N); break;
|
||||
@ -171,7 +171,10 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_ConstantFP(SDNode *N, unsigned ResNo) {
|
||||
}
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatRes_EXTRACT_VECTOR_ELT(SDNode *N) {
|
||||
SDValue DAGTypeLegalizer::SoftenFloatRes_EXTRACT_VECTOR_ELT(SDNode *N, unsigned ResNo) {
|
||||
// When LegalInHWReg, keep the extracted value in register.
|
||||
if (isLegalInHWReg(N->getValueType(ResNo)))
|
||||
return SDValue(N, ResNo);
|
||||
SDValue NewOp = BitConvertVectorToIntegerVector(N->getOperand(0));
|
||||
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(N),
|
||||
NewOp.getValueType().getVectorElementType(),
|
||||
|
@ -925,9 +925,9 @@ SDValue DAGTypeLegalizer::BitConvertVectorToIntegerVector(SDValue Op) {
|
||||
assert(Op.getValueType().isVector() && "Only applies to vectors!");
|
||||
unsigned EltWidth = Op.getScalarValueSizeInBits();
|
||||
EVT EltNVT = EVT::getIntegerVT(*DAG.getContext(), EltWidth);
|
||||
unsigned NumElts = Op.getValueType().getVectorNumElements();
|
||||
auto EltCnt = Op.getValueType().getVectorElementCount();
|
||||
return DAG.getNode(ISD::BITCAST, SDLoc(Op),
|
||||
EVT::getVectorVT(*DAG.getContext(), EltNVT, NumElts), Op);
|
||||
EVT::getVectorVT(*DAG.getContext(), EltNVT, EltCnt), Op);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::CreateStackStoreLoad(SDValue Op,
|
||||
|
@ -428,7 +428,7 @@ private:
|
||||
SDValue SoftenFloatRes_BITCAST(SDNode *N, unsigned ResNo);
|
||||
SDValue SoftenFloatRes_BUILD_PAIR(SDNode *N);
|
||||
SDValue SoftenFloatRes_ConstantFP(SDNode *N, unsigned ResNo);
|
||||
SDValue SoftenFloatRes_EXTRACT_VECTOR_ELT(SDNode *N);
|
||||
SDValue SoftenFloatRes_EXTRACT_VECTOR_ELT(SDNode *N, unsigned ResNo);
|
||||
SDValue SoftenFloatRes_FABS(SDNode *N, unsigned ResNo);
|
||||
SDValue SoftenFloatRes_FMINNUM(SDNode *N);
|
||||
SDValue SoftenFloatRes_FMAXNUM(SDNode *N);
|
||||
|
@ -1293,12 +1293,9 @@ void DAGTypeLegalizer::SplitVecRes_ExtendOp(SDNode *N, SDValue &Lo,
|
||||
if ((NumElements & 1) == 0 &&
|
||||
SrcVT.getSizeInBits() * 2 < DestVT.getSizeInBits()) {
|
||||
LLVMContext &Ctx = *DAG.getContext();
|
||||
EVT NewSrcVT = EVT::getVectorVT(
|
||||
Ctx, EVT::getIntegerVT(
|
||||
Ctx, SrcVT.getScalarSizeInBits() * 2),
|
||||
NumElements);
|
||||
EVT SplitSrcVT =
|
||||
EVT::getVectorVT(Ctx, SrcVT.getVectorElementType(), NumElements / 2);
|
||||
EVT NewSrcVT = SrcVT.widenIntegerVectorElementType(Ctx);
|
||||
EVT SplitSrcVT = SrcVT.getHalfNumVectorElementsVT(Ctx);
|
||||
|
||||
EVT SplitLoVT, SplitHiVT;
|
||||
std::tie(SplitLoVT, SplitHiVT) = DAG.GetSplitDestVTs(NewSrcVT);
|
||||
if (TLI.isTypeLegal(SrcVT) && !TLI.isTypeLegal(SplitSrcVT) &&
|
||||
@ -3012,8 +3009,8 @@ SDValue DAGTypeLegalizer::WidenVSELECTAndMask(SDNode *N) {
|
||||
// Don't touch if this will be scalarized.
|
||||
EVT FinalVT = VSelVT;
|
||||
while (getTypeAction(FinalVT) == TargetLowering::TypeSplitVector)
|
||||
FinalVT = EVT::getVectorVT(Ctx, FinalVT.getVectorElementType(),
|
||||
FinalVT.getVectorNumElements() / 2);
|
||||
FinalVT = FinalVT.getHalfNumVectorElementsVT(Ctx);
|
||||
|
||||
if (FinalVT.getVectorNumElements() == 1)
|
||||
return SDValue();
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user