[Mlir-commits] [mlir] 8f58a4c - [mlir][emitc]: Add MemberCallOpaque op (#200057)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Jun 2 07:58:21 PDT 2026
Author: Jeremy Kun
Date: 2026-06-02T09:58:16-05:00
New Revision: 8f58a4cab3a7eccad53797a49e16f8a933d149b1
URL: https://github.com/llvm/llvm-project/commit/8f58a4cab3a7eccad53797a49e16f8a933d149b1
DIFF: https://github.com/llvm/llvm-project/commit/8f58a4cab3a7eccad53797a49e16f8a933d149b1.diff
LOG: [mlir][emitc]: Add MemberCallOpaque op (#200057)
Cf. https://discourse.llvm.org/t/method-calls-in-emitc/90898
Added:
mlir/test/Dialect/EmitC/member_call_opaque.mlir
Modified:
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
mlir/lib/Dialect/EmitC/IR/EmitC.cpp
mlir/lib/Target/Cpp/TranslateToCpp.cpp
mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
mlir/test/Dialect/EmitC/attrs.mlir
mlir/test/Dialect/EmitC/invalid_ops.mlir
mlir/test/Dialect/EmitC/ops.mlir
mlir/test/Target/Cpp/call.mlir
mlir/test/Target/Cpp/expressions.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index e1ccf29ada660..65361a987a08e 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -338,24 +338,57 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
Arg<StrAttr, "the C++ function to call">:$callee,
Arg<OptionalAttr<ArrayAttr>, "the order of operands and further attributes">:$args,
Arg<OptionalAttr<ArrayAttr>, "template arguments">:$template_args,
- Variadic<EmitCType>:$operands
+ Variadic<EmitCType>:$arg_operands
);
let results = (outs Variadic<EmitCType>);
let builders = [
OpBuilder<(ins
"::mlir::TypeRange":$resultTypes,
"::llvm::StringRef":$callee,
- "::mlir::ValueRange":$operands,
+ "::mlir::ValueRange":$arg_operands,
CArg<"::mlir::ArrayAttr", "{}">:$args,
CArg<"::mlir::ArrayAttr", "{}">:$template_args), [{
build($_builder, $_state, resultTypes, callee, args, template_args,
- operands);
+ arg_operands);
}]
>
];
let assemblyFormat = [{
- $callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
+ $callee `(` $arg_operands `)` prop-dict attr-dict `:` functional-type($arg_operands, results)
+ }];
+ let hasVerifier = 1;
+}
+
+def EmitC_MemberCallOpaqueOp : EmitC_Op<"member_call_opaque", [CExpressionInterface]> {
+ let summary = "Opaque member call operation";
+ let description = [{
+ The `emitc.member_call_opaque` operation represents a C++ member function
+ call. It takes a receiver operand, a callee string attribute (the method
+ name), and variadic operands for arguments.
+
+ The call allows specifying order of operands and attributes in the call as
+ follows:
+ - integer value of index type refers to an argument operand;
+ - attribute which will get lowered to constant value in call;
+
+ Example:
+
+ ```mlir
+ %0 = emitc.member_call_opaque %receiver "method" (%arg0, %arg1) : !emitc.opaque<"MyClass">, (i32, i32) -> i32
+ ```
+ }];
+ let arguments = (ins
+ EmitCType:$receiver,
+ StrAttr:$callee,
+ OptionalAttr<ArrayAttr>:$args,
+ OptionalAttr<ArrayAttr>:$template_args,
+ Variadic<EmitCType>:$arg_operands
+ );
+ let results = (outs Variadic<EmitCType>);
+
+ let assemblyFormat = [{
+ $receiver $callee `(` $arg_operands `)` prop-dict attr-dict `:` type($receiver) `,` functional-type($arg_operands, results)
}];
let hasVerifier = 1;
}
@@ -395,7 +428,7 @@ def EmitC_CastOp : EmitC_Op<"cast",
def EmitC_CmpOp : EmitC_BinaryOp<"cmp", []> {
let summary = "Comparison operation";
let description = [{
- With the `emitc.cmp` operation the comparison operators ==, !=, <, <=, >, >=, <=>
+ With the `emitc.cmp` operation the comparison operators ==, !=, <, <=, >, >=, <=>
can be applied.
Its first argument is an attribute that defines the comparison operator:
@@ -412,7 +445,7 @@ def EmitC_CmpOp : EmitC_BinaryOp<"cmp", []> {
```mlir
// Custom form of the cmp operation.
%0 = emitc.cmp eq, %arg0, %arg1 : (i32, i32) -> i1
- %1 = emitc.cmp lt, %arg2, %arg3 :
+ %1 = emitc.cmp lt, %arg2, %arg3 :
(
!emitc.opaque<"std::valarray<float>">,
!emitc.opaque<"std::valarray<float>">
@@ -537,7 +570,7 @@ def EmitC_ExpressionOp
let summary = "Expression operation";
let description = [{
The `emitc.expression` operation returns a single SSA value which is yielded by
- its single-basic-block region. The operation takes zero or more input operands
+ its single-basic-block region. The operation takes zero or more input operands
that are passed as block arguments to the region.
As the operation is to be emitted as a C expression, the operations within
@@ -692,7 +725,7 @@ def EmitC_CallOp : EmitC_Op<"call",
%2 = emitc.call @my_add(%0, %1) : (f32, f32) -> f32
```
}];
- let arguments = (ins
+ let arguments = (ins
FlatSymbolRefAttr:$callee,
Variadic<EmitCType>:$operands,
OptionalAttr<DictArrayAttr>:$arg_attrs,
@@ -1042,8 +1075,8 @@ def EmitC_LoadOp : EmitC_Op<"load", [CExpressionInterface,
]> {
let summary = "Load an lvalue into an SSA value.";
let description = [{
- This operation loads the content of a modifiable lvalue into an SSA value.
- Modifications of the lvalue executed after the load are not observable on
+ This operation loads the content of a modifiable lvalue into an SSA value.
+ Modifications of the lvalue executed after the load are not observable on
the produced value.
Example:
@@ -1057,11 +1090,11 @@ def EmitC_LoadOp : EmitC_Op<"load", [CExpressionInterface,
```
}];
- let arguments = (ins
+ let arguments = (ins
Res<EmitC_LValueType, "", [MemRead<DefaultResource, 0, FullEffect>]>:$operand);
let results = (outs AnyType:$result);
- let assemblyFormat = "$operand attr-dict `:` type($operand)";
+ let assemblyFormat = "$operand attr-dict `:` type($operand)";
}
def EmitC_MulOp : EmitC_BinaryOp<"mul", []> {
@@ -1292,7 +1325,7 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> {
%0 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue<i32>
// Variable emitted as `int32_t* = NULL;`
- %1 = "emitc.variable"() {value = #emitc.opaque<"NULL">}
+ %1 = "emitc.variable"() {value = #emitc.opaque<"NULL">}
: () -> !emitc.lvalue<!emitc.ptr<!emitc.opaque<"int32_t">>>
```
@@ -1424,7 +1457,7 @@ def EmitC_VerbatimOp : EmitC_Op<"verbatim"> {
#endif
...
-
+
#ifdef __cplusplus
}
#endif
@@ -1486,7 +1519,7 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> {
```
}];
- let arguments = (ins
+ let arguments = (ins
Res<EmitC_LValueType, "", [MemWrite<DefaultResource, 1, FullEffect>]>:$var,
EmitCType:$value);
let results = (outs);
@@ -1791,7 +1824,7 @@ def EmitC_FieldOp : EmitC_Op<"field", [Symbol]> {
let summary = "A field within a class";
let description = [{
The `emitc.field` operation declares a named field within an `emitc.class`
- operation. The field's type must be an EmitC type.
+ operation. The field's type must be an EmitC type.
Example:
@@ -1868,8 +1901,8 @@ def EmitC_DoOp : EmitC_Op<"do",
2. An `emitc.yield` passing through the expression result
- The expression's body contains the actual condition logic
- The body region is executed before the first evaluation of the
- condition. Thus, there is a guarantee that the loop will be executed
+ The body region is executed before the first evaluation of the
+ condition. Thus, there is a guarantee that the loop will be executed
at least once. The loop terminates when the condition yields false.
The canonical structure of `emitc.do` is:
@@ -1886,7 +1919,7 @@ def EmitC_DoOp : EmitC_Op<"do",
emitc.yield %result : i1
}
// Forward expression result
- emitc.yield %condition : i1
+ emitc.yield %condition : i1
}
```
@@ -1933,7 +1966,7 @@ def EmitC_DoOp : EmitC_Op<"do",
}];
let arguments = (ins);
- let results = (outs);
+ let results = (outs);
let regions = (region SizedRegion<1>:$bodyRegion,
SizedRegion<1>:$conditionRegion);
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 36394e67008da..bab9cb4a91102 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -340,44 +340,57 @@ bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
// CallOpaqueOp
//===----------------------------------------------------------------------===//
-LogicalResult emitc::CallOpaqueOp::verify() {
+static LogicalResult
+verifyOpaqueCallCommon(Operation *op, StringRef callee,
+ std::optional<ArrayAttr> args,
+ std::optional<ArrayAttr> templateArgs,
+ TypeRange resultTypes, size_t numArgsOperands) {
// Callee must not be empty.
- if (getCallee().empty())
- return emitOpError("callee must not be empty");
+ if (callee.empty())
+ return op->emitOpError("callee must not be empty");
- if (std::optional<ArrayAttr> argsAttr = getArgs()) {
- for (Attribute arg : *argsAttr) {
+ if (args) {
+ for (Attribute arg : *args) {
auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
if (intAttr && llvm::isa<IndexType>(intAttr.getType())) {
int64_t index = intAttr.getInt();
// Args with elements of type index must be in range
- // [0..operands.size).
- if ((index < 0) || (index >= static_cast<int64_t>(getNumOperands())))
- return emitOpError("index argument is out of range");
-
- // Args with elements of type ArrayAttr must have a type.
- } else if (llvm::isa<ArrayAttr>(
- arg) /*&& llvm::isa<NoneType>(arg.getType())*/) {
- // FIXME: Array attributes never have types
- return emitOpError("array argument has no type");
+ // [0..numArgsOperands).
+ if ((index < 0) || (index >= static_cast<int64_t>(numArgsOperands)))
+ return op->emitOpError("index argument is out of range");
+
+ } else if (llvm::isa<ArrayAttr>(arg)) {
+ return op->emitOpError("array argument has no type");
}
}
}
- if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {
- for (Attribute tArg : *templateArgsAttr) {
+ if (templateArgs) {
+ for (Attribute tArg : *templateArgs) {
if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
- return emitOpError("template argument has invalid type");
+ return op->emitOpError("template argument has invalid type");
}
}
- if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) {
- return emitOpError() << "cannot return array type";
+ if (llvm::any_of(resultTypes, llvm::IsaPred<ArrayType>)) {
+ return op->emitOpError() << "cannot return array type";
}
return success();
}
+LogicalResult emitc::CallOpaqueOp::verify() {
+ return verifyOpaqueCallCommon(getOperation(), getCallee(), getArgs(),
+ getTemplateArgs(), getResultTypes(),
+ getNumOperands());
+}
+
+LogicalResult emitc::MemberCallOpaqueOp::verify() {
+ return verifyOpaqueCallCommon(getOperation(), getCallee(), getArgs(),
+ getTemplateArgs(), getResultTypes(),
+ getArgOperands().size());
+}
+
//===----------------------------------------------------------------------===//
// ConstantOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index a670fb152a1e5..74e608ea818cf 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -909,14 +909,29 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::CallOp callOp) {
return printCallOperation(emitter, operation, callee);
}
-static LogicalResult printOperation(CppEmitter &emitter,
- emitc::CallOpaqueOp callOpaqueOp) {
+template <typename OpTy>
+static LogicalResult
+printOpaqueCallCommon(CppEmitter &emitter, OpTy op, StringRef callee,
+ std::optional<ArrayAttr> templateArgs,
+ std::optional<ArrayAttr> args, bool isMemberCall,
+ Value receiver = nullptr) {
raw_ostream &os = emitter.ostream();
- Operation &op = *callOpaqueOp.getOperation();
- if (failed(emitter.emitAssignPrefix(op)))
+ if (failed(emitter.emitAssignPrefix(*op.getOperation())))
return failure();
- os << callOpaqueOp.getCallee();
+
+ if (isMemberCall) {
+ assert(receiver && "Expected receiver for member call");
+ if (failed(emitter.emitOperand(receiver)))
+ return failure();
+
+ if (llvm::isa<emitc::PointerType>(receiver.getType()))
+ os << "->";
+ else
+ os << ".";
+ }
+
+ os << callee;
// Template arguments can't refer to SSA values and as such the template
// arguments which are supplied in form of attributes can be emitted as is. We
@@ -926,21 +941,19 @@ static LogicalResult printOperation(CppEmitter &emitter,
return emitter.emitAttribute(op.getLoc(), attr);
};
- if (callOpaqueOp.getTemplateArgs()) {
+ if (templateArgs) {
os << "<";
- if (failed(interleaveCommaWithError(*callOpaqueOp.getTemplateArgs(), os,
- emitTemplateArgs)))
+ if (failed(interleaveCommaWithError(*templateArgs, os, emitTemplateArgs)))
return failure();
os << ">";
}
auto emitArgs = [&](Attribute attr) -> LogicalResult {
if (auto t = dyn_cast<IntegerAttr>(attr)) {
- // Index attributes are treated specially as operand index.
if (t.getType().isIndex()) {
int64_t idx = t.getInt();
- Value operand = op.getOperand(idx);
- return emitter.emitOperand(operand);
+ Value operand = op.getArgOperands()[idx];
+ return emitter.emitOperand(operand, /*isInBrackets=*/false);
}
}
if (failed(emitter.emitAttribute(op.getLoc(), attr)))
@@ -951,16 +964,38 @@ static LogicalResult printOperation(CppEmitter &emitter,
os << "(";
- LogicalResult emittedArgs =
- callOpaqueOp.getArgs()
- ? interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs)
- : emitter.emitOperands(op);
+ LogicalResult emittedArgs = success();
+ if (args) {
+ emittedArgs = interleaveCommaWithError(*args, os, emitArgs);
+ } else {
+ emittedArgs =
+ interleaveCommaWithError(op.getArgOperands(), os, [&](Value operand) {
+ return emitter.emitOperand(operand, /*isInBrackets=*/true);
+ });
+ }
if (failed(emittedArgs))
return failure();
os << ")";
return success();
}
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::CallOpaqueOp callOpaqueOp) {
+ return printOpaqueCallCommon(emitter, callOpaqueOp, callOpaqueOp.getCallee(),
+ callOpaqueOp.getTemplateArgs(),
+ callOpaqueOp.getArgs(),
+ /*isMemberCall=*/false);
+}
+
+static LogicalResult
+printOperation(CppEmitter &emitter,
+ emitc::MemberCallOpaqueOp memberCallOpaqueOp) {
+ return printOpaqueCallCommon(
+ emitter, memberCallOpaqueOp, memberCallOpaqueOp.getCallee(),
+ memberCallOpaqueOp.getTemplateArgs(), memberCallOpaqueOp.getArgs(),
+ /*isMemberCall=*/true, memberCallOpaqueOp.getReceiver());
+}
+
static LogicalResult printOperation(CppEmitter &emitter,
emitc::ApplyOp applyOp) {
raw_ostream &os = emitter.ostream();
@@ -1875,10 +1910,11 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
- emitc::MemberOfPtrOp, emitc::MemberOp, emitc::MulOp,
- emitc::RemOp, emitc::ReturnOp, emitc::SubscriptOp, emitc::SubOp,
- emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
- emitc::VariableOp, emitc::VerbatimOp>(
+ emitc::MemberCallOpaqueOp, emitc::MemberOfPtrOp,
+ emitc::MemberOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp,
+ emitc::SubscriptOp, emitc::SubOp, emitc::SwitchOp,
+ emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
+ emitc::VerbatimOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
index 19e1c7ae4263e..be0b9baf502bc 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
@@ -18,7 +18,7 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
// CHECK-LABEL: func.func @alloc_copy(
// CHECK-SAME: %[[ARG0:.*]]: memref<999xi32>) {
// CHECK: %[[UNREALIZED_CONVERSION_CAST_0:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<999xi32> to !emitc.array<999xi32>
-// CHECK: %[[CALL_OPAQUE_0:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CHECK: %[[CALL_OPAQUE_0:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// CHECK: %[[VAL_0:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// CHECK: %[[MUL_0:.*]] = emitc.mul %[[CALL_OPAQUE_0]], %[[VAL_0]] : (!emitc.size_t, index) -> !emitc.size_t
// CHECK: %[[CALL_OPAQUE_1:.*]] = emitc.call_opaque "malloc"(%[[MUL_0]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
@@ -30,11 +30,11 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
// CHECK: %[[VAL_2:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
// CHECK: %[[SUBSCRIPT_1:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_1]]{{\[}}%[[VAL_2]]] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
// CHECK: %[[ADDRESS_OF_1:.*]] = emitc.address_of %[[SUBSCRIPT_1]] : !emitc.lvalue<i32>
-// CHECK: %[[CALL_OPAQUE_2:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CHECK: %[[CALL_OPAQUE_2:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// CHECK: %[[VAL_3:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// CHECK: %[[MUL_1:.*]] = emitc.mul %[[CALL_OPAQUE_2]], %[[VAL_3]] : (!emitc.size_t, index) -> !emitc.size_t
// CHECK: emitc.call_opaque "memcpy"(%[[ADDRESS_OF_1]], %[[ADDRESS_OF_0]], %[[MUL_1]]) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
-// CHECK: %[[CALL_OPAQUE_3:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CHECK: %[[CALL_OPAQUE_3:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// CHECK: %[[VAL_4:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// CHECK: %[[MUL_2:.*]] = emitc.mul %[[CALL_OPAQUE_3]], %[[VAL_4]] : (!emitc.size_t, index) -> !emitc.size_t
// CHECK: %[[CALL_OPAQUE_4:.*]] = emitc.call_opaque "malloc"(%[[MUL_2]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
@@ -46,7 +46,7 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
// CHECK: %[[VAL_6:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
// CHECK: %[[SUBSCRIPT_3:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_2]]{{\[}}%[[VAL_6]]] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
// CHECK: %[[ADDRESS_OF_3:.*]] = emitc.address_of %[[SUBSCRIPT_3]] : !emitc.lvalue<i32>
-// CHECK: %[[CALL_OPAQUE_5:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CHECK: %[[CALL_OPAQUE_5:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// CHECK: %[[VAL_7:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// CHECK: %[[MUL_3:.*]] = emitc.mul %[[CALL_OPAQUE_5]], %[[VAL_7]] : (!emitc.size_t, index) -> !emitc.size_t
// CHECK: emitc.call_opaque "memcpy"(%[[ADDRESS_OF_3]], %[[ADDRESS_OF_2]], %[[MUL_3]]) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
index e391a893bc44a..ca7f3fbe20eff 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
@@ -9,7 +9,7 @@ func.func @alloc() {
// CPP: module {
// CPP-NEXT: emitc.include <"cstdlib">
// CPP-LABEL: alloc()
-// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// CPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
// CPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "malloc"(%[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
@@ -19,7 +19,7 @@ func.func @alloc() {
// NOCPP: module {
// NOCPP-NEXT: emitc.include <"stdlib.h">
// NOCPP-LABEL: alloc()
-// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// NOCPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
// NOCPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "malloc"(%[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
@@ -32,7 +32,7 @@ func.func @alloc_aligned() {
}
// CPP-LABEL: alloc_aligned
-// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [f32]}> : () -> !emitc.size_t
// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// CPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
// CPP-NEXT: %[[ALIGNMENT:.*]] = "emitc.constant"() <{value = 64 : index}> : () -> !emitc.size_t
@@ -41,7 +41,7 @@ func.func @alloc_aligned() {
// CPP-NEXT: return
// NOCPP-LABEL: alloc_aligned
-// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [f32]}> : () -> !emitc.size_t
// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
// NOCPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
// NOCPP-NEXT: %[[ALIGNMENT:.*]] = "emitc.constant"() <{value = 64 : index}> : () -> !emitc.size_t
@@ -55,7 +55,7 @@ func.func @allocating_multi() {
}
// CPP-LABEL: allocating_multi
-// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 6993 : index}> : () -> index
// CPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
// CPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "malloc"(%[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">
@@ -63,7 +63,7 @@ func.func @allocating_multi() {
// CPP-NEXT: return
// NOCPP-LABEL: allocating_multi
-// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 6993 : index}> : () -> index
// NOCPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
// NOCPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "malloc"(%[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
index 4b396005a7da3..07cad3b0c4dc2 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
@@ -21,7 +21,7 @@
// CHECK-SAME: %[[ARG_J:.*]]: !emitc.size_t)
func.func private @memref_alloc_store(%v : f32, %i: index, %j: index) {
/// Allocation size computation
- // CHECK: %[[SIZEOF_F32:.*]] = call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+ // CHECK: %[[SIZEOF_F32:.*]] = call_opaque "sizeof"() <{args = [f32]}> : () -> !emitc.size_t
// CHECK: %[[NUM_ELEMS:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
// CHECK: %[[TOTAL_BYTES:.*]] = mul %[[SIZEOF_F32]], %[[NUM_ELEMS]] : (!emitc.size_t, index) -> !emitc.size_t
/// Alloc
@@ -42,7 +42,7 @@ func.func private @memref_alloc_store(%v : f32, %i: index, %j: index) {
// CHECK-SAME: %[[ARG_I:.*]]: !emitc.size_t,
// CHECK-SAME: %[[ARG_J:.*]]: !emitc.size_t) -> f32
func.func private @memref_alloc_load(%i: index, %j: index) -> f32 {
- // CHECK: %[[SIZEOF_F32:.*]] = call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+ // CHECK: %[[SIZEOF_F32:.*]] = call_opaque "sizeof"() <{args = [f32]}> : () -> !emitc.size_t
// CHECK: %[[NUM_ELEMS:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
// CHECK: %[[TOTAL_BYTES:.*]] = mul %[[SIZEOF_F32]], %[[NUM_ELEMS]] : (!emitc.size_t, index) -> !emitc.size_t
// CHECK: %[[MALLOC_PTR:.*]] = call_opaque "malloc"(%[[TOTAL_BYTES]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
index 3de2d25f2b0d4..04e6edd5b6981 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
@@ -21,7 +21,7 @@ func.func @copying(%arg0 : memref<9x4x5x7xf32>, %arg1 : memref<9x4x5x7xf32>) {
// CHECK: %[[VAL_1:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
// CHECK: %[[SUBSCRIPT_1:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_0]]{{\[}}%[[VAL_1]], %[[VAL_1]], %[[VAL_1]], %[[VAL_1]]] : (!emitc.array<9x4x5x7xf32>, index, index, index, index) -> !emitc.lvalue<f32>
// CHECK: %[[ADDRESS_OF_1:.*]] = emitc.address_of %[[SUBSCRIPT_1]] : !emitc.lvalue<f32>
-// CHECK: %[[CALL_OPAQUE_0:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// CHECK: %[[CALL_OPAQUE_0:.*]] = emitc.call_opaque "sizeof"() <{args = [f32]}> : () -> !emitc.size_t
// CHECK: %[[VAL_2:.*]] = "emitc.constant"() <{value = 1260 : index}> : () -> index
// CHECK: %[[MUL_0:.*]] = emitc.mul %[[CALL_OPAQUE_0]], %[[VAL_2]] : (!emitc.size_t, index) -> !emitc.size_t
// CHECK: emitc.call_opaque "memcpy"(%[[ADDRESS_OF_1]], %[[ADDRESS_OF_0]], %[[MUL_0]]) : (!emitc.ptr<f32>, !emitc.ptr<f32>, !emitc.size_t) -> ()
diff --git a/mlir/test/Dialect/EmitC/attrs.mlir b/mlir/test/Dialect/EmitC/attrs.mlir
index 5a219c462678e..cc01673c3803c 100644
--- a/mlir/test/Dialect/EmitC/attrs.mlir
+++ b/mlir/test/Dialect/EmitC/attrs.mlir
@@ -5,8 +5,8 @@
// CHECK-LABEL: func @opaque_attrs() {
func.func @opaque_attrs() {
// CHECK-NEXT: #emitc.opaque<"attr">
- emitc.call_opaque "f"() {args = [#emitc.opaque<"attr">]} : () -> ()
+ emitc.call_opaque "f"() <{args = [#emitc.opaque<"attr">]}> : () -> ()
// CHECK-NEXT: #emitc.opaque<"\22quoted_attr\22">
- emitc.call_opaque "f"() {args = [#emitc.opaque<"\"quoted_attr\"">]} : () -> ()
+ emitc.call_opaque "f"() <{args = [#emitc.opaque<"\"quoted_attr\"">]}> : () -> ()
return
}
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 0d878e90cdf0c..e9b9987c9d73c 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -34,7 +34,7 @@ func.func @empty_constant() {
func.func @index_args_out_of_range_1() {
// expected-error @+1 {{'emitc.call_opaque' op index argument is out of range}}
- emitc.call_opaque "test" () {args = [0 : index]} : () -> ()
+ emitc.call_opaque "test" () <{args = [0 : index]}> : () -> ()
return
}
@@ -42,7 +42,7 @@ func.func @index_args_out_of_range_1() {
func.func @index_args_out_of_range_2(%arg : i32) {
// expected-error @+1 {{'emitc.call_opaque' op index argument is out of range}}
- emitc.call_opaque "test" (%arg, %arg) {args = [2 : index]} : (i32, i32) -> ()
+ emitc.call_opaque "test" (%arg, %arg) <{args = [2 : index]}> : (i32, i32) -> ()
return
}
@@ -58,7 +58,7 @@ func.func @empty_callee() {
func.func @nonetype_arg(%arg : i32) {
// expected-error @+1 {{'emitc.call_opaque' op array argument has no type}}
- emitc.call_opaque "nonetype_arg"(%arg) {args = [0 : index, [0, 1, 2]]} : (i32) -> i32
+ emitc.call_opaque "nonetype_arg"(%arg) <{args = [0 : index, [0, 1, 2]]}> : (i32) -> i32
return
}
@@ -66,7 +66,7 @@ func.func @nonetype_arg(%arg : i32) {
func.func @array_template_arg(%arg : i32) {
// expected-error @+1 {{'emitc.call_opaque' op template argument has invalid type}}
- emitc.call_opaque "nonetype_template_arg"(%arg) {template_args = [[0, 1, 2]]} : (i32) -> i32
+ emitc.call_opaque "nonetype_template_arg"(%arg) <{template_args = [[0, 1, 2]]}> : (i32) -> i32
return
}
@@ -74,7 +74,7 @@ func.func @array_template_arg(%arg : i32) {
func.func @dense_template_argument(%arg : i32) {
// expected-error @+1 {{'emitc.call_opaque' op template argument has invalid type}}
- emitc.call_opaque "dense_template_argument"(%arg) {template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]} : (i32) -> i32
+ emitc.call_opaque "dense_template_argument"(%arg) <{template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]}> : (i32) -> i32
return
}
@@ -88,6 +88,46 @@ func.func @array_result() {
// -----
+func.func @member_call_empty_callee(%arg0 : !emitc.opaque<"MyClass">) {
+ // expected-error @+1 {{'emitc.member_call_opaque' op callee must not be empty}}
+ emitc.member_call_opaque %arg0 "" () : !emitc.opaque<"MyClass">, () -> ()
+ return
+}
+
+// -----
+
+func.func @member_call_index_out_of_range(%arg0 : !emitc.opaque<"MyClass">) {
+ // expected-error @+1 {{'emitc.member_call_opaque' op index argument is out of range}}
+ emitc.member_call_opaque %arg0 "test" () <{args = [1 : index]}> : !emitc.opaque<"MyClass">, () -> ()
+ return
+}
+
+// -----
+
+func.func @member_call_array_result(%arg0 : !emitc.opaque<"MyClass">) {
+ // expected-error @+1 {{'emitc.member_call_opaque' op cannot return array type}}
+ emitc.member_call_opaque %arg0 "array_result"() : !emitc.opaque<"MyClass">, () -> !emitc.array<4xi32>
+ return
+}
+
+// -----
+
+func.func @member_call_nonetype_template_arg(%arg0 : !emitc.opaque<"MyClass">) {
+ // expected-error @+1 {{'emitc.member_call_opaque' op template argument has invalid type}}
+ emitc.member_call_opaque %arg0 "nonetype_template_arg"() <{template_args = [[0, 1, 2]]}> : !emitc.opaque<"MyClass">, () -> ()
+ return
+}
+
+// -----
+
+func.func @member_call_dense_template_argument(%arg0 : !emitc.opaque<"MyClass">) {
+ // expected-error @+1 {{'emitc.member_call_opaque' op template argument has invalid type}}
+ emitc.member_call_opaque %arg0 "dense_template_argument"() <{template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]}> : !emitc.opaque<"MyClass">, () -> ()
+ return
+}
+
+// -----
+
func.func @empty_operator() {
%0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<i32>
// expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}}
diff --git a/mlir/test/Dialect/EmitC/member_call_opaque.mlir b/mlir/test/Dialect/EmitC/member_call_opaque.mlir
new file mode 100644
index 0000000000000..6e64ac1ee3c7b
--- /dev/null
+++ b/mlir/test/Dialect/EmitC/member_call_opaque.mlir
@@ -0,0 +1,29 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+func.func @member_call(%arg0 : !emitc.opaque<"MyClass">) {
+ %0 = emitc.member_call_opaque %arg0 "method" () : !emitc.opaque<"MyClass">, () -> i32
+ return
+}
+// CHECK-LABEL: func @member_call
+// CHECK: emitc.member_call_opaque %arg0 "method"() : !emitc.opaque<"MyClass">, () -> i32
+
+func.func @member_call_args(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32) {
+ %0 = emitc.member_call_opaque %arg0 "method" (%arg1) : !emitc.opaque<"MyClass">, (i32) -> i32
+ return
+}
+// CHECK-LABEL: func @member_call_args
+// CHECK: emitc.member_call_opaque %arg0 "method"(%arg1) : !emitc.opaque<"MyClass">, (i32) -> i32
+
+func.func @member_call_template_args(%arg0 : !emitc.opaque<"MyClass">) {
+ %0 = emitc.member_call_opaque %arg0 "method" () <{template_args = [i32]}> : !emitc.opaque<"MyClass">, () -> i32
+ return
+}
+// CHECK-LABEL: func @member_call_template_args
+// CHECK: emitc.member_call_opaque %arg0 "method"() <{template_args = [i32]}> : !emitc.opaque<"MyClass">, () -> i32
+
+func.func @member_call_reorder(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32, %arg2 : i32) {
+ %0 = emitc.member_call_opaque %arg0 "method" (%arg1, %arg2) <{args = [1 : index, 0 : index]}> : !emitc.opaque<"MyClass">, (i32, i32) -> i32
+ return
+}
+// CHECK-LABEL: func @member_call_reorder
+// CHECK: emitc.member_call_opaque %arg0 "method"(%arg1, %arg2) <{args = [1 : index, 0 : index]}> : !emitc.opaque<"MyClass">, (i32, i32) -> i32
diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir
index 2f7544b5db096..82e8aa8d140c0 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -9,9 +9,9 @@ emitc.include "test.h"
// CHECK-LABEL: func @f(%{{.*}}: i32, %{{.*}}: !emitc.opaque<"int32_t">) {
func.func @f(%arg0: i32, %f: !emitc.opaque<"int32_t">) {
%1 = "emitc.call_opaque"() {callee = "blah"} : () -> i64
- emitc.call_opaque "foo" (%1) {args = [
+ emitc.call_opaque "foo" (%1) <{args = [
0 : index, dense<[0, 1]> : tensor<2xi32>, 0 : index
- ]} : (i64) -> ()
+ ]}> : (i64) -> ()
return
}
diff --git a/mlir/test/Target/Cpp/call.mlir b/mlir/test/Target/Cpp/call.mlir
index e3ac392f30b62..de279e667cac0 100644
--- a/mlir/test/Target/Cpp/call.mlir
+++ b/mlir/test/Target/Cpp/call.mlir
@@ -34,3 +34,33 @@ func.func @emitc_call_opaque_two_results() {
// CPP-DECLTOP-NEXT: int32_t [[V3:[^ ]*]];
// CPP-DECLTOP-NEXT: [[V1]] = 0;
// CPP-DECLTOP-NEXT: std::tie([[V2]], [[V3]]) = two_results();
+
+func.func @emitc_member_call(%arg0 : !emitc.opaque<"MyClass">, %arg1 : !emitc.ptr<!emitc.opaque<"MyClass">> ) {
+ %0 = emitc.member_call_opaque %arg0 "method" () : !emitc.opaque<"MyClass">, () -> i32
+ %1 = emitc.member_call_opaque %arg1 "ptr_method" () : !emitc.ptr<!emitc.opaque<"MyClass">>, () -> i32
+ return
+}
+// CPP-DEFAULT: void emitc_member_call(MyClass [[V0:[^ ]*]], MyClass* [[V1:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]].method();
+// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V1]]->ptr_method();
+
+func.func @emitc_member_call_args(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32) {
+ %0 = emitc.member_call_opaque %arg0 "method" (%arg1) : !emitc.opaque<"MyClass">, (i32) -> i32
+ return
+}
+// CPP-DEFAULT: void emitc_member_call_args(MyClass [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]].method([[V1]]);
+
+func.func @emitc_member_call_args_reorder(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32, %arg2 : i32) {
+ %0 = emitc.member_call_opaque %arg0 "method" (%arg1, %arg2) {args = [1 : index, 0 : index]} : !emitc.opaque<"MyClass">, (i32, i32) -> i32
+ return
+}
+// CPP-DEFAULT: void emitc_member_call_args_reorder(MyClass [[V0:[^ ]*]], int32_t [[V1:[^ ]*]], int32_t [[V2:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V0]].method([[V2]], [[V1]]);
+
+func.func @emitc_member_call_template_args(%arg0 : !emitc.opaque<"MyClass">) {
+ %0 = emitc.member_call_opaque %arg0 "method" () {template_args = [i32]} : !emitc.opaque<"MyClass">, () -> i32
+ return
+}
+// CPP-DEFAULT: void emitc_member_call_template_args(MyClass [[V0:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: int32_t [[V1:[^ ]*]] = [[V0]].method<int32_t>();
diff --git a/mlir/test/Target/Cpp/expressions.mlir b/mlir/test/Target/Cpp/expressions.mlir
index 7280377990cfc..7ea7affc86669 100644
--- a/mlir/test/Target/Cpp/expressions.mlir
+++ b/mlir/test/Target/Cpp/expressions.mlir
@@ -486,7 +486,7 @@ emitc.func @expression_with_load_and_call(%arg0: !emitc.ptr<i32>) -> i1 {
emitc.func @expression_with_call_opaque_with_args_array(%0 : i32, %1 : i32) {
%2 = expression %0, %1 : (i32, i32) -> i1 {
%3 = cmp lt, %0, %1 : (i32, i32) -> i1
- %4 = emitc.call_opaque "f"(%3) {"args" = [0: index]} : (i1) -> i1
+ %4 = emitc.call_opaque "f"(%3) {args = [0: index]} : (i1) -> i1
yield %4 : i1
}
return
More information about the Mlir-commits
mailing list