Skip to content

Commit 34f59a3

Browse files
committed
[mlir][emitc] Add ArrayType (llvm#83386)
This models a one or multi-dimensional C/C++ array. The type implements the `ShapedTypeInterface` and prints similar to memref/tensor: ``` %arg0: !emitc.array<1xf32>, %arg1: !emitc.array<10x20x30xi32>, %arg2: !emitc.array<30x!emitc.ptr<i32>>, %arg3: !emitc.array<30x!emitc.opaque<"int">> ``` It can be translated to a C array type when used as function parameter or as `emitc.variable` type.
1 parent 86a976b commit 34f59a3

File tree

11 files changed

+149
-30
lines changed

11 files changed

+149
-30
lines changed

mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def EmitC_ArrayType : EmitC_Type<"Array", "array", [ShapedTypeInterface]> {
6060
/// Returns if this type is ranked (always true).
6161
bool hasRank() const { return true; }
6262

63-
/// Clone this vector type with the given shape and element type. If the
63+
/// Clone this array type with the given shape and element type. If the
6464
/// provided shape is `std::nullopt`, the current shape of the type is used.
6565
ArrayType cloneWith(std::optional<ArrayRef<int64_t>> shape,
6666
Type elementType) const;

mlir/lib/Dialect/EmitC/IR/EmitC.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ LogicalResult emitc::AssignOp::verify() {
142142
return emitOpError() << "requires value's type (" << value.getType()
143143
<< ") to match variable's type (" << variable.getType()
144144
<< ")";
145+
if (isa<ArrayType>(variable.getType()))
146+
return emitOpError() << "cannot assign to array type";
145147
return success();
146148
}
147149

@@ -193,6 +195,11 @@ LogicalResult emitc::CallOpaqueOp::verify() {
193195
}
194196
}
195197

198+
if (llvm::any_of(getResultTypes(),
199+
[](Type type) { return isa<ArrayType>(type); })) {
200+
return emitOpError() << "cannot return array type";
201+
}
202+
196203
return success();
197204
}
198205

@@ -457,6 +464,9 @@ LogicalResult FuncOp::verify() {
457464
return emitOpError("requires zero or exactly one result, but has ")
458465
<< getNumResults();
459466

467+
if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))
468+
return emitOpError("cannot return array type");
469+
460470
return success();
461471
}
462472

