Merge llvm, clang, lld, lldb, compiler-rt and libc++ r303291, and update
build glue.
This commit is contained in:
commit
60ff8e32a5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang500-import/; revision=318477
@ -104,7 +104,7 @@ __floatdidf(di_int a)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__AEABI__)
|
#if defined(__ARM_EABI__)
|
||||||
AEABI_RTABI double __aeabi_l2d(di_int a) {
|
AEABI_RTABI double __aeabi_l2d(di_int a) {
|
||||||
return __floatdidf(a);
|
return __floatdidf(a);
|
||||||
}
|
}
|
||||||
|
@ -64,14 +64,23 @@ struct forward_iterator_tag : public input_iterator_tag {};
|
|||||||
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||||
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||||
|
|
||||||
|
// 27.4.3, iterator operations
|
||||||
// extension: second argument not conforming to C++03
|
// extension: second argument not conforming to C++03
|
||||||
template <class InputIterator>
|
template <class InputIterator> // constexpr in C++17
|
||||||
void advance(InputIterator& i,
|
constexpr void advance(InputIterator& i,
|
||||||
typename iterator_traits<InputIterator>::difference_type n);
|
typename iterator_traits<InputIterator>::difference_type n);
|
||||||
|
|
||||||
template <class InputIterator>
|
template <class InputIterator> // constexpr in C++17
|
||||||
typename iterator_traits<InputIterator>::difference_type
|
constexpr typename iterator_traits<InputIterator>::difference_type
|
||||||
distance(InputIterator first, InputIterator last);
|
distance(InputIterator first, InputIterator last);
|
||||||
|
|
||||||
|
template <class InputIterator> // constexpr in C++17
|
||||||
|
constexpr InputIterator next(InputIterator x,
|
||||||
|
typename iterator_traits<InputIterator>::difference_type n = 1);
|
||||||
|
|
||||||
|
template <class BidirectionalIterator> // constexpr in C++17
|
||||||
|
constexpr BidirectionalIterator prev(BidirectionalIterator x,
|
||||||
|
typename iterator_traits<BidirectionalIterator>::difference_type n = 1);
|
||||||
|
|
||||||
template <class Iterator>
|
template <class Iterator>
|
||||||
class reverse_iterator
|
class reverse_iterator
|
||||||
@ -529,7 +538,7 @@ struct _LIBCPP_TEMPLATE_VIS iterator
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class _InputIter>
|
template <class _InputIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
void __advance(_InputIter& __i,
|
void __advance(_InputIter& __i,
|
||||||
typename iterator_traits<_InputIter>::difference_type __n, input_iterator_tag)
|
typename iterator_traits<_InputIter>::difference_type __n, input_iterator_tag)
|
||||||
{
|
{
|
||||||
@ -538,7 +547,7 @@ void __advance(_InputIter& __i,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _BiDirIter>
|
template <class _BiDirIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
void __advance(_BiDirIter& __i,
|
void __advance(_BiDirIter& __i,
|
||||||
typename iterator_traits<_BiDirIter>::difference_type __n, bidirectional_iterator_tag)
|
typename iterator_traits<_BiDirIter>::difference_type __n, bidirectional_iterator_tag)
|
||||||
{
|
{
|
||||||
@ -551,7 +560,7 @@ void __advance(_BiDirIter& __i,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _RandIter>
|
template <class _RandIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
void __advance(_RandIter& __i,
|
void __advance(_RandIter& __i,
|
||||||
typename iterator_traits<_RandIter>::difference_type __n, random_access_iterator_tag)
|
typename iterator_traits<_RandIter>::difference_type __n, random_access_iterator_tag)
|
||||||
{
|
{
|
||||||
@ -559,7 +568,7 @@ void __advance(_RandIter& __i,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _InputIter>
|
template <class _InputIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
void advance(_InputIter& __i,
|
void advance(_InputIter& __i,
|
||||||
typename iterator_traits<_InputIter>::difference_type __n)
|
typename iterator_traits<_InputIter>::difference_type __n)
|
||||||
{
|
{
|
||||||
@ -567,7 +576,7 @@ void advance(_InputIter& __i,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _InputIter>
|
template <class _InputIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
typename iterator_traits<_InputIter>::difference_type
|
typename iterator_traits<_InputIter>::difference_type
|
||||||
__distance(_InputIter __first, _InputIter __last, input_iterator_tag)
|
__distance(_InputIter __first, _InputIter __last, input_iterator_tag)
|
||||||
{
|
{
|
||||||
@ -578,7 +587,7 @@ __distance(_InputIter __first, _InputIter __last, input_iterator_tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _RandIter>
|
template <class _RandIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
typename iterator_traits<_RandIter>::difference_type
|
typename iterator_traits<_RandIter>::difference_type
|
||||||
__distance(_RandIter __first, _RandIter __last, random_access_iterator_tag)
|
__distance(_RandIter __first, _RandIter __last, random_access_iterator_tag)
|
||||||
{
|
{
|
||||||
@ -586,7 +595,7 @@ __distance(_RandIter __first, _RandIter __last, random_access_iterator_tag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _InputIter>
|
template <class _InputIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
typename iterator_traits<_InputIter>::difference_type
|
typename iterator_traits<_InputIter>::difference_type
|
||||||
distance(_InputIter __first, _InputIter __last)
|
distance(_InputIter __first, _InputIter __last)
|
||||||
{
|
{
|
||||||
@ -594,7 +603,7 @@ distance(_InputIter __first, _InputIter __last)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _InputIter>
|
template <class _InputIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
_InputIter
|
_InputIter
|
||||||
next(_InputIter __x,
|
next(_InputIter __x,
|
||||||
typename iterator_traits<_InputIter>::difference_type __n = 1,
|
typename iterator_traits<_InputIter>::difference_type __n = 1,
|
||||||
@ -605,7 +614,7 @@ next(_InputIter __x,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class _BidiretionalIter>
|
template <class _BidiretionalIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||||
_BidiretionalIter
|
_BidiretionalIter
|
||||||
prev(_BidiretionalIter __x,
|
prev(_BidiretionalIter __x,
|
||||||
typename iterator_traits<_BidiretionalIter>::difference_type __n = 1,
|
typename iterator_traits<_BidiretionalIter>::difference_type __n = 1,
|
||||||
|
@ -599,8 +599,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
_LIBCPP_INLINE_VISIBILITY constexpr optional() noexcept {}
|
_LIBCPP_INLINE_VISIBILITY constexpr optional() noexcept {}
|
||||||
_LIBCPP_INLINE_VISIBILITY optional(const optional&) = default;
|
_LIBCPP_INLINE_VISIBILITY constexpr optional(const optional&) = default;
|
||||||
_LIBCPP_INLINE_VISIBILITY optional(optional&&) = default;
|
_LIBCPP_INLINE_VISIBILITY constexpr optional(optional&&) = default;
|
||||||
_LIBCPP_INLINE_VISIBILITY constexpr optional(nullopt_t) noexcept {}
|
_LIBCPP_INLINE_VISIBILITY constexpr optional(nullopt_t) noexcept {}
|
||||||
|
|
||||||
template <class... _Args, class = enable_if_t<
|
template <class... _Args, class = enable_if_t<
|
||||||
|
@ -1067,9 +1067,7 @@ class LLVM_NODISCARD APInt {
|
|||||||
/// \returns the bit value at bitPosition
|
/// \returns the bit value at bitPosition
|
||||||
bool operator[](unsigned bitPosition) const {
|
bool operator[](unsigned bitPosition) const {
|
||||||
assert(bitPosition < getBitWidth() && "Bit position out of bounds!");
|
assert(bitPosition < getBitWidth() && "Bit position out of bounds!");
|
||||||
return (maskBit(bitPosition) &
|
return (maskBit(bitPosition) & getWord(bitPosition)) != 0;
|
||||||
(isSingleWord() ? U.VAL : U.pVal[whichWord(bitPosition)])) !=
|
|
||||||
0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define LLVM_ADT_BITVECTOR_H
|
#define LLVM_ADT_BITVECTOR_H
|
||||||
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
|
#include "llvm/ADT/iterator_range.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -26,6 +27,50 @@
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
/// ForwardIterator for the bits that are set.
|
||||||
|
/// Iterators get invalidated when resize / reserve is called.
|
||||||
|
template <typename BitVectorT> class const_set_bits_iterator_impl {
|
||||||
|
const BitVectorT &Parent;
|
||||||
|
int Current = 0;
|
||||||
|
|
||||||
|
void advance() {
|
||||||
|
assert(Current != -1 && "Trying to advance past end.");
|
||||||
|
Current = Parent.find_next(Current);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const_set_bits_iterator_impl(const BitVectorT &Parent, int Current)
|
||||||
|
: Parent(Parent), Current(Current) {}
|
||||||
|
explicit const_set_bits_iterator_impl(const BitVectorT &Parent)
|
||||||
|
: const_set_bits_iterator_impl(Parent, Parent.find_first()) {}
|
||||||
|
const_set_bits_iterator_impl(const const_set_bits_iterator_impl &) = default;
|
||||||
|
|
||||||
|
const_set_bits_iterator_impl operator++(int) {
|
||||||
|
auto Prev = *this;
|
||||||
|
advance();
|
||||||
|
return Prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_set_bits_iterator_impl &operator++() {
|
||||||
|
advance();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned operator*() const { return Current; }
|
||||||
|
|
||||||
|
bool operator==(const const_set_bits_iterator_impl &Other) const {
|
||||||
|
assert(&Parent == &Other.Parent &&
|
||||||
|
"Comparing iterators from different BitVectors");
|
||||||
|
return Current == Other.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const const_set_bits_iterator_impl &Other) const {
|
||||||
|
assert(&Parent == &Other.Parent &&
|
||||||
|
"Comparing iterators from different BitVectors");
|
||||||
|
return Current != Other.Current;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class BitVector {
|
class BitVector {
|
||||||
typedef unsigned long BitWord;
|
typedef unsigned long BitWord;
|
||||||
|
|
||||||
@ -73,6 +118,18 @@ class BitVector {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef const_set_bits_iterator_impl<BitVector> const_set_bits_iterator;
|
||||||
|
typedef const_set_bits_iterator set_iterator;
|
||||||
|
|
||||||
|
const_set_bits_iterator set_bits_begin() const {
|
||||||
|
return const_set_bits_iterator(*this);
|
||||||
|
}
|
||||||
|
const_set_bits_iterator set_bits_end() const {
|
||||||
|
return const_set_bits_iterator(*this, -1);
|
||||||
|
}
|
||||||
|
iterator_range<const_set_bits_iterator> set_bits() const {
|
||||||
|
return make_range(set_bits_begin(), set_bits_end());
|
||||||
|
}
|
||||||
|
|
||||||
/// BitVector default ctor - Creates an empty bitvector.
|
/// BitVector default ctor - Creates an empty bitvector.
|
||||||
BitVector() : Size(0) {}
|
BitVector() : Size(0) {}
|
||||||
@ -146,138 +203,164 @@ class BitVector {
|
|||||||
return !any();
|
return !any();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// find_first - Returns the index of the first set bit, -1 if none
|
/// find_first_in - Returns the index of the first set bit in the range
|
||||||
/// of the bits are set.
|
/// [Begin, End). Returns -1 if all bits in the range are unset.
|
||||||
int find_first() const {
|
int find_first_in(unsigned Begin, unsigned End) const {
|
||||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
assert(Begin <= End && End <= Size);
|
||||||
if (Bits[i] != 0)
|
if (Begin == End)
|
||||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
return -1;
|
||||||
|
|
||||||
|
unsigned FirstWord = Begin / BITWORD_SIZE;
|
||||||
|
unsigned LastWord = (End - 1) / BITWORD_SIZE;
|
||||||
|
|
||||||
|
// Check subsequent words.
|
||||||
|
for (unsigned i = FirstWord; i <= LastWord; ++i) {
|
||||||
|
BitWord Copy = Bits[i];
|
||||||
|
|
||||||
|
if (i == FirstWord) {
|
||||||
|
unsigned FirstBit = Begin % BITWORD_SIZE;
|
||||||
|
Copy &= maskTrailingZeros<BitWord>(FirstBit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == LastWord) {
|
||||||
|
unsigned LastBit = (End - 1) % BITWORD_SIZE;
|
||||||
|
Copy &= maskTrailingOnes<BitWord>(LastBit + 1);
|
||||||
|
}
|
||||||
|
if (Copy != 0)
|
||||||
|
return i * BITWORD_SIZE + countTrailingZeros(Copy);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// find_last_in - Returns the index of the last set bit in the range
|
||||||
|
/// [Begin, End). Returns -1 if all bits in the range are unset.
|
||||||
|
int find_last_in(unsigned Begin, unsigned End) const {
|
||||||
|
assert(Begin <= End && End <= Size);
|
||||||
|
if (Begin == End)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unsigned LastWord = (End - 1) / BITWORD_SIZE;
|
||||||
|
unsigned FirstWord = Begin / BITWORD_SIZE;
|
||||||
|
|
||||||
|
for (unsigned i = LastWord + 1; i >= FirstWord + 1; --i) {
|
||||||
|
unsigned CurrentWord = i - 1;
|
||||||
|
|
||||||
|
BitWord Copy = Bits[CurrentWord];
|
||||||
|
if (CurrentWord == LastWord) {
|
||||||
|
unsigned LastBit = (End - 1) % BITWORD_SIZE;
|
||||||
|
Copy &= maskTrailingOnes<BitWord>(LastBit + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrentWord == FirstWord) {
|
||||||
|
unsigned FirstBit = Begin % BITWORD_SIZE;
|
||||||
|
Copy &= maskTrailingZeros<BitWord>(FirstBit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Copy != 0)
|
||||||
|
return (CurrentWord + 1) * BITWORD_SIZE - countLeadingZeros(Copy) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find_first_unset_in - Returns the index of the first unset bit in the
|
||||||
|
/// range [Begin, End). Returns -1 if all bits in the range are set.
|
||||||
|
int find_first_unset_in(unsigned Begin, unsigned End) const {
|
||||||
|
assert(Begin <= End && End <= Size);
|
||||||
|
if (Begin == End)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unsigned FirstWord = Begin / BITWORD_SIZE;
|
||||||
|
unsigned LastWord = (End - 1) / BITWORD_SIZE;
|
||||||
|
|
||||||
|
// Check subsequent words.
|
||||||
|
for (unsigned i = FirstWord; i <= LastWord; ++i) {
|
||||||
|
BitWord Copy = Bits[i];
|
||||||
|
|
||||||
|
if (i == FirstWord) {
|
||||||
|
unsigned FirstBit = Begin % BITWORD_SIZE;
|
||||||
|
Copy |= maskTrailingOnes<BitWord>(FirstBit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == LastWord) {
|
||||||
|
unsigned LastBit = (End - 1) % BITWORD_SIZE;
|
||||||
|
Copy |= maskTrailingZeros<BitWord>(LastBit + 1);
|
||||||
|
}
|
||||||
|
if (Copy != ~0UL) {
|
||||||
|
unsigned Result = i * BITWORD_SIZE + countTrailingOnes(Copy);
|
||||||
|
return Result < size() ? Result : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find_last_unset_in - Returns the index of the last unset bit in the
|
||||||
|
/// range [Begin, End). Returns -1 if all bits in the range are set.
|
||||||
|
int find_last_unset_in(unsigned Begin, unsigned End) const {
|
||||||
|
assert(Begin <= End && End <= Size);
|
||||||
|
if (Begin == End)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unsigned LastWord = (End - 1) / BITWORD_SIZE;
|
||||||
|
unsigned FirstWord = Begin / BITWORD_SIZE;
|
||||||
|
|
||||||
|
for (unsigned i = LastWord + 1; i >= FirstWord + 1; --i) {
|
||||||
|
unsigned CurrentWord = i - 1;
|
||||||
|
|
||||||
|
BitWord Copy = Bits[CurrentWord];
|
||||||
|
if (CurrentWord == LastWord) {
|
||||||
|
unsigned LastBit = (End - 1) % BITWORD_SIZE;
|
||||||
|
Copy |= maskTrailingZeros<BitWord>(LastBit + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurrentWord == FirstWord) {
|
||||||
|
unsigned FirstBit = Begin % BITWORD_SIZE;
|
||||||
|
Copy |= maskTrailingOnes<BitWord>(FirstBit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Copy != ~0UL) {
|
||||||
|
unsigned Result =
|
||||||
|
(CurrentWord + 1) * BITWORD_SIZE - countLeadingOnes(Copy) - 1;
|
||||||
|
return Result < Size ? Result : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find_first - Returns the index of the first set bit, -1 if none
|
||||||
|
/// of the bits are set.
|
||||||
|
int find_first() const { return find_first_in(0, Size); }
|
||||||
|
|
||||||
/// find_last - Returns the index of the last set bit, -1 if none of the bits
|
/// find_last - Returns the index of the last set bit, -1 if none of the bits
|
||||||
/// are set.
|
/// are set.
|
||||||
int find_last() const {
|
int find_last() const { return find_last_in(0, Size); }
|
||||||
if (Size == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
unsigned N = NumBitWords(size());
|
|
||||||
assert(N > 0);
|
|
||||||
|
|
||||||
unsigned i = N - 1;
|
|
||||||
while (i > 0 && Bits[i] == BitWord(0))
|
|
||||||
--i;
|
|
||||||
|
|
||||||
return int((i + 1) * BITWORD_SIZE - countLeadingZeros(Bits[i])) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find_first_unset - Returns the index of the first unset bit, -1 if all
|
|
||||||
/// of the bits are set.
|
|
||||||
int find_first_unset() const {
|
|
||||||
for (unsigned i = 0; i < NumBitWords(size()); ++i)
|
|
||||||
if (Bits[i] != ~0UL) {
|
|
||||||
unsigned Result = i * BITWORD_SIZE + countTrailingOnes(Bits[i]);
|
|
||||||
return Result < size() ? Result : -1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find_last_unset - Returns the index of the last unset bit, -1 if all of
|
|
||||||
/// the bits are set.
|
|
||||||
int find_last_unset() const {
|
|
||||||
if (Size == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const unsigned N = NumBitWords(size());
|
|
||||||
assert(N > 0);
|
|
||||||
|
|
||||||
unsigned i = N - 1;
|
|
||||||
BitWord W = Bits[i];
|
|
||||||
|
|
||||||
// The last word in the BitVector has some unused bits, so we need to set
|
|
||||||
// them all to 1 first. Set them all to 1 so they don't get treated as
|
|
||||||
// valid unset bits.
|
|
||||||
unsigned UnusedCount = BITWORD_SIZE - size() % BITWORD_SIZE;
|
|
||||||
W |= maskLeadingOnes<BitWord>(UnusedCount);
|
|
||||||
|
|
||||||
while (W == ~BitWord(0) && --i > 0)
|
|
||||||
W = Bits[i];
|
|
||||||
|
|
||||||
return int((i + 1) * BITWORD_SIZE - countLeadingOnes(W)) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find_next - Returns the index of the next set bit following the
|
/// find_next - Returns the index of the next set bit following the
|
||||||
/// "Prev" bit. Returns -1 if the next set bit is not found.
|
/// "Prev" bit. Returns -1 if the next set bit is not found.
|
||||||
int find_next(unsigned Prev) const {
|
int find_next(unsigned Prev) const { return find_first_in(Prev + 1, Size); }
|
||||||
++Prev;
|
|
||||||
if (Prev >= Size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
unsigned WordPos = Prev / BITWORD_SIZE;
|
/// find_prev - Returns the index of the first set bit that precedes the
|
||||||
unsigned BitPos = Prev % BITWORD_SIZE;
|
/// the bit at \p PriorTo. Returns -1 if all previous bits are unset.
|
||||||
BitWord Copy = Bits[WordPos];
|
int find_prev(unsigned PriorTo) const { return find_last_in(0, PriorTo); }
|
||||||
// Mask off previous bits.
|
|
||||||
Copy &= maskTrailingZeros<BitWord>(BitPos);
|
|
||||||
|
|
||||||
if (Copy != 0)
|
/// find_first_unset - Returns the index of the first unset bit, -1 if all
|
||||||
return WordPos * BITWORD_SIZE + countTrailingZeros(Copy);
|
/// of the bits are set.
|
||||||
|
int find_first_unset() const { return find_first_unset_in(0, Size); }
|
||||||
// Check subsequent words.
|
|
||||||
for (unsigned i = WordPos+1; i < NumBitWords(size()); ++i)
|
|
||||||
if (Bits[i] != 0)
|
|
||||||
return i * BITWORD_SIZE + countTrailingZeros(Bits[i]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// find_next_unset - Returns the index of the next unset bit following the
|
/// find_next_unset - Returns the index of the next unset bit following the
|
||||||
/// "Prev" bit. Returns -1 if all remaining bits are set.
|
/// "Prev" bit. Returns -1 if all remaining bits are set.
|
||||||
int find_next_unset(unsigned Prev) const {
|
int find_next_unset(unsigned Prev) const {
|
||||||
++Prev;
|
return find_first_unset_in(Prev + 1, Size);
|
||||||
if (Prev >= Size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
unsigned WordPos = Prev / BITWORD_SIZE;
|
|
||||||
unsigned BitPos = Prev % BITWORD_SIZE;
|
|
||||||
BitWord Copy = Bits[WordPos];
|
|
||||||
// Mask in previous bits.
|
|
||||||
BitWord Mask = (1 << BitPos) - 1;
|
|
||||||
Copy |= Mask;
|
|
||||||
|
|
||||||
if (Copy != ~0UL)
|
|
||||||
return next_unset_in_word(WordPos, Copy);
|
|
||||||
|
|
||||||
// Check subsequent words.
|
|
||||||
for (unsigned i = WordPos + 1; i < NumBitWords(size()); ++i)
|
|
||||||
if (Bits[i] != ~0UL)
|
|
||||||
return next_unset_in_word(i, Bits[i]);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// find_prev - Returns the index of the first set bit that precedes the
|
/// find_last_unset - Returns the index of the last unset bit, -1 if all of
|
||||||
/// the bit at \p PriorTo. Returns -1 if all previous bits are unset.
|
/// the bits are set.
|
||||||
int find_prev(unsigned PriorTo) const {
|
int find_last_unset() const { return find_last_unset_in(0, Size); }
|
||||||
if (PriorTo == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
--PriorTo;
|
/// find_prev_unset - Returns the index of the first unset bit that precedes
|
||||||
|
/// the bit at \p PriorTo. Returns -1 if all previous bits are set.
|
||||||
unsigned WordPos = PriorTo / BITWORD_SIZE;
|
int find_prev_unset(unsigned PriorTo) {
|
||||||
unsigned BitPos = PriorTo % BITWORD_SIZE;
|
return find_last_unset_in(0, PriorTo);
|
||||||
BitWord Copy = Bits[WordPos];
|
|
||||||
// Mask off next bits.
|
|
||||||
Copy &= maskTrailingOnes<BitWord>(BitPos + 1);
|
|
||||||
|
|
||||||
if (Copy != 0)
|
|
||||||
return (WordPos + 1) * BITWORD_SIZE - countLeadingZeros(Copy) - 1;
|
|
||||||
|
|
||||||
// Check previous words.
|
|
||||||
for (unsigned i = 1; i <= WordPos; ++i) {
|
|
||||||
unsigned Index = WordPos - i;
|
|
||||||
if (Bits[Index] == 0)
|
|
||||||
continue;
|
|
||||||
return (Index + 1) * BITWORD_SIZE - countLeadingZeros(Bits[Index]) - 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// clear - Removes all bits from the bitvector. Does not change capacity.
|
/// clear - Removes all bits from the bitvector. Does not change capacity.
|
||||||
|
@ -96,24 +96,14 @@ template <class GraphT,
|
|||||||
class po_iterator
|
class po_iterator
|
||||||
: public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>,
|
: public std::iterator<std::forward_iterator_tag, typename GT::NodeRef>,
|
||||||
public po_iterator_storage<SetType, ExtStorage> {
|
public po_iterator_storage<SetType, ExtStorage> {
|
||||||
typedef std::iterator<std::forward_iterator_tag, typename GT::NodeRef> super;
|
using super = std::iterator<std::forward_iterator_tag, typename GT::NodeRef>;
|
||||||
typedef typename GT::NodeRef NodeRef;
|
using NodeRef = typename GT::NodeRef;
|
||||||
typedef typename GT::ChildIteratorType ChildItTy;
|
using ChildItTy = typename GT::ChildIteratorType;
|
||||||
|
|
||||||
// VisitStack - Used to maintain the ordering. Top = current block
|
// VisitStack - Used to maintain the ordering. Top = current block
|
||||||
// First element is basic block pointer, second is the 'next child' to visit
|
// First element is basic block pointer, second is the 'next child' to visit
|
||||||
std::vector<std::pair<NodeRef, ChildItTy>> VisitStack;
|
std::vector<std::pair<NodeRef, ChildItTy>> VisitStack;
|
||||||
|
|
||||||
void traverseChild() {
|
|
||||||
while (VisitStack.back().second != GT::child_end(VisitStack.back().first)) {
|
|
||||||
NodeRef BB = *VisitStack.back().second++;
|
|
||||||
if (this->insertEdge(Optional<NodeRef>(VisitStack.back().first), BB)) {
|
|
||||||
// If the block is not visited...
|
|
||||||
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
po_iterator(NodeRef BB) {
|
po_iterator(NodeRef BB) {
|
||||||
this->insertEdge(Optional<NodeRef>(), BB);
|
this->insertEdge(Optional<NodeRef>(), BB);
|
||||||
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||||
@ -134,8 +124,18 @@ class po_iterator
|
|||||||
: po_iterator_storage<SetType, ExtStorage>(S) {
|
: po_iterator_storage<SetType, ExtStorage>(S) {
|
||||||
} // End is when stack is empty.
|
} // End is when stack is empty.
|
||||||
|
|
||||||
|
void traverseChild() {
|
||||||
|
while (VisitStack.back().second != GT::child_end(VisitStack.back().first)) {
|
||||||
|
NodeRef BB = *VisitStack.back().second++;
|
||||||
|
if (this->insertEdge(Optional<NodeRef>(VisitStack.back().first), BB)) {
|
||||||
|
// If the block is not visited...
|
||||||
|
VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename super::pointer pointer;
|
using pointer = typename super::pointer;
|
||||||
|
|
||||||
// Provide static "constructors"...
|
// Provide static "constructors"...
|
||||||
static po_iterator begin(GraphT G) {
|
static po_iterator begin(GraphT G) {
|
||||||
@ -286,7 +286,8 @@ inverse_post_order_ext(const T &G, SetType &S) {
|
|||||||
|
|
||||||
template<class GraphT, class GT = GraphTraits<GraphT>>
|
template<class GraphT, class GT = GraphTraits<GraphT>>
|
||||||
class ReversePostOrderTraversal {
|
class ReversePostOrderTraversal {
|
||||||
typedef typename GT::NodeRef NodeRef;
|
using NodeRef = typename GT::NodeRef;
|
||||||
|
|
||||||
std::vector<NodeRef> Blocks; // Block list in normal PO order
|
std::vector<NodeRef> Blocks; // Block list in normal PO order
|
||||||
|
|
||||||
void Initialize(NodeRef BB) {
|
void Initialize(NodeRef BB) {
|
||||||
@ -294,7 +295,7 @@ class ReversePostOrderTraversal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename std::vector<NodeRef>::reverse_iterator rpo_iterator;
|
using rpo_iterator = typename std::vector<NodeRef>::reverse_iterator;
|
||||||
|
|
||||||
ReversePostOrderTraversal(GraphT G) { Initialize(GT::getEntryNode(G)); }
|
ReversePostOrderTraversal(GraphT G) { Initialize(GT::getEntryNode(G)); }
|
||||||
|
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
#define LLVM_ADT_PRIORITYWORKLIST_H
|
#define LLVM_ADT_PRIORITYWORKLIST_H
|
||||||
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
|
||||||
#include "llvm/ADT/Sequence.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -55,11 +56,11 @@ template <typename T, typename VectorT = std::vector<T>,
|
|||||||
typename MapT = DenseMap<T, ptrdiff_t>>
|
typename MapT = DenseMap<T, ptrdiff_t>>
|
||||||
class PriorityWorklist {
|
class PriorityWorklist {
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
using value_type = T;
|
||||||
typedef T key_type;
|
using key_type = T;
|
||||||
typedef T& reference;
|
using reference = T&;
|
||||||
typedef const T& const_reference;
|
using const_reference = const T&;
|
||||||
typedef typename MapT::size_type size_type;
|
using size_type = typename MapT::size_type;
|
||||||
|
|
||||||
/// Construct an empty PriorityWorklist
|
/// Construct an empty PriorityWorklist
|
||||||
PriorityWorklist() = default;
|
PriorityWorklist() = default;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===---- ADT/SCCIterator.h - Strongly Connected Comp. Iter. ----*- C++ -*-===//
|
//===- ADT/SCCIterator.h - Strongly Connected Comp. Iter. -------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -43,10 +43,10 @@ template <class GraphT, class GT = GraphTraits<GraphT>>
|
|||||||
class scc_iterator : public iterator_facade_base<
|
class scc_iterator : public iterator_facade_base<
|
||||||
scc_iterator<GraphT, GT>, std::forward_iterator_tag,
|
scc_iterator<GraphT, GT>, std::forward_iterator_tag,
|
||||||
const std::vector<typename GT::NodeRef>, ptrdiff_t> {
|
const std::vector<typename GT::NodeRef>, ptrdiff_t> {
|
||||||
typedef typename GT::NodeRef NodeRef;
|
using NodeRef = typename GT::NodeRef;
|
||||||
typedef typename GT::ChildIteratorType ChildItTy;
|
using ChildItTy = typename GT::ChildIteratorType;
|
||||||
typedef std::vector<NodeRef> SccTy;
|
using SccTy = std::vector<NodeRef>;
|
||||||
typedef typename scc_iterator::reference reference;
|
using reference = typename scc_iterator::reference;
|
||||||
|
|
||||||
/// Element of VisitStack during DFS.
|
/// Element of VisitStack during DFS.
|
||||||
struct StackElement {
|
struct StackElement {
|
||||||
|
@ -13,27 +13,31 @@
|
|||||||
///
|
///
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef LLVM_ADT_SEQ_H
|
#ifndef LLVM_ADT_SEQUENCE_H
|
||||||
#define LLVM_ADT_SEQ_H
|
#define LLVM_ADT_SEQUENCE_H
|
||||||
|
|
||||||
#include "llvm/ADT/iterator.h"
|
#include "llvm/ADT/iterator.h"
|
||||||
#include "llvm/ADT/iterator_range.h"
|
#include "llvm/ADT/iterator_range.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
class value_sequence_iterator
|
class value_sequence_iterator
|
||||||
: public iterator_facade_base<value_sequence_iterator<ValueT>,
|
: public iterator_facade_base<value_sequence_iterator<ValueT>,
|
||||||
std::random_access_iterator_tag,
|
std::random_access_iterator_tag,
|
||||||
const ValueT> {
|
const ValueT> {
|
||||||
typedef typename value_sequence_iterator::iterator_facade_base BaseT;
|
using BaseT = typename value_sequence_iterator::iterator_facade_base;
|
||||||
|
|
||||||
ValueT Value;
|
ValueT Value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename BaseT::difference_type difference_type;
|
using difference_type = typename BaseT::difference_type;
|
||||||
typedef typename BaseT::reference reference;
|
using reference = typename BaseT::reference;
|
||||||
|
|
||||||
value_sequence_iterator() = default;
|
value_sequence_iterator() = default;
|
||||||
value_sequence_iterator(const value_sequence_iterator &) = default;
|
value_sequence_iterator(const value_sequence_iterator &) = default;
|
||||||
@ -65,7 +69,8 @@ class value_sequence_iterator
|
|||||||
|
|
||||||
reference operator*() const { return Value; }
|
reference operator*() const { return Value; }
|
||||||
};
|
};
|
||||||
} // End detail namespace.
|
|
||||||
|
} // end namespace detail
|
||||||
|
|
||||||
template <typename ValueT>
|
template <typename ValueT>
|
||||||
iterator_range<detail::value_sequence_iterator<ValueT>> seq(ValueT Begin,
|
iterator_range<detail::value_sequence_iterator<ValueT>> seq(ValueT Begin,
|
||||||
@ -74,6 +79,6 @@ iterator_range<detail::value_sequence_iterator<ValueT>> seq(ValueT Begin,
|
|||||||
detail::value_sequence_iterator<ValueT>(End));
|
detail::value_sequence_iterator<ValueT>(End));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif
|
#endif // LLVM_ADT_SEQUENCE_H
|
||||||
|
@ -40,17 +40,17 @@ template <typename T, typename Vector = std::vector<T>,
|
|||||||
typename Set = DenseSet<T>>
|
typename Set = DenseSet<T>>
|
||||||
class SetVector {
|
class SetVector {
|
||||||
public:
|
public:
|
||||||
typedef T value_type;
|
using value_type = T;
|
||||||
typedef T key_type;
|
using key_type = T;
|
||||||
typedef T& reference;
|
using reference = T&;
|
||||||
typedef const T& const_reference;
|
using const_reference = const T&;
|
||||||
typedef Set set_type;
|
using set_type = Set;
|
||||||
typedef Vector vector_type;
|
using vector_type = Vector;
|
||||||
typedef typename vector_type::const_iterator iterator;
|
using iterator = typename vector_type::const_iterator;
|
||||||
typedef typename vector_type::const_iterator const_iterator;
|
using const_iterator = typename vector_type::const_iterator;
|
||||||
typedef typename vector_type::const_reverse_iterator reverse_iterator;
|
using reverse_iterator = typename vector_type::const_reverse_iterator;
|
||||||
typedef typename vector_type::const_reverse_iterator const_reverse_iterator;
|
using const_reverse_iterator = typename vector_type::const_reverse_iterator;
|
||||||
typedef typename vector_type::size_type size_type;
|
using size_type = typename vector_type::size_type;
|
||||||
|
|
||||||
/// \brief Construct an empty SetVector
|
/// \brief Construct an empty SetVector
|
||||||
SetVector() = default;
|
SetVector() = default;
|
||||||
|
@ -134,6 +134,19 @@ class SmallBitVector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef const_set_bits_iterator_impl<SmallBitVector> const_set_bits_iterator;
|
||||||
|
typedef const_set_bits_iterator set_iterator;
|
||||||
|
|
||||||
|
const_set_bits_iterator set_bits_begin() const {
|
||||||
|
return const_set_bits_iterator(*this);
|
||||||
|
}
|
||||||
|
const_set_bits_iterator set_bits_end() const {
|
||||||
|
return const_set_bits_iterator(*this, -1);
|
||||||
|
}
|
||||||
|
iterator_range<const_set_bits_iterator> set_bits() const {
|
||||||
|
return make_range(set_bits_begin(), set_bits_end());
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates an empty bitvector.
|
/// Creates an empty bitvector.
|
||||||
SmallBitVector() : X(1) {}
|
SmallBitVector() : X(1) {}
|
||||||
|
|
||||||
|
@ -27,15 +27,13 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||||
template <class T = void> struct ReverseIterate { static bool value; };
|
template <class T = void> struct ReverseIterate { static bool value; };
|
||||||
template <class T> bool ReverseIterate<T>::value = false;
|
template <class T> bool ReverseIterate<T>::value = false;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
|
|
||||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||||
/// for small and one for large sets.
|
/// for small and one for large sets.
|
||||||
@ -92,7 +90,7 @@ class SmallPtrSetImplBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef unsigned size_type;
|
using size_type = unsigned;
|
||||||
|
|
||||||
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
|
SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
|
||||||
|
|
||||||
@ -273,14 +271,14 @@ class SmallPtrSetIteratorImpl {
|
|||||||
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
||||||
template<typename PtrTy>
|
template<typename PtrTy>
|
||||||
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
||||||
typedef PointerLikeTypeTraits<PtrTy> PtrTraits;
|
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef PtrTy value_type;
|
using value_type = PtrTy;
|
||||||
typedef PtrTy reference;
|
using reference = PtrTy;
|
||||||
typedef PtrTy pointer;
|
using pointer = PtrTy;
|
||||||
typedef std::ptrdiff_t difference_type;
|
using difference_type = std::ptrdiff_t;
|
||||||
typedef std::forward_iterator_tag iterator_category;
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
|
||||||
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
|
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
|
||||||
: SmallPtrSetIteratorImpl(BP, E) {}
|
: SmallPtrSetIteratorImpl(BP, E) {}
|
||||||
@ -351,8 +349,8 @@ struct RoundUpToPowerOfTwo {
|
|||||||
template <typename PtrType>
|
template <typename PtrType>
|
||||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||||
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
|
using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
|
||||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
using PtrTraits = PointerLikeTypeTraits<PtrType>;
|
||||||
typedef PointerLikeTypeTraits<ConstPtrType> ConstPtrTraits;
|
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Constructors that forward to the base.
|
// Constructors that forward to the base.
|
||||||
@ -365,8 +363,8 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
|||||||
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
|
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef SmallPtrSetIterator<PtrType> iterator;
|
using iterator = SmallPtrSetIterator<PtrType>;
|
||||||
typedef SmallPtrSetIterator<PtrType> const_iterator;
|
using const_iterator = SmallPtrSetIterator<PtrType>;
|
||||||
|
|
||||||
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
|
SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
|
||||||
|
|
||||||
@ -431,7 +429,7 @@ class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
|||||||
// DenseSet<> instead if you expect many elements in the set.
|
// DenseSet<> instead if you expect many elements in the set.
|
||||||
static_assert(SmallSize <= 32, "SmallSize should be small");
|
static_assert(SmallSize <= 32, "SmallSize should be small");
|
||||||
|
|
||||||
typedef SmallPtrSetImpl<PtrType> BaseT;
|
using BaseT = SmallPtrSetImpl<PtrType>;
|
||||||
|
|
||||||
// Make sure that SmallSize is a power of two, round up if not.
|
// Make sure that SmallSize is a power of two, round up if not.
|
||||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||||
|
@ -71,7 +71,7 @@ class SmallVectorTemplateCommon : public SmallVectorBase {
|
|||||||
// Allocate raw space for N elements of type T. If T has a ctor or dtor, we
|
// Allocate raw space for N elements of type T. If T has a ctor or dtor, we
|
||||||
// don't want it to be automatically run, so we need to represent the space as
|
// don't want it to be automatically run, so we need to represent the space as
|
||||||
// something else. Use an array of char of sufficient alignment.
|
// something else. Use an array of char of sufficient alignment.
|
||||||
typedef AlignedCharArrayUnion<T> U;
|
using U = AlignedCharArrayUnion<T>;
|
||||||
U FirstEl;
|
U FirstEl;
|
||||||
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
|
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.
|
||||||
|
|
||||||
@ -96,19 +96,19 @@ class SmallVectorTemplateCommon : public SmallVectorBase {
|
|||||||
void setEnd(T *P) { this->EndX = P; }
|
void setEnd(T *P) { this->EndX = P; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef size_t size_type;
|
using size_type = size_t;
|
||||||
typedef ptrdiff_t difference_type;
|
using difference_type = ptrdiff_t;
|
||||||
typedef T value_type;
|
using value_type = T;
|
||||||
typedef T *iterator;
|
using iterator = T *;
|
||||||
typedef const T *const_iterator;
|
using const_iterator = const T *;
|
||||||
|
|
||||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
|
||||||
typedef T &reference;
|
using reference = T &;
|
||||||
typedef const T &const_reference;
|
using const_reference = const T &;
|
||||||
typedef T *pointer;
|
using pointer = T *;
|
||||||
typedef const T *const_pointer;
|
using const_pointer = const T *;
|
||||||
|
|
||||||
// forward iterator creation methods.
|
// forward iterator creation methods.
|
||||||
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
||||||
@ -319,12 +319,12 @@ class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
|
|||||||
/// reduce code duplication based on the SmallVector 'N' template parameter.
|
/// reduce code duplication based on the SmallVector 'N' template parameter.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
|
||||||
typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
|
using SuperClass = SmallVectorTemplateBase<T, isPodLike<T>::value>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename SuperClass::iterator iterator;
|
using iterator = typename SuperClass::iterator;
|
||||||
typedef typename SuperClass::const_iterator const_iterator;
|
using const_iterator = typename SuperClass::const_iterator;
|
||||||
typedef typename SuperClass::size_type size_type;
|
using size_type = typename SuperClass::size_type;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Default ctor - Initialize to empty.
|
// Default ctor - Initialize to empty.
|
||||||
@ -845,8 +845,7 @@ class SmallVector : public SmallVectorImpl<T> {
|
|||||||
SmallVectorStorage<T, N> Storage;
|
SmallVectorStorage<T, N> Storage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SmallVector() : SmallVectorImpl<T>(N) {
|
SmallVector() : SmallVectorImpl<T>(N) {}
|
||||||
}
|
|
||||||
|
|
||||||
explicit SmallVector(size_t Size, const T &Value = T())
|
explicit SmallVector(size_t Size, const T &Value = T())
|
||||||
: SmallVectorImpl<T>(N) {
|
: SmallVectorImpl<T>(N) {
|
||||||
@ -883,16 +882,16 @@ class SmallVector : public SmallVectorImpl<T> {
|
|||||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||||
}
|
}
|
||||||
|
|
||||||
const SmallVector &operator=(SmallVector &&RHS) {
|
|
||||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
|
SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
|
||||||
if (!RHS.empty())
|
if (!RHS.empty())
|
||||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SmallVector &operator=(SmallVector &&RHS) {
|
||||||
|
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
|
const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
|
||||||
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
SmallVectorImpl<T>::operator=(::std::move(RHS));
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===- llvm/ADT/SparseBitVector.h - Efficient Sparse BitVector -*- C++ -*- ===//
|
//===- llvm/ADT/SparseBitVector.h - Efficient Sparse BitVector --*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -41,8 +41,8 @@ namespace llvm {
|
|||||||
|
|
||||||
template <unsigned ElementSize = 128> struct SparseBitVectorElement {
|
template <unsigned ElementSize = 128> struct SparseBitVectorElement {
|
||||||
public:
|
public:
|
||||||
typedef unsigned long BitWord;
|
using BitWord = unsigned long;
|
||||||
typedef unsigned size_type;
|
using size_type = unsigned;
|
||||||
enum {
|
enum {
|
||||||
BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT,
|
BITWORD_SIZE = sizeof(BitWord) * CHAR_BIT,
|
||||||
BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE,
|
BITWORDS_PER_ELEMENT = (ElementSize + BITWORD_SIZE - 1) / BITWORD_SIZE,
|
||||||
@ -100,7 +100,7 @@ template <unsigned ElementSize = 128> struct SparseBitVectorElement {
|
|||||||
Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE);
|
Bits[Idx / BITWORD_SIZE] |= 1L << (Idx % BITWORD_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool test_and_set (unsigned Idx) {
|
bool test_and_set(unsigned Idx) {
|
||||||
bool old = test(Idx);
|
bool old = test(Idx);
|
||||||
if (!old) {
|
if (!old) {
|
||||||
set(Idx);
|
set(Idx);
|
||||||
@ -254,9 +254,9 @@ template <unsigned ElementSize = 128> struct SparseBitVectorElement {
|
|||||||
|
|
||||||
template <unsigned ElementSize = 128>
|
template <unsigned ElementSize = 128>
|
||||||
class SparseBitVector {
|
class SparseBitVector {
|
||||||
typedef std::list<SparseBitVectorElement<ElementSize>> ElementList;
|
using ElementList = std::list<SparseBitVectorElement<ElementSize>>;
|
||||||
typedef typename ElementList::iterator ElementListIter;
|
using ElementListIter = typename ElementList::iterator;
|
||||||
typedef typename ElementList::const_iterator ElementListConstIter;
|
using ElementListConstIter = typename ElementList::const_iterator;
|
||||||
enum {
|
enum {
|
||||||
BITWORD_SIZE = SparseBitVectorElement<ElementSize>::BITWORD_SIZE
|
BITWORD_SIZE = SparseBitVectorElement<ElementSize>::BITWORD_SIZE
|
||||||
};
|
};
|
||||||
@ -421,14 +421,12 @@ class SparseBitVector {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef SparseBitVectorIterator iterator;
|
using iterator = SparseBitVectorIterator;
|
||||||
|
|
||||||
SparseBitVector() {
|
SparseBitVector() {
|
||||||
CurrElementIter = Elements.begin();
|
CurrElementIter = Elements.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
~SparseBitVector() = default;
|
|
||||||
|
|
||||||
// SparseBitVector copy ctor.
|
// SparseBitVector copy ctor.
|
||||||
SparseBitVector(const SparseBitVector &RHS) {
|
SparseBitVector(const SparseBitVector &RHS) {
|
||||||
ElementListConstIter ElementIter = RHS.Elements.begin();
|
ElementListConstIter ElementIter = RHS.Elements.begin();
|
||||||
@ -440,6 +438,8 @@ class SparseBitVector {
|
|||||||
CurrElementIter = Elements.begin ();
|
CurrElementIter = Elements.begin ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~SparseBitVector() = default;
|
||||||
|
|
||||||
// Clear.
|
// Clear.
|
||||||
void clear() {
|
void clear() {
|
||||||
Elements.clear();
|
Elements.clear();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===--- llvm/ADT/SparseMultiSet.h - Sparse multiset ------------*- C++ -*-===//
|
//===- llvm/ADT/SparseMultiSet.h - Sparse multiset --------------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -101,7 +101,7 @@ class SparseMultiSet {
|
|||||||
unsigned Prev;
|
unsigned Prev;
|
||||||
unsigned Next;
|
unsigned Next;
|
||||||
|
|
||||||
SMSNode(ValueT D, unsigned P, unsigned N) : Data(D), Prev(P), Next(N) { }
|
SMSNode(ValueT D, unsigned P, unsigned N) : Data(D), Prev(P), Next(N) {}
|
||||||
|
|
||||||
/// List tails have invalid Nexts.
|
/// List tails have invalid Nexts.
|
||||||
bool isTail() const {
|
bool isTail() const {
|
||||||
@ -118,8 +118,8 @@ class SparseMultiSet {
|
|||||||
bool isValid() const { return Prev != INVALID; }
|
bool isValid() const { return Prev != INVALID; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef typename KeyFunctorT::argument_type KeyT;
|
using KeyT = typename KeyFunctorT::argument_type;
|
||||||
typedef SmallVector<SMSNode, 8> DenseT;
|
using DenseT = SmallVector<SMSNode, 8>;
|
||||||
DenseT Dense;
|
DenseT Dense;
|
||||||
SparseT *Sparse = nullptr;
|
SparseT *Sparse = nullptr;
|
||||||
unsigned Universe = 0;
|
unsigned Universe = 0;
|
||||||
@ -183,12 +183,12 @@ class SparseMultiSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ValueT value_type;
|
using value_type = ValueT;
|
||||||
typedef ValueT &reference;
|
using reference = ValueT &;
|
||||||
typedef const ValueT &const_reference;
|
using const_reference = const ValueT &;
|
||||||
typedef ValueT *pointer;
|
using pointer = ValueT *;
|
||||||
typedef const ValueT *const_pointer;
|
using const_pointer = const ValueT *;
|
||||||
typedef unsigned size_type;
|
using size_type = unsigned;
|
||||||
|
|
||||||
SparseMultiSet() = default;
|
SparseMultiSet() = default;
|
||||||
SparseMultiSet(const SparseMultiSet &) = delete;
|
SparseMultiSet(const SparseMultiSet &) = delete;
|
||||||
@ -227,7 +227,7 @@ class SparseMultiSet {
|
|||||||
unsigned SparseIdx;
|
unsigned SparseIdx;
|
||||||
|
|
||||||
iterator_base(SMSPtrTy P, unsigned I, unsigned SI)
|
iterator_base(SMSPtrTy P, unsigned I, unsigned SI)
|
||||||
: SMS(P), Idx(I), SparseIdx(SI) { }
|
: SMS(P), Idx(I), SparseIdx(SI) {}
|
||||||
|
|
||||||
/// Whether our iterator has fallen outside our dense vector.
|
/// Whether our iterator has fallen outside our dense vector.
|
||||||
bool isEnd() const {
|
bool isEnd() const {
|
||||||
@ -248,11 +248,11 @@ class SparseMultiSet {
|
|||||||
void setNext(unsigned N) { SMS->Dense[Idx].Next = N; }
|
void setNext(unsigned N) { SMS->Dense[Idx].Next = N; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::iterator<std::bidirectional_iterator_tag, ValueT> super;
|
using super = std::iterator<std::bidirectional_iterator_tag, ValueT>;
|
||||||
typedef typename super::value_type value_type;
|
using value_type = typename super::value_type;
|
||||||
typedef typename super::difference_type difference_type;
|
using difference_type = typename super::difference_type;
|
||||||
typedef typename super::pointer pointer;
|
using pointer = typename super::pointer;
|
||||||
typedef typename super::reference reference;
|
using reference = typename super::reference;
|
||||||
|
|
||||||
reference operator*() const {
|
reference operator*() const {
|
||||||
assert(isKeyed() && SMS->sparseIndex(SMS->Dense[Idx].Data) == SparseIdx &&
|
assert(isKeyed() && SMS->sparseIndex(SMS->Dense[Idx].Data) == SparseIdx &&
|
||||||
@ -308,11 +308,12 @@ class SparseMultiSet {
|
|||||||
return I;
|
return I;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef iterator_base<SparseMultiSet *> iterator;
|
|
||||||
typedef iterator_base<const SparseMultiSet *> const_iterator;
|
using iterator = iterator_base<SparseMultiSet *>;
|
||||||
|
using const_iterator = iterator_base<const SparseMultiSet *>;
|
||||||
|
|
||||||
// Convenience types
|
// Convenience types
|
||||||
typedef std::pair<iterator, iterator> RangePair;
|
using RangePair = std::pair<iterator, iterator>;
|
||||||
|
|
||||||
/// Returns an iterator past this container. Note that such an iterator cannot
|
/// Returns an iterator past this container. Note that such an iterator cannot
|
||||||
/// be decremented, but will compare equal to other end iterators.
|
/// be decremented, but will compare equal to other end iterators.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===--- llvm/ADT/SparseSet.h - Sparse set ----------------------*- C++ -*-===//
|
//===- llvm/ADT/SparseSet.h - Sparse set ------------------------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -125,9 +125,9 @@ class SparseSet {
|
|||||||
!std::numeric_limits<SparseT>::is_signed,
|
!std::numeric_limits<SparseT>::is_signed,
|
||||||
"SparseT must be an unsigned integer type");
|
"SparseT must be an unsigned integer type");
|
||||||
|
|
||||||
typedef typename KeyFunctorT::argument_type KeyT;
|
using KeyT = typename KeyFunctorT::argument_type;
|
||||||
typedef SmallVector<ValueT, 8> DenseT;
|
using DenseT = SmallVector<ValueT, 8>;
|
||||||
typedef unsigned size_type;
|
using size_type = unsigned;
|
||||||
DenseT Dense;
|
DenseT Dense;
|
||||||
SparseT *Sparse = nullptr;
|
SparseT *Sparse = nullptr;
|
||||||
unsigned Universe = 0;
|
unsigned Universe = 0;
|
||||||
@ -135,11 +135,11 @@ class SparseSet {
|
|||||||
SparseSetValFunctor<KeyT, ValueT, KeyFunctorT> ValIndexOf;
|
SparseSetValFunctor<KeyT, ValueT, KeyFunctorT> ValIndexOf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ValueT value_type;
|
using value_type = ValueT;
|
||||||
typedef ValueT &reference;
|
using reference = ValueT &;
|
||||||
typedef const ValueT &const_reference;
|
using const_reference = const ValueT &;
|
||||||
typedef ValueT *pointer;
|
using pointer = ValueT *;
|
||||||
typedef const ValueT *const_pointer;
|
using const_pointer = const ValueT *;
|
||||||
|
|
||||||
SparseSet() = default;
|
SparseSet() = default;
|
||||||
SparseSet(const SparseSet &) = delete;
|
SparseSet(const SparseSet &) = delete;
|
||||||
@ -168,8 +168,8 @@ class SparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Import trivial vector stuff from DenseT.
|
// Import trivial vector stuff from DenseT.
|
||||||
typedef typename DenseT::iterator iterator;
|
using iterator = typename DenseT::iterator;
|
||||||
typedef typename DenseT::const_iterator const_iterator;
|
using const_iterator = typename DenseT::const_iterator;
|
||||||
|
|
||||||
const_iterator begin() const { return Dense.begin(); }
|
const_iterator begin() const { return Dense.begin(); }
|
||||||
const_iterator end() const { return Dense.end(); }
|
const_iterator end() const { return Dense.end(); }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===-- llvm/ADT/StringExtras.h - Useful string functions -------*- C++ -*-===//
|
//===- llvm/ADT/StringExtras.h - Useful string functions --------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -15,12 +15,18 @@
|
|||||||
#define LLVM_ADT_STRINGEXTRAS_H
|
#define LLVM_ADT_STRINGEXTRAS_H
|
||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Support/DataTypes.h"
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class raw_ostream;
|
|
||||||
template<typename T> class SmallVectorImpl;
|
template<typename T> class SmallVectorImpl;
|
||||||
|
class raw_ostream;
|
||||||
|
|
||||||
/// hexdigit - Return the hexadecimal character for the
|
/// hexdigit - Return the hexadecimal character for the
|
||||||
/// given number \p X (which should be less than 16).
|
/// given number \p X (which should be less than 16).
|
||||||
@ -128,7 +134,6 @@ static inline std::string utostr(uint64_t X, bool isNeg = false) {
|
|||||||
return std::string(BufPtr, std::end(Buffer));
|
return std::string(BufPtr, std::end(Buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline std::string itostr(int64_t X) {
|
static inline std::string itostr(int64_t X) {
|
||||||
if (X < 0)
|
if (X < 0)
|
||||||
return utostr(static_cast<uint64_t>(-X), true);
|
return utostr(static_cast<uint64_t>(-X), true);
|
||||||
@ -261,13 +266,14 @@ template <typename A1, typename... Args>
|
|||||||
inline size_t join_items_size(const A1 &A, Args &&... Items) {
|
inline size_t join_items_size(const A1 &A, Args &&... Items) {
|
||||||
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
|
return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // end namespace detail
|
||||||
|
|
||||||
/// Joins the strings in the range [Begin, End), adding Separator between
|
/// Joins the strings in the range [Begin, End), adding Separator between
|
||||||
/// the elements.
|
/// the elements.
|
||||||
template <typename IteratorT>
|
template <typename IteratorT>
|
||||||
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
|
inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) {
|
||||||
typedef typename std::iterator_traits<IteratorT>::iterator_category tag;
|
using tag = typename std::iterator_traits<IteratorT>::iterator_category;
|
||||||
return detail::join_impl(Begin, End, Separator, tag());
|
return detail::join_impl(Begin, End, Separator, tag());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +301,6 @@ inline std::string join_items(Sep Separator, Args &&... Items) {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End llvm namespace
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif
|
#endif // LLVM_ADT_STRINGEXTRAS_H
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===--- StringMap.h - String Hash table map interface ----------*- C++ -*-===//
|
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -16,25 +16,23 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ADT/iterator.h"
|
#include "llvm/ADT/iterator.h"
|
||||||
|
#include "llvm/ADT/iterator_range.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <new>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
template<typename ValueT>
|
template<typename ValueTy> class StringMapConstIterator;
|
||||||
class StringMapConstIterator;
|
template<typename ValueTy> class StringMapIterator;
|
||||||
template<typename ValueT>
|
template<typename ValueTy> class StringMapKeyIterator;
|
||||||
class StringMapIterator;
|
|
||||||
template <typename ValueT> class StringMapKeyIterator;
|
|
||||||
template<typename ValueTy>
|
|
||||||
class StringMapEntry;
|
|
||||||
|
|
||||||
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
/// StringMapEntryBase - Shared base class of StringMapEntry instances.
|
||||||
class StringMapEntryBase {
|
class StringMapEntryBase {
|
||||||
@ -53,17 +51,15 @@ class StringMapImpl {
|
|||||||
// Array of NumBuckets pointers to entries, null pointers are holes.
|
// Array of NumBuckets pointers to entries, null pointers are holes.
|
||||||
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
|
// TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed
|
||||||
// by an array of the actual hash values as unsigned integers.
|
// by an array of the actual hash values as unsigned integers.
|
||||||
StringMapEntryBase **TheTable;
|
StringMapEntryBase **TheTable = nullptr;
|
||||||
unsigned NumBuckets;
|
unsigned NumBuckets = 0;
|
||||||
unsigned NumItems;
|
unsigned NumItems = 0;
|
||||||
unsigned NumTombstones;
|
unsigned NumTombstones = 0;
|
||||||
unsigned ItemSize;
|
unsigned ItemSize;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit StringMapImpl(unsigned itemSize)
|
explicit StringMapImpl(unsigned itemSize)
|
||||||
: TheTable(nullptr),
|
: ItemSize(itemSize) {}
|
||||||
// Initialize the map with zero buckets to allocation.
|
|
||||||
NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {}
|
|
||||||
StringMapImpl(StringMapImpl &&RHS)
|
StringMapImpl(StringMapImpl &&RHS)
|
||||||
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
|
||||||
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
|
||||||
@ -225,9 +221,10 @@ class StringMap : public StringMapImpl {
|
|||||||
AllocatorTy Allocator;
|
AllocatorTy Allocator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef StringMapEntry<ValueTy> MapEntryTy;
|
using MapEntryTy = StringMapEntry<ValueTy>;
|
||||||
|
|
||||||
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||||
|
|
||||||
explicit StringMap(unsigned InitialSize)
|
explicit StringMap(unsigned InitialSize)
|
||||||
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
|
||||||
|
|
||||||
@ -248,12 +245,6 @@ class StringMap : public StringMapImpl {
|
|||||||
StringMap(StringMap &&RHS)
|
StringMap(StringMap &&RHS)
|
||||||
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
|
||||||
|
|
||||||
StringMap &operator=(StringMap RHS) {
|
|
||||||
StringMapImpl::swap(RHS);
|
|
||||||
std::swap(Allocator, RHS.Allocator);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringMap(const StringMap &RHS) :
|
StringMap(const StringMap &RHS) :
|
||||||
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
|
||||||
Allocator(RHS.Allocator) {
|
Allocator(RHS.Allocator) {
|
||||||
@ -289,16 +280,37 @@ class StringMap : public StringMapImpl {
|
|||||||
// not worthwhile.
|
// not worthwhile.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringMap &operator=(StringMap RHS) {
|
||||||
|
StringMapImpl::swap(RHS);
|
||||||
|
std::swap(Allocator, RHS.Allocator);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~StringMap() {
|
||||||
|
// Delete all the elements in the map, but don't reset the elements
|
||||||
|
// to default values. This is a copy of clear(), but avoids unnecessary
|
||||||
|
// work not required in the destructor.
|
||||||
|
if (!empty()) {
|
||||||
|
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
||||||
|
StringMapEntryBase *Bucket = TheTable[I];
|
||||||
|
if (Bucket && Bucket != getTombstoneVal()) {
|
||||||
|
static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(TheTable);
|
||||||
|
}
|
||||||
|
|
||||||
AllocatorTy &getAllocator() { return Allocator; }
|
AllocatorTy &getAllocator() { return Allocator; }
|
||||||
const AllocatorTy &getAllocator() const { return Allocator; }
|
const AllocatorTy &getAllocator() const { return Allocator; }
|
||||||
|
|
||||||
typedef const char* key_type;
|
using key_type = const char*;
|
||||||
typedef ValueTy mapped_type;
|
using mapped_type = ValueTy;
|
||||||
typedef StringMapEntry<ValueTy> value_type;
|
using value_type = StringMapEntry<ValueTy>;
|
||||||
typedef size_t size_type;
|
using size_type = size_t;
|
||||||
|
|
||||||
typedef StringMapConstIterator<ValueTy> const_iterator;
|
using const_iterator = StringMapConstIterator<ValueTy>;
|
||||||
typedef StringMapIterator<ValueTy> iterator;
|
using iterator = StringMapIterator<ValueTy>;
|
||||||
|
|
||||||
iterator begin() {
|
iterator begin() {
|
||||||
return iterator(TheTable, NumBuckets == 0);
|
return iterator(TheTable, NumBuckets == 0);
|
||||||
@ -313,7 +325,7 @@ class StringMap : public StringMapImpl {
|
|||||||
return const_iterator(TheTable+NumBuckets, true);
|
return const_iterator(TheTable+NumBuckets, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
|
||||||
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
return make_range(StringMapKeyIterator<ValueTy>(begin()),
|
||||||
StringMapKeyIterator<ValueTy>(end()));
|
StringMapKeyIterator<ValueTy>(end()));
|
||||||
}
|
}
|
||||||
@ -433,21 +445,6 @@ class StringMap : public StringMapImpl {
|
|||||||
erase(I);
|
erase(I);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
~StringMap() {
|
|
||||||
// Delete all the elements in the map, but don't reset the elements
|
|
||||||
// to default values. This is a copy of clear(), but avoids unnecessary
|
|
||||||
// work not required in the destructor.
|
|
||||||
if (!empty()) {
|
|
||||||
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
|
|
||||||
StringMapEntryBase *Bucket = TheTable[I];
|
|
||||||
if (Bucket && Bucket != getTombstoneVal()) {
|
|
||||||
static_cast<MapEntryTy*>(Bucket)->Destroy(Allocator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(TheTable);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename DerivedTy, typename ValueTy>
|
template <typename DerivedTy, typename ValueTy>
|
||||||
@ -542,7 +539,6 @@ class StringMapKeyIterator
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
StringMapKeyIterator() = default;
|
StringMapKeyIterator() = default;
|
||||||
|
|
||||||
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
|
||||||
: base(std::move(Iter)) {}
|
: base(std::move(Iter)) {}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===--- StringRef.h - Constant String Reference Wrapper --------*- C++ -*-===//
|
//===- StringRef.h - Constant String Reference Wrapper ----------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -15,16 +15,18 @@
|
|||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
template <typename T>
|
|
||||||
class SmallVectorImpl;
|
|
||||||
class APInt;
|
class APInt;
|
||||||
class hash_code;
|
class hash_code;
|
||||||
|
template <typename T> class SmallVectorImpl;
|
||||||
class StringRef;
|
class StringRef;
|
||||||
|
|
||||||
/// Helper functions for StringRef::getAsInteger.
|
/// Helper functions for StringRef::getAsInteger.
|
||||||
@ -46,10 +48,11 @@ namespace llvm {
|
|||||||
/// general safe to store a StringRef.
|
/// general safe to store a StringRef.
|
||||||
class StringRef {
|
class StringRef {
|
||||||
public:
|
public:
|
||||||
typedef const char *iterator;
|
|
||||||
typedef const char *const_iterator;
|
|
||||||
static const size_t npos = ~size_t(0);
|
static const size_t npos = ~size_t(0);
|
||||||
typedef size_t size_type;
|
|
||||||
|
using iterator = const char *;
|
||||||
|
using const_iterator = const char *;
|
||||||
|
using size_type = size_t;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The start of the string, in an external buffer.
|
/// The start of the string, in an external buffer.
|
||||||
@ -906,6 +909,7 @@ namespace llvm {
|
|||||||
// StringRefs can be treated like a POD type.
|
// StringRefs can be treated like a POD type.
|
||||||
template <typename T> struct isPodLike;
|
template <typename T> struct isPodLike;
|
||||||
template <> struct isPodLike<StringRef> { static const bool value = true; };
|
template <> struct isPodLike<StringRef> { static const bool value = true; };
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
} // end namespace llvm
|
||||||
|
|
||||||
|
#endif // LLVM_ADT_STRINGREF_H
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===--- StringSet.h - The LLVM Compiler Driver -----------------*- C++ -*-===//
|
//===- StringSet.h - The LLVM Compiler Driver -------------------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -15,13 +15,19 @@
|
|||||||
#define LLVM_ADT_STRINGSET_H
|
#define LLVM_ADT_STRINGSET_H
|
||||||
|
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/Support/Allocator.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
/// StringSet - A wrapper for StringMap that provides set-like functionality.
|
/// StringSet - A wrapper for StringMap that provides set-like functionality.
|
||||||
template <class AllocatorTy = llvm::MallocAllocator>
|
template <class AllocatorTy = MallocAllocator>
|
||||||
class StringSet : public llvm::StringMap<char, AllocatorTy> {
|
class StringSet : public StringMap<char, AllocatorTy> {
|
||||||
typedef llvm::StringMap<char, AllocatorTy> base;
|
using base = StringMap<char, AllocatorTy>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringSet() = default;
|
StringSet() = default;
|
||||||
StringSet(std::initializer_list<StringRef> S) {
|
StringSet(std::initializer_list<StringRef> S) {
|
||||||
@ -40,6 +46,7 @@ namespace llvm {
|
|||||||
base::insert(std::make_pair(*It, '\0'));
|
base::insert(std::make_pair(*It, '\0'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_ADT_STRINGSET_H
|
#endif // LLVM_ADT_STRINGSET_H
|
||||||
|
@ -30,9 +30,9 @@ namespace llvm {
|
|||||||
template <typename EltTy>
|
template <typename EltTy>
|
||||||
class TinyPtrVector {
|
class TinyPtrVector {
|
||||||
public:
|
public:
|
||||||
typedef SmallVector<EltTy, 4> VecTy;
|
using VecTy = SmallVector<EltTy, 4>;
|
||||||
typedef typename VecTy::value_type value_type;
|
using value_type = typename VecTy::value_type;
|
||||||
typedef PointerUnion<EltTy, VecTy *> PtrUnion;
|
using PtrUnion = PointerUnion<EltTy, VecTy *>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PtrUnion Val;
|
PtrUnion Val;
|
||||||
@ -167,10 +167,10 @@ class TinyPtrVector {
|
|||||||
return Val.template get<VecTy*>()->size();
|
return Val.template get<VecTy*>()->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef EltTy *iterator;
|
using iterator = EltTy *;
|
||||||
typedef const EltTy *const_iterator;
|
using const_iterator = const EltTy *;
|
||||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
iterator begin() {
|
iterator begin() {
|
||||||
if (Val.template is<EltTy>())
|
if (Val.template is<EltTy>())
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===-- llvm/ADT/UniqueVector.h ---------------------------------*- C++ -*-===//
|
//===- llvm/ADT/UniqueVector.h ----------------------------------*- C++ -*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -24,16 +24,15 @@ namespace llvm {
|
|||||||
/// Entries can be fetched using operator[] with the entry ID.
|
/// Entries can be fetched using operator[] with the entry ID.
|
||||||
template<class T> class UniqueVector {
|
template<class T> class UniqueVector {
|
||||||
public:
|
public:
|
||||||
typedef typename std::vector<T> VectorType;
|
using VectorType = typename std::vector<T>;
|
||||||
typedef typename VectorType::iterator iterator;
|
using iterator = typename VectorType::iterator;
|
||||||
typedef typename VectorType::const_iterator const_iterator;
|
using const_iterator = typename VectorType::const_iterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Map - Used to handle the correspondence of entry to ID.
|
// Map - Used to handle the correspondence of entry to ID.
|
||||||
std::map<T, unsigned> Map;
|
std::map<T, unsigned> Map;
|
||||||
|
|
||||||
// Vector - ID ordered vector of entries. Entries can be indexed by ID - 1.
|
// Vector - ID ordered vector of entries. Entries can be indexed by ID - 1.
|
||||||
//
|
|
||||||
VectorType Vector;
|
VectorType Vector;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -68,7 +67,6 @@ template<class T> class UniqueVector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// operator[] - Returns a reference to the entry with the specified ID.
|
/// operator[] - Returns a reference to the entry with the specified ID.
|
||||||
///
|
|
||||||
const T &operator[](unsigned ID) const {
|
const T &operator[](unsigned ID) const {
|
||||||
assert(ID-1 < size() && "ID is 0 or out of range!");
|
assert(ID-1 < size() && "ID is 0 or out of range!");
|
||||||
return Vector[ID - 1];
|
return Vector[ID - 1];
|
||||||
@ -87,21 +85,18 @@ template<class T> class UniqueVector {
|
|||||||
const_iterator end() const { return Vector.end(); }
|
const_iterator end() const { return Vector.end(); }
|
||||||
|
|
||||||
/// size - Returns the number of entries in the vector.
|
/// size - Returns the number of entries in the vector.
|
||||||
///
|
|
||||||
size_t size() const { return Vector.size(); }
|
size_t size() const { return Vector.size(); }
|
||||||
|
|
||||||
/// empty - Returns true if the vector is empty.
|
/// empty - Returns true if the vector is empty.
|
||||||
///
|
|
||||||
bool empty() const { return Vector.empty(); }
|
bool empty() const { return Vector.empty(); }
|
||||||
|
|
||||||
/// reset - Clears all the entries.
|
/// reset - Clears all the entries.
|
||||||
///
|
|
||||||
void reset() {
|
void reset() {
|
||||||
Map.clear();
|
Map.clear();
|
||||||
Vector.resize(0, 0);
|
Vector.resize(0, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_ADT_UNIQUEVECTOR_H
|
#endif // LLVM_ADT_UNIQUEVECTOR_H
|
||||||
|
@ -55,6 +55,21 @@ class ProfileSummaryInfo {
|
|||||||
ProfileSummaryInfo(ProfileSummaryInfo &&Arg)
|
ProfileSummaryInfo(ProfileSummaryInfo &&Arg)
|
||||||
: M(Arg.M), Summary(std::move(Arg.Summary)) {}
|
: M(Arg.M), Summary(std::move(Arg.Summary)) {}
|
||||||
|
|
||||||
|
/// \brief Returns true if profile summary is available.
|
||||||
|
bool hasProfileSummary() { return computeSummary(); }
|
||||||
|
|
||||||
|
/// \brief Returns true if module \c M has sample profile.
|
||||||
|
bool hasSampleProfile() {
|
||||||
|
return hasProfileSummary() &&
|
||||||
|
Summary->getKind() == ProfileSummary::PSK_Sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Returns true if module \c M has instrumentation profile.
|
||||||
|
bool hasInstrumentationProfile() {
|
||||||
|
return hasProfileSummary() &&
|
||||||
|
Summary->getKind() == ProfileSummary::PSK_Instr;
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle the invalidation of this information.
|
/// Handle the invalidation of this information.
|
||||||
///
|
///
|
||||||
/// When used as a result of \c ProfileSummaryAnalysis this method will be
|
/// When used as a result of \c ProfileSummaryAnalysis this method will be
|
||||||
|
@ -28,7 +28,7 @@ class CVTypeVisitor {
|
|||||||
|
|
||||||
Error visitTypeRecord(CVType &Record, TypeIndex Index);
|
Error visitTypeRecord(CVType &Record, TypeIndex Index);
|
||||||
Error visitTypeRecord(CVType &Record);
|
Error visitTypeRecord(CVType &Record);
|
||||||
Error visitMemberRecord(CVMemberRecord &Record);
|
Error visitMemberRecord(CVMemberRecord Record);
|
||||||
|
|
||||||
/// Visits the type records in Data. Sets the error flag on parse failures.
|
/// Visits the type records in Data. Sets the error flag on parse failures.
|
||||||
Error visitTypeStream(const CVTypeArray &Types);
|
Error visitTypeStream(const CVTypeArray &Types);
|
||||||
@ -47,6 +47,36 @@ class CVTypeVisitor {
|
|||||||
TinyPtrVector<TypeServerHandler *> Handlers;
|
TinyPtrVector<TypeServerHandler *> Handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum VisitorDataSource {
|
||||||
|
VDS_BytesPresent, // The record bytes are passed into the the visitation
|
||||||
|
// function. The algorithm should first deserialize them
|
||||||
|
// before passing them on through the pipeline.
|
||||||
|
VDS_BytesExternal // The record bytes are not present, and it is the
|
||||||
|
// responsibility of the visitor callback interface to
|
||||||
|
// supply the bytes.
|
||||||
|
};
|
||||||
|
|
||||||
|
Error visitTypeRecord(CVType &Record, TypeIndex Index,
|
||||||
|
TypeVisitorCallbacks &Callbacks,
|
||||||
|
VisitorDataSource Source = VDS_BytesPresent,
|
||||||
|
TypeServerHandler *TS = nullptr);
|
||||||
|
Error visitTypeRecord(CVType &Record, TypeVisitorCallbacks &Callbacks,
|
||||||
|
VisitorDataSource Source = VDS_BytesPresent,
|
||||||
|
TypeServerHandler *TS = nullptr);
|
||||||
|
|
||||||
|
Error visitMemberRecord(CVMemberRecord Record, TypeVisitorCallbacks &Callbacks,
|
||||||
|
VisitorDataSource Source = VDS_BytesPresent);
|
||||||
|
Error visitMemberRecord(TypeLeafKind Kind, ArrayRef<uint8_t> Record,
|
||||||
|
TypeVisitorCallbacks &Callbacks);
|
||||||
|
|
||||||
|
Error visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
|
||||||
|
TypeVisitorCallbacks &Callbacks);
|
||||||
|
|
||||||
|
Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks,
|
||||||
|
TypeServerHandler *TS = nullptr);
|
||||||
|
Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
|
||||||
|
TypeServerHandler *TS = nullptr);
|
||||||
|
|
||||||
} // end namespace codeview
|
} // end namespace codeview
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
|
@ -11,13 +11,10 @@
|
|||||||
#define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
|
#define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
|
||||||
|
|
||||||
#include "llvm/ADT/TinyPtrVector.h"
|
#include "llvm/ADT/TinyPtrVector.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
|
||||||
#include "llvm/Support/Error.h"
|
#include "llvm/Support/Error.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -73,18 +70,6 @@ class RandomAccessTypeVisitor {
|
|||||||
/// The database visitor which adds new records to the database.
|
/// The database visitor which adds new records to the database.
|
||||||
TypeDatabaseVisitor DatabaseVisitor;
|
TypeDatabaseVisitor DatabaseVisitor;
|
||||||
|
|
||||||
/// The deserializer which deserializes new records.
|
|
||||||
TypeDeserializer Deserializer;
|
|
||||||
|
|
||||||
/// The visitation callback pipeline to use. By default this contains a
|
|
||||||
/// deserializer and a type database visitor. But the callback specified
|
|
||||||
/// in the constructor is also added.
|
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
|
||||||
|
|
||||||
/// The visitor used to visit the internal pipeline for deserialization and
|
|
||||||
/// database maintenance.
|
|
||||||
CVTypeVisitor InternalVisitor;
|
|
||||||
|
|
||||||
/// A vector mapping type indices to type offset. For every record that has
|
/// A vector mapping type indices to type offset. For every record that has
|
||||||
/// been visited, contains the absolute offset of that record in the record
|
/// been visited, contains the absolute offset of that record in the record
|
||||||
/// array.
|
/// array.
|
||||||
|
@ -31,10 +31,10 @@ struct DWARFAttribute {
|
|||||||
dwarf::Attribute Attr;
|
dwarf::Attribute Attr;
|
||||||
/// The form and value for this attribute.
|
/// The form and value for this attribute.
|
||||||
DWARFFormValue Value;
|
DWARFFormValue Value;
|
||||||
|
|
||||||
DWARFAttribute(uint32_t O, dwarf::Attribute A = dwarf::Attribute(0),
|
DWARFAttribute(uint32_t O, dwarf::Attribute A = dwarf::Attribute(0),
|
||||||
dwarf::Form F = dwarf::Form(0)) : Attr(A), Value(F) {}
|
dwarf::Form F = dwarf::Form(0)) : Attr(A), Value(F) {}
|
||||||
|
|
||||||
bool isValid() const {
|
bool isValid() const {
|
||||||
return Offset != 0 && Attr != dwarf::Attribute(0);
|
return Offset != 0 && Attr != dwarf::Attribute(0);
|
||||||
}
|
}
|
||||||
|
@ -22,19 +22,19 @@ class raw_ostream;
|
|||||||
class DWARFDebugArangeSet {
|
class DWARFDebugArangeSet {
|
||||||
public:
|
public:
|
||||||
struct Header {
|
struct Header {
|
||||||
// The total length of the entries for that set, not including the length
|
/// The total length of the entries for that set, not including the length
|
||||||
// field itself.
|
/// field itself.
|
||||||
uint32_t Length;
|
uint32_t Length;
|
||||||
// The offset from the beginning of the .debug_info section of the
|
/// The offset from the beginning of the .debug_info section of the
|
||||||
// compilation unit entry referenced by the table.
|
/// compilation unit entry referenced by the table.
|
||||||
uint32_t CuOffset;
|
uint32_t CuOffset;
|
||||||
// The DWARF version number.
|
/// The DWARF version number.
|
||||||
uint16_t Version;
|
uint16_t Version;
|
||||||
// The size in bytes of an address on the target architecture. For segmented
|
/// The size in bytes of an address on the target architecture. For segmented
|
||||||
// addressing, this is the size of the offset portion of the address.
|
/// addressing, this is the size of the offset portion of the address.
|
||||||
uint8_t AddrSize;
|
uint8_t AddrSize;
|
||||||
// The size in bytes of a segment descriptor on the target architecture.
|
/// The size in bytes of a segment descriptor on the target architecture.
|
||||||
// If the target system uses a flat address space, this value is 0.
|
/// If the target system uses a flat address space, this value is 0.
|
||||||
uint8_t SegSize;
|
uint8_t SegSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class DWARFDebugAranges {
|
|||||||
void clear();
|
void clear();
|
||||||
void extract(DataExtractor DebugArangesData);
|
void extract(DataExtractor DebugArangesData);
|
||||||
|
|
||||||
// Call appendRange multiple times and then call construct.
|
/// Call appendRange multiple times and then call construct.
|
||||||
void appendRange(uint32_t CUOffset, uint64_t LowPC, uint64_t HighPC);
|
void appendRange(uint32_t CUOffset, uint64_t LowPC, uint64_t HighPC);
|
||||||
void construct();
|
void construct();
|
||||||
|
|
||||||
@ -58,9 +58,9 @@ class DWARFDebugAranges {
|
|||||||
return LowPC < other.LowPC;
|
return LowPC < other.LowPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t LowPC; // Start of address range.
|
uint64_t LowPC; /// Start of address range.
|
||||||
uint32_t Length; // End of address range (not including this address).
|
uint32_t Length; /// End of address range (not including this address).
|
||||||
uint32_t CUOffset; // Offset of the compile unit or die.
|
uint32_t CUOffset; /// Offset of the compile unit or die.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RangeEndpoint {
|
struct RangeEndpoint {
|
||||||
|
@ -33,31 +33,31 @@ typedef std::vector<DWARFAddressRange> DWARFAddressRangesVector;
|
|||||||
class DWARFDebugRangeList {
|
class DWARFDebugRangeList {
|
||||||
public:
|
public:
|
||||||
struct RangeListEntry {
|
struct RangeListEntry {
|
||||||
// A beginning address offset. This address offset has the size of an
|
/// A beginning address offset. This address offset has the size of an
|
||||||
// address and is relative to the applicable base address of the
|
/// address and is relative to the applicable base address of the
|
||||||
// compilation unit referencing this range list. It marks the beginning
|
/// compilation unit referencing this range list. It marks the beginning
|
||||||
// of an address range.
|
/// of an address range.
|
||||||
uint64_t StartAddress;
|
uint64_t StartAddress;
|
||||||
// An ending address offset. This address offset again has the size of
|
/// An ending address offset. This address offset again has the size of
|
||||||
// an address and is relative to the applicable base address of the
|
/// an address and is relative to the applicable base address of the
|
||||||
// compilation unit referencing this range list. It marks the first
|
/// compilation unit referencing this range list. It marks the first
|
||||||
// address past the end of the address range. The ending address must
|
/// address past the end of the address range. The ending address must
|
||||||
// be greater than or equal to the beginning address.
|
/// be greater than or equal to the beginning address.
|
||||||
uint64_t EndAddress;
|
uint64_t EndAddress;
|
||||||
|
|
||||||
// The end of any given range list is marked by an end of list entry,
|
/// The end of any given range list is marked by an end of list entry,
|
||||||
// which consists of a 0 for the beginning address offset
|
/// which consists of a 0 for the beginning address offset
|
||||||
// and a 0 for the ending address offset.
|
/// and a 0 for the ending address offset.
|
||||||
bool isEndOfListEntry() const {
|
bool isEndOfListEntry() const {
|
||||||
return (StartAddress == 0) && (EndAddress == 0);
|
return (StartAddress == 0) && (EndAddress == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A base address selection entry consists of:
|
/// A base address selection entry consists of:
|
||||||
// 1. The value of the largest representable address offset
|
/// 1. The value of the largest representable address offset
|
||||||
// (for example, 0xffffffff when the size of an address is 32 bits).
|
/// (for example, 0xffffffff when the size of an address is 32 bits).
|
||||||
// 2. An address, which defines the appropriate base address for
|
/// 2. An address, which defines the appropriate base address for
|
||||||
// use in interpreting the beginning and ending address offsets of
|
/// use in interpreting the beginning and ending address offsets of
|
||||||
// subsequent entries of the location list.
|
/// subsequent entries of the location list.
|
||||||
bool isBaseAddressSelectionEntry(uint8_t AddressSize) const {
|
bool isBaseAddressSelectionEntry(uint8_t AddressSize) const {
|
||||||
assert(AddressSize == 4 || AddressSize == 8);
|
assert(AddressSize == 4 || AddressSize == 8);
|
||||||
if (AddressSize == 4)
|
if (AddressSize == 4)
|
||||||
@ -68,7 +68,7 @@ class DWARFDebugRangeList {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Offset in .debug_ranges section.
|
/// Offset in .debug_ranges section.
|
||||||
uint32_t Offset;
|
uint32_t Offset;
|
||||||
uint8_t AddressSize;
|
uint8_t AddressSize;
|
||||||
std::vector<RangeListEntry> Entries;
|
std::vector<RangeListEntry> Entries;
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
class DWARFUnit;
|
class DWARFUnit;
|
||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
/// Utility class that carries the DWARF compile/type unit and the debug info
|
/// Utility class that carries the DWARF compile/type unit and the debug info
|
||||||
/// entry in an object.
|
/// entry in an object.
|
||||||
@ -47,7 +47,7 @@ class DWARFDie {
|
|||||||
public:
|
public:
|
||||||
DWARFDie() = default;
|
DWARFDie() = default;
|
||||||
DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry * D) : U(Unit), Die(D) {}
|
DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry * D) : U(Unit), Die(D) {}
|
||||||
|
|
||||||
bool isValid() const { return U && Die; }
|
bool isValid() const { return U && Die; }
|
||||||
explicit operator bool() const { return isValid(); }
|
explicit operator bool() const { return isValid(); }
|
||||||
const DWARFDebugInfoEntry *getDebugInfoEntry() const { return Die; }
|
const DWARFDebugInfoEntry *getDebugInfoEntry() const { return Die; }
|
||||||
@ -68,7 +68,7 @@ class DWARFDie {
|
|||||||
assert(isValid() && "must check validity prior to calling");
|
assert(isValid() && "must check validity prior to calling");
|
||||||
return Die->getOffset();
|
return Die->getOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
dwarf::Tag getTag() const {
|
dwarf::Tag getTag() const {
|
||||||
auto AbbrevDecl = getAbbreviationDeclarationPtr();
|
auto AbbrevDecl = getAbbreviationDeclarationPtr();
|
||||||
if (AbbrevDecl)
|
if (AbbrevDecl)
|
||||||
@ -80,7 +80,7 @@ class DWARFDie {
|
|||||||
assert(isValid() && "must check validity prior to calling");
|
assert(isValid() && "must check validity prior to calling");
|
||||||
return Die->hasChildren();
|
return Die->hasChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true for a valid DIE that terminates a sibling chain.
|
/// Returns true for a valid DIE that terminates a sibling chain.
|
||||||
bool isNULL() const {
|
bool isNULL() const {
|
||||||
return getAbbreviationDeclarationPtr() == nullptr;
|
return getAbbreviationDeclarationPtr() == nullptr;
|
||||||
@ -97,13 +97,13 @@ class DWARFDie {
|
|||||||
/// \returns a valid DWARFDie instance if this object has a parent or an
|
/// \returns a valid DWARFDie instance if this object has a parent or an
|
||||||
/// invalid DWARFDie instance if it doesn't.
|
/// invalid DWARFDie instance if it doesn't.
|
||||||
DWARFDie getParent() const;
|
DWARFDie getParent() const;
|
||||||
|
|
||||||
/// Get the sibling of this DIE object.
|
/// Get the sibling of this DIE object.
|
||||||
///
|
///
|
||||||
/// \returns a valid DWARFDie instance if this object has a sibling or an
|
/// \returns a valid DWARFDie instance if this object has a sibling or an
|
||||||
/// invalid DWARFDie instance if it doesn't.
|
/// invalid DWARFDie instance if it doesn't.
|
||||||
DWARFDie getSibling() const;
|
DWARFDie getSibling() const;
|
||||||
|
|
||||||
/// Get the first child of this DIE object.
|
/// Get the first child of this DIE object.
|
||||||
///
|
///
|
||||||
/// \returns a valid DWARFDie instance if this object has children or an
|
/// \returns a valid DWARFDie instance if this object has children or an
|
||||||
@ -113,7 +113,7 @@ class DWARFDie {
|
|||||||
return DWARFDie(U, Die + 1);
|
return DWARFDie(U, Die + 1);
|
||||||
return DWARFDie();
|
return DWARFDie();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dump the DIE and all of its attributes to the supplied stream.
|
/// Dump the DIE and all of its attributes to the supplied stream.
|
||||||
///
|
///
|
||||||
/// \param OS the stream to use for output.
|
/// \param OS the stream to use for output.
|
||||||
@ -121,7 +121,7 @@ class DWARFDie {
|
|||||||
/// children.
|
/// children.
|
||||||
/// \param indent the number of characters to indent each line that is output.
|
/// \param indent the number of characters to indent each line that is output.
|
||||||
void dump(raw_ostream &OS, unsigned recurseDepth, unsigned indent = 0) const;
|
void dump(raw_ostream &OS, unsigned recurseDepth, unsigned indent = 0) const;
|
||||||
|
|
||||||
/// Extract the specified attribute from this DIE.
|
/// Extract the specified attribute from this DIE.
|
||||||
///
|
///
|
||||||
/// Extract an attribute value from this DIE only. This call doesn't look
|
/// Extract an attribute value from this DIE only. This call doesn't look
|
||||||
@ -132,7 +132,7 @@ class DWARFDie {
|
|||||||
/// \returns an optional DWARFFormValue that will have the form value if the
|
/// \returns an optional DWARFFormValue that will have the form value if the
|
||||||
/// attribute was successfully extracted.
|
/// attribute was successfully extracted.
|
||||||
Optional<DWARFFormValue> find(dwarf::Attribute Attr) const;
|
Optional<DWARFFormValue> find(dwarf::Attribute Attr) const;
|
||||||
|
|
||||||
/// Extract the first value of any attribute in Attrs from this DIE.
|
/// Extract the first value of any attribute in Attrs from this DIE.
|
||||||
///
|
///
|
||||||
/// Extract the first attribute that matches from this DIE only. This call
|
/// Extract the first attribute that matches from this DIE only. This call
|
||||||
@ -180,7 +180,7 @@ class DWARFDie {
|
|||||||
///
|
///
|
||||||
/// \returns anm optional absolute section offset value for the attribute.
|
/// \returns anm optional absolute section offset value for the attribute.
|
||||||
Optional<uint64_t> getRangesBaseAttribute() const;
|
Optional<uint64_t> getRangesBaseAttribute() const;
|
||||||
|
|
||||||
/// Get the DW_AT_high_pc attribute value as an address.
|
/// Get the DW_AT_high_pc attribute value as an address.
|
||||||
///
|
///
|
||||||
/// In DWARF version 4 and later the high PC can be encoded as an offset from
|
/// In DWARF version 4 and later the high PC can be encoded as an offset from
|
||||||
@ -196,7 +196,7 @@ class DWARFDie {
|
|||||||
/// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU.
|
/// Retrieves DW_AT_low_pc and DW_AT_high_pc from CU.
|
||||||
/// Returns true if both attributes are present.
|
/// Returns true if both attributes are present.
|
||||||
bool getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC) const;
|
bool getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC) const;
|
||||||
|
|
||||||
/// Get the address ranges for this DIE.
|
/// Get the address ranges for this DIE.
|
||||||
///
|
///
|
||||||
/// Get the hi/low PC range if both attributes are available or exrtracts the
|
/// Get the hi/low PC range if both attributes are available or exrtracts the
|
||||||
@ -208,7 +208,7 @@ class DWARFDie {
|
|||||||
/// \returns a address range vector that might be empty if no address range
|
/// \returns a address range vector that might be empty if no address range
|
||||||
/// information is available.
|
/// information is available.
|
||||||
DWARFAddressRangesVector getAddressRanges() const;
|
DWARFAddressRangesVector getAddressRanges() const;
|
||||||
|
|
||||||
/// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any
|
/// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any
|
||||||
/// of its children.
|
/// of its children.
|
||||||
///
|
///
|
||||||
@ -218,19 +218,19 @@ class DWARFDie {
|
|||||||
///
|
///
|
||||||
/// \param Ranges the addres range vector to fill in.
|
/// \param Ranges the addres range vector to fill in.
|
||||||
void collectChildrenAddressRanges(DWARFAddressRangesVector &Ranges) const;
|
void collectChildrenAddressRanges(DWARFAddressRangesVector &Ranges) const;
|
||||||
|
|
||||||
bool addressRangeContainsAddress(const uint64_t Address) const;
|
bool addressRangeContainsAddress(const uint64_t Address) const;
|
||||||
|
|
||||||
/// If a DIE represents a subprogram (or inlined subroutine), returns its
|
/// If a DIE represents a subprogram (or inlined subroutine), returns its
|
||||||
/// mangled name (or short name, if mangled is missing). This name may be
|
/// mangled name (or short name, if mangled is missing). This name may be
|
||||||
/// fetched from specification or abstract origin for this subprogram.
|
/// fetched from specification or abstract origin for this subprogram.
|
||||||
/// Returns null if no name is found.
|
/// Returns null if no name is found.
|
||||||
const char *getSubroutineName(DINameKind Kind) const;
|
const char *getSubroutineName(DINameKind Kind) const;
|
||||||
|
|
||||||
/// Return the DIE name resolving DW_AT_sepcification or DW_AT_abstract_origin
|
/// Return the DIE name resolving DW_AT_sepcification or DW_AT_abstract_origin
|
||||||
/// references if necessary. Returns null if no name is found.
|
/// references if necessary. Returns null if no name is found.
|
||||||
const char *getName(DINameKind Kind) const;
|
const char *getName(DINameKind Kind) const;
|
||||||
|
|
||||||
/// Returns the declaration line (start line) for a DIE, assuming it specifies
|
/// Returns the declaration line (start line) for a DIE, assuming it specifies
|
||||||
/// a subprogram. This may be fetched from specification or abstract origin
|
/// a subprogram. This may be fetched from specification or abstract origin
|
||||||
/// for this subprogram by resolving DW_AT_sepcification or
|
/// for this subprogram by resolving DW_AT_sepcification or
|
||||||
@ -251,21 +251,21 @@ class DWARFDie {
|
|||||||
/// there is no DW_AT_GNU_discriminator attribute in this DIE.
|
/// there is no DW_AT_GNU_discriminator attribute in this DIE.
|
||||||
void getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
|
void getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
|
||||||
uint32_t &CallColumn, uint32_t &CallDiscriminator) const;
|
uint32_t &CallColumn, uint32_t &CallDiscriminator) const;
|
||||||
|
|
||||||
class attribute_iterator;
|
class attribute_iterator;
|
||||||
|
|
||||||
/// Get an iterator range to all attributes in the current DIE only.
|
/// Get an iterator range to all attributes in the current DIE only.
|
||||||
///
|
///
|
||||||
/// \returns an iterator range for the attributes of the current DIE.
|
/// \returns an iterator range for the attributes of the current DIE.
|
||||||
iterator_range<attribute_iterator> attributes() const;
|
iterator_range<attribute_iterator> attributes() const;
|
||||||
|
|
||||||
class iterator;
|
class iterator;
|
||||||
|
|
||||||
iterator begin() const;
|
iterator begin() const;
|
||||||
iterator end() const;
|
iterator end() const;
|
||||||
iterator_range<iterator> children() const;
|
iterator_range<iterator> children() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DWARFDie::attribute_iterator :
|
class DWARFDie::attribute_iterator :
|
||||||
public iterator_facade_base<attribute_iterator, std::forward_iterator_tag,
|
public iterator_facade_base<attribute_iterator, std::forward_iterator_tag,
|
||||||
const DWARFAttribute> {
|
const DWARFAttribute> {
|
||||||
@ -275,7 +275,7 @@ class DWARFDie::attribute_iterator :
|
|||||||
DWARFAttribute AttrValue;
|
DWARFAttribute AttrValue;
|
||||||
/// The attribute index within the abbreviation declaration in Die.
|
/// The attribute index within the abbreviation declaration in Die.
|
||||||
uint32_t Index;
|
uint32_t Index;
|
||||||
|
|
||||||
/// Update the attribute index and attempt to read the attribute value. If the
|
/// Update the attribute index and attempt to read the attribute value. If the
|
||||||
/// attribute is able to be read, update AttrValue and the Index member
|
/// attribute is able to be read, update AttrValue and the Index member
|
||||||
/// variable. If the attribute value is not able to be read, an appropriate
|
/// variable. If the attribute value is not able to be read, an appropriate
|
||||||
|
@ -49,9 +49,9 @@ class DWARFFormValue {
|
|||||||
const uint8_t *data = nullptr;
|
const uint8_t *data = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
dwarf::Form Form; // Form for this value.
|
dwarf::Form Form; /// Form for this value.
|
||||||
ValueType Value; // Contains all data for the form.
|
ValueType Value; /// Contains all data for the form.
|
||||||
const DWARFUnit *U = nullptr; // Remember the DWARFUnit at extract time.
|
const DWARFUnit *U = nullptr; /// Remember the DWARFUnit at extract time.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {}
|
DWARFFormValue(dwarf::Form F = dwarf::Form(0)) : Form(F) {}
|
||||||
@ -72,11 +72,14 @@ class DWARFFormValue {
|
|||||||
const DWARFUnit *getUnit() const { return U; }
|
const DWARFUnit *getUnit() const { return U; }
|
||||||
void dump(raw_ostream &OS) const;
|
void dump(raw_ostream &OS) const;
|
||||||
|
|
||||||
/// \brief extracts a value in data at offset *offset_ptr.
|
/// Extracts a value in \p Data at offset \p *OffsetPtr.
|
||||||
///
|
///
|
||||||
/// The passed DWARFUnit is allowed to be nullptr, in which
|
/// The passed DWARFUnit is allowed to be nullptr, in which
|
||||||
/// case no relocation processing will be performed and some
|
/// case no relocation processing will be performed and some
|
||||||
/// kind of forms that depend on Unit information are disallowed.
|
/// kind of forms that depend on Unit information are disallowed.
|
||||||
|
/// \param Data The DataExtractor to use.
|
||||||
|
/// \param OffsetPtr The offset within DataExtractor where the data starts.
|
||||||
|
/// \param U The optional DWARFUnit supplying information for some forms.
|
||||||
/// \returns whether the extraction succeeded.
|
/// \returns whether the extraction succeeded.
|
||||||
bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr,
|
bool extractValue(const DataExtractor &Data, uint32_t *OffsetPtr,
|
||||||
const DWARFUnit *U);
|
const DWARFUnit *U);
|
||||||
|
@ -29,25 +29,25 @@ class DWARFGdbIndex {
|
|||||||
uint32_t ConstantPoolOffset;
|
uint32_t ConstantPoolOffset;
|
||||||
|
|
||||||
struct CompUnitEntry {
|
struct CompUnitEntry {
|
||||||
uint64_t Offset; // Offset of a CU in the .debug_info section.
|
uint64_t Offset; /// Offset of a CU in the .debug_info section.
|
||||||
uint64_t Length; // Length of that CU.
|
uint64_t Length; /// Length of that CU.
|
||||||
};
|
};
|
||||||
SmallVector<CompUnitEntry, 0> CuList;
|
SmallVector<CompUnitEntry, 0> CuList;
|
||||||
|
|
||||||
struct AddressEntry {
|
struct AddressEntry {
|
||||||
uint64_t LowAddress; // The low address.
|
uint64_t LowAddress; /// The low address.
|
||||||
uint64_t HighAddress; // The high address.
|
uint64_t HighAddress; /// The high address.
|
||||||
uint32_t CuIndex; // The CU index.
|
uint32_t CuIndex; /// The CU index.
|
||||||
};
|
};
|
||||||
SmallVector<AddressEntry, 0> AddressArea;
|
SmallVector<AddressEntry, 0> AddressArea;
|
||||||
|
|
||||||
struct SymTableEntry {
|
struct SymTableEntry {
|
||||||
uint32_t NameOffset; // Offset of the symbol's name in the constant pool.
|
uint32_t NameOffset; /// Offset of the symbol's name in the constant pool.
|
||||||
uint32_t VecOffset; // Offset of the CU vector in the constant pool.
|
uint32_t VecOffset; /// Offset of the CU vector in the constant pool.
|
||||||
};
|
};
|
||||||
SmallVector<SymTableEntry, 0> SymbolTable;
|
SmallVector<SymTableEntry, 0> SymbolTable;
|
||||||
|
|
||||||
// Each value is CU index + attributes.
|
/// Each value is CU index + attributes.
|
||||||
SmallVector<std::pair<uint32_t, SmallVector<uint32_t, 0>>, 0>
|
SmallVector<std::pair<uint32_t, SmallVector<uint32_t, 0>>, 0>
|
||||||
ConstantPoolVectors;
|
ConstantPoolVectors;
|
||||||
|
|
||||||
|
@ -17,15 +17,14 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
struct RelocAddrEntry {
|
struct RelocAddrEntry {
|
||||||
uint8_t Width;
|
|
||||||
int64_t Value;
|
int64_t Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// In place of applying the relocations to the data we've read from disk we use
|
/// In place of applying the relocations to the data we've read from disk we use
|
||||||
// a separate mapping table to the side and checking that at locations in the
|
/// a separate mapping table to the side and checking that at locations in the
|
||||||
// dwarf where we expect relocated values. This adds a bit of complexity to the
|
/// dwarf where we expect relocated values. This adds a bit of complexity to the
|
||||||
// dwarf parsing/extraction at the benefit of not allocating memory for the
|
/// dwarf parsing/extraction at the benefit of not allocating memory for the
|
||||||
// entire size of the debug info sections.
|
/// entire size of the debug info sections.
|
||||||
typedef DenseMap<uint64_t, RelocAddrEntry> RelocAddrMap;
|
typedef DenseMap<uint64_t, RelocAddrEntry> RelocAddrMap;
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -111,7 +111,7 @@ class DWARFUnitSection final : public SmallVector<std::unique_ptr<UnitType>, 1>,
|
|||||||
|
|
||||||
class DWARFUnit {
|
class DWARFUnit {
|
||||||
DWARFContext &Context;
|
DWARFContext &Context;
|
||||||
// Section containing this DWARFUnit.
|
/// Section containing this DWARFUnit.
|
||||||
const DWARFSection &InfoSection;
|
const DWARFSection &InfoSection;
|
||||||
|
|
||||||
const DWARFDebugAbbrev *Abbrev;
|
const DWARFDebugAbbrev *Abbrev;
|
||||||
@ -133,12 +133,12 @@ class DWARFUnit {
|
|||||||
uint8_t UnitType;
|
uint8_t UnitType;
|
||||||
uint8_t AddrSize;
|
uint8_t AddrSize;
|
||||||
uint64_t BaseAddr;
|
uint64_t BaseAddr;
|
||||||
// The compile unit debug information entry items.
|
/// The compile unit debug information entry items.
|
||||||
std::vector<DWARFDebugInfoEntry> DieArray;
|
std::vector<DWARFDebugInfoEntry> DieArray;
|
||||||
|
|
||||||
// Map from range's start address to end address and corresponding DIE.
|
/// Map from range's start address to end address and corresponding DIE.
|
||||||
// IntervalMap does not support range removal, as a result, we use the
|
/// IntervalMap does not support range removal, as a result, we use the
|
||||||
// std::map::upper_bound for address range lookup.
|
/// std::map::upper_bound for address range lookup.
|
||||||
std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap;
|
std::map<uint64_t, std::pair<uint64_t, DWARFDie>> AddrDieMap;
|
||||||
typedef iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>
|
typedef iterator_range<std::vector<DWARFDebugInfoEntry>::iterator>
|
||||||
die_iterator_range;
|
die_iterator_range;
|
||||||
@ -189,7 +189,7 @@ class DWARFUnit {
|
|||||||
AddrOffsetSectionBase = Base;
|
AddrOffsetSectionBase = Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively update address to Die map.
|
/// Recursively update address to Die map.
|
||||||
void updateAddressDieMap(DWARFDie Die);
|
void updateAddressDieMap(DWARFDie Die);
|
||||||
|
|
||||||
void setRangesSection(const DWARFSection *RS, uint32_t Base) {
|
void setRangesSection(const DWARFSection *RS, uint32_t Base) {
|
||||||
|
@ -51,6 +51,7 @@ class TpiStream {
|
|||||||
HashTable &getHashAdjusters();
|
HashTable &getHashAdjusters();
|
||||||
|
|
||||||
codeview::CVTypeRange types(bool *HadError) const;
|
codeview::CVTypeRange types(bool *HadError) const;
|
||||||
|
const codeview::CVTypeArray &typeArray() const { return TypeRecords; }
|
||||||
|
|
||||||
Error commit();
|
Error commit();
|
||||||
|
|
||||||
|
@ -1132,4 +1132,6 @@ def int_ppc_tsuspend : GCCBuiltin<"__builtin_tsuspend">,
|
|||||||
|
|
||||||
def int_ppc_ttest : GCCBuiltin<"__builtin_ttest">,
|
def int_ppc_ttest : GCCBuiltin<"__builtin_ttest">,
|
||||||
Intrinsic<[llvm_i64_ty], [], []>;
|
Intrinsic<[llvm_i64_ty], [], []>;
|
||||||
|
|
||||||
|
def int_ppc_cfence : Intrinsic<[], [llvm_anyint_ty], []>;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ def : GINodeEquiv<G_FMUL, fmul>;
|
|||||||
def : GINodeEquiv<G_FDIV, fdiv>;
|
def : GINodeEquiv<G_FDIV, fdiv>;
|
||||||
def : GINodeEquiv<G_FREM, frem>;
|
def : GINodeEquiv<G_FREM, frem>;
|
||||||
def : GINodeEquiv<G_FPOW, fpow>;
|
def : GINodeEquiv<G_FPOW, fpow>;
|
||||||
|
def : GINodeEquiv<G_INTRINSIC, intrinsic_wo_chain>;
|
||||||
def : GINodeEquiv<G_BR, br>;
|
def : GINodeEquiv<G_BR, br>;
|
||||||
|
|
||||||
// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern.
|
// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern.
|
||||||
|
@ -2984,7 +2984,7 @@ bool DependenceInfo::propagate(const SCEV *&Src, const SCEV *&Dst,
|
|||||||
SmallVectorImpl<Constraint> &Constraints,
|
SmallVectorImpl<Constraint> &Constraints,
|
||||||
bool &Consistent) {
|
bool &Consistent) {
|
||||||
bool Result = false;
|
bool Result = false;
|
||||||
for (int LI = Loops.find_first(); LI >= 0; LI = Loops.find_next(LI)) {
|
for (unsigned LI : Loops.set_bits()) {
|
||||||
DEBUG(dbgs() << "\t Constraint[" << LI << "] is");
|
DEBUG(dbgs() << "\t Constraint[" << LI << "] is");
|
||||||
DEBUG(Constraints[LI].dump(dbgs()));
|
DEBUG(Constraints[LI].dump(dbgs()));
|
||||||
if (Constraints[LI].isDistance())
|
if (Constraints[LI].isDistance())
|
||||||
@ -3266,7 +3266,7 @@ bool DependenceInfo::tryDelinearize(Instruction *Src, Instruction *Dst,
|
|||||||
// For debugging purposes, dump a small bit vector to dbgs().
|
// For debugging purposes, dump a small bit vector to dbgs().
|
||||||
static void dumpSmallBitVector(SmallBitVector &BV) {
|
static void dumpSmallBitVector(SmallBitVector &BV) {
|
||||||
dbgs() << "{";
|
dbgs() << "{";
|
||||||
for (int VI = BV.find_first(); VI >= 0; VI = BV.find_next(VI)) {
|
for (unsigned VI : BV.set_bits()) {
|
||||||
dbgs() << VI;
|
dbgs() << VI;
|
||||||
if (BV.find_next(VI) >= 0)
|
if (BV.find_next(VI) >= 0)
|
||||||
dbgs() << ' ';
|
dbgs() << ' ';
|
||||||
@ -3506,7 +3506,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
NewConstraint.setAny(SE);
|
NewConstraint.setAny(SE);
|
||||||
|
|
||||||
// test separable subscripts
|
// test separable subscripts
|
||||||
for (int SI = Separable.find_first(); SI >= 0; SI = Separable.find_next(SI)) {
|
for (unsigned SI : Separable.set_bits()) {
|
||||||
DEBUG(dbgs() << "testing subscript " << SI);
|
DEBUG(dbgs() << "testing subscript " << SI);
|
||||||
switch (Pair[SI].Classification) {
|
switch (Pair[SI].Classification) {
|
||||||
case Subscript::ZIV:
|
case Subscript::ZIV:
|
||||||
@ -3545,14 +3545,14 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
SmallVector<Constraint, 4> Constraints(MaxLevels + 1);
|
SmallVector<Constraint, 4> Constraints(MaxLevels + 1);
|
||||||
for (unsigned II = 0; II <= MaxLevels; ++II)
|
for (unsigned II = 0; II <= MaxLevels; ++II)
|
||||||
Constraints[II].setAny(SE);
|
Constraints[II].setAny(SE);
|
||||||
for (int SI = Coupled.find_first(); SI >= 0; SI = Coupled.find_next(SI)) {
|
for (unsigned SI : Coupled.set_bits()) {
|
||||||
DEBUG(dbgs() << "testing subscript group " << SI << " { ");
|
DEBUG(dbgs() << "testing subscript group " << SI << " { ");
|
||||||
SmallBitVector Group(Pair[SI].Group);
|
SmallBitVector Group(Pair[SI].Group);
|
||||||
SmallBitVector Sivs(Pairs);
|
SmallBitVector Sivs(Pairs);
|
||||||
SmallBitVector Mivs(Pairs);
|
SmallBitVector Mivs(Pairs);
|
||||||
SmallBitVector ConstrainedLevels(MaxLevels + 1);
|
SmallBitVector ConstrainedLevels(MaxLevels + 1);
|
||||||
SmallVector<Subscript *, 4> PairsInGroup;
|
SmallVector<Subscript *, 4> PairsInGroup;
|
||||||
for (int SJ = Group.find_first(); SJ >= 0; SJ = Group.find_next(SJ)) {
|
for (unsigned SJ : Group.set_bits()) {
|
||||||
DEBUG(dbgs() << SJ << " ");
|
DEBUG(dbgs() << SJ << " ");
|
||||||
if (Pair[SJ].Classification == Subscript::SIV)
|
if (Pair[SJ].Classification == Subscript::SIV)
|
||||||
Sivs.set(SJ);
|
Sivs.set(SJ);
|
||||||
@ -3564,7 +3564,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
DEBUG(dbgs() << "}\n");
|
DEBUG(dbgs() << "}\n");
|
||||||
while (Sivs.any()) {
|
while (Sivs.any()) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
for (int SJ = Sivs.find_first(); SJ >= 0; SJ = Sivs.find_next(SJ)) {
|
for (unsigned SJ : Sivs.set_bits()) {
|
||||||
DEBUG(dbgs() << "testing subscript " << SJ << ", SIV\n");
|
DEBUG(dbgs() << "testing subscript " << SJ << ", SIV\n");
|
||||||
// SJ is an SIV subscript that's part of the current coupled group
|
// SJ is an SIV subscript that's part of the current coupled group
|
||||||
unsigned Level;
|
unsigned Level;
|
||||||
@ -3588,7 +3588,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
DEBUG(dbgs() << " propagating\n");
|
DEBUG(dbgs() << " propagating\n");
|
||||||
DEBUG(dbgs() << "\tMivs = ");
|
DEBUG(dbgs() << "\tMivs = ");
|
||||||
DEBUG(dumpSmallBitVector(Mivs));
|
DEBUG(dumpSmallBitVector(Mivs));
|
||||||
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
|
for (unsigned SJ : Mivs.set_bits()) {
|
||||||
// SJ is an MIV subscript that's part of the current coupled group
|
// SJ is an MIV subscript that's part of the current coupled group
|
||||||
DEBUG(dbgs() << "\tSJ = " << SJ << "\n");
|
DEBUG(dbgs() << "\tSJ = " << SJ << "\n");
|
||||||
if (propagate(Pair[SJ].Src, Pair[SJ].Dst, Pair[SJ].Loops,
|
if (propagate(Pair[SJ].Src, Pair[SJ].Dst, Pair[SJ].Loops,
|
||||||
@ -3622,7 +3622,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test & propagate remaining RDIVs
|
// test & propagate remaining RDIVs
|
||||||
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
|
for (unsigned SJ : Mivs.set_bits()) {
|
||||||
if (Pair[SJ].Classification == Subscript::RDIV) {
|
if (Pair[SJ].Classification == Subscript::RDIV) {
|
||||||
DEBUG(dbgs() << "RDIV test\n");
|
DEBUG(dbgs() << "RDIV test\n");
|
||||||
if (testRDIV(Pair[SJ].Src, Pair[SJ].Dst, Result))
|
if (testRDIV(Pair[SJ].Src, Pair[SJ].Dst, Result))
|
||||||
@ -3635,7 +3635,7 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
// test remaining MIVs
|
// test remaining MIVs
|
||||||
// This code is temporary.
|
// This code is temporary.
|
||||||
// Better to somehow test all remaining subscripts simultaneously.
|
// Better to somehow test all remaining subscripts simultaneously.
|
||||||
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
|
for (unsigned SJ : Mivs.set_bits()) {
|
||||||
if (Pair[SJ].Classification == Subscript::MIV) {
|
if (Pair[SJ].Classification == Subscript::MIV) {
|
||||||
DEBUG(dbgs() << "MIV test\n");
|
DEBUG(dbgs() << "MIV test\n");
|
||||||
if (testMIV(Pair[SJ].Src, Pair[SJ].Dst, Pair[SJ].Loops, Result))
|
if (testMIV(Pair[SJ].Src, Pair[SJ].Dst, Pair[SJ].Loops, Result))
|
||||||
@ -3647,9 +3647,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,
|
|||||||
|
|
||||||
// update Result.DV from constraint vector
|
// update Result.DV from constraint vector
|
||||||
DEBUG(dbgs() << " updating\n");
|
DEBUG(dbgs() << " updating\n");
|
||||||
for (int SJ = ConstrainedLevels.find_first(); SJ >= 0;
|
for (unsigned SJ : ConstrainedLevels.set_bits()) {
|
||||||
SJ = ConstrainedLevels.find_next(SJ)) {
|
if (SJ > CommonLevels)
|
||||||
if (SJ > (int)CommonLevels)
|
|
||||||
break;
|
break;
|
||||||
updateDirection(Result.DV[SJ - 1], Constraints[SJ]);
|
updateDirection(Result.DV[SJ - 1], Constraints[SJ]);
|
||||||
if (Result.DV[SJ - 1].Direction == Dependence::DVEntry::NONE)
|
if (Result.DV[SJ - 1].Direction == Dependence::DVEntry::NONE)
|
||||||
@ -3859,7 +3858,7 @@ const SCEV *DependenceInfo::getSplitIteration(const Dependence &Dep,
|
|||||||
NewConstraint.setAny(SE);
|
NewConstraint.setAny(SE);
|
||||||
|
|
||||||
// test separable subscripts
|
// test separable subscripts
|
||||||
for (int SI = Separable.find_first(); SI >= 0; SI = Separable.find_next(SI)) {
|
for (unsigned SI : Separable.set_bits()) {
|
||||||
switch (Pair[SI].Classification) {
|
switch (Pair[SI].Classification) {
|
||||||
case Subscript::SIV: {
|
case Subscript::SIV: {
|
||||||
unsigned Level;
|
unsigned Level;
|
||||||
@ -3886,12 +3885,12 @@ const SCEV *DependenceInfo::getSplitIteration(const Dependence &Dep,
|
|||||||
SmallVector<Constraint, 4> Constraints(MaxLevels + 1);
|
SmallVector<Constraint, 4> Constraints(MaxLevels + 1);
|
||||||
for (unsigned II = 0; II <= MaxLevels; ++II)
|
for (unsigned II = 0; II <= MaxLevels; ++II)
|
||||||
Constraints[II].setAny(SE);
|
Constraints[II].setAny(SE);
|
||||||
for (int SI = Coupled.find_first(); SI >= 0; SI = Coupled.find_next(SI)) {
|
for (unsigned SI : Coupled.set_bits()) {
|
||||||
SmallBitVector Group(Pair[SI].Group);
|
SmallBitVector Group(Pair[SI].Group);
|
||||||
SmallBitVector Sivs(Pairs);
|
SmallBitVector Sivs(Pairs);
|
||||||
SmallBitVector Mivs(Pairs);
|
SmallBitVector Mivs(Pairs);
|
||||||
SmallBitVector ConstrainedLevels(MaxLevels + 1);
|
SmallBitVector ConstrainedLevels(MaxLevels + 1);
|
||||||
for (int SJ = Group.find_first(); SJ >= 0; SJ = Group.find_next(SJ)) {
|
for (unsigned SJ : Group.set_bits()) {
|
||||||
if (Pair[SJ].Classification == Subscript::SIV)
|
if (Pair[SJ].Classification == Subscript::SIV)
|
||||||
Sivs.set(SJ);
|
Sivs.set(SJ);
|
||||||
else
|
else
|
||||||
@ -3899,7 +3898,7 @@ const SCEV *DependenceInfo::getSplitIteration(const Dependence &Dep,
|
|||||||
}
|
}
|
||||||
while (Sivs.any()) {
|
while (Sivs.any()) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
for (int SJ = Sivs.find_first(); SJ >= 0; SJ = Sivs.find_next(SJ)) {
|
for (unsigned SJ : Sivs.set_bits()) {
|
||||||
// SJ is an SIV subscript that's part of the current coupled group
|
// SJ is an SIV subscript that's part of the current coupled group
|
||||||
unsigned Level;
|
unsigned Level;
|
||||||
const SCEV *SplitIter = nullptr;
|
const SCEV *SplitIter = nullptr;
|
||||||
@ -3914,7 +3913,7 @@ const SCEV *DependenceInfo::getSplitIteration(const Dependence &Dep,
|
|||||||
}
|
}
|
||||||
if (Changed) {
|
if (Changed) {
|
||||||
// propagate, possibly creating new SIVs and ZIVs
|
// propagate, possibly creating new SIVs and ZIVs
|
||||||
for (int SJ = Mivs.find_first(); SJ >= 0; SJ = Mivs.find_next(SJ)) {
|
for (unsigned SJ : Mivs.set_bits()) {
|
||||||
// SJ is an MIV subscript that's part of the current coupled group
|
// SJ is an MIV subscript that's part of the current coupled group
|
||||||
if (propagate(Pair[SJ].Src, Pair[SJ].Dst,
|
if (propagate(Pair[SJ].Src, Pair[SJ].Dst,
|
||||||
Pair[SJ].Loops, Constraints, Result.Consistent)) {
|
Pair[SJ].Loops, Constraints, Result.Consistent)) {
|
||||||
|
@ -669,21 +669,33 @@ void CallAnalyzer::updateThreshold(CallSite CS, Function &Callee) {
|
|||||||
Threshold = MaxIfValid(Threshold, Params.HintThreshold);
|
Threshold = MaxIfValid(Threshold, Params.HintThreshold);
|
||||||
if (PSI) {
|
if (PSI) {
|
||||||
BlockFrequencyInfo *CallerBFI = GetBFI ? &((*GetBFI)(*Caller)) : nullptr;
|
BlockFrequencyInfo *CallerBFI = GetBFI ? &((*GetBFI)(*Caller)) : nullptr;
|
||||||
if (PSI->isHotCallSite(CS, CallerBFI)) {
|
// FIXME: After switching to the new passmanager, simplify the logic below
|
||||||
DEBUG(dbgs() << "Hot callsite.\n");
|
// by checking only the callsite hotness/coldness. The check for CallerBFI
|
||||||
Threshold = Params.HotCallSiteThreshold.getValue();
|
// exists only because we do not have BFI available with the old PM.
|
||||||
} else if (PSI->isFunctionEntryHot(&Callee)) {
|
//
|
||||||
DEBUG(dbgs() << "Hot callee.\n");
|
// Use callee's hotness information only if we have no way of determining
|
||||||
// If callsite hotness can not be determined, we may still know
|
// callsite's hotness information. Callsite hotness can be determined if
|
||||||
// that the callee is hot and treat it as a weaker hint for threshold
|
// sample profile is used (which adds hotness metadata to calls) or if
|
||||||
// increase.
|
// caller's BlockFrequencyInfo is available.
|
||||||
Threshold = MaxIfValid(Threshold, Params.HintThreshold);
|
if (CallerBFI || PSI->hasSampleProfile()) {
|
||||||
} else if (PSI->isColdCallSite(CS, CallerBFI)) {
|
if (PSI->isHotCallSite(CS, CallerBFI)) {
|
||||||
DEBUG(dbgs() << "Cold callsite.\n");
|
DEBUG(dbgs() << "Hot callsite.\n");
|
||||||
Threshold = MinIfValid(Threshold, Params.ColdCallSiteThreshold);
|
Threshold = Params.HotCallSiteThreshold.getValue();
|
||||||
} else if (PSI->isFunctionEntryCold(&Callee)) {
|
} else if (PSI->isColdCallSite(CS, CallerBFI)) {
|
||||||
DEBUG(dbgs() << "Cold callee.\n");
|
DEBUG(dbgs() << "Cold callsite.\n");
|
||||||
Threshold = MinIfValid(Threshold, Params.ColdThreshold);
|
Threshold = MinIfValid(Threshold, Params.ColdCallSiteThreshold);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (PSI->isFunctionEntryHot(&Callee)) {
|
||||||
|
DEBUG(dbgs() << "Hot callee.\n");
|
||||||
|
// If callsite hotness can not be determined, we may still know
|
||||||
|
// that the callee is hot and treat it as a weaker hint for threshold
|
||||||
|
// increase.
|
||||||
|
Threshold = MaxIfValid(Threshold, Params.HintThreshold);
|
||||||
|
} else if (PSI->isFunctionEntryCold(&Callee)) {
|
||||||
|
DEBUG(dbgs() << "Cold callee.\n");
|
||||||
|
Threshold = MinIfValid(Threshold, Params.ColdThreshold);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1752,6 +1752,24 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
|
|||||||
(A == Op0 || B == Op0))
|
(A == Op0 || B == Op0))
|
||||||
return Op0;
|
return Op0;
|
||||||
|
|
||||||
|
// A mask that only clears known zeros of a shifted value is a no-op.
|
||||||
|
Value *X;
|
||||||
|
const APInt *Mask;
|
||||||
|
const APInt *ShAmt;
|
||||||
|
if (match(Op1, m_APInt(Mask))) {
|
||||||
|
// If all bits in the inverted and shifted mask are clear:
|
||||||
|
// and (shl X, ShAmt), Mask --> shl X, ShAmt
|
||||||
|
if (match(Op0, m_Shl(m_Value(X), m_APInt(ShAmt))) &&
|
||||||
|
(~(*Mask)).lshr(*ShAmt).isNullValue())
|
||||||
|
return Op0;
|
||||||
|
|
||||||
|
// If all bits in the inverted and shifted mask are clear:
|
||||||
|
// and (lshr X, ShAmt), Mask --> lshr X, ShAmt
|
||||||
|
if (match(Op0, m_LShr(m_Value(X), m_APInt(ShAmt))) &&
|
||||||
|
(~(*Mask)).shl(*ShAmt).isNullValue())
|
||||||
|
return Op0;
|
||||||
|
}
|
||||||
|
|
||||||
// A & (-A) = A if A is a power of two or zero.
|
// A & (-A) = A if A is a power of two or zero.
|
||||||
if (match(Op0, m_Neg(m_Specific(Op1))) ||
|
if (match(Op0, m_Neg(m_Specific(Op1))) ||
|
||||||
match(Op1, m_Neg(m_Specific(Op0)))) {
|
match(Op1, m_Neg(m_Specific(Op0)))) {
|
||||||
|
@ -75,7 +75,7 @@ ProfileSummaryInfo::getProfileCount(const Instruction *Inst,
|
|||||||
return None;
|
return None;
|
||||||
assert((isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) &&
|
assert((isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) &&
|
||||||
"We can only get profile count for call/invoke instruction.");
|
"We can only get profile count for call/invoke instruction.");
|
||||||
if (computeSummary() && Summary->getKind() == ProfileSummary::PSK_Sample) {
|
if (hasSampleProfile()) {
|
||||||
// In sample PGO mode, check if there is a profile metadata on the
|
// In sample PGO mode, check if there is a profile metadata on the
|
||||||
// instruction. If it is present, determine hotness solely based on that,
|
// instruction. If it is present, determine hotness solely based on that,
|
||||||
// since the sampled entry count may not be accurate.
|
// since the sampled entry count may not be accurate.
|
||||||
|
@ -629,19 +629,19 @@ static int CompareSCEVComplexity(
|
|||||||
const SCEVAddRecExpr *LA = cast<SCEVAddRecExpr>(LHS);
|
const SCEVAddRecExpr *LA = cast<SCEVAddRecExpr>(LHS);
|
||||||
const SCEVAddRecExpr *RA = cast<SCEVAddRecExpr>(RHS);
|
const SCEVAddRecExpr *RA = cast<SCEVAddRecExpr>(RHS);
|
||||||
|
|
||||||
// If there is a dominance relationship between the loops, sort by the
|
// There is always a dominance between two recs that are used by one SCEV,
|
||||||
// dominance. Otherwise, sort by depth. We require such order in getAddExpr.
|
// so we can safely sort recs by loop header dominance. We require such
|
||||||
|
// order in getAddExpr.
|
||||||
const Loop *LLoop = LA->getLoop(), *RLoop = RA->getLoop();
|
const Loop *LLoop = LA->getLoop(), *RLoop = RA->getLoop();
|
||||||
if (LLoop != RLoop) {
|
if (LLoop != RLoop) {
|
||||||
const BasicBlock *LHead = LLoop->getHeader(), *RHead = RLoop->getHeader();
|
const BasicBlock *LHead = LLoop->getHeader(), *RHead = RLoop->getHeader();
|
||||||
assert(LHead != RHead && "Two loops share the same header?");
|
assert(LHead != RHead && "Two loops share the same header?");
|
||||||
if (DT.dominates(LHead, RHead))
|
if (DT.dominates(LHead, RHead))
|
||||||
return 1;
|
return 1;
|
||||||
else if (DT.dominates(RHead, LHead))
|
else
|
||||||
return -1;
|
assert(DT.dominates(RHead, LHead) &&
|
||||||
unsigned LDepth = LLoop->getLoopDepth(), RDepth = RLoop->getLoopDepth();
|
"No dominance between recurrences used by one SCEV?");
|
||||||
if (LDepth != RDepth)
|
return -1;
|
||||||
return (int)LDepth - (int)RDepth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addrec complexity grows with operand count.
|
// Addrec complexity grows with operand count.
|
||||||
@ -2512,22 +2512,23 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
|
|||||||
SmallVector<const SCEV *, 4> AddRecOps(AddRec->op_begin(),
|
SmallVector<const SCEV *, 4> AddRecOps(AddRec->op_begin(),
|
||||||
AddRec->op_end());
|
AddRec->op_end());
|
||||||
for (; OtherIdx != Ops.size() && isa<SCEVAddRecExpr>(Ops[OtherIdx]);
|
for (; OtherIdx != Ops.size() && isa<SCEVAddRecExpr>(Ops[OtherIdx]);
|
||||||
++OtherIdx)
|
++OtherIdx) {
|
||||||
if (const auto *OtherAddRec = dyn_cast<SCEVAddRecExpr>(Ops[OtherIdx]))
|
const auto *OtherAddRec = cast<SCEVAddRecExpr>(Ops[OtherIdx]);
|
||||||
if (OtherAddRec->getLoop() == AddRecLoop) {
|
if (OtherAddRec->getLoop() == AddRecLoop) {
|
||||||
for (unsigned i = 0, e = OtherAddRec->getNumOperands();
|
for (unsigned i = 0, e = OtherAddRec->getNumOperands();
|
||||||
i != e; ++i) {
|
i != e; ++i) {
|
||||||
if (i >= AddRecOps.size()) {
|
if (i >= AddRecOps.size()) {
|
||||||
AddRecOps.append(OtherAddRec->op_begin()+i,
|
AddRecOps.append(OtherAddRec->op_begin()+i,
|
||||||
OtherAddRec->op_end());
|
OtherAddRec->op_end());
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
SmallVector<const SCEV *, 2> TwoOps = {
|
|
||||||
AddRecOps[i], OtherAddRec->getOperand(i)};
|
|
||||||
AddRecOps[i] = getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1);
|
|
||||||
}
|
}
|
||||||
Ops.erase(Ops.begin() + OtherIdx); --OtherIdx;
|
SmallVector<const SCEV *, 2> TwoOps = {
|
||||||
|
AddRecOps[i], OtherAddRec->getOperand(i)};
|
||||||
|
AddRecOps[i] = getAddExpr(TwoOps, SCEV::FlagAnyWrap, Depth + 1);
|
||||||
}
|
}
|
||||||
|
Ops.erase(Ops.begin() + OtherIdx); --OtherIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Step size has changed, so we cannot guarantee no self-wraparound.
|
// Step size has changed, so we cannot guarantee no self-wraparound.
|
||||||
Ops[Idx] = getAddRecExpr(AddRecOps, AddRecLoop, SCEV::FlagAnyWrap);
|
Ops[Idx] = getAddRecExpr(AddRecOps, AddRecLoop, SCEV::FlagAnyWrap);
|
||||||
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
|
return getAddExpr(Ops, SCEV::FlagAnyWrap, Depth + 1);
|
||||||
|
@ -128,8 +128,7 @@ AggressiveAntiDepBreaker::AggressiveAntiDepBreaker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(dbgs() << "AntiDep Critical-Path Registers:");
|
DEBUG(dbgs() << "AntiDep Critical-Path Registers:");
|
||||||
DEBUG(for (int r = CriticalPathSet.find_first(); r != -1;
|
DEBUG(for (unsigned r : CriticalPathSet.set_bits())
|
||||||
r = CriticalPathSet.find_next(r))
|
|
||||||
dbgs() << " " << TRI->getName(r));
|
dbgs() << " " << TRI->getName(r));
|
||||||
DEBUG(dbgs() << '\n');
|
DEBUG(dbgs() << '\n');
|
||||||
}
|
}
|
||||||
@ -571,7 +570,7 @@ bool AggressiveAntiDepBreaker::FindSuitableFreeRegisters(
|
|||||||
|
|
||||||
DEBUG({
|
DEBUG({
|
||||||
dbgs() << " ::";
|
dbgs() << " ::";
|
||||||
for (int r = BV.find_first(); r != -1; r = BV.find_next(r))
|
for (unsigned r : BV.set_bits())
|
||||||
dbgs() << " " << TRI->getName(r);
|
dbgs() << " " << TRI->getName(r);
|
||||||
dbgs() << "\n";
|
dbgs() << "\n";
|
||||||
});
|
});
|
||||||
|
@ -501,7 +501,7 @@ void CodeViewDebug::emitTypeInformation() {
|
|||||||
Error E = Reader.readArray(Types, Reader.getLength());
|
Error E = Reader.readArray(Types, Reader.getLength());
|
||||||
if (!E) {
|
if (!E) {
|
||||||
TypeVisitorCallbacks C;
|
TypeVisitorCallbacks C;
|
||||||
E = CVTypeVisitor(C).visitTypeStream(Types);
|
E = codeview::visitTypeStream(Types, C);
|
||||||
}
|
}
|
||||||
if (E) {
|
if (E) {
|
||||||
logAllUnhandledErrors(std::move(E), errs(), "error: ");
|
logAllUnhandledErrors(std::move(E), errs(), "error: ");
|
||||||
|
@ -209,8 +209,7 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF,
|
|||||||
} else if (MO.isRegMask()) {
|
} else if (MO.isRegMask()) {
|
||||||
// If this is a register mask operand, clobber all debug values in
|
// If this is a register mask operand, clobber all debug values in
|
||||||
// non-CSRs.
|
// non-CSRs.
|
||||||
for (int I = ChangingRegs.find_first(); I != -1;
|
for (unsigned I : ChangingRegs.set_bits()) {
|
||||||
I = ChangingRegs.find_next(I)) {
|
|
||||||
// Don't consider SP to be clobbered by register masks.
|
// Don't consider SP to be clobbered by register masks.
|
||||||
if (unsigned(I) != SP && TRI->isPhysicalRegister(I) &&
|
if (unsigned(I) != SP && TRI->isPhysicalRegister(I) &&
|
||||||
MO.clobbersPhysReg(I)) {
|
MO.clobbersPhysReg(I)) {
|
||||||
|
@ -1129,6 +1129,11 @@ void IRTranslator::finalizeFunction() {
|
|||||||
ValToVReg.clear();
|
ValToVReg.clear();
|
||||||
FrameIndices.clear();
|
FrameIndices.clear();
|
||||||
MachinePreds.clear();
|
MachinePreds.clear();
|
||||||
|
// MachineIRBuilder::DebugLoc can outlive the DILocation it holds. Clear it
|
||||||
|
// to avoid accessing free’d memory (in runOnMachineFunction) and to avoid
|
||||||
|
// destroying it twice (in ~IRTranslator() and ~LLVMContext())
|
||||||
|
EntryBuilder = MachineIRBuilder();
|
||||||
|
CurBuilder = MachineIRBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
|
bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
|
||||||
|
@ -760,7 +760,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) {
|
|||||||
|
|
||||||
const MachineFrameInfo &MFI = MF->getFrameInfo();
|
const MachineFrameInfo &MFI = MF->getFrameInfo();
|
||||||
BitVector PR = MFI.getPristineRegs(*MF);
|
BitVector PR = MFI.getPristineRegs(*MF);
|
||||||
for (int I = PR.find_first(); I>0; I = PR.find_next(I)) {
|
for (unsigned I : PR.set_bits()) {
|
||||||
for (MCSubRegIterator SubRegs(I, TRI, /*IncludeSelf=*/true);
|
for (MCSubRegIterator SubRegs(I, TRI, /*IncludeSelf=*/true);
|
||||||
SubRegs.isValid(); ++SubRegs)
|
SubRegs.isValid(); ++SubRegs)
|
||||||
regsLive.insert(*SubRegs);
|
regsLive.insert(*SubRegs);
|
||||||
|
@ -285,8 +285,7 @@ class RAGreedy : public MachineFunctionPass,
|
|||||||
// Set B[i] = C for every live bundle where B[i] was NoCand.
|
// Set B[i] = C for every live bundle where B[i] was NoCand.
|
||||||
unsigned getBundles(SmallVectorImpl<unsigned> &B, unsigned C) {
|
unsigned getBundles(SmallVectorImpl<unsigned> &B, unsigned C) {
|
||||||
unsigned Count = 0;
|
unsigned Count = 0;
|
||||||
for (int i = LiveBundles.find_first(); i >= 0;
|
for (unsigned i : LiveBundles.set_bits())
|
||||||
i = LiveBundles.find_next(i))
|
|
||||||
if (B[i] == NoCand) {
|
if (B[i] == NoCand) {
|
||||||
B[i] = C;
|
B[i] = C;
|
||||||
Count++;
|
Count++;
|
||||||
@ -1162,9 +1161,8 @@ bool RAGreedy::calcCompactRegion(GlobalSplitCandidate &Cand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG({
|
DEBUG({
|
||||||
for (int i = Cand.LiveBundles.find_first(); i>=0;
|
for (int i : Cand.LiveBundles.set_bits())
|
||||||
i = Cand.LiveBundles.find_next(i))
|
dbgs() << " EB#" << i;
|
||||||
dbgs() << " EB#" << i;
|
|
||||||
dbgs() << ".\n";
|
dbgs() << ".\n";
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@ -1482,8 +1480,7 @@ unsigned RAGreedy::calculateRegionSplitCost(LiveInterval &VirtReg,
|
|||||||
DEBUG({
|
DEBUG({
|
||||||
dbgs() << ", total = "; MBFI->printBlockFreq(dbgs(), Cost)
|
dbgs() << ", total = "; MBFI->printBlockFreq(dbgs(), Cost)
|
||||||
<< " with bundles";
|
<< " with bundles";
|
||||||
for (int i = Cand.LiveBundles.find_first(); i>=0;
|
for (int i : Cand.LiveBundles.set_bits())
|
||||||
i = Cand.LiveBundles.find_next(i))
|
|
||||||
dbgs() << " EB#" << i;
|
dbgs() << " EB#" << i;
|
||||||
dbgs() << ".\n";
|
dbgs() << ".\n";
|
||||||
});
|
});
|
||||||
|
@ -13087,14 +13087,28 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a store followed by a store with the same value to the same
|
|
||||||
// location, then the store is dead/noop.
|
|
||||||
if (StoreSDNode *ST1 = dyn_cast<StoreSDNode>(Chain)) {
|
if (StoreSDNode *ST1 = dyn_cast<StoreSDNode>(Chain)) {
|
||||||
if (ST1->getBasePtr() == Ptr && ST->getMemoryVT() == ST1->getMemoryVT() &&
|
if (ST->isUnindexed() && !ST->isVolatile() && ST1->isUnindexed() &&
|
||||||
ST1->getValue() == Value && ST->isUnindexed() && !ST->isVolatile() &&
|
!ST1->isVolatile() && ST1->getBasePtr() == Ptr &&
|
||||||
ST1->isUnindexed() && !ST1->isVolatile()) {
|
ST->getMemoryVT() == ST1->getMemoryVT()) {
|
||||||
// The store is dead, remove it.
|
// If this is a store followed by a store with the same value to the same
|
||||||
return Chain;
|
// location, then the store is dead/noop.
|
||||||
|
if (ST1->getValue() == Value) {
|
||||||
|
// The store is dead, remove it.
|
||||||
|
return Chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a store who's preceeding store to the same location
|
||||||
|
// and no one other node is chained to that store we can effectively
|
||||||
|
// drop the store. Do not remove stores to undef as they may be used as
|
||||||
|
// data sinks.
|
||||||
|
if (OptLevel != CodeGenOpt::None && ST1->hasOneUse() &&
|
||||||
|
!ST1->getBasePtr().isUndef()) {
|
||||||
|
// ST1 is fully overwritten and can be elided. Combine with it's chain
|
||||||
|
// value.
|
||||||
|
CombineTo(ST1, ST1->getChain());
|
||||||
|
return SDValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ void SpillPlacement::addLinks(ArrayRef<unsigned> Links) {
|
|||||||
|
|
||||||
bool SpillPlacement::scanActiveBundles() {
|
bool SpillPlacement::scanActiveBundles() {
|
||||||
RecentPositive.clear();
|
RecentPositive.clear();
|
||||||
for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n)) {
|
for (unsigned n : ActiveNodes->set_bits()) {
|
||||||
update(n);
|
update(n);
|
||||||
// A node that must spill, or a node without any links is not going to
|
// A node that must spill, or a node without any links is not going to
|
||||||
// change its value ever again, so exclude it from iterations.
|
// change its value ever again, so exclude it from iterations.
|
||||||
@ -365,7 +365,7 @@ SpillPlacement::finish() {
|
|||||||
|
|
||||||
// Write preferences back to ActiveNodes.
|
// Write preferences back to ActiveNodes.
|
||||||
bool Perfect = true;
|
bool Perfect = true;
|
||||||
for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n))
|
for (unsigned n : ActiveNodes->set_bits())
|
||||||
if (!nodes[n].preferReg()) {
|
if (!nodes[n].preferReg()) {
|
||||||
ActiveNodes->reset(n);
|
ActiveNodes->reset(n);
|
||||||
Perfect = false;
|
Perfect = false;
|
||||||
|
@ -703,12 +703,10 @@ void StackColoring::calculateLiveIntervals(unsigned NumSlots) {
|
|||||||
|
|
||||||
// Create the interval of the blocks that we previously found to be 'alive'.
|
// Create the interval of the blocks that we previously found to be 'alive'.
|
||||||
BlockLifetimeInfo &MBBLiveness = BlockLiveness[&MBB];
|
BlockLifetimeInfo &MBBLiveness = BlockLiveness[&MBB];
|
||||||
for (int pos = MBBLiveness.LiveIn.find_first(); pos != -1;
|
for (unsigned pos : MBBLiveness.LiveIn.set_bits()) {
|
||||||
pos = MBBLiveness.LiveIn.find_next(pos)) {
|
|
||||||
Starts[pos] = Indexes->getMBBStartIdx(&MBB);
|
Starts[pos] = Indexes->getMBBStartIdx(&MBB);
|
||||||
}
|
}
|
||||||
for (int pos = MBBLiveness.LiveOut.find_first(); pos != -1;
|
for (unsigned pos : MBBLiveness.LiveOut.set_bits()) {
|
||||||
pos = MBBLiveness.LiveOut.find_next(pos)) {
|
|
||||||
Finishes[pos] = Indexes->getMBBEndIdx(&MBB);
|
Finishes[pos] = Indexes->getMBBEndIdx(&MBB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1312,7 +1312,7 @@ TargetLoweringBase::findRepresentativeClass(const TargetRegisterInfo *TRI,
|
|||||||
|
|
||||||
// Find the first legal register class with the largest spill size.
|
// Find the first legal register class with the largest spill size.
|
||||||
const TargetRegisterClass *BestRC = RC;
|
const TargetRegisterClass *BestRC = RC;
|
||||||
for (int i = SuperRegRC.find_first(); i >= 0; i = SuperRegRC.find_next(i)) {
|
for (unsigned i : SuperRegRC.set_bits()) {
|
||||||
const TargetRegisterClass *SuperRC = TRI->getRegClass(i);
|
const TargetRegisterClass *SuperRC = TRI->getRegClass(i);
|
||||||
// We want the largest possible spill size.
|
// We want the largest possible spill size.
|
||||||
if (TRI->getSpillSize(*SuperRC) <= TRI->getSpillSize(*BestRC))
|
if (TRI->getSpillSize(*SuperRC) <= TRI->getSpillSize(*BestRC))
|
||||||
|
@ -564,6 +564,14 @@ void TargetPassConfig::addISelPrepare() {
|
|||||||
addPass(createVerifierPass());
|
addPass(createVerifierPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// -regalloc=... command line option.
|
||||||
|
static FunctionPass *useDefaultRegisterAllocator() { return nullptr; }
|
||||||
|
static cl::opt<RegisterRegAlloc::FunctionPassCtor, false,
|
||||||
|
RegisterPassParser<RegisterRegAlloc> >
|
||||||
|
RegAlloc("regalloc",
|
||||||
|
cl::init(&useDefaultRegisterAllocator),
|
||||||
|
cl::desc("Register allocator to use"));
|
||||||
|
|
||||||
/// Add the complete set of target-independent postISel code generator passes.
|
/// Add the complete set of target-independent postISel code generator passes.
|
||||||
///
|
///
|
||||||
/// This can be read as the standard order of major LLVM CodeGen stages. Stages
|
/// This can be read as the standard order of major LLVM CodeGen stages. Stages
|
||||||
@ -625,8 +633,12 @@ void TargetPassConfig::addMachinePasses() {
|
|||||||
// including phi elimination and scheduling.
|
// including phi elimination and scheduling.
|
||||||
if (getOptimizeRegAlloc())
|
if (getOptimizeRegAlloc())
|
||||||
addOptimizedRegAlloc(createRegAllocPass(true));
|
addOptimizedRegAlloc(createRegAllocPass(true));
|
||||||
else
|
else {
|
||||||
|
if (RegAlloc != &useDefaultRegisterAllocator &&
|
||||||
|
RegAlloc != &createFastRegisterAllocator)
|
||||||
|
report_fatal_error("Must use fast (default) register allocator for unoptimized regalloc.");
|
||||||
addFastRegAlloc(createRegAllocPass(false));
|
addFastRegAlloc(createRegAllocPass(false));
|
||||||
|
}
|
||||||
|
|
||||||
// Run post-ra passes.
|
// Run post-ra passes.
|
||||||
addPostRegAlloc();
|
addPostRegAlloc();
|
||||||
@ -759,19 +771,12 @@ MachinePassRegistry RegisterRegAlloc::Registry;
|
|||||||
/// A dummy default pass factory indicates whether the register allocator is
|
/// A dummy default pass factory indicates whether the register allocator is
|
||||||
/// overridden on the command line.
|
/// overridden on the command line.
|
||||||
static llvm::once_flag InitializeDefaultRegisterAllocatorFlag;
|
static llvm::once_flag InitializeDefaultRegisterAllocatorFlag;
|
||||||
static FunctionPass *useDefaultRegisterAllocator() { return nullptr; }
|
|
||||||
static RegisterRegAlloc
|
static RegisterRegAlloc
|
||||||
defaultRegAlloc("default",
|
defaultRegAlloc("default",
|
||||||
"pick register allocator based on -O option",
|
"pick register allocator based on -O option",
|
||||||
useDefaultRegisterAllocator);
|
useDefaultRegisterAllocator);
|
||||||
|
|
||||||
/// -regalloc=... command line option.
|
|
||||||
static cl::opt<RegisterRegAlloc::FunctionPassCtor, false,
|
|
||||||
RegisterPassParser<RegisterRegAlloc> >
|
|
||||||
RegAlloc("regalloc",
|
|
||||||
cl::init(&useDefaultRegisterAllocator),
|
|
||||||
cl::desc("Register allocator to use"));
|
|
||||||
|
|
||||||
static void initializeDefaultRegisterAllocatorOnce() {
|
static void initializeDefaultRegisterAllocatorOnce() {
|
||||||
RegisterRegAlloc::FunctionPassCtor Ctor = RegisterRegAlloc::getDefault();
|
RegisterRegAlloc::FunctionPassCtor Ctor = RegisterRegAlloc::getDefault();
|
||||||
|
|
||||||
@ -781,7 +786,6 @@ static void initializeDefaultRegisterAllocatorOnce() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Instantiate the default register allocator pass for this target for either
|
/// Instantiate the default register allocator pass for this target for either
|
||||||
/// the optimized or unoptimized allocation path. This will be added to the pass
|
/// the optimized or unoptimized allocation path. This will be added to the pass
|
||||||
/// manager by addFastRegAlloc in the unoptimized case or addOptimizedRegAlloc
|
/// manager by addFastRegAlloc in the unoptimized case or addOptimizedRegAlloc
|
||||||
|
@ -50,8 +50,7 @@ bool TargetRegisterInfo::checkAllSuperRegsMarked(const BitVector &RegisterSet,
|
|||||||
ArrayRef<MCPhysReg> Exceptions) const {
|
ArrayRef<MCPhysReg> Exceptions) const {
|
||||||
// Check that all super registers of reserved regs are reserved as well.
|
// Check that all super registers of reserved regs are reserved as well.
|
||||||
BitVector Checked(getNumRegs());
|
BitVector Checked(getNumRegs());
|
||||||
for (int Reg = RegisterSet.find_first(); Reg>=0;
|
for (unsigned Reg : RegisterSet.set_bits()) {
|
||||||
Reg = RegisterSet.find_next(Reg)) {
|
|
||||||
if (Checked[Reg])
|
if (Checked[Reg])
|
||||||
continue;
|
continue;
|
||||||
for (MCSuperRegIterator SR(Reg, this); SR.isValid(); ++SR) {
|
for (MCSuperRegIterator SR(Reg, this); SR.isValid(); ++SR) {
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||||
#include "llvm/Support/BinaryByteStream.h"
|
#include "llvm/Support/BinaryByteStream.h"
|
||||||
@ -21,38 +20,23 @@ using namespace llvm::codeview;
|
|||||||
|
|
||||||
Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
|
Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
|
||||||
TypeDatabaseVisitor DBV(TypeDB);
|
TypeDatabaseVisitor DBV(TypeDB);
|
||||||
TypeDeserializer Deserializer;
|
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
TypeVisitorCallbackPipeline Pipeline;
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
|
||||||
Pipeline.addCallbackToPipeline(DBV);
|
Pipeline.addCallbackToPipeline(DBV);
|
||||||
Pipeline.addCallbackToPipeline(Dumper);
|
Pipeline.addCallbackToPipeline(Dumper);
|
||||||
|
|
||||||
CVTypeVisitor Visitor(Pipeline);
|
|
||||||
if (Handler)
|
|
||||||
Visitor.addTypeServerHandler(*Handler);
|
|
||||||
|
|
||||||
CVType RecordCopy = Record;
|
CVType RecordCopy = Record;
|
||||||
if (auto EC = Visitor.visitTypeRecord(RecordCopy))
|
return codeview::visitTypeRecord(RecordCopy, Pipeline, VDS_BytesPresent,
|
||||||
return EC;
|
Handler);
|
||||||
return Error::success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CVTypeDumper::dump(const CVTypeArray &Types,
|
Error CVTypeDumper::dump(const CVTypeArray &Types,
|
||||||
TypeVisitorCallbacks &Dumper) {
|
TypeVisitorCallbacks &Dumper) {
|
||||||
TypeDatabaseVisitor DBV(TypeDB);
|
TypeDatabaseVisitor DBV(TypeDB);
|
||||||
TypeDeserializer Deserializer;
|
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
TypeVisitorCallbackPipeline Pipeline;
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
|
||||||
Pipeline.addCallbackToPipeline(DBV);
|
Pipeline.addCallbackToPipeline(DBV);
|
||||||
Pipeline.addCallbackToPipeline(Dumper);
|
Pipeline.addCallbackToPipeline(Dumper);
|
||||||
|
|
||||||
CVTypeVisitor Visitor(Pipeline);
|
return codeview::visitTypeStream(Types, Pipeline, Handler);
|
||||||
if (Handler)
|
|
||||||
Visitor.addTypeServerHandler(*Handler);
|
|
||||||
|
|
||||||
if (auto EC = Visitor.visitTypeStream(Types))
|
|
||||||
return EC;
|
|
||||||
return Error::success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CVTypeDumper::dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper) {
|
Error CVTypeDumper::dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper) {
|
||||||
|
@ -59,13 +59,8 @@ static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TypeServer2Record R(TypeRecordKind::TypeServer2);
|
TypeServer2Record R(TypeRecordKind::TypeServer2);
|
||||||
TypeDeserializer Deserializer;
|
|
||||||
StealTypeServerVisitor Thief(R);
|
StealTypeServerVisitor Thief(R);
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
if (auto EC = visitTypeRecord(Record, Thief))
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
|
||||||
Pipeline.addCallbackToPipeline(Thief);
|
|
||||||
CVTypeVisitor Visitor(Pipeline);
|
|
||||||
if (auto EC = Visitor.visitTypeRecord(Record))
|
|
||||||
return std::move(EC);
|
return std::move(EC);
|
||||||
|
|
||||||
return R;
|
return R;
|
||||||
@ -178,7 +173,7 @@ static Error visitMemberRecord(CVMemberRecord &Record,
|
|||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) {
|
Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
|
||||||
return ::visitMemberRecord(Record, Callbacks);
|
return ::visitMemberRecord(Record, Callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,3 +219,93 @@ Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
|
|||||||
BinaryStreamReader SR(S);
|
BinaryStreamReader SR(S);
|
||||||
return visitFieldListMemberStream(SR);
|
return visitFieldListMemberStream(SR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct FieldListVisitHelper {
|
||||||
|
FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
|
||||||
|
VisitorDataSource Source)
|
||||||
|
: Stream(Data, llvm::support::little), Reader(Stream),
|
||||||
|
Deserializer(Reader),
|
||||||
|
Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
|
||||||
|
if (Source == VDS_BytesPresent) {
|
||||||
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
|
Pipeline.addCallbackToPipeline(Callbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryByteStream Stream;
|
||||||
|
BinaryStreamReader Reader;
|
||||||
|
FieldListDeserializer Deserializer;
|
||||||
|
TypeVisitorCallbackPipeline Pipeline;
|
||||||
|
CVTypeVisitor Visitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VisitHelper {
|
||||||
|
VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
|
||||||
|
TypeServerHandler *TS)
|
||||||
|
: Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
|
||||||
|
if (TS)
|
||||||
|
Visitor.addTypeServerHandler(*TS);
|
||||||
|
if (Source == VDS_BytesPresent) {
|
||||||
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
|
Pipeline.addCallbackToPipeline(Callbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDeserializer Deserializer;
|
||||||
|
TypeVisitorCallbackPipeline Pipeline;
|
||||||
|
CVTypeVisitor Visitor;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
|
||||||
|
TypeVisitorCallbacks &Callbacks,
|
||||||
|
VisitorDataSource Source,
|
||||||
|
TypeServerHandler *TS) {
|
||||||
|
VisitHelper Helper(Callbacks, Source, TS);
|
||||||
|
return Helper.Visitor.visitTypeRecord(Record, Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitTypeRecord(CVType &Record,
|
||||||
|
TypeVisitorCallbacks &Callbacks,
|
||||||
|
VisitorDataSource Source,
|
||||||
|
TypeServerHandler *TS) {
|
||||||
|
VisitHelper Helper(Callbacks, Source, TS);
|
||||||
|
return Helper.Visitor.visitTypeRecord(Record);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
|
||||||
|
TypeVisitorCallbacks &Callbacks) {
|
||||||
|
CVTypeVisitor Visitor(Callbacks);
|
||||||
|
return Visitor.visitFieldListMemberStream(FieldList);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
|
||||||
|
TypeVisitorCallbacks &Callbacks,
|
||||||
|
VisitorDataSource Source) {
|
||||||
|
FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
|
||||||
|
return Helper.Visitor.visitMemberRecord(Record);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
|
||||||
|
ArrayRef<uint8_t> Record,
|
||||||
|
TypeVisitorCallbacks &Callbacks) {
|
||||||
|
CVMemberRecord R;
|
||||||
|
R.Data = Record;
|
||||||
|
R.Kind = Kind;
|
||||||
|
return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
|
||||||
|
TypeVisitorCallbacks &Callbacks,
|
||||||
|
TypeServerHandler *TS) {
|
||||||
|
VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
|
||||||
|
return Helper.Visitor.visitTypeStream(Types);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error llvm::codeview::visitTypeStream(CVTypeRange Types,
|
||||||
|
TypeVisitorCallbacks &Callbacks,
|
||||||
|
TypeServerHandler *TS) {
|
||||||
|
VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
|
||||||
|
return Helper.Visitor.visitTypeStream(Types);
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||||
@ -20,9 +21,7 @@ RandomAccessTypeVisitor::RandomAccessTypeVisitor(
|
|||||||
const CVTypeArray &Types, uint32_t NumRecords,
|
const CVTypeArray &Types, uint32_t NumRecords,
|
||||||
PartialOffsetArray PartialOffsets)
|
PartialOffsetArray PartialOffsets)
|
||||||
: Database(NumRecords), Types(Types), DatabaseVisitor(Database),
|
: Database(NumRecords), Types(Types), DatabaseVisitor(Database),
|
||||||
InternalVisitor(Pipeline), PartialOffsets(PartialOffsets) {
|
PartialOffsets(PartialOffsets) {
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
|
||||||
Pipeline.addCallbackToPipeline(DatabaseVisitor);
|
|
||||||
|
|
||||||
KnownOffsets.resize(Database.capacity());
|
KnownOffsets.resize(Database.capacity());
|
||||||
}
|
}
|
||||||
@ -38,8 +37,7 @@ Error RandomAccessTypeVisitor::visitTypeIndex(TypeIndex TI,
|
|||||||
|
|
||||||
assert(Database.contains(TI));
|
assert(Database.contains(TI));
|
||||||
auto &Record = Database.getTypeRecord(TI);
|
auto &Record = Database.getTypeRecord(TI);
|
||||||
CVTypeVisitor V(Callbacks);
|
return codeview::visitTypeRecord(Record, TI, Callbacks);
|
||||||
return V.visitTypeRecord(Record, TI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error RandomAccessTypeVisitor::visitRangeForType(TypeIndex TI) {
|
Error RandomAccessTypeVisitor::visitRangeForType(TypeIndex TI) {
|
||||||
@ -78,7 +76,7 @@ Error RandomAccessTypeVisitor::visitRange(TypeIndex Begin, uint32_t BeginOffset,
|
|||||||
|
|
||||||
while (Begin != End) {
|
while (Begin != End) {
|
||||||
assert(!Database.contains(Begin));
|
assert(!Database.contains(Begin));
|
||||||
if (auto EC = InternalVisitor.visitTypeRecord(*RI, Begin))
|
if (auto EC = codeview::visitTypeRecord(*RI, Begin, DatabaseVisitor))
|
||||||
return EC;
|
return EC;
|
||||||
KnownOffsets[Begin.toArrayIndex()] = BeginOffset;
|
KnownOffsets[Begin.toArrayIndex()] = BeginOffset;
|
||||||
|
|
||||||
|
@ -216,8 +216,7 @@ Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
|
|||||||
|
|
||||||
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||||
FieldListRecord &FieldList) {
|
FieldListRecord &FieldList) {
|
||||||
CVTypeVisitor Visitor(*this);
|
if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
|
||||||
if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data))
|
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
@ -361,8 +361,7 @@ Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) {
|
|||||||
// Visit the members inside the field list.
|
// Visit the members inside the field list.
|
||||||
HadUntranslatedMember = false;
|
HadUntranslatedMember = false;
|
||||||
FieldListBuilder.begin();
|
FieldListBuilder.begin();
|
||||||
CVTypeVisitor Visitor(*this);
|
if (auto EC = codeview::visitMemberRecordStream(R.Data, *this))
|
||||||
if (auto EC = Visitor.visitFieldListMemberStream(R.Data))
|
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
// Write the record if we translated all field list members.
|
// Write the record if we translated all field list members.
|
||||||
@ -440,18 +439,9 @@ Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
|
|||||||
|
|
||||||
Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
|
Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
|
||||||
assert(IndexMap.empty());
|
assert(IndexMap.empty());
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
|
||||||
LastError = Error::success();
|
LastError = Error::success();
|
||||||
|
|
||||||
TypeDeserializer Deserializer;
|
if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
|
||||||
Pipeline.addCallbackToPipeline(*this);
|
|
||||||
|
|
||||||
CVTypeVisitor Visitor(Pipeline);
|
|
||||||
if (Handler)
|
|
||||||
Visitor.addTypeServerHandler(*Handler);
|
|
||||||
|
|
||||||
if (auto EC = Visitor.visitTypeStream(Types))
|
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
// If we found bad indices but no other errors, try doing another pass and see
|
// If we found bad indices but no other errors, try doing another pass and see
|
||||||
@ -466,7 +456,8 @@ Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
|
|||||||
IsSecondPass = true;
|
IsSecondPass = true;
|
||||||
NumBadIndices = 0;
|
NumBadIndices = 0;
|
||||||
CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
|
CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
|
||||||
if (auto EC = Visitor.visitTypeStream(Types))
|
|
||||||
|
if (auto EC = codeview::visitTypeStream(Types, *this, Handler))
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
assert(NumBadIndices <= BadIndicesRemaining &&
|
assert(NumBadIndices <= BadIndicesRemaining &&
|
||||||
|
@ -1086,49 +1086,32 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Section.relocation_begin() == Section.relocation_end())
|
||||||
|
continue;
|
||||||
|
|
||||||
std::map<SymbolRef, uint64_t> AddrCache;
|
std::map<SymbolRef, uint64_t> AddrCache;
|
||||||
if (Section.relocation_begin() != Section.relocation_end()) {
|
for (const RelocationRef &Reloc : Section.relocations()) {
|
||||||
uint64_t SectionSize = RelocatedSection->getSize();
|
// FIXME: it's not clear how to correctly handle scattered
|
||||||
for (const RelocationRef &Reloc : Section.relocations()) {
|
// relocations.
|
||||||
// FIXME: it's not clear how to correctly handle scattered
|
if (isRelocScattered(Obj, Reloc))
|
||||||
// relocations.
|
continue;
|
||||||
if (isRelocScattered(Obj, Reloc))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Expected<uint64_t> SymAddrOrErr =
|
Expected<uint64_t> SymAddrOrErr =
|
||||||
getSymbolAddress(Obj, Reloc, L, AddrCache);
|
getSymbolAddress(Obj, Reloc, L, AddrCache);
|
||||||
if (!SymAddrOrErr) {
|
if (!SymAddrOrErr) {
|
||||||
errs() << toString(SymAddrOrErr.takeError()) << '\n';
|
errs() << toString(SymAddrOrErr.takeError()) << '\n';
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
object::RelocVisitor V(Obj);
|
|
||||||
object::RelocToApply R(V.visit(Reloc.getType(), Reloc, *SymAddrOrErr));
|
|
||||||
if (V.error()) {
|
|
||||||
SmallString<32> Name;
|
|
||||||
Reloc.getTypeName(Name);
|
|
||||||
errs() << "error: failed to compute relocation: "
|
|
||||||
<< Name << "\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint64_t Address = Reloc.getOffset();
|
|
||||||
if (Address + R.Width > SectionSize) {
|
|
||||||
errs() << "error: " << R.Width << "-byte relocation starting "
|
|
||||||
<< Address << " bytes into section " << name << " which is "
|
|
||||||
<< SectionSize << " bytes long.\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (R.Width > 8) {
|
|
||||||
errs() << "error: can't handle a relocation of more than 8 bytes at "
|
|
||||||
"a time.\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DEBUG(dbgs() << "Writing " << format("%p", R.Value)
|
|
||||||
<< " at " << format("%p", Address)
|
|
||||||
<< " with width " << format("%d", R.Width)
|
|
||||||
<< "\n");
|
|
||||||
Map->insert({Address, {(uint8_t)R.Width, R.Value}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object::RelocVisitor V(Obj);
|
||||||
|
object::RelocToApply R(V.visit(Reloc.getType(), Reloc, *SymAddrOrErr));
|
||||||
|
if (V.error()) {
|
||||||
|
SmallString<32> Name;
|
||||||
|
Reloc.getTypeName(Name);
|
||||||
|
errs() << "error: failed to compute relocation: " << Name << "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map->insert({Reloc.getOffset(), {R.Value}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,8 @@ PDBTypeServerHandler::handleInternal(PDBFile &File,
|
|||||||
auto ExpectedTpi = File.getPDBTpiStream();
|
auto ExpectedTpi = File.getPDBTpiStream();
|
||||||
if (!ExpectedTpi)
|
if (!ExpectedTpi)
|
||||||
return ExpectedTpi.takeError();
|
return ExpectedTpi.takeError();
|
||||||
CVTypeVisitor Visitor(Callbacks);
|
|
||||||
|
|
||||||
if (auto EC = Visitor.visitTypeStream(ExpectedTpi->types(nullptr)))
|
if (auto EC = codeview::visitTypeStream(ExpectedTpi->typeArray(), Callbacks))
|
||||||
return std::move(EC);
|
return std::move(EC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -705,7 +705,7 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
|
|||||||
unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
|
unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
|
||||||
unsigned PaddingSize = 0;
|
unsigned PaddingSize = 0;
|
||||||
unsigned StubBufSize = 0;
|
unsigned StubBufSize = 0;
|
||||||
bool IsRequired = isRequiredForExecution(Section) || ProcessAllSections;
|
bool IsRequired = isRequiredForExecution(Section);
|
||||||
bool IsVirtual = Section.isVirtual();
|
bool IsVirtual = Section.isVirtual();
|
||||||
bool IsZeroInit = isZeroInit(Section);
|
bool IsZeroInit = isZeroInit(Section);
|
||||||
bool IsReadOnly = isReadOnlyData(Section);
|
bool IsReadOnly = isReadOnlyData(Section);
|
||||||
@ -745,8 +745,8 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
|
|||||||
Alignment = std::max(Alignment, getStubAlignment());
|
Alignment = std::max(Alignment, getStubAlignment());
|
||||||
|
|
||||||
// Some sections, such as debug info, don't need to be loaded for execution.
|
// Some sections, such as debug info, don't need to be loaded for execution.
|
||||||
// Leave those where they are.
|
// Process those only if explicitly requested.
|
||||||
if (IsRequired) {
|
if (IsRequired || ProcessAllSections) {
|
||||||
Allocate = DataSize + PaddingSize + StubBufSize;
|
Allocate = DataSize + PaddingSize + StubBufSize;
|
||||||
if (!Allocate)
|
if (!Allocate)
|
||||||
Allocate = 1;
|
Allocate = 1;
|
||||||
@ -790,6 +790,10 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
|
|||||||
Sections.push_back(
|
Sections.push_back(
|
||||||
SectionEntry(Name, Addr, DataSize, Allocate, (uintptr_t)pData));
|
SectionEntry(Name, Addr, DataSize, Allocate, (uintptr_t)pData));
|
||||||
|
|
||||||
|
// Debug info sections are linked as if their load address was zero
|
||||||
|
if (!IsRequired)
|
||||||
|
Sections.back().setLoadAddress(0);
|
||||||
|
|
||||||
if (Checker)
|
if (Checker)
|
||||||
Checker->registerSection(Obj.getFileName(), SectionID);
|
Checker->registerSection(Obj.getFileName(), SectionID);
|
||||||
|
|
||||||
|
@ -78,6 +78,9 @@ static bool gCrashRecoveryEnabled = false;
|
|||||||
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
|
static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>>
|
||||||
tlIsRecoveringFromCrash;
|
tlIsRecoveringFromCrash;
|
||||||
|
|
||||||
|
static void installExceptionOrSignalHandlers();
|
||||||
|
static void uninstallExceptionOrSignalHandlers();
|
||||||
|
|
||||||
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
|
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
|
||||||
|
|
||||||
CrashRecoveryContext::~CrashRecoveryContext() {
|
CrashRecoveryContext::~CrashRecoveryContext() {
|
||||||
@ -113,6 +116,23 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
|
|||||||
return CRCI->CRC;
|
return CRCI->CRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CrashRecoveryContext::Enable() {
|
||||||
|
sys::ScopedLock L(*gCrashRecoveryContextMutex);
|
||||||
|
// FIXME: Shouldn't this be a refcount or something?
|
||||||
|
if (gCrashRecoveryEnabled)
|
||||||
|
return;
|
||||||
|
gCrashRecoveryEnabled = true;
|
||||||
|
installExceptionOrSignalHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashRecoveryContext::Disable() {
|
||||||
|
sys::ScopedLock L(*gCrashRecoveryContextMutex);
|
||||||
|
if (!gCrashRecoveryEnabled)
|
||||||
|
return;
|
||||||
|
gCrashRecoveryEnabled = false;
|
||||||
|
uninstallExceptionOrSignalHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)
|
void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup)
|
||||||
{
|
{
|
||||||
if (!cleanup)
|
if (!cleanup)
|
||||||
@ -140,30 +160,70 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
|
|||||||
delete cleanup;
|
delete cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LLVM_ON_WIN32
|
#if defined(_MSC_VER)
|
||||||
|
// If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way
|
||||||
|
// better than VEH. Vectored exception handling catches all exceptions happening
|
||||||
|
// on the thread with installed exception handlers, so it can interfere with
|
||||||
|
// internal exception handling of other libraries on that thread. SEH works
|
||||||
|
// exactly as you would expect normal exception handling to work: it only
|
||||||
|
// catches exceptions if they would bubble out from the stack frame with __try /
|
||||||
|
// __except.
|
||||||
|
|
||||||
#include "Windows/WindowsSupport.h"
|
static void installExceptionOrSignalHandlers() {}
|
||||||
|
static void uninstallExceptionOrSignalHandlers() {}
|
||||||
|
|
||||||
// On Windows, we can make use of vectored exception handling to
|
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
|
||||||
// catch most crashing situations. Note that this does mean
|
if (!gCrashRecoveryEnabled) {
|
||||||
// we will be alerted of exceptions *before* structured exception
|
Fn();
|
||||||
// handling has the opportunity to catch it. But that isn't likely
|
return true;
|
||||||
// to cause problems because nowhere in the project is SEH being
|
}
|
||||||
// used.
|
|
||||||
|
bool Result = true;
|
||||||
|
__try {
|
||||||
|
Fn();
|
||||||
|
} __except (1) { // Catch any exception.
|
||||||
|
Result = false;
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !_MSC_VER
|
||||||
|
|
||||||
|
#if defined(LLVM_ON_WIN32)
|
||||||
|
// This is a non-MSVC compiler, probably mingw gcc or clang without
|
||||||
|
// -fms-extensions. Use vectored exception handling (VEH).
|
||||||
//
|
//
|
||||||
// Vectored exception handling is built on top of SEH, and so it
|
// On Windows, we can make use of vectored exception handling to catch most
|
||||||
// works on a per-thread basis.
|
// crashing situations. Note that this does mean we will be alerted of
|
||||||
|
// exceptions *before* structured exception handling has the opportunity to
|
||||||
|
// catch it. Unfortunately, this causes problems in practice with other code
|
||||||
|
// running on threads with LLVM crash recovery contexts, so we would like to
|
||||||
|
// eventually move away from VEH.
|
||||||
|
//
|
||||||
|
// Vectored works on a per-thread basis, which is an advantage over
|
||||||
|
// SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have
|
||||||
|
// any native support for chaining exception handlers, but VEH allows more than
|
||||||
|
// one.
|
||||||
//
|
//
|
||||||
// The vectored exception handler functionality was added in Windows
|
// The vectored exception handler functionality was added in Windows
|
||||||
// XP, so if support for older versions of Windows is required,
|
// XP, so if support for older versions of Windows is required,
|
||||||
// it will have to be added.
|
// it will have to be added.
|
||||||
//
|
|
||||||
// If we want to support as far back as Win2k, we could use the
|
#include "Windows/WindowsSupport.h"
|
||||||
// SetUnhandledExceptionFilter API, but there's a risk of that
|
|
||||||
// being entirely overwritten (it's not a chain).
|
|
||||||
|
|
||||||
static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
|
static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
|
||||||
{
|
{
|
||||||
|
// DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported
|
||||||
|
// compilers and platforms, so we define it manually.
|
||||||
|
constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
|
||||||
|
switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
|
||||||
|
{
|
||||||
|
case DBG_PRINTEXCEPTION_C:
|
||||||
|
case DbgPrintExceptionWideC:
|
||||||
|
case 0x406D1388: // set debugger thread name
|
||||||
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup the current thread local recovery object.
|
// Lookup the current thread local recovery object.
|
||||||
const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
|
const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
|
||||||
|
|
||||||
@ -192,14 +252,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
|
|||||||
// non-NULL, valid VEH handles, or NULL.
|
// non-NULL, valid VEH handles, or NULL.
|
||||||
static sys::ThreadLocal<const void> sCurrentExceptionHandle;
|
static sys::ThreadLocal<const void> sCurrentExceptionHandle;
|
||||||
|
|
||||||
void CrashRecoveryContext::Enable() {
|
static void installExceptionOrSignalHandlers() {
|
||||||
sys::ScopedLock L(*gCrashRecoveryContextMutex);
|
|
||||||
|
|
||||||
if (gCrashRecoveryEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gCrashRecoveryEnabled = true;
|
|
||||||
|
|
||||||
// We can set up vectored exception handling now. We will install our
|
// We can set up vectored exception handling now. We will install our
|
||||||
// handler as the front of the list, though there's no assurances that
|
// handler as the front of the list, though there's no assurances that
|
||||||
// it will remain at the front (another call could install itself before
|
// it will remain at the front (another call could install itself before
|
||||||
@ -208,14 +261,7 @@ void CrashRecoveryContext::Enable() {
|
|||||||
sCurrentExceptionHandle.set(handle);
|
sCurrentExceptionHandle.set(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashRecoveryContext::Disable() {
|
static void uninstallExceptionOrSignalHandlers() {
|
||||||
sys::ScopedLock L(*gCrashRecoveryContextMutex);
|
|
||||||
|
|
||||||
if (!gCrashRecoveryEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gCrashRecoveryEnabled = false;
|
|
||||||
|
|
||||||
PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get());
|
PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get());
|
||||||
if (currentHandle) {
|
if (currentHandle) {
|
||||||
// Now we can remove the vectored exception handler from the chain
|
// Now we can remove the vectored exception handler from the chain
|
||||||
@ -226,7 +272,7 @@ void CrashRecoveryContext::Disable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else // !LLVM_ON_WIN32
|
||||||
|
|
||||||
// Generic POSIX implementation.
|
// Generic POSIX implementation.
|
||||||
//
|
//
|
||||||
@ -278,14 +324,7 @@ static void CrashRecoverySignalHandler(int Signal) {
|
|||||||
const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();
|
const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashRecoveryContext::Enable() {
|
static void installExceptionOrSignalHandlers() {
|
||||||
sys::ScopedLock L(*gCrashRecoveryContextMutex);
|
|
||||||
|
|
||||||
if (gCrashRecoveryEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gCrashRecoveryEnabled = true;
|
|
||||||
|
|
||||||
// Setup the signal handler.
|
// Setup the signal handler.
|
||||||
struct sigaction Handler;
|
struct sigaction Handler;
|
||||||
Handler.sa_handler = CrashRecoverySignalHandler;
|
Handler.sa_handler = CrashRecoverySignalHandler;
|
||||||
@ -297,20 +336,13 @@ void CrashRecoveryContext::Enable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashRecoveryContext::Disable() {
|
static void uninstallExceptionOrSignalHandlers() {
|
||||||
sys::ScopedLock L(*gCrashRecoveryContextMutex);
|
|
||||||
|
|
||||||
if (!gCrashRecoveryEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gCrashRecoveryEnabled = false;
|
|
||||||
|
|
||||||
// Restore the previous signal handlers.
|
// Restore the previous signal handlers.
|
||||||
for (unsigned i = 0; i != NumSignals; ++i)
|
for (unsigned i = 0; i != NumSignals; ++i)
|
||||||
sigaction(Signals[i], &PrevActions[i], nullptr);
|
sigaction(Signals[i], &PrevActions[i], nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // !LLVM_ON_WIN32
|
||||||
|
|
||||||
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
|
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
|
||||||
// If crash recovery is disabled, do nothing.
|
// If crash recovery is disabled, do nothing.
|
||||||
@ -328,6 +360,8 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !_MSC_VER
|
||||||
|
|
||||||
void CrashRecoveryContext::HandleCrash() {
|
void CrashRecoveryContext::HandleCrash() {
|
||||||
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
|
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
|
||||||
assert(CRCI && "Crash recovery context never initialized!");
|
assert(CRCI && "Crash recovery context never initialized!");
|
||||||
|
@ -103,16 +103,13 @@
|
|||||||
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
|
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace sys {
|
namespace sys {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
#if defined(__Bitrig__) || defined(__OpenBSD__) || defined(__minix) || \
|
#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
|
||||||
|
defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \
|
||||||
defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) || \
|
defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__) || \
|
||||||
defined(_AIX)
|
defined(_AIX)
|
||||||
static int
|
static int
|
||||||
@ -167,7 +164,7 @@ getprogpath(char ret[PATH_MAX], const char *bin)
|
|||||||
free(pv);
|
free(pv);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif // Bitrig || OpenBSD || minix || linux || CYGWIN || DragonFly || AIX
|
#endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__
|
||||||
|
|
||||||
/// GetMainExecutable - Return the path to the main executable, given the
|
/// GetMainExecutable - Return the path to the main executable, given the
|
||||||
/// value of argv[0] from program startup.
|
/// value of argv[0] from program startup.
|
||||||
@ -183,24 +180,9 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
|
|||||||
if (realpath(exe_path, link_path))
|
if (realpath(exe_path, link_path))
|
||||||
return link_path;
|
return link_path;
|
||||||
}
|
}
|
||||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
|
#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
|
||||||
int mib[4];
|
defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \
|
||||||
mib[0] = CTL_KERN;
|
defined(__FreeBSD_kernel__) || defined(_AIX)
|
||||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
||||||
mib[1] = KERN_PROC;
|
|
||||||
mib[2] = KERN_PROC_PATHNAME;
|
|
||||||
mib[3] = -1;
|
|
||||||
#else
|
|
||||||
mib[1] = KERN_PROC_ARGS;
|
|
||||||
mib[2] = -1;
|
|
||||||
mib[3] = KERN_PROC_PATHNAME;
|
|
||||||
#endif
|
|
||||||
char exe_path[PATH_MAX];
|
|
||||||
size_t cb = sizeof(exe_path);
|
|
||||||
if (sysctl(mib, 4, exe_path, &cb, NULL, 0) == 0)
|
|
||||||
return exe_path;
|
|
||||||
#elif defined(__Bitrig__) || defined(__OpenBSD__) || defined(__minix) || \
|
|
||||||
defined(__DragonFly__) || defined(_AIX)
|
|
||||||
char exe_path[PATH_MAX];
|
char exe_path[PATH_MAX];
|
||||||
|
|
||||||
if (getprogpath(exe_path, argv0) != NULL)
|
if (getprogpath(exe_path, argv0) != NULL)
|
||||||
|
@ -1158,8 +1158,7 @@ void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(dbgs() << "*** determineCalleeSaves\nUsed CSRs:";
|
DEBUG(dbgs() << "*** determineCalleeSaves\nUsed CSRs:";
|
||||||
for (int Reg = SavedRegs.find_first(); Reg != -1;
|
for (unsigned Reg : SavedRegs.set_bits())
|
||||||
Reg = SavedRegs.find_next(Reg))
|
|
||||||
dbgs() << ' ' << PrintReg(Reg, RegInfo);
|
dbgs() << ' ' << PrintReg(Reg, RegInfo);
|
||||||
dbgs() << "\n";);
|
dbgs() << "\n";);
|
||||||
|
|
||||||
|
@ -553,7 +553,6 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
|
|||||||
setTargetDAGCombine(ISD::INTRINSIC_VOID);
|
setTargetDAGCombine(ISD::INTRINSIC_VOID);
|
||||||
setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN);
|
setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN);
|
||||||
setTargetDAGCombine(ISD::INSERT_VECTOR_ELT);
|
setTargetDAGCombine(ISD::INSERT_VECTOR_ELT);
|
||||||
setTargetDAGCombine(ISD::EXTRACT_VECTOR_ELT);
|
|
||||||
|
|
||||||
MaxStoresPerMemset = MaxStoresPerMemsetOptSize = 8;
|
MaxStoresPerMemset = MaxStoresPerMemsetOptSize = 8;
|
||||||
MaxStoresPerMemcpy = MaxStoresPerMemcpyOptSize = 4;
|
MaxStoresPerMemcpy = MaxStoresPerMemcpyOptSize = 4;
|
||||||
@ -659,6 +658,19 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
|
|||||||
setOperationAction(ISD::MUL, MVT::v4i32, Custom);
|
setOperationAction(ISD::MUL, MVT::v4i32, Custom);
|
||||||
setOperationAction(ISD::MUL, MVT::v2i64, Custom);
|
setOperationAction(ISD::MUL, MVT::v2i64, Custom);
|
||||||
|
|
||||||
|
// Vector reductions
|
||||||
|
for (MVT VT : MVT::integer_valuetypes()) {
|
||||||
|
setOperationAction(ISD::VECREDUCE_ADD, VT, Custom);
|
||||||
|
setOperationAction(ISD::VECREDUCE_SMAX, VT, Custom);
|
||||||
|
setOperationAction(ISD::VECREDUCE_SMIN, VT, Custom);
|
||||||
|
setOperationAction(ISD::VECREDUCE_UMAX, VT, Custom);
|
||||||
|
setOperationAction(ISD::VECREDUCE_UMIN, VT, Custom);
|
||||||
|
}
|
||||||
|
for (MVT VT : MVT::fp_valuetypes()) {
|
||||||
|
setOperationAction(ISD::VECREDUCE_FMAX, VT, Custom);
|
||||||
|
setOperationAction(ISD::VECREDUCE_FMIN, VT, Custom);
|
||||||
|
}
|
||||||
|
|
||||||
setOperationAction(ISD::ANY_EXTEND, MVT::v4i32, Legal);
|
setOperationAction(ISD::ANY_EXTEND, MVT::v4i32, Legal);
|
||||||
setTruncStoreAction(MVT::v2i32, MVT::v2i16, Expand);
|
setTruncStoreAction(MVT::v2i32, MVT::v2i16, Expand);
|
||||||
// Likewise, narrowing and extending vector loads/stores aren't handled
|
// Likewise, narrowing and extending vector loads/stores aren't handled
|
||||||
@ -2606,6 +2618,14 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
|
|||||||
return LowerMUL(Op, DAG);
|
return LowerMUL(Op, DAG);
|
||||||
case ISD::INTRINSIC_WO_CHAIN:
|
case ISD::INTRINSIC_WO_CHAIN:
|
||||||
return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
||||||
|
case ISD::VECREDUCE_ADD:
|
||||||
|
case ISD::VECREDUCE_SMAX:
|
||||||
|
case ISD::VECREDUCE_SMIN:
|
||||||
|
case ISD::VECREDUCE_UMAX:
|
||||||
|
case ISD::VECREDUCE_UMIN:
|
||||||
|
case ISD::VECREDUCE_FMAX:
|
||||||
|
case ISD::VECREDUCE_FMIN:
|
||||||
|
return LowerVECREDUCE(Op, DAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7128,6 +7148,47 @@ SDValue AArch64TargetLowering::LowerVSETCC(SDValue Op,
|
|||||||
return Cmp;
|
return Cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDValue getReductionSDNode(unsigned Op, SDLoc DL, SDValue ScalarOp,
|
||||||
|
SelectionDAG &DAG) {
|
||||||
|
SDValue VecOp = ScalarOp.getOperand(0);
|
||||||
|
auto Rdx = DAG.getNode(Op, DL, VecOp.getSimpleValueType(), VecOp);
|
||||||
|
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ScalarOp.getValueType(), Rdx,
|
||||||
|
DAG.getConstant(0, DL, MVT::i64));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDValue AArch64TargetLowering::LowerVECREDUCE(SDValue Op,
|
||||||
|
SelectionDAG &DAG) const {
|
||||||
|
SDLoc dl(Op);
|
||||||
|
switch (Op.getOpcode()) {
|
||||||
|
case ISD::VECREDUCE_ADD:
|
||||||
|
return getReductionSDNode(AArch64ISD::UADDV, dl, Op, DAG);
|
||||||
|
case ISD::VECREDUCE_SMAX:
|
||||||
|
return getReductionSDNode(AArch64ISD::SMAXV, dl, Op, DAG);
|
||||||
|
case ISD::VECREDUCE_SMIN:
|
||||||
|
return getReductionSDNode(AArch64ISD::SMINV, dl, Op, DAG);
|
||||||
|
case ISD::VECREDUCE_UMAX:
|
||||||
|
return getReductionSDNode(AArch64ISD::UMAXV, dl, Op, DAG);
|
||||||
|
case ISD::VECREDUCE_UMIN:
|
||||||
|
return getReductionSDNode(AArch64ISD::UMINV, dl, Op, DAG);
|
||||||
|
case ISD::VECREDUCE_FMAX: {
|
||||||
|
assert(Op->getFlags().hasNoNaNs() && "fmax vector reduction needs NoNaN flag");
|
||||||
|
return DAG.getNode(
|
||||||
|
ISD::INTRINSIC_WO_CHAIN, dl, Op.getValueType(),
|
||||||
|
DAG.getConstant(Intrinsic::aarch64_neon_fmaxnmv, dl, MVT::i32),
|
||||||
|
Op.getOperand(0));
|
||||||
|
}
|
||||||
|
case ISD::VECREDUCE_FMIN: {
|
||||||
|
assert(Op->getFlags().hasNoNaNs() && "fmin vector reduction needs NoNaN flag");
|
||||||
|
return DAG.getNode(
|
||||||
|
ISD::INTRINSIC_WO_CHAIN, dl, Op.getValueType(),
|
||||||
|
DAG.getConstant(Intrinsic::aarch64_neon_fminnmv, dl, MVT::i32),
|
||||||
|
Op.getOperand(0));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unhandled reduction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// getTgtMemIntrinsic - Represent NEON load and store intrinsics as
|
/// getTgtMemIntrinsic - Represent NEON load and store intrinsics as
|
||||||
/// MemIntrinsicNodes. The associated MachineMemOperands record the alignment
|
/// MemIntrinsicNodes. The associated MachineMemOperands record the alignment
|
||||||
/// specified in the intrinsic calls.
|
/// specified in the intrinsic calls.
|
||||||
@ -9490,266 +9551,6 @@ static SDValue performSTORECombine(SDNode *N,
|
|||||||
return SDValue();
|
return SDValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function handles the log2-shuffle pattern produced by the
|
|
||||||
/// LoopVectorizer for the across vector reduction. It consists of
|
|
||||||
/// log2(NumVectorElements) steps and, in each step, 2^(s) elements
|
|
||||||
/// are reduced, where s is an induction variable from 0 to
|
|
||||||
/// log2(NumVectorElements).
|
|
||||||
static SDValue tryMatchAcrossLaneShuffleForReduction(SDNode *N, SDValue OpV,
|
|
||||||
unsigned Op,
|
|
||||||
SelectionDAG &DAG) {
|
|
||||||
EVT VTy = OpV->getOperand(0).getValueType();
|
|
||||||
if (!VTy.isVector())
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
int NumVecElts = VTy.getVectorNumElements();
|
|
||||||
if (Op == ISD::FMAXNUM || Op == ISD::FMINNUM) {
|
|
||||||
if (NumVecElts != 4)
|
|
||||||
return SDValue();
|
|
||||||
} else {
|
|
||||||
if (NumVecElts != 4 && NumVecElts != 8 && NumVecElts != 16)
|
|
||||||
return SDValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
int NumExpectedSteps = APInt(8, NumVecElts).logBase2();
|
|
||||||
SDValue PreOp = OpV;
|
|
||||||
// Iterate over each step of the across vector reduction.
|
|
||||||
for (int CurStep = 0; CurStep != NumExpectedSteps; ++CurStep) {
|
|
||||||
SDValue CurOp = PreOp.getOperand(0);
|
|
||||||
SDValue Shuffle = PreOp.getOperand(1);
|
|
||||||
if (Shuffle.getOpcode() != ISD::VECTOR_SHUFFLE) {
|
|
||||||
// Try to swap the 1st and 2nd operand as add and min/max instructions
|
|
||||||
// are commutative.
|
|
||||||
CurOp = PreOp.getOperand(1);
|
|
||||||
Shuffle = PreOp.getOperand(0);
|
|
||||||
if (Shuffle.getOpcode() != ISD::VECTOR_SHUFFLE)
|
|
||||||
return SDValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the input vector is fed by the operator we want to handle,
|
|
||||||
// except the last step; the very first input vector is not necessarily
|
|
||||||
// the same operator we are handling.
|
|
||||||
if (CurOp.getOpcode() != Op && (CurStep != (NumExpectedSteps - 1)))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// Check if it forms one step of the across vector reduction.
|
|
||||||
// E.g.,
|
|
||||||
// %cur = add %1, %0
|
|
||||||
// %shuffle = vector_shuffle %cur, <2, 3, u, u>
|
|
||||||
// %pre = add %cur, %shuffle
|
|
||||||
if (Shuffle.getOperand(0) != CurOp)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
int NumMaskElts = 1 << CurStep;
|
|
||||||
ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(Shuffle)->getMask();
|
|
||||||
// Check mask values in each step.
|
|
||||||
// We expect the shuffle mask in each step follows a specific pattern
|
|
||||||
// denoted here by the <M, U> form, where M is a sequence of integers
|
|
||||||
// starting from NumMaskElts, increasing by 1, and the number integers
|
|
||||||
// in M should be NumMaskElts. U is a sequence of UNDEFs and the number
|
|
||||||
// of undef in U should be NumVecElts - NumMaskElts.
|
|
||||||
// E.g., for <8 x i16>, mask values in each step should be :
|
|
||||||
// step 0 : <1,u,u,u,u,u,u,u>
|
|
||||||
// step 1 : <2,3,u,u,u,u,u,u>
|
|
||||||
// step 2 : <4,5,6,7,u,u,u,u>
|
|
||||||
for (int i = 0; i < NumVecElts; ++i)
|
|
||||||
if ((i < NumMaskElts && Mask[i] != (NumMaskElts + i)) ||
|
|
||||||
(i >= NumMaskElts && !(Mask[i] < 0)))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
PreOp = CurOp;
|
|
||||||
}
|
|
||||||
unsigned Opcode;
|
|
||||||
bool IsIntrinsic = false;
|
|
||||||
|
|
||||||
switch (Op) {
|
|
||||||
default:
|
|
||||||
llvm_unreachable("Unexpected operator for across vector reduction");
|
|
||||||
case ISD::ADD:
|
|
||||||
Opcode = AArch64ISD::UADDV;
|
|
||||||
break;
|
|
||||||
case ISD::SMAX:
|
|
||||||
Opcode = AArch64ISD::SMAXV;
|
|
||||||
break;
|
|
||||||
case ISD::UMAX:
|
|
||||||
Opcode = AArch64ISD::UMAXV;
|
|
||||||
break;
|
|
||||||
case ISD::SMIN:
|
|
||||||
Opcode = AArch64ISD::SMINV;
|
|
||||||
break;
|
|
||||||
case ISD::UMIN:
|
|
||||||
Opcode = AArch64ISD::UMINV;
|
|
||||||
break;
|
|
||||||
case ISD::FMAXNUM:
|
|
||||||
Opcode = Intrinsic::aarch64_neon_fmaxnmv;
|
|
||||||
IsIntrinsic = true;
|
|
||||||
break;
|
|
||||||
case ISD::FMINNUM:
|
|
||||||
Opcode = Intrinsic::aarch64_neon_fminnmv;
|
|
||||||
IsIntrinsic = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SDLoc DL(N);
|
|
||||||
|
|
||||||
return IsIntrinsic
|
|
||||||
? DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, N->getValueType(0),
|
|
||||||
DAG.getConstant(Opcode, DL, MVT::i32), PreOp)
|
|
||||||
: DAG.getNode(
|
|
||||||
ISD::EXTRACT_VECTOR_ELT, DL, N->getValueType(0),
|
|
||||||
DAG.getNode(Opcode, DL, PreOp.getSimpleValueType(), PreOp),
|
|
||||||
DAG.getConstant(0, DL, MVT::i64));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Target-specific DAG combine for the across vector min/max reductions.
|
|
||||||
/// This function specifically handles the final clean-up step of the vector
|
|
||||||
/// min/max reductions produced by the LoopVectorizer. It is the log2-shuffle
|
|
||||||
/// pattern, which narrows down and finds the final min/max value from all
|
|
||||||
/// elements of the vector.
|
|
||||||
/// For example, for a <16 x i8> vector :
|
|
||||||
/// svn0 = vector_shuffle %0, undef<8,9,10,11,12,13,14,15,u,u,u,u,u,u,u,u>
|
|
||||||
/// %smax0 = smax %arr, svn0
|
|
||||||
/// %svn1 = vector_shuffle %smax0, undef<4,5,6,7,u,u,u,u,u,u,u,u,u,u,u,u>
|
|
||||||
/// %smax1 = smax %smax0, %svn1
|
|
||||||
/// %svn2 = vector_shuffle %smax1, undef<2,3,u,u,u,u,u,u,u,u,u,u,u,u,u,u>
|
|
||||||
/// %smax2 = smax %smax1, svn2
|
|
||||||
/// %svn3 = vector_shuffle %smax2, undef<1,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u>
|
|
||||||
/// %sc = setcc %smax2, %svn3, gt
|
|
||||||
/// %n0 = extract_vector_elt %sc, #0
|
|
||||||
/// %n1 = extract_vector_elt %smax2, #0
|
|
||||||
/// %n2 = extract_vector_elt $smax2, #1
|
|
||||||
/// %result = select %n0, %n1, n2
|
|
||||||
/// becomes :
|
|
||||||
/// %1 = smaxv %0
|
|
||||||
/// %result = extract_vector_elt %1, 0
|
|
||||||
static SDValue
|
|
||||||
performAcrossLaneMinMaxReductionCombine(SDNode *N, SelectionDAG &DAG,
|
|
||||||
const AArch64Subtarget *Subtarget) {
|
|
||||||
if (!Subtarget->hasNEON())
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
SDValue N0 = N->getOperand(0);
|
|
||||||
SDValue IfTrue = N->getOperand(1);
|
|
||||||
SDValue IfFalse = N->getOperand(2);
|
|
||||||
|
|
||||||
// Check if the SELECT merges up the final result of the min/max
|
|
||||||
// from a vector.
|
|
||||||
if (N0.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
|
|
||||||
IfTrue.getOpcode() != ISD::EXTRACT_VECTOR_ELT ||
|
|
||||||
IfFalse.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// Expect N0 is fed by SETCC.
|
|
||||||
SDValue SetCC = N0.getOperand(0);
|
|
||||||
EVT SetCCVT = SetCC.getValueType();
|
|
||||||
if (SetCC.getOpcode() != ISD::SETCC || !SetCCVT.isVector() ||
|
|
||||||
SetCCVT.getVectorElementType() != MVT::i1)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
SDValue VectorOp = SetCC.getOperand(0);
|
|
||||||
unsigned Op = VectorOp->getOpcode();
|
|
||||||
// Check if the input vector is fed by the operator we want to handle.
|
|
||||||
if (Op != ISD::SMAX && Op != ISD::UMAX && Op != ISD::SMIN &&
|
|
||||||
Op != ISD::UMIN && Op != ISD::FMAXNUM && Op != ISD::FMINNUM)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
EVT VTy = VectorOp.getValueType();
|
|
||||||
if (!VTy.isVector())
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
if (VTy.getSizeInBits() < 64)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
EVT EltTy = VTy.getVectorElementType();
|
|
||||||
if (Op == ISD::FMAXNUM || Op == ISD::FMINNUM) {
|
|
||||||
if (EltTy != MVT::f32)
|
|
||||||
return SDValue();
|
|
||||||
} else {
|
|
||||||
if (EltTy != MVT::i32 && EltTy != MVT::i16 && EltTy != MVT::i8)
|
|
||||||
return SDValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if extracting from the same vector.
|
|
||||||
// For example,
|
|
||||||
// %sc = setcc %vector, %svn1, gt
|
|
||||||
// %n0 = extract_vector_elt %sc, #0
|
|
||||||
// %n1 = extract_vector_elt %vector, #0
|
|
||||||
// %n2 = extract_vector_elt $vector, #1
|
|
||||||
if (!(VectorOp == IfTrue->getOperand(0) &&
|
|
||||||
VectorOp == IfFalse->getOperand(0)))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// Check if the condition code is matched with the operator type.
|
|
||||||
ISD::CondCode CC = cast<CondCodeSDNode>(SetCC->getOperand(2))->get();
|
|
||||||
if ((Op == ISD::SMAX && CC != ISD::SETGT && CC != ISD::SETGE) ||
|
|
||||||
(Op == ISD::UMAX && CC != ISD::SETUGT && CC != ISD::SETUGE) ||
|
|
||||||
(Op == ISD::SMIN && CC != ISD::SETLT && CC != ISD::SETLE) ||
|
|
||||||
(Op == ISD::UMIN && CC != ISD::SETULT && CC != ISD::SETULE) ||
|
|
||||||
(Op == ISD::FMAXNUM && CC != ISD::SETOGT && CC != ISD::SETOGE &&
|
|
||||||
CC != ISD::SETUGT && CC != ISD::SETUGE && CC != ISD::SETGT &&
|
|
||||||
CC != ISD::SETGE) ||
|
|
||||||
(Op == ISD::FMINNUM && CC != ISD::SETOLT && CC != ISD::SETOLE &&
|
|
||||||
CC != ISD::SETULT && CC != ISD::SETULE && CC != ISD::SETLT &&
|
|
||||||
CC != ISD::SETLE))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// Expect to check only lane 0 from the vector SETCC.
|
|
||||||
if (!isNullConstant(N0.getOperand(1)))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// Expect to extract the true value from lane 0.
|
|
||||||
if (!isNullConstant(IfTrue.getOperand(1)))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// Expect to extract the false value from lane 1.
|
|
||||||
if (!isOneConstant(IfFalse.getOperand(1)))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
return tryMatchAcrossLaneShuffleForReduction(N, SetCC, Op, DAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Target-specific DAG combine for the across vector add reduction.
|
|
||||||
/// This function specifically handles the final clean-up step of the vector
|
|
||||||
/// add reduction produced by the LoopVectorizer. It is the log2-shuffle
|
|
||||||
/// pattern, which adds all elements of a vector together.
|
|
||||||
/// For example, for a <4 x i32> vector :
|
|
||||||
/// %1 = vector_shuffle %0, <2,3,u,u>
|
|
||||||
/// %2 = add %0, %1
|
|
||||||
/// %3 = vector_shuffle %2, <1,u,u,u>
|
|
||||||
/// %4 = add %2, %3
|
|
||||||
/// %result = extract_vector_elt %4, 0
|
|
||||||
/// becomes :
|
|
||||||
/// %0 = uaddv %0
|
|
||||||
/// %result = extract_vector_elt %0, 0
|
|
||||||
static SDValue
|
|
||||||
performAcrossLaneAddReductionCombine(SDNode *N, SelectionDAG &DAG,
|
|
||||||
const AArch64Subtarget *Subtarget) {
|
|
||||||
if (!Subtarget->hasNEON())
|
|
||||||
return SDValue();
|
|
||||||
SDValue N0 = N->getOperand(0);
|
|
||||||
SDValue N1 = N->getOperand(1);
|
|
||||||
|
|
||||||
// Check if the input vector is fed by the ADD.
|
|
||||||
if (N0->getOpcode() != ISD::ADD)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
// The vector extract idx must constant zero because we only expect the final
|
|
||||||
// result of the reduction is placed in lane 0.
|
|
||||||
if (!isNullConstant(N1))
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
EVT VTy = N0.getValueType();
|
|
||||||
if (!VTy.isVector())
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
EVT EltTy = VTy.getVectorElementType();
|
|
||||||
if (EltTy != MVT::i32 && EltTy != MVT::i16 && EltTy != MVT::i8)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
if (VTy.getSizeInBits() < 64)
|
|
||||||
return SDValue();
|
|
||||||
|
|
||||||
return tryMatchAcrossLaneShuffleForReduction(N, N0, ISD::ADD, DAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Target-specific DAG combine function for NEON load/store intrinsics
|
/// Target-specific DAG combine function for NEON load/store intrinsics
|
||||||
/// to merge base address updates.
|
/// to merge base address updates.
|
||||||
@ -10428,12 +10229,8 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
|
|||||||
return performBitcastCombine(N, DCI, DAG);
|
return performBitcastCombine(N, DCI, DAG);
|
||||||
case ISD::CONCAT_VECTORS:
|
case ISD::CONCAT_VECTORS:
|
||||||
return performConcatVectorsCombine(N, DCI, DAG);
|
return performConcatVectorsCombine(N, DCI, DAG);
|
||||||
case ISD::SELECT: {
|
case ISD::SELECT:
|
||||||
SDValue RV = performSelectCombine(N, DCI);
|
return performSelectCombine(N, DCI);
|
||||||
if (!RV.getNode())
|
|
||||||
RV = performAcrossLaneMinMaxReductionCombine(N, DAG, Subtarget);
|
|
||||||
return RV;
|
|
||||||
}
|
|
||||||
case ISD::VSELECT:
|
case ISD::VSELECT:
|
||||||
return performVSelectCombine(N, DCI.DAG);
|
return performVSelectCombine(N, DCI.DAG);
|
||||||
case ISD::LOAD:
|
case ISD::LOAD:
|
||||||
@ -10455,8 +10252,6 @@ SDValue AArch64TargetLowering::PerformDAGCombine(SDNode *N,
|
|||||||
return performNVCASTCombine(N);
|
return performNVCASTCombine(N);
|
||||||
case ISD::INSERT_VECTOR_ELT:
|
case ISD::INSERT_VECTOR_ELT:
|
||||||
return performPostLD1Combine(N, DCI, true);
|
return performPostLD1Combine(N, DCI, true);
|
||||||
case ISD::EXTRACT_VECTOR_ELT:
|
|
||||||
return performAcrossLaneAddReductionCombine(N, DAG, Subtarget);
|
|
||||||
case ISD::INTRINSIC_VOID:
|
case ISD::INTRINSIC_VOID:
|
||||||
case ISD::INTRINSIC_W_CHAIN:
|
case ISD::INTRINSIC_W_CHAIN:
|
||||||
switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) {
|
switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) {
|
||||||
@ -10676,6 +10471,14 @@ void AArch64TargetLowering::ReplaceNodeResults(
|
|||||||
case ISD::BITCAST:
|
case ISD::BITCAST:
|
||||||
ReplaceBITCASTResults(N, Results, DAG);
|
ReplaceBITCASTResults(N, Results, DAG);
|
||||||
return;
|
return;
|
||||||
|
case ISD::VECREDUCE_ADD:
|
||||||
|
case ISD::VECREDUCE_SMAX:
|
||||||
|
case ISD::VECREDUCE_SMIN:
|
||||||
|
case ISD::VECREDUCE_UMAX:
|
||||||
|
case ISD::VECREDUCE_UMIN:
|
||||||
|
Results.push_back(LowerVECREDUCE(SDValue(N, 0), DAG));
|
||||||
|
return;
|
||||||
|
|
||||||
case AArch64ISD::SADDV:
|
case AArch64ISD::SADDV:
|
||||||
ReplaceReductionResults(N, Results, DAG, ISD::ADD, AArch64ISD::SADDV);
|
ReplaceReductionResults(N, Results, DAG, ISD::ADD, AArch64ISD::SADDV);
|
||||||
return;
|
return;
|
||||||
|
@ -568,6 +568,7 @@ class AArch64TargetLowering : public TargetLowering {
|
|||||||
SDValue LowerVectorOR(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerVectorOR(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
SDValue LowerVECREDUCE(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
|
||||||
SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG,
|
SDValue BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG,
|
||||||
std::vector<SDNode *> *Created) const override;
|
std::vector<SDNode *> *Created) const override;
|
||||||
|
@ -769,3 +769,28 @@ unsigned AArch64TTIImpl::getMinPrefetchStride() {
|
|||||||
unsigned AArch64TTIImpl::getMaxPrefetchIterationsAhead() {
|
unsigned AArch64TTIImpl::getMaxPrefetchIterationsAhead() {
|
||||||
return ST->getMaxPrefetchIterationsAhead();
|
return ST->getMaxPrefetchIterationsAhead();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AArch64TTIImpl::useReductionIntrinsic(unsigned Opcode, Type *Ty,
|
||||||
|
TTI::ReductionFlags Flags) const {
|
||||||
|
assert(isa<VectorType>(Ty) && "Expected Ty to be a vector type");
|
||||||
|
unsigned ScalarBits = Ty->getScalarSizeInBits();
|
||||||
|
switch (Opcode) {
|
||||||
|
case Instruction::FAdd:
|
||||||
|
case Instruction::FMul:
|
||||||
|
case Instruction::And:
|
||||||
|
case Instruction::Or:
|
||||||
|
case Instruction::Xor:
|
||||||
|
case Instruction::Mul:
|
||||||
|
return false;
|
||||||
|
case Instruction::Add:
|
||||||
|
return ScalarBits * Ty->getVectorNumElements() >= 128;
|
||||||
|
case Instruction::ICmp:
|
||||||
|
return (ScalarBits < 64) &&
|
||||||
|
(ScalarBits * Ty->getVectorNumElements() >= 128);
|
||||||
|
case Instruction::FCmp:
|
||||||
|
return Flags.NoNaN;
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unhandled reduction opcode");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -145,6 +145,9 @@ class AArch64TTIImpl : public BasicTTIImplBase<AArch64TTIImpl> {
|
|||||||
bool shouldExpandReduction(const IntrinsicInst *II) const {
|
bool shouldExpandReduction(const IntrinsicInst *II) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool useReductionIntrinsic(unsigned Opcode, Type *Ty,
|
||||||
|
TTI::ReductionFlags Flags) const;
|
||||||
/// @}
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1707,10 +1707,38 @@ bool AMDGPUDAGToDAGISel::SelectVOP3PMods(SDValue In, SDValue &Src,
|
|||||||
|
|
||||||
// FIXME: Look for on separate components
|
// FIXME: Look for on separate components
|
||||||
if (Src.getOpcode() == ISD::FNEG) {
|
if (Src.getOpcode() == ISD::FNEG) {
|
||||||
Mods |= (SISrcMods::NEG | SISrcMods::NEG_HI);
|
Mods ^= (SISrcMods::NEG | SISrcMods::NEG_HI);
|
||||||
Src = Src.getOperand(0);
|
Src = Src.getOperand(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Src.getOpcode() == ISD::BUILD_VECTOR) {
|
||||||
|
unsigned VecMods = Mods;
|
||||||
|
|
||||||
|
SDValue Lo = Src.getOperand(0);
|
||||||
|
SDValue Hi = Src.getOperand(1);
|
||||||
|
|
||||||
|
if (Lo.getOpcode() == ISD::FNEG) {
|
||||||
|
Lo = Lo.getOperand(0);
|
||||||
|
Mods ^= SISrcMods::NEG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Hi.getOpcode() == ISD::FNEG) {
|
||||||
|
Hi = Hi.getOperand(0);
|
||||||
|
Mods ^= SISrcMods::NEG_HI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Lo == Hi && !isInlineImmediate(Lo.getNode())) {
|
||||||
|
// Really a scalar input. Just select from the low half of the register to
|
||||||
|
// avoid packing.
|
||||||
|
|
||||||
|
Src = Lo;
|
||||||
|
SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mods = VecMods;
|
||||||
|
}
|
||||||
|
|
||||||
// Packed instructions do not have abs modifiers.
|
// Packed instructions do not have abs modifiers.
|
||||||
|
|
||||||
// FIXME: Handle abs/neg of individual components.
|
// FIXME: Handle abs/neg of individual components.
|
||||||
|
@ -289,6 +289,10 @@ class AMDGPUSubtarget : public AMDGPUGenSubtargetInfo {
|
|||||||
return getGeneration() >= GFX9;
|
return getGeneration() >= GFX9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasMin3Max3_16() const {
|
||||||
|
return getGeneration() >= GFX9;
|
||||||
|
}
|
||||||
|
|
||||||
bool hasCARRY() const {
|
bool hasCARRY() const {
|
||||||
return (getGeneration() >= EVERGREEN);
|
return (getGeneration() >= EVERGREEN);
|
||||||
}
|
}
|
||||||
|
@ -4491,7 +4491,8 @@ SDValue SITargetLowering::performMinMaxCombine(SDNode *N,
|
|||||||
|
|
||||||
|
|
||||||
if (Opc != AMDGPUISD::FMIN_LEGACY && Opc != AMDGPUISD::FMAX_LEGACY &&
|
if (Opc != AMDGPUISD::FMIN_LEGACY && Opc != AMDGPUISD::FMAX_LEGACY &&
|
||||||
VT != MVT::f64) {
|
VT != MVT::f64 &&
|
||||||
|
((VT != MVT::f16 && VT != MVT::i16) || Subtarget->hasMin3Max3_16())) {
|
||||||
// max(max(a, b), c) -> max3(a, b, c)
|
// max(max(a, b), c) -> max3(a, b, c)
|
||||||
// min(min(a, b), c) -> min3(a, b, c)
|
// min(min(a, b), c) -> min3(a, b, c)
|
||||||
if (Op0.getOpcode() == Opc && Op0.hasOneUse()) {
|
if (Op0.getOpcode() == Opc && Op0.hasOneUse()) {
|
||||||
|
@ -765,7 +765,7 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
|||||||
.addFrameIndex(FrameIndex) // addr
|
.addFrameIndex(FrameIndex) // addr
|
||||||
.addMemOperand(MMO)
|
.addMemOperand(MMO)
|
||||||
.addReg(MFI->getScratchRSrcReg(), RegState::Implicit)
|
.addReg(MFI->getScratchRSrcReg(), RegState::Implicit)
|
||||||
.addReg(MFI->getScratchWaveOffsetReg(), RegState::Implicit);
|
.addReg(MFI->getFrameOffsetReg(), RegState::Implicit);
|
||||||
// Add the scratch resource registers as implicit uses because we may end up
|
// Add the scratch resource registers as implicit uses because we may end up
|
||||||
// needing them, and need to ensure that the reserved registers are
|
// needing them, and need to ensure that the reserved registers are
|
||||||
// correctly handled.
|
// correctly handled.
|
||||||
@ -796,7 +796,7 @@ void SIInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
|||||||
.addReg(SrcReg, getKillRegState(isKill)) // data
|
.addReg(SrcReg, getKillRegState(isKill)) // data
|
||||||
.addFrameIndex(FrameIndex) // addr
|
.addFrameIndex(FrameIndex) // addr
|
||||||
.addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
|
.addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
|
||||||
.addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
|
.addReg(MFI->getFrameOffsetReg()) // scratch_offset
|
||||||
.addImm(0) // offset
|
.addImm(0) // offset
|
||||||
.addMemOperand(MMO);
|
.addMemOperand(MMO);
|
||||||
}
|
}
|
||||||
@ -869,7 +869,7 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
|||||||
.addFrameIndex(FrameIndex) // addr
|
.addFrameIndex(FrameIndex) // addr
|
||||||
.addMemOperand(MMO)
|
.addMemOperand(MMO)
|
||||||
.addReg(MFI->getScratchRSrcReg(), RegState::Implicit)
|
.addReg(MFI->getScratchRSrcReg(), RegState::Implicit)
|
||||||
.addReg(MFI->getScratchWaveOffsetReg(), RegState::Implicit);
|
.addReg(MFI->getFrameOffsetReg(), RegState::Implicit);
|
||||||
|
|
||||||
if (ST.hasScalarStores()) {
|
if (ST.hasScalarStores()) {
|
||||||
// m0 is used for offset to scalar stores if used to spill.
|
// m0 is used for offset to scalar stores if used to spill.
|
||||||
@ -892,10 +892,10 @@ void SIInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
|||||||
|
|
||||||
unsigned Opcode = getVGPRSpillRestoreOpcode(SpillSize);
|
unsigned Opcode = getVGPRSpillRestoreOpcode(SpillSize);
|
||||||
BuildMI(MBB, MI, DL, get(Opcode), DestReg)
|
BuildMI(MBB, MI, DL, get(Opcode), DestReg)
|
||||||
.addFrameIndex(FrameIndex) // vaddr
|
.addFrameIndex(FrameIndex) // vaddr
|
||||||
.addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
|
.addReg(MFI->getScratchRSrcReg()) // scratch_rsrc
|
||||||
.addReg(MFI->getScratchWaveOffsetReg()) // scratch_offset
|
.addReg(MFI->getFrameOffsetReg()) // scratch_offset
|
||||||
.addImm(0) // offset
|
.addImm(0) // offset
|
||||||
.addMemOperand(MMO);
|
.addMemOperand(MMO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,11 +654,11 @@ bool SIRegisterInfo::spillSGPR(MachineBasicBlock::iterator MI,
|
|||||||
int64_t Offset = (ST.getWavefrontSize() * FrOffset) + (EltSize * i);
|
int64_t Offset = (ST.getWavefrontSize() * FrOffset) + (EltSize * i);
|
||||||
if (Offset != 0) {
|
if (Offset != 0) {
|
||||||
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), OffsetReg)
|
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), OffsetReg)
|
||||||
.addReg(MFI->getScratchWaveOffsetReg())
|
.addReg(MFI->getFrameOffsetReg())
|
||||||
.addImm(Offset);
|
.addImm(Offset);
|
||||||
} else {
|
} else {
|
||||||
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
|
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
|
||||||
.addReg(MFI->getScratchWaveOffsetReg());
|
.addReg(MFI->getFrameOffsetReg());
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildMI(*MBB, MI, DL, TII->get(ScalarStoreOp))
|
BuildMI(*MBB, MI, DL, TII->get(ScalarStoreOp))
|
||||||
@ -715,11 +715,11 @@ bool SIRegisterInfo::spillSGPR(MachineBasicBlock::iterator MI,
|
|||||||
= MF->getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
|
= MF->getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
|
||||||
EltSize, MinAlign(Align, EltSize * i));
|
EltSize, MinAlign(Align, EltSize * i));
|
||||||
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_SAVE))
|
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_SAVE))
|
||||||
.addReg(TmpReg, RegState::Kill) // src
|
.addReg(TmpReg, RegState::Kill) // src
|
||||||
.addFrameIndex(Index) // vaddr
|
.addFrameIndex(Index) // vaddr
|
||||||
.addReg(MFI->getScratchRSrcReg()) // srrsrc
|
.addReg(MFI->getScratchRSrcReg()) // srrsrc
|
||||||
.addReg(MFI->getScratchWaveOffsetReg()) // soffset
|
.addReg(MFI->getFrameOffsetReg()) // soffset
|
||||||
.addImm(i * 4) // offset
|
.addImm(i * 4) // offset
|
||||||
.addMemOperand(MMO);
|
.addMemOperand(MMO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,11 +806,11 @@ bool SIRegisterInfo::restoreSGPR(MachineBasicBlock::iterator MI,
|
|||||||
int64_t Offset = (ST.getWavefrontSize() * FrOffset) + (EltSize * i);
|
int64_t Offset = (ST.getWavefrontSize() * FrOffset) + (EltSize * i);
|
||||||
if (Offset != 0) {
|
if (Offset != 0) {
|
||||||
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), OffsetReg)
|
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_ADD_U32), OffsetReg)
|
||||||
.addReg(MFI->getScratchWaveOffsetReg())
|
.addReg(MFI->getFrameOffsetReg())
|
||||||
.addImm(Offset);
|
.addImm(Offset);
|
||||||
} else {
|
} else {
|
||||||
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
|
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), OffsetReg)
|
||||||
.addReg(MFI->getScratchWaveOffsetReg());
|
.addReg(MFI->getFrameOffsetReg());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MIB =
|
auto MIB =
|
||||||
@ -853,10 +853,10 @@ bool SIRegisterInfo::restoreSGPR(MachineBasicBlock::iterator MI,
|
|||||||
MinAlign(Align, EltSize * i));
|
MinAlign(Align, EltSize * i));
|
||||||
|
|
||||||
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_RESTORE), TmpReg)
|
BuildMI(*MBB, MI, DL, TII->get(AMDGPU::SI_SPILL_V32_RESTORE), TmpReg)
|
||||||
.addFrameIndex(Index) // vaddr
|
.addFrameIndex(Index) // vaddr
|
||||||
.addReg(MFI->getScratchRSrcReg()) // srsrc
|
.addReg(MFI->getScratchRSrcReg()) // srsrc
|
||||||
.addReg(MFI->getScratchWaveOffsetReg()) // soffset
|
.addReg(MFI->getFrameOffsetReg()) // soffset
|
||||||
.addImm(i * 4) // offset
|
.addImm(i * 4) // offset
|
||||||
.addMemOperand(MMO);
|
.addMemOperand(MMO);
|
||||||
|
|
||||||
auto MIB =
|
auto MIB =
|
||||||
|
@ -300,10 +300,19 @@ def V_AND_OR_B32 : VOP3Inst <"v_and_or_b32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
|
|||||||
def V_OR3_B32 : VOP3Inst <"v_or3_b32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
|
def V_OR3_B32 : VOP3Inst <"v_or3_b32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
|
||||||
|
|
||||||
def V_XAD_U32 : VOP3Inst <"v_xad_u32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
|
def V_XAD_U32 : VOP3Inst <"v_xad_u32", VOP3_Profile<VOP_I32_I32_I32_I32>>;
|
||||||
|
|
||||||
def V_MED3_F16 : VOP3Inst <"v_med3_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, AMDGPUfmed3>;
|
def V_MED3_F16 : VOP3Inst <"v_med3_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, AMDGPUfmed3>;
|
||||||
def V_MED3_I16 : VOP3Inst <"v_med3_i16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUsmed3>;
|
def V_MED3_I16 : VOP3Inst <"v_med3_i16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUsmed3>;
|
||||||
def V_MED3_U16 : VOP3Inst <"v_med3_u16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUumed3>;
|
def V_MED3_U16 : VOP3Inst <"v_med3_u16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUumed3>;
|
||||||
}
|
|
||||||
|
def V_MIN3_F16 : VOP3Inst <"v_min3_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, AMDGPUfmin3>;
|
||||||
|
def V_MIN3_I16 : VOP3Inst <"v_min3_i16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUsmin3>;
|
||||||
|
def V_MIN3_U16 : VOP3Inst <"v_min3_u16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUumin3>;
|
||||||
|
|
||||||
|
def V_MAX3_F16 : VOP3Inst <"v_max3_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, AMDGPUfmax3>;
|
||||||
|
def V_MAX3_I16 : VOP3Inst <"v_max3_i16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUsmax3>;
|
||||||
|
def V_MAX3_U16 : VOP3Inst <"v_max3_u16", VOP3_Profile<VOP_I16_I16_I16_I16>, AMDGPUumax3>;
|
||||||
|
} // End SubtargetPredicate = isGFX9
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -509,6 +518,15 @@ defm V_OR3_B32 : VOP3_Real_vi <0x202>;
|
|||||||
defm V_PACK_B32_F16 : VOP3_Real_vi <0x2a0>;
|
defm V_PACK_B32_F16 : VOP3_Real_vi <0x2a0>;
|
||||||
|
|
||||||
defm V_XAD_U32 : VOP3_Real_vi <0x1f3>;
|
defm V_XAD_U32 : VOP3_Real_vi <0x1f3>;
|
||||||
|
|
||||||
|
defm V_MIN3_F16 : VOP3_Real_vi <0x1f4>;
|
||||||
|
defm V_MIN3_I16 : VOP3_Real_vi <0x1f5>;
|
||||||
|
defm V_MIN3_U16 : VOP3_Real_vi <0x1f6>;
|
||||||
|
|
||||||
|
defm V_MAX3_F16 : VOP3_Real_vi <0x1f7>;
|
||||||
|
defm V_MAX3_I16 : VOP3_Real_vi <0x1f8>;
|
||||||
|
defm V_MAX3_U16 : VOP3_Real_vi <0x1f9>;
|
||||||
|
|
||||||
defm V_MED3_F16 : VOP3_Real_vi <0x1fa>;
|
defm V_MED3_F16 : VOP3_Real_vi <0x1fa>;
|
||||||
defm V_MED3_I16 : VOP3_Real_vi <0x1fb>;
|
defm V_MED3_I16 : VOP3_Real_vi <0x1fb>;
|
||||||
defm V_MED3_U16 : VOP3_Real_vi <0x1fc>;
|
defm V_MED3_U16 : VOP3_Real_vi <0x1fc>;
|
||||||
|
@ -345,25 +345,10 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
|
|||||||
I.setDesc(TII.get(COPY));
|
I.setDesc(TII.get(COPY));
|
||||||
return selectCopy(I, TII, MRI, TRI, RBI);
|
return selectCopy(I, TII, MRI, TRI, RBI);
|
||||||
}
|
}
|
||||||
case G_ADD:
|
|
||||||
case G_GEP:
|
case G_GEP:
|
||||||
I.setDesc(TII.get(ARM::ADDrr));
|
I.setDesc(TII.get(ARM::ADDrr));
|
||||||
MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
|
MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
|
||||||
break;
|
break;
|
||||||
case G_SUB:
|
|
||||||
I.setDesc(TII.get(ARM::SUBrr));
|
|
||||||
MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
|
|
||||||
break;
|
|
||||||
case G_MUL:
|
|
||||||
if (TII.getSubtarget().hasV6Ops()) {
|
|
||||||
I.setDesc(TII.get(ARM::MUL));
|
|
||||||
} else {
|
|
||||||
assert(TII.getSubtarget().useMulOps() && "Unsupported target");
|
|
||||||
I.setDesc(TII.get(ARM::MULv5));
|
|
||||||
MIB->getOperand(0).setIsEarlyClobber(true);
|
|
||||||
}
|
|
||||||
MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
|
|
||||||
break;
|
|
||||||
case G_FRAME_INDEX:
|
case G_FRAME_INDEX:
|
||||||
// Add 0 to the given frame index and hope it will eventually be folded into
|
// Add 0 to the given frame index and hope it will eventually be folded into
|
||||||
// the user(s).
|
// the user(s).
|
||||||
|
@ -571,8 +571,7 @@ bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB,
|
|||||||
GPRsNoLRSP.reset(ARM::LR);
|
GPRsNoLRSP.reset(ARM::LR);
|
||||||
GPRsNoLRSP.reset(ARM::SP);
|
GPRsNoLRSP.reset(ARM::SP);
|
||||||
GPRsNoLRSP.reset(ARM::PC);
|
GPRsNoLRSP.reset(ARM::PC);
|
||||||
for (int Register = GPRsNoLRSP.find_first(); Register != -1;
|
for (unsigned Register : GPRsNoLRSP.set_bits()) {
|
||||||
Register = GPRsNoLRSP.find_next(Register)) {
|
|
||||||
if (!UsedRegs.contains(Register)) {
|
if (!UsedRegs.contains(Register)) {
|
||||||
// Remember the first pop-friendly register and exit.
|
// Remember the first pop-friendly register and exit.
|
||||||
if (PopFriendly.test(Register)) {
|
if (PopFriendly.test(Register)) {
|
||||||
|
@ -386,7 +386,7 @@ void RegDefsUses::setCallerSaved(const MachineInstr &MI) {
|
|||||||
void RegDefsUses::setUnallocatableRegs(const MachineFunction &MF) {
|
void RegDefsUses::setUnallocatableRegs(const MachineFunction &MF) {
|
||||||
BitVector AllocSet = TRI.getAllocatableSet(MF);
|
BitVector AllocSet = TRI.getAllocatableSet(MF);
|
||||||
|
|
||||||
for (int R = AllocSet.find_first(); R != -1; R = AllocSet.find_next(R))
|
for (unsigned R : AllocSet.set_bits())
|
||||||
for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI)
|
for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI)
|
||||||
AllocSet.set(*AI);
|
AllocSet.set(*AI);
|
||||||
|
|
||||||
|
@ -1765,31 +1765,36 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
|||||||
// Check whether the frame pointer register is allocated. If so, make sure it
|
// Check whether the frame pointer register is allocated. If so, make sure it
|
||||||
// is spilled to the correct offset.
|
// is spilled to the correct offset.
|
||||||
if (needsFP(MF)) {
|
if (needsFP(MF)) {
|
||||||
HasGPSaveArea = true;
|
|
||||||
|
|
||||||
int FI = PFI->getFramePointerSaveIndex();
|
int FI = PFI->getFramePointerSaveIndex();
|
||||||
assert(FI && "No Frame Pointer Save Slot!");
|
assert(FI && "No Frame Pointer Save Slot!");
|
||||||
|
|
||||||
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
|
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
|
||||||
|
// FP is R31/X31, so no need to update MinGPR/MinG8R.
|
||||||
|
HasGPSaveArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PFI->usesPICBase()) {
|
if (PFI->usesPICBase()) {
|
||||||
HasGPSaveArea = true;
|
|
||||||
|
|
||||||
int FI = PFI->getPICBasePointerSaveIndex();
|
int FI = PFI->getPICBasePointerSaveIndex();
|
||||||
assert(FI && "No PIC Base Pointer Save Slot!");
|
assert(FI && "No PIC Base Pointer Save Slot!");
|
||||||
|
|
||||||
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
|
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
|
||||||
|
|
||||||
|
MinGPR = std::min<unsigned>(MinGPR, PPC::R30);
|
||||||
|
HasGPSaveArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
|
const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo();
|
||||||
if (RegInfo->hasBasePointer(MF)) {
|
if (RegInfo->hasBasePointer(MF)) {
|
||||||
HasGPSaveArea = true;
|
|
||||||
|
|
||||||
int FI = PFI->getBasePointerSaveIndex();
|
int FI = PFI->getBasePointerSaveIndex();
|
||||||
assert(FI && "No Base Pointer Save Slot!");
|
assert(FI && "No Base Pointer Save Slot!");
|
||||||
|
|
||||||
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
|
MFI.setObjectOffset(FI, LowerBound + MFI.getObjectOffset(FI));
|
||||||
|
|
||||||
|
unsigned BP = RegInfo->getBaseRegister(MF);
|
||||||
|
if (PPC::G8RCRegClass.contains(BP)) {
|
||||||
|
MinG8R = std::min<unsigned>(MinG8R, BP);
|
||||||
|
HasG8SaveArea = true;
|
||||||
|
} else if (PPC::GPRCRegClass.contains(BP)) {
|
||||||
|
MinGPR = std::min<unsigned>(MinGPR, BP);
|
||||||
|
HasGPSaveArea = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// General register save area starts right below the Floating-point
|
// General register save area starts right below the Floating-point
|
||||||
|
@ -410,6 +410,11 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
|||||||
// To handle counter-based loop conditions.
|
// To handle counter-based loop conditions.
|
||||||
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i1, Custom);
|
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i1, Custom);
|
||||||
|
|
||||||
|
setOperationAction(ISD::INTRINSIC_VOID, MVT::i8, Custom);
|
||||||
|
setOperationAction(ISD::INTRINSIC_VOID, MVT::i16, Custom);
|
||||||
|
setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom);
|
||||||
|
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
|
||||||
|
|
||||||
// Comparisons that require checking two conditions.
|
// Comparisons that require checking two conditions.
|
||||||
setCondCodeAction(ISD::SETULT, MVT::f32, Expand);
|
setCondCodeAction(ISD::SETULT, MVT::f32, Expand);
|
||||||
setCondCodeAction(ISD::SETULT, MVT::f64, Expand);
|
setCondCodeAction(ISD::SETULT, MVT::f64, Expand);
|
||||||
@ -8184,6 +8189,26 @@ SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
|
|||||||
return Flags;
|
return Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDValue PPCTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
|
||||||
|
SelectionDAG &DAG) const {
|
||||||
|
// SelectionDAGBuilder::visitTargetIntrinsic may insert one extra chain to
|
||||||
|
// the beginning of the argument list.
|
||||||
|
int ArgStart = isa<ConstantSDNode>(Op.getOperand(0)) ? 0 : 1;
|
||||||
|
SDLoc DL(Op);
|
||||||
|
switch (cast<ConstantSDNode>(Op.getOperand(ArgStart))->getZExtValue()) {
|
||||||
|
case Intrinsic::ppc_cfence: {
|
||||||
|
assert(Subtarget.isPPC64() && "Only 64-bit is supported for now.");
|
||||||
|
return SDValue(DAG.getMachineNode(PPC::CFENCE8, DL, MVT::Other,
|
||||||
|
DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64,
|
||||||
|
Op.getOperand(ArgStart + 1))),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SDValue();
|
||||||
|
}
|
||||||
|
|
||||||
SDValue PPCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
|
SDValue PPCTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc dl(Op);
|
SDLoc dl(Op);
|
||||||
@ -8649,6 +8674,9 @@ SDValue PPCTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
|||||||
// Frame & Return address.
|
// Frame & Return address.
|
||||||
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
||||||
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||||
|
|
||||||
|
case ISD::INTRINSIC_VOID:
|
||||||
|
return LowerINTRINSIC_VOID(Op, DAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8753,12 +8781,19 @@ Instruction *PPCTargetLowering::emitLeadingFence(IRBuilder<> &Builder,
|
|||||||
Instruction *PPCTargetLowering::emitTrailingFence(IRBuilder<> &Builder,
|
Instruction *PPCTargetLowering::emitTrailingFence(IRBuilder<> &Builder,
|
||||||
Instruction *Inst,
|
Instruction *Inst,
|
||||||
AtomicOrdering Ord) const {
|
AtomicOrdering Ord) const {
|
||||||
if (Inst->hasAtomicLoad() && isAcquireOrStronger(Ord))
|
if (Inst->hasAtomicLoad() && isAcquireOrStronger(Ord)) {
|
||||||
|
// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html and
|
||||||
|
// http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2011.03.04a.html
|
||||||
|
// and http://www.cl.cam.ac.uk/~pes20/cppppc/ for justification.
|
||||||
|
if (isa<LoadInst>(Inst) && Subtarget.isPPC64())
|
||||||
|
return Builder.CreateCall(
|
||||||
|
Intrinsic::getDeclaration(
|
||||||
|
Builder.GetInsertBlock()->getParent()->getParent(),
|
||||||
|
Intrinsic::ppc_cfence, {Inst->getType()}),
|
||||||
|
{Inst});
|
||||||
|
// FIXME: Can use isync for rmw operation.
|
||||||
return callIntrinsic(Builder, Intrinsic::ppc_lwsync);
|
return callIntrinsic(Builder, Intrinsic::ppc_lwsync);
|
||||||
// FIXME: this is too conservative, a dependent branch + isync is enough.
|
}
|
||||||
// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html and
|
|
||||||
// http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2011.03.04a.html
|
|
||||||
// and http://www.cl.cam.ac.uk/~pes20/cppppc/ for justification.
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -905,6 +905,7 @@ namespace llvm {
|
|||||||
SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
@ -983,6 +983,10 @@ def LDgotTprelL: Pseudo<(outs g8rc:$rD), (ins s16imm64:$disp, g8rc_nox0:$reg),
|
|||||||
[(set i64:$rD,
|
[(set i64:$rD,
|
||||||
(PPCldGotTprelL tglobaltlsaddr:$disp, i64:$reg))]>,
|
(PPCldGotTprelL tglobaltlsaddr:$disp, i64:$reg))]>,
|
||||||
isPPC64;
|
isPPC64;
|
||||||
|
|
||||||
|
let isBarrier = 1, isPseudo = 1, Defs = [CR7], Itinerary = IIC_LdStSync in
|
||||||
|
def CFENCE8 : Pseudo<(outs), (ins g8rc:$cr), "#CFENCE8", []>;
|
||||||
|
|
||||||
def : Pat<(PPCaddTls i64:$in, tglobaltlsaddr:$g),
|
def : Pat<(PPCaddTls i64:$in, tglobaltlsaddr:$g),
|
||||||
(ADD8TLS $in, tglobaltlsaddr:$g)>;
|
(ADD8TLS $in, tglobaltlsaddr:$g)>;
|
||||||
def ADDIStlsgdHA: Pseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, s16imm64:$disp),
|
def ADDIStlsgdHA: Pseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, s16imm64:$disp),
|
||||||
|
@ -1873,6 +1873,8 @@ PPCInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
||||||
|
auto &MBB = *MI.getParent();
|
||||||
|
auto DL = MI.getDebugLoc();
|
||||||
switch (MI.getOpcode()) {
|
switch (MI.getOpcode()) {
|
||||||
case TargetOpcode::LOAD_STACK_GUARD: {
|
case TargetOpcode::LOAD_STACK_GUARD: {
|
||||||
assert(Subtarget.isTargetLinux() &&
|
assert(Subtarget.isTargetLinux() &&
|
||||||
@ -1920,6 +1922,17 @@ bool PPCInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
|||||||
MI.setDesc(get(Opcode));
|
MI.setDesc(get(Opcode));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case PPC::CFENCE8: {
|
||||||
|
auto Val = MI.getOperand(0).getReg();
|
||||||
|
BuildMI(MBB, MI, DL, get(PPC::CMPW), PPC::CR7).addReg(Val).addReg(Val);
|
||||||
|
BuildMI(MBB, MI, DL, get(PPC::CTRL_DEP))
|
||||||
|
.addImm(PPC::PRED_NE_MINUS)
|
||||||
|
.addReg(PPC::CR7)
|
||||||
|
.addImm(1);
|
||||||
|
MI.setDesc(get(PPC::ISYNC));
|
||||||
|
MI.RemoveOperand(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1223,9 +1223,15 @@ let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7 in {
|
|||||||
// FIXME: should be able to write a pattern for PPCcondbranch, but can't use
|
// FIXME: should be able to write a pattern for PPCcondbranch, but can't use
|
||||||
// a two-value operand where a dag node expects two operands. :(
|
// a two-value operand where a dag node expects two operands. :(
|
||||||
let isCodeGenOnly = 1 in {
|
let isCodeGenOnly = 1 in {
|
||||||
def BCC : BForm<16, 0, 0, (outs), (ins pred:$cond, condbrtarget:$dst),
|
class BCC_class : BForm<16, 0, 0, (outs), (ins pred:$cond, condbrtarget:$dst),
|
||||||
"b${cond:cc}${cond:pm} ${cond:reg}, $dst"
|
"b${cond:cc}${cond:pm} ${cond:reg}, $dst"
|
||||||
/*[(PPCcondbranch crrc:$crS, imm:$opc, bb:$dst)]*/>;
|
/*[(PPCcondbranch crrc:$crS, imm:$opc, bb:$dst)]*/>;
|
||||||
|
def BCC : BCC_class;
|
||||||
|
|
||||||
|
// The same as BCC, except that it's not a terminator. Used for introducing
|
||||||
|
// control flow dependency without creating new blocks.
|
||||||
|
let isTerminator = 0 in def CTRL_DEP : BCC_class;
|
||||||
|
|
||||||
def BCCA : BForm<16, 1, 0, (outs), (ins pred:$cond, abscondbrtarget:$dst),
|
def BCCA : BForm<16, 1, 0, (outs), (ins pred:$cond, abscondbrtarget:$dst),
|
||||||
"b${cond:cc}a${cond:pm} ${cond:reg}, $dst">;
|
"b${cond:cc}a${cond:pm} ${cond:reg}, $dst">;
|
||||||
|
|
||||||
|
@ -325,6 +325,30 @@ int SystemZTTIImpl::getArithmeticInstrCost(
|
|||||||
|
|
||||||
unsigned ScalarBits = Ty->getScalarSizeInBits();
|
unsigned ScalarBits = Ty->getScalarSizeInBits();
|
||||||
|
|
||||||
|
// Div with a constant which is a power of 2 will be converted by
|
||||||
|
// DAGCombiner to use shifts. With vector shift-element instructions, a
|
||||||
|
// vector sdiv costs about as much as a scalar one.
|
||||||
|
const unsigned SDivCostEstimate = 4;
|
||||||
|
bool SDivPow2 = false;
|
||||||
|
bool UDivPow2 = false;
|
||||||
|
if ((Opcode == Instruction::SDiv || Opcode == Instruction::UDiv) &&
|
||||||
|
Args.size() == 2) {
|
||||||
|
const ConstantInt *CI = nullptr;
|
||||||
|
if (const Constant *C = dyn_cast<Constant>(Args[1])) {
|
||||||
|
if (C->getType()->isVectorTy())
|
||||||
|
CI = dyn_cast_or_null<const ConstantInt>(C->getSplatValue());
|
||||||
|
else
|
||||||
|
CI = dyn_cast<const ConstantInt>(C);
|
||||||
|
}
|
||||||
|
if (CI != nullptr &&
|
||||||
|
(CI->getValue().isPowerOf2() || (-CI->getValue()).isPowerOf2())) {
|
||||||
|
if (Opcode == Instruction::SDiv)
|
||||||
|
SDivPow2 = true;
|
||||||
|
else
|
||||||
|
UDivPow2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Ty->isVectorTy()) {
|
if (Ty->isVectorTy()) {
|
||||||
assert (ST->hasVector() && "getArithmeticInstrCost() called with vector type.");
|
assert (ST->hasVector() && "getArithmeticInstrCost() called with vector type.");
|
||||||
unsigned VF = Ty->getVectorNumElements();
|
unsigned VF = Ty->getVectorNumElements();
|
||||||
@ -333,10 +357,13 @@ int SystemZTTIImpl::getArithmeticInstrCost(
|
|||||||
// These vector operations are custom handled, but are still supported
|
// These vector operations are custom handled, but are still supported
|
||||||
// with one instruction per vector, regardless of element size.
|
// with one instruction per vector, regardless of element size.
|
||||||
if (Opcode == Instruction::Shl || Opcode == Instruction::LShr ||
|
if (Opcode == Instruction::Shl || Opcode == Instruction::LShr ||
|
||||||
Opcode == Instruction::AShr) {
|
Opcode == Instruction::AShr || UDivPow2) {
|
||||||
return NumVectors;
|
return NumVectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SDivPow2)
|
||||||
|
return (NumVectors * SDivCostEstimate);
|
||||||
|
|
||||||
// These FP operations are supported with a single vector instruction for
|
// These FP operations are supported with a single vector instruction for
|
||||||
// double (base implementation assumes float generally costs 2). For
|
// double (base implementation assumes float generally costs 2). For
|
||||||
// FP128, the scalar cost is 1, and there is no overhead since the values
|
// FP128, the scalar cost is 1, and there is no overhead since the values
|
||||||
@ -395,6 +422,11 @@ int SystemZTTIImpl::getArithmeticInstrCost(
|
|||||||
// 2 * ipm sequences ; xor ; shift ; compare
|
// 2 * ipm sequences ; xor ; shift ; compare
|
||||||
return 7;
|
return 7;
|
||||||
|
|
||||||
|
if (UDivPow2)
|
||||||
|
return 1;
|
||||||
|
if (SDivPow2)
|
||||||
|
return SDivCostEstimate;
|
||||||
|
|
||||||
// An extra extension for narrow types is needed.
|
// An extra extension for narrow types is needed.
|
||||||
if ((Opcode == Instruction::SDiv || Opcode == Instruction::SRem))
|
if ((Opcode == Instruction::SDiv || Opcode == Instruction::SRem))
|
||||||
// sext of op(s) for narrow types
|
// sext of op(s) for narrow types
|
||||||
|
@ -140,8 +140,7 @@ bool WebAssemblyRegColoring::runOnMachineFunction(MachineFunction &MF) {
|
|||||||
|
|
||||||
// Check if it's possible to reuse any of the used colors.
|
// Check if it's possible to reuse any of the used colors.
|
||||||
if (!MRI->isLiveIn(Old))
|
if (!MRI->isLiveIn(Old))
|
||||||
for (int C(UsedColors.find_first()); C != -1;
|
for (unsigned C : UsedColors.set_bits()) {
|
||||||
C = UsedColors.find_next(C)) {
|
|
||||||
if (MRI->getRegClass(SortedIntervals[C]->reg) != RC)
|
if (MRI->getRegClass(SortedIntervals[C]->reg) != RC)
|
||||||
continue;
|
continue;
|
||||||
for (LiveInterval *OtherLI : Assignments[C])
|
for (LiveInterval *OtherLI : Assignments[C])
|
||||||
|
@ -33,9 +33,6 @@ built-in-setjmp.c
|
|||||||
pr60003.c
|
pr60003.c
|
||||||
|
|
||||||
# Error in the program / unsupported by Clang.
|
# Error in the program / unsupported by Clang.
|
||||||
scal-to-vec1.c
|
|
||||||
scal-to-vec2.c
|
|
||||||
scal-to-vec3.c
|
|
||||||
20000822-1.c
|
20000822-1.c
|
||||||
20010209-1.c
|
20010209-1.c
|
||||||
20010605-1.c
|
20010605-1.c
|
||||||
|
@ -235,8 +235,6 @@ def FeatureLEAUsesAG : SubtargetFeature<"lea-uses-ag", "LEAUsesAG", "true",
|
|||||||
"LEA instruction needs inputs at AG stage">;
|
"LEA instruction needs inputs at AG stage">;
|
||||||
def FeatureSlowLEA : SubtargetFeature<"slow-lea", "SlowLEA", "true",
|
def FeatureSlowLEA : SubtargetFeature<"slow-lea", "SlowLEA", "true",
|
||||||
"LEA instruction with certain arguments is slow">;
|
"LEA instruction with certain arguments is slow">;
|
||||||
def FeatureSlow3OpsLEA : SubtargetFeature<"slow-3ops-lea", "Slow3OpsLEA", "true",
|
|
||||||
"LEA instruction with 3 ops or certain registers is slow">;
|
|
||||||
def FeatureSlowIncDec : SubtargetFeature<"slow-incdec", "SlowIncDec", "true",
|
def FeatureSlowIncDec : SubtargetFeature<"slow-incdec", "SlowIncDec", "true",
|
||||||
"INC and DEC instructions are slower than ADD and SUB">;
|
"INC and DEC instructions are slower than ADD and SUB">;
|
||||||
def FeatureSoftFloat
|
def FeatureSoftFloat
|
||||||
@ -482,7 +480,6 @@ def SNBFeatures : ProcessorFeatures<[], [
|
|||||||
FeatureXSAVE,
|
FeatureXSAVE,
|
||||||
FeatureXSAVEOPT,
|
FeatureXSAVEOPT,
|
||||||
FeatureLAHFSAHF,
|
FeatureLAHFSAHF,
|
||||||
FeatureSlow3OpsLEA,
|
|
||||||
FeatureFastScalarFSQRT,
|
FeatureFastScalarFSQRT,
|
||||||
FeatureFastSHLDRotate
|
FeatureFastSHLDRotate
|
||||||
]>;
|
]>;
|
||||||
|
@ -27,26 +27,20 @@
|
|||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace llvm {
|
#define DEBUG_TYPE "x86-fixup-LEAs"
|
||||||
void initializeFixupLEAPassPass(PassRegistry &);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FIXUPLEA_DESC "X86 LEA Fixup"
|
|
||||||
#define FIXUPLEA_NAME "x86-fixup-LEAs"
|
|
||||||
|
|
||||||
#define DEBUG_TYPE FIXUPLEA_NAME
|
|
||||||
|
|
||||||
STATISTIC(NumLEAs, "Number of LEA instructions created");
|
STATISTIC(NumLEAs, "Number of LEA instructions created");
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class FixupLEAPass : public MachineFunctionPass {
|
class FixupLEAPass : public MachineFunctionPass {
|
||||||
enum RegUsageState { RU_NotUsed, RU_Write, RU_Read };
|
enum RegUsageState { RU_NotUsed, RU_Write, RU_Read };
|
||||||
|
static char ID;
|
||||||
/// \brief Loop over all of the instructions in the basic block
|
/// \brief Loop over all of the instructions in the basic block
|
||||||
/// replacing applicable instructions with LEA instructions,
|
/// replacing applicable instructions with LEA instructions,
|
||||||
/// where appropriate.
|
/// where appropriate.
|
||||||
bool processBasicBlock(MachineFunction &MF, MachineFunction::iterator MFI);
|
bool processBasicBlock(MachineFunction &MF, MachineFunction::iterator MFI);
|
||||||
|
|
||||||
|
StringRef getPassName() const override { return "X86 LEA Fixup"; }
|
||||||
|
|
||||||
/// \brief Given a machine register, look for the instruction
|
/// \brief Given a machine register, look for the instruction
|
||||||
/// which writes it in the current basic block. If found,
|
/// which writes it in the current basic block. If found,
|
||||||
@ -68,22 +62,6 @@ class FixupLEAPass : public MachineFunctionPass {
|
|||||||
void processInstructionForSLM(MachineBasicBlock::iterator &I,
|
void processInstructionForSLM(MachineBasicBlock::iterator &I,
|
||||||
MachineFunction::iterator MFI);
|
MachineFunction::iterator MFI);
|
||||||
|
|
||||||
|
|
||||||
/// \brief Given a LEA instruction which is unprofitable
|
|
||||||
/// on SNB+ try to replace it with other instructions.
|
|
||||||
/// According to Intel's Optimization Reference Manual:
|
|
||||||
/// " For LEA instructions with three source operands and some specific
|
|
||||||
/// situations, instruction latency has increased to 3 cycles, and must
|
|
||||||
/// dispatch via port 1:
|
|
||||||
/// - LEA that has all three source operands: base, index, and offset
|
|
||||||
/// - LEA that uses base and index registers where the base is EBP, RBP,
|
|
||||||
/// or R13
|
|
||||||
/// - LEA that uses RIP relative addressing mode
|
|
||||||
/// - LEA that uses 16-bit addressing mode "
|
|
||||||
/// This function currently handles the first 2 cases only.
|
|
||||||
MachineInstr *processInstrForSlow3OpLEA(MachineInstr &MI,
|
|
||||||
MachineFunction::iterator MFI);
|
|
||||||
|
|
||||||
/// \brief Look for LEAs that add 1 to reg or subtract 1 from reg
|
/// \brief Look for LEAs that add 1 to reg or subtract 1 from reg
|
||||||
/// and convert them to INC or DEC respectively.
|
/// and convert them to INC or DEC respectively.
|
||||||
bool fixupIncDec(MachineBasicBlock::iterator &I,
|
bool fixupIncDec(MachineBasicBlock::iterator &I,
|
||||||
@ -107,13 +85,7 @@ class FixupLEAPass : public MachineFunctionPass {
|
|||||||
MachineBasicBlock::iterator &MBBI) const;
|
MachineBasicBlock::iterator &MBBI) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID;
|
FixupLEAPass() : MachineFunctionPass(ID) {}
|
||||||
|
|
||||||
StringRef getPassName() const override { return FIXUPLEA_DESC; }
|
|
||||||
|
|
||||||
FixupLEAPass() : MachineFunctionPass(ID) {
|
|
||||||
initializeFixupLEAPassPass(*PassRegistry::getPassRegistry());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Loop over all of the basic blocks,
|
/// \brief Loop over all of the basic blocks,
|
||||||
/// replacing instructions by equivalent LEA instructions
|
/// replacing instructions by equivalent LEA instructions
|
||||||
@ -132,11 +104,8 @@ class FixupLEAPass : public MachineFunctionPass {
|
|||||||
bool OptIncDec;
|
bool OptIncDec;
|
||||||
bool OptLEA;
|
bool OptLEA;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
char FixupLEAPass::ID = 0;
|
char FixupLEAPass::ID = 0;
|
||||||
|
}
|
||||||
INITIALIZE_PASS(FixupLEAPass, FIXUPLEA_NAME, FIXUPLEA_DESC, false, false)
|
|
||||||
|
|
||||||
MachineInstr *
|
MachineInstr *
|
||||||
FixupLEAPass::postRAConvertToLEA(MachineFunction::iterator &MFI,
|
FixupLEAPass::postRAConvertToLEA(MachineFunction::iterator &MFI,
|
||||||
@ -199,7 +168,7 @@ bool FixupLEAPass::runOnMachineFunction(MachineFunction &Func) {
|
|||||||
MF = &Func;
|
MF = &Func;
|
||||||
const X86Subtarget &ST = Func.getSubtarget<X86Subtarget>();
|
const X86Subtarget &ST = Func.getSubtarget<X86Subtarget>();
|
||||||
OptIncDec = !ST.slowIncDec() || Func.getFunction()->optForMinSize();
|
OptIncDec = !ST.slowIncDec() || Func.getFunction()->optForMinSize();
|
||||||
OptLEA = ST.LEAusesAG() || ST.slowLEA() || ST.slow3OpsLEA();
|
OptLEA = ST.LEAusesAG() || ST.slowLEA();
|
||||||
|
|
||||||
if (!OptLEA && !OptIncDec)
|
if (!OptLEA && !OptIncDec)
|
||||||
return false;
|
return false;
|
||||||
@ -273,64 +242,9 @@ FixupLEAPass::searchBackwards(MachineOperand &p, MachineBasicBlock::iterator &I,
|
|||||||
return MachineBasicBlock::iterator();
|
return MachineBasicBlock::iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isLEA(const int Opcode) {
|
static inline bool isLEA(const int opcode) {
|
||||||
return Opcode == X86::LEA16r || Opcode == X86::LEA32r ||
|
return opcode == X86::LEA16r || opcode == X86::LEA32r ||
|
||||||
Opcode == X86::LEA64r || Opcode == X86::LEA64_32r;
|
opcode == X86::LEA64r || opcode == X86::LEA64_32r;
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isInefficientLEAReg(unsigned int Reg) {
|
|
||||||
return Reg == X86::EBP || Reg == X86::RBP || Reg == X86::R13;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isRegOperand(const MachineOperand &Op) {
|
|
||||||
return Op.isReg() && Op.getReg() != X86::NoRegister;
|
|
||||||
}
|
|
||||||
/// hasIneffecientLEARegs - LEA that uses base and index registers
|
|
||||||
/// where the base is EBP, RBP, or R13
|
|
||||||
static inline bool hasInefficientLEABaseReg(const MachineOperand &Base,
|
|
||||||
const MachineOperand &Index) {
|
|
||||||
return Base.isReg() && isInefficientLEAReg(Base.getReg()) &&
|
|
||||||
isRegOperand(Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool hasLEAOffset(const MachineOperand &Offset) {
|
|
||||||
return (Offset.isImm() && Offset.getImm() != 0) || Offset.isGlobal();
|
|
||||||
}
|
|
||||||
|
|
||||||
// LEA instruction that has all three operands: offset, base and index
|
|
||||||
static inline bool isThreeOperandsLEA(const MachineOperand &Base,
|
|
||||||
const MachineOperand &Index,
|
|
||||||
const MachineOperand &Offset) {
|
|
||||||
return isRegOperand(Base) && isRegOperand(Index) && hasLEAOffset(Offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int getADDrrFromLEA(int LEAOpcode) {
|
|
||||||
switch (LEAOpcode) {
|
|
||||||
default:
|
|
||||||
llvm_unreachable("Unexpected LEA instruction");
|
|
||||||
case X86::LEA16r:
|
|
||||||
return X86::ADD16rr;
|
|
||||||
case X86::LEA32r:
|
|
||||||
return X86::ADD32rr;
|
|
||||||
case X86::LEA64_32r:
|
|
||||||
case X86::LEA64r:
|
|
||||||
return X86::ADD64rr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int getADDriFromLEA(int LEAOpcode, const MachineOperand &Offset) {
|
|
||||||
bool IsInt8 = Offset.isImm() && isInt<8>(Offset.getImm());
|
|
||||||
switch (LEAOpcode) {
|
|
||||||
default:
|
|
||||||
llvm_unreachable("Unexpected LEA instruction");
|
|
||||||
case X86::LEA16r:
|
|
||||||
return IsInt8 ? X86::ADD16ri8 : X86::ADD16ri;
|
|
||||||
case X86::LEA32r:
|
|
||||||
case X86::LEA64_32r:
|
|
||||||
return IsInt8 ? X86::ADD32ri8 : X86::ADD32ri;
|
|
||||||
case X86::LEA64r:
|
|
||||||
return IsInt8 ? X86::ADD64ri8 : X86::ADD64ri32;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isLEASimpleIncOrDec - Does this LEA have one these forms:
|
/// isLEASimpleIncOrDec - Does this LEA have one these forms:
|
||||||
@ -423,8 +337,8 @@ void FixupLEAPass::seekLEAFixup(MachineOperand &p,
|
|||||||
void FixupLEAPass::processInstructionForSLM(MachineBasicBlock::iterator &I,
|
void FixupLEAPass::processInstructionForSLM(MachineBasicBlock::iterator &I,
|
||||||
MachineFunction::iterator MFI) {
|
MachineFunction::iterator MFI) {
|
||||||
MachineInstr &MI = *I;
|
MachineInstr &MI = *I;
|
||||||
const int Opcode = MI.getOpcode();
|
const int opcode = MI.getOpcode();
|
||||||
if (!isLEA(Opcode))
|
if (!isLEA(opcode))
|
||||||
return;
|
return;
|
||||||
if (MI.getOperand(5).getReg() != 0 || !MI.getOperand(4).isImm() ||
|
if (MI.getOperand(5).getReg() != 0 || !MI.getOperand(4).isImm() ||
|
||||||
!TII->isSafeToClobberEFLAGS(*MFI, I))
|
!TII->isSafeToClobberEFLAGS(*MFI, I))
|
||||||
@ -436,144 +350,55 @@ void FixupLEAPass::processInstructionForSLM(MachineBasicBlock::iterator &I,
|
|||||||
return;
|
return;
|
||||||
if (MI.getOperand(2).getImm() > 1)
|
if (MI.getOperand(2).getImm() > 1)
|
||||||
return;
|
return;
|
||||||
|
int addrr_opcode, addri_opcode;
|
||||||
|
switch (opcode) {
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unexpected LEA instruction");
|
||||||
|
case X86::LEA16r:
|
||||||
|
addrr_opcode = X86::ADD16rr;
|
||||||
|
addri_opcode = X86::ADD16ri;
|
||||||
|
break;
|
||||||
|
case X86::LEA32r:
|
||||||
|
addrr_opcode = X86::ADD32rr;
|
||||||
|
addri_opcode = X86::ADD32ri;
|
||||||
|
break;
|
||||||
|
case X86::LEA64_32r:
|
||||||
|
case X86::LEA64r:
|
||||||
|
addrr_opcode = X86::ADD64rr;
|
||||||
|
addri_opcode = X86::ADD64ri32;
|
||||||
|
break;
|
||||||
|
}
|
||||||
DEBUG(dbgs() << "FixLEA: Candidate to replace:"; I->dump(););
|
DEBUG(dbgs() << "FixLEA: Candidate to replace:"; I->dump(););
|
||||||
DEBUG(dbgs() << "FixLEA: Replaced by: ";);
|
DEBUG(dbgs() << "FixLEA: Replaced by: ";);
|
||||||
MachineInstr *NewMI = nullptr;
|
MachineInstr *NewMI = nullptr;
|
||||||
|
const MachineOperand &Dst = MI.getOperand(0);
|
||||||
// Make ADD instruction for two registers writing to LEA's destination
|
// Make ADD instruction for two registers writing to LEA's destination
|
||||||
if (SrcR1 != 0 && SrcR2 != 0) {
|
if (SrcR1 != 0 && SrcR2 != 0) {
|
||||||
const MCInstrDesc &ADDrr = TII->get(getADDrrFromLEA(Opcode));
|
const MachineOperand &Src1 = MI.getOperand(SrcR1 == DstR ? 1 : 3);
|
||||||
const MachineOperand &Src = MI.getOperand(SrcR1 == DstR ? 3 : 1);
|
const MachineOperand &Src2 = MI.getOperand(SrcR1 == DstR ? 3 : 1);
|
||||||
NewMI =
|
NewMI = BuildMI(*MF, MI.getDebugLoc(), TII->get(addrr_opcode))
|
||||||
BuildMI(*MFI, I, MI.getDebugLoc(), ADDrr, DstR).addReg(DstR).add(Src);
|
.add(Dst)
|
||||||
|
.add(Src1)
|
||||||
|
.add(Src2);
|
||||||
|
MFI->insert(I, NewMI);
|
||||||
DEBUG(NewMI->dump(););
|
DEBUG(NewMI->dump(););
|
||||||
}
|
}
|
||||||
// Make ADD instruction for immediate
|
// Make ADD instruction for immediate
|
||||||
if (MI.getOperand(4).getImm() != 0) {
|
if (MI.getOperand(4).getImm() != 0) {
|
||||||
const MCInstrDesc &ADDri =
|
|
||||||
TII->get(getADDriFromLEA(Opcode, MI.getOperand(4)));
|
|
||||||
const MachineOperand &SrcR = MI.getOperand(SrcR1 == DstR ? 1 : 3);
|
const MachineOperand &SrcR = MI.getOperand(SrcR1 == DstR ? 1 : 3);
|
||||||
NewMI = BuildMI(*MFI, I, MI.getDebugLoc(), ADDri, DstR)
|
NewMI = BuildMI(*MF, MI.getDebugLoc(), TII->get(addri_opcode))
|
||||||
|
.add(Dst)
|
||||||
.add(SrcR)
|
.add(SrcR)
|
||||||
.addImm(MI.getOperand(4).getImm());
|
.addImm(MI.getOperand(4).getImm());
|
||||||
|
MFI->insert(I, NewMI);
|
||||||
DEBUG(NewMI->dump(););
|
DEBUG(NewMI->dump(););
|
||||||
}
|
}
|
||||||
if (NewMI) {
|
if (NewMI) {
|
||||||
MFI->erase(I);
|
MFI->erase(I);
|
||||||
I = NewMI;
|
I = static_cast<MachineBasicBlock::iterator>(NewMI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MachineInstr *
|
|
||||||
FixupLEAPass::processInstrForSlow3OpLEA(MachineInstr &MI,
|
|
||||||
MachineFunction::iterator MFI) {
|
|
||||||
|
|
||||||
const int LEAOpcode = MI.getOpcode();
|
|
||||||
if (!isLEA(LEAOpcode))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const MachineOperand &Dst = MI.getOperand(0);
|
|
||||||
const MachineOperand &Base = MI.getOperand(1);
|
|
||||||
const MachineOperand &Scale = MI.getOperand(2);
|
|
||||||
const MachineOperand &Index = MI.getOperand(3);
|
|
||||||
const MachineOperand &Offset = MI.getOperand(4);
|
|
||||||
const MachineOperand &Segment = MI.getOperand(5);
|
|
||||||
|
|
||||||
if (!(isThreeOperandsLEA(Base, Index, Offset) ||
|
|
||||||
hasInefficientLEABaseReg(Base, Index)) ||
|
|
||||||
!TII->isSafeToClobberEFLAGS(*MFI, MI) ||
|
|
||||||
Segment.getReg() != X86::NoRegister)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
unsigned int DstR = Dst.getReg();
|
|
||||||
unsigned int BaseR = Base.getReg();
|
|
||||||
unsigned int IndexR = Index.getReg();
|
|
||||||
unsigned SSDstR =
|
|
||||||
(LEAOpcode == X86::LEA64_32r) ? getX86SubSuperRegister(DstR, 64) : DstR;
|
|
||||||
bool IsScale1 = Scale.getImm() == 1;
|
|
||||||
bool IsInefficientBase = isInefficientLEAReg(BaseR);
|
|
||||||
bool IsInefficientIndex = isInefficientLEAReg(IndexR);
|
|
||||||
|
|
||||||
// Skip these cases since it takes more than 2 instructions
|
|
||||||
// to replace the LEA instruction.
|
|
||||||
if (IsInefficientBase && SSDstR == BaseR && !IsScale1)
|
|
||||||
return nullptr;
|
|
||||||
if (LEAOpcode == X86::LEA64_32r && IsInefficientBase &&
|
|
||||||
(IsInefficientIndex || !IsScale1))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
const DebugLoc DL = MI.getDebugLoc();
|
|
||||||
const MCInstrDesc &ADDrr = TII->get(getADDrrFromLEA(LEAOpcode));
|
|
||||||
const MCInstrDesc &ADDri = TII->get(getADDriFromLEA(LEAOpcode, Offset));
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "FixLEA: Candidate to replace:"; MI.dump(););
|
|
||||||
DEBUG(dbgs() << "FixLEA: Replaced by: ";);
|
|
||||||
|
|
||||||
// First try to replace LEA with one or two (for the 3-op LEA case)
|
|
||||||
// add instructions:
|
|
||||||
// 1.lea (%base,%index,1), %base => add %index,%base
|
|
||||||
// 2.lea (%base,%index,1), %index => add %base,%index
|
|
||||||
if (IsScale1 && (DstR == BaseR || DstR == IndexR)) {
|
|
||||||
const MachineOperand &Src = DstR == BaseR ? Index : Base;
|
|
||||||
MachineInstr *NewMI =
|
|
||||||
BuildMI(*MFI, MI, DL, ADDrr, DstR).addReg(DstR).add(Src);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
// Create ADD instruction for the Offset in case of 3-Ops LEA.
|
|
||||||
if (hasLEAOffset(Offset)) {
|
|
||||||
NewMI = BuildMI(*MFI, MI, DL, ADDri, DstR).addReg(DstR).add(Offset);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
}
|
|
||||||
return NewMI;
|
|
||||||
}
|
|
||||||
// If the base is inefficient try switching the index and base operands,
|
|
||||||
// otherwise just break the 3-Ops LEA inst into 2-Ops LEA + ADD instruction:
|
|
||||||
// lea offset(%base,%index,scale),%dst =>
|
|
||||||
// lea (%base,%index,scale); add offset,%dst
|
|
||||||
if (!IsInefficientBase || (!IsInefficientIndex && IsScale1)) {
|
|
||||||
MachineInstr *NewMI = BuildMI(*MFI, MI, DL, TII->get(LEAOpcode))
|
|
||||||
.add(Dst)
|
|
||||||
.add(IsInefficientBase ? Index : Base)
|
|
||||||
.add(Scale)
|
|
||||||
.add(IsInefficientBase ? Base : Index)
|
|
||||||
.addImm(0)
|
|
||||||
.add(Segment);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
// Create ADD instruction for the Offset in case of 3-Ops LEA.
|
|
||||||
if (hasLEAOffset(Offset)) {
|
|
||||||
NewMI = BuildMI(*MFI, MI, DL, ADDri, DstR).addReg(DstR).add(Offset);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
}
|
|
||||||
return NewMI;
|
|
||||||
}
|
|
||||||
// Handle the rest of the cases with inefficient base register:
|
|
||||||
assert(SSDstR != BaseR && "SSDstR == BaseR should be handled already!");
|
|
||||||
assert(IsInefficientBase && "efficient base should be handled already!");
|
|
||||||
|
|
||||||
// lea (%base,%index,1), %dst => mov %base,%dst; add %index,%dst
|
|
||||||
if (IsScale1 && !hasLEAOffset(Offset)) {
|
|
||||||
TII->copyPhysReg(*MFI, MI, DL, DstR, BaseR, Base.isKill());
|
|
||||||
DEBUG(MI.getPrevNode()->dump(););
|
|
||||||
|
|
||||||
MachineInstr *NewMI =
|
|
||||||
BuildMI(*MFI, MI, DL, ADDrr, DstR).addReg(DstR).add(Index);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
return NewMI;
|
|
||||||
}
|
|
||||||
// lea offset(%base,%index,scale), %dst =>
|
|
||||||
// lea offset( ,%index,scale), %dst; add %base,%dst
|
|
||||||
MachineInstr *NewMI = BuildMI(*MFI, MI, DL, TII->get(LEAOpcode))
|
|
||||||
.add(Dst)
|
|
||||||
.addReg(0)
|
|
||||||
.add(Scale)
|
|
||||||
.add(Index)
|
|
||||||
.add(Offset)
|
|
||||||
.add(Segment);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
|
|
||||||
NewMI = BuildMI(*MFI, MI, DL, ADDrr, DstR).addReg(DstR).add(Base);
|
|
||||||
DEBUG(NewMI->dump(););
|
|
||||||
return NewMI;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FixupLEAPass::processBasicBlock(MachineFunction &MF,
|
bool FixupLEAPass::processBasicBlock(MachineFunction &MF,
|
||||||
MachineFunction::iterator MFI) {
|
MachineFunction::iterator MFI) {
|
||||||
|
|
||||||
@ -585,16 +410,8 @@ bool FixupLEAPass::processBasicBlock(MachineFunction &MF,
|
|||||||
if (OptLEA) {
|
if (OptLEA) {
|
||||||
if (MF.getSubtarget<X86Subtarget>().isSLM())
|
if (MF.getSubtarget<X86Subtarget>().isSLM())
|
||||||
processInstructionForSLM(I, MFI);
|
processInstructionForSLM(I, MFI);
|
||||||
|
else
|
||||||
else {
|
processInstruction(I, MFI);
|
||||||
if (MF.getSubtarget<X86Subtarget>().slow3OpsLEA()) {
|
|
||||||
if (auto *NewMI = processInstrForSlow3OpLEA(*I, MFI)) {
|
|
||||||
MFI->erase(I);
|
|
||||||
I = NewMI;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
processInstruction(I, MFI);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "X86Subtarget.h"
|
#include "X86Subtarget.h"
|
||||||
#include "X86TargetMachine.h"
|
#include "X86TargetMachine.h"
|
||||||
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
|
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
|
||||||
|
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
#include "llvm/CodeGen/MachineFunction.h"
|
||||||
#include "llvm/CodeGen/MachineInstr.h"
|
#include "llvm/CodeGen/MachineInstr.h"
|
||||||
@ -72,6 +73,9 @@ class X86InstructionSelector : public InstructionSelector {
|
|||||||
bool selectCmp(MachineInstr &I, MachineRegisterInfo &MRI,
|
bool selectCmp(MachineInstr &I, MachineRegisterInfo &MRI,
|
||||||
MachineFunction &MF) const;
|
MachineFunction &MF) const;
|
||||||
|
|
||||||
|
bool selectUadde(MachineInstr &I, MachineRegisterInfo &MRI,
|
||||||
|
MachineFunction &MF) const;
|
||||||
|
|
||||||
const X86TargetMachine &TM;
|
const X86TargetMachine &TM;
|
||||||
const X86Subtarget &STI;
|
const X86Subtarget &STI;
|
||||||
const X86InstrInfo &TII;
|
const X86InstrInfo &TII;
|
||||||
@ -243,6 +247,8 @@ bool X86InstructionSelector::select(MachineInstr &I) const {
|
|||||||
return true;
|
return true;
|
||||||
if (selectCmp(I, MRI, MF))
|
if (selectCmp(I, MRI, MF))
|
||||||
return true;
|
return true;
|
||||||
|
if (selectUadde(I, MRI, MF))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -564,6 +570,66 @@ bool X86InstructionSelector::selectCmp(MachineInstr &I,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool X86InstructionSelector::selectUadde(MachineInstr &I,
|
||||||
|
MachineRegisterInfo &MRI,
|
||||||
|
MachineFunction &MF) const {
|
||||||
|
if (I.getOpcode() != TargetOpcode::G_UADDE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const unsigned DstReg = I.getOperand(0).getReg();
|
||||||
|
const unsigned CarryOutReg = I.getOperand(1).getReg();
|
||||||
|
const unsigned Op0Reg = I.getOperand(2).getReg();
|
||||||
|
const unsigned Op1Reg = I.getOperand(3).getReg();
|
||||||
|
unsigned CarryInReg = I.getOperand(4).getReg();
|
||||||
|
|
||||||
|
const LLT DstTy = MRI.getType(DstReg);
|
||||||
|
|
||||||
|
if (DstTy != LLT::scalar(32))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// find CarryIn def instruction.
|
||||||
|
MachineInstr *Def = MRI.getVRegDef(CarryInReg);
|
||||||
|
while (Def->getOpcode() == TargetOpcode::G_TRUNC) {
|
||||||
|
CarryInReg = Def->getOperand(1).getReg();
|
||||||
|
Def = MRI.getVRegDef(CarryInReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Opcode;
|
||||||
|
if (Def->getOpcode() == TargetOpcode::G_UADDE) {
|
||||||
|
// carry set by prev ADD.
|
||||||
|
|
||||||
|
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), X86::EFLAGS)
|
||||||
|
.addReg(CarryInReg);
|
||||||
|
|
||||||
|
if (!RBI.constrainGenericRegister(CarryInReg, X86::GR32RegClass, MRI))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Opcode = X86::ADC32rr;
|
||||||
|
} else if (auto val = getConstantVRegVal(CarryInReg, MRI)) {
|
||||||
|
// carry is constant, support only 0.
|
||||||
|
if (*val != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Opcode = X86::ADD32rr;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MachineInstr &AddInst =
|
||||||
|
*BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode), DstReg)
|
||||||
|
.addReg(Op0Reg)
|
||||||
|
.addReg(Op1Reg);
|
||||||
|
|
||||||
|
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), CarryOutReg)
|
||||||
|
.addReg(X86::EFLAGS);
|
||||||
|
|
||||||
|
if (!constrainSelectedInstRegOperands(AddInst, TII, TRI, RBI) ||
|
||||||
|
!RBI.constrainGenericRegister(CarryOutReg, X86::GR32RegClass, MRI))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
I.eraseFromParent();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
InstructionSelector *
|
InstructionSelector *
|
||||||
llvm::createX86InstructionSelector(const X86TargetMachine &TM,
|
llvm::createX86InstructionSelector(const X86TargetMachine &TM,
|
||||||
X86Subtarget &Subtarget,
|
X86Subtarget &Subtarget,
|
||||||
|
@ -59,6 +59,11 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
|
|||||||
for (auto Ty : {s8, s16, s32})
|
for (auto Ty : {s8, s16, s32})
|
||||||
setAction({BinOp, Ty}, Legal);
|
setAction({BinOp, Ty}, Legal);
|
||||||
|
|
||||||
|
for (unsigned Op : {G_UADDE}) {
|
||||||
|
setAction({Op, s32}, Legal);
|
||||||
|
setAction({Op, 1, s1}, Legal);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned MemOp : {G_LOAD, G_STORE}) {
|
for (unsigned MemOp : {G_LOAD, G_STORE}) {
|
||||||
for (auto Ty : {s8, s16, s32, p0})
|
for (auto Ty : {s8, s16, s32, p0})
|
||||||
setAction({MemOp, Ty}, Legal);
|
setAction({MemOp, Ty}, Legal);
|
||||||
|
@ -253,11 +253,6 @@ class X86Subtarget final : public X86GenSubtargetInfo {
|
|||||||
/// True if the LEA instruction with certain arguments is slow
|
/// True if the LEA instruction with certain arguments is slow
|
||||||
bool SlowLEA;
|
bool SlowLEA;
|
||||||
|
|
||||||
/// True if the LEA instruction has all three source operands: base, index,
|
|
||||||
/// and offset or if the LEA instruction uses base and index registers where
|
|
||||||
/// the base is EBP, RBP,or R13
|
|
||||||
bool Slow3OpsLEA;
|
|
||||||
|
|
||||||
/// True if INC and DEC instructions are slow when writing to flags
|
/// True if INC and DEC instructions are slow when writing to flags
|
||||||
bool SlowIncDec;
|
bool SlowIncDec;
|
||||||
|
|
||||||
@ -495,7 +490,6 @@ class X86Subtarget final : public X86GenSubtargetInfo {
|
|||||||
bool callRegIndirect() const { return CallRegIndirect; }
|
bool callRegIndirect() const { return CallRegIndirect; }
|
||||||
bool LEAusesAG() const { return LEAUsesAG; }
|
bool LEAusesAG() const { return LEAUsesAG; }
|
||||||
bool slowLEA() const { return SlowLEA; }
|
bool slowLEA() const { return SlowLEA; }
|
||||||
bool slow3OpsLEA() const { return Slow3OpsLEA; }
|
|
||||||
bool slowIncDec() const { return SlowIncDec; }
|
bool slowIncDec() const { return SlowIncDec; }
|
||||||
bool hasCDI() const { return HasCDI; }
|
bool hasCDI() const { return HasCDI; }
|
||||||
bool hasPFI() const { return HasPFI; }
|
bool hasPFI() const { return HasPFI; }
|
||||||
|
@ -61,7 +61,6 @@ static cl::opt<bool> EnableMachineCombinerPass("x86-machine-combiner",
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
void initializeWinEHStatePassPass(PassRegistry &);
|
void initializeWinEHStatePassPass(PassRegistry &);
|
||||||
void initializeFixupLEAPassPass(PassRegistry &);
|
|
||||||
void initializeX86ExecutionDepsFixPass(PassRegistry &);
|
void initializeX86ExecutionDepsFixPass(PassRegistry &);
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
@ -76,7 +75,6 @@ extern "C" void LLVMInitializeX86Target() {
|
|||||||
initializeWinEHStatePassPass(PR);
|
initializeWinEHStatePassPass(PR);
|
||||||
initializeFixupBWInstPassPass(PR);
|
initializeFixupBWInstPassPass(PR);
|
||||||
initializeEvexToVexInstPassPass(PR);
|
initializeEvexToVexInstPassPass(PR);
|
||||||
initializeFixupLEAPassPass(PR);
|
|
||||||
initializeX86ExecutionDepsFixPass(PR);
|
initializeX86ExecutionDepsFixPass(PR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1392,6 +1392,16 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
|
|||||||
// CTLZ: llvm\test\CodeGen\X86\vector-lzcnt-*.ll
|
// CTLZ: llvm\test\CodeGen\X86\vector-lzcnt-*.ll
|
||||||
// CTPOP: llvm\test\CodeGen\X86\vector-popcnt-*.ll
|
// CTPOP: llvm\test\CodeGen\X86\vector-popcnt-*.ll
|
||||||
// CTTZ: llvm\test\CodeGen\X86\vector-tzcnt-*.ll
|
// CTTZ: llvm\test\CodeGen\X86\vector-tzcnt-*.ll
|
||||||
|
static const CostTblEntry AVX512BWCostTbl[] = {
|
||||||
|
{ ISD::BITREVERSE, MVT::v8i64, 5 },
|
||||||
|
{ ISD::BITREVERSE, MVT::v16i32, 5 },
|
||||||
|
{ ISD::BITREVERSE, MVT::v32i16, 5 },
|
||||||
|
{ ISD::BITREVERSE, MVT::v64i8, 5 },
|
||||||
|
};
|
||||||
|
static const CostTblEntry AVX512CostTbl[] = {
|
||||||
|
{ ISD::BITREVERSE, MVT::v8i64, 36 },
|
||||||
|
{ ISD::BITREVERSE, MVT::v16i32, 24 },
|
||||||
|
};
|
||||||
static const CostTblEntry XOPCostTbl[] = {
|
static const CostTblEntry XOPCostTbl[] = {
|
||||||
{ ISD::BITREVERSE, MVT::v4i64, 4 },
|
{ ISD::BITREVERSE, MVT::v4i64, 4 },
|
||||||
{ ISD::BITREVERSE, MVT::v8i32, 4 },
|
{ ISD::BITREVERSE, MVT::v8i32, 4 },
|
||||||
@ -1550,6 +1560,14 @@ int X86TTIImpl::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy,
|
|||||||
MVT MTy = LT.second;
|
MVT MTy = LT.second;
|
||||||
|
|
||||||
// Attempt to lookup cost.
|
// Attempt to lookup cost.
|
||||||
|
if (ST->hasBWI())
|
||||||
|
if (const auto *Entry = CostTableLookup(AVX512BWCostTbl, ISD, MTy))
|
||||||
|
return LT.first * Entry->Cost;
|
||||||
|
|
||||||
|
if (ST->hasAVX512())
|
||||||
|
if (const auto *Entry = CostTableLookup(AVX512CostTbl, ISD, MTy))
|
||||||
|
return LT.first * Entry->Cost;
|
||||||
|
|
||||||
if (ST->hasXOP())
|
if (ST->hasXOP())
|
||||||
if (const auto *Entry = CostTableLookup(XOPCostTbl, ISD, MTy))
|
if (const auto *Entry = CostTableLookup(XOPCostTbl, ISD, MTy))
|
||||||
return LT.first * Entry->Cost;
|
return LT.first * Entry->Cost;
|
||||||
|
@ -347,6 +347,27 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape,
|
|||||||
return FrameTy;
|
return FrameTy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to make room to insert a spill after initial PHIs, but before
|
||||||
|
// catchswitch instruction. Placing it before violates the requirement that
|
||||||
|
// catchswitch, like all other EHPads must be the first nonPHI in a block.
|
||||||
|
//
|
||||||
|
// Split away catchswitch into a separate block and insert in its place:
|
||||||
|
//
|
||||||
|
// cleanuppad <InsertPt> cleanupret.
|
||||||
|
//
|
||||||
|
// cleanupret instruction will act as an insert point for the spill.
|
||||||
|
static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
|
||||||
|
BasicBlock *CurrentBlock = CatchSwitch->getParent();
|
||||||
|
BasicBlock *NewBlock = CurrentBlock->splitBasicBlock(CatchSwitch);
|
||||||
|
CurrentBlock->getTerminator()->eraseFromParent();
|
||||||
|
|
||||||
|
auto *CleanupPad =
|
||||||
|
CleanupPadInst::Create(CatchSwitch->getParentPad(), {}, "", CurrentBlock);
|
||||||
|
auto *CleanupRet =
|
||||||
|
CleanupReturnInst::Create(CleanupPad, NewBlock, CurrentBlock);
|
||||||
|
return CleanupRet;
|
||||||
|
}
|
||||||
|
|
||||||
// Replace all alloca and SSA values that are accessed across suspend points
|
// Replace all alloca and SSA values that are accessed across suspend points
|
||||||
// with GetElementPointer from coroutine frame + loads and stores. Create an
|
// with GetElementPointer from coroutine frame + loads and stores. Create an
|
||||||
// AllocaSpillBB that will become the new entry block for the resume parts of
|
// AllocaSpillBB that will become the new entry block for the resume parts of
|
||||||
@ -437,8 +458,11 @@ static Instruction *insertSpills(SpillInfo &Spills, coro::Shape &Shape) {
|
|||||||
InsertPt = NewBB->getTerminator();
|
InsertPt = NewBB->getTerminator();
|
||||||
} else if (dyn_cast<PHINode>(CurrentValue)) {
|
} else if (dyn_cast<PHINode>(CurrentValue)) {
|
||||||
// Skip the PHINodes and EH pads instructions.
|
// Skip the PHINodes and EH pads instructions.
|
||||||
InsertPt =
|
BasicBlock *DefBlock = cast<Instruction>(E.def())->getParent();
|
||||||
&*cast<Instruction>(E.def())->getParent()->getFirstInsertionPt();
|
if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator()))
|
||||||
|
InsertPt = splitBeforeCatchSwitch(CSI);
|
||||||
|
else
|
||||||
|
InsertPt = &*DefBlock->getFirstInsertionPt();
|
||||||
} else {
|
} else {
|
||||||
// For all other values, the spill is placed immediately after
|
// For all other values, the spill is placed immediately after
|
||||||
// the definition.
|
// the definition.
|
||||||
|
@ -74,6 +74,27 @@ static inline unsigned getComplexity(Value *V) {
|
|||||||
return isa<Constant>(V) ? (isa<UndefValue>(V) ? 0 : 1) : 2;
|
return isa<Constant>(V) ? (isa<UndefValue>(V) ? 0 : 1) : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Predicate canonicalization reduces the number of patterns that need to be
|
||||||
|
/// matched by other transforms. For example, we may swap the operands of a
|
||||||
|
/// conditional branch or select to create a compare with a canonical (inverted)
|
||||||
|
/// predicate which is then more likely to be matched with other values.
|
||||||
|
static inline bool isCanonicalPredicate(CmpInst::Predicate Pred) {
|
||||||
|
switch (Pred) {
|
||||||
|
case CmpInst::ICMP_NE:
|
||||||
|
case CmpInst::ICMP_ULE:
|
||||||
|
case CmpInst::ICMP_SLE:
|
||||||
|
case CmpInst::ICMP_UGE:
|
||||||
|
case CmpInst::ICMP_SGE:
|
||||||
|
// TODO: There are 16 FCMP predicates. Should others be (not) canonical?
|
||||||
|
case CmpInst::FCMP_ONE:
|
||||||
|
case CmpInst::FCMP_OLE:
|
||||||
|
case CmpInst::FCMP_OGE:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Add one to a Constant
|
/// \brief Add one to a Constant
|
||||||
static inline Constant *AddOne(Constant *C) {
|
static inline Constant *AddOne(Constant *C) {
|
||||||
return ConstantExpr::getAdd(C, ConstantInt::get(C->getType(), 1));
|
return ConstantExpr::getAdd(C, ConstantInt::get(C->getType(), 1));
|
||||||
|
@ -2210,37 +2210,17 @@ Instruction *InstCombiner::visitBranchInst(BranchInst &BI) {
|
|||||||
return &BI;
|
return &BI;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Canonicalize fcmp_one -> fcmp_oeq
|
// Canonicalize, for example, icmp_ne -> icmp_eq or fcmp_one -> fcmp_oeq.
|
||||||
FCmpInst::Predicate FPred; Value *Y;
|
CmpInst::Predicate Pred;
|
||||||
if (match(&BI, m_Br(m_OneUse(m_FCmp(FPred, m_Value(X), m_Value(Y))),
|
if (match(&BI, m_Br(m_OneUse(m_Cmp(Pred, m_Value(), m_Value())), TrueDest,
|
||||||
TrueDest, FalseDest))) {
|
FalseDest)) &&
|
||||||
// TODO: Why are we only transforming these 3 predicates?
|
!isCanonicalPredicate(Pred)) {
|
||||||
if (FPred == FCmpInst::FCMP_ONE || FPred == FCmpInst::FCMP_OLE ||
|
// Swap destinations and condition.
|
||||||
FPred == FCmpInst::FCMP_OGE) {
|
CmpInst *Cond = cast<CmpInst>(BI.getCondition());
|
||||||
FCmpInst *Cond = cast<FCmpInst>(BI.getCondition());
|
Cond->setPredicate(CmpInst::getInversePredicate(Pred));
|
||||||
Cond->setPredicate(FCmpInst::getInversePredicate(FPred));
|
BI.swapSuccessors();
|
||||||
|
Worklist.Add(Cond);
|
||||||
// Swap Destinations and condition.
|
return &BI;
|
||||||
BI.swapSuccessors();
|
|
||||||
Worklist.Add(Cond);
|
|
||||||
return &BI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonicalize icmp_ne -> icmp_eq
|
|
||||||
ICmpInst::Predicate IPred;
|
|
||||||
if (match(&BI, m_Br(m_OneUse(m_ICmp(IPred, m_Value(X), m_Value(Y))),
|
|
||||||
TrueDest, FalseDest))) {
|
|
||||||
if (IPred == ICmpInst::ICMP_NE || IPred == ICmpInst::ICMP_ULE ||
|
|
||||||
IPred == ICmpInst::ICMP_SLE || IPred == ICmpInst::ICMP_UGE ||
|
|
||||||
IPred == ICmpInst::ICMP_SGE) {
|
|
||||||
ICmpInst *Cond = cast<ICmpInst>(BI.getCondition());
|
|
||||||
Cond->setPredicate(ICmpInst::getInversePredicate(IPred));
|
|
||||||
// Swap Destinations and condition.
|
|
||||||
BI.swapSuccessors();
|
|
||||||
Worklist.Add(Cond);
|
|
||||||
return &BI;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -3053,7 +3033,10 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB, const DataLayout &DL,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrsForInstCombineWorklist.push_back(Inst);
|
// Skip processing debug intrinsics in InstCombine. Processing these call instructions
|
||||||
|
// consumes non-trivial amount of time and provides no value for the optimization.
|
||||||
|
if (!isa<DbgInfoIntrinsic>(Inst))
|
||||||
|
InstrsForInstCombineWorklist.push_back(Inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively visit successors. If this is a branch or switch on a
|
// Recursively visit successors. If this is a branch or switch on a
|
||||||
|
@ -546,7 +546,7 @@ static bool isLoadInvariantInLoop(LoadInst *LI, DominatorTree *DT,
|
|||||||
// If there are escaping uses of invariant.start instruction, the load maybe
|
// If there are escaping uses of invariant.start instruction, the load maybe
|
||||||
// non-invariant.
|
// non-invariant.
|
||||||
if (!II || II->getIntrinsicID() != Intrinsic::invariant_start ||
|
if (!II || II->getIntrinsicID() != Intrinsic::invariant_start ||
|
||||||
II->hasNUsesOrMore(1))
|
!II->use_empty())
|
||||||
continue;
|
continue;
|
||||||
unsigned InvariantSizeInBits =
|
unsigned InvariantSizeInBits =
|
||||||
cast<ConstantInt>(II->getArgOperand(0))->getSExtValue() * 8;
|
cast<ConstantInt>(II->getArgOperand(0))->getSExtValue() * 8;
|
||||||
|
@ -1292,13 +1292,15 @@ bool LoopIdiomRecognize::recognizeAndInsertCTLZ() {
|
|||||||
BasicBlock *PH = CurLoop->getLoopPreheader();
|
BasicBlock *PH = CurLoop->getLoopPreheader();
|
||||||
Value *InitX = PhiX->getIncomingValueForBlock(PH);
|
Value *InitX = PhiX->getIncomingValueForBlock(PH);
|
||||||
// If we check X != 0 before entering the loop we don't need a zero
|
// If we check X != 0 before entering the loop we don't need a zero
|
||||||
// check in CTLZ intrinsic.
|
// check in CTLZ intrinsic, but only if Cnt Phi is not used outside of the
|
||||||
if (BasicBlock *PreCondBB = PH->getSinglePredecessor())
|
// loop (if it is used we count CTLZ(X >> 1)).
|
||||||
if (BranchInst *PreCondBr =
|
if (!IsCntPhiUsedOutsideLoop)
|
||||||
dyn_cast<BranchInst>(PreCondBB->getTerminator())) {
|
if (BasicBlock *PreCondBB = PH->getSinglePredecessor())
|
||||||
if (matchCondition(PreCondBr, PH) == InitX)
|
if (BranchInst *PreCondBr =
|
||||||
ZeroCheck = true;
|
dyn_cast<BranchInst>(PreCondBB->getTerminator())) {
|
||||||
}
|
if (matchCondition(PreCondBr, PH) == InitX)
|
||||||
|
ZeroCheck = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if CTLZ intrinsic is profitable. Assume it is always profitable
|
// Check if CTLZ intrinsic is profitable. Assume it is always profitable
|
||||||
// if we delete the loop (the loop has only 6 instructions):
|
// if we delete the loop (the loop has only 6 instructions):
|
||||||
|
@ -3902,8 +3902,7 @@ void LSRInstance::GenerateCrossUseConstantOffsets() {
|
|||||||
|
|
||||||
// Compute the difference between the two.
|
// Compute the difference between the two.
|
||||||
int64_t Imm = (uint64_t)JImm - M->first;
|
int64_t Imm = (uint64_t)JImm - M->first;
|
||||||
for (int LUIdx = UsedByIndices.find_first(); LUIdx != -1;
|
for (unsigned LUIdx : UsedByIndices.set_bits())
|
||||||
LUIdx = UsedByIndices.find_next(LUIdx))
|
|
||||||
// Make a memo of this use, offset, and register tuple.
|
// Make a memo of this use, offset, and register tuple.
|
||||||
if (UniqueItems.insert(std::make_pair(LUIdx, Imm)).second)
|
if (UniqueItems.insert(std::make_pair(LUIdx, Imm)).second)
|
||||||
WorkItems.push_back(WorkItem(LUIdx, Imm, OrigReg));
|
WorkItems.push_back(WorkItem(LUIdx, Imm, OrigReg));
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user