Skip to content

Commit 3bc2325

Browse files
gitoleglanza
authored andcommitted
[CIR][CodeGen][Lowering] Supports arrays with trailing zeros (#393)
This PR adds support for constant arrays with trailing zeros. The original `CodeGen` does the following: once a constant array contain trailing zeros, a struct with two members is generated: initialized elements and `zeroinitializer` for the remaining part. And depending on some conditions, `memset` or `memcpy` are emitted. In the latter case a global const array is created. Well, we may go this way, but it requires us to implement [features](https://github.com/llvm/clangir/blob/main/clang/lib/CIR/CodeGen/CIRGenDecl.cpp#L182) that are not implemented yet. Another option is to add one more parameter to the `constArrayAttr` and utilize it during the lowering. So far I chose this way, but if you have any doubts, we can discuss here. So we just emit constant array as usually and once there are trailing zeros, lower this arrray (i.e. an attribute) as a value. I added a couple of tests and will add more, once we agree on the approach. So far I marked the PR as a draft one.
1 parent 11ff613 commit 3bc2325

File tree

6 files changed

+92
-10
lines changed

6 files changed

+92
-10
lines changed

clang/include/clang/CIR/Dialect/IR/CIRAttrs.td

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,22 @@ def ConstArrayAttr : CIR_Attr<"ConstArray", "const_array", [TypedAttrInterface]>
116116
}];
117117

118118
let parameters = (ins AttributeSelfTypeParameter<"">:$type,
119-
"Attribute":$elts);
119+
"Attribute":$elts,
120+
"int":$trailingZerosNum);
120121

121122
// Define a custom builder for the type; that removes the need to pass
122123
// in an MLIRContext instance, as it can be infered from the `type`.
123124
let builders = [
124125
AttrBuilderWithInferredContext<(ins "mlir::cir::ArrayType":$type,
125126
"Attribute":$elts), [{
126-
return $_get(type.getContext(), type, elts);
127+
int zeros = 0;
128+
auto typeSize = type.cast<mlir::cir::ArrayType>().getSize();
129+
if (auto str = elts.dyn_cast<mlir::StringAttr>())
130+
zeros = typeSize - str.size();
131+
else
132+
zeros = typeSize - elts.cast<mlir::ArrayAttr>().size();
133+
134+
return $_get(type.getContext(), type, elts, zeros);
127135
}]>
128136
];
129137

@@ -132,6 +140,10 @@ def ConstArrayAttr : CIR_Attr<"ConstArray", "const_array", [TypedAttrInterface]>
132140

133141
// Enable verifier.
134142
let genVerifyDecl = 1;
143+
144+
let extraClassDeclaration = [{
145+
bool hasTrailingZeros() const { return getTrailingZerosNum() != 0; };
146+
}];
135147
}
136148

