This is an archive of the discontinued LLVM Phabricator instance.

[ADT] Use Empty Base Optimization for Allocators
ClosedPublic

Authored by njames93 on Jul 6 2022, 7:43 AM.

Details

Summary

In D94439, BumpPtrAllocator changed its implementation to use an empty base optimization for the underlying allocator.
This patch builds on that by extending its functionality to more classes as well as enabling the underlying allocator to be a reference type, something not currently possible as you can't derive from a reference.

The main place this sees use is in StringMaps which often use the default MallocAllocator, yet have to pay the size of a pointer for no reason.

Diff Detail

Event Timeline

njames93 created this revision.Jul 6 2022, 7:43 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 6 2022, 7:43 AM
njames93 requested review of this revision.Jul 6 2022, 7:43 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 6 2022, 7:43 AM

Got some testing for this? Perhaps some static_asserts in the unit test class that demonstrates the smaller size? (specifically, I thought the EBO only applied to the first base class or something like that, so the StringMap case where the allocator is the second base I'm not sure would correctly trigger EBO?)

llvm/include/llvm/ADT/ScopedHashTable.h
178–179

Are these casts necessary? Looks like the conversion is implicit/would work without the casts?

Got some testing for this? Perhaps some static_asserts in the unit test class that demonstrates the smaller size? (specifically, I thought the EBO only applied to the first base class or something like that, so the StringMap case where the allocator is the second base I'm not sure would correctly trigger EBO?)

The standard places no such restriction and clang(on a 64 bit build) currently determines StringMap to be 32 bytes, after this patch it drops to 24 bytes.

llvm/include/llvm/ADT/ScopedHashTable.h
178–179

These may be, but I definitely had some issues building where some of the casts I've added resulted in failed builds.

njames93 updated this revision to Diff 442789.Jul 6 2022, 11:31 PM

Add a static assert to verify smaller size.

dblaikie added inline comments.Jul 7 2022, 11:34 AM
llvm/include/llvm/Support/AllocatorBase.h
102–136

Could this be a bit simpler if it were an explicit allocator holder, rather than a wrapper (that still ends up needing the conversion operators anyway)?

template<typename Alloc> class AllocatorHolder: Alloc {
public:
  AllocatorHolder(const Alloc &A) : Alloc(A) { }
  Alloc &getAllocator() { return *this; }
  const Alloc &getAllocator() { return *this; }
};
template<typename Alloc> class AllocatorHolder<Alloc&> {
  Alloc &A;
public:
  AllocatorHolder(const Alloc &A) : A(A) { }
  Alloc &getAllocator() { return *this; }
  const Alloc &getAllocator() { return *this; }
};
njames93 updated this revision to Diff 443778.Jul 11 2022, 3:48 PM

Reimplement using AllocatorHolder as per suggestion.

dblaikie accepted this revision.Jul 11 2022, 5:08 PM

Looks good, thanks!

This revision is now accepted and ready to land.Jul 11 2022, 5:08 PM
njames93 updated this revision to Diff 444056.Jul 12 2022, 1:08 PM

Add a move constructor to AllocatorHolder<> to fix broken build.

This revision was automatically updated to reflect the committed changes.

This broke building lldb with GCC 9:

In file included from ../tools/lldb/include/lldb/Host/Host.h:14,
                 from ../tools/lldb/source/Host/common/File.cpp:28:
../tools/lldb/include/lldb/Utility/Environment.h: In copy constructor ‘lldb_private::Environment::Environment(const lldb_private::Environment&)’:
../tools/lldb/include/lldb/Utility/Environment.h:60:49: error: call of overloaded ‘StringMap(const lldb_private::Environment&)’ is ambiguous
   60 |   Environment(const Environment &RHS) : Base(RHS) {}
      |                                                 ^
In file included from ../include/llvm/Support/YAMLTraits.h:16,
                 from ../tools/lldb/include/lldb/Utility/ConstString.h:15,
                 from ../tools/lldb/include/lldb/Utility/FileSpec.h:15,
                 from ../tools/lldb/include/lldb/Host/FileSystem.h:14,
                 from ../tools/lldb/source/Host/common/File.cpp:27:
../include/llvm/ADT/StringMap.h:137:3: note: candidate: ‘llvm::StringMap<ValueTy, AllocatorTy>::StringMap(const llvm::StringMap<ValueTy, AllocatorTy>&) [with ValueTy = std::__cxx11::basic_string<char>; AllocatorTy = llvm::MallocAllocator]’
  137 |   StringMap(const StringMap &RHS)
      |   ^~~~~~~~~
../include/llvm/ADT/StringMap.h:122:12: note: candidate: ‘llvm::StringMap<ValueTy, AllocatorTy>::StringMap(AllocatorTy) [with ValueTy = std::__cxx11::basic_string<char>; AllocatorTy = llvm::MallocAllocator]’
  122 |   explicit StringMap(AllocatorTy A)
      |            ^~~~~~~~~

This broke building lldb with GCC 9:

I pushed a fix for this in 306fc2cd87f2a52c21eb3606eff33d78e25d9368.

This broke building lldb with GCC 9:

I pushed a fix for this in 306fc2cd87f2a52c21eb3606eff33d78e25d9368.

Thanks for the speedy fix, I didn't even have a failing buildbot message for this bug 🙃

This broke building lldb with GCC 9:

I pushed a fix for this in 306fc2cd87f2a52c21eb3606eff33d78e25d9368.

Thanks for the speedy fix, I didn't even have a failing buildbot message for this bug 🙃

FWIW, I don’t think we’re actually have any buildbots that built lldb with gcc (but I guess it would good to have one).