diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td index 5ab729df67882..1ff41022eba8c 100644 --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td @@ -60,7 +60,7 @@ def EmitC_ArrayType : EmitC_Type<"Array", "array", [ShapedTypeInterface]> { /// Returns if this type is ranked (always true). bool hasRank() const { return true; } - /// Clone this vector type with the given shape and element type. If the + /// Clone this array type with the given shape and element type. If the /// provided shape is `std::nullopt`, the current shape of the type is used. ArrayType cloneWith(std::optional> shape, Type elementType) const; diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp index 5db0777bc30ab..7015a7e8c230d 100644 --- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp +++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp @@ -142,6 +142,8 @@ LogicalResult emitc::AssignOp::verify() { return emitOpError() << "requires value's type (" << value.getType() << ") to match variable's type (" << variable.getType() << ")"; + if (isa(variable.getType())) + return emitOpError() << "cannot assign to array type"; return success(); } @@ -193,6 +195,11 @@ LogicalResult emitc::CallOpaqueOp::verify() { } } + if (llvm::any_of(getResultTypes(), + [](Type type) { return isa(type); })) { + return emitOpError() << "cannot return array type"; + } + return success(); } @@ -457,6 +464,9 @@ LogicalResult FuncOp::verify() { return emitOpError("requires zero or exactly one result, but has ") << getNumResults(); + if (getNumResults() == 1 && isa(getResultTypes()[0])) + return emitOpError("cannot return array type"); + return success(); } @@ -796,7 +806,7 @@ Type emitc::ArrayType::parse(AsmParser &parser) { if (parser.parseType(elementType)) return Type(); - // Check that memref is formed from allowed types. + // Check that array is formed from allowed types. if (!isValidElementType(elementType)) return parser.emitError(typeLoc, "invalid array element type"), Type(); if (parser.parseGreater()) @@ -819,8 +829,8 @@ LogicalResult emitc::ArrayType::verify( if (shape.empty()) return emitError() << "shape must not be empty"; - for (auto d : shape) { - if (d <= 0) + for (int64_t dim : shape) { + if (dim <= 0) return emitError() << "dimensions must have positive size"; } diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp index 6dbcac5f912dd..6e477a34fc4ba 100644 --- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp +++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp @@ -881,15 +881,11 @@ static LogicalResult printFunctionArgs(CppEmitter &emitter, Region::BlockArgListType arguments) { raw_indented_ostream &os = emitter.ostream(); - if (failed(interleaveCommaWithError(arguments, os, - [&](BlockArgument arg) -> LogicalResult { - return emitter.emitVariableDeclaration( - functionOp->getLoc(), arg.getType(), - emitter.getOrCreateName(arg)); - }))) - return failure(); - - return success(); + return (interleaveCommaWithError( + arguments, os, [&](BlockArgument arg) -> LogicalResult { + return emitter.emitVariableDeclaration( + functionOp->getLoc(), arg.getType(), emitter.getOrCreateName(arg)); + })); } static LogicalResult printFunctionBody(CppEmitter &emitter, @@ -932,6 +928,9 @@ static LogicalResult printFunctionBody(CppEmitter &emitter, if (emitter.hasValueInScope(arg)) return functionOp->emitOpError(" block argument #") << arg.getArgNumber() << " is out of scope"; + if (isa(arg.getType())) + return functionOp->emitOpError("cannot emit block argument #") + << arg.getArgNumber() << " with array type"; if (failed( emitter.emitType(block.getParentOp()->getLoc(), arg.getType()))) { return failure(); @@ -975,6 +974,11 @@ static LogicalResult printOperation(CppEmitter &emitter, "with multiple blocks needs variables declared at top"); } + if (llvm::any_of(functionOp.getResultTypes(), + [](Type type) { return isa(type); })) { + return functionOp.emitOpError() << "cannot emit array type as result type"; + } + CppEmitter::Scope scope(emitter); raw_indented_ostream &os = emitter.ostream(); if (failed(emitter.emitTypes(functionOp.getLoc(), @@ -1489,6 +1493,8 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { if (!tType.hasStaticShape()) return emitError(loc, "cannot emit tensor type with non static shape"); os << "Tensor<"; + if (isa(tType.getElementType())) + return emitError(loc, "cannot emit tensor of array type ") << type; if (failed(emitType(loc, tType.getElementType()))) return failure(); auto shape = tType.getShape(); @@ -1505,7 +1511,16 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) { os << oType.getValue(); return success(); } + if (auto aType = dyn_cast(type)) { + if (failed(emitType(loc, aType.getElementType()))) + return failure(); + for (auto dim : aType.getShape()) + os << "[" << dim << "]"; + return success(); + } if (auto pType = dyn_cast(type)) { + if (isa(pType.getPointee())) + return emitError(loc, "cannot emit pointer to array type ") << type; if (failed(emitType(loc, pType.getPointee()))) return failure(); os << "*"; @@ -1527,6 +1542,9 @@ LogicalResult CppEmitter::emitTypes(Location loc, ArrayRef types) { } LogicalResult CppEmitter::emitTupleType(Location loc, ArrayRef types) { + if (llvm::any_of(types, [](Type type) { return isa(type); })) { + return emitError(loc, "cannot emit tuple of array type"); + } os << "std::tuple<"; if (failed(interleaveCommaWithError( types, os, [&](Type type) { return emitType(loc, type); }))) diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir index 51b68eecbbd56..58b3a11ed93e1 100644 --- a/mlir/test/Dialect/EmitC/invalid_ops.mlir +++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir @@ -80,6 +80,14 @@ func.func @dense_template_argument(%arg : i32) { // ----- +func.func @array_result() { + // expected-error @+1 {{'emitc.call_opaque' op cannot return array type}} + emitc.call_opaque "array_result"() : () -> !emitc.array<4xi32> + return +} + +// ----- + func.func @empty_operator(%arg : i32) { // expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}} %2 = emitc.apply ""(%arg) : (i32) -> !emitc.ptr @@ -129,6 +137,14 @@ func.func @cast_tensor(%arg : tensor) { // ----- +func.func @cast_array(%arg : !emitc.array<4xf32>) { + // expected-error @+1 {{'emitc.cast' op operand type '!emitc.array<4xf32>' and result type '!emitc.array<4xf32>' are cast incompatible}} + %1 = emitc.cast %arg: !emitc.array<4xf32> to !emitc.array<4xf32> + return +} + +// ----- + func.func @add_two_pointers(%arg0: !emitc.ptr, %arg1: !emitc.ptr) { // expected-error @+1 {{'emitc.add' op requires that at most one operand is a pointer}} %1 = "emitc.add" (%arg0, %arg1) : (!emitc.ptr, !emitc.ptr) -> !emitc.ptr @@ -235,9 +251,10 @@ func.func @test_assign_type_mismatch(%arg1: f32) { // ----- -func.func @test_subscript_indices_mismatch(%arg0: !emitc.array<4x8xf32>, %arg2: index) { - // expected-error @+1 {{'emitc.subscript' op requires number of indices (1) to match the rank of the array type (2)}} - %0 = emitc.subscript %arg0[%arg2] : <4x8xf32> +func.func @test_assign_to_array(%arg1: !emitc.array<4xi32>) { + %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4xi32> + // expected-error @+1 {{'emitc.assign' op cannot assign to array type}} + emitc.assign %arg1 : !emitc.array<4xi32> to %v : !emitc.array<4xi32> return } @@ -321,6 +338,13 @@ emitc.func @return_type_mismatch() -> i32 { // ----- +// expected-error@+1 {{'emitc.func' op cannot return array type}} +emitc.func @return_type_array(%arg : !emitc.array<4xi32>) -> !emitc.array<4xi32> { + emitc.return %arg : !emitc.array<4xi32> +} + +// ----- + func.func @return_inside_func.func(%0: i32) -> (i32) { // expected-error@+1 {{'emitc.return' op expects parent op 'emitc.func'}} emitc.return %0 : i32 diff --git a/mlir/test/Dialect/EmitC/invalid_types.mlir b/mlir/test/Dialect/EmitC/invalid_types.mlir index 4c526aa93dffb..079371b39b9d1 100644 --- a/mlir/test/Dialect/EmitC/invalid_types.mlir +++ b/mlir/test/Dialect/EmitC/invalid_types.mlir @@ -65,3 +65,19 @@ func.func @illegal_array_unranked( %arg0: !emitc.array<*xi32> ) { } + +// ----- + +func.func @illegal_array_with_array_element_type( + // expected-error @+1 {{invalid array element type}} + %arg0: !emitc.array<4x!emitc.array<4xi32>> +) { +} + +// ----- + +func.func @illegal_array_with_tensor_element_type( + // expected-error @+1 {{invalid array element type}} + %arg0: !emitc.array<4xtensor<4xi32>> +) { +} diff --git a/mlir/test/Dialect/EmitC/types.mlir b/mlir/test/Dialect/EmitC/types.mlir index 8477b0ed05977..752f2c10c17be 100644 --- a/mlir/test/Dialect/EmitC/types.mlir +++ b/mlir/test/Dialect/EmitC/types.mlir @@ -2,6 +2,20 @@ // check parser // RUN: mlir-opt -verify-diagnostics %s | mlir-opt -verify-diagnostics | FileCheck %s +// CHECK-LABEL: func @array_types( +func.func @array_types( + // CHECK-SAME: !emitc.array<1xf32>, + %arg0: !emitc.array<1xf32>, + // CHECK-SAME: !emitc.array<10x20x30xi32>, + %arg1: !emitc.array<10x20x30xi32>, + // CHECK-SAME: !emitc.array<30x!emitc.ptr>, + %arg2: !emitc.array<30x!emitc.ptr>, + // CHECK-SAME: !emitc.array<30x!emitc.opaque<"int">> + %arg3: !emitc.array<30x!emitc.opaque<"int">> +) { + return +} + // CHECK-LABEL: func @opaque_types() { func.func @opaque_types() { // CHECK-NEXT: !emitc.opaque<"int"> @@ -39,17 +53,3 @@ func.func @pointer_types() { return } - -// CHECK-LABEL: func @array_types( -func.func @array_types( - // CHECK-SAME: !emitc.array<1xf32>, - %arg0: !emitc.array<1xf32>, - // CHECK-SAME: !emitc.array<10x20x30xi32>, - %arg1: !emitc.array<10x20x30xi32>, - // CHECK-SAME: !emitc.array<30x!emitc.ptr>, - %arg2: !emitc.array<30x!emitc.ptr>, - // CHECK-SAME: !emitc.array<30x!emitc.opaque<"int">> - %arg3: !emitc.array<30x!emitc.opaque<"int">> -) { - return -} diff --git a/mlir/test/Target/Cpp/declare_func.mlir b/mlir/test/Target/Cpp/declare_func.mlir index 72c087a3388e2..00680d71824ae 100644 --- a/mlir/test/Target/Cpp/declare_func.mlir +++ b/mlir/test/Target/Cpp/declare_func.mlir @@ -14,3 +14,11 @@ emitc.declare_func @foo emitc.func @foo(%arg0: i32) -> i32 attributes {specifiers = ["static","inline"]} { emitc.return %arg0 : i32 } + + +// CHECK: void array_arg(int32_t [[V2:[^ ]*]][3]); +emitc.declare_func @array_arg +// CHECK: void array_arg(int32_t [[V2:[^ ]*]][3]) { +emitc.func @array_arg(%arg0: !emitc.array<3xi32>) { + emitc.return +} diff --git a/mlir/test/Target/Cpp/func.mlir b/mlir/test/Target/Cpp/func.mlir index a639cae6f623c..9c9ea55bfc4e1 100644 --- a/mlir/test/Target/Cpp/func.mlir +++ b/mlir/test/Target/Cpp/func.mlir @@ -40,3 +40,6 @@ emitc.func @emitc_call() -> i32 { emitc.func private @extern_func(i32) attributes {specifiers = ["extern"]} // CPP-DEFAULT: extern void extern_func(int32_t); + +emitc.func private @array_arg(!emitc.array<3xi32>) attributes {specifiers = ["extern"]} +// CPP-DEFAULT: extern void array_arg(int32_t[3]); diff --git a/mlir/test/Target/Cpp/invalid.mlir b/mlir/test/Target/Cpp/invalid.mlir index 18dabb9155866..552c04a9b07f7 100644 --- a/mlir/test/Target/Cpp/invalid.mlir +++ b/mlir/test/Target/Cpp/invalid.mlir @@ -57,3 +57,31 @@ func.func @non_static_shape(%arg0 : tensor) { func.func @unranked_tensor(%arg0 : tensor<*xf32>) { return } + +// ----- + +// expected-error@+1 {{cannot emit tensor of array type}} +func.func @tensor_of_array(%arg0 : tensor<4x!emitc.array<4xf32>>) { + return +} + +// ----- + +// expected-error@+1 {{cannot emit pointer to array type}} +func.func @pointer_to_array(%arg0 : !emitc.ptr>) { + return +} + +// ----- + +// expected-error@+1 {{cannot emit array type as result type}} +func.func @array_as_result(%arg: !emitc.array<4xi8>) -> (!emitc.array<4xi8>) { + return %arg : !emitc.array<4xi8> +} + +// ----- +func.func @ptr_to_array() { + // expected-error@+1 {{cannot emit pointer to array type '!emitc.ptr>'}} + %v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr> + return +} diff --git a/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir b/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir new file mode 100644 index 0000000000000..844fe03bad4ab --- /dev/null +++ b/mlir/test/Target/Cpp/invalid_declare_variables_at_top.mlir @@ -0,0 +1,9 @@ +// RUN: mlir-translate -split-input-file -declare-variables-at-top -mlir-to-cpp -verify-diagnostics %s + +// expected-error@+1 {{'func.func' op cannot emit block argument #0 with array type}} +func.func @array_as_block_argument(!emitc.array<4xi8>) { +^bb0(%arg0 : !emitc.array<4xi8>): + cf.br ^bb1(%arg0 : !emitc.array<4xi8>) +^bb1(%a : !emitc.array<4xi8>): + return +} diff --git a/mlir/test/Target/Cpp/variable.mlir b/mlir/test/Target/Cpp/variable.mlir index 5d061a6c87505..126dd384b47a2 100644 --- a/mlir/test/Target/Cpp/variable.mlir +++ b/mlir/test/Target/Cpp/variable.mlir @@ -10,6 +10,7 @@ func.func @emitc_variable() { %c5 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.ptr %c6 = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr %c7 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<3x7xi32> + %c8 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<5x!emitc.ptr> return } // CPP-DEFAULT: void emitc_variable() { @@ -21,6 +22,7 @@ func.func @emitc_variable() { // CPP-DEFAULT-NEXT: int32_t* [[V5:[^ ]*]]; // CPP-DEFAULT-NEXT: int32_t* [[V6:[^ ]*]] = NULL; // CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]][3][7]; +// CPP-DEFAULT-NEXT: int8_t* [[V8:[^ ]*]][5]; // CPP-DECLTOP: void emitc_variable() { // CPP-DECLTOP-NEXT: int32_t [[V0:[^ ]*]]; @@ -31,6 +33,7 @@ func.func @emitc_variable() { // CPP-DECLTOP-NEXT: int32_t* [[V5:[^ ]*]]; // CPP-DECLTOP-NEXT: int32_t* [[V6:[^ ]*]]; // CPP-DECLTOP-NEXT: int32_t [[V7:[^ ]*]][3][7]; +// CPP-DECLTOP-NEXT: int8_t* [[V8:[^ ]*]][5]; // CPP-DECLTOP-NEXT: ; // CPP-DECLTOP-NEXT: [[V1]] = 42; // CPP-DECLTOP-NEXT: [[V2]] = -1;