mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
Vendor import of llvm trunk r302069:
https://llvm.org/svn/llvm-project/llvm/trunk@302069
This commit is contained in:
parent
a303c417bb
commit
148779df30
225 changed files with 5699 additions and 2676 deletions
|
|
@ -530,6 +530,8 @@ if(LLVM_LINK_LLVM_DYLIB OR LLVM_BUILD_LLVM_C_DYLIB)
|
|||
endif()
|
||||
option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" ${LLVM_BUILD_LLVM_DYLIB_default})
|
||||
|
||||
option(LLVM_DYLIB_SYMBOL_VERSIONING OFF)
|
||||
|
||||
option(LLVM_OPTIMIZED_TABLEGEN "Force TableGen to be built with optimization" OFF)
|
||||
if(CMAKE_CROSSCOMPILING OR (LLVM_OPTIMIZED_TABLEGEN AND (LLVM_ENABLE_ASSERTIONS OR CMAKE_CONFIGURATION_TYPES)))
|
||||
set(LLVM_USE_HOST_TOOLS ON)
|
||||
|
|
|
|||
|
|
@ -1539,7 +1539,7 @@ example:
|
|||
This function attribute indicates that the function does not have any
|
||||
effects besides calculating its result and does not have undefined behavior.
|
||||
Note that ``speculatable`` is not enough to conclude that along any
|
||||
particular exection path the number of calls to this function will not be
|
||||
particular execution path the number of calls to this function will not be
|
||||
externally observable. This attribute is only valid on functions
|
||||
and declarations, not on individual call sites. If a function is
|
||||
incorrectly marked as speculatable and really does exhibit
|
||||
|
|
@ -7915,7 +7915,7 @@ makes sense:
|
|||
; get pointers for 8 elements from array B
|
||||
%ptrs = getelementptr double, double* %B, <8 x i32> %C
|
||||
; load 8 elements from array B into A
|
||||
%A = call <8 x double> @llvm.masked.gather.v8f64(<8 x double*> %ptrs,
|
||||
%A = call <8 x double> @llvm.masked.gather.v8f64.v8p0f64(<8 x double*> %ptrs,
|
||||
i32 8, <8 x i1> %mask, <8 x double> %passthru)
|
||||
|
||||
Conversion Operations
|
||||
|
|
@ -12024,9 +12024,9 @@ This is an overloaded intrinsic. The loaded data are multiple scalar values of a
|
|||
|
||||
::
|
||||
|
||||
declare <16 x float> @llvm.masked.gather.v16f32 (<16 x float*> <ptrs>, i32 <alignment>, <16 x i1> <mask>, <16 x float> <passthru>)
|
||||
declare <2 x double> @llvm.masked.gather.v2f64 (<2 x double*> <ptrs>, i32 <alignment>, <2 x i1> <mask>, <2 x double> <passthru>)
|
||||
declare <8 x float*> @llvm.masked.gather.v8p0f32 (<8 x float**> <ptrs>, i32 <alignment>, <8 x i1> <mask>, <8 x float*> <passthru>)
|
||||
declare <16 x float> @llvm.masked.gather.v16f32.v16p0f32 (<16 x float*> <ptrs>, i32 <alignment>, <16 x i1> <mask>, <16 x float> <passthru>)
|
||||
declare <2 x double> @llvm.masked.gather.v2f64.v2p1f64 (<2 x double addrspace(1)*> <ptrs>, i32 <alignment>, <2 x i1> <mask>, <2 x double> <passthru>)
|
||||
declare <8 x float*> @llvm.masked.gather.v8p0f32.v8p0p0f32 (<8 x float**> <ptrs>, i32 <alignment>, <8 x i1> <mask>, <8 x float*> <passthru>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
|
@ -12049,7 +12049,7 @@ The semantics of this operation are equivalent to a sequence of conditional scal
|
|||
|
||||
::
|
||||
|
||||
%res = call <4 x double> @llvm.masked.gather.v4f64 (<4 x double*> %ptrs, i32 8, <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x double> undef)
|
||||
%res = call <4 x double> @llvm.masked.gather.v4f64.v4p0f64 (<4 x double*> %ptrs, i32 8, <4 x i1> <i1 true, i1 true, i1 true, i1 true>, <4 x double> undef)
|
||||
|
||||
;; The gather with all-true mask is equivalent to the following instruction sequence
|
||||
%ptr0 = extractelement <4 x double*> %ptrs, i32 0
|
||||
|
|
@ -12078,9 +12078,9 @@ This is an overloaded intrinsic. The data stored in memory is a vector of any in
|
|||
|
||||
::
|
||||
|
||||
declare void @llvm.masked.scatter.v8i32 (<8 x i32> <value>, <8 x i32*> <ptrs>, i32 <alignment>, <8 x i1> <mask>)
|
||||
declare void @llvm.masked.scatter.v16f32 (<16 x float> <value>, <16 x float*> <ptrs>, i32 <alignment>, <16 x i1> <mask>)
|
||||
declare void @llvm.masked.scatter.v4p0f64 (<4 x double*> <value>, <4 x double**> <ptrs>, i32 <alignment>, <4 x i1> <mask>)
|
||||
declare void @llvm.masked.scatter.v8i32.v8p0i32 (<8 x i32> <value>, <8 x i32*> <ptrs>, i32 <alignment>, <8 x i1> <mask>)
|
||||
declare void @llvm.masked.scatter.v16f32.v16p1f32 (<16 x float> <value>, <16 x float addrspace(1)*> <ptrs>, i32 <alignment>, <16 x i1> <mask>)
|
||||
declare void @llvm.masked.scatter.v4p0f64.v4p0p0f64 (<4 x double*> <value>, <4 x double**> <ptrs>, i32 <alignment>, <4 x i1> <mask>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
|
@ -12101,7 +12101,7 @@ The '``llvm.masked.scatter``' intrinsics is designed for writing selected vector
|
|||
::
|
||||
|
||||
;; This instruction unconditionally stores data vector in multiple addresses
|
||||
call @llvm.masked.scatter.v8i32 (<8 x i32> %value, <8 x i32*> %ptrs, i32 4, <8 x i1> <true, true, .. true>)
|
||||
call @llvm.masked.scatter.v8i32.v8p0i32 (<8 x i32> %value, <8 x i32*> %ptrs, i32 4, <8 x i1> <true, true, .. true>)
|
||||
|
||||
;; It is equivalent to a list of scalar stores
|
||||
%val0 = extractelement <8 x i32> %value, i32 0
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ private:
|
|||
union {
|
||||
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
|
||||
uint64_t *pVal; ///< Used to store the >64 bits integer value.
|
||||
};
|
||||
} U;
|
||||
|
||||
unsigned BitWidth; ///< The number of bits in this APInt.
|
||||
|
||||
|
|
@ -98,7 +98,9 @@ private:
|
|||
///
|
||||
/// This constructor is used only internally for speed of construction of
|
||||
/// temporaries. It is unsafe for general use so it is not public.
|
||||
APInt(uint64_t *val, unsigned bits) : pVal(val), BitWidth(bits) {}
|
||||
APInt(uint64_t *val, unsigned bits) : BitWidth(bits) {
|
||||
U.pVal = val;
|
||||
}
|
||||
|
||||
/// \brief Determine if this APInt just has one word to store value.
|
||||
///
|
||||
|
|
@ -143,16 +145,16 @@ private:
|
|||
// Mask out the high bits.
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - WordBits);
|
||||
if (isSingleWord())
|
||||
VAL &= mask;
|
||||
U.VAL &= mask;
|
||||
else
|
||||
pVal[getNumWords() - 1] &= mask;
|
||||
U.pVal[getNumWords() - 1] &= mask;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Get the word corresponding to a bit position
|
||||
/// \returns the corresponding word for the specified bit position.
|
||||
uint64_t getWord(unsigned bitPosition) const {
|
||||
return isSingleWord() ? VAL : pVal[whichWord(bitPosition)];
|
||||
return isSingleWord() ? U.VAL : U.pVal[whichWord(bitPosition)];
|
||||
}
|
||||
|
||||
/// \brief Convert a char array into an APInt
|
||||
|
|
@ -258,7 +260,7 @@ public:
|
|||
: BitWidth(numBits) {
|
||||
assert(BitWidth && "bitwidth too small");
|
||||
if (isSingleWord()) {
|
||||
VAL = val;
|
||||
U.VAL = val;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
initSlowCase(val, isSigned);
|
||||
|
|
@ -300,20 +302,21 @@ public:
|
|||
/// @brief Copy Constructor.
|
||||
APInt(const APInt &that) : BitWidth(that.BitWidth) {
|
||||
if (isSingleWord())
|
||||
VAL = that.VAL;
|
||||
U.VAL = that.U.VAL;
|
||||
else
|
||||
initSlowCase(that);
|
||||
}
|
||||
|
||||
/// \brief Move Constructor.
|
||||
APInt(APInt &&that) : VAL(that.VAL), BitWidth(that.BitWidth) {
|
||||
APInt(APInt &&that) : BitWidth(that.BitWidth) {
|
||||
memcpy(&U, &that.U, sizeof(U));
|
||||
that.BitWidth = 0;
|
||||
}
|
||||
|
||||
/// \brief Destructor.
|
||||
~APInt() {
|
||||
if (needsCleanup())
|
||||
delete[] pVal;
|
||||
delete[] U.pVal;
|
||||
}
|
||||
|
||||
/// \brief Default constructor that creates an uninteresting APInt
|
||||
|
|
@ -321,7 +324,7 @@ public:
|
|||
///
|
||||
/// This is useful for object deserialization (pair this with the static
|
||||
/// method Read).
|
||||
explicit APInt() : VAL(0), BitWidth(1) {}
|
||||
explicit APInt() : BitWidth(1) { U.VAL = 0; }
|
||||
|
||||
/// \brief Returns whether this instance allocated memory.
|
||||
bool needsCleanup() const { return !isSingleWord(); }
|
||||
|
|
@ -373,7 +376,7 @@ public:
|
|||
/// This checks to see if the value has all bits of the APInt are set or not.
|
||||
bool isAllOnesValue() const {
|
||||
if (isSingleWord())
|
||||
return VAL == WORD_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return U.VAL == WORD_MAX >> (APINT_BITS_PER_WORD - BitWidth);
|
||||
return countPopulationSlowCase() == BitWidth;
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +431,7 @@ public:
|
|||
/// \returns true if the argument APInt value is a power of two > 0.
|
||||
bool isPowerOf2() const {
|
||||
if (isSingleWord())
|
||||
return isPowerOf2_64(VAL);
|
||||
return isPowerOf2_64(U.VAL);
|
||||
return countPopulationSlowCase() == 1;
|
||||
}
|
||||
|
||||
|
|
@ -461,7 +464,7 @@ public:
|
|||
assert(numBits != 0 && "numBits must be non-zero");
|
||||
assert(numBits <= BitWidth && "numBits out of range");
|
||||
if (isSingleWord())
|
||||
return VAL == (WORD_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
return U.VAL == (WORD_MAX >> (APINT_BITS_PER_WORD - numBits));
|
||||
unsigned Ones = countTrailingOnesSlowCase();
|
||||
return (numBits == Ones) &&
|
||||
((Ones + countLeadingZerosSlowCase()) == BitWidth);
|
||||
|
|
@ -472,7 +475,7 @@ public:
|
|||
/// Ex. isMask(0x0000FFFFU) == true.
|
||||
bool isMask() const {
|
||||
if (isSingleWord())
|
||||
return isMask_64(VAL);
|
||||
return isMask_64(U.VAL);
|
||||
unsigned Ones = countTrailingOnesSlowCase();
|
||||
return (Ones > 0) && ((Ones + countLeadingZerosSlowCase()) == BitWidth);
|
||||
}
|
||||
|
|
@ -481,7 +484,7 @@ public:
|
|||
/// the remainder zero.
|
||||
bool isShiftedMask() const {
|
||||
if (isSingleWord())
|
||||
return isShiftedMask_64(VAL);
|
||||
return isShiftedMask_64(U.VAL);
|
||||
unsigned Ones = countPopulationSlowCase();
|
||||
unsigned LeadZ = countLeadingZerosSlowCase();
|
||||
return (Ones + LeadZ + countTrailingZeros()) == BitWidth;
|
||||
|
|
@ -639,8 +642,8 @@ public:
|
|||
/// conversions.
|
||||
const uint64_t *getRawData() const {
|
||||
if (isSingleWord())
|
||||
return &VAL;
|
||||
return &pVal[0];
|
||||
return &U.VAL;
|
||||
return &U.pVal[0];
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
|
@ -686,7 +689,7 @@ public:
|
|||
/// \returns true if *this is zero, false otherwise.
|
||||
bool operator!() const {
|
||||
if (isSingleWord())
|
||||
return VAL == 0;
|
||||
return U.VAL == 0;
|
||||
return countLeadingZerosSlowCase() == BitWidth;
|
||||
}
|
||||
|
||||
|
|
@ -700,7 +703,7 @@ public:
|
|||
APInt &operator=(const APInt &RHS) {
|
||||
// If the bitwidths are the same, we can avoid mucking with memory
|
||||
if (isSingleWord() && RHS.isSingleWord()) {
|
||||
VAL = RHS.VAL;
|
||||
U.VAL = RHS.U.VAL;
|
||||
BitWidth = RHS.BitWidth;
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
|
@ -713,11 +716,11 @@ public:
|
|||
APInt &operator=(APInt &&that) {
|
||||
assert(this != &that && "Self-move not supported");
|
||||
if (!isSingleWord())
|
||||
delete[] pVal;
|
||||
delete[] U.pVal;
|
||||
|
||||
// Use memcpy so that type based alias analysis sees both VAL and pVal
|
||||
// as modified.
|
||||
memcpy(&VAL, &that.VAL, sizeof(uint64_t));
|
||||
memcpy(&U, &that.U, sizeof(U));
|
||||
|
||||
BitWidth = that.BitWidth;
|
||||
that.BitWidth = 0;
|
||||
|
|
@ -734,11 +737,11 @@ public:
|
|||
/// \returns *this after assignment of RHS value.
|
||||
APInt &operator=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL = RHS;
|
||||
U.VAL = RHS;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
pVal[0] = RHS;
|
||||
memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
|
||||
U.pVal[0] = RHS;
|
||||
memset(U.pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -752,7 +755,7 @@ public:
|
|||
APInt &operator&=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
VAL &= RHS.VAL;
|
||||
U.VAL &= RHS.U.VAL;
|
||||
else
|
||||
AndAssignSlowCase(RHS);
|
||||
return *this;
|
||||
|
|
@ -765,11 +768,11 @@ public:
|
|||
/// the LHS.
|
||||
APInt &operator&=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL &= RHS;
|
||||
U.VAL &= RHS;
|
||||
return *this;
|
||||
}
|
||||
pVal[0] &= RHS;
|
||||
memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
|
||||
U.pVal[0] &= RHS;
|
||||
memset(U.pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -782,7 +785,7 @@ public:
|
|||
APInt &operator|=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
VAL |= RHS.VAL;
|
||||
U.VAL |= RHS.U.VAL;
|
||||
else
|
||||
OrAssignSlowCase(RHS);
|
||||
return *this;
|
||||
|
|
@ -795,10 +798,10 @@ public:
|
|||
/// the LHS.
|
||||
APInt &operator|=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL |= RHS;
|
||||
U.VAL |= RHS;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
pVal[0] |= RHS;
|
||||
U.pVal[0] |= RHS;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -812,7 +815,7 @@ public:
|
|||
APInt &operator^=(const APInt &RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
VAL ^= RHS.VAL;
|
||||
U.VAL ^= RHS.U.VAL;
|
||||
else
|
||||
XorAssignSlowCase(RHS);
|
||||
return *this;
|
||||
|
|
@ -825,10 +828,10 @@ public:
|
|||
/// the LHS.
|
||||
APInt &operator^=(uint64_t RHS) {
|
||||
if (isSingleWord()) {
|
||||
VAL ^= RHS;
|
||||
U.VAL ^= RHS;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
pVal[0] ^= RHS;
|
||||
U.pVal[0] ^= RHS;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -865,9 +868,9 @@ public:
|
|||
assert(ShiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
if (ShiftAmt == BitWidth)
|
||||
VAL = 0;
|
||||
U.VAL = 0;
|
||||
else
|
||||
VAL <<= ShiftAmt;
|
||||
U.VAL <<= ShiftAmt;
|
||||
return clearUnusedBits();
|
||||
}
|
||||
shlSlowCase(ShiftAmt);
|
||||
|
|
@ -913,11 +916,11 @@ public:
|
|||
void ashrInPlace(unsigned ShiftAmt) {
|
||||
assert(ShiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
int64_t SExtVAL = SignExtend64(VAL, BitWidth);
|
||||
int64_t SExtVAL = SignExtend64(U.VAL, BitWidth);
|
||||
if (ShiftAmt == BitWidth)
|
||||
VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // Fill with sign bit.
|
||||
U.VAL = SExtVAL >> (APINT_BITS_PER_WORD - 1); // Fill with sign bit.
|
||||
else
|
||||
VAL = SExtVAL >> ShiftAmt;
|
||||
U.VAL = SExtVAL >> ShiftAmt;
|
||||
clearUnusedBits();
|
||||
return;
|
||||
}
|
||||
|
|
@ -938,9 +941,9 @@ public:
|
|||
assert(ShiftAmt <= BitWidth && "Invalid shift amount");
|
||||
if (isSingleWord()) {
|
||||
if (ShiftAmt == BitWidth)
|
||||
VAL = 0;
|
||||
U.VAL = 0;
|
||||
else
|
||||
VAL >>= ShiftAmt;
|
||||
U.VAL >>= ShiftAmt;
|
||||
return;
|
||||
}
|
||||
lshrSlowCase(ShiftAmt);
|
||||
|
|
@ -1059,7 +1062,7 @@ public:
|
|||
bool operator[](unsigned bitPosition) const {
|
||||
assert(bitPosition < getBitWidth() && "Bit position out of bounds!");
|
||||
return (maskBit(bitPosition) &
|
||||
(isSingleWord() ? VAL : pVal[whichWord(bitPosition)])) !=
|
||||
(isSingleWord() ? U.VAL : U.pVal[whichWord(bitPosition)])) !=
|
||||
0;
|
||||
}
|
||||
|
||||
|
|
@ -1074,7 +1077,7 @@ public:
|
|||
bool operator==(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Comparison requires equal bit widths");
|
||||
if (isSingleWord())
|
||||
return VAL == RHS.VAL;
|
||||
return U.VAL == RHS.U.VAL;
|
||||
return EqualSlowCase(RHS);
|
||||
}
|
||||
|
||||
|
|
@ -1265,7 +1268,7 @@ public:
|
|||
bool intersects(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return (VAL & RHS.VAL) != 0;
|
||||
return (U.VAL & RHS.U.VAL) != 0;
|
||||
return intersectsSlowCase(RHS);
|
||||
}
|
||||
|
||||
|
|
@ -1273,7 +1276,7 @@ public:
|
|||
bool isSubsetOf(const APInt &RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return (VAL & ~RHS.VAL) == 0;
|
||||
return (U.VAL & ~RHS.U.VAL) == 0;
|
||||
return isSubsetOfSlowCase(RHS);
|
||||
}
|
||||
|
||||
|
|
@ -1333,10 +1336,10 @@ public:
|
|||
/// \brief Set every bit to 1.
|
||||
void setAllBits() {
|
||||
if (isSingleWord())
|
||||
VAL = WORD_MAX;
|
||||
U.VAL = WORD_MAX;
|
||||
else
|
||||
// Set all the bits in all the words.
|
||||
memset(pVal, -1, getNumWords() * APINT_WORD_SIZE);
|
||||
memset(U.pVal, -1, getNumWords() * APINT_WORD_SIZE);
|
||||
// Clear the unused ones
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
|
@ -1348,9 +1351,9 @@ public:
|
|||
assert(BitPosition <= BitWidth && "BitPosition out of range");
|
||||
WordType Mask = maskBit(BitPosition);
|
||||
if (isSingleWord())
|
||||
VAL |= Mask;
|
||||
U.VAL |= Mask;
|
||||
else
|
||||
pVal[whichWord(BitPosition)] |= Mask;
|
||||
U.pVal[whichWord(BitPosition)] |= Mask;
|
||||
}
|
||||
|
||||
/// Set the sign bit to 1.
|
||||
|
|
@ -1369,9 +1372,9 @@ public:
|
|||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - (hiBit - loBit));
|
||||
mask <<= loBit;
|
||||
if (isSingleWord())
|
||||
VAL |= mask;
|
||||
U.VAL |= mask;
|
||||
else
|
||||
pVal[0] |= mask;
|
||||
U.pVal[0] |= mask;
|
||||
} else {
|
||||
setBitsSlowCase(loBit, hiBit);
|
||||
}
|
||||
|
|
@ -1395,9 +1398,9 @@ public:
|
|||
/// \brief Set every bit to 0.
|
||||
void clearAllBits() {
|
||||
if (isSingleWord())
|
||||
VAL = 0;
|
||||
U.VAL = 0;
|
||||
else
|
||||
memset(pVal, 0, getNumWords() * APINT_WORD_SIZE);
|
||||
memset(U.pVal, 0, getNumWords() * APINT_WORD_SIZE);
|
||||
}
|
||||
|
||||
/// \brief Set a given bit to 0.
|
||||
|
|
@ -1407,9 +1410,9 @@ public:
|
|||
assert(BitPosition <= BitWidth && "BitPosition out of range");
|
||||
WordType Mask = ~maskBit(BitPosition);
|
||||
if (isSingleWord())
|
||||
VAL &= Mask;
|
||||
U.VAL &= Mask;
|
||||
else
|
||||
pVal[whichWord(BitPosition)] &= Mask;
|
||||
U.pVal[whichWord(BitPosition)] &= Mask;
|
||||
}
|
||||
|
||||
/// Set the sign bit to 0.
|
||||
|
|
@ -1420,7 +1423,7 @@ public:
|
|||
/// \brief Toggle every bit to its opposite value.
|
||||
void flipAllBits() {
|
||||
if (isSingleWord()) {
|
||||
VAL ^= WORD_MAX;
|
||||
U.VAL ^= WORD_MAX;
|
||||
clearUnusedBits();
|
||||
} else {
|
||||
flipAllBitsSlowCase();
|
||||
|
|
@ -1500,9 +1503,9 @@ public:
|
|||
/// uint64_t. Otherwise an assertion will result.
|
||||
uint64_t getZExtValue() const {
|
||||
if (isSingleWord())
|
||||
return VAL;
|
||||
return U.VAL;
|
||||
assert(getActiveBits() <= 64 && "Too many bits for uint64_t");
|
||||
return pVal[0];
|
||||
return U.pVal[0];
|
||||
}
|
||||
|
||||
/// \brief Get sign extended value
|
||||
|
|
@ -1512,9 +1515,9 @@ public:
|
|||
/// int64_t. Otherwise an assertion will result.
|
||||
int64_t getSExtValue() const {
|
||||
if (isSingleWord())
|
||||
return SignExtend64(VAL, BitWidth);
|
||||
return SignExtend64(U.VAL, BitWidth);
|
||||
assert(getMinSignedBits() <= 64 && "Too many bits for int64_t");
|
||||
return int64_t(pVal[0]);
|
||||
return int64_t(U.pVal[0]);
|
||||
}
|
||||
|
||||
/// \brief Get bits required for string value.
|
||||
|
|
@ -1534,7 +1537,7 @@ public:
|
|||
unsigned countLeadingZeros() const {
|
||||
if (isSingleWord()) {
|
||||
unsigned unusedBits = APINT_BITS_PER_WORD - BitWidth;
|
||||
return llvm::countLeadingZeros(VAL) - unusedBits;
|
||||
return llvm::countLeadingZeros(U.VAL) - unusedBits;
|
||||
}
|
||||
return countLeadingZerosSlowCase();
|
||||
}
|
||||
|
|
@ -1575,7 +1578,7 @@ public:
|
|||
/// of ones from the least significant bit to the first zero bit.
|
||||
unsigned countTrailingOnes() const {
|
||||
if (isSingleWord())
|
||||
return llvm::countTrailingOnes(VAL);
|
||||
return llvm::countTrailingOnes(U.VAL);
|
||||
return countTrailingOnesSlowCase();
|
||||
}
|
||||
|
||||
|
|
@ -1587,7 +1590,7 @@ public:
|
|||
/// \returns 0 if the value is zero, otherwise returns the number of set bits.
|
||||
unsigned countPopulation() const {
|
||||
if (isSingleWord())
|
||||
return llvm::countPopulation(VAL);
|
||||
return llvm::countPopulation(U.VAL);
|
||||
return countPopulationSlowCase();
|
||||
}
|
||||
|
||||
|
|
@ -1646,7 +1649,7 @@ public:
|
|||
uint64_t I;
|
||||
double D;
|
||||
} T;
|
||||
T.I = (isSingleWord() ? VAL : pVal[0]);
|
||||
T.I = (isSingleWord() ? U.VAL : U.pVal[0]);
|
||||
return T.D;
|
||||
}
|
||||
|
||||
|
|
@ -1660,7 +1663,7 @@ public:
|
|||
unsigned I;
|
||||
float F;
|
||||
} T;
|
||||
T.I = unsigned((isSingleWord() ? VAL : pVal[0]));
|
||||
T.I = unsigned((isSingleWord() ? U.VAL : U.pVal[0]));
|
||||
return T.F;
|
||||
}
|
||||
|
||||
|
|
@ -1718,7 +1721,7 @@ public:
|
|||
// get 0. If VAL is 0, we get WORD_MAX which gets truncated to
|
||||
// UINT32_MAX.
|
||||
if (BitWidth == 1)
|
||||
return VAL - 1;
|
||||
return U.VAL - 1;
|
||||
|
||||
// Handle the zero case.
|
||||
if (isNullValue())
|
||||
|
|
|
|||
|
|
@ -346,29 +346,21 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features,
|
|||
Module &M) {
|
||||
for (auto &F : M) {
|
||||
auto &Ctx = F.getContext();
|
||||
AttributeList Attrs = F.getAttributes(), NewAttrs;
|
||||
AttributeList Attrs = F.getAttributes();
|
||||
AttrBuilder NewAttrs;
|
||||
|
||||
if (!CPU.empty())
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"target-cpu", CPU);
|
||||
|
||||
NewAttrs.addAttribute("target-cpu", CPU);
|
||||
if (!Features.empty())
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"target-features", Features);
|
||||
|
||||
NewAttrs.addAttribute("target-features", Features);
|
||||
if (DisableFPElim.getNumOccurrences() > 0)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"no-frame-pointer-elim",
|
||||
DisableFPElim ? "true" : "false");
|
||||
|
||||
NewAttrs.addAttribute("no-frame-pointer-elim",
|
||||
DisableFPElim ? "true" : "false");
|
||||
if (DisableTailCalls.getNumOccurrences() > 0)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"disable-tail-calls",
|
||||
toStringRef(DisableTailCalls));
|
||||
|
||||
NewAttrs.addAttribute("disable-tail-calls",
|
||||
toStringRef(DisableTailCalls));
|
||||
if (StackRealign)
|
||||
NewAttrs = NewAttrs.addAttribute(Ctx, AttributeList::FunctionIndex,
|
||||
"stackrealign");
|
||||
NewAttrs.addAttribute("stackrealign");
|
||||
|
||||
if (TrapFuncName.getNumOccurrences() > 0)
|
||||
for (auto &B : F)
|
||||
|
|
@ -382,8 +374,8 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features,
|
|||
Attribute::get(Ctx, "trap-func-name", TrapFuncName));
|
||||
|
||||
// Let NewAttrs override Attrs.
|
||||
NewAttrs = Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs);
|
||||
F.setAttributes(NewAttrs);
|
||||
F.setAttributes(
|
||||
Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> {
|
|||
typedef void ContextType;
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Len,
|
||||
codeview::CVRecord<Kind> &Item, void *Ctx) {
|
||||
codeview::CVRecord<Kind> &Item) {
|
||||
using namespace codeview;
|
||||
const RecordPrefix *Prefix = nullptr;
|
||||
BinaryStreamReader Reader(Stream);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class StringTable;
|
||||
|
||||
struct FileChecksumEntry {
|
||||
uint32_t FileNameOffset; // Byte offset of filename in global stringtable.
|
||||
FileChecksumKind Kind; // The type of checksum.
|
||||
|
|
@ -35,7 +37,7 @@ public:
|
|||
typedef void ContextType;
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Len,
|
||||
codeview::FileChecksumEntry &Item, void *Ctx);
|
||||
codeview::FileChecksumEntry &Item);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -55,8 +57,8 @@ public:
|
|||
|
||||
Error initialize(BinaryStreamReader Reader);
|
||||
|
||||
Iterator begin() const { return Checksums.begin(); }
|
||||
Iterator end() const { return Checksums.end(); }
|
||||
Iterator begin() { return Checksums.begin(); }
|
||||
Iterator end() { return Checksums.end(); }
|
||||
|
||||
const FileChecksumArray &getArray() const { return Checksums; }
|
||||
|
||||
|
|
@ -66,20 +68,22 @@ private:
|
|||
|
||||
class ModuleDebugFileChecksumFragment final : public ModuleDebugFragment {
|
||||
public:
|
||||
ModuleDebugFileChecksumFragment();
|
||||
explicit ModuleDebugFileChecksumFragment(StringTable &Strings);
|
||||
|
||||
static bool classof(const ModuleDebugFragment *S) {
|
||||
return S->kind() == ModuleDebugFragmentKind::FileChecksums;
|
||||
}
|
||||
|
||||
void addChecksum(uint32_t StringTableOffset, FileChecksumKind Kind,
|
||||
void addChecksum(StringRef FileName, FileChecksumKind Kind,
|
||||
ArrayRef<uint8_t> Bytes);
|
||||
|
||||
uint32_t calculateSerializedLength() override;
|
||||
Error commit(BinaryStreamWriter &Writer) override;
|
||||
uint32_t mapChecksumOffset(uint32_t StringTableOffset) const;
|
||||
uint32_t mapChecksumOffset(StringRef FileName) const;
|
||||
|
||||
private:
|
||||
StringTable &Strings;
|
||||
|
||||
DenseMap<uint32_t, uint32_t> OffsetMap;
|
||||
uint32_t SerializedSize = 0;
|
||||
llvm::BumpPtrAllocator Storage;
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@ private:
|
|||
ModuleDebugFragment &Frag;
|
||||
};
|
||||
|
||||
typedef VarStreamArray<ModuleDebugFragmentRecord> ModuleDebugFragmentArray;
|
||||
|
||||
} // namespace codeview
|
||||
|
||||
template <>
|
||||
|
|
@ -66,13 +64,17 @@ struct VarStreamArrayExtractor<codeview::ModuleDebugFragmentRecord> {
|
|||
typedef void ContextType;
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Length,
|
||||
codeview::ModuleDebugFragmentRecord &Info, void *Ctx) {
|
||||
codeview::ModuleDebugFragmentRecord &Info) {
|
||||
if (auto EC = codeview::ModuleDebugFragmentRecord::initialize(Stream, Info))
|
||||
return EC;
|
||||
Length = Info.getRecordLength();
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
namespace codeview {
|
||||
typedef VarStreamArray<ModuleDebugFragmentRecord> ModuleDebugFragmentArray;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ namespace llvm {
|
|||
namespace codeview {
|
||||
|
||||
class ModuleDebugInlineeLineFragmentRef;
|
||||
class ModuleDebugFileChecksumFragment;
|
||||
class StringTable;
|
||||
|
||||
enum class InlineeLinesSignature : uint32_t {
|
||||
Normal, // CV_INLINEE_SOURCE_LINE_SIGNATURE
|
||||
|
|
@ -42,11 +44,10 @@ struct InlineeSourceLine {
|
|||
}
|
||||
|
||||
template <> struct VarStreamArrayExtractor<codeview::InlineeSourceLine> {
|
||||
typedef codeview::ModuleDebugInlineeLineFragmentRef ContextType;
|
||||
typedef bool ContextType;
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Len,
|
||||
codeview::InlineeSourceLine &Item,
|
||||
ContextType *Fragment);
|
||||
codeview::InlineeSourceLine &Item, bool HasExtraFiles);
|
||||
};
|
||||
|
||||
namespace codeview {
|
||||
|
|
@ -74,7 +75,8 @@ private:
|
|||
|
||||
class ModuleDebugInlineeLineFragment final : public ModuleDebugFragment {
|
||||
public:
|
||||
explicit ModuleDebugInlineeLineFragment(bool HasExtraFiles);
|
||||
ModuleDebugInlineeLineFragment(ModuleDebugFileChecksumFragment &Checksums,
|
||||
bool HasExtraFiles);
|
||||
|
||||
static bool classof(const ModuleDebugFragment *S) {
|
||||
return S->kind() == ModuleDebugFragmentKind::InlineeLines;
|
||||
|
|
@ -83,11 +85,12 @@ public:
|
|||
Error commit(BinaryStreamWriter &Writer) override;
|
||||
uint32_t calculateSerializedLength() override;
|
||||
|
||||
void addInlineSite(TypeIndex FuncId, uint32_t FileOffset,
|
||||
uint32_t SourceLine);
|
||||
void addExtraFile(uint32_t FileOffset);
|
||||
void addInlineSite(TypeIndex FuncId, StringRef FileName, uint32_t SourceLine);
|
||||
void addExtraFile(StringRef FileName);
|
||||
|
||||
private:
|
||||
ModuleDebugFileChecksumFragment &Checksums;
|
||||
|
||||
bool HasExtraFiles = false;
|
||||
uint32_t ExtraFileCount = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class ModuleDebugFileChecksumFragment;
|
||||
class StringTable;
|
||||
|
||||
// Corresponds to the `CV_DebugSLinesHeader_t` structure.
|
||||
struct LineFragmentHeader {
|
||||
support::ulittle32_t RelocOffset; // Code offset of line contribution.
|
||||
|
|
@ -61,10 +64,10 @@ struct LineColumnEntry {
|
|||
|
||||
class LineColumnExtractor {
|
||||
public:
|
||||
typedef const LineFragmentHeader ContextType;
|
||||
typedef const LineFragmentHeader *ContextType;
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Len,
|
||||
LineColumnEntry &Item, const LineFragmentHeader *Header);
|
||||
LineColumnEntry &Item, const LineFragmentHeader *Ctx);
|
||||
};
|
||||
|
||||
class ModuleDebugLineFragmentRef final : public ModuleDebugFragmentRef {
|
||||
|
|
@ -104,13 +107,14 @@ class ModuleDebugLineFragment final : public ModuleDebugFragment {
|
|||
};
|
||||
|
||||
public:
|
||||
ModuleDebugLineFragment();
|
||||
ModuleDebugLineFragment(ModuleDebugFileChecksumFragment &Checksums,
|
||||
StringTable &Strings);
|
||||
|
||||
static bool classof(const ModuleDebugFragment *S) {
|
||||
return S->kind() == ModuleDebugFragmentKind::Lines;
|
||||
}
|
||||
|
||||
void createBlock(uint32_t ChecksumBufferOffset);
|
||||
void createBlock(StringRef FileName);
|
||||
void addLineInfo(uint32_t Offset, const LineInfo &Line);
|
||||
void addLineAndColumnInfo(uint32_t Offset, const LineInfo &Line,
|
||||
uint32_t ColStart, uint32_t ColEnd);
|
||||
|
|
@ -125,6 +129,8 @@ public:
|
|||
bool hasColumnInfo() const;
|
||||
|
||||
private:
|
||||
ModuleDebugFileChecksumFragment &Checksums;
|
||||
|
||||
uint16_t RelocOffset = 0;
|
||||
uint16_t RelocSegment = 0;
|
||||
uint32_t CodeSize = 0;
|
||||
|
|
|
|||
75
include/llvm/DebugInfo/CodeView/StringTable.h
Normal file
75
include/llvm/DebugInfo/CodeView/StringTable.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
//===- StringTable.h - CodeView String Table Reader/Writer ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_STRINGTABLE_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_STRINGTABLE_H
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BinaryStreamReader;
|
||||
class BinaryStreamRef;
|
||||
class BinaryStreamWriter;
|
||||
|
||||
namespace codeview {
|
||||
|
||||
/// Represents a read-only view of a CodeView string table. This is a very
|
||||
/// simple flat buffer consisting of null-terminated strings, where strings
|
||||
/// are retrieved by their offset in the buffer. StringTableRef does not own
|
||||
/// the underlying storage for the buffer.
|
||||
class StringTableRef {
|
||||
public:
|
||||
StringTableRef();
|
||||
|
||||
Error initialize(BinaryStreamRef Contents);
|
||||
|
||||
Expected<StringRef> getString(uint32_t Offset) const;
|
||||
|
||||
bool valid() const { return Stream.valid(); }
|
||||
|
||||
private:
|
||||
BinaryStreamRef Stream;
|
||||
};
|
||||
|
||||
/// Represents a read-write view of a CodeView string table. StringTable owns
|
||||
/// the underlying storage for the table, and is capable of serializing the
|
||||
/// string table into a format understood by StringTableRef.
|
||||
class StringTable {
|
||||
public:
|
||||
// If string S does not exist in the string table, insert it.
|
||||
// Returns the ID for S.
|
||||
uint32_t insert(StringRef S);
|
||||
|
||||
// Return the ID for string S. Assumes S exists in the table.
|
||||
uint32_t getStringId(StringRef S) const;
|
||||
|
||||
uint32_t calculateSerializedSize() const;
|
||||
Error commit(BinaryStreamWriter &Writer) const;
|
||||
|
||||
uint32_t size() const;
|
||||
|
||||
StringMap<uint32_t>::const_iterator begin() const { return Strings.begin(); }
|
||||
|
||||
StringMap<uint32_t>::const_iterator end() const { return Strings.end(); }
|
||||
|
||||
private:
|
||||
StringMap<uint32_t> Strings;
|
||||
uint32_t StringSize = 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -19,13 +19,15 @@ class BinaryStreamReader;
|
|||
|
||||
namespace codeview {
|
||||
|
||||
class StringTableRef;
|
||||
|
||||
class SymbolVisitorDelegate {
|
||||
public:
|
||||
virtual ~SymbolVisitorDelegate() = default;
|
||||
|
||||
virtual uint32_t getRecordOffset(BinaryStreamReader Reader) = 0;
|
||||
virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0;
|
||||
virtual StringRef getStringTable() = 0;
|
||||
virtual StringTableRef getStringTable() = 0;
|
||||
};
|
||||
|
||||
} // end namespace codeview
|
||||
|
|
|
|||
|
|
@ -172,6 +172,9 @@ public:
|
|||
return DWOCUs[index].get();
|
||||
}
|
||||
|
||||
/// Get a DIE given an exact offset.
|
||||
DWARFDie getDIEForOffset(uint32_t Offset);
|
||||
|
||||
const DWARFUnitIndex &getCUIndex();
|
||||
DWARFGdbIndex &getGdbIndex();
|
||||
const DWARFUnitIndex &getTUIndex();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public:
|
|||
struct FileNameEntry {
|
||||
FileNameEntry() = default;
|
||||
|
||||
const char *Name = nullptr;
|
||||
StringRef Name = StringRef();
|
||||
uint64_t DirIdx = 0;
|
||||
uint64_t ModTime = 0;
|
||||
uint64_t Length = 0;
|
||||
|
|
@ -44,6 +44,10 @@ public:
|
|||
uint64_t TotalLength;
|
||||
/// Version identifier for the statement information format.
|
||||
uint16_t Version;
|
||||
/// In v5, size in bytes of an address (or segment offset).
|
||||
uint8_t AddressSize;
|
||||
/// In v5, size in bytes of a segment selector.
|
||||
uint8_t SegSelectorSize;
|
||||
/// The number of bytes following the prologue_length field to the beginning
|
||||
/// of the first byte of the statement program itself.
|
||||
uint64_t PrologueLength;
|
||||
|
|
@ -63,7 +67,7 @@ public:
|
|||
/// The number assigned to the first special opcode.
|
||||
uint8_t OpcodeBase;
|
||||
std::vector<uint8_t> StandardOpcodeLengths;
|
||||
std::vector<const char *> IncludeDirectories;
|
||||
std::vector<StringRef> IncludeDirectories;
|
||||
std::vector<FileNameEntry> FileNames;
|
||||
|
||||
bool IsDWARF64;
|
||||
|
|
@ -100,7 +104,7 @@ public:
|
|||
void postAppend();
|
||||
void reset(bool DefaultIsStmt);
|
||||
void dump(raw_ostream &OS) const;
|
||||
|
||||
static void dumpTableHeader(raw_ostream &OS);
|
||||
static bool orderByAddress(const Row &LHS, const Row &RHS) {
|
||||
return LHS.Address < RHS.Address;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,9 +312,9 @@ public:
|
|||
[](const DWARFDebugInfoEntry &LHS, uint32_t Offset) {
|
||||
return LHS.getOffset() < Offset;
|
||||
});
|
||||
if (it == DieArray.end())
|
||||
return DWARFDie();
|
||||
return DWARFDie(this, &*it);
|
||||
if (it != DieArray.end() && it->getOffset() == Offset)
|
||||
return DWARFDie(this, &*it);
|
||||
return DWARFDie();
|
||||
}
|
||||
|
||||
uint32_t getLineTableOffset() const {
|
||||
|
|
|
|||
98
include/llvm/DebugInfo/DWARF/DWARFVerifier.h
Normal file
98
include/llvm/DebugInfo/DWARF/DWARFVerifier.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
//===- DWARFVerifier.h ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
|
||||
#define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
struct DWARFAttribute;
|
||||
class DWARFContext;
|
||||
class DWARFDie;
|
||||
class DWARFUnit;
|
||||
|
||||
/// A class that verifies DWARF debug information given a DWARF Context.
|
||||
class DWARFVerifier {
|
||||
raw_ostream &OS;
|
||||
DWARFContext &DCtx;
|
||||
/// A map that tracks all references (converted absolute references) so we
|
||||
/// can verify each reference points to a valid DIE and not an offset that
|
||||
/// lies between to valid DIEs.
|
||||
std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets;
|
||||
uint32_t NumDebugInfoErrors;
|
||||
uint32_t NumDebugLineErrors;
|
||||
|
||||
/// Verifies the attribute's DWARF attribute and its value.
|
||||
///
|
||||
/// This function currently checks for:
|
||||
/// - DW_AT_ranges values is a valid .debug_ranges offset
|
||||
/// - DW_AT_stmt_list is a valid .debug_line offset
|
||||
///
|
||||
/// @param Die The DWARF DIE that owns the attribute value
|
||||
/// @param AttrValue The DWARF attribute value to check
|
||||
void verifyDebugInfoAttribute(DWARFDie &Die, DWARFAttribute &AttrValue);
|
||||
|
||||
/// Verifies the attribute's DWARF form.
|
||||
///
|
||||
/// This function currently checks for:
|
||||
/// - All DW_FORM_ref values that are CU relative have valid CU offsets
|
||||
/// - All DW_FORM_ref_addr values have valid .debug_info offsets
|
||||
/// - All DW_FORM_strp values have valid .debug_str offsets
|
||||
///
|
||||
/// @param Die The DWARF DIE that owns the attribute value
|
||||
/// @param AttrValue The DWARF attribute value to check
|
||||
void verifyDebugInfoForm(DWARFDie &Die, DWARFAttribute &AttrValue);
|
||||
|
||||
/// Verifies the all valid references that were found when iterating through
|
||||
/// all of the DIE attributes.
|
||||
///
|
||||
/// This function will verify that all references point to DIEs whose DIE
|
||||
/// offset matches. This helps to ensure if a DWARF link phase moved things
|
||||
/// around, that it doesn't create invalid references by failing to relocate
|
||||
/// CU relative and absolute references.
|
||||
void veifyDebugInfoReferences();
|
||||
|
||||
/// Verify the the DW_AT_stmt_list encoding and value and ensure that no
|
||||
/// compile units that have the same DW_AT_stmt_list value.
|
||||
void verifyDebugLineStmtOffsets();
|
||||
|
||||
/// Verify that all of the rows in the line table are valid.
|
||||
///
|
||||
/// This function currently checks for:
|
||||
/// - addresses within a sequence that decrease in value
|
||||
/// - invalid file indexes
|
||||
void verifyDebugLineRows();
|
||||
|
||||
public:
|
||||
DWARFVerifier(raw_ostream &S, DWARFContext &D)
|
||||
: OS(S), DCtx(D), NumDebugInfoErrors(0), NumDebugLineErrors(0) {}
|
||||
/// Verify the information in the .debug_info section.
|
||||
///
|
||||
/// Any errors are reported to the stream that was this object was
|
||||
/// constructed with.
|
||||
///
|
||||
/// @return True if the .debug_info verifies successfully, false otherwise.
|
||||
bool handleDebugInfo();
|
||||
|
||||
/// Verify the information in the .debug_line section.
|
||||
///
|
||||
/// Any errors are reported to the stream that was this object was
|
||||
/// constructed with.
|
||||
///
|
||||
/// @return True if the .debug_line verifies successfully, false otherwise.
|
||||
bool handleDebugLine();
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H
|
||||
|
|
@ -66,7 +66,7 @@ struct ModuleInfoEx {
|
|||
template <> struct VarStreamArrayExtractor<pdb::DbiModuleDescriptor> {
|
||||
typedef void ContextType;
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Length,
|
||||
pdb::DbiModuleDescriptor &Info, void *Ctx) {
|
||||
pdb::DbiModuleDescriptor &Info) {
|
||||
if (auto EC = pdb::DbiModuleDescriptor::initialize(Stream, Info))
|
||||
return EC;
|
||||
Length = Info.getRecordLength();
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
#include "llvm/DebugInfo/CodeView/ModuleDebugFragment.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTable.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
|
|
@ -91,7 +91,7 @@ private:
|
|||
std::unique_ptr<msf::MappedBlockStream> Stream;
|
||||
|
||||
std::vector<ModuleInfoEx> ModuleInfos;
|
||||
StringTable ECNames;
|
||||
PDBStringTable ECNames;
|
||||
|
||||
BinaryStreamRef ModInfoSubstream;
|
||||
BinaryStreamRef SecContrSubstream;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace pdb {
|
|||
class DbiStream;
|
||||
class GlobalsStream;
|
||||
class InfoStream;
|
||||
class StringTable;
|
||||
class PDBStringTable;
|
||||
class PDBFileBuilder;
|
||||
class PublicsStream;
|
||||
class SymbolStream;
|
||||
|
|
@ -95,7 +95,7 @@ public:
|
|||
Expected<TpiStream &> getPDBIpiStream();
|
||||
Expected<PublicsStream &> getPDBPublicsStream();
|
||||
Expected<SymbolStream &> getPDBSymbolStream();
|
||||
Expected<StringTable &> getStringTable();
|
||||
Expected<PDBStringTable &> getStringTable();
|
||||
|
||||
BumpPtrAllocator &getAllocator() { return Allocator; }
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ public:
|
|||
bool hasPDBPublicsStream();
|
||||
bool hasPDBSymbolStream();
|
||||
bool hasPDBTpiStream() const;
|
||||
bool hasStringTable();
|
||||
bool hasPDBStringTable();
|
||||
|
||||
private:
|
||||
Expected<std::unique_ptr<msf::MappedBlockStream>>
|
||||
|
|
@ -131,7 +131,7 @@ private:
|
|||
std::unique_ptr<SymbolStream> Symbols;
|
||||
std::unique_ptr<msf::MappedBlockStream> DirectoryStream;
|
||||
std::unique_ptr<msf::MappedBlockStream> StringTableStream;
|
||||
std::unique_ptr<StringTable> Strings;
|
||||
std::unique_ptr<PDBStringTable> Strings;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
|
@ -46,12 +46,14 @@ public:
|
|||
DbiStreamBuilder &getDbiBuilder();
|
||||
TpiStreamBuilder &getTpiBuilder();
|
||||
TpiStreamBuilder &getIpiBuilder();
|
||||
StringTableBuilder &getStringTableBuilder();
|
||||
PDBStringTableBuilder &getStringTableBuilder();
|
||||
|
||||
Error commit(StringRef Filename);
|
||||
|
||||
private:
|
||||
Expected<uint32_t> getNamedStreamIndex(StringRef Name) const;
|
||||
Error addNamedStream(StringRef Name, uint32_t Size);
|
||||
|
||||
private:
|
||||
Expected<msf::MSFLayout> finalizeMsfLayout();
|
||||
|
||||
BumpPtrAllocator &Allocator;
|
||||
|
|
@ -62,7 +64,7 @@ private:
|
|||
std::unique_ptr<TpiStreamBuilder> Tpi;
|
||||
std::unique_ptr<TpiStreamBuilder> Ipi;
|
||||
|
||||
StringTableBuilder Strings;
|
||||
PDBStringTableBuilder Strings;
|
||||
NamedStreamMap NamedStreams;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===- StringTable.h - PDB String Table -------------------------*- C++ -*-===//
|
||||
//===- PDBStringTable.h - PDB String Table -----------------------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_PDB_RAW_STRINGTABLE_H
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_STRINGTABLE_H
|
||||
#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBSTRINGTABLE_H
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_PDBSTRINGTABLE_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
|
@ -22,31 +23,38 @@
|
|||
namespace llvm {
|
||||
class BinaryStreamReader;
|
||||
|
||||
namespace msf {
|
||||
class MappedBlockStream;
|
||||
}
|
||||
|
||||
namespace pdb {
|
||||
|
||||
class StringTable {
|
||||
public:
|
||||
StringTable();
|
||||
struct PDBStringTableHeader;
|
||||
|
||||
Error load(BinaryStreamReader &Stream);
|
||||
class PDBStringTable {
|
||||
public:
|
||||
Error reload(BinaryStreamReader &Reader);
|
||||
|
||||
uint32_t getByteSize() const;
|
||||
uint32_t getNameCount() const;
|
||||
uint32_t getHashVersion() const;
|
||||
uint32_t getSignature() const;
|
||||
|
||||
uint32_t getNameCount() const { return NameCount; }
|
||||
uint32_t getHashVersion() const { return HashVersion; }
|
||||
uint32_t getSignature() const { return Signature; }
|
||||
|
||||
StringRef getStringForID(uint32_t ID) const;
|
||||
uint32_t getIDForString(StringRef Str) const;
|
||||
Expected<StringRef> getStringForID(uint32_t ID) const;
|
||||
Expected<uint32_t> getIDForString(StringRef Str) const;
|
||||
|
||||
FixedStreamArray<support::ulittle32_t> name_ids() const;
|
||||
|
||||
private:
|
||||
BinaryStreamRef NamesBuffer;
|
||||
Error readHeader(BinaryStreamReader &Reader);
|
||||
Error readStrings(BinaryStreamReader &Reader);
|
||||
Error readHashTable(BinaryStreamReader &Reader);
|
||||
Error readEpilogue(BinaryStreamReader &Reader);
|
||||
|
||||
const PDBStringTableHeader *Header = nullptr;
|
||||
codeview::StringTableRef Strings;
|
||||
FixedStreamArray<support::ulittle32_t> IDs;
|
||||
uint32_t ByteSize = 0;
|
||||
uint32_t Signature = 0;
|
||||
uint32_t HashVersion = 0;
|
||||
uint32_t NameCount = 0;
|
||||
};
|
||||
|
||||
60
include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h
Normal file
60
include/llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
//===- PDBStringTableBuilder.h - PDB String Table Builder -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file creates the "/names" stream.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBSTRINGTABLEBUILDER_H
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_PDBSTRINGTABLEBUILDER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class BinaryStreamWriter;
|
||||
class WritableBinaryStreamRef;
|
||||
|
||||
namespace msf {
|
||||
struct MSFLayout;
|
||||
}
|
||||
|
||||
namespace pdb {
|
||||
|
||||
class PDBFileBuilder;
|
||||
|
||||
class PDBStringTableBuilder {
|
||||
public:
|
||||
// If string S does not exist in the string table, insert it.
|
||||
// Returns the ID for S.
|
||||
uint32_t insert(StringRef S);
|
||||
|
||||
uint32_t calculateSerializedSize() const;
|
||||
Error commit(BinaryStreamWriter &Writer) const;
|
||||
|
||||
codeview::StringTable &getStrings() { return Strings; }
|
||||
const codeview::StringTable &getStrings() const { return Strings; }
|
||||
|
||||
private:
|
||||
uint32_t calculateHashTableSize() const;
|
||||
Error writeHeader(BinaryStreamWriter &Writer) const;
|
||||
Error writeStrings(BinaryStreamWriter &Writer) const;
|
||||
Error writeHashTable(BinaryStreamWriter &Writer) const;
|
||||
Error writeEpilogue(BinaryStreamWriter &Writer) const;
|
||||
|
||||
codeview::StringTable Strings;
|
||||
};
|
||||
|
||||
} // end namespace pdb
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_PDB_RAW_PDBSTRINGTABLEBUILDER_H
|
||||
|
|
@ -307,13 +307,13 @@ struct InfoStreamHeader {
|
|||
};
|
||||
|
||||
/// The header preceeding the /names stream.
|
||||
struct StringTableHeader {
|
||||
support::ulittle32_t Signature;
|
||||
support::ulittle32_t HashVersion;
|
||||
support::ulittle32_t ByteSize;
|
||||
struct PDBStringTableHeader {
|
||||
support::ulittle32_t Signature; // PDBStringTableSignature
|
||||
support::ulittle32_t HashVersion; // 1 or 2
|
||||
support::ulittle32_t ByteSize; // Number of bytes of names buffer.
|
||||
};
|
||||
|
||||
const uint32_t StringTableSignature = 0xEFFEEFFE;
|
||||
const uint32_t PDBStringTableSignature = 0xEFFEEFFE;
|
||||
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
//===- StringTableBuilder.h - PDB String Table Builder ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file creates the "/names" stream.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_PDB_RAW_STRINGTABLEBUILDER_H
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_STRINGTABLEBUILDER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class BinaryStreamWriter;
|
||||
|
||||
namespace pdb {
|
||||
|
||||
class StringTableBuilder {
|
||||
public:
|
||||
// If string S does not exist in the string table, insert it.
|
||||
// Returns the ID for S.
|
||||
uint32_t insert(StringRef S);
|
||||
uint32_t getStringIndex(StringRef S);
|
||||
|
||||
uint32_t finalize();
|
||||
Error commit(BinaryStreamWriter &Writer) const;
|
||||
|
||||
private:
|
||||
DenseMap<StringRef, uint32_t> Strings;
|
||||
uint32_t StringSize = 1;
|
||||
};
|
||||
|
||||
} // end namespace pdb
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_PDB_RAW_STRINGTABLEBUILDER_H
|
||||
|
|
@ -285,7 +285,8 @@ class AttributeList {
|
|||
public:
|
||||
enum AttrIndex : unsigned {
|
||||
ReturnIndex = 0U,
|
||||
FunctionIndex = ~0U
|
||||
FunctionIndex = ~0U,
|
||||
FirstArgIndex = 1,
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -336,6 +337,13 @@ public:
|
|||
static AttributeList get(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B);
|
||||
|
||||
/// Add an argument attribute to the list. Returns a new list because
|
||||
/// attribute lists are immutable.
|
||||
AttributeList addParamAttribute(LLVMContext &C, unsigned ArgNo,
|
||||
Attribute::AttrKind Kind) const {
|
||||
return addAttribute(C, ArgNo + FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Add an attribute to the attribute set at the given index. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeList addAttribute(LLVMContext &C, unsigned Index,
|
||||
|
|
@ -353,9 +361,6 @@ public:
|
|||
|
||||
/// \brief Add attributes to the attribute set at the given index. Because
|
||||
/// attribute sets are immutable, this returns a new set.
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
AttributeList Attrs) const;
|
||||
|
||||
AttributeList addAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B) const;
|
||||
|
||||
|
|
@ -375,13 +380,7 @@ public:
|
|||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
/// new list.
|
||||
AttributeList removeAttributes(LLVMContext &C, unsigned Index,
|
||||
AttributeList Attrs) const;
|
||||
|
||||
/// \brief Remove the specified attributes at the specified index from this
|
||||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
/// new list.
|
||||
AttributeList removeAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &Attrs) const;
|
||||
const AttrBuilder &AttrsToRemove) const;
|
||||
|
||||
/// \brief Remove all attributes at the specified index from this
|
||||
/// attribute list. Because attribute lists are immutable, this returns the
|
||||
|
|
@ -442,7 +441,7 @@ public:
|
|||
/// may be faster.
|
||||
bool hasFnAttribute(StringRef Kind) const;
|
||||
|
||||
/// \brief Equivalent to hasAttribute(ArgNo + 1, Kind).
|
||||
/// \brief Equivalent to hasAttribute(ArgNo + FirstArgIndex, Kind).
|
||||
bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const;
|
||||
|
||||
/// \brief Return true if the specified attribute is set for at least one
|
||||
|
|
|
|||
|
|
@ -339,6 +339,10 @@ public:
|
|||
CALLSITE_DELEGATE_SETTER(addAttribute(i, Attr));
|
||||
}
|
||||
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
CALLSITE_DELEGATE_SETTER(addParamAttr(ArgNo, Kind));
|
||||
}
|
||||
|
||||
void removeAttribute(unsigned i, Attribute::AttrKind Kind) {
|
||||
CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind));
|
||||
}
|
||||
|
|
@ -347,6 +351,10 @@ public:
|
|||
CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind));
|
||||
}
|
||||
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
CALLSITE_DELEGATE_SETTER(removeParamAttr(ArgNo, Kind));
|
||||
}
|
||||
|
||||
/// Return true if this function has the given attribute.
|
||||
bool hasFnAttr(Attribute::AttrKind Kind) const {
|
||||
CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind));
|
||||
|
|
@ -408,11 +416,9 @@ public:
|
|||
CALLSITE_DELEGATE_GETTER(getDereferenceableOrNullBytes(i));
|
||||
}
|
||||
|
||||
/// Determine if the parameter or return value is marked with NoAlias
|
||||
/// attribute.
|
||||
/// @param n The parameter to check. 1 is the first parameter, 0 is the return
|
||||
bool doesNotAlias(unsigned n) const {
|
||||
CALLSITE_DELEGATE_GETTER(doesNotAlias(n));
|
||||
/// Determine if the return value is marked with NoAlias attribute.
|
||||
bool returnDoesNotAlias() const {
|
||||
CALLSITE_DELEGATE_GETTER(returnDoesNotAlias());
|
||||
}
|
||||
|
||||
/// Return true if the call should not be treated as a call to a builtin.
|
||||
|
|
|
|||
|
|
@ -204,6 +204,10 @@ public:
|
|||
addAttribute(AttributeList::FunctionIndex, Attr);
|
||||
}
|
||||
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
addAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// @brief Remove function attributes from this function.
|
||||
void removeFnAttr(Attribute::AttrKind Kind) {
|
||||
removeAttribute(AttributeList::FunctionIndex, Kind);
|
||||
|
|
@ -211,10 +215,14 @@ public:
|
|||
|
||||
/// @brief Remove function attribute from this function.
|
||||
void removeFnAttr(StringRef Kind) {
|
||||
setAttributes(AttributeSets.removeAttribute(
|
||||
setAttributes(getAttributes().removeAttribute(
|
||||
getContext(), AttributeList::FunctionIndex, Kind));
|
||||
}
|
||||
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
removeAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
/// \brief Set the entry count for this function.
|
||||
///
|
||||
/// Entry count is the number of times this function was executed based on
|
||||
|
|
@ -279,7 +287,7 @@ public:
|
|||
void addAttribute(unsigned i, Attribute Attr);
|
||||
|
||||
/// @brief adds the attributes to the list of attributes.
|
||||
void addAttributes(unsigned i, AttributeList Attrs);
|
||||
void addAttributes(unsigned i, const AttrBuilder &Attrs);
|
||||
|
||||
/// @brief removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, Attribute::AttrKind Kind);
|
||||
|
|
@ -288,7 +296,7 @@ public:
|
|||
void removeAttribute(unsigned i, StringRef Kind);
|
||||
|
||||
/// @brief removes the attributes from the list of attributes.
|
||||
void removeAttributes(unsigned i, AttributeList Attrs);
|
||||
void removeAttributes(unsigned i, const AttrBuilder &Attrs);
|
||||
|
||||
/// @brief check if an attributes is in the list of attributes.
|
||||
bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
|
||||
|
|
@ -459,35 +467,12 @@ public:
|
|||
/// @brief Determine if the parameter or return value is marked with NoAlias
|
||||
/// attribute.
|
||||
/// @param n The parameter to check. 1 is the first parameter, 0 is the return
|
||||
bool doesNotAlias(unsigned n) const {
|
||||
return AttributeSets.hasAttribute(n, Attribute::NoAlias);
|
||||
bool returnDoesNotAlias() const {
|
||||
return AttributeSets.hasAttribute(AttributeList::ReturnIndex,
|
||||
Attribute::NoAlias);
|
||||
}
|
||||
void setDoesNotAlias(unsigned n) {
|
||||
addAttribute(n, Attribute::NoAlias);
|
||||
}
|
||||
|
||||
/// @brief Determine if the parameter can be captured.
|
||||
/// @param n The parameter to check. 1 is the first parameter, 0 is the return
|
||||
bool doesNotCapture(unsigned n) const {
|
||||
return AttributeSets.hasAttribute(n, Attribute::NoCapture);
|
||||
}
|
||||
void setDoesNotCapture(unsigned n) {
|
||||
addAttribute(n, Attribute::NoCapture);
|
||||
}
|
||||
|
||||
bool doesNotAccessMemory(unsigned n) const {
|
||||
return AttributeSets.hasAttribute(n, Attribute::ReadNone);
|
||||
}
|
||||
void setDoesNotAccessMemory(unsigned n) {
|
||||
addAttribute(n, Attribute::ReadNone);
|
||||
}
|
||||
|
||||
bool onlyReadsMemory(unsigned n) const {
|
||||
return doesNotAccessMemory(n) ||
|
||||
AttributeSets.hasAttribute(n, Attribute::ReadOnly);
|
||||
}
|
||||
void setOnlyReadsMemory(unsigned n) {
|
||||
addAttribute(n, Attribute::ReadOnly);
|
||||
void setReturnDoesNotAlias() {
|
||||
addAttribute(AttributeList::ReturnIndex, Attribute::NoAlias);
|
||||
}
|
||||
|
||||
/// Optimize this function for minimum size (-Oz).
|
||||
|
|
|
|||
|
|
@ -1658,12 +1658,18 @@ public:
|
|||
/// adds the attribute to the list of attributes.
|
||||
void addAttribute(unsigned i, Attribute Attr);
|
||||
|
||||
/// Adds the attribute to the indicated argument
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, Attribute::AttrKind Kind);
|
||||
|
||||
/// removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, StringRef Kind);
|
||||
|
||||
/// Removes the attribute from the given argument
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// adds the dereferenceable attribute to the list of attributes.
|
||||
void addDereferenceableAttr(unsigned i, uint64_t Bytes);
|
||||
|
||||
|
|
@ -1734,11 +1740,9 @@ public:
|
|||
return Attrs.getDereferenceableOrNullBytes(i);
|
||||
}
|
||||
|
||||
/// @brief Determine if the parameter or return value is marked with NoAlias
|
||||
/// attribute.
|
||||
/// @param n The parameter to check. 1 is the first parameter, 0 is the return
|
||||
bool doesNotAlias(unsigned n) const {
|
||||
return Attrs.hasAttribute(n, Attribute::NoAlias);
|
||||
/// @brief Determine if the return value is marked with NoAlias attribute.
|
||||
bool returnDoesNotAlias() const {
|
||||
return Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias);
|
||||
}
|
||||
|
||||
/// Return true if the call should not be treated as a call to a
|
||||
|
|
@ -3750,12 +3754,18 @@ public:
|
|||
/// adds the attribute to the list of attributes.
|
||||
void addAttribute(unsigned i, Attribute Attr);
|
||||
|
||||
/// Adds the attribute to the indicated argument
|
||||
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, Attribute::AttrKind Kind);
|
||||
|
||||
/// removes the attribute from the list of attributes.
|
||||
void removeAttribute(unsigned i, StringRef Kind);
|
||||
|
||||
/// Removes the attribute from the given argument
|
||||
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind);
|
||||
|
||||
/// adds the dereferenceable attribute to the list of attributes.
|
||||
void addDereferenceableAttr(unsigned i, uint64_t Bytes);
|
||||
|
||||
|
|
@ -3827,11 +3837,9 @@ public:
|
|||
return Attrs.getDereferenceableOrNullBytes(i);
|
||||
}
|
||||
|
||||
/// @brief Determine if the parameter or return value is marked with NoAlias
|
||||
/// attribute.
|
||||
/// @param n The parameter to check. 1 is the first parameter, 0 is the return
|
||||
bool doesNotAlias(unsigned n) const {
|
||||
return Attrs.hasAttribute(n, Attribute::NoAlias);
|
||||
/// @brief Determine if the return value is marked with NoAlias attribute.
|
||||
bool returnDoesNotAlias() const {
|
||||
return Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias);
|
||||
}
|
||||
|
||||
/// Return true if the call should not be treated as a call to a
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace Intrinsic {
|
|||
Void, VarArg, MMX, Token, Metadata, Half, Float, Double,
|
||||
Integer, Vector, Pointer, Struct,
|
||||
Argument, ExtendArgument, TruncArgument, HalfVecArgument,
|
||||
SameVecWidthArgument, PtrToArgument, PtrToElt, VecOfPtrsToElt
|
||||
SameVecWidthArgument, PtrToArgument, PtrToElt, VecOfAnyPtrsToElt
|
||||
} Kind;
|
||||
|
||||
union {
|
||||
|
|
@ -119,25 +119,43 @@ namespace Intrinsic {
|
|||
AK_AnyVector,
|
||||
AK_AnyPointer
|
||||
};
|
||||
|
||||
unsigned getArgumentNumber() const {
|
||||
assert(Kind == Argument || Kind == ExtendArgument ||
|
||||
Kind == TruncArgument || Kind == HalfVecArgument ||
|
||||
Kind == SameVecWidthArgument || Kind == PtrToArgument ||
|
||||
Kind == PtrToElt || Kind == VecOfPtrsToElt);
|
||||
Kind == PtrToElt);
|
||||
return Argument_Info >> 3;
|
||||
}
|
||||
ArgKind getArgumentKind() const {
|
||||
assert(Kind == Argument || Kind == ExtendArgument ||
|
||||
Kind == TruncArgument || Kind == HalfVecArgument ||
|
||||
Kind == SameVecWidthArgument || Kind == PtrToArgument ||
|
||||
Kind == VecOfPtrsToElt);
|
||||
Kind == SameVecWidthArgument || Kind == PtrToArgument);
|
||||
return (ArgKind)(Argument_Info & 7);
|
||||
}
|
||||
|
||||
// VecOfAnyPtrsToElt uses both an overloaded argument (for address space)
|
||||
// and a reference argument (for matching vector width and element types)
|
||||
unsigned getOverloadArgNumber() const {
|
||||
assert(Kind == VecOfAnyPtrsToElt);
|
||||
return Argument_Info >> 16;
|
||||
}
|
||||
unsigned getRefArgNumber() const {
|
||||
assert(Kind == VecOfAnyPtrsToElt);
|
||||
return Argument_Info & 0xFFFF;
|
||||
}
|
||||
|
||||
static IITDescriptor get(IITDescriptorKind K, unsigned Field) {
|
||||
IITDescriptor Result = { K, { Field } };
|
||||
return Result;
|
||||
}
|
||||
|
||||
static IITDescriptor get(IITDescriptorKind K, unsigned short Hi,
|
||||
unsigned short Lo) {
|
||||
unsigned Field = Hi << 16 | Lo;
|
||||
IITDescriptor Result = {K, {Field}};
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
|
||||
/// Return the IIT table descriptor for the specified intrinsic into an array
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class LLVMVectorSameWidth<int num, LLVMType elty>
|
|||
}
|
||||
class LLVMPointerTo<int num> : LLVMMatchType<num>;
|
||||
class LLVMPointerToElt<int num> : LLVMMatchType<num>;
|
||||
class LLVMVectorOfPointersToElt<int num> : LLVMMatchType<num>;
|
||||
class LLVMVectorOfAnyPointersToElt<int num> : LLVMMatchType<num>;
|
||||
|
||||
// Match the type of another intrinsic parameter that is expected to be a
|
||||
// vector type, but change the element count to be half as many
|
||||
|
|
@ -404,7 +404,7 @@ def int_memset : Intrinsic<[],
|
|||
// FIXME: Add version of these floating point intrinsics which allow non-default
|
||||
// rounding modes and FP exception handling.
|
||||
|
||||
let IntrProperties = [IntrNoMem] in {
|
||||
let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
|
||||
def int_fma : Intrinsic<[llvm_anyfloat_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>,
|
||||
LLVMMatchType<0>]>;
|
||||
|
|
@ -440,10 +440,12 @@ let IntrProperties = [IntrNoMem] in {
|
|||
}
|
||||
|
||||
def int_minnum : Intrinsic<[llvm_anyfloat_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, Commutative]
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem, IntrSpeculatable, Commutative]
|
||||
>;
|
||||
def int_maxnum : Intrinsic<[llvm_anyfloat_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, Commutative]
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem, IntrSpeculatable, Commutative]
|
||||
>;
|
||||
|
||||
// NOTE: these are internal interfaces.
|
||||
|
|
@ -455,7 +457,7 @@ def int_siglongjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], [IntrNoReturn]>;
|
|||
// Internal interface for object size checking
|
||||
def int_objectsize : Intrinsic<[llvm_anyint_ty],
|
||||
[llvm_anyptr_ty, llvm_i1_ty, llvm_i1_ty],
|
||||
[IntrNoMem]>,
|
||||
[IntrNoMem, IntrSpeculatable]>,
|
||||
GCCBuiltin<"__builtin_object_size">;
|
||||
|
||||
//===--------------- Constrained Floating Point Intrinsics ----------------===//
|
||||
|
|
@ -500,7 +502,7 @@ def int_expect : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>,
|
|||
//
|
||||
|
||||
// None of these intrinsics accesses memory at all.
|
||||
let IntrProperties = [IntrNoMem] in {
|
||||
let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
|
||||
def int_bswap: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>;
|
||||
def int_ctpop: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>;
|
||||
def int_ctlz : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, llvm_i1_ty]>;
|
||||
|
|
@ -511,10 +513,11 @@ let IntrProperties = [IntrNoMem] in {
|
|||
//===------------------------ Debugger Intrinsics -------------------------===//
|
||||
//
|
||||
|
||||
// None of these intrinsics accesses memory at all...but that doesn't mean the
|
||||
// optimizers can change them aggressively. Special handling needed in a few
|
||||
// places.
|
||||
let IntrProperties = [IntrNoMem] in {
|
||||
// None of these intrinsics accesses memory at all...but that doesn't
|
||||
// mean the optimizers can change them aggressively. Special handling
|
||||
// needed in a few places. These synthetic intrinsics have no
|
||||
// side-effects and just mark information about their operands.
|
||||
let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
|
||||
def int_dbg_declare : Intrinsic<[],
|
||||
[llvm_metadata_ty,
|
||||
llvm_metadata_ty,
|
||||
|
|
@ -592,24 +595,24 @@ def int_adjust_trampoline : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty],
|
|||
// Expose the carry flag from add operations on two integrals.
|
||||
def int_sadd_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem]>;
|
||||
[IntrNoMem, IntrSpeculatable]>;
|
||||
def int_uadd_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem]>;
|
||||
[IntrNoMem, IntrSpeculatable]>;
|
||||
|
||||
def int_ssub_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem]>;
|
||||
[IntrNoMem, IntrSpeculatable]>;
|
||||
def int_usub_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem]>;
|
||||
[IntrNoMem, IntrSpeculatable]>;
|
||||
|
||||
def int_smul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem]>;
|
||||
[IntrNoMem, IntrSpeculatable]>;
|
||||
def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty],
|
||||
[LLVMMatchType<0>, LLVMMatchType<0>],
|
||||
[IntrNoMem]>;
|
||||
[IntrNoMem, IntrSpeculatable]>;
|
||||
|
||||
//===------------------------- Memory Use Markers -------------------------===//
|
||||
//
|
||||
|
|
@ -633,7 +636,7 @@ def int_invariant_end : Intrinsic<[],
|
|||
// it can be CSE only if memory didn't change between 2 barriers call,
|
||||
// which is valid.
|
||||
// The argument also can't be marked with 'returned' attribute, because
|
||||
// it would remove barrier.
|
||||
// it would remove barrier.
|
||||
def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty],
|
||||
[llvm_ptr_ty],
|
||||
[IntrReadMem, IntrArgMemOnly]>;
|
||||
|
|
@ -758,14 +761,14 @@ def int_masked_load : Intrinsic<[llvm_anyvector_ty],
|
|||
[IntrReadMem, IntrArgMemOnly]>;
|
||||
|
||||
def int_masked_gather: Intrinsic<[llvm_anyvector_ty],
|
||||
[LLVMVectorOfPointersToElt<0>, llvm_i32_ty,
|
||||
[LLVMVectorOfAnyPointersToElt<0>, llvm_i32_ty,
|
||||
LLVMVectorSameWidth<0, llvm_i1_ty>,
|
||||
LLVMMatchType<0>],
|
||||
[IntrReadMem]>;
|
||||
|
||||
def int_masked_scatter: Intrinsic<[],
|
||||
[llvm_anyvector_ty,
|
||||
LLVMVectorOfPointersToElt<0>, llvm_i32_ty,
|
||||
LLVMVectorOfAnyPointersToElt<0>, llvm_i32_ty,
|
||||
LLVMVectorSameWidth<0, llvm_i1_ty>]>;
|
||||
|
||||
def int_masked_expandload: Intrinsic<[llvm_anyvector_ty],
|
||||
|
|
|
|||
|
|
@ -3220,6 +3220,29 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
|||
[IntrNoMem]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LWP
|
||||
let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
def int_x86_llwpcb :
|
||||
GCCBuiltin<"__builtin_ia32_llwpcb">,
|
||||
Intrinsic<[], [llvm_ptr_ty], []>;
|
||||
def int_x86_slwpcb :
|
||||
GCCBuiltin<"__builtin_ia32_slwpcb">,
|
||||
Intrinsic<[llvm_ptr_ty], [], []>;
|
||||
def int_x86_lwpins32 :
|
||||
GCCBuiltin<"__builtin_ia32_lwpins32">,
|
||||
Intrinsic<[llvm_i8_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>;
|
||||
def int_x86_lwpins64 :
|
||||
GCCBuiltin<"__builtin_ia32_lwpins64">,
|
||||
Intrinsic<[llvm_i8_ty], [llvm_i64_ty, llvm_i32_ty, llvm_i32_ty], []>;
|
||||
def int_x86_lwpval32 :
|
||||
GCCBuiltin<"__builtin_ia32_lwpval32">,
|
||||
Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>;
|
||||
def int_x86_lwpval64 :
|
||||
GCCBuiltin<"__builtin_ia32_lwpval64">,
|
||||
Intrinsic<[], [llvm_i64_ty, llvm_i32_ty, llvm_i32_ty], []>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MMX
|
||||
|
||||
|
|
|
|||
|
|
@ -42,99 +42,34 @@ namespace llvm {
|
|||
/// having to specify a second template argument to VarStreamArray (documented
|
||||
/// below).
|
||||
template <typename T> struct VarStreamArrayExtractor {
|
||||
typedef void Context;
|
||||
struct ContextType {};
|
||||
|
||||
// Method intentionally deleted. You must provide an explicit specialization
|
||||
// with the following method implemented.
|
||||
// with one of the following two methods implemented.
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item) = delete;
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item,
|
||||
Context *Ctx) = delete;
|
||||
const ContextType &Ctx) = delete;
|
||||
};
|
||||
|
||||
/// VarStreamArray represents an array of variable length records backed by a
|
||||
/// stream. This could be a contiguous sequence of bytes in memory, it could
|
||||
/// be a file on disk, or it could be a PDB stream where bytes are stored as
|
||||
/// discontiguous blocks in a file. Usually it is desirable to treat arrays
|
||||
/// as contiguous blocks of memory, but doing so with large PDB files, for
|
||||
/// example, could mean allocating huge amounts of memory just to allow
|
||||
/// re-ordering of stream data to be contiguous before iterating over it. By
|
||||
/// abstracting this out, we need not duplicate this memory, and we can
|
||||
/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
|
||||
/// lazily on iteration, so there is no upfront cost associated with building
|
||||
/// or copying a VarStreamArray, no matter how large it may be.
|
||||
///
|
||||
/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
|
||||
/// If you do not specify an Extractor type, you are expected to specialize
|
||||
/// VarStreamArrayExtractor<T> for your ValueType.
|
||||
///
|
||||
/// The default extractor type is stateless, but by specializing
|
||||
/// VarStreamArrayExtractor or defining your own custom extractor type and
|
||||
/// adding the appropriate ContextType typedef to the class, you can pass a
|
||||
/// context field during construction of the VarStreamArray that will be
|
||||
/// passed to each call to extract.
|
||||
///
|
||||
template <typename ValueType, typename ExtractorType>
|
||||
class VarStreamArrayIterator;
|
||||
|
||||
template <typename ValueType,
|
||||
typename ExtractorType = VarStreamArrayExtractor<ValueType>>
|
||||
class VarStreamArray {
|
||||
public:
|
||||
typedef typename ExtractorType::ContextType ContextType;
|
||||
typedef VarStreamArrayIterator<ValueType, ExtractorType> Iterator;
|
||||
friend Iterator;
|
||||
|
||||
VarStreamArray() = default;
|
||||
|
||||
explicit VarStreamArray(BinaryStreamRef Stream,
|
||||
ContextType *Context = nullptr)
|
||||
: Stream(Stream), Context(Context) {}
|
||||
|
||||
VarStreamArray(const VarStreamArray<ValueType, ExtractorType> &Other)
|
||||
: Stream(Other.Stream), Context(Other.Context) {}
|
||||
|
||||
Iterator begin(bool *HadError = nullptr) const {
|
||||
if (empty())
|
||||
return end();
|
||||
|
||||
return Iterator(*this, Context, HadError);
|
||||
}
|
||||
|
||||
Iterator end() const { return Iterator(); }
|
||||
|
||||
bool empty() const { return Stream.getLength() == 0; }
|
||||
|
||||
/// \brief given an offset into the array's underlying stream, return an
|
||||
/// iterator to the record at that offset. This is considered unsafe
|
||||
/// since the behavior is undefined if \p Offset does not refer to the
|
||||
/// beginning of a valid record.
|
||||
Iterator at(uint32_t Offset) const {
|
||||
return Iterator(*this, Context, Stream.drop_front(Offset), nullptr);
|
||||
}
|
||||
|
||||
BinaryStreamRef getUnderlyingStream() const { return Stream; }
|
||||
|
||||
private:
|
||||
BinaryStreamRef Stream;
|
||||
ContextType *Context = nullptr;
|
||||
};
|
||||
|
||||
template <typename ValueType, typename ExtractorType>
|
||||
template <typename ArrayType, typename Value, typename Extractor,
|
||||
typename WrappedCtx>
|
||||
class VarStreamArrayIterator
|
||||
: public iterator_facade_base<
|
||||
VarStreamArrayIterator<ValueType, ExtractorType>,
|
||||
std::forward_iterator_tag, ValueType> {
|
||||
typedef typename ExtractorType::ContextType ContextType;
|
||||
typedef VarStreamArrayIterator<ValueType, ExtractorType> IterType;
|
||||
typedef VarStreamArray<ValueType, ExtractorType> ArrayType;
|
||||
VarStreamArrayIterator<ArrayType, Value, Extractor, WrappedCtx>,
|
||||
std::forward_iterator_tag, Value> {
|
||||
typedef VarStreamArrayIterator<ArrayType, Value, Extractor, WrappedCtx>
|
||||
IterType;
|
||||
|
||||
public:
|
||||
VarStreamArrayIterator(const ArrayType &Array, ContextType *Context,
|
||||
VarStreamArrayIterator() = default;
|
||||
VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx,
|
||||
BinaryStreamRef Stream, bool *HadError = nullptr)
|
||||
: IterRef(Stream), Context(Context), Array(&Array), HadError(HadError) {
|
||||
: IterRef(Stream), Ctx(&Ctx), Array(&Array), HadError(HadError) {
|
||||
if (IterRef.getLength() == 0)
|
||||
moveToEnd();
|
||||
else {
|
||||
auto EC = ExtractorType::extract(IterRef, ThisLen, ThisValue, Context);
|
||||
auto EC = Ctx.template invoke<Extractor>(IterRef, ThisLen, ThisValue);
|
||||
if (EC) {
|
||||
consumeError(std::move(EC));
|
||||
markError();
|
||||
|
|
@ -142,11 +77,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
VarStreamArrayIterator(const ArrayType &Array, ContextType *Context,
|
||||
VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx,
|
||||
bool *HadError = nullptr)
|
||||
: VarStreamArrayIterator(Array, Context, Array.Stream, HadError) {}
|
||||
: VarStreamArrayIterator(Array, Ctx, Array.Stream, HadError) {}
|
||||
|
||||
VarStreamArrayIterator(const WrappedCtx &Ctx) : Ctx(&Ctx) {}
|
||||
VarStreamArrayIterator(const VarStreamArrayIterator &Other) = default;
|
||||
|
||||
VarStreamArrayIterator() = default;
|
||||
~VarStreamArrayIterator() = default;
|
||||
|
||||
bool operator==(const IterType &R) const {
|
||||
|
|
@ -164,12 +101,12 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
const ValueType &operator*() const {
|
||||
const Value &operator*() const {
|
||||
assert(Array && !HasError);
|
||||
return ThisValue;
|
||||
}
|
||||
|
||||
ValueType &operator*() {
|
||||
Value &operator*() {
|
||||
assert(Array && !HasError);
|
||||
return ThisValue;
|
||||
}
|
||||
|
|
@ -185,7 +122,7 @@ public:
|
|||
moveToEnd();
|
||||
} else {
|
||||
// There is some data after the current record.
|
||||
auto EC = ExtractorType::extract(IterRef, ThisLen, ThisValue, Context);
|
||||
auto EC = Ctx->template invoke<Extractor>(IterRef, ThisLen, ThisValue);
|
||||
if (EC) {
|
||||
consumeError(std::move(EC));
|
||||
markError();
|
||||
|
|
@ -210,15 +147,136 @@ private:
|
|||
*HadError = true;
|
||||
}
|
||||
|
||||
ValueType ThisValue;
|
||||
Value ThisValue;
|
||||
BinaryStreamRef IterRef;
|
||||
ContextType *Context{nullptr};
|
||||
const WrappedCtx *Ctx{nullptr};
|
||||
const ArrayType *Array{nullptr};
|
||||
uint32_t ThisLen{0};
|
||||
bool HasError{false};
|
||||
bool *HadError{nullptr};
|
||||
};
|
||||
|
||||
template <typename T, typename Context> struct ContextWrapper {
|
||||
ContextWrapper() = default;
|
||||
|
||||
explicit ContextWrapper(Context &&Ctx) : Ctx(Ctx) {}
|
||||
|
||||
template <typename Extractor>
|
||||
Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const {
|
||||
return Extractor::extract(Stream, Len, Item, Ctx);
|
||||
}
|
||||
|
||||
Context Ctx;
|
||||
};
|
||||
|
||||
template <typename T> struct ContextWrapper<T, void> {
|
||||
ContextWrapper() = default;
|
||||
|
||||
template <typename Extractor>
|
||||
Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const {
|
||||
return Extractor::extract(Stream, Len, Item);
|
||||
}
|
||||
};
|
||||
|
||||
/// VarStreamArray represents an array of variable length records backed by a
|
||||
/// stream. This could be a contiguous sequence of bytes in memory, it could
|
||||
/// be a file on disk, or it could be a PDB stream where bytes are stored as
|
||||
/// discontiguous blocks in a file. Usually it is desirable to treat arrays
|
||||
/// as contiguous blocks of memory, but doing so with large PDB files, for
|
||||
/// example, could mean allocating huge amounts of memory just to allow
|
||||
/// re-ordering of stream data to be contiguous before iterating over it. By
|
||||
/// abstracting this out, we need not duplicate this memory, and we can
|
||||
/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
|
||||
/// lazily on iteration, so there is no upfront cost associated with building
|
||||
/// or copying a VarStreamArray, no matter how large it may be.
|
||||
///
|
||||
/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
|
||||
/// If you do not specify an Extractor type, you are expected to specialize
|
||||
/// VarStreamArrayExtractor<T> for your ValueType.
|
||||
///
|
||||
/// The default extractor type is stateless, but by specializing
|
||||
/// VarStreamArrayExtractor or defining your own custom extractor type and
|
||||
/// adding the appropriate ContextType typedef to the class, you can pass a
|
||||
/// context field during construction of the VarStreamArray that will be
|
||||
/// passed to each call to extract.
|
||||
///
|
||||
template <typename Value, typename Extractor, typename WrappedCtx>
|
||||
class VarStreamArrayBase {
|
||||
typedef VarStreamArrayBase<Value, Extractor, WrappedCtx> MyType;
|
||||
|
||||
public:
|
||||
typedef VarStreamArrayIterator<MyType, Value, Extractor, WrappedCtx> Iterator;
|
||||
friend Iterator;
|
||||
|
||||
VarStreamArrayBase() = default;
|
||||
|
||||
VarStreamArrayBase(BinaryStreamRef Stream, const WrappedCtx &Ctx)
|
||||
: Stream(Stream), Ctx(Ctx) {}
|
||||
|
||||
VarStreamArrayBase(const MyType &Other)
|
||||
: Stream(Other.Stream), Ctx(Other.Ctx) {}
|
||||
|
||||
Iterator begin(bool *HadError = nullptr) const {
|
||||
if (empty())
|
||||
return end();
|
||||
|
||||
return Iterator(*this, Ctx, Stream, HadError);
|
||||
}
|
||||
|
||||
bool valid() const { return Stream.valid(); }
|
||||
|
||||
Iterator end() const { return Iterator(Ctx); }
|
||||
|
||||
bool empty() const { return Stream.getLength() == 0; }
|
||||
|
||||
/// \brief given an offset into the array's underlying stream, return an
|
||||
/// iterator to the record at that offset. This is considered unsafe
|
||||
/// since the behavior is undefined if \p Offset does not refer to the
|
||||
/// beginning of a valid record.
|
||||
Iterator at(uint32_t Offset) const {
|
||||
return Iterator(*this, Ctx, Stream.drop_front(Offset), nullptr);
|
||||
}
|
||||
|
||||
BinaryStreamRef getUnderlyingStream() const { return Stream; }
|
||||
|
||||
private:
|
||||
BinaryStreamRef Stream;
|
||||
WrappedCtx Ctx;
|
||||
};
|
||||
|
||||
template <typename Value, typename Extractor, typename Context>
|
||||
class VarStreamArrayImpl
|
||||
: public VarStreamArrayBase<Value, Extractor,
|
||||
ContextWrapper<Value, Context>> {
|
||||
typedef ContextWrapper<Value, Context> WrappedContext;
|
||||
typedef VarStreamArrayImpl<Value, Extractor, Context> MyType;
|
||||
typedef VarStreamArrayBase<Value, Extractor, WrappedContext> BaseType;
|
||||
|
||||
public:
|
||||
typedef Context ContextType;
|
||||
|
||||
VarStreamArrayImpl() = default;
|
||||
VarStreamArrayImpl(BinaryStreamRef Stream, Context &&Ctx)
|
||||
: BaseType(Stream, WrappedContext(std::forward<Context>(Ctx))) {}
|
||||
};
|
||||
|
||||
template <typename Value, typename Extractor>
|
||||
class VarStreamArrayImpl<Value, Extractor, void>
|
||||
: public VarStreamArrayBase<Value, Extractor, ContextWrapper<Value, void>> {
|
||||
typedef ContextWrapper<Value, void> WrappedContext;
|
||||
typedef VarStreamArrayImpl<Value, Extractor, void> MyType;
|
||||
typedef VarStreamArrayBase<Value, Extractor, WrappedContext> BaseType;
|
||||
|
||||
public:
|
||||
VarStreamArrayImpl() = default;
|
||||
VarStreamArrayImpl(BinaryStreamRef Stream)
|
||||
: BaseType(Stream, WrappedContext()) {}
|
||||
};
|
||||
|
||||
template <typename Value, typename Extractor = VarStreamArrayExtractor<Value>>
|
||||
using VarStreamArray =
|
||||
VarStreamArrayImpl<Value, Extractor, typename Extractor::ContextType>;
|
||||
|
||||
template <typename T> class FixedStreamArrayIterator;
|
||||
|
||||
/// FixedStreamArray is similar to VarStreamArray, except with each record
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ namespace llvm {
|
|||
/// are overridable.
|
||||
class BinaryStreamReader {
|
||||
public:
|
||||
BinaryStreamReader() = default;
|
||||
explicit BinaryStreamReader(BinaryStreamRef Stream);
|
||||
virtual ~BinaryStreamReader() {}
|
||||
|
||||
|
|
@ -172,13 +173,29 @@ public:
|
|||
/// \returns a success error code if the data was successfully read, otherwise
|
||||
/// returns an appropriate error code.
|
||||
template <typename T, typename U>
|
||||
Error
|
||||
readArray(VarStreamArray<T, U> &Array, uint32_t Size,
|
||||
typename VarStreamArray<T, U>::ContextType *Context = nullptr) {
|
||||
Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
|
||||
BinaryStreamRef S;
|
||||
if (auto EC = readStreamRef(S, Size))
|
||||
return EC;
|
||||
Array = VarStreamArray<T, U>(S, Context);
|
||||
Array = VarStreamArray<T, U>(S);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Read a VarStreamArray of size \p Size bytes and store the result into
|
||||
/// \p Array. Updates the stream's offset to point after the newly read
|
||||
/// array. Never causes a copy (although iterating the elements of the
|
||||
/// VarStreamArray may, depending upon the implementation of the underlying
|
||||
/// stream).
|
||||
///
|
||||
/// \returns a success error code if the data was successfully read, otherwise
|
||||
/// returns an appropriate error code.
|
||||
template <typename T, typename U, typename ContextType>
|
||||
Error readArray(VarStreamArray<T, U> &Array, uint32_t Size,
|
||||
ContextType &&Context) {
|
||||
BinaryStreamRef S;
|
||||
if (auto EC = readStreamRef(S, Size))
|
||||
return EC;
|
||||
Array = VarStreamArray<T, U>(S, std::move(Context));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
|
@ -227,6 +244,9 @@ public:
|
|||
/// \returns the next byte in the stream.
|
||||
uint8_t peek() const;
|
||||
|
||||
std::pair<BinaryStreamReader, BinaryStreamReader>
|
||||
split(uint32_t Offset) const;
|
||||
|
||||
private:
|
||||
BinaryStreamRef Stream;
|
||||
uint32_t Offset;
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ public:
|
|||
BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
|
||||
uint32_t Length) = delete;
|
||||
|
||||
/// Check if a Stream is valid.
|
||||
bool valid() const { return Stream != nullptr; }
|
||||
|
||||
/// Given an Offset into this StreamRef and a Size, return a reference to a
|
||||
/// buffer owned by the stream.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
|
@ -30,8 +31,6 @@ namespace llvm {
|
|||
/// although no methods are overridable.
|
||||
class BinaryStreamWriter {
|
||||
public:
|
||||
// FIXME: We should be able to slice and drop_front etc on Writers / Readers.
|
||||
|
||||
BinaryStreamWriter() = default;
|
||||
explicit BinaryStreamWriter(WritableBinaryStreamRef Stream);
|
||||
virtual ~BinaryStreamWriter() {}
|
||||
|
|
@ -152,6 +151,9 @@ public:
|
|||
return writeStreamRef(Array.getUnderlyingStream());
|
||||
}
|
||||
|
||||
/// Splits the Writer into two Writers at a given offset.
|
||||
std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint32_t Off) const;
|
||||
|
||||
void setOffset(uint32_t Off) { Offset = Off; }
|
||||
uint32_t getOffset() const { return Offset; }
|
||||
uint32_t getLength() const { return Stream.getLength(); }
|
||||
|
|
|
|||
|
|
@ -58,6 +58,28 @@ public:
|
|||
/// NULL will be returned.
|
||||
const char *getCStr(uint32_t *offset_ptr) const;
|
||||
|
||||
/// Extract a C string from \a *OffsetPtr.
|
||||
///
|
||||
/// Returns a StringRef for the C String from the data at the offset
|
||||
/// pointed to by \a OffsetPtr. A variable length NULL terminated C
|
||||
/// string will be extracted and the \a OffsetPtr will be
|
||||
/// updated with the offset of the byte that follows the NULL
|
||||
/// terminator byte.
|
||||
///
|
||||
/// \param[in,out] OffsetPtr
|
||||
/// A pointer to an offset within the data that will be advanced
|
||||
/// by the appropriate number of bytes if the value is extracted
|
||||
/// correctly. If the offset is out of bounds or there are not
|
||||
/// enough bytes to extract this value, the offset will be left
|
||||
/// unmodified.
|
||||
///
|
||||
/// \return
|
||||
/// A StringRef for the C string value in the data. If the offset
|
||||
/// pointed to by \a OffsetPtr is out of bounds, or if the
|
||||
/// offset plus the length of the C string is out of bounds,
|
||||
/// a default-initialized StringRef will be returned.
|
||||
StringRef getCStrRef(uint32_t *OffsetPtr) const;
|
||||
|
||||
/// Extract an unsigned integer of size \a byte_size from \a
|
||||
/// *offset_ptr.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -99,3 +99,8 @@ ELF_RELOC(R_HEX_LD_GOT_32_6_X, 91)
|
|||
ELF_RELOC(R_HEX_LD_GOT_16_X, 92)
|
||||
ELF_RELOC(R_HEX_LD_GOT_11_X, 93)
|
||||
ELF_RELOC(R_HEX_23_REG, 94)
|
||||
ELF_RELOC(R_HEX_GD_PLT_B22_PCREL_X, 95)
|
||||
ELF_RELOC(R_HEX_GD_PLT_B32_PCREL_X, 96)
|
||||
ELF_RELOC(R_HEX_LD_PLT_B22_PCREL_X, 97)
|
||||
ELF_RELOC(R_HEX_LD_PLT_B32_PCREL_X, 98)
|
||||
ELF_RELOC(R_HEX_27_REG, 99)
|
||||
|
|
|
|||
|
|
@ -2061,6 +2061,14 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
// Return true if the instruction that performs a << b actually performs
|
||||
// a << (b % (sizeof(a) * 8)).
|
||||
virtual bool supportsModuloShift(ISD::NodeType Inst, EVT ReturnType) const {
|
||||
assert((Inst == ISD::SHL || Inst == ISD::SRA || Inst == ISD::SRL) &&
|
||||
"Expect a shift instruction");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Runtime Library hooks
|
||||
//
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ template <typename CFLAA> class CFLGraphBuilder {
|
|||
|
||||
if (Inst->getType()->isPointerTy()) {
|
||||
auto *Fn = CS.getCalledFunction();
|
||||
if (Fn == nullptr || !Fn->doesNotAlias(AttributeList::ReturnIndex))
|
||||
if (Fn == nullptr || !Fn->returnDoesNotAlias())
|
||||
// No need to call addNode() since we've added Inst at the
|
||||
// beginning of this function and we know it is not a global.
|
||||
Graph.addAttr(InstantiatedValue{Inst, 0}, getAttrUnknown());
|
||||
|
|
|
|||
|
|
@ -4056,13 +4056,20 @@ static Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
|||
unsigned MaskNumElts = Mask->getType()->getVectorNumElements();
|
||||
unsigned InVecNumElts = InVecTy->getVectorNumElements();
|
||||
|
||||
auto *Op0Const = dyn_cast<Constant>(Op0);
|
||||
auto *Op1Const = dyn_cast<Constant>(Op1);
|
||||
|
||||
// If all operands are constant, constant fold the shuffle.
|
||||
if (Op0Const && Op1Const)
|
||||
return ConstantFoldShuffleVectorInstruction(Op0Const, Op1Const, Mask);
|
||||
|
||||
SmallVector<int, 32> Indices;
|
||||
ShuffleVectorInst::getShuffleMask(Mask, Indices);
|
||||
assert(MaskNumElts == Indices.size() &&
|
||||
"Size of Indices not same as number of mask elements?");
|
||||
|
||||
// Canonicalization: If mask does not select elements from an input vector,
|
||||
// replace that input vector with undef.
|
||||
// If only one of the operands is constant, constant fold the shuffle if the
|
||||
// mask does not select elements from the variable operand.
|
||||
bool MaskSelects0 = false, MaskSelects1 = false;
|
||||
for (unsigned i = 0; i != MaskNumElts; ++i) {
|
||||
if (Indices[i] == -1)
|
||||
|
|
@ -4072,39 +4079,23 @@ static Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
|
|||
else
|
||||
MaskSelects1 = true;
|
||||
}
|
||||
if (!MaskSelects0)
|
||||
Op0 = UndefValue::get(InVecTy);
|
||||
if (!MaskSelects1)
|
||||
Op1 = UndefValue::get(InVecTy);
|
||||
|
||||
auto *Op0Const = dyn_cast<Constant>(Op0);
|
||||
auto *Op1Const = dyn_cast<Constant>(Op1);
|
||||
|
||||
// If all operands are constant, constant fold the shuffle.
|
||||
if (Op0Const && Op1Const)
|
||||
return ConstantFoldShuffleVectorInstruction(Op0Const, Op1Const, Mask);
|
||||
|
||||
// Canonicalization: if only one input vector is constant, it shall be the
|
||||
// second one.
|
||||
if (Op0Const && !Op1Const) {
|
||||
std::swap(Op0, Op1);
|
||||
for (auto &Idx : Indices) {
|
||||
if (Idx == -1)
|
||||
continue;
|
||||
Idx = Idx < (int)MaskNumElts ? Idx + MaskNumElts : Idx - MaskNumElts;
|
||||
}
|
||||
Mask = ConstantDataVector::get(
|
||||
Mask->getContext(),
|
||||
makeArrayRef(reinterpret_cast<uint32_t *>(Indices.data()),
|
||||
MaskNumElts));
|
||||
}
|
||||
if (!MaskSelects0 && Op1Const)
|
||||
return ConstantFoldShuffleVectorInstruction(UndefValue::get(InVecTy),
|
||||
Op1Const, Mask);
|
||||
if (!MaskSelects1 && Op0Const)
|
||||
return ConstantFoldShuffleVectorInstruction(Op0Const,
|
||||
UndefValue::get(InVecTy), Mask);
|
||||
|
||||
// A shuffle of a splat is always the splat itself. Legal if the shuffle's
|
||||
// value type is same as the input vectors' type.
|
||||
if (auto *OpShuf = dyn_cast<ShuffleVectorInst>(Op0))
|
||||
if (isa<UndefValue>(Op1) && RetTy == InVecTy &&
|
||||
if (!MaskSelects1 && RetTy == InVecTy &&
|
||||
OpShuf->getMask()->getSplatValue())
|
||||
return Op0;
|
||||
if (auto *OpShuf = dyn_cast<ShuffleVectorInst>(Op1))
|
||||
if (!MaskSelects0 && RetTy == InVecTy &&
|
||||
OpShuf->getMask()->getSplatValue())
|
||||
return Op1;
|
||||
|
||||
// Don't fold a shuffle with undef mask elements. This may get folded in a
|
||||
// better way using demanded bits or other analysis.
|
||||
|
|
|
|||
|
|
@ -451,12 +451,6 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
|
|||
auto &Summary = GlobalList.second[0];
|
||||
bool AllRefsCanBeExternallyReferenced =
|
||||
llvm::all_of(Summary->refs(), [&](const ValueInfo &VI) {
|
||||
// If a global value definition references an unnamed global,
|
||||
// be conservative. They're valid IR so we don't want to crash
|
||||
// when we encounter any of them but they're infrequent enough
|
||||
// that we don't bother optimizing them.
|
||||
if (!VI.getValue()->hasName())
|
||||
return false;
|
||||
return !CantBePromoted.count(VI.getValue()->getGUID());
|
||||
});
|
||||
if (!AllRefsCanBeExternallyReferenced) {
|
||||
|
|
|
|||
|
|
@ -3320,67 +3320,10 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
|
|||
case Instruction::Call: {
|
||||
auto *CI = cast<const CallInst>(Inst);
|
||||
const Function *Callee = CI->getCalledFunction();
|
||||
if (Callee && Callee->isSpeculatable())
|
||||
return true;
|
||||
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
|
||||
switch (II->getIntrinsicID()) {
|
||||
// These synthetic intrinsics have no side-effects and just mark
|
||||
// information about their operands.
|
||||
// FIXME: There are other no-op synthetic instructions that potentially
|
||||
// should be considered at least *safe* to speculate...
|
||||
// FIXME: The speculatable attribute should be added to all these
|
||||
// intrinsics and this case statement should be removed.
|
||||
case Intrinsic::dbg_declare:
|
||||
case Intrinsic::dbg_value:
|
||||
return true;
|
||||
|
||||
case Intrinsic::bitreverse:
|
||||
case Intrinsic::bswap:
|
||||
case Intrinsic::ctlz:
|
||||
case Intrinsic::ctpop:
|
||||
case Intrinsic::cttz:
|
||||
case Intrinsic::objectsize:
|
||||
case Intrinsic::sadd_with_overflow:
|
||||
case Intrinsic::smul_with_overflow:
|
||||
case Intrinsic::ssub_with_overflow:
|
||||
case Intrinsic::uadd_with_overflow:
|
||||
case Intrinsic::umul_with_overflow:
|
||||
case Intrinsic::usub_with_overflow:
|
||||
return true;
|
||||
// These intrinsics are defined to have the same behavior as libm
|
||||
// functions except for setting errno.
|
||||
case Intrinsic::sqrt:
|
||||
case Intrinsic::fma:
|
||||
case Intrinsic::fmuladd:
|
||||
return true;
|
||||
// These intrinsics are defined to have the same behavior as libm
|
||||
// functions, and the corresponding libm functions never set errno.
|
||||
case Intrinsic::trunc:
|
||||
case Intrinsic::copysign:
|
||||
case Intrinsic::fabs:
|
||||
case Intrinsic::minnum:
|
||||
case Intrinsic::maxnum:
|
||||
return true;
|
||||
// These intrinsics are defined to have the same behavior as libm
|
||||
// functions, which never overflow when operating on the IEEE754 types
|
||||
// that we support, and never set errno otherwise.
|
||||
case Intrinsic::ceil:
|
||||
case Intrinsic::floor:
|
||||
case Intrinsic::nearbyint:
|
||||
case Intrinsic::rint:
|
||||
case Intrinsic::round:
|
||||
return true;
|
||||
// These intrinsics do not correspond to any libm function, and
|
||||
// do not set errno.
|
||||
case Intrinsic::powi:
|
||||
return true;
|
||||
// TODO: are convert_{from,to}_fp16 safe?
|
||||
// TODO: can we list target-specific intrinsics here?
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return false; // The called function could have undefined behavior or
|
||||
// side-effects, even if marked readnone nounwind.
|
||||
// The called function could have undefined behavior or side-effects, even
|
||||
// if marked readnone nounwind.
|
||||
return Callee && Callee->isSpeculatable();
|
||||
}
|
||||
case Instruction::VAArg:
|
||||
case Instruction::Alloca:
|
||||
|
|
|
|||
|
|
@ -340,146 +340,28 @@ public:
|
|||
// in writing out the call graph edges. Save the mapping from GUID
|
||||
// to the new global value id to use when writing those edges, which
|
||||
// are currently saved in the index in terms of GUID.
|
||||
for (const auto &I : *this)
|
||||
forEachSummary([&](GVInfo I) {
|
||||
GUIDToValueIdMap[I.first] = ++GlobalValueId;
|
||||
});
|
||||
}
|
||||
|
||||
/// The below iterator returns the GUID and associated summary.
|
||||
typedef std::pair<GlobalValue::GUID, GlobalValueSummary *> GVInfo;
|
||||
|
||||
/// Iterator over the value GUID and summaries to be written to bitcode,
|
||||
/// hides the details of whether they are being pulled from the entire
|
||||
/// index or just those in a provided ModuleToSummariesForIndex map.
|
||||
class iterator
|
||||
: public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
|
||||
GVInfo> {
|
||||
/// Enables access to parent class.
|
||||
const IndexBitcodeWriter &Writer;
|
||||
|
||||
// Iterators used when writing only those summaries in a provided
|
||||
// ModuleToSummariesForIndex map:
|
||||
|
||||
/// Points to the last element in outer ModuleToSummariesForIndex map.
|
||||
std::map<std::string, GVSummaryMapTy>::const_iterator ModuleSummariesBack;
|
||||
/// Iterator on outer ModuleToSummariesForIndex map.
|
||||
std::map<std::string, GVSummaryMapTy>::const_iterator ModuleSummariesIter;
|
||||
/// Iterator on an inner global variable summary map.
|
||||
GVSummaryMapTy::const_iterator ModuleGVSummariesIter;
|
||||
|
||||
// Iterators used when writing all summaries in the index:
|
||||
|
||||
/// Points to the last element in the Index outer GlobalValueMap.
|
||||
const_gvsummary_iterator IndexSummariesBack;
|
||||
/// Iterator on outer GlobalValueMap.
|
||||
const_gvsummary_iterator IndexSummariesIter;
|
||||
/// Iterator on an inner GlobalValueSummaryList.
|
||||
GlobalValueSummaryList::const_iterator IndexGVSummariesIter;
|
||||
|
||||
public:
|
||||
/// Construct iterator from parent \p Writer and indicate if we are
|
||||
/// constructing the end iterator.
|
||||
iterator(const IndexBitcodeWriter &Writer, bool IsAtEnd) : Writer(Writer) {
|
||||
// Set up the appropriate set of iterators given whether we are writing
|
||||
// the full index or just a subset.
|
||||
// Can't setup the Back or inner iterators if the corresponding map
|
||||
// is empty. This will be handled specially in operator== as well.
|
||||
if (Writer.ModuleToSummariesForIndex &&
|
||||
!Writer.ModuleToSummariesForIndex->empty()) {
|
||||
for (ModuleSummariesBack = Writer.ModuleToSummariesForIndex->begin();
|
||||
std::next(ModuleSummariesBack) !=
|
||||
Writer.ModuleToSummariesForIndex->end();
|
||||
ModuleSummariesBack++)
|
||||
;
|
||||
ModuleSummariesIter = !IsAtEnd
|
||||
? Writer.ModuleToSummariesForIndex->begin()
|
||||
: ModuleSummariesBack;
|
||||
ModuleGVSummariesIter = !IsAtEnd ? ModuleSummariesIter->second.begin()
|
||||
: ModuleSummariesBack->second.end();
|
||||
} else if (!Writer.ModuleToSummariesForIndex &&
|
||||
Writer.Index.begin() != Writer.Index.end()) {
|
||||
for (IndexSummariesBack = Writer.Index.begin();
|
||||
std::next(IndexSummariesBack) != Writer.Index.end();
|
||||
IndexSummariesBack++)
|
||||
;
|
||||
IndexSummariesIter =
|
||||
!IsAtEnd ? Writer.Index.begin() : IndexSummariesBack;
|
||||
IndexGVSummariesIter = !IsAtEnd ? IndexSummariesIter->second.begin()
|
||||
: IndexSummariesBack->second.end();
|
||||
}
|
||||
/// Calls the callback for each value GUID and summary to be written to
|
||||
/// bitcode. This hides the details of whether they are being pulled from the
|
||||
/// entire index or just those in a provided ModuleToSummariesForIndex map.
|
||||
void forEachSummary(std::function<void(GVInfo)> Callback) {
|
||||
if (ModuleToSummariesForIndex) {
|
||||
for (auto &M : *ModuleToSummariesForIndex)
|
||||
for (auto &Summary : M.second)
|
||||
Callback(Summary);
|
||||
} else {
|
||||
for (auto &Summaries : Index)
|
||||
for (auto &Summary : Summaries.second)
|
||||
Callback({Summaries.first, Summary.get()});
|
||||
}
|
||||
|
||||
/// Increment the appropriate set of iterators.
|
||||
iterator &operator++() {
|
||||
// First the inner iterator is incremented, then if it is at the end
|
||||
// and there are more outer iterations to go, the inner is reset to
|
||||
// the start of the next inner list.
|
||||
if (Writer.ModuleToSummariesForIndex) {
|
||||
++ModuleGVSummariesIter;
|
||||
if (ModuleGVSummariesIter == ModuleSummariesIter->second.end() &&
|
||||
ModuleSummariesIter != ModuleSummariesBack) {
|
||||
++ModuleSummariesIter;
|
||||
ModuleGVSummariesIter = ModuleSummariesIter->second.begin();
|
||||
}
|
||||
} else {
|
||||
++IndexGVSummariesIter;
|
||||
if (IndexGVSummariesIter == IndexSummariesIter->second.end() &&
|
||||
IndexSummariesIter != IndexSummariesBack) {
|
||||
++IndexSummariesIter;
|
||||
IndexGVSummariesIter = IndexSummariesIter->second.begin();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Access the <GUID,GlobalValueSummary*> pair corresponding to the current
|
||||
/// outer and inner iterator positions.
|
||||
GVInfo operator*() {
|
||||
if (Writer.ModuleToSummariesForIndex)
|
||||
return std::make_pair(ModuleGVSummariesIter->first,
|
||||
ModuleGVSummariesIter->second);
|
||||
return std::make_pair(IndexSummariesIter->first,
|
||||
IndexGVSummariesIter->get());
|
||||
}
|
||||
|
||||
/// Checks if the iterators are equal, with special handling for empty
|
||||
/// indexes.
|
||||
bool operator==(const iterator &RHS) const {
|
||||
if (Writer.ModuleToSummariesForIndex) {
|
||||
// First ensure that both are writing the same subset.
|
||||
if (Writer.ModuleToSummariesForIndex !=
|
||||
RHS.Writer.ModuleToSummariesForIndex)
|
||||
return false;
|
||||
// Already determined above that maps are the same, so if one is
|
||||
// empty, they both are.
|
||||
if (Writer.ModuleToSummariesForIndex->empty())
|
||||
return true;
|
||||
// Ensure the ModuleGVSummariesIter are iterating over the same
|
||||
// container before checking them below.
|
||||
if (ModuleSummariesIter != RHS.ModuleSummariesIter)
|
||||
return false;
|
||||
return ModuleGVSummariesIter == RHS.ModuleGVSummariesIter;
|
||||
}
|
||||
// First ensure RHS also writing the full index, and that both are
|
||||
// writing the same full index.
|
||||
if (RHS.Writer.ModuleToSummariesForIndex ||
|
||||
&Writer.Index != &RHS.Writer.Index)
|
||||
return false;
|
||||
// Already determined above that maps are the same, so if one is
|
||||
// empty, they both are.
|
||||
if (Writer.Index.begin() == Writer.Index.end())
|
||||
return true;
|
||||
// Ensure the IndexGVSummariesIter are iterating over the same
|
||||
// container before checking them below.
|
||||
if (IndexSummariesIter != RHS.IndexSummariesIter)
|
||||
return false;
|
||||
return IndexGVSummariesIter == RHS.IndexGVSummariesIter;
|
||||
}
|
||||
};
|
||||
|
||||
/// Obtain the start iterator over the summaries to be written.
|
||||
iterator begin() { return iterator(*this, /*IsAtEnd=*/false); }
|
||||
/// Obtain the end iterator over the summaries to be written.
|
||||
iterator end() { return iterator(*this, /*IsAtEnd=*/true); }
|
||||
}
|
||||
|
||||
/// Main entry point for writing a combined index to bitcode.
|
||||
void write();
|
||||
|
|
@ -3528,16 +3410,16 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
Stream.EmitRecord(bitc::FS_VERSION, ArrayRef<uint64_t>{INDEX_VERSION});
|
||||
|
||||
// Create value IDs for undefined references.
|
||||
for (const auto &I : *this) {
|
||||
forEachSummary([&](GVInfo I) {
|
||||
if (auto *VS = dyn_cast<GlobalVarSummary>(I.second)) {
|
||||
for (auto &RI : VS->refs())
|
||||
assignValueId(RI.getGUID());
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
auto *FS = dyn_cast<FunctionSummary>(I.second);
|
||||
if (!FS)
|
||||
continue;
|
||||
return;
|
||||
for (auto &RI : FS->refs())
|
||||
assignValueId(RI.getGUID());
|
||||
|
||||
|
|
@ -3553,7 +3435,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
}
|
||||
assignValueId(GUID);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const auto &GVI : valueIds()) {
|
||||
Stream.EmitRecord(bitc::FS_VALUE_GUID,
|
||||
|
|
@ -3624,7 +3506,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
NameVals.clear();
|
||||
};
|
||||
|
||||
for (const auto &I : *this) {
|
||||
forEachSummary([&](GVInfo I) {
|
||||
GlobalValueSummary *S = I.second;
|
||||
assert(S);
|
||||
|
||||
|
|
@ -3636,7 +3518,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
// Will process aliases as a post-pass because the reader wants all
|
||||
// global to be loaded first.
|
||||
Aliases.push_back(AS);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto *VS = dyn_cast<GlobalVarSummary>(S)) {
|
||||
|
|
@ -3652,7 +3534,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
FSModRefsAbbrev);
|
||||
NameVals.clear();
|
||||
MaybeEmitOriginalName(*S);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
auto *FS = cast<FunctionSummary>(S);
|
||||
|
|
@ -3700,7 +3582,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
Stream.EmitRecord(Code, NameVals, FSAbbrev);
|
||||
NameVals.clear();
|
||||
MaybeEmitOriginalName(*S);
|
||||
}
|
||||
});
|
||||
|
||||
for (auto *AS : Aliases) {
|
||||
auto AliasValueId = SummaryToValueIdMap[AS];
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ bool CallLowering::lowerCall(
|
|||
for (auto &Arg : CS.args()) {
|
||||
ArgInfo OrigArg{ArgRegs[i], Arg->getType(), ISD::ArgFlagsTy{},
|
||||
i < NumFixedArgs};
|
||||
setArgFlags(OrigArg, i + 1, DL, CS);
|
||||
setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, CS);
|
||||
OrigArgs.push_back(OrigArg);
|
||||
++i;
|
||||
}
|
||||
|
|
@ -83,8 +83,8 @@ void CallLowering::setArgFlags(CallLowering::ArgInfo &Arg, unsigned OpIdx,
|
|||
// For ByVal, alignment should be passed from FE. BE will guess if
|
||||
// this info is not there but there are cases it cannot get right.
|
||||
unsigned FrameAlign;
|
||||
if (FuncInfo.getParamAlignment(OpIdx - 1))
|
||||
FrameAlign = FuncInfo.getParamAlignment(OpIdx - 1);
|
||||
if (FuncInfo.getParamAlignment(OpIdx - 2))
|
||||
FrameAlign = FuncInfo.getParamAlignment(OpIdx - 2);
|
||||
else
|
||||
FrameAlign = getTLI()->getByValTypeAlignment(ElementTy, DL);
|
||||
Arg.Flags.setByValAlign(FrameAlign);
|
||||
|
|
|
|||
|
|
@ -761,6 +761,9 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
|
|||
} else if (MaxCSFrameIndex >= MinCSFrameIndex) {
|
||||
// Be careful about underflow in comparisons agains MinCSFrameIndex.
|
||||
for (unsigned i = MaxCSFrameIndex; i != MinCSFrameIndex - 1; --i) {
|
||||
if (MFI.isDeadObjectIndex(i))
|
||||
continue;
|
||||
|
||||
unsigned Align = MFI.getObjectAlignment(i);
|
||||
// Adjust to alignment boundary
|
||||
Offset = alignTo(Offset, Align, Skew);
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ namespace {
|
|||
SDValue visitUSUBO(SDNode *N);
|
||||
SDValue visitADDE(SDNode *N);
|
||||
SDValue visitADDCARRY(SDNode *N);
|
||||
SDValue visitADDCARRYLike(SDValue N0, SDValue N1, SDValue CarryIn, SDNode *N);
|
||||
SDValue visitSUBE(SDNode *N);
|
||||
SDValue visitSUBCARRY(SDNode *N);
|
||||
SDValue visitMUL(SDNode *N);
|
||||
|
|
@ -2142,6 +2143,24 @@ SDValue DAGCombiner::visitADDCARRY(SDNode *N) {
|
|||
if (isNullConstant(CarryIn))
|
||||
return DAG.getNode(ISD::UADDO, SDLoc(N), N->getVTList(), N0, N1);
|
||||
|
||||
if (SDValue Combined = visitADDCARRYLike(N0, N1, CarryIn, N))
|
||||
return Combined;
|
||||
|
||||
if (SDValue Combined = visitADDCARRYLike(N1, N0, CarryIn, N))
|
||||
return Combined;
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
SDValue DAGCombiner::visitADDCARRYLike(SDValue N0, SDValue N1, SDValue CarryIn,
|
||||
SDNode *N) {
|
||||
// Iff the flag result is dead:
|
||||
// (addcarry (add|uaddo X, Y), 0, Carry) -> (addcarry X, Y, Carry)
|
||||
if ((N0.getOpcode() == ISD::ADD || N0.getOpcode() == ISD::UADDO) &&
|
||||
isNullConstant(N1) && !N->hasAnyUseOfValue(1))
|
||||
return DAG.getNode(ISD::ADDCARRY, SDLoc(N), N->getVTList(),
|
||||
N0.getOperand(0), N0.getOperand(1), CarryIn);
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
|
|
@ -5294,6 +5313,17 @@ SDValue DAGCombiner::visitSHL(SDNode *N) {
|
|||
}
|
||||
}
|
||||
|
||||
// If the target supports masking y in (shl, y),
|
||||
// fold (shl x, (and y, ((1 << numbits(x)) - 1))) -> (shl x, y)
|
||||
if (TLI.isOperationLegal(ISD::SHL, VT) &&
|
||||
TLI.supportsModuloShift(ISD::SHL, VT) && N1->getOpcode() == ISD::AND) {
|
||||
if (ConstantSDNode *Mask = isConstOrConstSplat(N1->getOperand(1))) {
|
||||
if (Mask->getZExtValue() == OpSizeInBits - 1) {
|
||||
return DAG.getNode(ISD::SHL, SDLoc(N), VT, N0, N1->getOperand(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConstantSDNode *N1C = isConstOrConstSplat(N1);
|
||||
|
||||
// fold (shl c1, c2) -> c1<<c2
|
||||
|
|
@ -5492,6 +5522,17 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
|
|||
EVT VT = N0.getValueType();
|
||||
unsigned OpSizeInBits = VT.getScalarSizeInBits();
|
||||
|
||||
// If the target supports masking y in (sra, y),
|
||||
// fold (sra x, (and y, ((1 << numbits(x)) - 1))) -> (sra x, y)
|
||||
if (TLI.isOperationLegal(ISD::SRA, VT) &&
|
||||
TLI.supportsModuloShift(ISD::SRA, VT) && N1->getOpcode() == ISD::AND) {
|
||||
if (ConstantSDNode *Mask = isConstOrConstSplat(N1->getOperand(1))) {
|
||||
if (Mask->getZExtValue() == OpSizeInBits - 1) {
|
||||
return DAG.getNode(ISD::SRA, SDLoc(N), VT, N0, N1->getOperand(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Arithmetic shifting an all-sign-bit value is a no-op.
|
||||
if (DAG.ComputeNumSignBits(N0) == OpSizeInBits)
|
||||
return N0;
|
||||
|
|
@ -5650,6 +5691,17 @@ SDValue DAGCombiner::visitSRL(SDNode *N) {
|
|||
EVT VT = N0.getValueType();
|
||||
unsigned OpSizeInBits = VT.getScalarSizeInBits();
|
||||
|
||||
// If the target supports masking y in (srl, y),
|
||||
// fold (srl x, (and y, ((1 << numbits(x)) - 1))) -> (srl x, y)
|
||||
if (TLI.isOperationLegal(ISD::SRL, VT) &&
|
||||
TLI.supportsModuloShift(ISD::SRL, VT) && N1->getOpcode() == ISD::AND) {
|
||||
if (ConstantSDNode *Mask = isConstOrConstSplat(N1->getOperand(1))) {
|
||||
if (Mask->getZExtValue() == OpSizeInBits - 1) {
|
||||
return DAG.getNode(ISD::SRL, SDLoc(N), VT, N0, N1->getOperand(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fold vector ops
|
||||
if (VT.isVector())
|
||||
if (SDValue FoldedVOp = SimplifyVBinOp(N))
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ add_llvm_library(LLVMDebugInfoCodeView
|
|||
ModuleDebugLineFragment.cpp
|
||||
ModuleDebugUnknownFragment.cpp
|
||||
RecordSerialization.cpp
|
||||
StringTable.cpp
|
||||
SymbolRecordMapping.cpp
|
||||
SymbolDumper.cpp
|
||||
SymbolSerializer.cpp
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
|
@ -25,7 +26,7 @@ struct FileChecksumEntryHeader {
|
|||
};
|
||||
|
||||
Error llvm::VarStreamArrayExtractor<FileChecksumEntry>::extract(
|
||||
BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item, void *Ctx) {
|
||||
BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {
|
||||
BinaryStreamReader Reader(Stream);
|
||||
|
||||
const FileChecksumEntryHeader *Header;
|
||||
|
|
@ -49,10 +50,12 @@ Error ModuleDebugFileChecksumFragmentRef::initialize(
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
ModuleDebugFileChecksumFragment::ModuleDebugFileChecksumFragment()
|
||||
: ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums) {}
|
||||
ModuleDebugFileChecksumFragment::ModuleDebugFileChecksumFragment(
|
||||
StringTable &Strings)
|
||||
: ModuleDebugFragment(ModuleDebugFragmentKind::FileChecksums),
|
||||
Strings(Strings) {}
|
||||
|
||||
void ModuleDebugFileChecksumFragment::addChecksum(uint32_t StringTableOffset,
|
||||
void ModuleDebugFileChecksumFragment::addChecksum(StringRef FileName,
|
||||
FileChecksumKind Kind,
|
||||
ArrayRef<uint8_t> Bytes) {
|
||||
FileChecksumEntry Entry;
|
||||
|
|
@ -61,13 +64,14 @@ void ModuleDebugFileChecksumFragment::addChecksum(uint32_t StringTableOffset,
|
|||
::memcpy(Copy, Bytes.data(), Bytes.size());
|
||||
Entry.Checksum = makeArrayRef(Copy, Bytes.size());
|
||||
}
|
||||
Entry.FileNameOffset = StringTableOffset;
|
||||
|
||||
Entry.FileNameOffset = Strings.insert(FileName);
|
||||
Entry.Kind = Kind;
|
||||
Checksums.push_back(Entry);
|
||||
|
||||
// This maps the offset of this string in the string table to the offset
|
||||
// of this checksum entry in the checksum buffer.
|
||||
OffsetMap[StringTableOffset] = SerializedSize;
|
||||
OffsetMap[Entry.FileNameOffset] = SerializedSize;
|
||||
assert(SerializedSize % 4 == 0);
|
||||
|
||||
uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
|
||||
|
|
@ -94,9 +98,10 @@ Error ModuleDebugFileChecksumFragment::commit(BinaryStreamWriter &Writer) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t ModuleDebugFileChecksumFragment::mapChecksumOffset(
|
||||
uint32_t StringTableOffset) const {
|
||||
auto Iter = OffsetMap.find(StringTableOffset);
|
||||
uint32_t
|
||||
ModuleDebugFileChecksumFragment::mapChecksumOffset(StringRef FileName) const {
|
||||
uint32_t Offset = Strings.getStringId(FileName);
|
||||
auto Iter = OffsetMap.find(Offset);
|
||||
assert(Iter != OffsetMap.end());
|
||||
return Iter->second;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,20 +10,22 @@
|
|||
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
Error VarStreamArrayExtractor<InlineeSourceLine>::extract(
|
||||
BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item,
|
||||
ContextType *Fragment) {
|
||||
bool HasExtraFiles) {
|
||||
BinaryStreamReader Reader(Stream);
|
||||
|
||||
if (auto EC = Reader.readObject(Item.Header))
|
||||
return EC;
|
||||
|
||||
if (Fragment->hasExtraFiles()) {
|
||||
if (HasExtraFiles) {
|
||||
uint32_t ExtraFileCount;
|
||||
if (auto EC = Reader.readInteger(ExtraFileCount))
|
||||
return EC;
|
||||
|
|
@ -42,7 +44,8 @@ Error ModuleDebugInlineeLineFragmentRef::initialize(BinaryStreamReader Reader) {
|
|||
if (auto EC = Reader.readEnum(Signature))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining(), this))
|
||||
if (auto EC =
|
||||
Reader.readArray(Lines, Reader.bytesRemaining(), hasExtraFiles()))
|
||||
return EC;
|
||||
|
||||
assert(Reader.bytesRemaining() == 0);
|
||||
|
|
@ -54,9 +57,9 @@ bool ModuleDebugInlineeLineFragmentRef::hasExtraFiles() const {
|
|||
}
|
||||
|
||||
ModuleDebugInlineeLineFragment::ModuleDebugInlineeLineFragment(
|
||||
bool HasExtraFiles)
|
||||
ModuleDebugFileChecksumFragment &Checksums, bool HasExtraFiles)
|
||||
: ModuleDebugFragment(ModuleDebugFragmentKind::InlineeLines),
|
||||
HasExtraFiles(HasExtraFiles) {}
|
||||
Checksums(Checksums), HasExtraFiles(HasExtraFiles) {}
|
||||
|
||||
uint32_t ModuleDebugInlineeLineFragment::calculateSerializedLength() {
|
||||
// 4 bytes for the signature
|
||||
|
|
@ -99,18 +102,22 @@ Error ModuleDebugInlineeLineFragment::commit(BinaryStreamWriter &Writer) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
void ModuleDebugInlineeLineFragment::addExtraFile(uint32_t FileOffset) {
|
||||
void ModuleDebugInlineeLineFragment::addExtraFile(StringRef FileName) {
|
||||
uint32_t Offset = Checksums.mapChecksumOffset(FileName);
|
||||
|
||||
auto &Entry = Entries.back();
|
||||
Entry.ExtraFiles.push_back(ulittle32_t(FileOffset));
|
||||
Entry.ExtraFiles.push_back(ulittle32_t(Offset));
|
||||
++ExtraFileCount;
|
||||
}
|
||||
|
||||
void ModuleDebugInlineeLineFragment::addInlineSite(TypeIndex FuncId,
|
||||
uint32_t FileOffset,
|
||||
StringRef FileName,
|
||||
uint32_t SourceLine) {
|
||||
uint32_t Offset = Checksums.mapChecksumOffset(FileName);
|
||||
|
||||
Entries.emplace_back();
|
||||
auto &Entry = Entries.back();
|
||||
Entry.Header.FileID = FileOffset;
|
||||
Entry.Header.FileID = Offset;
|
||||
Entry.Header.SourceLineNum = SourceLine;
|
||||
Entry.Header.Inlinee = FuncId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
|
@ -65,11 +67,15 @@ bool ModuleDebugLineFragmentRef::hasColumnInfo() const {
|
|||
return !!(Header->Flags & LF_HaveColumns);
|
||||
}
|
||||
|
||||
ModuleDebugLineFragment::ModuleDebugLineFragment()
|
||||
: ModuleDebugFragment(ModuleDebugFragmentKind::Lines) {}
|
||||
ModuleDebugLineFragment::ModuleDebugLineFragment(
|
||||
ModuleDebugFileChecksumFragment &Checksums, StringTable &Strings)
|
||||
: ModuleDebugFragment(ModuleDebugFragmentKind::Lines),
|
||||
Checksums(Checksums) {}
|
||||
|
||||
void ModuleDebugLineFragment::createBlock(uint32_t ChecksumBufferOffset) {
|
||||
Blocks.emplace_back(ChecksumBufferOffset);
|
||||
void ModuleDebugLineFragment::createBlock(StringRef FileName) {
|
||||
uint32_t Offset = Checksums.mapChecksumOffset(FileName);
|
||||
|
||||
Blocks.emplace_back(Offset);
|
||||
}
|
||||
|
||||
void ModuleDebugLineFragment::addLineInfo(uint32_t Offset,
|
||||
|
|
|
|||
71
lib/DebugInfo/CodeView/StringTable.cpp
Normal file
71
lib/DebugInfo/CodeView/StringTable.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
//===- StringTable.cpp - CodeView String Table Reader/Writer ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
|
||||
#include "llvm/Support/BinaryStream.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
StringTableRef::StringTableRef() {}
|
||||
|
||||
Error StringTableRef::initialize(BinaryStreamRef Contents) {
|
||||
Stream = Contents;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<StringRef> StringTableRef::getString(uint32_t Offset) const {
|
||||
BinaryStreamReader Reader(Stream);
|
||||
Reader.setOffset(Offset);
|
||||
StringRef Result;
|
||||
if (auto EC = Reader.readCString(Result))
|
||||
return std::move(EC);
|
||||
return Result;
|
||||
}
|
||||
|
||||
uint32_t StringTable::insert(StringRef S) {
|
||||
auto P = Strings.insert({S, StringSize});
|
||||
|
||||
// If a given string didn't exist in the string table, we want to increment
|
||||
// the string table size.
|
||||
if (P.second)
|
||||
StringSize += S.size() + 1; // +1 for '\0'
|
||||
return P.first->second;
|
||||
}
|
||||
|
||||
uint32_t StringTable::calculateSerializedSize() const { return StringSize; }
|
||||
|
||||
Error StringTable::commit(BinaryStreamWriter &Writer) const {
|
||||
assert(Writer.bytesRemaining() == StringSize);
|
||||
uint32_t MaxOffset = 1;
|
||||
|
||||
for (auto &Pair : Strings) {
|
||||
StringRef S = Pair.getKey();
|
||||
uint32_t Offset = Pair.getValue();
|
||||
Writer.setOffset(Offset);
|
||||
if (auto EC = Writer.writeCString(S))
|
||||
return EC;
|
||||
MaxOffset = std::max<uint32_t>(MaxOffset, Offset + S.size() + 1);
|
||||
}
|
||||
|
||||
Writer.setOffset(MaxOffset);
|
||||
assert(Writer.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t StringTable::size() const { return Strings.size(); }
|
||||
|
||||
uint32_t StringTable::getStringId(StringRef S) const {
|
||||
auto P = Strings.find(S);
|
||||
assert(P != Strings.end());
|
||||
return P->second;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
||||
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
|
|
@ -369,14 +370,14 @@ Error CVSymbolDumperImpl::visitKnownRecord(
|
|||
DictScope S(W, "DefRangeSubfield");
|
||||
|
||||
if (ObjDelegate) {
|
||||
StringRef StringTable = ObjDelegate->getStringTable();
|
||||
auto ProgramStringTableOffset = DefRangeSubfield.Program;
|
||||
if (ProgramStringTableOffset >= StringTable.size())
|
||||
StringTableRef Strings = ObjDelegate->getStringTable();
|
||||
auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program);
|
||||
if (!ExpectedProgram) {
|
||||
consumeError(ExpectedProgram.takeError());
|
||||
return llvm::make_error<CodeViewError>(
|
||||
"String table offset outside of bounds of String Table!");
|
||||
StringRef Program =
|
||||
StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
|
||||
W.printString("Program", Program);
|
||||
}
|
||||
W.printString("Program", *ExpectedProgram);
|
||||
}
|
||||
W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
|
||||
printLocalVariableAddrRange(DefRangeSubfield.Range,
|
||||
|
|
@ -390,14 +391,14 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
|||
DictScope S(W, "DefRange");
|
||||
|
||||
if (ObjDelegate) {
|
||||
StringRef StringTable = ObjDelegate->getStringTable();
|
||||
auto ProgramStringTableOffset = DefRange.Program;
|
||||
if (ProgramStringTableOffset >= StringTable.size())
|
||||
StringTableRef Strings = ObjDelegate->getStringTable();
|
||||
auto ExpectedProgram = Strings.getString(DefRange.Program);
|
||||
if (!ExpectedProgram) {
|
||||
consumeError(ExpectedProgram.takeError());
|
||||
return llvm::make_error<CodeViewError>(
|
||||
"String table offset outside of bounds of String Table!");
|
||||
StringRef Program =
|
||||
StringTable.drop_front(ProgramStringTableOffset).split('\0').first;
|
||||
W.printString("Program", Program);
|
||||
}
|
||||
W.printString("Program", *ExpectedProgram);
|
||||
}
|
||||
printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
|
||||
printLocalVariableAddrGap(DefRange.Gaps);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ add_llvm_library(LLVMDebugInfoDWARF
|
|||
DWARFTypeUnit.cpp
|
||||
DWARFUnitIndex.cpp
|
||||
DWARFUnit.cpp
|
||||
DWARFVerifier.cpp
|
||||
SyntaxHighlighting.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
|
||||
#include "llvm/Object/Decompressor.h"
|
||||
#include "llvm/Object/MachO.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
|
|
@ -42,6 +43,8 @@
|
|||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -284,11 +287,30 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH,
|
|||
getStringSection(), isLittleEndian());
|
||||
}
|
||||
|
||||
bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
|
||||
bool Success = true;
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Info) {
|
||||
DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
|
||||
parseCompileUnits();
|
||||
if (auto *CU = CUs.getUnitForOffset(Offset))
|
||||
return CU->getDIEForOffset(Offset);
|
||||
return DWARFDie();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class Verifier {
|
||||
raw_ostream &OS;
|
||||
DWARFContext &DCtx;
|
||||
public:
|
||||
Verifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {}
|
||||
|
||||
bool HandleDebugInfo() {
|
||||
bool Success = true;
|
||||
// A map that tracks all references (converted absolute references) so we
|
||||
// can verify each reference points to a valid DIE and not an offset that
|
||||
// lies between to valid DIEs.
|
||||
std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets;
|
||||
|
||||
OS << "Verifying .debug_info...\n";
|
||||
for (const auto &CU : compile_units()) {
|
||||
for (const auto &CU : DCtx.compile_units()) {
|
||||
unsigned NumDies = CU->getNumDIEs();
|
||||
for (unsigned I = 0; I < NumDies; ++I) {
|
||||
auto Die = CU->getDIEAtIndex(I);
|
||||
|
|
@ -299,101 +321,231 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
|
|||
const auto Attr = AttrValue.Attr;
|
||||
const auto Form = AttrValue.Value.getForm();
|
||||
switch (Attr) {
|
||||
case DW_AT_ranges:
|
||||
// Make sure the offset in the DW_AT_ranges attribute is valid.
|
||||
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||
if (*SectionOffset >= getRangeSection().Data.size()) {
|
||||
case DW_AT_ranges:
|
||||
// Make sure the offset in the DW_AT_ranges attribute is valid.
|
||||
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||
if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
|
||||
Success = false;
|
||||
OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
|
||||
"bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
} else {
|
||||
Success = false;
|
||||
OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
|
||||
"bounds:\n";
|
||||
OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
} else {
|
||||
Success = false;
|
||||
OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
case DW_AT_stmt_list:
|
||||
// Make sure the offset in the DW_AT_stmt_list attribute is valid.
|
||||
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||
if (*SectionOffset >= getLineSection().Data.size()) {
|
||||
break;
|
||||
case DW_AT_stmt_list:
|
||||
// Make sure the offset in the DW_AT_stmt_list attribute is valid.
|
||||
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||
if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
|
||||
Success = false;
|
||||
OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
|
||||
"bounds: "
|
||||
<< format("0x%08" PRIx32, *SectionOffset) << "\n";
|
||||
CU->getUnitDIE().dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
} else {
|
||||
Success = false;
|
||||
OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
|
||||
"bounds: "
|
||||
<< format("0x%08" PRIx32, *SectionOffset) << "\n";
|
||||
CU->getUnitDIE().dump(OS, 0);
|
||||
OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
} else {
|
||||
Success = false;
|
||||
OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (Form) {
|
||||
case DW_FORM_ref1:
|
||||
case DW_FORM_ref2:
|
||||
case DW_FORM_ref4:
|
||||
case DW_FORM_ref8:
|
||||
case DW_FORM_ref_udata: {
|
||||
// Verify all CU relative references are valid CU offsets.
|
||||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
auto DieCU = Die.getDwarfUnit();
|
||||
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
|
||||
auto CUOffset = AttrValue.Value.getRawUValue();
|
||||
if (CUOffset >= CUSize) {
|
||||
case DW_FORM_ref1:
|
||||
case DW_FORM_ref2:
|
||||
case DW_FORM_ref4:
|
||||
case DW_FORM_ref8:
|
||||
case DW_FORM_ref_udata: {
|
||||
// Verify all CU relative references are valid CU offsets.
|
||||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
auto DieCU = Die.getDwarfUnit();
|
||||
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
|
||||
auto CUOffset = AttrValue.Value.getRawUValue();
|
||||
if (CUOffset >= CUSize) {
|
||||
Success = false;
|
||||
OS << "error: " << FormEncodingString(Form) << " CU offset "
|
||||
<< format("0x%08" PRIx32, CUOffset)
|
||||
<< " is invalid (must be less than CU size of "
|
||||
<< format("0x%08" PRIx32, CUSize) << "):\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
} else {
|
||||
// Valid reference, but we will verify it points to an actual
|
||||
// DIE later.
|
||||
ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DW_FORM_ref_addr: {
|
||||
// Verify all absolute DIE references have valid offsets in the
|
||||
// .debug_info section.
|
||||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
if(*RefVal >= DCtx.getInfoSection().Data.size()) {
|
||||
Success = false;
|
||||
OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
|
||||
"bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
} else {
|
||||
// Valid reference, but we will verify it points to an actual
|
||||
// DIE later.
|
||||
ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DW_FORM_strp: {
|
||||
auto SecOffset = AttrValue.Value.getAsSectionOffset();
|
||||
assert(SecOffset); // DW_FORM_strp is a section offset.
|
||||
if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
|
||||
Success = false;
|
||||
OS << "error: " << FormEncodingString(Form) << " CU offset "
|
||||
<< format("0x%08" PRIx32, CUOffset)
|
||||
<< " is invalid (must be less than CU size of "
|
||||
<< format("0x%08" PRIx32, CUSize) << "):\n";
|
||||
OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DW_FORM_ref_addr: {
|
||||
// Verify all absolute DIE references have valid offsets in the
|
||||
// .debug_info section.
|
||||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal && *RefVal >= getInfoSection().Data.size()) {
|
||||
Success = false;
|
||||
OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
|
||||
"bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DW_FORM_strp: {
|
||||
auto SecOffset = AttrValue.Value.getAsSectionOffset();
|
||||
assert(SecOffset); // DW_FORM_strp is a section offset.
|
||||
if (SecOffset && *SecOffset >= getStringSection().size()) {
|
||||
Success = false;
|
||||
OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Take all references and make sure they point to an actual DIE by
|
||||
// getting the DIE by offset and emitting an error
|
||||
OS << "Verifying .debug_info references...\n";
|
||||
for (auto Pair: ReferenceToDIEOffsets) {
|
||||
auto Die = DCtx.getDIEForOffset(Pair.first);
|
||||
if (Die)
|
||||
continue;
|
||||
Success = false;
|
||||
OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
|
||||
<< ". Offset is in between DIEs:\n";
|
||||
for (auto Offset: Pair.second) {
|
||||
auto ReferencingDie = DCtx.getDIEForOffset(Offset);
|
||||
ReferencingDie.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
OS << "\n";
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool HandleDebugLine() {
|
||||
std::map<uint64_t, DWARFDie> StmtListToDie;
|
||||
bool Success = true;
|
||||
OS << "Verifying .debug_line...\n";
|
||||
for (const auto &CU : DCtx.compile_units()) {
|
||||
uint32_t LineTableOffset = 0;
|
||||
auto CUDie = CU->getUnitDIE();
|
||||
auto StmtFormValue = CUDie.find(DW_AT_stmt_list);
|
||||
if (!StmtFormValue) {
|
||||
// No line table for this compile unit.
|
||||
continue;
|
||||
}
|
||||
// Get the attribute value as a section offset. No need to produce an
|
||||
// error here if the encoding isn't correct because we validate this in
|
||||
// the .debug_info verifier.
|
||||
if (auto StmtSectionOffset = toSectionOffset(StmtFormValue)) {
|
||||
LineTableOffset = *StmtSectionOffset;
|
||||
if (LineTableOffset >= DCtx.getLineSection().Data.size()) {
|
||||
// Make sure we don't get a valid line table back if the offset
|
||||
// is wrong.
|
||||
assert(DCtx.getLineTableForUnit(CU.get()) == nullptr);
|
||||
// Skip this line table as it isn't valid. No need to create an error
|
||||
// here because we validate this in the .debug_info verifier.
|
||||
continue;
|
||||
} else {
|
||||
auto Iter = StmtListToDie.find(LineTableOffset);
|
||||
if (Iter != StmtListToDie.end()) {
|
||||
Success = false;
|
||||
OS << "error: two compile unit DIEs, "
|
||||
<< format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
|
||||
<< format("0x%08" PRIx32, CUDie.getOffset())
|
||||
<< ", have the same DW_AT_stmt_list section offset:\n";
|
||||
Iter->second.dump(OS, 0);
|
||||
CUDie.dump(OS, 0);
|
||||
OS << '\n';
|
||||
// Already verified this line table before, no need to do it again.
|
||||
continue;
|
||||
}
|
||||
StmtListToDie[LineTableOffset] = CUDie;
|
||||
}
|
||||
}
|
||||
auto LineTable = DCtx.getLineTableForUnit(CU.get());
|
||||
if (!LineTable) {
|
||||
Success = false;
|
||||
OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
|
||||
<< "] was not able to be parsed for CU:\n";
|
||||
CUDie.dump(OS, 0);
|
||||
OS << '\n';
|
||||
continue;
|
||||
}
|
||||
uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
|
||||
uint64_t PrevAddress = 0;
|
||||
uint32_t RowIndex = 0;
|
||||
for (const auto &Row : LineTable->Rows) {
|
||||
if (Row.Address < PrevAddress) {
|
||||
Success = false;
|
||||
OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
|
||||
<< "] row[" << RowIndex
|
||||
<< "] decreases in address from previous row:\n";
|
||||
|
||||
DWARFDebugLine::Row::dumpTableHeader(OS);
|
||||
if (RowIndex > 0)
|
||||
LineTable->Rows[RowIndex - 1].dump(OS);
|
||||
Row.dump(OS);
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
if (Row.File > MaxFileIndex) {
|
||||
Success = false;
|
||||
OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
|
||||
<< "][" << RowIndex << "] has invalid file index " << Row.File
|
||||
<< " (valid values are [1," << MaxFileIndex << "]):\n";
|
||||
DWARFDebugLine::Row::dumpTableHeader(OS);
|
||||
Row.dump(OS);
|
||||
OS << '\n';
|
||||
}
|
||||
if (Row.EndSequence)
|
||||
PrevAddress = 0;
|
||||
else
|
||||
PrevAddress = Row.Address;
|
||||
++RowIndex;
|
||||
}
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
|
||||
bool Success = true;
|
||||
DWARFVerifier verifier(OS, *this);
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Info) {
|
||||
if (!verifier.handleDebugInfo())
|
||||
Success = false;
|
||||
}
|
||||
if (DumpType == DIDT_All || DumpType == DIDT_Line) {
|
||||
if (!verifier.handleDebugLine())
|
||||
Success = false;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
|
@ -26,11 +27,19 @@ using namespace llvm;
|
|||
using namespace dwarf;
|
||||
|
||||
typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind;
|
||||
namespace {
|
||||
struct ContentDescriptor {
|
||||
dwarf::LineNumberEntryFormat Type;
|
||||
dwarf::Form Form;
|
||||
};
|
||||
typedef SmallVector<ContentDescriptor, 4> ContentDescriptors;
|
||||
} // end anonmyous namespace
|
||||
|
||||
DWARFDebugLine::Prologue::Prologue() { clear(); }
|
||||
|
||||
void DWARFDebugLine::Prologue::clear() {
|
||||
TotalLength = Version = PrologueLength = 0;
|
||||
AddressSize = SegSelectorSize = 0;
|
||||
MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
|
||||
OpcodeBase = 0;
|
||||
IsDWARF64 = false;
|
||||
|
|
@ -43,6 +52,8 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
|
|||
OS << "Line table prologue:\n"
|
||||
<< format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength)
|
||||
<< format(" version: %u\n", Version)
|
||||
<< format(Version >= 5 ? " address_size: %u\n" : "", AddressSize)
|
||||
<< format(Version >= 5 ? " seg_select_size: %u\n" : "", SegSelectorSize)
|
||||
<< format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength)
|
||||
<< format(" min_inst_length: %u\n", MinInstLength)
|
||||
<< format(Version >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
|
||||
|
|
@ -74,6 +85,125 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
|
|||
}
|
||||
}
|
||||
|
||||
// Parse v2-v4 directory and file tables.
|
||||
static void
|
||||
parseV2DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr,
|
||||
uint64_t EndPrologueOffset,
|
||||
std::vector<StringRef> &IncludeDirectories,
|
||||
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
StringRef S = DebugLineData.getCStrRef(OffsetPtr);
|
||||
if (S.empty())
|
||||
break;
|
||||
IncludeDirectories.push_back(S);
|
||||
}
|
||||
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
StringRef Name = DebugLineData.getCStrRef(OffsetPtr);
|
||||
if (Name.empty())
|
||||
break;
|
||||
DWARFDebugLine::FileNameEntry FileEntry;
|
||||
FileEntry.Name = Name;
|
||||
FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileNames.push_back(FileEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse v5 directory/file entry content descriptions.
|
||||
// Returns the descriptors, or an empty vector if we did not find a path or
|
||||
// ran off the end of the prologue.
|
||||
static ContentDescriptors
|
||||
parseV5EntryFormat(DataExtractor DebugLineData, uint32_t *OffsetPtr,
|
||||
uint64_t EndPrologueOffset) {
|
||||
ContentDescriptors Descriptors;
|
||||
int FormatCount = DebugLineData.getU8(OffsetPtr);
|
||||
bool HasPath = false;
|
||||
for (int I = 0; I != FormatCount; ++I) {
|
||||
if (*OffsetPtr >= EndPrologueOffset)
|
||||
return ContentDescriptors();
|
||||
ContentDescriptor Descriptor;
|
||||
Descriptor.Type =
|
||||
dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
|
||||
Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr));
|
||||
if (Descriptor.Type == dwarf::DW_LNCT_path)
|
||||
HasPath = true;
|
||||
Descriptors.push_back(Descriptor);
|
||||
}
|
||||
return HasPath ? Descriptors : ContentDescriptors();
|
||||
}
|
||||
|
||||
static bool
|
||||
parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr,
|
||||
uint64_t EndPrologueOffset,
|
||||
std::vector<StringRef> &IncludeDirectories,
|
||||
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
|
||||
// Get the directory entry description.
|
||||
ContentDescriptors DirDescriptors =
|
||||
parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset);
|
||||
if (DirDescriptors.empty())
|
||||
return false;
|
||||
|
||||
// Get the directory entries, according to the format described above.
|
||||
int DirEntryCount = DebugLineData.getU8(OffsetPtr);
|
||||
for (int I = 0; I != DirEntryCount; ++I) {
|
||||
if (*OffsetPtr >= EndPrologueOffset)
|
||||
return false;
|
||||
for (auto Descriptor : DirDescriptors) {
|
||||
DWARFFormValue Value(Descriptor.Form);
|
||||
switch (Descriptor.Type) {
|
||||
case DW_LNCT_path:
|
||||
if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr))
|
||||
return false;
|
||||
IncludeDirectories.push_back(Value.getAsCString().getValue());
|
||||
break;
|
||||
default:
|
||||
if (!Value.skipValue(DebugLineData, OffsetPtr, nullptr))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the file entry description.
|
||||
ContentDescriptors FileDescriptors =
|
||||
parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset);
|
||||
if (FileDescriptors.empty())
|
||||
return false;
|
||||
|
||||
// Get the file entries, according to the format described above.
|
||||
int FileEntryCount = DebugLineData.getU8(OffsetPtr);
|
||||
for (int I = 0; I != FileEntryCount; ++I) {
|
||||
if (*OffsetPtr >= EndPrologueOffset)
|
||||
return false;
|
||||
DWARFDebugLine::FileNameEntry FileEntry;
|
||||
for (auto Descriptor : FileDescriptors) {
|
||||
DWARFFormValue Value(Descriptor.Form);
|
||||
if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr))
|
||||
return false;
|
||||
switch (Descriptor.Type) {
|
||||
case DW_LNCT_path:
|
||||
FileEntry.Name = Value.getAsCString().getValue();
|
||||
break;
|
||||
case DW_LNCT_directory_index:
|
||||
FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue();
|
||||
break;
|
||||
case DW_LNCT_timestamp:
|
||||
FileEntry.ModTime = Value.getAsUnsignedConstant().getValue();
|
||||
break;
|
||||
case DW_LNCT_size:
|
||||
FileEntry.Length = Value.getAsUnsignedConstant().getValue();
|
||||
break;
|
||||
// FIXME: Add MD5
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
FileNames.push_back(FileEntry);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData,
|
||||
uint32_t *OffsetPtr) {
|
||||
const uint64_t PrologueOffset = *OffsetPtr;
|
||||
|
|
@ -90,6 +220,11 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData,
|
|||
if (Version < 2)
|
||||
return false;
|
||||
|
||||
if (Version >= 5) {
|
||||
AddressSize = DebugLineData.getU8(OffsetPtr);
|
||||
SegSelectorSize = DebugLineData.getU8(OffsetPtr);
|
||||
}
|
||||
|
||||
PrologueLength = DebugLineData.getUnsigned(OffsetPtr, sizeofPrologueLength());
|
||||
const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr;
|
||||
MinInstLength = DebugLineData.getU8(OffsetPtr);
|
||||
|
|
@ -106,27 +241,18 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData,
|
|||
StandardOpcodeLengths.push_back(OpLen);
|
||||
}
|
||||
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
const char *S = DebugLineData.getCStr(OffsetPtr);
|
||||
if (S && S[0])
|
||||
IncludeDirectories.push_back(S);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
while (*OffsetPtr < EndPrologueOffset) {
|
||||
const char *Name = DebugLineData.getCStr(OffsetPtr);
|
||||
if (Name && Name[0]) {
|
||||
FileNameEntry FileEntry;
|
||||
FileEntry.Name = Name;
|
||||
FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
|
||||
FileNames.push_back(FileEntry);
|
||||
} else {
|
||||
break;
|
||||
if (Version >= 5) {
|
||||
if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
|
||||
IncludeDirectories, FileNames)) {
|
||||
fprintf(stderr,
|
||||
"warning: parsing line table prologue at 0x%8.8" PRIx64
|
||||
" found an invalid directory or file table description at"
|
||||
" 0x%8.8" PRIx64 "\n", PrologueOffset, (uint64_t)*OffsetPtr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else
|
||||
parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
|
||||
IncludeDirectories, FileNames);
|
||||
|
||||
if (*OffsetPtr != EndPrologueOffset) {
|
||||
fprintf(stderr,
|
||||
|
|
@ -161,6 +287,12 @@ void DWARFDebugLine::Row::reset(bool DefaultIsStmt) {
|
|||
EpilogueBegin = false;
|
||||
}
|
||||
|
||||
void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) {
|
||||
OS << "Address Line Column File ISA Discriminator Flags\n"
|
||||
<< "------------------ ------ ------ ------ --- ------------- "
|
||||
"-------------\n";
|
||||
}
|
||||
|
||||
void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
|
||||
OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column)
|
||||
<< format(" %6u %3u %13u ", File, Isa, Discriminator)
|
||||
|
|
@ -187,9 +319,7 @@ void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const {
|
|||
OS << '\n';
|
||||
|
||||
if (!Rows.empty()) {
|
||||
OS << "Address Line Column File ISA Discriminator Flags\n"
|
||||
<< "------------------ ------ ------ ------ --- ------------- "
|
||||
"-------------\n";
|
||||
Row::dumpTableHeader(OS);
|
||||
for (const Row &R : Rows) {
|
||||
R.dump(OS);
|
||||
}
|
||||
|
|
@ -637,7 +767,7 @@ bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
|
|||
if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
|
||||
return false;
|
||||
const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1];
|
||||
const char *FileName = Entry.Name;
|
||||
StringRef FileName = Entry.Name;
|
||||
if (Kind != FileLineInfoKind::AbsoluteFilePath ||
|
||||
sys::path::is_absolute(FileName)) {
|
||||
Result = FileName;
|
||||
|
|
@ -646,7 +776,7 @@ bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
|
|||
|
||||
SmallString<16> FilePath;
|
||||
uint64_t IncludeDirIndex = Entry.DirIdx;
|
||||
const char *IncludeDir = "";
|
||||
StringRef IncludeDir;
|
||||
// Be defensive about the contents of Entry.
|
||||
if (IncludeDirIndex > 0 &&
|
||||
IncludeDirIndex <= Prologue.IncludeDirectories.size())
|
||||
|
|
|
|||
277
lib/DebugInfo/DWARF/DWARFVerifier.cpp
Normal file
277
lib/DebugInfo/DWARF/DWARFVerifier.cpp
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
//===- DWARFVerifier.cpp --------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace dwarf;
|
||||
using namespace object;
|
||||
|
||||
void DWARFVerifier::verifyDebugInfoAttribute(DWARFDie &Die,
|
||||
DWARFAttribute &AttrValue) {
|
||||
const auto Attr = AttrValue.Attr;
|
||||
switch (Attr) {
|
||||
case DW_AT_ranges:
|
||||
// Make sure the offset in the DW_AT_ranges attribute is valid.
|
||||
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||
if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
|
||||
"bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
} else {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
case DW_AT_stmt_list:
|
||||
// Make sure the offset in the DW_AT_stmt_list attribute is valid.
|
||||
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
|
||||
if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
|
||||
"bounds: "
|
||||
<< format("0x%08" PRIx32, *SectionOffset) << "\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
} else {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFVerifier::verifyDebugInfoForm(DWARFDie &Die,
|
||||
DWARFAttribute &AttrValue) {
|
||||
const auto Form = AttrValue.Value.getForm();
|
||||
switch (Form) {
|
||||
case DW_FORM_ref1:
|
||||
case DW_FORM_ref2:
|
||||
case DW_FORM_ref4:
|
||||
case DW_FORM_ref8:
|
||||
case DW_FORM_ref_udata: {
|
||||
// Verify all CU relative references are valid CU offsets.
|
||||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
auto DieCU = Die.getDwarfUnit();
|
||||
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
|
||||
auto CUOffset = AttrValue.Value.getRawUValue();
|
||||
if (CUOffset >= CUSize) {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: " << FormEncodingString(Form) << " CU offset "
|
||||
<< format("0x%08" PRIx32, CUOffset)
|
||||
<< " is invalid (must be less than CU size of "
|
||||
<< format("0x%08" PRIx32, CUSize) << "):\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
} else {
|
||||
// Valid reference, but we will verify it points to an actual
|
||||
// DIE later.
|
||||
ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DW_FORM_ref_addr: {
|
||||
// Verify all absolute DIE references have valid offsets in the
|
||||
// .debug_info section.
|
||||
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
|
||||
assert(RefVal);
|
||||
if (RefVal) {
|
||||
if (*RefVal >= DCtx.getInfoSection().Data.size()) {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
|
||||
"bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
} else {
|
||||
// Valid reference, but we will verify it points to an actual
|
||||
// DIE later.
|
||||
ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DW_FORM_strp: {
|
||||
auto SecOffset = AttrValue.Value.getAsSectionOffset();
|
||||
assert(SecOffset); // DW_FORM_strp is a section offset.
|
||||
if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFVerifier::veifyDebugInfoReferences() {
|
||||
// Take all references and make sure they point to an actual DIE by
|
||||
// getting the DIE by offset and emitting an error
|
||||
OS << "Verifying .debug_info references...\n";
|
||||
for (auto Pair : ReferenceToDIEOffsets) {
|
||||
auto Die = DCtx.getDIEForOffset(Pair.first);
|
||||
if (Die)
|
||||
continue;
|
||||
++NumDebugInfoErrors;
|
||||
OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
|
||||
<< ". Offset is in between DIEs:\n";
|
||||
for (auto Offset : Pair.second) {
|
||||
auto ReferencingDie = DCtx.getDIEForOffset(Offset);
|
||||
ReferencingDie.dump(OS, 0);
|
||||
OS << "\n";
|
||||
}
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool DWARFVerifier::handleDebugInfo() {
|
||||
NumDebugInfoErrors = 0;
|
||||
OS << "Verifying .debug_info...\n";
|
||||
for (const auto &CU : DCtx.compile_units()) {
|
||||
unsigned NumDies = CU->getNumDIEs();
|
||||
for (unsigned I = 0; I < NumDies; ++I) {
|
||||
auto Die = CU->getDIEAtIndex(I);
|
||||
const auto Tag = Die.getTag();
|
||||
if (Tag == DW_TAG_null)
|
||||
continue;
|
||||
for (auto AttrValue : Die.attributes()) {
|
||||
verifyDebugInfoAttribute(Die, AttrValue);
|
||||
verifyDebugInfoForm(Die, AttrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
veifyDebugInfoReferences();
|
||||
return NumDebugInfoErrors == 0;
|
||||
}
|
||||
|
||||
void DWARFVerifier::verifyDebugLineStmtOffsets() {
|
||||
std::map<uint64_t, DWARFDie> StmtListToDie;
|
||||
for (const auto &CU : DCtx.compile_units()) {
|
||||
auto Die = CU->getUnitDIE();
|
||||
// Get the attribute value as a section offset. No need to produce an
|
||||
// error here if the encoding isn't correct because we validate this in
|
||||
// the .debug_info verifier.
|
||||
auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
|
||||
if (!StmtSectionOffset)
|
||||
continue;
|
||||
const uint32_t LineTableOffset = *StmtSectionOffset;
|
||||
auto LineTable = DCtx.getLineTableForUnit(CU.get());
|
||||
if (LineTableOffset < DCtx.getLineSection().Data.size()) {
|
||||
if (!LineTable) {
|
||||
++NumDebugLineErrors;
|
||||
OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
|
||||
<< "] was not able to be parsed for CU:\n";
|
||||
Die.dump(OS, 0);
|
||||
OS << '\n';
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Make sure we don't get a valid line table back if the offset is wrong.
|
||||
assert(LineTable == nullptr);
|
||||
// Skip this line table as it isn't valid. No need to create an error
|
||||
// here because we validate this in the .debug_info verifier.
|
||||
continue;
|
||||
}
|
||||
auto Iter = StmtListToDie.find(LineTableOffset);
|
||||
if (Iter != StmtListToDie.end()) {
|
||||
++NumDebugLineErrors;
|
||||
OS << "error: two compile unit DIEs, "
|
||||
<< format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
|
||||
<< format("0x%08" PRIx32, Die.getOffset())
|
||||
<< ", have the same DW_AT_stmt_list section offset:\n";
|
||||
Iter->second.dump(OS, 0);
|
||||
Die.dump(OS, 0);
|
||||
OS << '\n';
|
||||
// Already verified this line table before, no need to do it again.
|
||||
continue;
|
||||
}
|
||||
StmtListToDie[LineTableOffset] = Die;
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFVerifier::verifyDebugLineRows() {
|
||||
for (const auto &CU : DCtx.compile_units()) {
|
||||
auto Die = CU->getUnitDIE();
|
||||
auto LineTable = DCtx.getLineTableForUnit(CU.get());
|
||||
// If there is no line table we will have created an error in the
|
||||
// .debug_info verifier or in verifyDebugLineStmtOffsets().
|
||||
if (!LineTable)
|
||||
continue;
|
||||
uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
|
||||
uint64_t PrevAddress = 0;
|
||||
uint32_t RowIndex = 0;
|
||||
for (const auto &Row : LineTable->Rows) {
|
||||
if (Row.Address < PrevAddress) {
|
||||
++NumDebugLineErrors;
|
||||
OS << "error: .debug_line["
|
||||
<< format("0x%08" PRIx32,
|
||||
*toSectionOffset(Die.find(DW_AT_stmt_list)))
|
||||
<< "] row[" << RowIndex
|
||||
<< "] decreases in address from previous row:\n";
|
||||
|
||||
DWARFDebugLine::Row::dumpTableHeader(OS);
|
||||
if (RowIndex > 0)
|
||||
LineTable->Rows[RowIndex - 1].dump(OS);
|
||||
Row.dump(OS);
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
if (Row.File > MaxFileIndex) {
|
||||
++NumDebugLineErrors;
|
||||
OS << "error: .debug_line["
|
||||
<< format("0x%08" PRIx32,
|
||||
*toSectionOffset(Die.find(DW_AT_stmt_list)))
|
||||
<< "][" << RowIndex << "] has invalid file index " << Row.File
|
||||
<< " (valid values are [1," << MaxFileIndex << "]):\n";
|
||||
DWARFDebugLine::Row::dumpTableHeader(OS);
|
||||
Row.dump(OS);
|
||||
OS << '\n';
|
||||
}
|
||||
if (Row.EndSequence)
|
||||
PrevAddress = 0;
|
||||
else
|
||||
PrevAddress = Row.Address;
|
||||
++RowIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DWARFVerifier::handleDebugLine() {
|
||||
NumDebugLineErrors = 0;
|
||||
OS << "Verifying .debug_line...\n";
|
||||
verifyDebugLineStmtOffsets();
|
||||
verifyDebugLineRows();
|
||||
return NumDebugLineErrors == 0;
|
||||
}
|
||||
|
|
@ -48,11 +48,11 @@ add_pdb_impl_folder(Native
|
|||
Native/NativeSession.cpp
|
||||
Native/PDBFile.cpp
|
||||
Native/PDBFileBuilder.cpp
|
||||
Native/PDBStringTable.cpp
|
||||
Native/PDBStringTableBuilder.cpp
|
||||
Native/PDBTypeServerHandler.cpp
|
||||
Native/PublicsStream.cpp
|
||||
Native/RawError.cpp
|
||||
Native/StringTable.cpp
|
||||
Native/StringTableBuilder.cpp
|
||||
Native/SymbolStream.cpp
|
||||
Native/TpiHashing.cpp
|
||||
Native/TpiStream.cpp
|
||||
|
|
|
|||
|
|
@ -89,6 +89,14 @@ uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
|
|||
return alignTo(L + M + O, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
template <typename T> struct Foo {
|
||||
explicit Foo(T &&Answer) : Answer(Answer) {}
|
||||
|
||||
T Answer;
|
||||
};
|
||||
|
||||
template <typename T> Foo<T> makeFoo(T &&t) { return Foo<T>(std::move(t)); }
|
||||
|
||||
void DbiModuleDescriptorBuilder::finalize() {
|
||||
Layout.FileNameOffs = 0; // TODO: Fix this
|
||||
Layout.Flags = 0; // TODO: Fix this
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ Error DbiStream::reload() {
|
|||
|
||||
if (ECSubstream.getLength() > 0) {
|
||||
BinaryStreamReader ECReader(ECSubstream);
|
||||
if (auto EC = ECNames.load(ECReader))
|
||||
if (auto EC = ECNames.reload(ECReader))
|
||||
return EC;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@
|
|||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTable.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||
#include "llvm/Support/BinaryStream.h"
|
||||
|
|
@ -337,8 +337,8 @@ Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
|
|||
return *Symbols;
|
||||
}
|
||||
|
||||
Expected<StringTable &> PDBFile::getStringTable() {
|
||||
if (!Strings || !StringTableStream) {
|
||||
Expected<PDBStringTable &> PDBFile::getStringTable() {
|
||||
if (!Strings) {
|
||||
auto IS = getPDBInfoStream();
|
||||
if (!IS)
|
||||
return IS.takeError();
|
||||
|
|
@ -350,12 +350,13 @@ Expected<StringTable &> PDBFile::getStringTable() {
|
|||
if (!NS)
|
||||
return NS.takeError();
|
||||
|
||||
auto N = llvm::make_unique<PDBStringTable>();
|
||||
BinaryStreamReader Reader(**NS);
|
||||
auto N = llvm::make_unique<StringTable>();
|
||||
if (auto EC = N->load(Reader))
|
||||
if (auto EC = N->reload(Reader))
|
||||
return std::move(EC);
|
||||
Strings = std::move(N);
|
||||
assert(Reader.bytesRemaining() == 0);
|
||||
StringTableStream = std::move(*NS);
|
||||
Strings = std::move(N);
|
||||
}
|
||||
return *Strings;
|
||||
}
|
||||
|
|
@ -389,7 +390,7 @@ bool PDBFile::hasPDBSymbolStream() {
|
|||
|
||||
bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
|
||||
|
||||
bool PDBFile::hasStringTable() {
|
||||
bool PDBFile::hasPDBStringTable() {
|
||||
auto IS = getPDBInfoStream();
|
||||
if (!IS)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
|
||||
#include "llvm/Support/BinaryStream.h"
|
||||
|
|
@ -67,7 +67,9 @@ TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
|
|||
return *Ipi;
|
||||
}
|
||||
|
||||
StringTableBuilder &PDBFileBuilder::getStringTableBuilder() { return Strings; }
|
||||
PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
|
||||
return Strings;
|
||||
}
|
||||
|
||||
Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
|
||||
auto ExpectedStream = Msf->addStream(Size);
|
||||
|
|
@ -78,9 +80,9 @@ Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
|
|||
}
|
||||
|
||||
Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
|
||||
uint32_t StringTableSize = Strings.finalize();
|
||||
uint32_t StringsLen = Strings.calculateSerializedSize();
|
||||
|
||||
if (auto EC = addNamedStream("/names", StringTableSize))
|
||||
if (auto EC = addNamedStream("/names", StringsLen))
|
||||
return std::move(EC);
|
||||
if (auto EC = addNamedStream("/LinkInfo", 0))
|
||||
return std::move(EC);
|
||||
|
|
@ -107,6 +109,13 @@ Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
|
|||
return Msf->build();
|
||||
}
|
||||
|
||||
Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
|
||||
uint32_t SN = 0;
|
||||
if (!NamedStreams.get(Name, SN))
|
||||
return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
|
||||
return SN;
|
||||
}
|
||||
|
||||
Error PDBFileBuilder::commit(StringRef Filename) {
|
||||
auto ExpectedLayout = finalizeMsfLayout();
|
||||
if (!ExpectedLayout)
|
||||
|
|
@ -144,12 +153,12 @@ Error PDBFileBuilder::commit(StringRef Filename) {
|
|||
return EC;
|
||||
}
|
||||
|
||||
uint32_t StringTableStreamNo = 0;
|
||||
if (!NamedStreams.get("/names", StringTableStreamNo))
|
||||
return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
|
||||
auto ExpectedSN = getNamedStreamIndex("/names");
|
||||
if (!ExpectedSN)
|
||||
return ExpectedSN.takeError();
|
||||
|
||||
auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
|
||||
StringTableStreamNo);
|
||||
*ExpectedSN);
|
||||
BinaryStreamWriter NSWriter(*NS);
|
||||
if (auto EC = Strings.commit(NSWriter))
|
||||
return EC;
|
||||
|
|
|
|||
134
lib/DebugInfo/PDB/Native/PDBStringTable.cpp
Normal file
134
lib/DebugInfo/PDB/Native/PDBStringTable.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
//===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/Hash.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::support;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
uint32_t PDBStringTable::getByteSize() const { return ByteSize; }
|
||||
uint32_t PDBStringTable::getNameCount() const { return NameCount; }
|
||||
uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; }
|
||||
uint32_t PDBStringTable::getSignature() const { return Header->Signature; }
|
||||
|
||||
Error PDBStringTable::readHeader(BinaryStreamReader &Reader) {
|
||||
if (auto EC = Reader.readObject(Header))
|
||||
return EC;
|
||||
|
||||
if (Header->Signature != PDBStringTableSignature)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid hash table signature");
|
||||
if (Header->HashVersion != 1 && Header->HashVersion != 2)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Unsupported hash version");
|
||||
|
||||
assert(Reader.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
|
||||
BinaryStreamRef Stream;
|
||||
if (auto EC = Reader.readStreamRef(Stream))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Strings.initialize(Stream)) {
|
||||
return joinErrors(std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid hash table byte length"));
|
||||
}
|
||||
|
||||
assert(Reader.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) {
|
||||
const support::ulittle32_t *HashCount;
|
||||
if (auto EC = Reader.readObject(HashCount))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Reader.readArray(IDs, *HashCount)) {
|
||||
return joinErrors(std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Could not read bucket array"));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) {
|
||||
if (auto EC = Reader.readInteger(NameCount))
|
||||
return EC;
|
||||
|
||||
assert(Reader.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTable::reload(BinaryStreamReader &Reader) {
|
||||
|
||||
BinaryStreamReader SectionReader;
|
||||
|
||||
std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader));
|
||||
if (auto EC = readHeader(SectionReader))
|
||||
return EC;
|
||||
|
||||
std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize);
|
||||
if (auto EC = readStrings(SectionReader))
|
||||
return EC;
|
||||
|
||||
// We don't know how long the hash table is until we parse it, so let the
|
||||
// function responsible for doing that figure it out.
|
||||
if (auto EC = readHashTable(Reader))
|
||||
return EC;
|
||||
|
||||
std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t));
|
||||
if (auto EC = readEpilogue(SectionReader))
|
||||
return EC;
|
||||
|
||||
assert(Reader.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const {
|
||||
return Strings.getString(ID);
|
||||
}
|
||||
|
||||
Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const {
|
||||
uint32_t Hash =
|
||||
(Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
|
||||
size_t Count = IDs.size();
|
||||
uint32_t Start = Hash % Count;
|
||||
for (size_t I = 0; I < Count; ++I) {
|
||||
// The hash is just a starting point for the search, but if it
|
||||
// doesn't work we should find the string no matter what, because
|
||||
// we iterate the entire array.
|
||||
uint32_t Index = (Start + I) % Count;
|
||||
|
||||
uint32_t ID = IDs[Index];
|
||||
auto ExpectedStr = getStringForID(ID);
|
||||
if (!ExpectedStr)
|
||||
return ExpectedStr.takeError();
|
||||
|
||||
if (*ExpectedStr == Str)
|
||||
return ID;
|
||||
}
|
||||
return make_error<RawError>(raw_error_code::no_entry);
|
||||
}
|
||||
|
||||
FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const {
|
||||
return IDs;
|
||||
}
|
||||
133
lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
Normal file
133
lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
//===- PDBStringTableBuilder.cpp - PDB String Table -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/Hash.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::support;
|
||||
using namespace llvm::support::endian;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
uint32_t PDBStringTableBuilder::insert(StringRef S) {
|
||||
return Strings.insert(S);
|
||||
}
|
||||
|
||||
static uint32_t computeBucketCount(uint32_t NumStrings) {
|
||||
// The /names stream is basically an on-disk open-addressing hash table.
|
||||
// Hash collisions are resolved by linear probing. We cannot make
|
||||
// utilization 100% because it will make the linear probing extremely
|
||||
// slow. But lower utilization wastes disk space. As a reasonable
|
||||
// load factor, we choose 80%. We need +1 because slot 0 is reserved.
|
||||
return (NumStrings + 1) * 1.25;
|
||||
}
|
||||
|
||||
uint32_t PDBStringTableBuilder::calculateHashTableSize() const {
|
||||
uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field.
|
||||
Size += sizeof(uint32_t) * computeBucketCount(Strings.size());
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
uint32_t PDBStringTableBuilder::calculateSerializedSize() const {
|
||||
uint32_t Size = 0;
|
||||
Size += sizeof(PDBStringTableHeader);
|
||||
Size += Strings.calculateSerializedSize();
|
||||
Size += calculateHashTableSize();
|
||||
Size += sizeof(uint32_t); // The /names stream ends with the string count.
|
||||
return Size;
|
||||
}
|
||||
|
||||
Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const {
|
||||
// Write a header
|
||||
PDBStringTableHeader H;
|
||||
H.Signature = PDBStringTableSignature;
|
||||
H.HashVersion = 1;
|
||||
H.ByteSize = Strings.calculateSerializedSize();
|
||||
if (auto EC = Writer.writeObject(H))
|
||||
return EC;
|
||||
assert(Writer.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const {
|
||||
if (auto EC = Strings.commit(Writer))
|
||||
return EC;
|
||||
|
||||
assert(Writer.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const {
|
||||
// Write a hash table.
|
||||
uint32_t BucketCount = computeBucketCount(Strings.size());
|
||||
if (auto EC = Writer.writeInteger(BucketCount))
|
||||
return EC;
|
||||
std::vector<ulittle32_t> Buckets(BucketCount);
|
||||
|
||||
for (auto &Pair : Strings) {
|
||||
StringRef S = Pair.getKey();
|
||||
uint32_t Offset = Pair.getValue();
|
||||
uint32_t Hash = hashStringV1(S);
|
||||
|
||||
for (uint32_t I = 0; I != BucketCount; ++I) {
|
||||
uint32_t Slot = (Hash + I) % BucketCount;
|
||||
if (Slot == 0)
|
||||
continue; // Skip reserved slot
|
||||
if (Buckets[Slot] != 0)
|
||||
continue;
|
||||
Buckets[Slot] = Offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets)))
|
||||
return EC;
|
||||
|
||||
assert(Writer.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const {
|
||||
if (auto EC = Writer.writeInteger<uint32_t>(Strings.size()))
|
||||
return EC;
|
||||
assert(Writer.bytesRemaining() == 0);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const {
|
||||
BinaryStreamWriter SectionWriter;
|
||||
|
||||
std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader));
|
||||
if (auto EC = writeHeader(SectionWriter))
|
||||
return EC;
|
||||
|
||||
std::tie(SectionWriter, Writer) =
|
||||
Writer.split(Strings.calculateSerializedSize());
|
||||
if (auto EC = writeStrings(SectionWriter))
|
||||
return EC;
|
||||
|
||||
std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize());
|
||||
if (auto EC = writeHashTable(SectionWriter))
|
||||
return EC;
|
||||
|
||||
std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t));
|
||||
if (auto EC = writeEpilogue(SectionWriter))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
//===- StringTable.cpp - PDB String Table -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTable.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/Hash.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::support;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
StringTable::StringTable() {}
|
||||
|
||||
Error StringTable::load(BinaryStreamReader &Stream) {
|
||||
ByteSize = Stream.getLength();
|
||||
|
||||
const StringTableHeader *H;
|
||||
if (auto EC = Stream.readObject(H))
|
||||
return EC;
|
||||
|
||||
if (H->Signature != StringTableSignature)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid hash table signature");
|
||||
if (H->HashVersion != 1 && H->HashVersion != 2)
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Unsupported hash version");
|
||||
|
||||
Signature = H->Signature;
|
||||
HashVersion = H->HashVersion;
|
||||
if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
|
||||
return joinErrors(std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Invalid hash table byte length"));
|
||||
|
||||
const support::ulittle32_t *HashCount;
|
||||
if (auto EC = Stream.readObject(HashCount))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Stream.readArray(IDs, *HashCount))
|
||||
return joinErrors(std::move(EC),
|
||||
make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Could not read bucket array"));
|
||||
|
||||
if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
|
||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
||||
"Missing name count");
|
||||
|
||||
if (auto EC = Stream.readInteger(NameCount))
|
||||
return EC;
|
||||
|
||||
if (Stream.bytesRemaining() > 0)
|
||||
return make_error<RawError>(raw_error_code::stream_too_long,
|
||||
"Unexpected bytes found in string table");
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t StringTable::getByteSize() const {
|
||||
return ByteSize;
|
||||
}
|
||||
|
||||
StringRef StringTable::getStringForID(uint32_t ID) const {
|
||||
if (ID == IDs[0])
|
||||
return StringRef();
|
||||
|
||||
// NamesBuffer is a buffer of null terminated strings back to back. ID is
|
||||
// the starting offset of the string we're looking for. So just seek into
|
||||
// the desired offset and a read a null terminated stream from that offset.
|
||||
StringRef Result;
|
||||
BinaryStreamReader NameReader(NamesBuffer);
|
||||
NameReader.setOffset(ID);
|
||||
if (auto EC = NameReader.readCString(Result))
|
||||
consumeError(std::move(EC));
|
||||
return Result;
|
||||
}
|
||||
|
||||
uint32_t StringTable::getIDForString(StringRef Str) const {
|
||||
uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
|
||||
size_t Count = IDs.size();
|
||||
uint32_t Start = Hash % Count;
|
||||
for (size_t I = 0; I < Count; ++I) {
|
||||
// The hash is just a starting point for the search, but if it
|
||||
// doesn't work we should find the string no matter what, because
|
||||
// we iterate the entire array.
|
||||
uint32_t Index = (Start + I) % Count;
|
||||
|
||||
uint32_t ID = IDs[Index];
|
||||
StringRef S = getStringForID(ID);
|
||||
if (S == Str)
|
||||
return ID;
|
||||
}
|
||||
// IDs[0] contains the ID of the "invalid" entry.
|
||||
return IDs[0];
|
||||
}
|
||||
|
||||
FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const {
|
||||
return IDs;
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
//===- StringTableBuilder.cpp - PDB String Table ----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/Hash.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::support;
|
||||
using namespace llvm::support::endian;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
uint32_t StringTableBuilder::insert(StringRef S) {
|
||||
auto P = Strings.insert({S, StringSize});
|
||||
|
||||
// If a given string didn't exist in the string table, we want to increment
|
||||
// the string table size.
|
||||
if (P.second)
|
||||
StringSize += S.size() + 1; // +1 for '\0'
|
||||
return P.first->second;
|
||||
}
|
||||
|
||||
uint32_t StringTableBuilder::getStringIndex(StringRef S) {
|
||||
auto Iter = Strings.find(S);
|
||||
assert(Iter != Strings.end());
|
||||
return Iter->second;
|
||||
}
|
||||
|
||||
static uint32_t computeBucketCount(uint32_t NumStrings) {
|
||||
// The /names stream is basically an on-disk open-addressing hash table.
|
||||
// Hash collisions are resolved by linear probing. We cannot make
|
||||
// utilization 100% because it will make the linear probing extremely
|
||||
// slow. But lower utilization wastes disk space. As a reasonable
|
||||
// load factor, we choose 80%. We need +1 because slot 0 is reserved.
|
||||
return (NumStrings + 1) * 1.25;
|
||||
}
|
||||
|
||||
uint32_t StringTableBuilder::finalize() {
|
||||
uint32_t Size = 0;
|
||||
Size += sizeof(StringTableHeader);
|
||||
Size += StringSize;
|
||||
Size += sizeof(uint32_t); // Hash table begins with 4-byte size field.
|
||||
|
||||
uint32_t BucketCount = computeBucketCount(Strings.size());
|
||||
Size += BucketCount * sizeof(uint32_t);
|
||||
|
||||
Size +=
|
||||
sizeof(uint32_t); // The /names stream ends with the number of strings.
|
||||
return Size;
|
||||
}
|
||||
|
||||
Error StringTableBuilder::commit(BinaryStreamWriter &Writer) const {
|
||||
// Write a header
|
||||
StringTableHeader H;
|
||||
H.Signature = StringTableSignature;
|
||||
H.HashVersion = 1;
|
||||
H.ByteSize = StringSize;
|
||||
if (auto EC = Writer.writeObject(H))
|
||||
return EC;
|
||||
|
||||
// Write a string table.
|
||||
uint32_t StringStart = Writer.getOffset();
|
||||
for (auto Pair : Strings) {
|
||||
StringRef S = Pair.first;
|
||||
uint32_t Offset = Pair.second;
|
||||
Writer.setOffset(StringStart + Offset);
|
||||
if (auto EC = Writer.writeCString(S))
|
||||
return EC;
|
||||
}
|
||||
Writer.setOffset(StringStart + StringSize);
|
||||
|
||||
// Write a hash table.
|
||||
uint32_t BucketCount = computeBucketCount(Strings.size());
|
||||
if (auto EC = Writer.writeInteger(BucketCount))
|
||||
return EC;
|
||||
std::vector<ulittle32_t> Buckets(BucketCount);
|
||||
|
||||
for (auto Pair : Strings) {
|
||||
StringRef S = Pair.first;
|
||||
uint32_t Offset = Pair.second;
|
||||
uint32_t Hash = hashStringV1(S);
|
||||
|
||||
for (uint32_t I = 0; I != BucketCount; ++I) {
|
||||
uint32_t Slot = (Hash + I) % BucketCount;
|
||||
if (Slot == 0)
|
||||
continue; // Skip reserved slot
|
||||
if (Buckets[Slot] != 0)
|
||||
continue;
|
||||
Buckets[Slot] = Offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets)))
|
||||
return EC;
|
||||
if (auto EC = Writer.writeInteger(static_cast<uint32_t>(Strings.size())))
|
||||
return EC;
|
||||
return Error::success();
|
||||
}
|
||||
|
|
@ -819,6 +819,34 @@ void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
|
|||
}
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section,
|
||||
uint64_t Offset, uint64_t Value,
|
||||
uint32_t Type, int64_t Addend) {
|
||||
bool isBE = Arch == Triple::bpfeb;
|
||||
|
||||
switch (Type) {
|
||||
default:
|
||||
llvm_unreachable("Relocation type not implemented yet!");
|
||||
break;
|
||||
case ELF::R_BPF_NONE:
|
||||
break;
|
||||
case ELF::R_BPF_64_64: {
|
||||
write(isBE, Section.getAddressWithOffset(Offset), Value + Addend);
|
||||
DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at "
|
||||
<< format("%p\n", Section.getAddressWithOffset(Offset)));
|
||||
break;
|
||||
}
|
||||
case ELF::R_BPF_64_32: {
|
||||
Value += Addend;
|
||||
assert(Value <= UINT32_MAX);
|
||||
write(isBE, Section.getAddressWithOffset(Offset), static_cast<uint32_t>(Value));
|
||||
DEBUG(dbgs() << "Writing " << format("%p", Value) << " at "
|
||||
<< format("%p\n", Section.getAddressWithOffset(Offset)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The target location for the relocation is described by RE.SectionID and
|
||||
// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
|
||||
// SectionEntry has three members describing its location.
|
||||
|
|
@ -879,6 +907,10 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section,
|
|||
case Triple::systemz:
|
||||
resolveSystemZRelocation(Section, Offset, Value, Type, Addend);
|
||||
break;
|
||||
case Triple::bpfel:
|
||||
case Triple::bpfeb:
|
||||
resolveBPFRelocation(Section, Offset, Value, Type, Addend);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported CPU type!");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
|
|||
void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint64_t Value, uint32_t Type, int64_t Addend);
|
||||
|
||||
void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint64_t Value, uint32_t Type, int64_t Addend);
|
||||
|
||||
unsigned getMaxStubSize() override {
|
||||
if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be)
|
||||
return 20; // movz; movk; movk; movk; br
|
||||
|
|
|
|||
|
|
@ -936,7 +936,9 @@ AttributeList AttributeList::get(LLVMContext &C,
|
|||
AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute::AttrKind Kind) const {
|
||||
if (hasAttribute(Index, Kind)) return *this;
|
||||
return addAttributes(C, Index, AttributeList::get(C, Index, Kind));
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Kind);
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
|
||||
|
|
@ -944,7 +946,7 @@ AttributeList AttributeList::addAttribute(LLVMContext &C, unsigned Index,
|
|||
StringRef Value) const {
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Kind, Value);
|
||||
return addAttributes(C, Index, AttributeList::get(C, Index, B));
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addAttribute(LLVMContext &C,
|
||||
|
|
@ -977,14 +979,6 @@ AttributeList AttributeList::addAttribute(LLVMContext &C,
|
|||
return get(C, AttrVec);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index,
|
||||
AttributeList Attrs) const {
|
||||
if (!pImpl) return Attrs;
|
||||
if (!Attrs.pImpl) return *this;
|
||||
|
||||
return addAttributes(C, Index, Attrs.getAttributes(Index));
|
||||
}
|
||||
|
||||
AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index,
|
||||
const AttrBuilder &B) const {
|
||||
if (!B.hasAttributes())
|
||||
|
|
@ -1034,18 +1028,17 @@ AttributeList AttributeList::addAttributes(LLVMContext &C, unsigned Index,
|
|||
AttributeList AttributeList::removeAttribute(LLVMContext &C, unsigned Index,
|
||||
Attribute::AttrKind Kind) const {
|
||||
if (!hasAttribute(Index, Kind)) return *this;
|
||||
return removeAttributes(C, Index, AttributeList::get(C, Index, Kind));
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Kind);
|
||||
return removeAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::removeAttribute(LLVMContext &C, unsigned Index,
|
||||
StringRef Kind) const {
|
||||
if (!hasAttribute(Index, Kind)) return *this;
|
||||
return removeAttributes(C, Index, AttributeList::get(C, Index, Kind));
|
||||
}
|
||||
|
||||
AttributeList AttributeList::removeAttributes(LLVMContext &C, unsigned Index,
|
||||
AttributeList Attrs) const {
|
||||
return removeAttributes(C, Index, AttrBuilder(Attrs.getAttributes(Index)));
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Kind);
|
||||
return removeAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList AttributeList::removeAttributes(LLVMContext &C, unsigned Index,
|
||||
|
|
@ -1103,7 +1096,7 @@ AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C,
|
|||
uint64_t Bytes) const {
|
||||
AttrBuilder B;
|
||||
B.addDereferenceableAttr(Bytes);
|
||||
return addAttributes(C, Index, AttributeList::get(C, Index, B));
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList
|
||||
|
|
@ -1111,7 +1104,7 @@ AttributeList::addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index,
|
|||
uint64_t Bytes) const {
|
||||
AttrBuilder B;
|
||||
B.addDereferenceableOrNullAttr(Bytes);
|
||||
return addAttributes(C, Index, AttributeList::get(C, Index, B));
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
AttributeList
|
||||
|
|
@ -1120,7 +1113,7 @@ AttributeList::addAllocSizeAttr(LLVMContext &C, unsigned Index,
|
|||
const Optional<unsigned> &NumElemsArg) {
|
||||
AttrBuilder B;
|
||||
B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
|
||||
return addAttributes(C, Index, AttributeList::get(C, Index, B));
|
||||
return addAttributes(C, Index, B);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -1130,7 +1123,7 @@ AttributeList::addAllocSizeAttr(LLVMContext &C, unsigned Index,
|
|||
LLVMContext &AttributeList::getContext() const { return pImpl->getContext(); }
|
||||
|
||||
AttributeSet AttributeList::getParamAttributes(unsigned ArgNo) const {
|
||||
return getAttributes(ArgNo + 1);
|
||||
return getAttributes(ArgNo + FirstArgIndex);
|
||||
}
|
||||
|
||||
AttributeSet AttributeList::getRetAttributes() const {
|
||||
|
|
@ -1196,7 +1189,7 @@ unsigned AttributeList::getRetAlignment() const {
|
|||
}
|
||||
|
||||
unsigned AttributeList::getParamAlignment(unsigned ArgNo) const {
|
||||
return getAttributes(ArgNo + 1).getAlignment();
|
||||
return getAttributes(ArgNo + FirstArgIndex).getAlignment();
|
||||
}
|
||||
|
||||
unsigned AttributeList::getStackAlignment(unsigned Index) const {
|
||||
|
|
@ -1610,12 +1603,10 @@ static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {
|
|||
// If upgrading the SSP attribute, clear out the old SSP Attributes first.
|
||||
// Having multiple SSP attributes doesn't actually hurt, but it adds useless
|
||||
// clutter to the IR.
|
||||
AttrBuilder B;
|
||||
B.addAttribute(Attribute::StackProtect)
|
||||
.addAttribute(Attribute::StackProtectStrong)
|
||||
.addAttribute(Attribute::StackProtectReq);
|
||||
AttributeList OldSSPAttr =
|
||||
AttributeList::get(Caller.getContext(), AttributeList::FunctionIndex, B);
|
||||
AttrBuilder OldSSPAttr;
|
||||
OldSSPAttr.addAttribute(Attribute::StackProtect)
|
||||
.addAttribute(Attribute::StackProtectStrong)
|
||||
.addAttribute(Attribute::StackProtectReq);
|
||||
|
||||
if (Callee.hasFnAttribute(Attribute::StackProtectReq)) {
|
||||
Caller.removeAttributes(AttributeList::FunctionIndex, OldSSPAttr);
|
||||
|
|
|
|||
|
|
@ -467,6 +467,27 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
// Renaming gather/scatter intrinsics with no address space overloading
|
||||
// to the new overload which includes an address space
|
||||
if (Name.startswith("masked.gather.")) {
|
||||
Type *Tys[] = {F->getReturnType(), F->arg_begin()->getType()};
|
||||
if (F->getName() != Intrinsic::getName(Intrinsic::masked_gather, Tys)) {
|
||||
rename(F);
|
||||
NewFn = Intrinsic::getDeclaration(F->getParent(),
|
||||
Intrinsic::masked_gather, Tys);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (Name.startswith("masked.scatter.")) {
|
||||
auto Args = F->getFunctionType()->params();
|
||||
Type *Tys[] = {Args[0], Args[1]};
|
||||
if (F->getName() != Intrinsic::getName(Intrinsic::masked_scatter, Tys)) {
|
||||
rename(F);
|
||||
NewFn = Intrinsic::getDeclaration(F->getParent(),
|
||||
Intrinsic::masked_scatter, Tys);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
|
|
@ -2072,7 +2093,9 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) {
|
|||
case Intrinsic::invariant_start:
|
||||
case Intrinsic::invariant_end:
|
||||
case Intrinsic::masked_load:
|
||||
case Intrinsic::masked_store: {
|
||||
case Intrinsic::masked_store:
|
||||
case Intrinsic::masked_gather:
|
||||
case Intrinsic::masked_scatter: {
|
||||
SmallVector<Value *, 4> Args(CI->arg_operands().begin(),
|
||||
CI->arg_operands().end());
|
||||
NewCall = Builder.CreateCall(NewFn, Args);
|
||||
|
|
|
|||
|
|
@ -90,13 +90,15 @@ unsigned Argument::getParamAlignment() const {
|
|||
uint64_t Argument::getDereferenceableBytes() const {
|
||||
assert(getType()->isPointerTy() &&
|
||||
"Only pointers have dereferenceable bytes");
|
||||
return getParent()->getDereferenceableBytes(getArgNo()+1);
|
||||
return getParent()->getDereferenceableBytes(getArgNo() +
|
||||
AttributeList::FirstArgIndex);
|
||||
}
|
||||
|
||||
uint64_t Argument::getDereferenceableOrNullBytes() const {
|
||||
assert(getType()->isPointerTy() &&
|
||||
"Only pointers have dereferenceable bytes");
|
||||
return getParent()->getDereferenceableOrNullBytes(getArgNo()+1);
|
||||
return getParent()->getDereferenceableOrNullBytes(
|
||||
getArgNo() + AttributeList::FirstArgIndex);
|
||||
}
|
||||
|
||||
bool Argument::hasNestAttr() const {
|
||||
|
|
@ -139,20 +141,21 @@ bool Argument::onlyReadsMemory() const {
|
|||
|
||||
void Argument::addAttrs(AttrBuilder &B) {
|
||||
AttributeList AL = getParent()->getAttributes();
|
||||
AL = AL.addAttributes(Parent->getContext(), getArgNo() + 1, B);
|
||||
AL = AL.addAttributes(Parent->getContext(),
|
||||
getArgNo() + AttributeList::FirstArgIndex, B);
|
||||
getParent()->setAttributes(AL);
|
||||
}
|
||||
|
||||
void Argument::addAttr(Attribute::AttrKind Kind) {
|
||||
getParent()->addAttribute(getArgNo() + 1, Kind);
|
||||
getParent()->addAttribute(getArgNo() + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
void Argument::addAttr(Attribute Attr) {
|
||||
getParent()->addAttribute(getArgNo() + 1, Attr);
|
||||
getParent()->addAttribute(getArgNo() + AttributeList::FirstArgIndex, Attr);
|
||||
}
|
||||
|
||||
void Argument::removeAttr(Attribute::AttrKind Kind) {
|
||||
getParent()->removeAttribute(getArgNo() + 1, Kind);
|
||||
getParent()->removeAttribute(getArgNo() + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
bool Argument::hasAttribute(Attribute::AttrKind Kind) const {
|
||||
|
|
@ -328,7 +331,7 @@ void Function::addAttribute(unsigned i, Attribute Attr) {
|
|||
setAttributes(PAL);
|
||||
}
|
||||
|
||||
void Function::addAttributes(unsigned i, AttributeList Attrs) {
|
||||
void Function::addAttributes(unsigned i, const AttrBuilder &Attrs) {
|
||||
AttributeList PAL = getAttributes();
|
||||
PAL = PAL.addAttributes(getContext(), i, Attrs);
|
||||
setAttributes(PAL);
|
||||
|
|
@ -346,7 +349,7 @@ void Function::removeAttribute(unsigned i, StringRef Kind) {
|
|||
setAttributes(PAL);
|
||||
}
|
||||
|
||||
void Function::removeAttributes(unsigned i, AttributeList Attrs) {
|
||||
void Function::removeAttributes(unsigned i, const AttrBuilder &Attrs) {
|
||||
AttributeList PAL = getAttributes();
|
||||
PAL = PAL.removeAttributes(getContext(), i, Attrs);
|
||||
setAttributes(PAL);
|
||||
|
|
@ -574,13 +577,12 @@ enum IIT_Info {
|
|||
IIT_SAME_VEC_WIDTH_ARG = 31,
|
||||
IIT_PTR_TO_ARG = 32,
|
||||
IIT_PTR_TO_ELT = 33,
|
||||
IIT_VEC_OF_PTRS_TO_ELT = 34,
|
||||
IIT_VEC_OF_ANYPTRS_TO_ELT = 34,
|
||||
IIT_I128 = 35,
|
||||
IIT_V512 = 36,
|
||||
IIT_V1024 = 37
|
||||
};
|
||||
|
||||
|
||||
static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
|
||||
SmallVectorImpl<Intrinsic::IITDescriptor> &OutputTable) {
|
||||
IIT_Info Info = IIT_Info(Infos[NextElt++]);
|
||||
|
|
@ -716,10 +718,11 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
|
|||
OutputTable.push_back(IITDescriptor::get(IITDescriptor::PtrToElt, ArgInfo));
|
||||
return;
|
||||
}
|
||||
case IIT_VEC_OF_PTRS_TO_ELT: {
|
||||
unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
|
||||
OutputTable.push_back(IITDescriptor::get(IITDescriptor::VecOfPtrsToElt,
|
||||
ArgInfo));
|
||||
case IIT_VEC_OF_ANYPTRS_TO_ELT: {
|
||||
unsigned short ArgNo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
|
||||
unsigned short RefNo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
|
||||
OutputTable.push_back(
|
||||
IITDescriptor::get(IITDescriptor::VecOfAnyPtrsToElt, ArgNo, RefNo));
|
||||
return;
|
||||
}
|
||||
case IIT_EMPTYSTRUCT:
|
||||
|
|
@ -808,7 +811,6 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
|
|||
Elts[i] = DecodeFixedType(Infos, Tys, Context);
|
||||
return StructType::get(Context, makeArrayRef(Elts,D.Struct_NumElements));
|
||||
}
|
||||
|
||||
case IITDescriptor::Argument:
|
||||
return Tys[D.getArgumentNumber()];
|
||||
case IITDescriptor::ExtendArgument: {
|
||||
|
|
@ -850,15 +852,9 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
|
|||
Type *EltTy = VTy->getVectorElementType();
|
||||
return PointerType::getUnqual(EltTy);
|
||||
}
|
||||
case IITDescriptor::VecOfPtrsToElt: {
|
||||
Type *Ty = Tys[D.getArgumentNumber()];
|
||||
VectorType *VTy = dyn_cast<VectorType>(Ty);
|
||||
if (!VTy)
|
||||
llvm_unreachable("Expected an argument of Vector Type");
|
||||
Type *EltTy = VTy->getVectorElementType();
|
||||
return VectorType::get(PointerType::getUnqual(EltTy),
|
||||
VTy->getNumElements());
|
||||
}
|
||||
case IITDescriptor::VecOfAnyPtrsToElt:
|
||||
// Return the overloaded type (which determines the pointers address space)
|
||||
return Tys[D.getOverloadArgNumber()];
|
||||
}
|
||||
llvm_unreachable("unhandled");
|
||||
}
|
||||
|
|
@ -1054,11 +1050,22 @@ bool Intrinsic::matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor>
|
|||
return (!ThisArgType || !ReferenceType ||
|
||||
ThisArgType->getElementType() != ReferenceType->getElementType());
|
||||
}
|
||||
case IITDescriptor::VecOfPtrsToElt: {
|
||||
if (D.getArgumentNumber() >= ArgTys.size())
|
||||
case IITDescriptor::VecOfAnyPtrsToElt: {
|
||||
unsigned RefArgNumber = D.getRefArgNumber();
|
||||
|
||||
// This may only be used when referring to a previous argument.
|
||||
if (RefArgNumber >= ArgTys.size())
|
||||
return true;
|
||||
VectorType * ReferenceType =
|
||||
dyn_cast<VectorType> (ArgTys[D.getArgumentNumber()]);
|
||||
|
||||
// Record the overloaded type
|
||||
assert(D.getOverloadArgNumber() == ArgTys.size() &&
|
||||
"Table consistency error");
|
||||
ArgTys.push_back(Ty);
|
||||
|
||||
// Verify the overloaded type "matches" the Ref type.
|
||||
// i.e. Ty is a vector with the same width as Ref.
|
||||
// Composed of pointers to the same element type as Ref.
|
||||
VectorType *ReferenceType = dyn_cast<VectorType>(ArgTys[RefArgNumber]);
|
||||
VectorType *ThisArgVecTy = dyn_cast<VectorType>(Ty);
|
||||
if (!ThisArgVecTy || !ReferenceType ||
|
||||
(ReferenceType->getVectorNumElements() !=
|
||||
|
|
|
|||
|
|
@ -293,11 +293,13 @@ CallInst *IRBuilderBase::CreateMaskedGather(Value *Ptrs, unsigned Align,
|
|||
Mask = Constant::getAllOnesValue(VectorType::get(Type::getInt1Ty(Context),
|
||||
NumElts));
|
||||
|
||||
Type *OverloadedTypes[] = {DataTy, PtrsTy};
|
||||
Value * Ops[] = {Ptrs, getInt32(Align), Mask, UndefValue::get(DataTy)};
|
||||
|
||||
// We specify only one type when we create this intrinsic. Types of other
|
||||
// arguments are derived from this type.
|
||||
return CreateMaskedIntrinsic(Intrinsic::masked_gather, Ops, { DataTy }, Name);
|
||||
return CreateMaskedIntrinsic(Intrinsic::masked_gather, Ops, OverloadedTypes,
|
||||
Name);
|
||||
}
|
||||
|
||||
/// \brief Create a call to a Masked Scatter intrinsic.
|
||||
|
|
@ -323,11 +325,13 @@ CallInst *IRBuilderBase::CreateMaskedScatter(Value *Data, Value *Ptrs,
|
|||
if (!Mask)
|
||||
Mask = Constant::getAllOnesValue(VectorType::get(Type::getInt1Ty(Context),
|
||||
NumElts));
|
||||
|
||||
Type *OverloadedTypes[] = {DataTy, PtrsTy};
|
||||
Value * Ops[] = {Data, Ptrs, getInt32(Align), Mask};
|
||||
|
||||
// We specify only one type when we create this intrinsic. Types of other
|
||||
// arguments are derived from this type.
|
||||
return CreateMaskedIntrinsic(Intrinsic::masked_scatter, Ops, { DataTy });
|
||||
return CreateMaskedIntrinsic(Intrinsic::masked_scatter, Ops, OverloadedTypes);
|
||||
}
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
|
|
|
|||
|
|
@ -335,12 +335,12 @@ Value *CallInst::getReturnedArgOperand() const {
|
|||
unsigned Index;
|
||||
|
||||
if (Attrs.hasAttrSomewhere(Attribute::Returned, &Index) && Index)
|
||||
return getArgOperand(Index-1);
|
||||
return getArgOperand(Index - AttributeList::FirstArgIndex);
|
||||
if (const Function *F = getCalledFunction())
|
||||
if (F->getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) &&
|
||||
Index)
|
||||
return getArgOperand(Index-1);
|
||||
|
||||
return getArgOperand(Index - AttributeList::FirstArgIndex);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -356,6 +356,10 @@ void CallInst::addAttribute(unsigned i, Attribute Attr) {
|
|||
setAttributes(PAL);
|
||||
}
|
||||
|
||||
void CallInst::addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
addAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
void CallInst::removeAttribute(unsigned i, Attribute::AttrKind Kind) {
|
||||
AttributeList PAL = getAttributes();
|
||||
PAL = PAL.removeAttribute(getContext(), i, Kind);
|
||||
|
|
@ -368,6 +372,10 @@ void CallInst::removeAttribute(unsigned i, StringRef Kind) {
|
|||
setAttributes(PAL);
|
||||
}
|
||||
|
||||
void CallInst::removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
removeAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
void CallInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
|
||||
AttributeList PAL = getAttributes();
|
||||
PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);
|
||||
|
|
@ -501,8 +509,8 @@ static Instruction *createMalloc(Instruction *InsertBefore,
|
|||
MCall->setTailCall();
|
||||
if (Function *F = dyn_cast<Function>(MallocFunc)) {
|
||||
MCall->setCallingConv(F->getCallingConv());
|
||||
if (!F->doesNotAlias(AttributeList::ReturnIndex))
|
||||
F->setDoesNotAlias(AttributeList::ReturnIndex);
|
||||
if (!F->returnDoesNotAlias())
|
||||
F->setReturnDoesNotAlias();
|
||||
}
|
||||
assert(!MCall->getType()->isVoidTy() && "Malloc has void return type");
|
||||
|
||||
|
|
@ -695,12 +703,12 @@ Value *InvokeInst::getReturnedArgOperand() const {
|
|||
unsigned Index;
|
||||
|
||||
if (Attrs.hasAttrSomewhere(Attribute::Returned, &Index) && Index)
|
||||
return getArgOperand(Index-1);
|
||||
return getArgOperand(Index - AttributeList::FirstArgIndex);
|
||||
if (const Function *F = getCalledFunction())
|
||||
if (F->getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) &&
|
||||
Index)
|
||||
return getArgOperand(Index-1);
|
||||
|
||||
return getArgOperand(Index - AttributeList::FirstArgIndex);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -756,6 +764,10 @@ void InvokeInst::addAttribute(unsigned i, Attribute Attr) {
|
|||
setAttributes(PAL);
|
||||
}
|
||||
|
||||
void InvokeInst::addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
addAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
void InvokeInst::removeAttribute(unsigned i, Attribute::AttrKind Kind) {
|
||||
AttributeList PAL = getAttributes();
|
||||
PAL = PAL.removeAttribute(getContext(), i, Kind);
|
||||
|
|
@ -768,6 +780,10 @@ void InvokeInst::removeAttribute(unsigned i, StringRef Kind) {
|
|||
setAttributes(PAL);
|
||||
}
|
||||
|
||||
void InvokeInst::removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) {
|
||||
removeAttribute(ArgNo + AttributeList::FirstArgIndex, Kind);
|
||||
}
|
||||
|
||||
void InvokeInst::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
|
||||
AttributeList PAL = getAttributes();
|
||||
PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@ class Value;
|
|||
struct DenseMapAPIntKeyInfo {
|
||||
static inline APInt getEmptyKey() {
|
||||
APInt V(nullptr, 0);
|
||||
V.VAL = 0;
|
||||
V.U.VAL = 0;
|
||||
return V;
|
||||
}
|
||||
static inline APInt getTombstoneKey() {
|
||||
APInt V(nullptr, 0);
|
||||
V.VAL = 1;
|
||||
V.U.VAL = 1;
|
||||
return V;
|
||||
}
|
||||
static unsigned getHashValue(const APInt &Key) {
|
||||
|
|
|
|||
|
|
@ -286,6 +286,10 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T) {
|
|||
((CMModel == CodeModel::Large) ? dwarf::DW_EH_PE_sdata8
|
||||
: dwarf::DW_EH_PE_sdata4);
|
||||
break;
|
||||
case Triple::bpfel:
|
||||
case Triple::bpfeb:
|
||||
FDECFIEncoding = dwarf::DW_EH_PE_sdata8;
|
||||
break;
|
||||
default:
|
||||
FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -76,34 +76,31 @@ inline static unsigned getDigit(char cdigit, uint8_t radix) {
|
|||
|
||||
|
||||
void APInt::initSlowCase(uint64_t val, bool isSigned) {
|
||||
VAL = 0;
|
||||
pVal = getClearedMemory(getNumWords());
|
||||
pVal[0] = val;
|
||||
U.pVal = getClearedMemory(getNumWords());
|
||||
U.pVal[0] = val;
|
||||
if (isSigned && int64_t(val) < 0)
|
||||
for (unsigned i = 1; i < getNumWords(); ++i)
|
||||
pVal[i] = WORD_MAX;
|
||||
U.pVal[i] = WORD_MAX;
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
||||
void APInt::initSlowCase(const APInt& that) {
|
||||
VAL = 0;
|
||||
pVal = getMemory(getNumWords());
|
||||
memcpy(pVal, that.pVal, getNumWords() * APINT_WORD_SIZE);
|
||||
U.pVal = getMemory(getNumWords());
|
||||
memcpy(U.pVal, that.U.pVal, getNumWords() * APINT_WORD_SIZE);
|
||||
}
|
||||
|
||||
void APInt::initFromArray(ArrayRef<uint64_t> bigVal) {
|
||||
assert(BitWidth && "Bitwidth too small");
|
||||
assert(bigVal.data() && "Null pointer detected!");
|
||||
if (isSingleWord())
|
||||
VAL = bigVal[0];
|
||||
U.VAL = bigVal[0];
|
||||
else {
|
||||
// Get memory, cleared to 0
|
||||
VAL = 0;
|
||||
pVal = getClearedMemory(getNumWords());
|
||||
U.pVal = getClearedMemory(getNumWords());
|
||||
// Calculate the number of words to copy
|
||||
unsigned words = std::min<unsigned>(bigVal.size(), getNumWords());
|
||||
// Copy the words from bigVal to pVal
|
||||
memcpy(pVal, bigVal.data(), words * APINT_WORD_SIZE);
|
||||
memcpy(U.pVal, bigVal.data(), words * APINT_WORD_SIZE);
|
||||
}
|
||||
// Make sure unused high bits are cleared
|
||||
clearUnusedBits();
|
||||
|
|
@ -120,7 +117,7 @@ APInt::APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[])
|
|||
}
|
||||
|
||||
APInt::APInt(unsigned numbits, StringRef Str, uint8_t radix)
|
||||
: VAL(0), BitWidth(numbits) {
|
||||
: BitWidth(numbits) {
|
||||
assert(BitWidth && "Bitwidth too small");
|
||||
fromString(numbits, Str, radix);
|
||||
}
|
||||
|
|
@ -133,25 +130,24 @@ void APInt::AssignSlowCase(const APInt& RHS) {
|
|||
if (BitWidth == RHS.getBitWidth()) {
|
||||
// assume same bit-width single-word case is already handled
|
||||
assert(!isSingleWord());
|
||||
memcpy(pVal, RHS.pVal, getNumWords() * APINT_WORD_SIZE);
|
||||
memcpy(U.pVal, RHS.U.pVal, getNumWords() * APINT_WORD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSingleWord()) {
|
||||
// assume case where both are single words is already handled
|
||||
assert(!RHS.isSingleWord());
|
||||
VAL = 0;
|
||||
pVal = getMemory(RHS.getNumWords());
|
||||
memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE);
|
||||
U.pVal = getMemory(RHS.getNumWords());
|
||||
memcpy(U.pVal, RHS.U.pVal, RHS.getNumWords() * APINT_WORD_SIZE);
|
||||
} else if (getNumWords() == RHS.getNumWords())
|
||||
memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE);
|
||||
memcpy(U.pVal, RHS.U.pVal, RHS.getNumWords() * APINT_WORD_SIZE);
|
||||
else if (RHS.isSingleWord()) {
|
||||
delete [] pVal;
|
||||
VAL = RHS.VAL;
|
||||
delete [] U.pVal;
|
||||
U.VAL = RHS.U.VAL;
|
||||
} else {
|
||||
delete [] pVal;
|
||||
pVal = getMemory(RHS.getNumWords());
|
||||
memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE);
|
||||
delete [] U.pVal;
|
||||
U.pVal = getMemory(RHS.getNumWords());
|
||||
memcpy(U.pVal, RHS.U.pVal, RHS.getNumWords() * APINT_WORD_SIZE);
|
||||
}
|
||||
BitWidth = RHS.BitWidth;
|
||||
clearUnusedBits();
|
||||
|
|
@ -162,30 +158,30 @@ void APInt::Profile(FoldingSetNodeID& ID) const {
|
|||
ID.AddInteger(BitWidth);
|
||||
|
||||
if (isSingleWord()) {
|
||||
ID.AddInteger(VAL);
|
||||
ID.AddInteger(U.VAL);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned NumWords = getNumWords();
|
||||
for (unsigned i = 0; i < NumWords; ++i)
|
||||
ID.AddInteger(pVal[i]);
|
||||
ID.AddInteger(U.pVal[i]);
|
||||
}
|
||||
|
||||
/// @brief Prefix increment operator. Increments the APInt by one.
|
||||
APInt& APInt::operator++() {
|
||||
if (isSingleWord())
|
||||
++VAL;
|
||||
++U.VAL;
|
||||
else
|
||||
tcIncrement(pVal, getNumWords());
|
||||
tcIncrement(U.pVal, getNumWords());
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
/// @brief Prefix decrement operator. Decrements the APInt by one.
|
||||
APInt& APInt::operator--() {
|
||||
if (isSingleWord())
|
||||
--VAL;
|
||||
--U.VAL;
|
||||
else
|
||||
tcDecrement(pVal, getNumWords());
|
||||
tcDecrement(U.pVal, getNumWords());
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
|
|
@ -195,17 +191,17 @@ APInt& APInt::operator--() {
|
|||
APInt& APInt::operator+=(const APInt& RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
VAL += RHS.VAL;
|
||||
U.VAL += RHS.U.VAL;
|
||||
else
|
||||
tcAdd(pVal, RHS.pVal, 0, getNumWords());
|
||||
tcAdd(U.pVal, RHS.U.pVal, 0, getNumWords());
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
APInt& APInt::operator+=(uint64_t RHS) {
|
||||
if (isSingleWord())
|
||||
VAL += RHS;
|
||||
U.VAL += RHS;
|
||||
else
|
||||
tcAddPart(pVal, RHS, getNumWords());
|
||||
tcAddPart(U.pVal, RHS, getNumWords());
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
|
|
@ -215,17 +211,17 @@ APInt& APInt::operator+=(uint64_t RHS) {
|
|||
APInt& APInt::operator-=(const APInt& RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
VAL -= RHS.VAL;
|
||||
U.VAL -= RHS.U.VAL;
|
||||
else
|
||||
tcSubtract(pVal, RHS.pVal, 0, getNumWords());
|
||||
tcSubtract(U.pVal, RHS.U.pVal, 0, getNumWords());
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
APInt& APInt::operator-=(uint64_t RHS) {
|
||||
if (isSingleWord())
|
||||
VAL -= RHS;
|
||||
U.VAL -= RHS;
|
||||
else
|
||||
tcSubtractPart(pVal, RHS, getNumWords());
|
||||
tcSubtractPart(U.pVal, RHS, getNumWords());
|
||||
return clearUnusedBits();
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +296,7 @@ static void mul(uint64_t dest[], uint64_t x[], unsigned xlen, uint64_t y[],
|
|||
APInt& APInt::operator*=(const APInt& RHS) {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
VAL *= RHS.VAL;
|
||||
U.VAL *= RHS.U.VAL;
|
||||
clearUnusedBits();
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -326,12 +322,12 @@ APInt& APInt::operator*=(const APInt& RHS) {
|
|||
uint64_t *dest = getMemory(destWords);
|
||||
|
||||
// Perform the long multiply
|
||||
mul(dest, pVal, lhsWords, RHS.pVal, rhsWords);
|
||||
mul(dest, U.pVal, lhsWords, RHS.U.pVal, rhsWords);
|
||||
|
||||
// Copy result back into *this
|
||||
clearAllBits();
|
||||
unsigned wordsToCopy = destWords >= getNumWords() ? getNumWords() : destWords;
|
||||
memcpy(pVal, dest, wordsToCopy * APINT_WORD_SIZE);
|
||||
memcpy(U.pVal, dest, wordsToCopy * APINT_WORD_SIZE);
|
||||
clearUnusedBits();
|
||||
|
||||
// delete dest array and return
|
||||
|
|
@ -340,43 +336,43 @@ APInt& APInt::operator*=(const APInt& RHS) {
|
|||
}
|
||||
|
||||
void APInt::AndAssignSlowCase(const APInt& RHS) {
|
||||
tcAnd(pVal, RHS.pVal, getNumWords());
|
||||
tcAnd(U.pVal, RHS.U.pVal, getNumWords());
|
||||
}
|
||||
|
||||
void APInt::OrAssignSlowCase(const APInt& RHS) {
|
||||
tcOr(pVal, RHS.pVal, getNumWords());
|
||||
tcOr(U.pVal, RHS.U.pVal, getNumWords());
|
||||
}
|
||||
|
||||
void APInt::XorAssignSlowCase(const APInt& RHS) {
|
||||
tcXor(pVal, RHS.pVal, getNumWords());
|
||||
tcXor(U.pVal, RHS.U.pVal, getNumWords());
|
||||
}
|
||||
|
||||
APInt APInt::operator*(const APInt& RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord())
|
||||
return APInt(BitWidth, VAL * RHS.VAL);
|
||||
return APInt(BitWidth, U.VAL * RHS.U.VAL);
|
||||
APInt Result(*this);
|
||||
Result *= RHS;
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool APInt::EqualSlowCase(const APInt& RHS) const {
|
||||
return std::equal(pVal, pVal + getNumWords(), RHS.pVal);
|
||||
return std::equal(U.pVal, U.pVal + getNumWords(), RHS.U.pVal);
|
||||
}
|
||||
|
||||
int APInt::compare(const APInt& RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison");
|
||||
if (isSingleWord())
|
||||
return VAL < RHS.VAL ? -1 : VAL > RHS.VAL;
|
||||
return U.VAL < RHS.U.VAL ? -1 : U.VAL > RHS.U.VAL;
|
||||
|
||||
return tcCompare(pVal, RHS.pVal, getNumWords());
|
||||
return tcCompare(U.pVal, RHS.U.pVal, getNumWords());
|
||||
}
|
||||
|
||||
int APInt::compareSigned(const APInt& RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison");
|
||||
if (isSingleWord()) {
|
||||
int64_t lhsSext = SignExtend64(VAL, BitWidth);
|
||||
int64_t rhsSext = SignExtend64(RHS.VAL, BitWidth);
|
||||
int64_t lhsSext = SignExtend64(U.VAL, BitWidth);
|
||||
int64_t rhsSext = SignExtend64(RHS.U.VAL, BitWidth);
|
||||
return lhsSext < rhsSext ? -1 : lhsSext > rhsSext;
|
||||
}
|
||||
|
||||
|
|
@ -389,7 +385,7 @@ int APInt::compareSigned(const APInt& RHS) const {
|
|||
|
||||
// Otherwise we can just use an unsigned comparison, because even negative
|
||||
// numbers compare correctly this way if both have the same signed-ness.
|
||||
return tcCompare(pVal, RHS.pVal, getNumWords());
|
||||
return tcCompare(U.pVal, RHS.U.pVal, getNumWords());
|
||||
}
|
||||
|
||||
void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {
|
||||
|
|
@ -409,19 +405,19 @@ void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) {
|
|||
if (hiWord == loWord)
|
||||
loMask &= hiMask;
|
||||
else
|
||||
pVal[hiWord] |= hiMask;
|
||||
U.pVal[hiWord] |= hiMask;
|
||||
}
|
||||
// Apply the mask to the low word.
|
||||
pVal[loWord] |= loMask;
|
||||
U.pVal[loWord] |= loMask;
|
||||
|
||||
// Fill any words between loWord and hiWord with all ones.
|
||||
for (unsigned word = loWord + 1; word < hiWord; ++word)
|
||||
pVal[word] = WORD_MAX;
|
||||
U.pVal[word] = WORD_MAX;
|
||||
}
|
||||
|
||||
/// @brief Toggle every bit to its opposite value.
|
||||
void APInt::flipAllBitsSlowCase() {
|
||||
tcComplement(pVal, getNumWords());
|
||||
tcComplement(U.pVal, getNumWords());
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
||||
|
|
@ -448,8 +444,8 @@ void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
|
|||
// Single word result can be done as a direct bitmask.
|
||||
if (isSingleWord()) {
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - subBitWidth);
|
||||
VAL &= ~(mask << bitPosition);
|
||||
VAL |= (subBits.VAL << bitPosition);
|
||||
U.VAL &= ~(mask << bitPosition);
|
||||
U.VAL |= (subBits.U.VAL << bitPosition);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -460,8 +456,8 @@ void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
|
|||
// Insertion within a single word can be done as a direct bitmask.
|
||||
if (loWord == hi1Word) {
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - subBitWidth);
|
||||
pVal[loWord] &= ~(mask << loBit);
|
||||
pVal[loWord] |= (subBits.VAL << loBit);
|
||||
U.pVal[loWord] &= ~(mask << loBit);
|
||||
U.pVal[loWord] |= (subBits.U.VAL << loBit);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -469,15 +465,15 @@ void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
|
|||
if (loBit == 0) {
|
||||
// Direct copy whole words.
|
||||
unsigned numWholeSubWords = subBitWidth / APINT_BITS_PER_WORD;
|
||||
memcpy(pVal + loWord, subBits.getRawData(),
|
||||
memcpy(U.pVal + loWord, subBits.getRawData(),
|
||||
numWholeSubWords * APINT_WORD_SIZE);
|
||||
|
||||
// Mask+insert remaining bits.
|
||||
unsigned remainingBits = subBitWidth % APINT_BITS_PER_WORD;
|
||||
if (remainingBits != 0) {
|
||||
uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - remainingBits);
|
||||
pVal[hi1Word] &= ~mask;
|
||||
pVal[hi1Word] |= subBits.getWord(subBitWidth - 1);
|
||||
U.pVal[hi1Word] &= ~mask;
|
||||
U.pVal[hi1Word] |= subBits.getWord(subBitWidth - 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -499,7 +495,7 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
|
|||
"Illegal bit extraction");
|
||||
|
||||
if (isSingleWord())
|
||||
return APInt(numBits, VAL >> bitPosition);
|
||||
return APInt(numBits, U.VAL >> bitPosition);
|
||||
|
||||
unsigned loBit = whichBit(bitPosition);
|
||||
unsigned loWord = whichWord(bitPosition);
|
||||
|
|
@ -507,12 +503,12 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
|
|||
|
||||
// Single word result extracting bits from a single word source.
|
||||
if (loWord == hiWord)
|
||||
return APInt(numBits, pVal[loWord] >> loBit);
|
||||
return APInt(numBits, U.pVal[loWord] >> loBit);
|
||||
|
||||
// Extracting bits that start on a source word boundary can be done
|
||||
// as a fast memory copy.
|
||||
if (loBit == 0)
|
||||
return APInt(numBits, makeArrayRef(pVal + loWord, 1 + hiWord - loWord));
|
||||
return APInt(numBits, makeArrayRef(U.pVal + loWord, 1 + hiWord - loWord));
|
||||
|
||||
// General case - shift + copy source words directly into place.
|
||||
APInt Result(numBits, 0);
|
||||
|
|
@ -520,10 +516,10 @@ APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
|
|||
unsigned NumDstWords = Result.getNumWords();
|
||||
|
||||
for (unsigned word = 0; word < NumDstWords; ++word) {
|
||||
uint64_t w0 = pVal[loWord + word];
|
||||
uint64_t w0 = U.pVal[loWord + word];
|
||||
uint64_t w1 =
|
||||
(loWord + word + 1) < NumSrcWords ? pVal[loWord + word + 1] : 0;
|
||||
Result.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit));
|
||||
(loWord + word + 1) < NumSrcWords ? U.pVal[loWord + word + 1] : 0;
|
||||
Result.U.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit));
|
||||
}
|
||||
|
||||
return Result.clearUnusedBits();
|
||||
|
|
@ -584,9 +580,9 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) {
|
|||
|
||||
hash_code llvm::hash_value(const APInt &Arg) {
|
||||
if (Arg.isSingleWord())
|
||||
return hash_combine(Arg.VAL);
|
||||
return hash_combine(Arg.U.VAL);
|
||||
|
||||
return hash_combine_range(Arg.pVal, Arg.pVal + Arg.getNumWords());
|
||||
return hash_combine_range(Arg.U.pVal, Arg.U.pVal + Arg.getNumWords());
|
||||
}
|
||||
|
||||
bool APInt::isSplat(unsigned SplatSizeInBits) const {
|
||||
|
|
@ -623,7 +619,7 @@ APInt APInt::getSplat(unsigned NewLen, const APInt &V) {
|
|||
unsigned APInt::countLeadingZerosSlowCase() const {
|
||||
unsigned Count = 0;
|
||||
for (int i = getNumWords()-1; i >= 0; --i) {
|
||||
uint64_t V = pVal[i];
|
||||
uint64_t V = U.pVal[i];
|
||||
if (V == 0)
|
||||
Count += APINT_BITS_PER_WORD;
|
||||
else {
|
||||
|
|
@ -639,7 +635,7 @@ unsigned APInt::countLeadingZerosSlowCase() const {
|
|||
|
||||
unsigned APInt::countLeadingOnes() const {
|
||||
if (isSingleWord())
|
||||
return llvm::countLeadingOnes(VAL << (APINT_BITS_PER_WORD - BitWidth));
|
||||
return llvm::countLeadingOnes(U.VAL << (APINT_BITS_PER_WORD - BitWidth));
|
||||
|
||||
unsigned highWordBits = BitWidth % APINT_BITS_PER_WORD;
|
||||
unsigned shift;
|
||||
|
|
@ -650,13 +646,13 @@ unsigned APInt::countLeadingOnes() const {
|
|||
shift = APINT_BITS_PER_WORD - highWordBits;
|
||||
}
|
||||
int i = getNumWords() - 1;
|
||||
unsigned Count = llvm::countLeadingOnes(pVal[i] << shift);
|
||||
unsigned Count = llvm::countLeadingOnes(U.pVal[i] << shift);
|
||||
if (Count == highWordBits) {
|
||||
for (i--; i >= 0; --i) {
|
||||
if (pVal[i] == WORD_MAX)
|
||||
if (U.pVal[i] == WORD_MAX)
|
||||
Count += APINT_BITS_PER_WORD;
|
||||
else {
|
||||
Count += llvm::countLeadingOnes(pVal[i]);
|
||||
Count += llvm::countLeadingOnes(U.pVal[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -666,23 +662,23 @@ unsigned APInt::countLeadingOnes() const {
|
|||
|
||||
unsigned APInt::countTrailingZeros() const {
|
||||
if (isSingleWord())
|
||||
return std::min(unsigned(llvm::countTrailingZeros(VAL)), BitWidth);
|
||||
return std::min(unsigned(llvm::countTrailingZeros(U.VAL)), BitWidth);
|
||||
unsigned Count = 0;
|
||||
unsigned i = 0;
|
||||
for (; i < getNumWords() && pVal[i] == 0; ++i)
|
||||
for (; i < getNumWords() && U.pVal[i] == 0; ++i)
|
||||
Count += APINT_BITS_PER_WORD;
|
||||
if (i < getNumWords())
|
||||
Count += llvm::countTrailingZeros(pVal[i]);
|
||||
Count += llvm::countTrailingZeros(U.pVal[i]);
|
||||
return std::min(Count, BitWidth);
|
||||
}
|
||||
|
||||
unsigned APInt::countTrailingOnesSlowCase() const {
|
||||
unsigned Count = 0;
|
||||
unsigned i = 0;
|
||||
for (; i < getNumWords() && pVal[i] == WORD_MAX; ++i)
|
||||
for (; i < getNumWords() && U.pVal[i] == WORD_MAX; ++i)
|
||||
Count += APINT_BITS_PER_WORD;
|
||||
if (i < getNumWords())
|
||||
Count += llvm::countTrailingOnes(pVal[i]);
|
||||
Count += llvm::countTrailingOnes(U.pVal[i]);
|
||||
assert(Count <= BitWidth);
|
||||
return Count;
|
||||
}
|
||||
|
|
@ -690,13 +686,13 @@ unsigned APInt::countTrailingOnesSlowCase() const {
|
|||
unsigned APInt::countPopulationSlowCase() const {
|
||||
unsigned Count = 0;
|
||||
for (unsigned i = 0; i < getNumWords(); ++i)
|
||||
Count += llvm::countPopulation(pVal[i]);
|
||||
Count += llvm::countPopulation(U.pVal[i]);
|
||||
return Count;
|
||||
}
|
||||
|
||||
bool APInt::intersectsSlowCase(const APInt &RHS) const {
|
||||
for (unsigned i = 0, e = getNumWords(); i != e; ++i)
|
||||
if ((pVal[i] & RHS.pVal[i]) != 0)
|
||||
if ((U.pVal[i] & RHS.U.pVal[i]) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -704,7 +700,7 @@ bool APInt::intersectsSlowCase(const APInt &RHS) const {
|
|||
|
||||
bool APInt::isSubsetOfSlowCase(const APInt &RHS) const {
|
||||
for (unsigned i = 0, e = getNumWords(); i != e; ++i)
|
||||
if ((pVal[i] & ~RHS.pVal[i]) != 0)
|
||||
if ((U.pVal[i] & ~RHS.U.pVal[i]) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -713,22 +709,22 @@ bool APInt::isSubsetOfSlowCase(const APInt &RHS) const {
|
|||
APInt APInt::byteSwap() const {
|
||||
assert(BitWidth >= 16 && BitWidth % 16 == 0 && "Cannot byteswap!");
|
||||
if (BitWidth == 16)
|
||||
return APInt(BitWidth, ByteSwap_16(uint16_t(VAL)));
|
||||
return APInt(BitWidth, ByteSwap_16(uint16_t(U.VAL)));
|
||||
if (BitWidth == 32)
|
||||
return APInt(BitWidth, ByteSwap_32(unsigned(VAL)));
|
||||
return APInt(BitWidth, ByteSwap_32(unsigned(U.VAL)));
|
||||
if (BitWidth == 48) {
|
||||
unsigned Tmp1 = unsigned(VAL >> 16);
|
||||
unsigned Tmp1 = unsigned(U.VAL >> 16);
|
||||
Tmp1 = ByteSwap_32(Tmp1);
|
||||
uint16_t Tmp2 = uint16_t(VAL);
|
||||
uint16_t Tmp2 = uint16_t(U.VAL);
|
||||
Tmp2 = ByteSwap_16(Tmp2);
|
||||
return APInt(BitWidth, (uint64_t(Tmp2) << 32) | Tmp1);
|
||||
}
|
||||
if (BitWidth == 64)
|
||||
return APInt(BitWidth, ByteSwap_64(VAL));
|
||||
return APInt(BitWidth, ByteSwap_64(U.VAL));
|
||||
|
||||
APInt Result(getNumWords() * APINT_BITS_PER_WORD, 0);
|
||||
for (unsigned I = 0, N = getNumWords(); I != N; ++I)
|
||||
Result.pVal[I] = ByteSwap_64(pVal[N - I - 1]);
|
||||
Result.U.pVal[I] = ByteSwap_64(U.pVal[N - I - 1]);
|
||||
if (Result.BitWidth != BitWidth) {
|
||||
Result.lshrInPlace(Result.BitWidth - BitWidth);
|
||||
Result.BitWidth = BitWidth;
|
||||
|
|
@ -739,13 +735,13 @@ APInt APInt::byteSwap() const {
|
|||
APInt APInt::reverseBits() const {
|
||||
switch (BitWidth) {
|
||||
case 64:
|
||||
return APInt(BitWidth, llvm::reverseBits<uint64_t>(VAL));
|
||||
return APInt(BitWidth, llvm::reverseBits<uint64_t>(U.VAL));
|
||||
case 32:
|
||||
return APInt(BitWidth, llvm::reverseBits<uint32_t>(VAL));
|
||||
return APInt(BitWidth, llvm::reverseBits<uint32_t>(U.VAL));
|
||||
case 16:
|
||||
return APInt(BitWidth, llvm::reverseBits<uint16_t>(VAL));
|
||||
return APInt(BitWidth, llvm::reverseBits<uint16_t>(U.VAL));
|
||||
case 8:
|
||||
return APInt(BitWidth, llvm::reverseBits<uint8_t>(VAL));
|
||||
return APInt(BitWidth, llvm::reverseBits<uint8_t>(U.VAL));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -890,13 +886,13 @@ double APInt::roundToDouble(bool isSigned) const {
|
|||
uint64_t mantissa;
|
||||
unsigned hiWord = whichWord(n-1);
|
||||
if (hiWord == 0) {
|
||||
mantissa = Tmp.pVal[0];
|
||||
mantissa = Tmp.U.pVal[0];
|
||||
if (n > 52)
|
||||
mantissa >>= n - 52; // shift down, we want the top 52 bits.
|
||||
} else {
|
||||
assert(hiWord > 0 && "huh?");
|
||||
uint64_t hibits = Tmp.pVal[hiWord] << (52 - n % APINT_BITS_PER_WORD);
|
||||
uint64_t lobits = Tmp.pVal[hiWord-1] >> (11 + n % APINT_BITS_PER_WORD);
|
||||
uint64_t hibits = Tmp.U.pVal[hiWord] << (52 - n % APINT_BITS_PER_WORD);
|
||||
uint64_t lobits = Tmp.U.pVal[hiWord-1] >> (11 + n % APINT_BITS_PER_WORD);
|
||||
mantissa = hibits | lobits;
|
||||
}
|
||||
|
||||
|
|
@ -923,12 +919,12 @@ APInt APInt::trunc(unsigned width) const {
|
|||
// Copy full words.
|
||||
unsigned i;
|
||||
for (i = 0; i != width / APINT_BITS_PER_WORD; i++)
|
||||
Result.pVal[i] = pVal[i];
|
||||
Result.U.pVal[i] = U.pVal[i];
|
||||
|
||||
// Truncate and copy any partial word.
|
||||
unsigned bits = (0 - width) % APINT_BITS_PER_WORD;
|
||||
if (bits != 0)
|
||||
Result.pVal[i] = pVal[i] << bits >> bits;
|
||||
Result.U.pVal[i] = U.pVal[i] << bits >> bits;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
|
@ -938,20 +934,20 @@ APInt APInt::sext(unsigned Width) const {
|
|||
assert(Width > BitWidth && "Invalid APInt SignExtend request");
|
||||
|
||||
if (Width <= APINT_BITS_PER_WORD)
|
||||
return APInt(Width, SignExtend64(VAL, BitWidth));
|
||||
return APInt(Width, SignExtend64(U.VAL, BitWidth));
|
||||
|
||||
APInt Result(getMemory(getNumWords(Width)), Width);
|
||||
|
||||
// Copy words.
|
||||
std::memcpy(Result.pVal, getRawData(), getNumWords() * APINT_WORD_SIZE);
|
||||
std::memcpy(Result.U.pVal, getRawData(), getNumWords() * APINT_WORD_SIZE);
|
||||
|
||||
// Sign extend the last word since there may be unused bits in the input.
|
||||
Result.pVal[getNumWords() - 1] =
|
||||
SignExtend64(Result.pVal[getNumWords() - 1],
|
||||
Result.U.pVal[getNumWords() - 1] =
|
||||
SignExtend64(Result.U.pVal[getNumWords() - 1],
|
||||
((BitWidth - 1) % APINT_BITS_PER_WORD) + 1);
|
||||
|
||||
// Fill with sign bits.
|
||||
std::memset(Result.pVal + getNumWords(), isNegative() ? -1 : 0,
|
||||
std::memset(Result.U.pVal + getNumWords(), isNegative() ? -1 : 0,
|
||||
(Result.getNumWords() - getNumWords()) * APINT_WORD_SIZE);
|
||||
Result.clearUnusedBits();
|
||||
return Result;
|
||||
|
|
@ -962,15 +958,15 @@ APInt APInt::zext(unsigned width) const {
|
|||
assert(width > BitWidth && "Invalid APInt ZeroExtend request");
|
||||
|
||||
if (width <= APINT_BITS_PER_WORD)
|
||||
return APInt(width, VAL);
|
||||
return APInt(width, U.VAL);
|
||||
|
||||
APInt Result(getMemory(getNumWords(width)), width);
|
||||
|
||||
// Copy words.
|
||||
std::memcpy(Result.pVal, getRawData(), getNumWords() * APINT_WORD_SIZE);
|
||||
std::memcpy(Result.U.pVal, getRawData(), getNumWords() * APINT_WORD_SIZE);
|
||||
|
||||
// Zero remaining words.
|
||||
std::memset(Result.pVal + getNumWords(), 0,
|
||||
std::memset(Result.U.pVal + getNumWords(), 0,
|
||||
(Result.getNumWords() - getNumWords()) * APINT_WORD_SIZE);
|
||||
|
||||
return Result;
|
||||
|
|
@ -1027,28 +1023,28 @@ void APInt::ashrSlowCase(unsigned ShiftAmt) {
|
|||
unsigned WordsToMove = getNumWords() - WordShift;
|
||||
if (WordsToMove != 0) {
|
||||
// Sign extend the last word to fill in the unused bits.
|
||||
pVal[getNumWords() - 1] = SignExtend64(
|
||||
pVal[getNumWords() - 1], ((BitWidth - 1) % APINT_BITS_PER_WORD) + 1);
|
||||
U.pVal[getNumWords() - 1] = SignExtend64(
|
||||
U.pVal[getNumWords() - 1], ((BitWidth - 1) % APINT_BITS_PER_WORD) + 1);
|
||||
|
||||
// Fastpath for moving by whole words.
|
||||
if (BitShift == 0) {
|
||||
std::memmove(pVal, pVal + WordShift, WordsToMove * APINT_WORD_SIZE);
|
||||
std::memmove(U.pVal, U.pVal + WordShift, WordsToMove * APINT_WORD_SIZE);
|
||||
} else {
|
||||
// Move the words containing significant bits.
|
||||
for (unsigned i = 0; i != WordsToMove - 1; ++i)
|
||||
pVal[i] = (pVal[i + WordShift] >> BitShift) |
|
||||
(pVal[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift));
|
||||
U.pVal[i] = (U.pVal[i + WordShift] >> BitShift) |
|
||||
(U.pVal[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift));
|
||||
|
||||
// Handle the last word which has no high bits to copy.
|
||||
pVal[WordsToMove - 1] = pVal[WordShift + WordsToMove - 1] >> BitShift;
|
||||
U.pVal[WordsToMove - 1] = U.pVal[WordShift + WordsToMove - 1] >> BitShift;
|
||||
// Sign extend one more time.
|
||||
pVal[WordsToMove - 1] =
|
||||
SignExtend64(pVal[WordsToMove - 1], APINT_BITS_PER_WORD - BitShift);
|
||||
U.pVal[WordsToMove - 1] =
|
||||
SignExtend64(U.pVal[WordsToMove - 1], APINT_BITS_PER_WORD - BitShift);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the remainder based on the original sign.
|
||||
std::memset(pVal + WordsToMove, Negative ? -1 : 0,
|
||||
std::memset(U.pVal + WordsToMove, Negative ? -1 : 0,
|
||||
WordShift * APINT_WORD_SIZE);
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
|
@ -1062,7 +1058,7 @@ void APInt::lshrInPlace(const APInt &shiftAmt) {
|
|||
/// Logical right-shift this APInt by shiftAmt.
|
||||
/// @brief Logical right-shift function.
|
||||
void APInt::lshrSlowCase(unsigned ShiftAmt) {
|
||||
tcShiftRight(pVal, getNumWords(), ShiftAmt);
|
||||
tcShiftRight(U.pVal, getNumWords(), ShiftAmt);
|
||||
}
|
||||
|
||||
/// Left-shift this APInt by shiftAmt.
|
||||
|
|
@ -1074,7 +1070,7 @@ APInt &APInt::operator<<=(const APInt &shiftAmt) {
|
|||
}
|
||||
|
||||
void APInt::shlSlowCase(unsigned ShiftAmt) {
|
||||
tcShiftLeft(pVal, getNumWords(), ShiftAmt);
|
||||
tcShiftLeft(U.pVal, getNumWords(), ShiftAmt);
|
||||
clearUnusedBits();
|
||||
}
|
||||
|
||||
|
|
@ -1137,7 +1133,7 @@ APInt APInt::sqrt() const {
|
|||
/* 21-30 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
/* 31 */ 6
|
||||
};
|
||||
return APInt(BitWidth, results[ (isSingleWord() ? VAL : pVal[0]) ]);
|
||||
return APInt(BitWidth, results[ (isSingleWord() ? U.VAL : U.pVal[0]) ]);
|
||||
}
|
||||
|
||||
// If the magnitude of the value fits in less than 52 bits (the precision of
|
||||
|
|
@ -1146,7 +1142,8 @@ APInt APInt::sqrt() const {
|
|||
// This should be faster than the algorithm below.
|
||||
if (magnitude < 52) {
|
||||
return APInt(BitWidth,
|
||||
uint64_t(::round(::sqrt(double(isSingleWord()?VAL:pVal[0])))));
|
||||
uint64_t(::round(::sqrt(double(isSingleWord() ? U.VAL
|
||||
: U.pVal[0])))));
|
||||
}
|
||||
|
||||
// Okay, all the short cuts are exhausted. We must compute it. The following
|
||||
|
|
@ -1524,7 +1521,7 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
|||
// Initialize the dividend
|
||||
memset(U, 0, (m+n+1)*sizeof(unsigned));
|
||||
for (unsigned i = 0; i < lhsWords; ++i) {
|
||||
uint64_t tmp = (LHS.getNumWords() == 1 ? LHS.VAL : LHS.pVal[i]);
|
||||
uint64_t tmp = (LHS.getNumWords() == 1 ? LHS.U.VAL : LHS.U.pVal[i]);
|
||||
U[i * 2] = (unsigned)(tmp & mask);
|
||||
U[i * 2 + 1] = (unsigned)(tmp >> (sizeof(unsigned)*CHAR_BIT));
|
||||
}
|
||||
|
|
@ -1533,7 +1530,7 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
|||
// Initialize the divisor
|
||||
memset(V, 0, (n)*sizeof(unsigned));
|
||||
for (unsigned i = 0; i < rhsWords; ++i) {
|
||||
uint64_t tmp = (RHS.getNumWords() == 1 ? RHS.VAL : RHS.pVal[i]);
|
||||
uint64_t tmp = (RHS.getNumWords() == 1 ? RHS.U.VAL : RHS.U.pVal[i]);
|
||||
V[i * 2] = (unsigned)(tmp & mask);
|
||||
V[i * 2 + 1] = (unsigned)(tmp >> (sizeof(unsigned)*CHAR_BIT));
|
||||
}
|
||||
|
|
@ -1593,12 +1590,12 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
|||
// Set up the Quotient value's memory.
|
||||
if (Quotient->BitWidth != LHS.BitWidth) {
|
||||
if (Quotient->isSingleWord())
|
||||
Quotient->VAL = 0;
|
||||
Quotient->U.VAL = 0;
|
||||
else
|
||||
delete [] Quotient->pVal;
|
||||
delete [] Quotient->U.pVal;
|
||||
Quotient->BitWidth = LHS.BitWidth;
|
||||
if (!Quotient->isSingleWord())
|
||||
Quotient->pVal = getClearedMemory(Quotient->getNumWords());
|
||||
Quotient->U.pVal = getClearedMemory(Quotient->getNumWords());
|
||||
} else
|
||||
Quotient->clearAllBits();
|
||||
|
||||
|
|
@ -1610,13 +1607,13 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
|||
uint64_t tmp =
|
||||
uint64_t(Q[0]) | (uint64_t(Q[1]) << (APINT_BITS_PER_WORD / 2));
|
||||
if (Quotient->isSingleWord())
|
||||
Quotient->VAL = tmp;
|
||||
Quotient->U.VAL = tmp;
|
||||
else
|
||||
Quotient->pVal[0] = tmp;
|
||||
Quotient->U.pVal[0] = tmp;
|
||||
} else {
|
||||
assert(!Quotient->isSingleWord() && "Quotient APInt not large enough");
|
||||
for (unsigned i = 0; i < lhsWords; ++i)
|
||||
Quotient->pVal[i] =
|
||||
Quotient->U.pVal[i] =
|
||||
uint64_t(Q[i*2]) | (uint64_t(Q[i*2+1]) << (APINT_BITS_PER_WORD / 2));
|
||||
}
|
||||
}
|
||||
|
|
@ -1626,12 +1623,12 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
|||
// Set up the Remainder value's memory.
|
||||
if (Remainder->BitWidth != RHS.BitWidth) {
|
||||
if (Remainder->isSingleWord())
|
||||
Remainder->VAL = 0;
|
||||
Remainder->U.VAL = 0;
|
||||
else
|
||||
delete [] Remainder->pVal;
|
||||
delete [] Remainder->U.pVal;
|
||||
Remainder->BitWidth = RHS.BitWidth;
|
||||
if (!Remainder->isSingleWord())
|
||||
Remainder->pVal = getClearedMemory(Remainder->getNumWords());
|
||||
Remainder->U.pVal = getClearedMemory(Remainder->getNumWords());
|
||||
} else
|
||||
Remainder->clearAllBits();
|
||||
|
||||
|
|
@ -1641,13 +1638,13 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS,
|
|||
uint64_t tmp =
|
||||
uint64_t(R[0]) | (uint64_t(R[1]) << (APINT_BITS_PER_WORD / 2));
|
||||
if (Remainder->isSingleWord())
|
||||
Remainder->VAL = tmp;
|
||||
Remainder->U.VAL = tmp;
|
||||
else
|
||||
Remainder->pVal[0] = tmp;
|
||||
Remainder->U.pVal[0] = tmp;
|
||||
} else {
|
||||
assert(!Remainder->isSingleWord() && "Remainder APInt not large enough");
|
||||
for (unsigned i = 0; i < rhsWords; ++i)
|
||||
Remainder->pVal[i] =
|
||||
Remainder->U.pVal[i] =
|
||||
uint64_t(R[i*2]) | (uint64_t(R[i*2+1]) << (APINT_BITS_PER_WORD / 2));
|
||||
}
|
||||
}
|
||||
|
|
@ -1666,8 +1663,8 @@ APInt APInt::udiv(const APInt& RHS) const {
|
|||
|
||||
// First, deal with the easy case
|
||||
if (isSingleWord()) {
|
||||
assert(RHS.VAL != 0 && "Divide by zero?");
|
||||
return APInt(BitWidth, VAL / RHS.VAL);
|
||||
assert(RHS.U.VAL != 0 && "Divide by zero?");
|
||||
return APInt(BitWidth, U.VAL / RHS.U.VAL);
|
||||
}
|
||||
|
||||
// Get some facts about the LHS and RHS number of bits and words
|
||||
|
|
@ -1689,7 +1686,7 @@ APInt APInt::udiv(const APInt& RHS) const {
|
|||
return APInt(BitWidth, 1);
|
||||
} else if (lhsWords == 1 && rhsWords == 1) {
|
||||
// All high words are zero, just use native divide
|
||||
return APInt(BitWidth, this->pVal[0] / RHS.pVal[0]);
|
||||
return APInt(BitWidth, this->U.pVal[0] / RHS.U.pVal[0]);
|
||||
}
|
||||
|
||||
// We have to compute it the hard way. Invoke the Knuth divide algorithm.
|
||||
|
|
@ -1712,8 +1709,8 @@ APInt APInt::sdiv(const APInt &RHS) const {
|
|||
APInt APInt::urem(const APInt& RHS) const {
|
||||
assert(BitWidth == RHS.BitWidth && "Bit widths must be the same");
|
||||
if (isSingleWord()) {
|
||||
assert(RHS.VAL != 0 && "Remainder by zero?");
|
||||
return APInt(BitWidth, VAL % RHS.VAL);
|
||||
assert(RHS.U.VAL != 0 && "Remainder by zero?");
|
||||
return APInt(BitWidth, U.VAL % RHS.U.VAL);
|
||||
}
|
||||
|
||||
// Get some facts about the LHS
|
||||
|
|
@ -1737,7 +1734,7 @@ APInt APInt::urem(const APInt& RHS) const {
|
|||
return APInt(BitWidth, 0);
|
||||
} else if (lhsWords == 1) {
|
||||
// All high words are zero, just use native remainder
|
||||
return APInt(BitWidth, pVal[0] % RHS.pVal[0]);
|
||||
return APInt(BitWidth, U.pVal[0] % RHS.U.pVal[0]);
|
||||
}
|
||||
|
||||
// We have to compute it the hard way. Invoke the Knuth divide algorithm.
|
||||
|
|
@ -1763,9 +1760,9 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS,
|
|||
|
||||
// First, deal with the easy case
|
||||
if (LHS.isSingleWord()) {
|
||||
assert(RHS.VAL != 0 && "Divide by zero?");
|
||||
uint64_t QuotVal = LHS.VAL / RHS.VAL;
|
||||
uint64_t RemVal = LHS.VAL % RHS.VAL;
|
||||
assert(RHS.U.VAL != 0 && "Divide by zero?");
|
||||
uint64_t QuotVal = LHS.U.VAL / RHS.U.VAL;
|
||||
uint64_t RemVal = LHS.U.VAL % RHS.U.VAL;
|
||||
Quotient = APInt(LHS.BitWidth, QuotVal);
|
||||
Remainder = APInt(LHS.BitWidth, RemVal);
|
||||
return;
|
||||
|
|
@ -1798,8 +1795,8 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS,
|
|||
|
||||
if (lhsWords == 1 && rhsWords == 1) {
|
||||
// There is only one word to consider so use the native versions.
|
||||
uint64_t lhsValue = LHS.isSingleWord() ? LHS.VAL : LHS.pVal[0];
|
||||
uint64_t rhsValue = RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0];
|
||||
uint64_t lhsValue = LHS.isSingleWord() ? LHS.U.VAL : LHS.U.pVal[0];
|
||||
uint64_t rhsValue = RHS.isSingleWord() ? RHS.U.VAL : RHS.U.pVal[0];
|
||||
Quotient = APInt(LHS.getBitWidth(), lhsValue / rhsValue);
|
||||
Remainder = APInt(LHS.getBitWidth(), lhsValue % rhsValue);
|
||||
return;
|
||||
|
|
@ -1926,9 +1923,11 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) {
|
|||
assert((((slen-1)*64)/22 <= numbits || radix != 10) &&
|
||||
"Insufficient bit width");
|
||||
|
||||
// Allocate memory
|
||||
if (!isSingleWord())
|
||||
pVal = getClearedMemory(getNumWords());
|
||||
// Allocate memory if needed
|
||||
if (isSingleWord())
|
||||
U.VAL = 0;
|
||||
else
|
||||
U.pVal = getClearedMemory(getNumWords());
|
||||
|
||||
// Figure out if we can shift instead of multiply
|
||||
unsigned shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0);
|
||||
|
|
|
|||
|
|
@ -93,3 +93,16 @@ uint8_t BinaryStreamReader::peek() const {
|
|||
llvm::consumeError(std::move(EC));
|
||||
return Buffer[0];
|
||||
}
|
||||
|
||||
std::pair<BinaryStreamReader, BinaryStreamReader>
|
||||
BinaryStreamReader::split(uint32_t Off) const {
|
||||
assert(getLength() >= Off);
|
||||
|
||||
BinaryStreamRef First = Stream.drop_front(Offset);
|
||||
|
||||
BinaryStreamRef Second = First.drop_front(Off);
|
||||
First = First.keep_front(Off);
|
||||
BinaryStreamReader W1{First};
|
||||
BinaryStreamReader W2{Second};
|
||||
return std::make_pair(W1, W2);
|
||||
}
|
||||
|
|
@ -59,6 +59,19 @@ Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
std::pair<BinaryStreamWriter, BinaryStreamWriter>
|
||||
BinaryStreamWriter::split(uint32_t Off) const {
|
||||
assert(getLength() >= Off);
|
||||
|
||||
WritableBinaryStreamRef First = Stream.drop_front(Offset);
|
||||
|
||||
WritableBinaryStreamRef Second = First.drop_front(Off);
|
||||
First = First.keep_front(Off);
|
||||
BinaryStreamWriter W1{First};
|
||||
BinaryStreamWriter W2{Second};
|
||||
return std::make_pair(W1, W2);
|
||||
}
|
||||
|
||||
Error BinaryStreamWriter::padToAlignment(uint32_t Align) {
|
||||
uint32_t NewOffset = alignTo(Offset, Align);
|
||||
if (NewOffset > getLength())
|
||||
|
|
|
|||
|
|
@ -128,6 +128,16 @@ const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const {
|
||||
uint32_t Start = *OffsetPtr;
|
||||
StringRef::size_type Pos = Data.find('\0', Start);
|
||||
if (Pos != StringRef::npos) {
|
||||
*OffsetPtr = Pos + 1;
|
||||
return StringRef(Data.data() + Start, Pos - Start);
|
||||
}
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const {
|
||||
uint64_t result = 0;
|
||||
if (Data.empty())
|
||||
|
|
|
|||
|
|
@ -1363,6 +1363,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
|
|||
Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1);
|
||||
Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1);
|
||||
Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave;
|
||||
Features["lwp"] = HasExtLeaf1 && ((ECX >> 15) & 1);
|
||||
Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave;
|
||||
Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1);
|
||||
Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1);
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ static Triple::OSType parseOS(StringRef OSName) {
|
|||
.StartsWith("kfreebsd", Triple::KFreeBSD)
|
||||
.StartsWith("linux", Triple::Linux)
|
||||
.StartsWith("lv2", Triple::Lv2)
|
||||
.StartsWith("macosx", Triple::MacOSX)
|
||||
.StartsWith("macos", Triple::MacOSX)
|
||||
.StartsWith("netbsd", Triple::NetBSD)
|
||||
.StartsWith("openbsd", Triple::OpenBSD)
|
||||
.StartsWith("solaris", Triple::Solaris)
|
||||
|
|
@ -984,6 +984,8 @@ void Triple::getOSVersion(unsigned &Major, unsigned &Minor,
|
|||
StringRef OSTypeName = getOSTypeName(getOS());
|
||||
if (OSName.startswith(OSTypeName))
|
||||
OSName = OSName.substr(OSTypeName.size());
|
||||
else if (getOS() == MacOSX)
|
||||
OSName.consume_front("macos");
|
||||
|
||||
parseVersionFromName(OSName, Major, Minor, Micro);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ bool AArch64CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
|
|||
unsigned i = 0;
|
||||
for (auto &Arg : F.args()) {
|
||||
ArgInfo OrigArg{VRegs[i], Arg.getType()};
|
||||
setArgFlags(OrigArg, i + 1, DL, F);
|
||||
setArgFlags(OrigArg, i + AttributeList::FirstArgIndex, DL, F);
|
||||
bool Split = false;
|
||||
LLT Ty = MRI.getType(VRegs[i]);
|
||||
unsigned Dst = VRegs[i];
|
||||
|
|
|
|||
|
|
@ -677,12 +677,19 @@ void AMDGPUPromoteAlloca::handleAlloca(AllocaInst &I) {
|
|||
}
|
||||
|
||||
const Function &ContainingFunction = *I.getParent()->getParent();
|
||||
CallingConv::ID CC = ContainingFunction.getCallingConv();
|
||||
|
||||
// Don't promote the alloca to LDS for shader calling conventions as the work
|
||||
// item ID intrinsics are not supported for these calling conventions.
|
||||
// Furthermore not all LDS is available for some of the stages.
|
||||
if (AMDGPU::isShader(ContainingFunction.getCallingConv()))
|
||||
switch (CC) {
|
||||
case CallingConv::AMDGPU_KERNEL:
|
||||
case CallingConv::SPIR_KERNEL:
|
||||
break;
|
||||
default:
|
||||
DEBUG(dbgs() << " promote alloca to LDS not supported with calling convention.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const AMDGPUSubtarget &ST =
|
||||
TM->getSubtarget<AMDGPUSubtarget>(ContainingFunction);
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ def : Processor<"cortex-m0plus", ARMV6Itineraries, [ARMv6m]>;
|
|||
def : Processor<"cortex-m1", ARMV6Itineraries, [ARMv6m]>;
|
||||
def : Processor<"sc000", ARMV6Itineraries, [ARMv6m]>;
|
||||
|
||||
def : Processor<"arm1176j-s", ARMV6Itineraries, [ARMv6kz]>;
|
||||
def : Processor<"arm1176jz-s", ARMV6Itineraries, [ARMv6kz]>;
|
||||
def : Processor<"arm1176jzf-s", ARMV6Itineraries, [ARMv6kz,
|
||||
FeatureVFP2,
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
|
|||
unsigned Idx = 0;
|
||||
for (auto &Arg : F.args()) {
|
||||
ArgInfo AInfo(VRegs[Idx], Arg.getType());
|
||||
setArgFlags(AInfo, Idx + 1, DL, F);
|
||||
setArgFlags(AInfo, Idx + AttributeList::FirstArgIndex, DL, F);
|
||||
splitToValueTypes(AInfo, ArgInfos, DL, MF.getRegInfo());
|
||||
Idx++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -740,7 +740,9 @@ bool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset,
|
|||
unsigned PowerOfTwo = 0;
|
||||
SDValue NewMulConst;
|
||||
if (canExtractShiftFromMul(Offset, 31, PowerOfTwo, NewMulConst)) {
|
||||
HandleSDNode Handle(Offset);
|
||||
replaceDAGValue(Offset.getOperand(1), NewMulConst);
|
||||
Offset = Handle.getValue();
|
||||
ShAmt = PowerOfTwo;
|
||||
ShOpcVal = ARM_AM::lsl;
|
||||
}
|
||||
|
|
@ -1420,7 +1422,9 @@ bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N,
|
|||
unsigned PowerOfTwo = 0;
|
||||
SDValue NewMulConst;
|
||||
if (canExtractShiftFromMul(OffReg, 3, PowerOfTwo, NewMulConst)) {
|
||||
HandleSDNode Handle(OffReg);
|
||||
replaceDAGValue(OffReg.getOperand(1), NewMulConst);
|
||||
OffReg = Handle.getValue();
|
||||
ShAmt = PowerOfTwo;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,9 +228,8 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
|
|||
bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
|
||||
const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
|
||||
|
||||
// TODO: We do not always need a frame pointer.
|
||||
// This can be optimised.
|
||||
return true;
|
||||
return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||
|
||||
FuncInfo->getHasStackArgs());
|
||||
}
|
||||
|
||||
bool AVRFrameLowering::spillCalleeSavedRegisters(
|
||||
|
|
|
|||
|
|
@ -65,12 +65,18 @@ BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
|
|||
Reserved.set(AVR::SPH);
|
||||
Reserved.set(AVR::SP);
|
||||
|
||||
// Reserve the frame pointer registers r28 and r29 if the function requires one.
|
||||
if (TFI->hasFP(MF)) {
|
||||
Reserved.set(AVR::R28);
|
||||
Reserved.set(AVR::R29);
|
||||
Reserved.set(AVR::R29R28);
|
||||
}
|
||||
// We tenatively reserve the frame pointer register r29:r28 because the
|
||||
// function may require one, but we cannot tell until register allocation
|
||||
// is complete, which can be too late.
|
||||
//
|
||||
// Instead we just unconditionally reserve the Y register.
|
||||
//
|
||||
// TODO: Write a pass to enumerate functions which reserved the Y register
|
||||
// but didn't end up needing a frame pointer. In these, we can
|
||||
// convert one or two of the spills inside to use the Y register.
|
||||
Reserved.set(AVR::R28);
|
||||
Reserved.set(AVR::R29);
|
||||
Reserved.set(AVR::R29R28);
|
||||
|
||||
return Reserved;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ public:
|
|||
bool iss31_1Imm() const { return true; }
|
||||
bool iss30_2Imm() const { return true; }
|
||||
bool iss29_3Imm() const { return true; }
|
||||
bool iss23_2Imm() const { return CheckImmRange(23, 2, true, true, false); }
|
||||
bool iss27_2Imm() const { return CheckImmRange(27, 2, true, true, false); }
|
||||
bool iss10_0Imm() const { return CheckImmRange(10, 0, true, false, false); }
|
||||
bool iss10_6Imm() const { return CheckImmRange(10, 6, true, false, false); }
|
||||
bool iss9_0Imm() const { return CheckImmRange(9, 0, true, false, false); }
|
||||
|
|
@ -1292,13 +1292,13 @@ int HexagonAsmParser::processInstruction(MCInst &Inst,
|
|||
case Hexagon::A2_iconst: {
|
||||
Inst.setOpcode(Hexagon::A2_addi);
|
||||
MCOperand Reg = Inst.getOperand(0);
|
||||
MCOperand S16 = Inst.getOperand(1);
|
||||
HexagonMCInstrInfo::setMustNotExtend(*S16.getExpr());
|
||||
HexagonMCInstrInfo::setS23_2_reloc(*S16.getExpr());
|
||||
MCOperand S27 = Inst.getOperand(1);
|
||||
HexagonMCInstrInfo::setMustNotExtend(*S27.getExpr());
|
||||
HexagonMCInstrInfo::setS27_2_reloc(*S27.getExpr());
|
||||
Inst.clear();
|
||||
Inst.addOperand(Reg);
|
||||
Inst.addOperand(MCOperand::createReg(Hexagon::R0));
|
||||
Inst.addOperand(S16);
|
||||
Inst.addOperand(S27);
|
||||
break;
|
||||
}
|
||||
case Hexagon::M4_mpyrr_addr:
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ void HexagonAsmPrinter::HexagonProcessInstruction(MCInst &Inst,
|
|||
MCOperand Reg = Inst.getOperand(0);
|
||||
MCOperand S16 = Inst.getOperand(1);
|
||||
HexagonMCInstrInfo::setMustNotExtend(*S16.getExpr());
|
||||
HexagonMCInstrInfo::setS23_2_reloc(*S16.getExpr());
|
||||
HexagonMCInstrInfo::setS27_2_reloc(*S16.getExpr());
|
||||
Inst.clear();
|
||||
Inst.addOperand(Reg);
|
||||
Inst.addOperand(MCOperand::createReg(Hexagon::R0));
|
||||
|
|
|
|||
|
|
@ -1720,8 +1720,13 @@ HexagonTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA,
|
|||
Chain = DAG.getCopyToReg(DAG.getEntryNode(), dl, Hexagon::R0, Chain, InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
unsigned Flags =
|
||||
static_cast<const HexagonSubtarget &>(DAG.getSubtarget()).useLongCalls()
|
||||
? HexagonII::MO_GDPLT | HexagonII::HMOTF_ConstExtended
|
||||
: HexagonII::MO_GDPLT;
|
||||
|
||||
return GetDynamicTLSAddr(DAG, Chain, GA, InFlag, PtrVT,
|
||||
Hexagon::R0, HexagonII::MO_GDPLT);
|
||||
Hexagon::R0, Flags);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -7,16 +7,6 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Maintain list of valid subtargets for each instruction.
|
||||
class SubTarget<bits<6> value> {
|
||||
bits<6> Value = value;
|
||||
}
|
||||
|
||||
def HasAnySubT : SubTarget<0x3f>; // 111111
|
||||
def HasV5SubT : SubTarget<0x3e>; // 111110
|
||||
def HasV55SubT : SubTarget<0x3c>; // 111100
|
||||
def HasV60SubT : SubTarget<0x38>; // 111000
|
||||
|
||||
// Addressing modes for load/store instructions
|
||||
class AddrModeType<bits<3> value> {
|
||||
bits<3> Value = value;
|
||||
|
|
@ -131,12 +121,6 @@ class InstHexagon<dag outs, dag ins, string asmstr, list<dag> pattern,
|
|||
bits<2> opExtentAlign = 0;
|
||||
let TSFlags{34-33} = opExtentAlign; // Alignment exponent before extending.
|
||||
|
||||
// If an instruction is valid on a subtarget, set the corresponding
|
||||
// bit from validSubTargets.
|
||||
// By default, instruction is valid on all subtargets.
|
||||
SubTarget validSubTargets = HasAnySubT;
|
||||
let TSFlags{40-35} = validSubTargets.Value;
|
||||
|
||||
// Addressing mode for load/store instructions.
|
||||
AddrModeType addrMode = NoAddrMode;
|
||||
let TSFlags{43-41} = addrMode.Value;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
// Instruction Classes Definitions +
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
let validSubTargets = HasV60SubT in
|
||||
{
|
||||
class CVI_VA_Resource<dag outs, dag ins, string asmstr,
|
||||
list<dag> pattern = [], string cstr = "",
|
||||
InstrItinClass itin = CVI_VA>
|
||||
|
|
@ -184,10 +182,7 @@ class CVI_HIST_Resource<dag outs, dag ins, string asmstr,
|
|||
InstrItinClass itin = CVI_HIST>
|
||||
: InstHexagon<outs, ins, asmstr, pattern, cstr, itin, TypeCVI_HIST>,
|
||||
OpcodeHexagon, Requires<[HasV60T, UseHVX]>;
|
||||
}
|
||||
|
||||
let validSubTargets = HasV60SubT in
|
||||
{
|
||||
class CVI_VA_Resource1<dag outs, dag ins, string asmstr,
|
||||
list<dag> pattern = [], string cstr = "",
|
||||
InstrItinClass itin = CVI_VA>
|
||||
|
|
@ -205,6 +200,3 @@ class CVI_HIST_Resource1<dag outs, dag ins, string asmstr,
|
|||
InstrItinClass itin = CVI_HIST>
|
||||
: InstHexagon<outs, ins, asmstr, pattern, cstr, itin, TypeCVI_HIST>,
|
||||
Requires<[HasV60T, UseHVX]>;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -869,6 +869,9 @@ void HexagonInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
|||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
unsigned Align = MFI.getObjectAlignment(FI);
|
||||
unsigned KillFlag = getKillRegState(isKill);
|
||||
bool HasAlloca = MFI.hasVarSizedObjects();
|
||||
const auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
const HexagonFrameLowering &HFI = *HST.getFrameLowering();
|
||||
|
||||
MachineMemOperand *MMO = MF.getMachineMemOperand(
|
||||
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
|
||||
|
|
@ -899,24 +902,36 @@ void HexagonInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
|||
.addFrameIndex(FI).addImm(0)
|
||||
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
|
||||
} else if (Hexagon::VectorRegs128BRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 128 ? Hexagon::V6_vS32Ub_ai_128B
|
||||
: Hexagon::V6_vS32b_ai_128B;
|
||||
BuildMI(MBB, I, DL, get(Opc))
|
||||
.addFrameIndex(FI).addImm(0)
|
||||
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
|
||||
} else if (Hexagon::VectorRegsRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 64 ? Hexagon::V6_vS32Ub_ai
|
||||
: Hexagon::V6_vS32b_ai;
|
||||
BuildMI(MBB, I, DL, get(Opc))
|
||||
.addFrameIndex(FI).addImm(0)
|
||||
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
|
||||
} else if (Hexagon::VecDblRegsRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 64 ? Hexagon::PS_vstorerwu_ai
|
||||
: Hexagon::PS_vstorerw_ai;
|
||||
BuildMI(MBB, I, DL, get(Opc))
|
||||
.addFrameIndex(FI).addImm(0)
|
||||
.addReg(SrcReg, KillFlag).addMemOperand(MMO);
|
||||
} else if (Hexagon::VecDblRegs128BRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 128 ? Hexagon::PS_vstorerwu_ai_128B
|
||||
: Hexagon::PS_vstorerw_ai_128B;
|
||||
BuildMI(MBB, I, DL, get(Opc))
|
||||
|
|
@ -935,6 +950,9 @@ void HexagonInstrInfo::loadRegFromStackSlot(
|
|||
MachineFunction &MF = *MBB.getParent();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
unsigned Align = MFI.getObjectAlignment(FI);
|
||||
bool HasAlloca = MFI.hasVarSizedObjects();
|
||||
const auto &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
const HexagonFrameLowering &HFI = *HST.getFrameLowering();
|
||||
|
||||
MachineMemOperand *MMO = MF.getMachineMemOperand(
|
||||
MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
|
||||
|
|
@ -959,21 +977,33 @@ void HexagonInstrInfo::loadRegFromStackSlot(
|
|||
BuildMI(MBB, I, DL, get(Hexagon::PS_vloadrq_ai), DestReg)
|
||||
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
|
||||
} else if (Hexagon::VecDblRegs128BRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 128 ? Hexagon::PS_vloadrwu_ai_128B
|
||||
: Hexagon::PS_vloadrw_ai_128B;
|
||||
BuildMI(MBB, I, DL, get(Opc), DestReg)
|
||||
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
|
||||
} else if (Hexagon::VectorRegs128BRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 128 ? Hexagon::V6_vL32Ub_ai_128B
|
||||
: Hexagon::V6_vL32b_ai_128B;
|
||||
BuildMI(MBB, I, DL, get(Opc), DestReg)
|
||||
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
|
||||
} else if (Hexagon::VectorRegsRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 64 ? Hexagon::V6_vL32Ub_ai
|
||||
: Hexagon::V6_vL32b_ai;
|
||||
BuildMI(MBB, I, DL, get(Opc), DestReg)
|
||||
.addFrameIndex(FI).addImm(0).addMemOperand(MMO);
|
||||
} else if (Hexagon::VecDblRegsRegClass.hasSubClassEq(RC)) {
|
||||
// If there are variable-sized objects, spills will not be aligned.
|
||||
if (HasAlloca)
|
||||
Align = HFI.getStackAlignment();
|
||||
unsigned Opc = Align < 64 ? Hexagon::PS_vloadrwu_ai
|
||||
: Hexagon::PS_vloadrw_ai;
|
||||
BuildMI(MBB, I, DL, get(Opc), DestReg)
|
||||
|
|
@ -1110,8 +1140,9 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
|||
unsigned Offset = Is128B ? VecOffset << 7 : VecOffset << 6;
|
||||
MachineInstr *MI1New = BuildMI(MBB, MI, DL, get(NewOpc),
|
||||
HRI.getSubReg(DstReg, Hexagon::vsub_lo))
|
||||
.add(MI.getOperand(1))
|
||||
.addImm(MI.getOperand(2).getImm());
|
||||
.add(MI.getOperand(1))
|
||||
.addImm(MI.getOperand(2).getImm())
|
||||
.setMemRefs(MI.memoperands_begin(), MI.memoperands_end());
|
||||
MI1New->getOperand(1).setIsKill(false);
|
||||
BuildMI(MBB, MI, DL, get(NewOpc), HRI.getSubReg(DstReg, Hexagon::vsub_hi))
|
||||
.add(MI.getOperand(1))
|
||||
|
|
@ -1940,7 +1971,7 @@ bool HexagonInstrInfo::isDeallocRet(const MachineInstr &MI) const {
|
|||
case Hexagon::L4_return_fnew_pnt :
|
||||
case Hexagon::L4_return_tnew_pt :
|
||||
case Hexagon::L4_return_fnew_pt :
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1967,12 +1998,12 @@ bool HexagonInstrInfo::isDependent(const MachineInstr &ProdMI,
|
|||
if (RegA == RegB)
|
||||
return true;
|
||||
|
||||
if (Hexagon::DoubleRegsRegClass.contains(RegA))
|
||||
if (TargetRegisterInfo::isPhysicalRegister(RegA))
|
||||
for (MCSubRegIterator SubRegs(RegA, &HRI); SubRegs.isValid(); ++SubRegs)
|
||||
if (RegB == *SubRegs)
|
||||
return true;
|
||||
|
||||
if (Hexagon::DoubleRegsRegClass.contains(RegB))
|
||||
if (TargetRegisterInfo::isPhysicalRegister(RegB))
|
||||
for (MCSubRegIterator SubRegs(RegB, &HRI); SubRegs.isValid(); ++SubRegs)
|
||||
if (RegA == *SubRegs)
|
||||
return true;
|
||||
|
|
@ -2139,7 +2170,7 @@ bool HexagonInstrInfo::isJumpR(const MachineInstr &MI) const {
|
|||
bool HexagonInstrInfo::isJumpWithinBranchRange(const MachineInstr &MI,
|
||||
unsigned offset) const {
|
||||
// This selection of jump instructions matches to that what
|
||||
// AnalyzeBranch can parse, plus NVJ.
|
||||
// analyzeBranch can parse, plus NVJ.
|
||||
if (isNewValueJump(MI)) // r9:2
|
||||
return isInt<11>(offset);
|
||||
|
||||
|
|
@ -2666,6 +2697,7 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset,
|
|||
case Hexagon::L2_loadrh_io:
|
||||
case Hexagon::L2_loadruh_io:
|
||||
case Hexagon::S2_storerh_io:
|
||||
case Hexagon::S2_storerf_io:
|
||||
return (Offset >= Hexagon_MEMH_OFFSET_MIN) &&
|
||||
(Offset <= Hexagon_MEMH_OFFSET_MAX);
|
||||
|
||||
|
|
@ -2876,6 +2908,11 @@ bool HexagonInstrInfo::getMemOpBaseRegImmOfs(MachineInstr &LdSt,
|
|||
/// \brief Can these instructions execute at the same time in a bundle.
|
||||
bool HexagonInstrInfo::canExecuteInBundle(const MachineInstr &First,
|
||||
const MachineInstr &Second) const {
|
||||
if (Second.mayStore() && First.getOpcode() == Hexagon::S2_allocframe) {
|
||||
const MachineOperand &Op = Second.getOperand(0);
|
||||
if (Op.isReg() && Op.isUse() && Op.getReg() == Hexagon::R29)
|
||||
return true;
|
||||
}
|
||||
if (DisableNVSchedule)
|
||||
return false;
|
||||
if (mayBeNewStore(Second)) {
|
||||
|
|
@ -3000,13 +3037,9 @@ bool HexagonInstrInfo::producesStall(const MachineInstr &MI,
|
|||
MachineBasicBlock::const_instr_iterator MII = BII;
|
||||
MachineBasicBlock::const_instr_iterator MIE = MII->getParent()->instr_end();
|
||||
|
||||
if (!MII->isBundle()) {
|
||||
if (!(*MII).isBundle()) {
|
||||
const MachineInstr &J = *MII;
|
||||
if (!isV60VectorInstruction(J))
|
||||
return false;
|
||||
else if (isVecUsableNextPacket(J, MI))
|
||||
return false;
|
||||
return true;
|
||||
return producesStall(J, MI);
|
||||
}
|
||||
|
||||
for (++MII; MII != MIE && MII->isInsideBundle(); ++MII) {
|
||||
|
|
@ -3034,12 +3067,14 @@ bool HexagonInstrInfo::predCanBeUsedAsDotNew(const MachineInstr &MI,
|
|||
}
|
||||
|
||||
bool HexagonInstrInfo::PredOpcodeHasJMP_c(unsigned Opcode) const {
|
||||
return (Opcode == Hexagon::J2_jumpt) ||
|
||||
(Opcode == Hexagon::J2_jumpf) ||
|
||||
(Opcode == Hexagon::J2_jumptnew) ||
|
||||
(Opcode == Hexagon::J2_jumpfnew) ||
|
||||
(Opcode == Hexagon::J2_jumptnewpt) ||
|
||||
(Opcode == Hexagon::J2_jumpfnewpt);
|
||||
return Opcode == Hexagon::J2_jumpt ||
|
||||
Opcode == Hexagon::J2_jumptpt ||
|
||||
Opcode == Hexagon::J2_jumpf ||
|
||||
Opcode == Hexagon::J2_jumpfpt ||
|
||||
Opcode == Hexagon::J2_jumptnew ||
|
||||
Opcode == Hexagon::J2_jumpfnew ||
|
||||
Opcode == Hexagon::J2_jumptnewpt ||
|
||||
Opcode == Hexagon::J2_jumpfnewpt;
|
||||
}
|
||||
|
||||
bool HexagonInstrInfo::predOpcodeHasNot(ArrayRef<MachineOperand> Cond) const {
|
||||
|
|
@ -3341,9 +3376,30 @@ int HexagonInstrInfo::getDotCurOp(const MachineInstr &MI) const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Return the regular version of the .cur instruction.
|
||||
int HexagonInstrInfo::getNonDotCurOp(const MachineInstr &MI) const {
|
||||
switch (MI.getOpcode()) {
|
||||
default: llvm_unreachable("Unknown .cur type");
|
||||
case Hexagon::V6_vL32b_cur_pi:
|
||||
return Hexagon::V6_vL32b_pi;
|
||||
case Hexagon::V6_vL32b_cur_ai:
|
||||
return Hexagon::V6_vL32b_ai;
|
||||
//128B
|
||||
case Hexagon::V6_vL32b_cur_pi_128B:
|
||||
return Hexagon::V6_vL32b_pi_128B;
|
||||
case Hexagon::V6_vL32b_cur_ai_128B:
|
||||
return Hexagon::V6_vL32b_ai_128B;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// The diagram below shows the steps involved in the conversion of a predicated
|
||||
// store instruction to its .new predicated new-value form.
|
||||
//
|
||||
// Note: It doesn't include conditional new-value stores as they can't be
|
||||
// converted to .new predicate.
|
||||
//
|
||||
// p.new NV store [ if(p0.new)memw(R0+#0)=R2.new ]
|
||||
// ^ ^
|
||||
// / \ (not OK. it will cause new-value store to be
|
||||
|
|
@ -3564,11 +3620,11 @@ int HexagonInstrInfo::getDotNewPredOp(const MachineInstr &MI,
|
|||
}
|
||||
|
||||
int HexagonInstrInfo::getDotOldOp(const MachineInstr &MI) const {
|
||||
const MachineFunction &MF = *MI.getParent()->getParent();
|
||||
const HexagonSubtarget &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
int NewOp = MI.getOpcode();
|
||||
if (isPredicated(NewOp) && isPredicatedNew(NewOp)) { // Get predicate old form
|
||||
NewOp = Hexagon::getPredOldOpcode(NewOp);
|
||||
const MachineFunction &MF = *MI.getParent()->getParent();
|
||||
const HexagonSubtarget &HST = MF.getSubtarget<HexagonSubtarget>();
|
||||
// All Hexagon architectures have prediction bits on dot-new branches,
|
||||
// but only Hexagon V60+ has prediction bits on dot-old ones. Make sure
|
||||
// to pick the right opcode when converting back to dot-old.
|
||||
|
|
@ -3596,6 +3652,21 @@ int HexagonInstrInfo::getDotOldOp(const MachineInstr &MI) const {
|
|||
NewOp = Hexagon::getNonNVStore(NewOp);
|
||||
assert(NewOp >= 0 && "Couldn't change new-value store to its old form.");
|
||||
}
|
||||
|
||||
if (HST.hasV60TOps())
|
||||
return NewOp;
|
||||
|
||||
// Subtargets prior to V60 didn't support 'taken' forms of predicated jumps.
|
||||
switch (NewOp) {
|
||||
case Hexagon::J2_jumpfpt:
|
||||
return Hexagon::J2_jumpf;
|
||||
case Hexagon::J2_jumptpt:
|
||||
return Hexagon::J2_jumpt;
|
||||
case Hexagon::J2_jumprfpt:
|
||||
return Hexagon::J2_jumprf;
|
||||
case Hexagon::J2_jumprtpt:
|
||||
return Hexagon::J2_jumprt;
|
||||
}
|
||||
return NewOp;
|
||||
}
|
||||
|
||||
|
|
@ -3947,18 +4018,6 @@ short HexagonInstrInfo::getEquivalentHWInstr(const MachineInstr &MI) const {
|
|||
return Hexagon::getRealHWInstr(MI.getOpcode(), Hexagon::InstrType_Real);
|
||||
}
|
||||
|
||||
// Return first non-debug instruction in the basic block.
|
||||
MachineInstr *HexagonInstrInfo::getFirstNonDbgInst(MachineBasicBlock *BB)
|
||||
const {
|
||||
for (auto MII = BB->instr_begin(), End = BB->instr_end(); MII != End; MII++) {
|
||||
MachineInstr &MI = *MII;
|
||||
if (MI.isDebugValue())
|
||||
continue;
|
||||
return &MI;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned HexagonInstrInfo::getInstrTimingClassLatency(
|
||||
const InstrItineraryData *ItinData, const MachineInstr &MI) const {
|
||||
// Default to one cycle for no itinerary. However, an "empty" itinerary may
|
||||
|
|
@ -4139,11 +4198,6 @@ unsigned HexagonInstrInfo::getUnits(const MachineInstr &MI) const {
|
|||
return IS.getUnits();
|
||||
}
|
||||
|
||||
unsigned HexagonInstrInfo::getValidSubTargets(const unsigned Opcode) const {
|
||||
const uint64_t F = get(Opcode).TSFlags;
|
||||
return (F >> HexagonII::validSubTargetPos) & HexagonII::validSubTargetMask;
|
||||
}
|
||||
|
||||
// Calculate size of the basic block without debug instructions.
|
||||
unsigned HexagonInstrInfo::nonDbgBBSize(const MachineBasicBlock *BB) const {
|
||||
return nonDbgMICount(BB->instr_begin(), BB->instr_end());
|
||||
|
|
|
|||
|
|
@ -399,6 +399,7 @@ public:
|
|||
const MachineInstr &GB) const;
|
||||
int getCondOpcode(int Opc, bool sense) const;
|
||||
int getDotCurOp(const MachineInstr &MI) const;
|
||||
int getNonDotCurOp(const MachineInstr &MI) const;
|
||||
int getDotNewOp(const MachineInstr &MI) const;
|
||||
int getDotNewPredJumpOp(const MachineInstr &MI,
|
||||
const MachineBranchProbabilityInfo *MBPI) const;
|
||||
|
|
@ -424,7 +425,6 @@ public:
|
|||
unsigned getSize(const MachineInstr &MI) const;
|
||||
uint64_t getType(const MachineInstr &MI) const;
|
||||
unsigned getUnits(const MachineInstr &MI) const;
|
||||
unsigned getValidSubTargets(const unsigned Opcode) const;
|
||||
|
||||
/// getInstrTimingClassLatency - Compute the instruction latency of a given
|
||||
/// instruction using Timing Class information, if available.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
|
|||
// Populate the relocation type based on Hexagon target flags
|
||||
// set on an operand
|
||||
MCSymbolRefExpr::VariantKind RelocationType;
|
||||
switch (MO.getTargetFlags()) {
|
||||
switch (MO.getTargetFlags() & ~HexagonII::HMOTF_ConstExtended) {
|
||||
default:
|
||||
RelocationType = MCSymbolRefExpr::VK_None;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ def f64Imm : Operand<f64> { let ParserMatchClass = f64ImmOperand; }
|
|||
def s8_0Imm64Pred : PatLeaf<(i64 imm), [{ return isInt<8>(N->getSExtValue()); }]>;
|
||||
def s9_0ImmOperand : AsmOperandClass { let Name = "s9_0Imm"; }
|
||||
def s9_0Imm : Operand<i32> { let ParserMatchClass = s9_0ImmOperand; }
|
||||
def s23_2ImmOperand : AsmOperandClass { let Name = "s23_2Imm"; let RenderMethod = "addSignedImmOperands"; }
|
||||
def s23_2Imm : Operand<i32> { let ParserMatchClass = s23_2ImmOperand; }
|
||||
def s27_2ImmOperand : AsmOperandClass { let Name = "s27_2Imm"; let RenderMethod = "addSignedImmOperands"; }
|
||||
def s27_2Imm : Operand<i32> { let ParserMatchClass = s27_2ImmOperand; }
|
||||
def r32_0ImmPred : PatLeaf<(i32 imm), [{
|
||||
int64_t v = (int64_t)N->getSExtValue();
|
||||
return isInt<32>(v);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,11 @@ let PrintMethod = "printGlobalOperand" in {
|
|||
|
||||
let isPseudo = 1 in {
|
||||
let isCodeGenOnly = 0 in
|
||||
def A2_iconst : Pseudo<(outs IntRegs:$Rd32), (ins s23_2Imm:$Ii), "${Rd32}=iconst(#${Ii})">;
|
||||
def DUPLEX_Pseudo : InstHexagon<(outs), (ins s32_0Imm:$offset), "DUPLEX", [], "", DUPLEX, TypePSEUDO>;
|
||||
def A2_iconst : Pseudo<(outs IntRegs:$Rd32),
|
||||
(ins s27_2Imm:$Ii), "${Rd32}=iconst(#${Ii})">;
|
||||
|
||||
def DUPLEX_Pseudo : InstHexagon<(outs),
|
||||
(ins s32_0Imm:$offset), "DUPLEX", [], "", DUPLEX, TypePSEUDO>;
|
||||
}
|
||||
|
||||
let isExtendable = 1, opExtendable = 1, opExtentBits = 6,
|
||||
|
|
@ -321,7 +324,7 @@ def LDriw_mod : LDInst<(outs ModRegs:$dst),
|
|||
|
||||
// Vector load
|
||||
let Predicates = [HasV60T, UseHVX] in
|
||||
let mayLoad = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
|
||||
let mayLoad = 1, hasSideEffects = 0 in
|
||||
class V6_LDInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
|
||||
string cstr = "", InstrItinClass itin = CVI_VM_LD,
|
||||
IType type = TypeCVI_VM_LD>
|
||||
|
|
@ -329,7 +332,7 @@ let mayLoad = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
|
|||
|
||||
// Vector store
|
||||
let Predicates = [HasV60T, UseHVX] in
|
||||
let mayStore = 1, validSubTargets = HasV60SubT, hasSideEffects = 0 in
|
||||
let mayStore = 1, hasSideEffects = 0 in
|
||||
class V6_STInst<dag outs, dag ins, string asmstr, list<dag> pattern = [],
|
||||
string cstr = "", InstrItinClass itin = CVI_VM_ST,
|
||||
IType type = TypeCVI_VM_ST>
|
||||
|
|
@ -415,7 +418,7 @@ let isCall = 1, Uses = [R29, R31], isAsmParserOnly = 1 in {
|
|||
|
||||
// Vector load/store pseudos
|
||||
|
||||
let isPseudo = 1, isCodeGenOnly = 1, validSubTargets = HasV60SubT in
|
||||
let isPseudo = 1, isCodeGenOnly = 1 in
|
||||
class STrivv_template<RegisterClass RC>
|
||||
: V6_STInst<(outs), (ins IntRegs:$addr, s32_0Imm:$off, RC:$src), "", []>;
|
||||
|
||||
|
|
@ -429,7 +432,7 @@ def PS_vstorerwu_ai_128B: STrivv_template<VecDblRegs128B>,
|
|||
Requires<[HasV60T,UseHVXDbl]>;
|
||||
|
||||
|
||||
let isPseudo = 1, isCodeGenOnly = 1, validSubTargets = HasV60SubT in
|
||||
let isPseudo = 1, isCodeGenOnly = 1 in
|
||||
class LDrivv_template<RegisterClass RC>
|
||||
: V6_LDInst<(outs RC:$dst), (ins IntRegs:$addr, s32_0Imm:$off), "", []>;
|
||||
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ void HexagonPacketizerList::cleanUpDotCur() {
|
|||
MachineInstr *MI = nullptr;
|
||||
for (auto BI : CurrentPacketMIs) {
|
||||
DEBUG(dbgs() << "Cleanup packet has "; BI->dump(););
|
||||
if (BI->getOpcode() == Hexagon::V6_vL32b_cur_ai) {
|
||||
if (HII->isDotCurInst(*BI)) {
|
||||
MI = BI;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -369,7 +369,7 @@ void HexagonPacketizerList::cleanUpDotCur() {
|
|||
if (!MI)
|
||||
return;
|
||||
// We did not find a use of the CUR, so de-cur it.
|
||||
MI->setDesc(HII->get(Hexagon::V6_vL32b_ai));
|
||||
MI->setDesc(HII->get(HII->getNonDotCurOp(*MI)));
|
||||
DEBUG(dbgs() << "Demoted CUR "; MI->dump(););
|
||||
}
|
||||
|
||||
|
|
@ -1579,14 +1579,13 @@ MachineBasicBlock::iterator
|
|||
HexagonPacketizerList::addToPacket(MachineInstr &MI) {
|
||||
MachineBasicBlock::iterator MII = MI.getIterator();
|
||||
MachineBasicBlock *MBB = MI.getParent();
|
||||
if (MI.isImplicitDef()) {
|
||||
unsigned R = MI.getOperand(0).getReg();
|
||||
if (Hexagon::IntRegsRegClass.contains(R)) {
|
||||
MCSuperRegIterator S(R, HRI, false);
|
||||
MI.addOperand(MachineOperand::CreateReg(*S, true, true));
|
||||
}
|
||||
|
||||
if (CurrentPacketMIs.size() == 0)
|
||||
PacketStalls = false;
|
||||
PacketStalls |= producesStall(MI);
|
||||
|
||||
if (MI.isImplicitDef())
|
||||
return MII;
|
||||
}
|
||||
assert(ResourceTracker->canReserveResources(MI));
|
||||
|
||||
bool ExtMI = HII->isExtended(MI) || HII->isConstExtended(MI);
|
||||
|
|
@ -1677,6 +1676,11 @@ static bool isDependent(const MachineInstr &ProdMI,
|
|||
|
||||
// V60 forward scheduling.
|
||||
bool HexagonPacketizerList::producesStall(const MachineInstr &I) {
|
||||
// If the packet already stalls, then ignore the stall from a subsequent
|
||||
// instruction in the same packet.
|
||||
if (PacketStalls)
|
||||
return false;
|
||||
|
||||
// Check whether the previous packet is in a different loop. If this is the
|
||||
// case, there is little point in trying to avoid a stall because that would
|
||||
// favor the rare case (loop entry) over the common case (loop iteration).
|
||||
|
|
@ -1699,6 +1703,7 @@ bool HexagonPacketizerList::producesStall(const MachineInstr &I) {
|
|||
if (isDependent(*J, I) && !HII->isVecUsableNextPacket(*J, I))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1721,6 +1726,16 @@ bool HexagonPacketizerList::producesStall(const MachineInstr &I) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if the latency is greater than one between this instruction and any
|
||||
// instruction in the previous packet.
|
||||
SUnit *SUI = MIToSUnit[const_cast<MachineInstr *>(&I)];
|
||||
for (auto J : OldPacketMIs) {
|
||||
SUnit *SUJ = MIToSUnit[J];
|
||||
for (auto &Pred : SUI->Preds)
|
||||
if (Pred.getSUnit() == SUJ && Pred.getLatency() > 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ class HexagonPacketizerList : public VLIWPacketizerList {
|
|||
// Track MIs with ignored dependence.
|
||||
std::vector<MachineInstr*> IgnoreDepMIs;
|
||||
|
||||
// Set to true if the packet contains an instruction that stalls with an
|
||||
// instruction from the previous packet.
|
||||
bool PacketStalls = false;
|
||||
|
||||
protected:
|
||||
/// \brief A handle to the branch probability pass.
|
||||
const MachineBranchProbabilityInfo *MBPI;
|
||||
|
|
|
|||
|
|
@ -184,7 +184,11 @@ public:
|
|||
{ "fixup_Hexagon_IE_GOT_11_X", 0, 32, 0 },
|
||||
{ "fixup_Hexagon_TPREL_32_6_X", 0, 32, 0 },
|
||||
{ "fixup_Hexagon_TPREL_16_X", 0, 32, 0 },
|
||||
{ "fixup_Hexagon_TPREL_11_X", 0, 32, 0 }
|
||||
{ "fixup_Hexagon_TPREL_11_X", 0, 32, 0 },
|
||||
{ "fixup_Hexagon_GD_PLT_B22_PCREL_X",0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
||||
{ "fixup_Hexagon_GD_PLT_B32_PCREL_X",0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
||||
{ "fixup_Hexagon_LD_PLT_B22_PCREL_X",0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
||||
{ "fixup_Hexagon_LD_PLT_B32_PCREL_X",0, 32, MCFixupKindInfo::FKF_IsPCRel }
|
||||
};
|
||||
|
||||
if (Kind < FirstTargetFixupKind)
|
||||
|
|
@ -291,6 +295,11 @@ public:
|
|||
case fixup_Hexagon_32_PCREL:
|
||||
case fixup_Hexagon_6_PCREL_X:
|
||||
case fixup_Hexagon_23_REG:
|
||||
case fixup_Hexagon_27_REG:
|
||||
case fixup_Hexagon_GD_PLT_B22_PCREL_X:
|
||||
case fixup_Hexagon_GD_PLT_B32_PCREL_X:
|
||||
case fixup_Hexagon_LD_PLT_B22_PCREL_X:
|
||||
case fixup_Hexagon_LD_PLT_B32_PCREL_X:
|
||||
// These relocations should always have a relocation recorded
|
||||
IsResolved = false;
|
||||
return;
|
||||
|
|
@ -347,6 +356,8 @@ public:
|
|||
case fixup_Hexagon_B9_PCREL_X:
|
||||
case fixup_Hexagon_B7_PCREL:
|
||||
case fixup_Hexagon_B7_PCREL_X:
|
||||
case fixup_Hexagon_GD_PLT_B32_PCREL_X:
|
||||
case fixup_Hexagon_LD_PLT_B32_PCREL_X:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
|
@ -374,6 +385,8 @@ public:
|
|||
break;
|
||||
|
||||
case fixup_Hexagon_B32_PCREL_X:
|
||||
case fixup_Hexagon_GD_PLT_B32_PCREL_X:
|
||||
case fixup_Hexagon_LD_PLT_B32_PCREL_X:
|
||||
Value >>= 6;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,10 +128,6 @@ namespace HexagonII {
|
|||
ExtentAlignPos = 33,
|
||||
ExtentAlignMask = 0x3,
|
||||
|
||||
// Valid subtargets
|
||||
validSubTargetPos = 35,
|
||||
validSubTargetMask = 0x3f,
|
||||
|
||||
// Addressing mode for load/store instructions.
|
||||
AddrModePos = 41,
|
||||
AddrModeMask = 0x7,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue