[Mlir-commits] [mlir] [mlir][emitc]: support method calls in CallOpaqueOp (PR #200057)
Jeremy Kun
llvmlistbot at llvm.org
Thu May 28 21:11:28 PDT 2026
https://github.com/j2kun updated https://github.com/llvm/llvm-project/pull/200057
>From fecadd4be5238f03563c5439b7fbfa606428d736 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Wed, 27 May 2026 14:10:04 -0700
Subject: [PATCH 1/7] [mlir][emitc]: support method calls in CallOpaqueOp
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 22 +++++++++++++-
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 3 ++
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 33 ++++++++++++++++++---
mlir/test/Dialect/EmitC/invalid_ops.mlir | 8 +++++
mlir/test/Target/Cpp/call.mlir | 24 +++++++++++++++
5 files changed, 85 insertions(+), 5 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index e1ccf29ada660..dc83b85993a99 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -324,6 +324,19 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
- integer value of index type refers to an operand;
- attribute which will get lowered to constant value in call;
+ If `is_member_call` is true, the operation represents a member call. The
+ first operand is treated as the receiver and emitted before the member
+ access operator (`.` or `->`).
+
+ The `args` attribute can be used to override the default operand order and
+ to mix operands with attributes. If `args` is present, it specifies the
+ arguments passed to the call in parentheses.
+
+ If `args` is not present:
+ - If `is_member_call` is true, the first operand is the receiver, and the
+ remaining operands are passed as arguments.
+ - If `is_member_call` is false, all operands are passed as arguments.
+
Example:
```mlir
@@ -332,12 +345,19 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
// Generic form of the same operation.
%0 = "emitc.call_opaque"() {callee = "foo"} : () -> i32
+
+ // Member call
+ %1 = emitc.call_opaque "method" (%arg0, %arg1) {is_member_call = true} : (!emitc.opaque<"MyClass">, i32) -> i32
+
+ // Member call with args attribute
+ %2 = emitc.call_opaque "method" (%arg0, %arg1) {is_member_call = true, args = [1 : index]} : (!emitc.opaque<"MyClass">, i32) -> i32
```
}];
let arguments = (ins
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,
+ DefaultValuedAttr<BoolAttr, "false">:$is_member_call,
Variadic<EmitCType>:$operands
);
let results = (outs Variadic<EmitCType>);
@@ -349,7 +369,7 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
CArg<"::mlir::ArrayAttr", "{}">:$args,
CArg<"::mlir::ArrayAttr", "{}">:$template_args), [{
build($_builder, $_state, resultTypes, callee, args, template_args,
- operands);
+ false, operands);
}]
>
];
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 36394e67008da..cd27a97941e10 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -345,6 +345,9 @@ LogicalResult emitc::CallOpaqueOp::verify() {
if (getCallee().empty())
return emitOpError("callee must not be empty");
+ if (getIsMemberCall() && getNumOperands() == 0)
+ return emitOpError("member call requires at least one operand (receiver)");
+
if (std::optional<ArrayAttr> argsAttr = getArgs()) {
for (Attribute arg : *argsAttr) {
auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index a670fb152a1e5..71ed42b7d5aa2 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -916,6 +916,23 @@ static LogicalResult printOperation(CppEmitter &emitter,
if (failed(emitter.emitAssignPrefix(op)))
return failure();
+
+ bool isMemberCall = callOpaqueOp.getIsMemberCall();
+
+ if (isMemberCall) {
+ Value receiver = op.getOperand(0);
+ bool isPtr = llvm::isa<emitc::PointerType>(receiver.getType());
+
+ if (failed(emitter.emitOperand(receiver)))
+ return failure();
+
+ if (isPtr) {
+ os << "->";
+ } else {
+ os << ".";
+ }
+ }
+
os << callOpaqueOp.getCallee();
// Template arguments can't refer to SSA values and as such the template
@@ -951,10 +968,18 @@ static LogicalResult printOperation(CppEmitter &emitter,
os << "(";
- LogicalResult emittedArgs =
- callOpaqueOp.getArgs()
- ? interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs)
- : emitter.emitOperands(op);
+ LogicalResult emittedArgs = success();
+ if (callOpaqueOp.getArgs()) {
+ emittedArgs =
+ interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs);
+ } else if (isMemberCall) {
+ emittedArgs = interleaveCommaWithError(
+ llvm::seq<size_t>(1, op.getNumOperands()), os,
+ [&](size_t i) { return emitter.emitOperand(op.getOperand(i)); });
+ } else {
+ emittedArgs = emitter.emitOperands(op);
+ }
+
if (failed(emittedArgs))
return failure();
os << ")";
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 0d878e90cdf0c..79f2c0b210be9 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -48,6 +48,14 @@ func.func @index_args_out_of_range_2(%arg : i32) {
// -----
+func.func @member_call_no_operands() {
+ // expected-error @+1 {{'emitc.call_opaque' op member call requires at least one operand (receiver)}}
+ emitc.call_opaque "method" () {is_member_call = true} : () -> ()
+ return
+}
+
+// -----
+
func.func @empty_callee() {
// expected-error @+1 {{'emitc.call_opaque' op callee must not be empty}}
emitc.call_opaque "" () : () -> ()
diff --git a/mlir/test/Target/Cpp/call.mlir b/mlir/test/Target/Cpp/call.mlir
index e3ac392f30b62..c447b149f84c3 100644
--- a/mlir/test/Target/Cpp/call.mlir
+++ b/mlir/test/Target/Cpp/call.mlir
@@ -34,3 +34,27 @@ 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_call_opaque_member(%arg0 : !emitc.opaque<"MyClass">, %arg1 : !emitc.ptr<!emitc.opaque<"MyClass">>) {
+ %0 = emitc.call_opaque "method" (%arg0) {is_member_call = true} : (!emitc.opaque<"MyClass">) -> i32
+ %1 = emitc.call_opaque "ptr_method" (%arg1) {is_member_call = true} : (!emitc.ptr<!emitc.opaque<"MyClass">>) -> i32
+ return
+}
+// CPP-DEFAULT: void emitc_call_opaque_member(MyClass [[V0:[^ ]*]], MyClass* [[V1:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]].method();
+// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V1]]->ptr_method();
+
+func.func @emitc_call_opaque_member_args(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32, %arg2 : i32) {
+ %0 = emitc.call_opaque "method" (%arg0, %arg1, %arg2) {is_member_call = true} : (!emitc.opaque<"MyClass">, i32, i32) -> i32
+ %1 = emitc.call_opaque "method_with_args" (%arg0, %arg1, %arg2) {is_member_call = true, args = [1 : index, 2 : index]} : (!emitc.opaque<"MyClass">, i32, i32) -> i32
+ return
+}
+// CPP-DEFAULT: void emitc_call_opaque_member_args(MyClass [[V0:[^ ]*]], int32_t [[V1:[^ ]*]], int32_t [[V2:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V0]].method([[V1]], [[V2]]);
+// CPP-DEFAULT-NEXT: int32_t [[V4:[^ ]*]] = [[V0]].method_with_args([[V1]], [[V2]]);
+
+// CPP-DECLTOP: void emitc_call_opaque_member_args(MyClass [[V0:[^ ]*]], int32_t [[V1:[^ ]*]], int32_t [[V2:[^ ]*]]) {
+// CPP-DECLTOP-NEXT: int32_t [[V3:[^ ]*]];
+// CPP-DECLTOP-NEXT: int32_t [[V4:[^ ]*]];
+// CPP-DECLTOP-NEXT: [[V3]] = [[V0]].method([[V1]], [[V2]]);
+// CPP-DECLTOP-NEXT: [[V4]] = [[V0]].method_with_args([[V1]], [[V2]]);
>From de71b7b2705e0a06cfe453f43cf67a226e62d629 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 28 May 2026 10:50:52 -0700
Subject: [PATCH 2/7] Revert "[mlir][emitc]: support method calls in
CallOpaqueOp"
This reverts commit 54c78bae731103d2719514ae893ab5e72596ec04.
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 22 +-------------
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 3 --
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 33 +++------------------
mlir/test/Dialect/EmitC/invalid_ops.mlir | 8 -----
mlir/test/Target/Cpp/call.mlir | 24 ---------------
5 files changed, 5 insertions(+), 85 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index dc83b85993a99..e1ccf29ada660 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -324,19 +324,6 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
- integer value of index type refers to an operand;
- attribute which will get lowered to constant value in call;
- If `is_member_call` is true, the operation represents a member call. The
- first operand is treated as the receiver and emitted before the member
- access operator (`.` or `->`).
-
- The `args` attribute can be used to override the default operand order and
- to mix operands with attributes. If `args` is present, it specifies the
- arguments passed to the call in parentheses.
-
- If `args` is not present:
- - If `is_member_call` is true, the first operand is the receiver, and the
- remaining operands are passed as arguments.
- - If `is_member_call` is false, all operands are passed as arguments.
-
Example:
```mlir
@@ -345,19 +332,12 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
// Generic form of the same operation.
%0 = "emitc.call_opaque"() {callee = "foo"} : () -> i32
-
- // Member call
- %1 = emitc.call_opaque "method" (%arg0, %arg1) {is_member_call = true} : (!emitc.opaque<"MyClass">, i32) -> i32
-
- // Member call with args attribute
- %2 = emitc.call_opaque "method" (%arg0, %arg1) {is_member_call = true, args = [1 : index]} : (!emitc.opaque<"MyClass">, i32) -> i32
```
}];
let arguments = (ins
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,
- DefaultValuedAttr<BoolAttr, "false">:$is_member_call,
Variadic<EmitCType>:$operands
);
let results = (outs Variadic<EmitCType>);
@@ -369,7 +349,7 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
CArg<"::mlir::ArrayAttr", "{}">:$args,
CArg<"::mlir::ArrayAttr", "{}">:$template_args), [{
build($_builder, $_state, resultTypes, callee, args, template_args,
- false, operands);
+ operands);
}]
>
];
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index cd27a97941e10..36394e67008da 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -345,9 +345,6 @@ LogicalResult emitc::CallOpaqueOp::verify() {
if (getCallee().empty())
return emitOpError("callee must not be empty");
- if (getIsMemberCall() && getNumOperands() == 0)
- return emitOpError("member call requires at least one operand (receiver)");
-
if (std::optional<ArrayAttr> argsAttr = getArgs()) {
for (Attribute arg : *argsAttr) {
auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 71ed42b7d5aa2..a670fb152a1e5 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -916,23 +916,6 @@ static LogicalResult printOperation(CppEmitter &emitter,
if (failed(emitter.emitAssignPrefix(op)))
return failure();
-
- bool isMemberCall = callOpaqueOp.getIsMemberCall();
-
- if (isMemberCall) {
- Value receiver = op.getOperand(0);
- bool isPtr = llvm::isa<emitc::PointerType>(receiver.getType());
-
- if (failed(emitter.emitOperand(receiver)))
- return failure();
-
- if (isPtr) {
- os << "->";
- } else {
- os << ".";
- }
- }
-
os << callOpaqueOp.getCallee();
// Template arguments can't refer to SSA values and as such the template
@@ -968,18 +951,10 @@ static LogicalResult printOperation(CppEmitter &emitter,
os << "(";
- LogicalResult emittedArgs = success();
- if (callOpaqueOp.getArgs()) {
- emittedArgs =
- interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs);
- } else if (isMemberCall) {
- emittedArgs = interleaveCommaWithError(
- llvm::seq<size_t>(1, op.getNumOperands()), os,
- [&](size_t i) { return emitter.emitOperand(op.getOperand(i)); });
- } else {
- emittedArgs = emitter.emitOperands(op);
- }
-
+ LogicalResult emittedArgs =
+ callOpaqueOp.getArgs()
+ ? interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs)
+ : emitter.emitOperands(op);
if (failed(emittedArgs))
return failure();
os << ")";
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 79f2c0b210be9..0d878e90cdf0c 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -48,14 +48,6 @@ func.func @index_args_out_of_range_2(%arg : i32) {
// -----
-func.func @member_call_no_operands() {
- // expected-error @+1 {{'emitc.call_opaque' op member call requires at least one operand (receiver)}}
- emitc.call_opaque "method" () {is_member_call = true} : () -> ()
- return
-}
-
-// -----
-
func.func @empty_callee() {
// expected-error @+1 {{'emitc.call_opaque' op callee must not be empty}}
emitc.call_opaque "" () : () -> ()
diff --git a/mlir/test/Target/Cpp/call.mlir b/mlir/test/Target/Cpp/call.mlir
index c447b149f84c3..e3ac392f30b62 100644
--- a/mlir/test/Target/Cpp/call.mlir
+++ b/mlir/test/Target/Cpp/call.mlir
@@ -34,27 +34,3 @@ 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_call_opaque_member(%arg0 : !emitc.opaque<"MyClass">, %arg1 : !emitc.ptr<!emitc.opaque<"MyClass">>) {
- %0 = emitc.call_opaque "method" (%arg0) {is_member_call = true} : (!emitc.opaque<"MyClass">) -> i32
- %1 = emitc.call_opaque "ptr_method" (%arg1) {is_member_call = true} : (!emitc.ptr<!emitc.opaque<"MyClass">>) -> i32
- return
-}
-// CPP-DEFAULT: void emitc_call_opaque_member(MyClass [[V0:[^ ]*]], MyClass* [[V1:[^ ]*]]) {
-// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = [[V0]].method();
-// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V1]]->ptr_method();
-
-func.func @emitc_call_opaque_member_args(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32, %arg2 : i32) {
- %0 = emitc.call_opaque "method" (%arg0, %arg1, %arg2) {is_member_call = true} : (!emitc.opaque<"MyClass">, i32, i32) -> i32
- %1 = emitc.call_opaque "method_with_args" (%arg0, %arg1, %arg2) {is_member_call = true, args = [1 : index, 2 : index]} : (!emitc.opaque<"MyClass">, i32, i32) -> i32
- return
-}
-// CPP-DEFAULT: void emitc_call_opaque_member_args(MyClass [[V0:[^ ]*]], int32_t [[V1:[^ ]*]], int32_t [[V2:[^ ]*]]) {
-// CPP-DEFAULT-NEXT: int32_t [[V3:[^ ]*]] = [[V0]].method([[V1]], [[V2]]);
-// CPP-DEFAULT-NEXT: int32_t [[V4:[^ ]*]] = [[V0]].method_with_args([[V1]], [[V2]]);
-
-// CPP-DECLTOP: void emitc_call_opaque_member_args(MyClass [[V0:[^ ]*]], int32_t [[V1:[^ ]*]], int32_t [[V2:[^ ]*]]) {
-// CPP-DECLTOP-NEXT: int32_t [[V3:[^ ]*]];
-// CPP-DECLTOP-NEXT: int32_t [[V4:[^ ]*]];
-// CPP-DECLTOP-NEXT: [[V3]] = [[V0]].method([[V1]], [[V2]]);
-// CPP-DECLTOP-NEXT: [[V4]] = [[V0]].method_with_args([[V1]], [[V2]]);
>From 4c92de38ef839e276c32c2d848833496b8c37228 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 28 May 2026 12:26:50 -0700
Subject: [PATCH 3/7] [mlir][emitc]: add MemberCallOpaque op
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 33 +++++++++
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 36 +++++++++
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 74 ++++++++++++++++++-
mlir/test/Dialect/EmitC/invalid_ops.mlir | 40 ++++++++++
.../Dialect/EmitC/member_call_opaque.mlir | 29 ++++++++
mlir/test/Target/Cpp/call.mlir | 30 ++++++++
6 files changed, 238 insertions(+), 4 deletions(-)
create mode 100644 mlir/test/Dialect/EmitC/member_call_opaque.mlir
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index e1ccf29ada660..c0a9b4523256d 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -360,6 +360,39 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
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>:$args_operands
+ );
+ let results = (outs Variadic<EmitCType>);
+
+ let assemblyFormat = [{
+ $receiver $callee `(` $args_operands `)` attr-dict `:` type($receiver) `,` functional-type($args_operands, results)
+ }];
+ let hasVerifier = 1;
+}
+
def EmitC_CastOp : EmitC_Op<"cast",
[CExpressionInterface,
DeclareOpInterfaceMethods<CastOpInterface>]> {
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 36394e67008da..80f856f5a1234 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -378,6 +378,42 @@ LogicalResult emitc::CallOpaqueOp::verify() {
return success();
}
+LogicalResult emitc::MemberCallOpaqueOp::verify() {
+ // Callee must not be empty.
+ if (getCallee().empty())
+ return emitOpError("callee must not be empty");
+
+ if (std::optional<ArrayAttr> argsAttr = getArgs()) {
+ for (Attribute arg : *argsAttr) {
+ 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..args_operands.size).
+ if ((index < 0) ||
+ (index >= static_cast<int64_t>(getArgsOperands().size())))
+ return emitOpError("index argument is out of range");
+
+ } else if (llvm::isa<ArrayAttr>(arg)) {
+ return emitOpError("array argument has no type");
+ }
+ }
+ }
+
+ if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {
+ for (Attribute tArg : *templateArgsAttr) {
+ if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
+ return emitOpError("template argument has invalid type");
+ }
+ }
+
+ if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) {
+ return emitOpError() << "cannot return array type";
+ }
+
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// ConstantOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index a670fb152a1e5..7ab1062bf0820 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -961,6 +961,71 @@ static LogicalResult printOperation(CppEmitter &emitter,
return success();
}
+static LogicalResult
+printOperation(CppEmitter &emitter,
+ emitc::MemberCallOpaqueOp memberCallOpaqueOp) {
+ raw_ostream &os = emitter.ostream();
+ Operation &op = *memberCallOpaqueOp.getOperation();
+
+ if (failed(emitter.emitAssignPrefix(op)))
+ return failure();
+
+ Value receiver = memberCallOpaqueOp.getReceiver();
+ if (failed(emitter.emitOperand(receiver)))
+ return failure();
+
+ if (llvm::isa<emitc::PointerType>(receiver.getType()))
+ os << "->";
+ else
+ os << ".";
+
+ os << memberCallOpaqueOp.getCallee();
+
+ auto emitTemplateArgs = [&](Attribute attr) -> LogicalResult {
+ return emitter.emitAttribute(op.getLoc(), attr);
+ };
+
+ if (memberCallOpaqueOp.getTemplateArgs()) {
+ os << "<";
+ if (failed(interleaveCommaWithError(*memberCallOpaqueOp.getTemplateArgs(),
+ os, emitTemplateArgs)))
+ return failure();
+ os << ">";
+ }
+
+ auto emitArgs = [&](Attribute attr) -> LogicalResult {
+ if (auto t = dyn_cast<IntegerAttr>(attr)) {
+ if (t.getType().isIndex()) {
+ int64_t idx = t.getInt();
+ Value operand = op.getOperand(idx + 1);
+ return emitter.emitOperand(operand, /*isInBrackets=*/true);
+ }
+ }
+ if (failed(emitter.emitAttribute(op.getLoc(), attr)))
+ return failure();
+
+ return success();
+ };
+
+ os << "(";
+
+ LogicalResult emittedArgs = success();
+ if (memberCallOpaqueOp.getArgs()) {
+ emittedArgs =
+ interleaveCommaWithError(*memberCallOpaqueOp.getArgs(), os, emitArgs);
+ } else {
+ auto operands = op.getOperands().drop_front(1);
+ emittedArgs = interleaveCommaWithError(operands, os, [&](Value operand) {
+ return emitter.emitOperand(operand, /*isInBrackets=*/true);
+ });
+ }
+
+ if (failed(emittedArgs))
+ return failure();
+ os << ")";
+ return success();
+}
+
static LogicalResult printOperation(CppEmitter &emitter,
emitc::ApplyOp applyOp) {
raw_ostream &os = emitter.ostream();
@@ -1875,10 +1940,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/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 0d878e90cdf0c..1c15af89bdbcd 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -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..e7a0a0be5eef6
--- /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 = [0 : index, 2 : index, 1 : index]} : !emitc.opaque<"MyClass">, (i32, i32) -> i32
+ return
+}
+// CHECK-LABEL: func @member_call_reorder
+// CHECK: emitc.member_call_opaque %arg0 "method"(%arg1, %arg2) {args = [0 : index, 2 : index, 1 : index]} : !emitc.opaque<"MyClass">, (i32, i32) -> i32
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>();
>From d332e89d3ae73655f90e1c96e6be85e4dd44c903 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 28 May 2026 13:45:00 -0700
Subject: [PATCH 4/7] refactor common logic among verifier and emitter
---
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 81 +++++-------
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 120 +++++++-----------
.../Dialect/EmitC/member_call_opaque.mlir | 4 +-
3 files changed, 78 insertions(+), 127 deletions(-)
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 80f856f5a1234..d57bf5e2faf55 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -340,78 +340,55 @@ 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::MemberCallOpaqueOp::verify() {
- // Callee must not be empty.
- if (getCallee().empty())
- return emitOpError("callee must not be empty");
-
- if (std::optional<ArrayAttr> argsAttr = getArgs()) {
- for (Attribute arg : *argsAttr) {
- 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..args_operands.size).
- if ((index < 0) ||
- (index >= static_cast<int64_t>(getArgsOperands().size())))
- return emitOpError("index argument is out of range");
-
- } else if (llvm::isa<ArrayAttr>(arg)) {
- return emitOpError("array argument has no type");
- }
- }
- }
-
- if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {
- for (Attribute tArg : *templateArgsAttr) {
- if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))
- return emitOpError("template argument has invalid type");
- }
- }
-
- if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) {
- return emitOpError() << "cannot return array type";
- }
+LogicalResult emitc::CallOpaqueOp::verify() {
+ return verifyOpaqueCallCommon(getOperation(), getCallee(), getArgs(),
+ getTemplateArgs(), getResultTypes(),
+ getNumOperands());
+}
- return success();
+LogicalResult emitc::MemberCallOpaqueOp::verify() {
+ return verifyOpaqueCallCommon(getOperation(), getCallee(), getArgs(),
+ getTemplateArgs(), getResultTypes(),
+ getArgsOperands().size());
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 7ab1062bf0820..595ff07f99455 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -909,86 +909,40 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::CallOp callOp) {
return printCallOperation(emitter, operation, callee);
}
-static LogicalResult printOperation(CppEmitter &emitter,
- emitc::CallOpaqueOp callOpaqueOp) {
- raw_ostream &os = emitter.ostream();
- Operation &op = *callOpaqueOp.getOperation();
-
- if (failed(emitter.emitAssignPrefix(op)))
- return failure();
- os << callOpaqueOp.getCallee();
-
- // 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
- // don't need to handle integer attributes specially like we do for arguments
- // - see below.
- auto emitTemplateArgs = [&](Attribute attr) -> LogicalResult {
- return emitter.emitAttribute(op.getLoc(), attr);
- };
-
- if (callOpaqueOp.getTemplateArgs()) {
- os << "<";
- if (failed(interleaveCommaWithError(*callOpaqueOp.getTemplateArgs(), 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);
- }
- }
- if (failed(emitter.emitAttribute(op.getLoc(), attr)))
- return failure();
-
- return success();
- };
-
- os << "(";
-
- LogicalResult emittedArgs =
- callOpaqueOp.getArgs()
- ? interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs)
- : emitter.emitOperands(op);
- if (failed(emittedArgs))
- return failure();
- os << ")";
- return success();
-}
-
static LogicalResult
-printOperation(CppEmitter &emitter,
- emitc::MemberCallOpaqueOp memberCallOpaqueOp) {
+printOpaqueCallCommon(CppEmitter &emitter, Operation &op, StringRef callee,
+ std::optional<ArrayAttr> templateArgs,
+ std::optional<ArrayAttr> args, bool isMemberCall,
+ Value receiver = nullptr) {
raw_ostream &os = emitter.ostream();
- Operation &op = *memberCallOpaqueOp.getOperation();
if (failed(emitter.emitAssignPrefix(op)))
return failure();
- Value receiver = memberCallOpaqueOp.getReceiver();
- if (failed(emitter.emitOperand(receiver)))
- return failure();
+ 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 << ".";
+ if (llvm::isa<emitc::PointerType>(receiver.getType()))
+ os << "->";
+ else
+ os << ".";
+ }
- os << memberCallOpaqueOp.getCallee();
+ 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
+ // don't need to handle integer attributes specially like we do for arguments
+ // - see below.
auto emitTemplateArgs = [&](Attribute attr) -> LogicalResult {
return emitter.emitAttribute(op.getLoc(), attr);
};
- if (memberCallOpaqueOp.getTemplateArgs()) {
+ if (templateArgs) {
os << "<";
- if (failed(interleaveCommaWithError(*memberCallOpaqueOp.getTemplateArgs(),
- os, emitTemplateArgs)))
+ if (failed(interleaveCommaWithError(*templateArgs, os, emitTemplateArgs)))
return failure();
os << ">";
}
@@ -997,8 +951,9 @@ printOperation(CppEmitter &emitter,
if (auto t = dyn_cast<IntegerAttr>(attr)) {
if (t.getType().isIndex()) {
int64_t idx = t.getInt();
- Value operand = op.getOperand(idx + 1);
- return emitter.emitOperand(operand, /*isInBrackets=*/true);
+ // Shift index by 1 for member calls to skip the receiver operand.
+ Value operand = op.getOperand(isMemberCall ? idx + 1 : idx);
+ return emitter.emitOperand(operand, /*isInBrackets=*/false);
}
}
if (failed(emitter.emitAttribute(op.getLoc(), attr)))
@@ -1010,22 +965,41 @@ printOperation(CppEmitter &emitter,
os << "(";
LogicalResult emittedArgs = success();
- if (memberCallOpaqueOp.getArgs()) {
- emittedArgs =
- interleaveCommaWithError(*memberCallOpaqueOp.getArgs(), os, emitArgs);
+ if (args) {
+ emittedArgs = interleaveCommaWithError(*args, os, emitArgs);
} else {
- auto operands = op.getOperands().drop_front(1);
+ auto operands = op.getOperands();
+ if (isMemberCall)
+ operands = operands.drop_front(1);
+
emittedArgs = interleaveCommaWithError(operands, 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.getOperation(), callOpaqueOp.getCallee(),
+ callOpaqueOp.getTemplateArgs(), callOpaqueOp.getArgs(),
+ /*isMemberCall=*/false);
+}
+
+static LogicalResult
+printOperation(CppEmitter &emitter,
+ emitc::MemberCallOpaqueOp memberCallOpaqueOp) {
+ return printOpaqueCallCommon(
+ emitter, *memberCallOpaqueOp.getOperation(),
+ memberCallOpaqueOp.getCallee(), memberCallOpaqueOp.getTemplateArgs(),
+ memberCallOpaqueOp.getArgs(),
+ /*isMemberCall=*/true, memberCallOpaqueOp.getReceiver());
+}
+
static LogicalResult printOperation(CppEmitter &emitter,
emitc::ApplyOp applyOp) {
raw_ostream &os = emitter.ostream();
diff --git a/mlir/test/Dialect/EmitC/member_call_opaque.mlir b/mlir/test/Dialect/EmitC/member_call_opaque.mlir
index e7a0a0be5eef6..2413da6f740d2 100644
--- a/mlir/test/Dialect/EmitC/member_call_opaque.mlir
+++ b/mlir/test/Dialect/EmitC/member_call_opaque.mlir
@@ -22,8 +22,8 @@ func.func @member_call_template_args(%arg0 : !emitc.opaque<"MyClass">) {
// 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 = [0 : index, 2 : index, 1 : index]} : !emitc.opaque<"MyClass">, (i32, i32) -> 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 = [0 : index, 2 : index, 1 : index]} : !emitc.opaque<"MyClass">, (i32, i32) -> i32
+// CHECK: emitc.member_call_opaque %arg0 "method"(%arg1, %arg2) {args = [1 : index, 0 : index]} : !emitc.opaque<"MyClass">, (i32, i32) -> i32
>From ae0430003090932020d785bd7ce9185f22f81152 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 28 May 2026 20:31:00 -0700
Subject: [PATCH 5/7] use prop-dict attr-dict on both member_call_opaque and
call_opaque
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 4 ++--
mlir/test/Dialect/EmitC/member_call_opaque.mlir | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index c0a9b4523256d..c15e8b415f83d 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -355,7 +355,7 @@ def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", [CExpressionInterface]> {
];
let assemblyFormat = [{
- $callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
+ $callee `(` $operands `)` prop-dict attr-dict `:` functional-type($operands, results)
}];
let hasVerifier = 1;
}
@@ -388,7 +388,7 @@ def EmitC_MemberCallOpaqueOp : EmitC_Op<"member_call_opaque", [CExpressionInterf
let results = (outs Variadic<EmitCType>);
let assemblyFormat = [{
- $receiver $callee `(` $args_operands `)` attr-dict `:` type($receiver) `,` functional-type($args_operands, results)
+ $receiver $callee `(` $args_operands `)` prop-dict attr-dict `:` type($receiver) `,` functional-type($args_operands, results)
}];
let hasVerifier = 1;
}
diff --git a/mlir/test/Dialect/EmitC/member_call_opaque.mlir b/mlir/test/Dialect/EmitC/member_call_opaque.mlir
index 2413da6f740d2..6e64ac1ee3c7b 100644
--- a/mlir/test/Dialect/EmitC/member_call_opaque.mlir
+++ b/mlir/test/Dialect/EmitC/member_call_opaque.mlir
@@ -15,15 +15,15 @@ func.func @member_call_args(%arg0 : !emitc.opaque<"MyClass">, %arg1 : i32) {
// 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
+ %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
+// 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
+ %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
+// CHECK: emitc.member_call_opaque %arg0 "method"(%arg1, %arg2) <{args = [1 : index, 0 : index]}> : !emitc.opaque<"MyClass">, (i32, i32) -> i32
>From 1c5859961ea05b253be29be5080c1890fd994f0e Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 28 May 2026 20:38:34 -0700
Subject: [PATCH 6/7] update tests to match new property syntax
---
mlir/test/Dialect/EmitC/attrs.mlir | 4 ++--
mlir/test/Dialect/EmitC/invalid_ops.mlir | 16 ++++++++--------
mlir/test/Dialect/EmitC/ops.mlir | 4 ++--
mlir/test/Target/Cpp/expressions.mlir | 2 +-
4 files changed, 13 insertions(+), 13 deletions(-)
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 1c15af89bdbcd..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
}
@@ -98,7 +98,7 @@ func.func @member_call_empty_callee(%arg0 : !emitc.opaque<"MyClass">) {
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">, () -> ()
+ emitc.member_call_opaque %arg0 "test" () <{args = [1 : index]}> : !emitc.opaque<"MyClass">, () -> ()
return
}
@@ -114,7 +114,7 @@ func.func @member_call_array_result(%arg0 : !emitc.opaque<"MyClass">) {
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">, () -> ()
+ emitc.member_call_opaque %arg0 "nonetype_template_arg"() <{template_args = [[0, 1, 2]]}> : !emitc.opaque<"MyClass">, () -> ()
return
}
@@ -122,7 +122,7 @@ func.func @member_call_nonetype_template_arg(%arg0 : !emitc.opaque<"MyClass">) {
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">, () -> ()
+ emitc.member_call_opaque %arg0 "dense_template_argument"() <{template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]}> : !emitc.opaque<"MyClass">, () -> ()
return
}
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/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
>From f6e7d317baa0fc6a4e1a8de744694ba383dc0a58 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Thu, 28 May 2026 21:07:34 -0700
Subject: [PATCH 7/7] more syntax updates for MemRefToEmitC tests
---
.../MemRefToEmitC/memref-to-emitc-alloc-copy.mlir | 8 ++++----
.../MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir | 12 ++++++------
.../memref-to-emitc-alloc-load-store.mlir | 4 ++--
.../MemRefToEmitC/memref-to-emitc-copy.mlir | 2 +-
4 files changed, 13 insertions(+), 13 deletions(-)
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) -> ()
More information about the Mlir-commits
mailing list