================ @@ -21,20 +20,526 @@ #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; + + 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. + cgm.errorNYI("overlapping constants"); + return false; +} + +mlir::Attribute ConstantAggregateBuilder::buildFrom( + CIRGenModule &cgm, ArrayRef<mlir::TypedAttr> elems, + ArrayRef<CharUnits> offsets, CharUnits startOffset, CharUnits size, + bool naturalLayout, mlir::Type desiredTy, bool allowOversized) { + ConstantAggregateBuilderUtils utils(cgm); + + if (elems.empty()) + return cir::UndefAttr::get(desiredTy); + + auto offset = [&](size_t i) { return offsets[i] - startOffset; }; + + // 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 {}; + } + + // 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; + } + + // The natural alignment of an unpacked CIR record with the given elements. + CharUnits align = CharUnits::One(); + for (mlir::TypedAttr e : 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; + ArrayRef<mlir::TypedAttr> unpackedElems = elems; + + llvm::SmallVector<mlir::TypedAttr, 32> unpackedElemStorage; ---------------- andykaylor wrote:
```suggestion llvm::SmallVector<mlir::TypedAttr> unpackedElemStorage; ``` maybe? I think using 32 here will yield about double the default size, so maybe that's been thought through. 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