Skip to content

Commit

Permalink
Reduce alignment of SmallVector<T> to the required amount, rather tha…
Browse files Browse the repository at this point in the history
…n forcing 16-byte alignment. This fixes misaligned SmallVector accesses via ExtractValueInst's SmallVector data member.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@162331 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
zygoloid committed Aug 22, 2012
1 parent 6871d1e commit bc36393
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 104 deletions.
13 changes: 9 additions & 4 deletions include/llvm/ADT/ArrayRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,17 @@ namespace llvm {
ArrayRef(const T *begin, const T *end)
: Data(begin), Length(end - begin) {}

/// Construct an ArrayRef from a SmallVector.
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T> &Vec)
: Data(Vec.data()), Length(Vec.size()) {}
/// Construct an ArrayRef from a SmallVector. This is templated in order to
/// avoid instantiating SmallVectorTemplateCommon<T> whenever we
/// copy-construct an ArrayRef.
template<typename U>
/*implicit*/ ArrayRef(const SmallVectorTemplateCommon<T, U> &Vec)
: Data(Vec.data()), Length(Vec.size()) {
}

/// Construct an ArrayRef from a std::vector.
/*implicit*/ ArrayRef(const std::vector<T> &Vec)
template<typename A>
/*implicit*/ ArrayRef(const std::vector<T, A> &Vec)
: Data(Vec.empty() ? (T*)0 : &Vec[0]), Length(Vec.size()) {}

/// Construct an ArrayRef from a C array.
Expand Down
152 changes: 55 additions & 97 deletions include/llvm/ADT/SmallVector.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_ADT_SMALLVECTOR_H
#define LLVM_ADT_SMALLVECTOR_H

