Commit 2f00bf6d by Jim Stichnoth

Subzero: Improve the behavior of resizing vectors.

In some cases, Subzero needs to insert into a std::vector at a particular index, resizing the vector as necessary. It appears that our vector implementation sets the capacity to exactly the size when growing the vector, without leaving any extra capacity. This causes lots of mallocs and recopies each time the vector size is increased. (Adding elements via push_back() or emplace_back() doesn't seem to have that behavior.) We help this by reserving some extra space before resizing - bump to the next power of 2 up to some point, then bump to the next multiple of a chunk size beyond that point. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4360 R=kschimpf@google.com Review URL: https://codereview.chromium.org/1783113002 .
parent 96fac393
...@@ -63,7 +63,7 @@ AssemblerX86Base<TraitsType>::getOrCreateLabel(SizeT Number, ...@@ -63,7 +63,7 @@ AssemblerX86Base<TraitsType>::getOrCreateLabel(SizeT Number,
return L; return L;
} }
if (Number > Labels.size()) { if (Number > Labels.size()) {
Labels.resize(Number + 1); Utils::reserveAndResize(Labels, Number + 1);
} }
L = Labels[Number]; L = Labels[Number];
if (!L) { if (!L) {
......
...@@ -375,7 +375,7 @@ namespace { ...@@ -375,7 +375,7 @@ namespace {
// Ensure Pending is large enough that Pending[Index] is valid. // Ensure Pending is large enough that Pending[Index] is valid.
void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) {
if (Index >= Pending.size()) if (Index >= Pending.size())
Pending.resize(Index + 1); Utils::reserveAndResize(Pending, Index + 1);
} }
} // end of anonymous namespace } // end of anonymous namespace
......
...@@ -36,14 +36,14 @@ template <typename D, typename S> inline D bitCopy(const S &Source) { ...@@ -36,14 +36,14 @@ template <typename D, typename S> inline D bitCopy(const S &Source) {
} }
/// Check whether an N-bit two's-complement representation can hold value. /// Check whether an N-bit two's-complement representation can hold value.
template <typename T> static inline bool IsInt(int N, T value) { template <typename T> inline bool IsInt(int N, T value) {
assert((0 < N) && assert((0 < N) &&
(static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(value)))); (static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(value))));
T limit = static_cast<T>(1) << (N - 1); T limit = static_cast<T>(1) << (N - 1);
return (-limit <= value) && (value < limit); return (-limit <= value) && (value < limit);
} }
template <typename T> static inline bool IsUint(int N, T value) { template <typename T> inline bool IsUint(int N, T value) {
assert((0 < N) && assert((0 < N) &&
(static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(value)))); (static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(value))));
T limit = static_cast<T>(1) << N; T limit = static_cast<T>(1) << N;
...@@ -52,7 +52,7 @@ template <typename T> static inline bool IsUint(int N, T value) { ...@@ -52,7 +52,7 @@ template <typename T> static inline bool IsUint(int N, T value) {
/// Check whether the magnitude of value fits in N bits, i.e., whether an /// Check whether the magnitude of value fits in N bits, i.e., whether an
/// (N+1)-bit sign-magnitude representation can hold value. /// (N+1)-bit sign-magnitude representation can hold value.
template <typename T> static inline bool IsAbsoluteUint(int N, T Value) { template <typename T> inline bool IsAbsoluteUint(int N, T Value) {
assert((0 < N) && assert((0 < N) &&
(static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(Value)))); (static_cast<unsigned int>(N) < (CHAR_BIT * sizeof(Value))));
if (Value < 0) if (Value < 0)
...@@ -62,14 +62,14 @@ template <typename T> static inline bool IsAbsoluteUint(int N, T Value) { ...@@ -62,14 +62,14 @@ template <typename T> static inline bool IsAbsoluteUint(int N, T Value) {
/// Return true if the addition X + Y will cause integer overflow for integers /// Return true if the addition X + Y will cause integer overflow for integers
/// of type T. /// of type T.
template <typename T> static inline bool WouldOverflowAdd(T X, T Y) { template <typename T> inline bool WouldOverflowAdd(T X, T Y) {
return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) || return ((X > 0 && Y > 0 && (X > std::numeric_limits<T>::max() - Y)) ||
(X < 0 && Y < 0 && (X < std::numeric_limits<T>::min() - Y))); (X < 0 && Y < 0 && (X < std::numeric_limits<T>::min() - Y)));
} }
/// Adds x to y and stores the result in sum. Returns true if the addition /// Adds x to y and stores the result in sum. Returns true if the addition
/// overflowed. /// overflowed.
static inline bool add_overflow(uint32_t x, uint32_t y, uint32_t *sum) { inline bool add_overflow(uint32_t x, uint32_t y, uint32_t *sum) {
static_assert(std::is_same<uint32_t, unsigned>::value, "Must match type"); static_assert(std::is_same<uint32_t, unsigned>::value, "Must match type");
#if __has_builtin(__builtin_uadd_overflow) #if __has_builtin(__builtin_uadd_overflow)
return __builtin_uadd_overflow(x, y, sum); return __builtin_uadd_overflow(x, y, sum);
...@@ -80,20 +80,20 @@ static inline bool add_overflow(uint32_t x, uint32_t y, uint32_t *sum) { ...@@ -80,20 +80,20 @@ static inline bool add_overflow(uint32_t x, uint32_t y, uint32_t *sum) {
} }
/// Return true if X is already aligned by N, where N is a power of 2. /// Return true if X is already aligned by N, where N is a power of 2.
template <typename T> static inline bool IsAligned(T X, intptr_t N) { template <typename T> inline bool IsAligned(T X, intptr_t N) {
assert(llvm::isPowerOf2_64(N)); assert(llvm::isPowerOf2_64(N));
return (X & (N - 1)) == 0; return (X & (N - 1)) == 0;
} }
/// Return Value adjusted to the next highest multiple of Alignment. /// Return Value adjusted to the next highest multiple of Alignment.
static inline uint32_t applyAlignment(uint32_t Value, uint32_t Alignment) { inline uint32_t applyAlignment(uint32_t Value, uint32_t Alignment) {
assert(llvm::isPowerOf2_32(Alignment)); assert(llvm::isPowerOf2_32(Alignment));
return (Value + Alignment - 1) & -Alignment; return (Value + Alignment - 1) & -Alignment;
} }
/// Return amount which must be added to adjust Pos to the next highest /// Return amount which must be added to adjust Pos to the next highest
/// multiple of Align. /// multiple of Align.
static inline uint64_t OffsetToAlignment(uint64_t Pos, uint64_t Align) { inline uint64_t OffsetToAlignment(uint64_t Pos, uint64_t Align) {
assert(llvm::isPowerOf2_64(Align)); assert(llvm::isPowerOf2_64(Align));
uint64_t Mod = Pos & (Align - 1); uint64_t Mod = Pos & (Align - 1);
if (Mod == 0) if (Mod == 0)
...@@ -103,26 +103,53 @@ static inline uint64_t OffsetToAlignment(uint64_t Pos, uint64_t Align) { ...@@ -103,26 +103,53 @@ static inline uint64_t OffsetToAlignment(uint64_t Pos, uint64_t Align) {
/// Rotate the value bit pattern to the left by shift bits. /// Rotate the value bit pattern to the left by shift bits.
/// Precondition: 0 <= shift < 32 /// Precondition: 0 <= shift < 32
static inline uint32_t rotateLeft32(uint32_t value, uint32_t shift) { inline uint32_t rotateLeft32(uint32_t value, uint32_t shift) {
if (shift == 0) if (shift == 0)
return value; return value;
return (value << shift) | (value >> (32 - shift)); return (value << shift) | (value >> (32 - shift));
} }
/// Rotate the value bit pattern to the right by shift bits. /// Rotate the value bit pattern to the right by shift bits.
static inline uint32_t rotateRight32(uint32_t value, uint32_t shift) { inline uint32_t rotateRight32(uint32_t value, uint32_t shift) {
if (shift == 0) if (shift == 0)
return value; return value;
return (value >> shift) | (value << (32 - shift)); return (value >> shift) | (value << (32 - shift));
} }
/// Returns true if Val is +0.0. It requires T to be a floating point type. /// Returns true if Val is +0.0. It requires T to be a floating point type.
template <typename T> static bool isPositiveZero(T Val) { template <typename T> bool isPositiveZero(T Val) {
static_assert(std::is_floating_point<T>::value, static_assert(std::is_floating_point<T>::value,
"Input type must be floating point"); "Input type must be floating point");
return Val == 0 && !std::signbit(Val); return Val == 0 && !std::signbit(Val);
} }
/// Resize a vector (or other suitable container) to a particular size, and also
/// reserve possibly a larger size to avoid repeatedly recopying as the
/// container grows. It uses a strategy of doubling capacity up to a certain
/// point, after which it bumps the capacity by a fixed amount.
template <typename Container>
inline void reserveAndResize(Container &V, uint32_t Size,
uint32_t ChunkSizeBits = 10) {
#if __has_builtin(__builtin_clz)
// Don't call reserve() if Size==0.
if (Size > 0) {
uint32_t Mask;
if (Size <= (1 << ChunkSizeBits)) {
// For smaller sizes, reserve the smallest power of 2 greater than or
// equal to Size.
Mask =
((1 << (CHAR_BIT * sizeof(uint32_t) - __builtin_clz(Size))) - 1) - 1;
} else {
// For larger sizes, round up to the smallest multiple of 1<<ChunkSizeBits
// greater than or equal to Size.
Mask = (1 << ChunkSizeBits) - 1;
}
V.reserve((Size + Mask) & ~Mask);
}
#endif
V.resize(Size);
}
/// An RAII class to ensure that a boolean flag is restored to its previous /// An RAII class to ensure that a boolean flag is restored to its previous
/// value upon function exit. /// value upon function exit.
/// ///
......
...@@ -275,7 +275,7 @@ public: ...@@ -275,7 +275,7 @@ public:
// Recover by using existing type slot. // Recover by using existing type slot.
return &TypeIDValues[0]; return &TypeIDValues[0];
} }
TypeIDValues.resize(ID + 1); Ice::Utils::reserveAndResize(TypeIDValues, ID + 1);
} }
return &TypeIDValues[ID]; return &TypeIDValues[ID];
} }
...@@ -1566,7 +1566,7 @@ private: ...@@ -1566,7 +1566,7 @@ private:
// Recover by using index one beyond the maximal allowed. // Recover by using index one beyond the maximal allowed.
LocalIndex = MaxRecordsInBlock; LocalIndex = MaxRecordsInBlock;
} }
LocalOperands.resize(LocalIndex + 1); Ice::Utils::reserveAndResize(LocalOperands, LocalIndex + 1);
} }
// If element not defined, set it. // If element not defined, set it.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment