Vendor import of llvm trunk r302069:

https://llvm.org/svn/llvm-project/llvm/trunk@302069
This commit is contained in:
Dimitry Andric 2017-05-03 20:26:11 +00:00
parent a303c417bb
commit 148779df30
225 changed files with 5699 additions and 2676 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,6 +15,7 @@ add_llvm_library(LLVMDebugInfoCodeView
ModuleDebugLineFragment.cpp
ModuleDebugUnknownFragment.cpp
RecordSerialization.cpp
StringTable.cpp
SymbolRecordMapping.cpp
SymbolDumper.cpp
SymbolSerializer.cpp

View file

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

View file

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

View file

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

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

View file

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

View file

@ -19,6 +19,7 @@ add_llvm_library(LLVMDebugInfoDWARF
DWARFTypeUnit.cpp
DWARFUnitIndex.cpp
DWARFUnit.cpp
DWARFVerifier.cpp
SyntaxHighlighting.cpp
ADDITIONAL_HEADER_DIRS

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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), "", []>;

View file

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

View file

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

View file

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

View file

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