aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/SmallVector.cpp
diff options
context:
space:
mode:
authorAndrew Browne <browneee@google.com>2020-04-21 23:32:31 -0700
committerAndrew Browne <browneee@google.com>2020-04-24 18:57:54 -0700
commitb5f0eae1dc3c09c020cdf9d07238dec9acdacf5f (patch)
treee6331d22c0413c200b97debe0a6261acefb95740 /llvm/lib/Support/SmallVector.cpp
parenta0919ac080951dec5047f18319a2974b6c6258e5 (diff)
downloadllvm-b5f0eae1dc3c09c020cdf9d07238dec9acdacf5f.zip
llvm-b5f0eae1dc3c09c020cdf9d07238dec9acdacf5f.tar.gz
llvm-b5f0eae1dc3c09c020cdf9d07238dec9acdacf5f.tar.bz2
ADT: SmallVector size/capacity use word-size integers when elements are small
SmallVector currently uses 32bit integers for size and capacity to reduce sizeof(SmallVector). This limits the number of elements to UINT32_MAX. For a SmallVector<char>, this limits the SmallVector size to only 4GB. Buffering bitcode output uses SmallVector<char>, but needs >4GB output. This changes SmallVector size and capacity to conditionally use word-size integers if the element type is small (<4 bytes). For larger elements types, the vector size can reach ~16GB with 32bit size. Making this conditional on the element type provides both the smaller sizeof(SmallVector) for larger types which are unlikely to grow so large, and supports larger capacities for smaller element types.
Diffstat (limited to 'llvm/lib/Support/SmallVector.cpp')
-rw-r--r--llvm/lib/Support/SmallVector.cpp29
1 files changed, 19 insertions, 10 deletions
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index 9ece0c5..e267bde 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -37,24 +37,30 @@ static_assert(sizeof(SmallVector<void *, 1>) ==
sizeof(unsigned) * 2 + sizeof(void *) * 2,
"wasted space in SmallVector size 1");
-/// grow_pod - This is an implementation of the grow() method which only works
-/// on POD-like datatypes and is out of line to reduce code duplication.
-/// This function will report a fatal error if it cannot increase capacity.
-void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
- size_t TSize) {
- // Ensure we can fit the new capacity in 32 bits.
- if (MinCapacity > UINT32_MAX)
+static_assert(sizeof(SmallVector<char, 0>) ==
+ sizeof(void *) * 2 + sizeof(void *),
+ "1 byte elements have word-sized type for size and capacity");
+
+// Note: Moving this function into the header may cause performance regression.
+template <class Size_T>
+void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinCapacity,
+ size_t TSize) {
+ // Ensure we can fit the new capacity.
+ // This is only going to be applicable when the capacity is 32 bit.
+ if (MinCapacity > SizeTypeMax())
report_bad_alloc_error("SmallVector capacity overflow during allocation");
// Ensure we can meet the guarantee of space for at least one more element.
// The above check alone will not catch the case where grow is called with a
// default MinCapacity of 0, but the current capacity cannot be increased.
- if (capacity() == size_t(UINT32_MAX))
+ // This is only going to be applicable when the capacity is 32 bit.
+ if (capacity() == SizeTypeMax())
report_bad_alloc_error("SmallVector capacity unable to grow");
+ // In theory 2*capacity can overflow if the capacity is 64 bit, but the
+ // original capacity would never be large enough for this to be a problem.
size_t NewCapacity = 2 * capacity() + 1; // Always grow.
- NewCapacity =
- std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
+ NewCapacity = std::min(std::max(NewCapacity, MinCapacity), SizeTypeMax());
void *NewElts;
if (BeginX == FirstEl) {
@@ -70,3 +76,6 @@ void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
this->BeginX = NewElts;
this->Capacity = NewCapacity;
}
+
+template class llvm::SmallVectorBase<uint32_t>;
+template class llvm::SmallVectorBase<uintptr_t>;