================
@@ -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