diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 90b1660577f9..c0f8501b10f6 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -116,14 +116,22 @@ def ConstArrayAttr : CIR_Attr<"ConstArray", "const_array", [TypedAttrInterface]> }]; let parameters = (ins AttributeSelfTypeParameter<"">:$type, - "Attribute":$elts); + "Attribute":$elts, + "int":$trailingZerosNum); // Define a custom builder for the type; that removes the need to pass // in an MLIRContext instance, as it can be infered from the `type`. let builders = [ AttrBuilderWithInferredContext<(ins "mlir::cir::ArrayType":$type, "Attribute":$elts), [{ - return $_get(type.getContext(), type, elts); + int zeros = 0; + auto typeSize = type.cast().getSize(); + if (auto str = elts.dyn_cast()) + zeros = typeSize - str.size(); + else + zeros = typeSize - elts.cast().size(); + + return $_get(type.getContext(), type, elts, zeros); }]> ]; @@ -132,6 +140,10 @@ def ConstArrayAttr : CIR_Attr<"ConstArray", "const_array", [TypedAttrInterface]> // Enable verifier. let genVerifyDecl = 1; + + let extraClassDeclaration = [{ + bool hasTrailingZeros() const { return getTrailingZerosNum() != 0; }; + }]; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp index bfd5f4bd50ce..2f4bc5f55835 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp @@ -956,10 +956,18 @@ buildArrayConstant(CIRGenModule &CGM, mlir::Type DesiredType, // Add a zeroinitializer array filler if we have lots of trailing zeroes. unsigned TrailingZeroes = ArrayBound - NonzeroLength; if (TrailingZeroes >= 8) { - assert(0 && "NYE"); assert(Elements.size() >= NonzeroLength && "missing initializer for non-zero element"); + SmallVector Eles; + Eles.reserve(Elements.size()); + for (auto const &Element : Elements) + Eles.push_back(Element); + + return builder.getConstArray( + mlir::ArrayAttr::get(builder.getContext(), Eles), + mlir::cir::ArrayType::get(builder.getContext(), CommonElementType, + ArrayBound)); // TODO(cir): If all the elements had the same type up to the trailing // zeroes, emit a struct of two arrays (the nonzero data and the // zeroinitializer). Use DesiredType to get the element type. diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index a5ac89d45b9f..f69e15cc21db 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2295,7 +2295,7 @@ mlir::OpTrait::impl::verifySameFirstSecondOperandAndResultType(Operation *op) { LogicalResult mlir::cir::ConstArrayAttr::verify( ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError, - ::mlir::Type type, Attribute attr) { + ::mlir::Type type, Attribute attr, int trailingZerosNum) { if (!(attr.isa() || attr.isa())) return emitError() << "constant array expects ArrayAttr or StringAttr"; @@ -2318,7 +2318,7 @@ LogicalResult mlir::cir::ConstArrayAttr::verify( auto at = type.cast(); // Make sure both number of elements and subelement types match type. - if (at.getSize() != arrayAttr.size()) + if (at.getSize() != arrayAttr.size() + trailingZerosNum) return emitError() << "constant array size should match type size"; LogicalResult eltTypeCheck = success(); arrayAttr.walkImmediateSubElements( @@ -2383,16 +2383,33 @@ ::mlir::Attribute ConstArrayAttr::parse(::mlir::AsmParser &parser, } } + auto zeros = 0; + if (parser.parseOptionalComma().succeeded()) { + if (parser.parseOptionalKeyword("trailing_zeros").succeeded()) { + auto typeSize = resultTy.value().cast().getSize(); + auto elts = resultVal.value(); + if (auto str = elts.dyn_cast()) + zeros = typeSize - str.size(); + else + zeros = typeSize - elts.cast().size(); + } else { + return {}; + } + } + // Parse literal '>' if (parser.parseGreater()) return {}; - return parser.getChecked(loc, parser.getContext(), - resultTy.value(), resultVal.value()); + + return parser.getChecked( + loc, parser.getContext(), resultTy.value(), resultVal.value(), zeros); } void ConstArrayAttr::print(::mlir::AsmPrinter &printer) const { printer << "<"; printer.printStrippedAttrOrType(getElts()); + if (auto zeros = getTrailingZerosNum()) + printer << ", trailing_zeros"; printer << ">"; } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3bfbc15c7e69..fd6bf0e092c4 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -258,7 +258,15 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, const mlir::TypeConverter *converter) { auto llvmTy = converter->convertType(constArr.getType()); auto loc = parentOp->getLoc(); - mlir::Value result = rewriter.create(loc, llvmTy); + mlir::Value result; + + if (auto zeros = constArr.getTrailingZerosNum()) { + auto arrayTy = constArr.getType(); + result = rewriter.create( + loc, converter->convertType(arrayTy)); + } else { + result = rewriter.create(loc, llvmTy); + } // Iteratively lower each constant element of the array. if (auto arrayAttr = constArr.getElts().dyn_cast()) { @@ -1068,6 +1076,15 @@ lowerConstArrayAttr(mlir::cir::ConstArrayAttr constArr, return std::nullopt; } +bool hasTrailingZeros(mlir::cir::ConstArrayAttr attr) { + auto array = attr.getElts().dyn_cast(); + return attr.hasTrailingZeros() || + (array && std::count_if(array.begin(), array.end(), [](auto elt) { + auto ar = dyn_cast(elt); + return ar && hasTrailingZeros(ar); + })); +} + class CIRConstantLowering : public mlir::OpConversionPattern { public: @@ -1119,8 +1136,13 @@ class CIRConstantLowering return op.emitError() << "array does not have a constant initializer"; std::optional denseAttr; - if (constArr && - (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) { + if (constArr && hasTrailingZeros(constArr)) { + auto newOp = + lowerCirAttrAsValue(op, constArr, rewriter, getTypeConverter()); + rewriter.replaceOp(op, newOp); + return mlir::success(); + } else if (constArr && + (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) { attr = denseAttr.value(); } else { auto initVal = diff --git a/clang/test/CIR/CodeGen/const-array.c b/clang/test/CIR/CodeGen/const-array.c new file mode 100644 index 000000000000..c75ba59b8f17 --- /dev/null +++ b/clang/test/CIR/CodeGen/const-array.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s + +void foo() { + int a[10] = {1}; +} + +// CHECK: cir.func {{.*@foo}} +// CHECK: %0 = cir.alloca !cir.array, cir.ptr >, ["a"] {alignment = 16 : i64} +// CHECK: %1 = cir.const(#cir.const_array<[#cir.int<1> : !s32i], trailing_zeros> : !cir.array) : !cir.array +// CHECK: cir.store %1, %0 : !cir.array, cir.ptr > diff --git a/clang/test/CIR/Lowering/const.cir b/clang/test/CIR/Lowering/const.cir index 7d0c63f8ccbb..46b4677d40b4 100644 --- a/clang/test/CIR/Lowering/const.cir +++ b/clang/test/CIR/Lowering/const.cir @@ -54,4 +54,17 @@ module { // CHECK: llvm.store %8, %1 : !llvm.array<1 x struct<"struct.anon.1", (i32, i32)>>, !llvm.ptr // CHECK: llvm.return + cir.func @testArrWithTrailingZeros() { + %0 = cir.alloca !cir.array, cir.ptr >, ["a"] {alignment = 16 : i64} + %1 = cir.const(#cir.const_array<[#cir.int<1> : !s32i], trailing_zeros> : !cir.array) : !cir.array + cir.store %1, %0 : !cir.array, cir.ptr > + cir.return + } + // CHECK: llvm.func @testArrWithTrailingZeros() + // CHECK: %0 = llvm.mlir.constant(1 : index) : i64 + // CHECK: %1 = llvm.alloca %0 x !llvm.array<10 x i32> {alignment = 16 : i64} : (i64) -> !llvm.ptr + // CHECK: %2 = cir.llvmir.zeroinit : !llvm.array<10 x i32> + // CHECK: %3 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %4 = llvm.insertvalue %3, %2[0] : !llvm.array<10 x i32> + }