#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/type_traits.h"
#include <algorithm>
Expand All @@ -32,44 +33,20 @@ class SmallVectorBase {
protected:
void *BeginX, *EndX, *CapacityX;

// 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
// something else. An array of char would work great, but might not be
// aligned sufficiently. Instead we use some number of union instances for
// the space, which guarantee maximal alignment.
union U {
double D;
long double LD;
long long L;
void *P;
} FirstEl;
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.

protected:
SmallVectorBase(size_t Size)
: BeginX(&FirstEl), EndX(&FirstEl), CapacityX((char*)&FirstEl+Size) {}

/// isSmall - Return true if this is a smallvector which has not had dynamic
/// memory allocated for it.
bool isSmall() const {
return BeginX == static_cast<const void*>(&FirstEl);
}

/// resetToSmall - Put this vector in a state of being small.
void resetToSmall() {
BeginX = EndX = CapacityX = &FirstEl;
}
SmallVectorBase(void *FirstEl, size_t Size)
: BeginX(FirstEl), EndX(FirstEl), CapacityX((char*)FirstEl+Size) {}

/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like data types and is out of line to reduce code duplication.
void grow_pod(size_t MinSizeInBytes, size_t TSize);
void grow_pod(void *FirstEl, size_t MinSizeInBytes, size_t TSize);

public:
/// size_in_bytes - This returns size()*sizeof(T).
size_t size_in_bytes() const {
return size_t((char*)EndX - (char*)BeginX);
}

/// capacity_in_bytes - This returns capacity()*sizeof(T).
size_t capacity_in_bytes() const {
return size_t((char*)CapacityX - (char*)BeginX);
Expand All @@ -78,11 +55,41 @@ class SmallVectorBase {
bool empty() const { return BeginX == EndX; }
};

template <typename T, unsigned N> struct SmallVectorStorage;

template <typename T>
/// SmallVectorTemplateCommon - This is the part of SmallVectorTemplateBase
/// which does not depend on whether the type T is a POD. The extra dummy
/// template argument is used by ArrayRef to avoid unnecessarily requiring T
/// to be complete.
template <typename T, typename = void>
class SmallVectorTemplateCommon : public SmallVectorBase {
private:
template <typename, unsigned> friend struct SmallVectorStorage;

// 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
// something else. Use an array of char of sufficient alignment.
typedef llvm::AlignedCharArrayUnion<T> U;
U FirstEl;
// Space after 'FirstEl' is clobbered, do not add any instance vars after it.

protected:
SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(Size) {}
SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(&FirstEl, Size) {}

void grow_pod(size_t MinSizeInBytes, size_t TSize) {
SmallVectorBase::grow_pod(&FirstEl, MinSizeInBytes, TSize);
}

/// isSmall - Return true if this is a smallvector which has not had dynamic
/// memory allocated for it.
bool isSmall() const {
return BeginX == static_cast<const void*>(&FirstEl);
}

/// resetToSmall - Put this vector in a state of being small.
void resetToSmall() {
BeginX = EndX = CapacityX = &FirstEl;
}

void setEnd(T *P) { this->EndX = P; }
public:
Expand Down Expand Up @@ -844,6 +851,17 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
}
#endif

/// Storage for the SmallVector elements which aren't contained in
/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1'
/// element is in the base class. This is specialized for the N=1 and N=0 cases
/// to avoid allocating unnecessary storage.
template <typename T, unsigned N>
struct SmallVectorStorage {
typename SmallVectorTemplateCommon<T>::U InlineElts[N - 1];
};
template <typename T> struct SmallVectorStorage<T, 1> {};
template <typename T> struct SmallVectorStorage<T, 0> {};

/// SmallVector - This is a 'vector' (really, a variable-sized array), optimized
/// for the case when the array is small. It contains some number of elements
/// in-place, which allows it to avoid heap allocation when the actual number of
Expand All @@ -854,41 +872,23 @@ SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
///
template <typename T, unsigned N>
class SmallVector : public SmallVectorImpl<T> {
/// InlineElts - These are 'N-1' elements that are stored inline in the body
/// of the vector. The extra '1' element is stored in SmallVectorImpl.
typedef typename SmallVectorImpl<T>::U U;
enum {
// MinUs - The number of U's require to cover N T's.
MinUs = (static_cast<unsigned int>(sizeof(T))*N +
static_cast<unsigned int>(sizeof(U)) - 1) /
static_cast<unsigned int>(sizeof(U)),

// NumInlineEltsElts - The number of elements actually in this array. There
// is already one in the parent class, and we have to round up to avoid
// having a zero-element array.
NumInlineEltsElts = MinUs > 1 ? (MinUs - 1) : 1,

// NumTsAvailable - The number of T's we actually have space for, which may
// be more than N due to rounding.
NumTsAvailable = (NumInlineEltsElts+1)*static_cast<unsigned int>(sizeof(U))/
static_cast<unsigned int>(sizeof(T))
};
U InlineElts[NumInlineEltsElts];
/// Storage - Inline space for elements which aren't stored in the base class.
SmallVectorStorage<T, N> Storage;
public:
SmallVector() : SmallVectorImpl<T>(NumTsAvailable) {
SmallVector() : SmallVectorImpl<T>(N) {
}

explicit SmallVector(unsigned Size, const T &Value = T())
: SmallVectorImpl<T>(NumTsAvailable) {
: SmallVectorImpl<T>(N) {
this->assign(Size, Value);
}

template<typename ItTy>
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(NumTsAvailable) {
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
this->append(S, E);
}

SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(NumTsAvailable) {
SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(RHS);
}
Expand All @@ -899,7 +899,7 @@ class SmallVector : public SmallVectorImpl<T> {
}

#if LLVM_USE_RVALUE_REFERENCES
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(NumTsAvailable) {
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(::std::move(RHS));
}
Expand All @@ -912,48 +912,6 @@ class SmallVector : public SmallVectorImpl<T> {

};

/// Specialize SmallVector at N=0. This specialization guarantees
/// that it can be instantiated at an incomplete T if none of its
/// members are required.
template <typename T>
class SmallVector<T,0> : public SmallVectorImpl<T> {
public:
SmallVector() : SmallVectorImpl<T>(0) {
}

explicit SmallVector(unsigned Size, const T &Value = T())
: SmallVectorImpl<T>(0) {
this->assign(Size, Value);
}

template<typename ItTy>
SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(0) {
this->append(S, E);
}

SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(0) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(RHS);
}

const SmallVector &operator=(const SmallVector &RHS) {
SmallVectorImpl<T>::operator=(RHS);
return *this;
}

#if LLVM_USE_RVALUE_REFERENCES
SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(0) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(::std::move(RHS));
}

const SmallVector &operator=(SmallVector &&RHS) {
SmallVectorImpl<T>::operator=(::std::move(RHS));
return *this;
}
#endif
};

template<typename T, unsigned N>
static inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
return X.capacity_in_bytes();
Expand Down
6 changes: 3 additions & 3 deletions lib/Support/SmallVector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ using namespace llvm;

/// 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.
void SmallVectorBase::grow_pod(size_t MinSizeInBytes, size_t TSize) {
void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
size_t TSize) {
size_t CurSizeBytes = size_in_bytes();
size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
if (NewCapacityInBytes < MinSizeInBytes)
NewCapacityInBytes = MinSizeInBytes;

void *NewElts;
if (this->isSmall()) {
if (BeginX == FirstEl) {
NewElts = malloc(NewCapacityInBytes);

// Copy the elements over. No need to run dtors on PODs.
Expand All @@ -37,4 +38,3 @@ void SmallVectorBase::grow_pod(size_t MinSizeInBytes, size_t TSize) {
this->BeginX = NewElts;
this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
}

0 comments on commit bc36393

Please sign in to comment.