llvm-project
c48ce525 - [ADT] Add SmallVectorWithFlags with packed user flags

Commit
11 days ago
[ADT] Add SmallVectorWithFlags with packed user flags Structures that hold a SmallVector followed by a bool or a couple of flag bits pay up to eight bytes of padding for those bits, and there is no padding inside the vector to reuse: the header is exactly a pointer and two 32-bit fields, and the inline storage of pointer-sized elements is a multiple of eight bytes. SmallVectorWithFlags stores one to four user flag bits in the high bits of the capacity field, so it has the same size and inline capacity as SmallVector. The capacity field is the one header field not read on the hot path: the buffer pointer's free low bits depend on the element alignment and are read on every element access, and the size is read by size() and end(). Only capacity() masks the flags out, which costs one extra `and` in the growth check of push_back; begin(), end(), and size() are untouched. The cost is a maximum capacity divided by 2^FlagBits, which with the 32-bit size type and four flag bits is 268 million elements. The SmallVector implementation layers take a FlagBits template parameter. For zero flags, SmallVectorHeader aliases SmallVectorBase directly, preserving the unmasked storage and growth path. Only flagged vectors instantiate the masking header, avoiding an extra constructor and growth wrappers for ordinary SmallVector users. The out-of-line growth routines stay in SmallVectorBase and remain instantiated once per size type, with masked variants taking the capacity mask at run time. The extra template argument and detail::SmallVectorImplBase layer increase debug metadata. In an X86 clang RelWithDebInfo build with Clang 22.1.0, uncompressed .debug_info grows from 545,020,545 to 548,899,795 bytes (+0.71%). All 329 existing SmallVector and SmallVectorWithFlags tests pass. The trade-off versus a composed { SmallVector, uint8_t Flags } is that the flagged container is not a SmallVectorImpl<T>: use ArrayRef<T> for read-only interfaces and SmallVectorWithFlagsImpl<T, FlagBits> for output parameters. A flagged vector can be moved into a plain SmallVector<T, N>, dropping the flags, since the element algorithms never depend on the flag bits of the header. The flags are part of the vector's value. Element operations preserve them; copy, move, and swap transfer them along with the elements, also through SmallVectorWithFlagsImpl, and moving leaves the source flags unchanged. Constructors taking the flag mask before an iterator range or a vector to move from set them directly. Equality compares flags and elements, and ordering compares elements before flags. Comparison against ArrayRef is intentionally not provided; convert explicitly for an element-only comparison. The ProgrammersManual sentence suggesting SmallVectorHeader as a better name for SmallVectorImpl is removed, as that name is now taken by the header-selection alias. Assisted-by: Codex Assisted-by: Claude Code
Author
Committer
Parents
Loading