137149
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenExprConst.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,10 +959,18 @@ buildArrayConstant(CIRGenModule &CGM, mlir::Type DesiredType,
959959
// Add a zeroinitializer array filler if we have lots of trailing zeroes.
960960
unsigned TrailingZeroes = ArrayBound - NonzeroLength;
961961
if (TrailingZeroes >= 8) {
962-
assert(0 && "NYE");
963962
assert(Elements.size() >= NonzeroLength &&
964963
"missing initializer for non-zero element");
965964

965+
SmallVector<mlir::Attribute, 4> Eles;
966+
Eles.reserve(Elements.size());
967+
for (auto const &Element : Elements)
968+
Eles.push_back(Element);
969+
970+
return builder.getConstArray(
971+
mlir::ArrayAttr::get(builder.getContext(), Eles),
972+
mlir::cir::ArrayType::get(builder.getContext(), CommonElementType,
973+
ArrayBound));
966974
// TODO(cir): If all the elements had the same type up to the trailing
967975
// zeroes, emit a struct of two arrays (the nonzero data and the
968976
// zeroinitializer). Use DesiredType to get the element type.

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,7 +2295,7 @@ mlir::OpTrait::impl::verifySameFirstSecondOperandAndResultType(Operation *op) {
22952295

22962296
LogicalResult mlir::cir::ConstArrayAttr::verify(
22972297
::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError,
2298-
::mlir::Type type, Attribute attr) {
2298+
::mlir::Type type, Attribute attr, int trailingZerosNum) {
22992299

23002300
if (!(attr.isa<mlir::ArrayAttr>() || attr.isa<mlir::StringAttr>()))
23012301
return emitError() << "constant array expects ArrayAttr or StringAttr";
@@ -2318,7 +2318,7 @@ LogicalResult mlir::cir::ConstArrayAttr::verify(
23182318
auto at = type.cast<ArrayType>();
23192319

23202320
// Make sure both number of elements and subelement types match type.
2321-
if (at.getSize() != arrayAttr.size())
2321+
if (at.getSize() != arrayAttr.size() + trailingZerosNum)
23222322
return emitError() << "constant array size should match type size";
23232323
LogicalResult eltTypeCheck = success();
23242324
arrayAttr.walkImmediateSubElements(
@@ -2383,16 +2383,33 @@ ::mlir::Attribute ConstArrayAttr::parse(::mlir::AsmParser &parser,
23832383
}
23842384
}
23852385

2386+
auto zeros = 0;
2387+
if (parser.parseOptionalComma().succeeded()) {
2388+
if (parser.parseOptionalKeyword("trailing_zeros").succeeded()) {
2389+
auto typeSize = resultTy.value().cast<mlir::cir::ArrayType>().getSize();
2390+
auto elts = resultVal.value();
2391+
if (auto str = elts.dyn_cast<mlir::StringAttr>())
2392+
zeros = typeSize - str.size();
2393+
else
2394+
zeros = typeSize - elts.cast<mlir::ArrayAttr>().size();
2395+
} else {
2396+
return {};
2397+
}
2398+
}
2399+
23862400
// Parse literal '>'
23872401
if (parser.parseGreater())
23882402
return {};
2389-
return parser.getChecked<ConstArrayAttr>(loc, parser.getContext(),
2390-
resultTy.value(), resultVal.value());
2403+
2404+
return parser.getChecked<ConstArrayAttr>(
2405+
loc, parser.getContext(), resultTy.value(), resultVal.value(), zeros);
23912406
}
23922407

23932408
void ConstArrayAttr::print(::mlir::AsmPrinter &printer) const {
23942409
printer << "<";
23952410
printer.printStrippedAttrOrType(getElts());
2411+
if (auto zeros = getTrailingZerosNum())
2412+
printer << ", trailing_zeros";
23962413
printer << ">";
23972414
}
23982415

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,15 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
258258
const mlir::TypeConverter *converter) {
259259
auto llvmTy = converter->convertType(constArr.getType());
260260
auto loc = parentOp->getLoc();
261-
mlir::Value result = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmTy);
261+
mlir::Value result;
262+
263+
if (auto zeros = constArr.getTrailingZerosNum()) {
264+
auto arrayTy = constArr.getType();
265+
result = rewriter.create<mlir::cir::ZeroInitConstOp>(
266+
loc, converter->convertType(arrayTy));
267+
} else {
268+
result = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmTy);
269+
}
262270

263271
// Iteratively lower each constant element of the array.
264272
if (auto arrayAttr = constArr.getElts().dyn_cast<mlir::ArrayAttr>()) {
@@ -1069,6 +1077,15 @@ lowerConstArrayAttr(mlir::cir::ConstArrayAttr constArr,
10691077
return std::nullopt;
10701078
}
10711079

1080+
bool hasTrailingZeros(mlir::cir::ConstArrayAttr attr) {
1081+
auto array = attr.getElts().dyn_cast<mlir::ArrayAttr>();
1082+
return attr.hasTrailingZeros() ||
1083+
(array && std::count_if(array.begin(), array.end(), [](auto elt) {
1084+
auto ar = dyn_cast<mlir::cir::ConstArrayAttr>(elt);
1085+
return ar && hasTrailingZeros(ar);
1086+
}));
1087+
}
1088+
10721089
class CIRConstantLowering
10731090
: public mlir::OpConversionPattern<mlir::cir::ConstantOp> {
10741091
public:
@@ -1120,8 +1137,13 @@ class CIRConstantLowering
11201137
return op.emitError() << "array does not have a constant initializer";
11211138

11221139
std::optional<mlir::Attribute> denseAttr;
1123-
if (constArr &&
1124-
(denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {
1140+
if (constArr && hasTrailingZeros(constArr)) {
1141+
auto newOp =
1142+
lowerCirAttrAsValue(op, constArr, rewriter, getTypeConverter());
1143+
rewriter.replaceOp(op, newOp);
1144+
return mlir::success();
1145+
} else if (constArr &&
1146+
(denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {
11251147
attr = denseAttr.value();
11261148
} else {
11271149
auto initVal =
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s
2+
3+
void foo() {
4+
int a[10] = {1};
5+
}
6+
7+
// CHECK: cir.func {{.*@foo}}
8+
// CHECK: %0 = cir.alloca !cir.array<!s32i x 10>, cir.ptr <!cir.array<!s32i x 10>>, ["a"] {alignment = 16 : i64}
9+
// CHECK: %1 = cir.const(#cir.const_array<[#cir.int<1> : !s32i], trailing_zeros> : !cir.array<!s32i x 10>) : !cir.array<!s32i x 10>
10+
// CHECK: cir.store %1, %0 : !cir.array<!s32i x 10>, cir.ptr <!cir.array<!s32i x 10>>

clang/test/CIR/Lowering/const.cir

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,17 @@ module {
5454
// CHECK: llvm.store %8, %1 : !llvm.array<1 x struct<"struct.anon.1", (i32, i32)>>, !llvm.ptr
5555
// CHECK: llvm.return
5656

57+
cir.func @testArrWithTrailingZeros() {
58+
%0 = cir.alloca !cir.array<!s32i x 10>, cir.ptr <!cir.array<!s32i x 10>>, ["a"] {alignment = 16 : i64}
59+
%1 = cir.const(#cir.const_array<[#cir.int<1> : !s32i], trailing_zeros> : !cir.array<!s32i x 10>) : !cir.array<!s32i x 10>
60+
cir.store %1, %0 : !cir.array<!s32i x 10>, cir.ptr <!cir.array<!s32i x 10>>
61+
cir.return
62+
}
63+
// CHECK: llvm.func @testArrWithTrailingZeros()
64+
// CHECK: %0 = llvm.mlir.constant(1 : index) : i64
65+
// CHECK: %1 = llvm.alloca %0 x !llvm.array<10 x i32> {alignment = 16 : i64} : (i64) -> !llvm.ptr
66+
// CHECK: %2 = cir.llvmir.zeroinit : !llvm.array<10 x i32>
67+
// CHECK: %3 = llvm.mlir.constant(1 : i32) : i32
68+
// CHECK: %4 = llvm.insertvalue %3, %2[0] : !llvm.array<10 x i32>
69+
5770
}

0 commit comments

Comments
 (0)