[StructLayout] Use TrailingObjects to allocate space for MemberOffsets.
authorCraig Topper <craig.topper@sifive.com>
Tue, 30 Mar 2021 23:43:12 +0000 (16:43 -0700)
committerCraig Topper <craig.topper@sifive.com>
Wed, 31 Mar 2021 00:36:50 +0000 (17:36 -0700)
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

llvm/include/llvm/IR/DataLayout.h
llvm/lib/IR/DataLayout.cpp

index eae409e..80bb349 100644 (file)
@@ -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 <cassert>
 #include <cstdint>
@@ -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<StructLayout, uint64_t> {
   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<uint64_t> getMemberOffsets() {
+    return llvm::makeMutableArrayRef(getTrailingObjects<uint64_t>(),
+                                     NumElements);
+  }
+
+  ArrayRef<uint64_t> getMemberOffsets() const {
+    return llvm::makeArrayRef(getTrailingObjects<uint64_t>(), 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<uint64_t>) const {
+    return NumElements;
+  }
 };
 
 // The implementation of this method is provided inline as it is particularly
index 274ea0a..ecd7444 100644 (file)
@@ -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<uint64_t> 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<uint64_t>(Ty->getNumElements()));
 
   // Set SL before calling StructLayout's ctor.  The ctor could cause other
   // entries to be added to TheMap, invalidating our reference.