From 58085bdcabbba9a4711c6bde22a0ff5af6a00e40 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 30 Mar 2021 16:43:12 -0700 Subject: [PATCH] [StructLayout] Use TrailingObjects to allocate space for MemberOffsets. MemberOffsets are stored at the end of StructLayout. The class contains a single entry array to mark the start of the member offsets. getStructLayout calculates the additional space needed for additional elements before allocating memory. This patch converts this to use TrailingObjects. This simplifies the size computation in getStructLayout and gets rid of the single entry array. This is prep work, but to use TypeSize instead of uint64_t for D98169. The single entry array doesn't work with TypeSize because TypeSize doesn't have a default constructor. We thought this change was an improvement by itself so we've separated it out. Reviewed By: mehdi_amini Differential Revision: https://reviews.llvm.org/D99608 --- include/llvm/IR/DataLayout.h | 19 ++++++++++++++++--- lib/IR/DataLayout.cpp | 19 +++++++++---------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/include/llvm/IR/DataLayout.h b/include/llvm/IR/DataLayout.h index eae409e7529..80bb349d3e2 100644 --- a/include/llvm/IR/DataLayout.h +++ b/include/llvm/IR/DataLayout.h @@ -29,6 +29,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Alignment.h" +#include "llvm/Support/TrailingObjects.h" #include "llvm/Support/TypeSize.h" #include #include @@ -619,12 +620,11 @@ inline LLVMTargetDataRef wrap(const DataLayout *P) { /// Used to lazily calculate structure layout information for a target machine, /// based on the DataLayout structure. -class StructLayout { +class StructLayout final : public TrailingObjects { uint64_t StructSize; Align StructAlignment; unsigned IsPadded : 1; unsigned NumElements : 31; - uint64_t MemberOffsets[1]; // variable sized array! public: uint64_t getSizeInBytes() const { return StructSize; } @@ -641,9 +641,18 @@ public: /// index that contains it. unsigned getElementContainingOffset(uint64_t Offset) const; + MutableArrayRef getMemberOffsets() { + return llvm::makeMutableArrayRef(getTrailingObjects(), + NumElements); + } + + ArrayRef getMemberOffsets() const { + return llvm::makeArrayRef(getTrailingObjects(), NumElements); + } + uint64_t getElementOffset(unsigned Idx) const { assert(Idx < NumElements && "Invalid element idx!"); - return MemberOffsets[Idx]; + return getMemberOffsets()[Idx]; } uint64_t getElementOffsetInBits(unsigned Idx) const { @@ -654,6 +663,10 @@ private: friend class DataLayout; // Only DataLayout can create this class StructLayout(StructType *ST, const DataLayout &DL); + + size_t numTrailingObjects(OverloadToken) const { + return NumElements; + } }; // The implementation of this method is provided inline as it is particularly diff --git a/lib/IR/DataLayout.cpp b/lib/IR/DataLayout.cpp index 274ea0aa5fd..ecd74449dc3 100644 --- a/lib/IR/DataLayout.cpp +++ b/lib/IR/DataLayout.cpp @@ -64,7 +64,7 @@ StructLayout::StructLayout(StructType *ST, const DataLayout &DL) { // Keep track of maximum alignment constraint. StructAlignment = std::max(TyAlign, StructAlignment); - MemberOffsets[i] = StructSize; + getMemberOffsets()[i] = StructSize; // Consume space for this data item StructSize += DL.getTypeAllocSize(Ty).getFixedValue(); } @@ -80,13 +80,13 @@ StructLayout::StructLayout(StructType *ST, const DataLayout &DL) { /// getElementContainingOffset - Given a valid offset into the structure, /// return the structure index that contains it. unsigned StructLayout::getElementContainingOffset(uint64_t Offset) const { - const uint64_t *SI = - std::upper_bound(&MemberOffsets[0], &MemberOffsets[NumElements], Offset); - assert(SI != &MemberOffsets[0] && "Offset not in structure type!"); + ArrayRef MemberOffsets = getMemberOffsets(); + auto SI = llvm::upper_bound(MemberOffsets, Offset); + assert(SI != MemberOffsets.begin() && "Offset not in structure type!"); --SI; assert(*SI <= Offset && "upper_bound didn't work"); - assert((SI == &MemberOffsets[0] || *(SI-1) <= Offset) && - (SI+1 == &MemberOffsets[NumElements] || *(SI+1) > Offset) && + assert((SI == MemberOffsets.begin() || *(SI - 1) <= Offset) && + (SI + 1 == MemberOffsets.end() || *(SI + 1) > Offset) && "Upper bound didn't work!"); // Multiple fields can have the same offset if any of them are zero sized. @@ -94,7 +94,7 @@ unsigned StructLayout::getElementContainingOffset(uint64_t Offset) const { // at the i32 element, because it is the last element at that offset. This is // the right one to return, because anything after it will have a higher // offset, implying that this element is non-empty. - return SI-&MemberOffsets[0]; + return SI - MemberOffsets.begin(); } //===----------------------------------------------------------------------===// @@ -678,9 +678,8 @@ const StructLayout *DataLayout::getStructLayout(StructType *Ty) const { // Otherwise, create the struct layout. Because it is variable length, we // malloc it, then use placement new. - int NumElts = Ty->getNumElements(); - StructLayout *L = (StructLayout *) - safe_malloc(sizeof(StructLayout)+(NumElts-1) * sizeof(uint64_t)); + StructLayout *L = (StructLayout *)safe_malloc( + StructLayout::totalSizeToAlloc(Ty->getNumElements())); // Set SL before calling StructLayout's ctor. The ctor could cause other // entries to be added to TheMap, invalidating our reference.