@@ -796,7 +806,7 @@ Type emitc::ArrayType::parse(AsmParser &parser) {
796806
if (parser.parseType(elementType))
797807
return Type();
798808

799-
// Check that memref is formed from allowed types.
809+
// Check that array is formed from allowed types.
800810
if (!isValidElementType(elementType))
801811
return parser.emitError(typeLoc, "invalid array element type"), Type();
802812
if (parser.parseGreater())
@@ -819,8 +829,8 @@ LogicalResult emitc::ArrayType::verify(
819829
if (shape.empty())
820830
return emitError() << "shape must not be empty";
821831

822-
for (auto d : shape) {
823-
if (d <= 0)
832+
for (int64_t dim : shape) {
833+
if (dim <= 0)
824834
return emitError() << "dimensions must have positive size";
825835
}
826836

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -881,15 +881,11 @@ static LogicalResult printFunctionArgs(CppEmitter &emitter,
881881
Region::BlockArgListType arguments) {
882882
raw_indented_ostream &os = emitter.ostream();
883883

884-
if (failed(interleaveCommaWithError(arguments, os,
885-
[&](BlockArgument arg) -> LogicalResult {
886-
return emitter.emitVariableDeclaration(
887-
functionOp->getLoc(), arg.getType(),
888-
emitter.getOrCreateName(arg));
889-
})))
890-
return failure();
891-
892-
return success();
884+
return (interleaveCommaWithError(
885+
arguments, os, [&](BlockArgument arg) -> LogicalResult {
886+
return emitter.emitVariableDeclaration(
887+
functionOp->getLoc(), arg.getType(), emitter.getOrCreateName(arg));
888+
}));
893889
}
894890

895891
static LogicalResult printFunctionBody(CppEmitter &emitter,
@@ -932,6 +928,9 @@ static LogicalResult printFunctionBody(CppEmitter &emitter,
932928
if (emitter.hasValueInScope(arg))
933929
return functionOp->emitOpError(" block argument #")
934930
<< arg.getArgNumber() << " is out of scope";
931+
if (isa<ArrayType>(arg.getType()))
932+
return functionOp->emitOpError("cannot emit block argument #")
933+
<< arg.getArgNumber() << " with array type";
935934
if (failed(
936935
emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) {
937936
return failure();
@@ -975,6 +974,11 @@ static LogicalResult printOperation(CppEmitter &emitter,
975974
"with multiple blocks needs variables declared at top");
976975
}
977976

977+
if (llvm::any_of(functionOp.getResultTypes(),
978+
[](Type type) { return isa<ArrayType>(type); })) {
979+
return functionOp.emitOpError() << "cannot emit array type as result type";
980+
}
981+
978982
CppEmitter::Scope scope(emitter);
979983
raw_indented_ostream &os = emitter.ostream();
980984
if (failed(emitter.emitTypes(functionOp.getLoc(),
@@ -1489,6 +1493,8 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) {
14891493
if (!tType.hasStaticShape())
14901494
return emitError(loc, "cannot emit tensor type with non static shape");
14911495
os << "Tensor<";
1496+
if (isa<ArrayType>(tType.getElementType()))
1497+
return emitError(loc, "cannot emit tensor of array type ") << type;
14921498
if (failed(emitType(loc, tType.getElementType())))
14931499
return failure();
14941500
auto shape = tType.getShape();
@@ -1505,7 +1511,16 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) {
15051511
os << oType.getValue();
15061512
return success();
15071513
}
1514+
if (auto aType = dyn_cast<emitc::ArrayType>(type)) {
1515+
if (failed(emitType(loc, aType.getElementType())))
1516+
return failure();
1517+
for (auto dim : aType.getShape())
1518+
os << "[" << dim << "]";
1519+
return success();
1520+
}
15081521
if (auto pType = dyn_cast<emitc::PointerType>(type)) {
1522+
if (isa<ArrayType>(pType.getPointee()))
1523+
return emitError(loc, "cannot emit pointer to array type ") << type;
15091524
if (failed(emitType(loc, pType.getPointee())))
15101525
return failure();
15111526
os << "*";
@@ -1527,6 +1542,9 @@ LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef<Type> types) {
15271542
}
15281543

15291544
LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef<Type> types) {
1545+
if (llvm::any_of(types, [](Type type) { return isa<ArrayType>(type); })) {
1546+
return emitError(loc, "cannot emit tuple of array type");
1547+
}
15301548
os << "std::tuple<";
15311549
if (failed(interleaveCommaWithError(
15321550
types, os, [&](Type type) { return emitType(loc, type); })))

mlir/test/Dialect/EmitC/invalid_ops.mlir

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ func.func @dense_template_argument(%arg : i32) {
8080

8181
// -----
8282

83+
func.func @array_result() {
84+
// expected-error @+1 {{'emitc.call_opaque' op cannot return array type}}
85+
emitc.call_opaque "array_result"() : () -> !emitc.array<4xi32>
86+
return
87+
}
88+
89+
// -----
90+
8391
func.func @empty_operator(%arg : i32) {
8492
// expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}}
8593
%2 = emitc.apply ""(%arg) : (i32) -> !emitc.ptr<i32>
@@ -129,6 +137,14 @@ func.func @cast_tensor(%arg : tensor<f32>) {
129137

130138
// -----
131139

140+
func.func @cast_array(%arg : !emitc.array<4xf32>) {
141+
// expected-error @+1 {{'emitc.cast' op operand type '!emitc.array<4xf32>' and result type '!emitc.array<4xf32>' are cast incompatible}}
142+
%1 = emitc.cast %arg: !emitc.array<4xf32> to !emitc.array<4xf32>
143+
return
144+
}
145+
146+
// -----
147+
132148
func.func @add_two_pointers(%arg0: !emitc.ptr<f32>, %arg1: !emitc.ptr<f32>) {
133149
// expected-error @+1 {{'emitc.add' op requires that at most one operand is a pointer}}
134150
%1 = "emitc.add" (%arg0, %arg1) : (!emitc.ptr<f32>, !emitc.ptr<f32>) -> !emitc.ptr<f32>
@@ -235,9 +251,10 @@ func.func @test_assign_type_mismatch(%arg1: f32) {
235251

236252
// -----
237253

238-
func.func @test_subscript_indices_mismatch(%arg0: !emitc.array<4x8xf32>, %arg2: index) {
239-
// expected-error @+1 {{'emitc.subscript' op requires number of indices (1) to match the rank of the array type (2)}}
240-
%0 = emitc.subscript %arg0[%arg2] : <4x8xf32>
254+
func.func @test_assign_to_array(%arg1: !emitc.array<4xi32>) {
255+
%v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4xi32>
256+
// expected-error @+1 {{'emitc.assign' op cannot assign to array type}}
257+
emitc.assign %arg1 : !emitc.array<4xi32> to %v : !emitc.array<4xi32>
241258
return
242259
}
243260

@@ -321,6 +338,13 @@ emitc.func @return_type_mismatch() -> i32 {
321338

322339
// -----
323340

341+
// expected-error@+1 {{'emitc.func' op cannot return array type}}
342+
emitc.func @return_type_array(%arg : !emitc.array<4xi32>) -> !emitc.array<4xi32> {
343+
emitc.return %arg : !emitc.array<4xi32>
344+
}
345+
346+
// -----
347+
324348
func.func @return_inside_func.func(%0: i32) -> (i32) {
325349
// expected-error@+1 {{'emitc.return' op expects parent op 'emitc.func'}}
326350
emitc.return %0 : i32

mlir/test/Dialect/EmitC/invalid_types.mlir

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,19 @@ func.func @illegal_array_unranked(
6565
%arg0: !emitc.array<*xi32>
6666
) {
6767
}
68+
69+
// -----
70+
71+
func.func @illegal_array_with_array_element_type(
72+
// expected-error @+1 {{invalid array element type}}
73+
%arg0: !emitc.array<4x!emitc.array<4xi32>>
74+
) {
75+
}
76+
77+
// -----
78+
79+
func.func @illegal_array_with_tensor_element_type(
80+
// expected-error @+1 {{invalid array element type}}
81+
%arg0: !emitc.array<4xtensor<4xi32>>
82+
) {
83+
}

mlir/test/Dialect/EmitC/types.mlir

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22
// check parser
33
// RUN: mlir-opt -verify-diagnostics %s | mlir-opt -verify-diagnostics | FileCheck %s
44

5+
// CHECK-LABEL: func @array_types(
6+
func.func @array_types(
7+
// CHECK-SAME: !emitc.array<1xf32>,
8+
%arg0: !emitc.array<1xf32>,
9+
// CHECK-SAME: !emitc.array<10x20x30xi32>,
10+
%arg1: !emitc.array<10x20x30xi32>,
11+
// CHECK-SAME: !emitc.array<30x!emitc.ptr<i32>>,
12+
%arg2: !emitc.array<30x!emitc.ptr<i32>>,
13+
// CHECK-SAME: !emitc.array<30x!emitc.opaque<"int">>
14+
%arg3: !emitc.array<30x!emitc.opaque<"int">>
15+
) {
16+
return
17+
}
18+
519
// CHECK-LABEL: func @opaque_types() {
620
func.func @opaque_types() {
721
// CHECK-NEXT: !emitc.opaque<"int">
@@ -39,17 +53,3 @@ func.func @pointer_types() {
3953

4054
return
4155
}
42-
43-
// CHECK-LABEL: func @array_types(
44-
func.func @array_types(
45-
// CHECK-SAME: !emitc.array<1xf32>,
46-
%arg0: !emitc.array<1xf32>,
47-
// CHECK-SAME: !emitc.array<10x20x30xi32>,
48-
%arg1: !emitc.array<10x20x30xi32>,
49-
// CHECK-SAME: !emitc.array<30x!emitc.ptr<i32>>,
50-
%arg2: !emitc.array<30x!emitc.ptr<i32>>,
51-
// CHECK-SAME: !emitc.array<30x!emitc.opaque<"int">>
52-
%arg3: !emitc.array<30x!emitc.opaque<"int">>
53-
) {
54-
return
55-
}

mlir/test/Target/Cpp/declare_func.mlir

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,11 @@ emitc.declare_func @foo
1414
emitc.func @foo(%arg0: i32) -> i32 attributes {specifiers = ["static","inline"]} {
1515
emitc.return %arg0 : i32
1616
}
17+
18+
19+
// CHECK: void array_arg(int32_t [[V2:[^ ]*]][3]);
20+
emitc.declare_func @array_arg
21+
// CHECK: void array_arg(int32_t [[V2:[^ ]*]][3]) {
22+
emitc.func @array_arg(%arg0: !emitc.array<3xi32>) {
23+
emitc.return
24+
}

mlir/test/Target/Cpp/func.mlir

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@ emitc.func @emitc_call() -> i32 {
4040

4141
emitc.func private @extern_func(i32) attributes {specifiers = ["extern"]}
4242
// CPP-DEFAULT: extern void extern_func(int32_t);
43+
44+
emitc.func private @array_arg(!emitc.array<3xi32>) attributes {specifiers = ["extern"]}
45+
// CPP-DEFAULT: extern void array_arg(int32_t[3]);

mlir/test/Target/Cpp/invalid.mlir

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,31 @@ func.func @non_static_shape(%arg0 : tensor<?xf32>) {
5757
func.func @unranked_tensor(%arg0 : tensor<*xf32>) {
5858
return
5959
}
60+
61+
// -----
62+
63+
// expected-error@+1 {{cannot emit tensor of array type}}
64+
func.func @tensor_of_array(%arg0 : tensor<4x!emitc.array<4xf32>>) {
65+
return
66+
}
67+
68+
// -----
69+
70+
// expected-error@+1 {{cannot emit pointer to array type}}
71+
func.func @pointer_to_array(%arg0 : !emitc.ptr<!emitc.array<4xf32>>) {
72+
return
73+
}
74+
75+
// -----
76+
77+
// expected-error@+1 {{cannot emit array type as result type}}
78+
func.func @array_as_result(%arg: !emitc.array<4xi8>) -> (!emitc.array<4xi8>) {
79+
return %arg : !emitc.array<4xi8>
80+
}
81+
82+
// -----
83+
func.func @ptr_to_array() {
84+
// expected-error@+1 {{cannot emit pointer to array type '!emitc.ptr<!emitc.array<9xi16>>'}}
85+
%v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr<!emitc.array<9xi16>>
86+
return
87+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: mlir-translate -split-input-file -declare-variables-at-top -mlir-to-cpp -verify-diagnostics %s
2+
3+
// expected-error@+1 {{'func.func' op cannot emit block argument #0 with array type}}
4+
func.func @array_as_block_argument(!emitc.array<4xi8>) {
5+
^bb0(%arg0 : !emitc.array<4xi8>):
6+
cf.br ^bb1(%arg0 : !emitc.array<4xi8>)
7+
^bb1(%a : !emitc.array<4xi8>):
8+
return
9+
}

mlir/test/Target/Cpp/variable.mlir

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ func.func @emitc_variable() {
1010
%c5 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.ptr<i32>
1111
%c6 = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr<i32>
1212
%c7 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<3x7xi32>
13+
%c8 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<5x!emitc.ptr<i8>>
1314
return
1415
}
1516
// CPP-DEFAULT: void emitc_variable() {
@@ -21,6 +22,7 @@ func.func @emitc_variable() {
2122
// CPP-DEFAULT-NEXT: int32_t* [[V5:[^ ]*]];
2223
// CPP-DEFAULT-NEXT: int32_t* [[V6:[^ ]*]] = NULL;
2324
// CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]][3][7];
25+
// CPP-DEFAULT-NEXT: int8_t* [[V8:[^ ]*]][5];
2426

2527
// CPP-DECLTOP: void emitc_variable() {
2628
// CPP-DECLTOP-NEXT: int32_t [[V0:[^ ]*]];
@@ -31,6 +33,7 @@ func.func @emitc_variable() {
3133
// CPP-DECLTOP-NEXT: int32_t* [[V5:[^ ]*]];
3234
// CPP-DECLTOP-NEXT: int32_t* [[V6:[^ ]*]];
3335
// CPP-DECLTOP-NEXT: int32_t [[V7:[^ ]*]][3][7];
36+
// CPP-DECLTOP-NEXT: int8_t* [[V8:[^ ]*]][5];
3437
// CPP-DECLTOP-NEXT: ;
3538
// CPP-DECLTOP-NEXT: [[V1]] = 42;
3639
// CPP-DECLTOP-NEXT: [[V2]] = -1;

0 commit comments

Comments
 (0)