llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Erich Keane (erichkeane)

<details>
<summary>Changes</summary>

Note: this is a pretty sizable change, and for that I apologize. Fortunately 
most of it is test changes, and the actual generation code is fairly managable. 
Unfortunately this couldn't really get any smaller, as the individual actual 
differences (unions, arrays, etc) all cascade.

The existing implementation of the ConstRecordBuilder mirrors the 
ConstStructBuilder from classic codegen. In both cases, this is a type that 
attempts to do a layout of the record/struct type in a byte-compatible way with 
the actual struct layout for the purposes of a constant.

This has a few problems:

First: it is another layout that we have to keep in sync with the main one.

Second: it adds an additional layer of complexity to the IR in a way that is 
mildly confusing.

Third: Most importantly, this attempts to be byte compatible, but NOT field 
compatible. This results in inconsistent field/padding/etc in the structs, so 
any time we access one via a member-wise GEP (rather than casting to i8, which 
we've been attempting to do!), we end up with mismatched GEPs, incorrect 
values, and in some cases, LLVM-IR Dialect verification errors (since doing a 
member-wise GEP will cause mismatched
    types).

For these reasons, I believe this to be the 'correct' way forward.

This DOES result in a handful of visible changes:
-Bitfields are represented as their storage type, which can make them
 seem odd.
-Arrays are no longer stored as a struct of values + zeroes. Arrays in CIR have 
'trailing zeros' as a concept, so this is unnecessary for CIR anyway.  These 
are unfortunately currently lowered to full-arrays in LLVM, so can result in 
massive 'zero' lists.  However #<!-- -->205918 intends to fix this.
-"Inline" constants are now promoted to private "global" constants more often. 
This is because of an optimization we have in LoweringPrepare which does this 
if it sees a constant immediately put in an alloca. This didn't happen 
previously, because we would have to Bitcast it, losing that ability.
-Fewer bitcasts: We lose a bunch of bitcasts because the types match now!

Note: This is a pretty sizable change, so I suspect we'll see a handful of 
regressions here on things that I missed as they don't have test coverage that 
reproduces them. I will likely need to be responding to these, so if you notice 
something like this, please let me know!

ONE such regression that I'm aware of is Flexible Array Members.  I have a 
patch in my local tree that fixes this, but it touches quite a bit of other 
stuff and makes this an even bigger patch, so I've left an NYI here. I'll do 
that as a followup after this is merged.

AI Disclosure: A few weeks ago I used Claude to generate #<!-- -->201430 which 
attempts to accomplish the same thing. When doing self-review on that, I found 
that it wasn't fit for task, and didn't accomplish what I wanted. Therefore, I 
implemented this from scratch myself, however, influenced by that patch at 
times. I also kept the tests from that implementation, as I found them useful 
to cover the cases I was concerned about.

---

Patch is 130.86 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/206137.diff


30 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp (+292-854) 
- (modified) clang/lib/CIR/CodeGen/CIRGenRecordLayout.h (+9) 
- (modified) clang/lib/CIR/Dialect/IR/CIRAttrs.cpp (+13) 
- (modified) clang/lib/CIR/Lowering/LoweringHelpers.cpp (+11) 
- (modified) clang/test/CIR/CodeGen/agg-expr-lvalue.c (+1-1) 
- (modified) clang/test/CIR/CodeGen/agg-init-constexpr.cpp (+8-5) 
- (added) clang/test/CIR/CodeGen/anonymous-nested-init.c (+36) 
- (modified) clang/test/CIR/CodeGen/array.cpp (+19-24) 
- (added) clang/test/CIR/CodeGen/bitfield-init-values.c (+28) 
- (modified) clang/test/CIR/CodeGen/bitfields.cpp (+10) 
- (modified) clang/test/CIR/CodeGen/const-array-floating-point.c (+6-6) 
- (modified) clang/test/CIR/CodeGen/constant-inits.cpp (+9-13) 
- (modified) clang/test/CIR/CodeGen/constexpr-ptr-offset.cpp (+13-4) 
- (added) clang/test/CIR/CodeGen/cross-reference-globals.c (+61) 
- (modified) clang/test/CIR/CodeGen/global-dtor-union-narrowed.cpp (+9-14) 
- (modified) clang/test/CIR/CodeGen/globals.cpp (+1-1) 
- (modified) clang/test/CIR/CodeGen/lambda.cpp (+2-2) 
- (modified) clang/test/CIR/CodeGen/paren-list-agg-init.cpp (+14-15) 
- (modified) clang/test/CIR/CodeGen/record-zero-init-padding.c (+16-16) 
- (modified) clang/test/CIR/CodeGen/replace-global.cpp (+5-6) 
- (modified) clang/test/CIR/CodeGen/self-ref-temporaries.cpp (+9-6) 
- (modified) clang/test/CIR/CodeGen/struct-init.cpp (+6-6) 
- (modified) clang/test/CIR/CodeGen/union-agg-init.c (+6-5) 
- (added) clang/test/CIR/CodeGenCXX/base-layout.cpp (+36) 
- (modified) clang/test/CIR/CodeGenCXX/global-refs.cpp (+11-6) 
- (modified) clang/test/CIR/CodeGenCXX/sizeof-pack.cpp (+1-1) 
- (modified) clang/test/CIR/CodeGenCXX/zero_init_bases.cpp (+5-4) 
- (modified) 
clang/test/CIR/CodeGenOpenACC/compute-reduction-clause-default-ops.c (+18-27) 
- (modified) clang/test/CIR/IR/invalid-const-record.cir (+29) 
- (modified) clang/test/CIR/Lowering/array.cpp (+1-1) 


``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index eddb00c6fb2c1..3747eecb5d1fb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -43,830 +43,334 @@ using namespace clang::CIRGen;
 
//===----------------------------------------------------------------------===//
 
 namespace {
-class ConstExprEmitter;
-
-static mlir::TypedAttr computePadding(CIRGenModule &cgm, CharUnits size) {
-  mlir::Type eltTy = cgm.uCharTy;
-  clang::CharUnits::QuantityType arSize = size.getQuantity();
-  CIRGenBuilderTy &bld = cgm.getBuilder();
-  if (size > CharUnits::One()) {
-    SmallVector<mlir::Attribute> elts(arSize, cir::ZeroAttr::get(eltTy));
-    return bld.getConstArray(mlir::ArrayAttr::get(bld.getContext(), elts),
-                             cir::ArrayType::get(eltTy, arSize));
-  }
-
-  return cir::ZeroAttr::get(eltTy);
-}
-
-static mlir::Attribute
-emitArrayConstant(CIRGenModule &cgm, mlir::Type desiredType,
-                  mlir::Type commonElementType, unsigned arrayBound,
-                  SmallVectorImpl<mlir::TypedAttr> &elements,
-                  mlir::TypedAttr filler);
-
-struct ConstantAggregateBuilderUtils {
-  CIRGenModule &cgm;
-  cir::CIRDataLayout dataLayout;
-
-  ConstantAggregateBuilderUtils(CIRGenModule &cgm)
-      : cgm(cgm), dataLayout{cgm.getModule()} {}
+namespace ConstRecordBuilder {
+// A class to manage the list of 'initializers' for building the record
+// initialization.  This abstracts out the APValue and the InitListExpr.
+class RecordBuilderInitList {
+  unsigned initIdx = 0;
+  bool isUnion = false;
+  std::variant<APValue, const InitListExpr *> value;
 
-  CharUnits getAlignment(const mlir::TypedAttr c) const {
-    return CharUnits::fromQuantity(
-        dataLayout.getAlignment(c.getType(), /*useABIAlign=*/true));
+  bool holdsExpr() const {
+    return std::holds_alternative<const InitListExpr *>(value);
   }
 
-  CharUnits getSize(mlir::Type ty) const {
-    return CharUnits::fromQuantity(dataLayout.getTypeAllocSize(ty));
+  const Expr *getExpr() {
+    assert(holdsExpr());
+    return std::get<const InitListExpr *>(value)->getInit(initIdx);
   }
 
-  CharUnits getSize(const mlir::TypedAttr c) const {
-    return getSize(c.getType());
+  mlir::Location getExprLoc(CIRGenModule &cgm) {
+    assert(holdsExpr());
+    return cgm.getLoc(std::get<const InitListExpr *>(value)->getBeginLoc());
   }
 
-  mlir::TypedAttr getPadding(CharUnits size) const {
-    return computePadding(cgm, size);
+  const APValue getAPVal() {
+    assert(!holdsExpr());
+    if (isUnion)
+      return std::get<APValue>(value).getUnionValue();
+    return std::get<APValue>(value).getStructField(initIdx);
   }
-};
-
-/// Incremental builder for an mlir::TypedAttr holding a record or array
-/// constant.
-class ConstantAggregateBuilder : private ConstantAggregateBuilderUtils {
-  struct Element {
-    Element(mlir::TypedAttr element, CharUnits offset)
-        : element(element), offset(offset) {}
-
-    mlir::TypedAttr element;
-    /// Describes the offset of `element` within the constant.
-    CharUnits offset;
-  };
-  /// The elements of the constant. The elements are kept in increasing offset
-  /// order, and we ensure that there is no overlap:
-  /// elements.offset[i+1] >= elements.offset[i] + getSize(elements.element[i])
-  ///
-  /// This may contain explicit padding elements (in order to create a
-  /// natural layout), but need not. Gaps between elements are implicitly
-  /// considered to be filled with undef.
-  llvm::SmallVector<Element, 32> elements;
-
-  /// The size of the constant (the maximum end offset of any added element).
-  /// May be larger than the end of elems.back() if we split the last element
-  /// and removed some trailing undefs.
-  CharUnits size = CharUnits::Zero();
-
-  /// This is true only if laying out elems in order as the elements of a
-  /// non-packed LLVM struct will give the correct layout.
-  bool naturalLayout = true;
-
-  bool split(size_t index, CharUnits hint);
-  std::optional<size_t> splitAt(CharUnits pos);
-
-  static mlir::Attribute buildFrom(CIRGenModule &cgm, ArrayRef<Element> elems,
-                                   CharUnits startOffset, CharUnits size,
-                                   bool naturalLayout, mlir::Type desiredTy,
-                                   bool allowOversized);
 
 public:
-  ConstantAggregateBuilder(CIRGenModule &cgm)
-      : ConstantAggregateBuilderUtils(cgm) {}
-
-  /// Update or overwrite the value starting at \p offset with \c c.
-  ///
-  /// \param allowOverwrite If \c true, this constant might overwrite (part of)
-  ///        a constant that has already been added. This flag is only used to
-  ///        detect bugs.
-  bool add(mlir::TypedAttr typedAttr, CharUnits offset, bool allowOverwrite);
-
-  /// Update or overwrite the bits starting at \p offsetInBits with \p bits.
-  bool addBits(llvm::APInt bits, uint64_t offsetInBits, bool allowOverwrite);
-
-  /// Attempt to condense the value starting at \p offset to a constant of type
-  /// \p desiredTy.
-  void condense(CharUnits offset, mlir::Type desiredTy);
-
-  /// Produce a constant representing the entire accumulated value, ideally of
-  /// the specified type. If \p allowOversized, the constant might be larger
-  /// than implied by \p desiredTy (eg, if there is a flexible array member).
-  /// Otherwise, the constant will be of exactly the same size as \p desiredTy
-  /// even if we can't represent it as that type.
-  mlir::Attribute build(mlir::Type desiredTy, bool allowOversized) const {
-    return buildFrom(cgm, elements, CharUnits::Zero(), size, naturalLayout,
-                     desiredTy, allowOversized);
+  RecordBuilderInitList(const RecordDecl *rd, APValue val)
+      : isUnion(rd->isUnion()), value(val) {}
+  RecordBuilderInitList(const RecordDecl *rd, const InitListExpr *ile)
+      : isUnion(rd->isUnion()), value(ile) {
+    assert(ile);
   }
-};
 
-template <typename Container, typename Range = std::initializer_list<
-                                  typename Container::value_type>>
-static void replace(Container &c, size_t beginOff, size_t endOff, Range vals) {
-  assert(beginOff <= endOff && "invalid replacement range");
-  llvm::replace(c, c.begin() + beginOff, c.begin() + endOff, vals);
-}
+  bool empty() const {
+    if (auto *const *ile = std::get_if<const InitListExpr *>(&value))
+      return initIdx >= (*ile)->getNumInits();
 
-bool ConstantAggregateBuilder::add(mlir::TypedAttr typedAttr, CharUnits offset,
-                                   bool allowOverwrite) {
-  // Common case: appending to a layout.
-  if (offset >= size) {
-    CharUnits align = getAlignment(typedAttr);
-    CharUnits alignedSize = size.alignTo(align);
-    if (alignedSize > offset || offset.alignTo(align) != offset) {
-      naturalLayout = false;
-    } else if (alignedSize < offset) {
-      elements.emplace_back(getPadding(offset - size), size);
-    }
-    elements.emplace_back(typedAttr, offset);
-    size = offset + getSize(typedAttr);
-    return true;
-  }
-
-  // Uncommon case: constant overlaps what we've already created.
-  std::optional<size_t> firstElemToReplace = splitAt(offset);
-  if (!firstElemToReplace)
-    return false;
+    // This branch is likely always true, but we guard against it being 'none'
+    // anyway.
+    if (isUnion)
+      return !std::get<APValue>(value).isUnion();
 
-  CharUnits cSize = getSize(typedAttr);
-  std::optional<size_t> lastElemToReplace = splitAt(offset + cSize);
-  if (!lastElemToReplace)
-    return false;
-
-  assert((firstElemToReplace == lastElemToReplace || allowOverwrite) &&
-         "unexpectedly overwriting field");
-
-  Element newElt(typedAttr, offset);
-  replace(elements, *firstElemToReplace, *lastElemToReplace, {newElt});
-  size = std::max(size, offset + cSize);
-  naturalLayout = false;
-  return true;
-}
-
-bool ConstantAggregateBuilder::addBits(llvm::APInt bits, uint64_t offsetInBits,
-                                       bool allowOverwrite) {
-  const ASTContext &astContext = cgm.getASTContext();
-  const uint64_t charWidth = astContext.getCharWidth();
-  mlir::Type charTy = cgm.getBuilder().getUIntNTy(charWidth);
-
-  // Offset of where we want the first bit to go within the bits of the
-  // current char.
-  unsigned offsetWithinChar = offsetInBits % charWidth;
-
-  // We split bit-fields up into individual bytes. Walk over the bytes and
-  // update them.
-  for (CharUnits offsetInChars =
-           astContext.toCharUnitsFromBits(offsetInBits - offsetWithinChar);
-       /**/; ++offsetInChars) {
-    // Number of bits we want to fill in this char.
-    unsigned wantedBits =
-        std::min((uint64_t)bits.getBitWidth(), charWidth - offsetWithinChar);
-
-    // Get a char containing the bits we want in the right places. The other
-    // bits have unspecified values.
-    llvm::APInt bitsThisChar = bits;
-    if (bitsThisChar.getBitWidth() < charWidth)
-      bitsThisChar = bitsThisChar.zext(charWidth);
-    if (cgm.getDataLayout().isBigEndian()) {
-      // Figure out how much to shift by. We may need to left-shift if we have
-      // less than one byte of Bits left.
-      int shift = bits.getBitWidth() - charWidth + offsetWithinChar;
-      if (shift > 0)
-        bitsThisChar.lshrInPlace(shift);
-      else if (shift < 0)
-        bitsThisChar = bitsThisChar.shl(-shift);
-    } else {
-      bitsThisChar = bitsThisChar.shl(offsetWithinChar);
-    }
-    if (bitsThisChar.getBitWidth() > charWidth)
-      bitsThisChar = bitsThisChar.trunc(charWidth);
-
-    if (wantedBits == charWidth) {
-      // Got a full byte: just add it directly.
-      add(cir::IntAttr::get(charTy, bitsThisChar), offsetInChars,
-          allowOverwrite);
-    } else {
-      // Partial byte: update the existing integer if there is one. If we
-      // can't split out a 1-CharUnit range to update, then we can't add
-      // these bits and fail the entire constant emission.
-      std::optional<size_t> firstElemToUpdate = splitAt(offsetInChars);
-      if (!firstElemToUpdate)
-        return false;
-      std::optional<size_t> lastElemToUpdate =
-          splitAt(offsetInChars + CharUnits::One());
-      if (!lastElemToUpdate)
-        return false;
-      assert(*lastElemToUpdate - *firstElemToUpdate < 2 &&
-             "should have at most one element covering one byte");
-
-      // Figure out which bits we want and discard the rest.
-      llvm::APInt updateMask(charWidth, 0);
-      if (cgm.getDataLayout().isBigEndian())
-        updateMask.setBits(charWidth - offsetWithinChar - wantedBits,
-                           charWidth - offsetWithinChar);
-      else
-        updateMask.setBits(offsetWithinChar, offsetWithinChar + wantedBits);
-      bitsThisChar &= updateMask;
-      bool isNull = false;
-      if (*firstElemToUpdate < elements.size()) {
-        auto firstEltToUpdate =
-            mlir::dyn_cast<cir::IntAttr>(elements[*firstElemToUpdate].element);
-        isNull = firstEltToUpdate && firstEltToUpdate.isNullValue();
-      }
-
-      if (*firstElemToUpdate == *lastElemToUpdate || isNull) {
-        // All existing bits are either zero or undef.
-        add(cir::IntAttr::get(charTy, bitsThisChar), offsetInChars,
-            /*allowOverwrite*/ true);
-      } else {
-        cir::IntAttr ci =
-            mlir::dyn_cast<cir::IntAttr>(elements[*firstElemToUpdate].element);
-        // In order to perform a partial update, we need the existing bitwise
-        // value, which we can only extract for a constant int.
-        if (!ci)
-          return false;
-        // Because this is a 1-CharUnit range, the constant occupying it must
-        // be exactly one CharUnit wide.
-        assert(ci.getBitWidth() == charWidth && "splitAt failed");
-        assert((!(ci.getValue() & updateMask) || allowOverwrite) &&
-               "unexpectedly overwriting bitfield");
-        bitsThisChar |= (ci.getValue() & ~updateMask);
-        elements[*firstElemToUpdate].element =
-            cir::IntAttr::get(charTy, bitsThisChar);
-      }
-    }
-
-    // Stop if we've added all the bits.
-    if (wantedBits == bits.getBitWidth())
-      break;
-
-    // Remove the consumed bits from Bits.
-    if (!cgm.getDataLayout().isBigEndian())
-      bits.lshrInPlace(wantedBits);
-    bits = bits.trunc(bits.getBitWidth() - wantedBits);
-
-    // The remaining bits go at the start of the following bytes.
-    offsetWithinChar = 0;
+    return initIdx >= std::get<APValue>(value).getStructNumFields();
   }
 
-  return true;
-}
-
-/// Returns a position within elements such that all elements
-/// before the returned index end before pos and all elements at or after
-/// the returned index begin at or after pos. Splits elements as necessary
-/// to ensure this. Returns std::nullopt if we find something we can't split.
-std::optional<size_t> ConstantAggregateBuilder::splitAt(CharUnits pos) {
-  if (pos >= size)
-    return elements.size();
-
-  while (true) {
-    // Find the first element that starts after pos.
-    Element *iter =
-        llvm::upper_bound(elements, pos, [](CharUnits pos, const Element &elt) 
{
-          return pos < elt.offset;
-        });
-
-    if (iter == elements.begin())
-      return 0;
-
-    size_t index = iter - elements.begin() - 1;
-    const Element &elt = elements[index];
-
-    // If we already have an element starting at pos, we're done.
-    if (elt.offset == pos)
-      return index;
-
-    // Check for overlap with the element that starts before pos.
-    CharUnits eltEnd = elt.offset + getSize(elt.element);
-    if (eltEnd <= pos)
-      return index + 1;
-
-    // Try to decompose it into smaller constants.
-    if (!split(index, pos))
-      return std::nullopt;
+  const FieldDecl *getActiveUnionField() const {
+    if (holdsExpr())
+      return std::get<const InitListExpr *>(value)
+          ->getInitializedFieldInUnion();
+    return std::get<APValue>(value).getUnionField();
   }
-}
 
-/// Split the constant at index, if possible. Return true if we did.
-/// Hint indicates the location at which we'd like to split, but may be
-/// ignored.
-bool ConstantAggregateBuilder::split(size_t index, CharUnits hint) {
-  cgm.errorNYI("split constant at index");
-  return false;
-}
+  // Return whether this is a field that should be skipped for one reason or
+  // another.
+  bool shouldSkip(const FieldDecl *fd) {
+    if (fd->isUnnamedBitField())
+      return true;
 
-void ConstantAggregateBuilder::condense(CharUnits offset,
-                                        mlir::Type desiredTy) {
-  CharUnits desiredSize = getSize(desiredTy);
+    if (holdsExpr() && isa_and_nonnull<NoInitExpr>(getExpr()))
+      return true;
 
-  std::optional<size_t> firstElemToReplace = splitAt(offset);
-  if (!firstElemToReplace)
-    return;
-  size_t first = *firstElemToReplace;
-
-  std::optional<size_t> lastElemToReplace = splitAt(offset + desiredSize);
-  if (!lastElemToReplace)
-    return;
-  size_t last = *lastElemToReplace;
-
-  size_t length = last - first;
-  if (length == 0)
-    return;
-
-  if (length == 1 && elements[first].offset == offset &&
-      getSize(elements[first].element) == desiredSize) {
-    cgm.errorNYI("re-wrapping single element records");
-    return;
+    return false;
   }
 
-  // Build a new constant from the elements in the range.
-  SmallVector<Element> subElems(elements.begin() + first,
-                                elements.begin() + last);
-  mlir::Attribute replacement =
-      buildFrom(cgm, subElems, offset, desiredSize,
-                /*naturalLayout=*/false, desiredTy, false);
-
-  // Replace the range with the condensed constant.
-  Element newElt(mlir::cast<mlir::TypedAttr>(replacement), offset);
-  replace(elements, first, last, {newElt});
-}
-
-mlir::Attribute
-ConstantAggregateBuilder::buildFrom(CIRGenModule &cgm, ArrayRef<Element> elems,
-                                    CharUnits startOffset, CharUnits size,
-                                    bool naturalLayout, mlir::Type desiredTy,
-                                    bool allowOversized) {
-  ConstantAggregateBuilderUtils utils(cgm);
-
-  if (elems.empty())
-    return cir::UndefAttr::get(desiredTy);
-
-  // If we want an array type, see if all the elements are the same type and
-  // appropriately spaced.
-  if (mlir::isa<cir::ArrayType>(desiredTy)) {
-    cgm.errorNYI("array aggregate constants");
-    return {};
+  // Advance the iterator on a 'skipped' field.  Note in the case of an
+  // init-list this doesn't advance if its an unnamed bitfield, as those aren't
+  // represented in the AST.
+  void advanceSkip(const FieldDecl *fd) {
+    assert(!isUnion);
+    if (holdsExpr())
+      if (fd->isUnnamedBitField())
+        return;
+    ++initIdx;
   }
+  // Advance the iterator on a 'normal' field, which always just increments the
+  // index.
+  void advance() {
+    assert(!isUnion);
+    ++initIdx;
+  }
+
+  APValue getBase(unsigned idx) {
+    // We could potentially handle this with init-list, but we just skip it
+    // because classic codegen does. If we decide to, we'll probably have to do
+    // something where we get through the init-list elements to make this work
+    // right (sub-init-list?).
+    assert(!holdsExpr());
 
-  // The size of the constant we plan to generate. This is usually just the 
size
-  // of the initialized type, but in AllowOversized mode (i.e. flexible array
-  // init), it can be larger.
-  CharUnits desiredSize = utils.getSize(desiredTy);
-  if (size > desiredSize) {
-    assert(allowOversized && "elems are oversized");
-    desiredSize = size;
+    return std::get<APValue>(value).getStructBase(idx);
   }
 
-  // The natural alignment of an unpacked CIR record with the given elements.
-  CharUnits align = CharUnits::One();
-  for (auto [e, offset] : elems)
-    align = std::max(align, utils.getAlignment(e));
-
-  // The natural size of an unpacked LLVM struct with the given elements.
-  CharUnits alignedSize = size.alignTo(align);
-
-  bool packed = false;
-  bool padded = false;
-
-  llvm::SmallVector<mlir::Attribute, 32> unpackedElems;
-  if (desiredSize < alignedSize || desiredSize.alignTo(align) != desiredSize) {
-    naturalLayout = false;
-    packed = true;
-  } else {
-    // The natural layout would be too small. Add padding to fix it. (This
-    // is ignored if we choose a packed layout.)
-    unpackedElems.reserve(elems.size() + 1);
-    llvm::transform(elems, std::back_inserter(unpackedElems),
-                    std::mem_fn(&Element::element));
-    if (desiredSize > alignedSize)
-      unpackedElems.push_back(utils.getPadding(desiredSize - size));
+  bool hasSideEffects(const ASTContext &ctx) {
+    if (holdsExpr() && getExpr()->HasSideEffects(ctx))
+      return true;
+    // APValue never has side effects.
+    return false;
   }
 
-  // If we don't have a natural layout, insert padding as necessary.
-  // As we go, double-check to see if we can actually just emit Elems
-  // as a non-packed record and do so opportunistically if possible.
-  llvm::SmallVector<mlir::Attribute, 32> packedElems;
-  packedElems.reserve(elems.size());
-  if (!naturalLayout) {
-    CharUnits sizeSoFar = CharUnits::Zero();
-    for (auto [element, offset] : elems) {
-      CharUnits align = utils.getAlignment(element);
-      CharUnits naturalOffset = sizeSoFar.alignTo(align);
-      CharUnits desiredOffset = offset - startOffset;
-      assert(desiredOffset >= sizeSoFar && "elements out of order");
-
-      if (desiredOffset != naturalOffset)
-        packed = true;
-      if (desiredOffset != sizeSoFar)
-        packedElems.push_back(utils.getPadding(desiredOffset - sizeSoFar));
-      packedElems.push_back(element);
-      sizeSoFar = desiredOffset + utils.getSize(element);
-    }
-    // If we're using the packed layout, pad it out to the desired size if
-    // necessary.
-    if (packed) {
-      assert(sizeSoFar <= desiredSize &&
-             "requested size is too small for contents");
-
-      if (sizeSoFar < desiredSize)
-        packedElems.push_back(utils.getPadding(desiredSize - sizeSoFar));
+  mlir::Attribute emit(ConstantEmitter &emitter, QualType fieldTy) {
+    if (holdsExpr()) {
+      const Expr *e = getExpr();
+      return e ? emitter.tryEmitPrivateForMemory(e, fieldTy)
+               : em...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/206137
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to