================
@@ -21,20 +20,571 @@
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
-#include "clang/Basic/Specifiers.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "clang/CIR/MissingFeatures.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/Sequence.h"
 #include "llvm/Support/ErrorHandling.h"
+#include <iterator>
 
 using namespace clang;
 using namespace clang::CIRGen;
 
+//===----------------------------------------------------------------------===//
+//                            ConstantAggregateBuilder
+//===----------------------------------------------------------------------===//
+
+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, 4> 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()} {}
+
+  CharUnits getAlignment(const mlir::TypedAttr c) const {
+    return CharUnits::fromQuantity(
+        dataLayout.getAlignment(c.getType(), /*abiOrPref=*/true));
+  }
+
+  CharUnits getSize(mlir::Type ty) const {
+    return CharUnits::fromQuantity(dataLayout.getTypeAllocSize(ty));
+  }
+
+  CharUnits getSize(const mlir::TypedAttr c) const {
+    return getSize(c.getType());
+  }
+
+  mlir::TypedAttr getPadding(CharUnits size) const {
+    return computePadding(cgm, size);
+  }
+};
+
+/// Incremental builder for an mlir::TypedAttr holding a record or array
+/// constant.
+class ConstantAggregateBuilder : private ConstantAggregateBuilderUtils {
+  /// The elements of the constant. These two arrays must have the same size;
+  /// Offsets[i] describes the offset of Elems[i] within the constant. The
+  /// elements are kept in increasing offset order, and we ensure that there
+  /// is no overlap: Offsets[i+1] >= Offsets[i] + getSize(Elemes[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<mlir::TypedAttr, 32> elems;
+  llvm::SmallVector<CharUnits, 32> offsets;
+
+  /// 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;
+
+  std::optional<size_t> splitAt(CharUnits pos);
+
+  static mlir::Attribute
+  buildFrom(CIRGenModule &cgm, ArrayRef<mlir::TypedAttr> elems,
+            ArrayRef<CharUnits> offsets, 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);
+
+  /// 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, elems, offsets, CharUnits::Zero(), size,
+                     naturalLayout, desiredTy, allowOversized);
+  }
+};
+
+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 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) {
+      elems.push_back(getPadding(offset - size));
+      offsets.push_back(size);
+    }
+    elems.push_back(typedAttr);
+    offsets.push_back(offset);
+    size = offset + getSize(typedAttr);
+    return true;
+  }
+
+  // Uncommon case: constant overlaps what we've already created.
----------------
andykaylor wrote:

Maybe refactor all of the "uncommon" handling into a separate PR?

https://github.com/llvm/llvm-project/pull/155663
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to