================
@@ -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())
----------------
erichkeane wrote:

Because my brain actually broke while writing this and got myself caught up 
trying to Demorgan the nonsense I was coming up with, and gave up :D  Fixed.

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