This is an archive of the discontinued LLVM Phabricator instance.

ADT: Shrink SmallVector size 0 to 16B on 64-bit platforms
ClosedPublic

Authored by dexonsmith on Jul 10 2018, 5:14 PM.

Details

Reviewers
rsmith
rnk
Summary

SmallVectorTemplateCommon wants to know the address of the first element so it can detect whether it's in "small size" mode.

The old implementation split the small array, creating the storage for the first element in SmallVectorTemplateCommon, and pulling the rest into SmallVectorStorage where we know the size of the array. This bloats SmallVector small-size 0 by the larger of sizeof(void*) and sizeof(T) unnecessarily.

The new implementation leaves the full small storage to SmallVectorStorage. To calculate the offset of the first element in SmallVectorTemplateCommon, we just need to know how far to jump, which we can calculate out-of-band. One subtlety is that we need SmallVectorStorage to be properly aligned even when the size is 0, to be sure that (for large alignments) we actually have the padding and it's well defined to do the pointer math.

Diff Detail

Event Timeline

dexonsmith created this revision.Jul 10 2018, 5:14 PM
rnk added a reviewer: rsmith.Jul 19 2018, 2:51 PM
rnk added a subscriber: rnk.

@rsmith, what's the least bad way to do what SmallVector is trying to do?

llvm/include/llvm/ADT/SmallVector.h
90

This assumes that base classes are laid out more or less the same as fields, but we were already assuming that there wouldn't be padding between FirstEl and InlineElts, so this seems like an improvement.

dexonsmith added inline comments.Jul 19 2018, 3:37 PM
llvm/include/llvm/ADT/SmallVector.h
90

What about this?

struct SmallVectorAlignmentAndSizeBase {
  AlignedCharArrayUnion<SmallVectorBase> Base;
};
template <class T>
struct SmallVectorAlignmentAndSize : SmallVectorAlignmentAndSizeBase {
  AlignedCharArrayUnion<T> FirstEl;
};

// still doing this later:
  void *getFirstEl() const {
    return const_cast<void *>(reinterpret_cast<const void *>(
        reinterpret_cast<const char *>(this) +
        offsetof(SmallVectorAlignmentAndSize<T>, FirstEl)));
  }
dexonsmith added inline comments.Jul 19 2018, 5:35 PM
llvm/include/llvm/ADT/SmallVector.h
90

we were already assuming that there wouldn't be padding between FirstEl and InlineElts

BTW, I don't think we had to assuming that there wouldn't be padding. As long as there's enough otherwise-unused storage after FirstEl, we won't overflow the allocation.

rnk accepted this revision.Jul 23 2018, 11:41 AM

lgtm, I was hoping @rsmith would have a better suggestion, but we don't need to wait on it.

llvm/include/llvm/ADT/SmallVector.h
90

I think there are interesting differences between multiple inheritance and single inheritance, so I don't think this is an improvement over the simpler offsetof calculation that you have now.

This revision is now accepted and ready to land.Jul 23 2018, 11:41 AM
dexonsmith closed this revision.Jul 24 2018, 4:33 AM

Committed in r337820.