[Mlir-commits] [mlir] [mlir][EmitC] Add member access ops (PR #98460)
Marius Brehler
llvmlistbot at llvm.org
Sat Jul 13 02:57:42 PDT 2024
https://github.com/marbre updated https://github.com/llvm/llvm-project/pull/98460
>From a3db5faf7068ac470a6833adaaa2b861eb6ae5f1 Mon Sep 17 00:00:00 2001
From: Marius Brehler <marius.brehler at gmail.com>
Date: Sat, 13 Jul 2024 11:58:25 +0200
Subject: [PATCH] [mlir][EmitC] Add member access ops
This adds an `emitc.member` and `emitc.member_of_ptr` operation for the
corresponding member access operators. Furthermore, `emitc.assign` is
adjusted to be used with the member acces operators.
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 42 +++++++++++++++++++++
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 7 ++--
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 34 ++++++++++++++++-
mlir/test/Dialect/EmitC/invalid_ops.mlir | 18 ++++++++-
mlir/test/Dialect/EmitC/ops.mlir | 7 ++++
mlir/test/Target/Cpp/member.mlir | 34 +++++++++++++++++
6 files changed, 136 insertions(+), 6 deletions(-)
create mode 100644 mlir/test/Target/Cpp/member.mlir
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 452302c565139..626b0576efd9c 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -908,6 +908,48 @@ def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpression]> {
let hasVerifier = 1;
}
+def EmitC_MemberOp : EmitC_Op<"member"> {
+ let summary = "Member operation";
+ let description = [{
+ With the `member` operation the member access operator `.` can be
+ applied.
+
+ Example:
+
+ ```mlir
+ %0 = "emitc.member" (%arg0) {member = "a"}
+ : (!emitc.opaque<"mystruct">) -> i32
+ ```
+ }];
+
+ let arguments = (ins
+ Arg<StrAttr, "the member to access">:$member,
+ EmitC_OpaqueType:$operand
+ );
+ let results = (outs EmitCType);
+}
+
+def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> {
+ let summary = "Member of pointer operation";
+ let description = [{
+ With the `member_of_ptr` operation the member access operator `->`
+ can be applied.
+
+ Example:
+
+ ```mlir
+ %0 = "emitc.member_of_ptr" (%arg0) {member = "a"}
+ : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
+ ```
+ }];
+
+ let arguments = (ins
+ Arg<StrAttr, "the member to access">:$member,
+ AnyTypeOf<[EmitC_OpaqueType,EmitC_PointerType]>:$operand
+ );
+ let results = (outs EmitCType);
+}
+
def EmitC_ConditionalOp : EmitC_Op<"conditional",
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpression]> {
let summary = "Conditional (ternary) operation";
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 9f99eb1233cb1..70e3e728e0195 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -213,10 +213,11 @@ LogicalResult emitc::AssignOp::verify() {
Value variable = getVar();
Operation *variableDef = variable.getDefiningOp();
if (!variableDef ||
- !llvm::isa<emitc::GetGlobalOp, emitc::SubscriptOp, emitc::VariableOp>(
- variableDef))
+ !llvm::isa<emitc::GetGlobalOp, emitc::MemberOp, emitc::MemberOfPtrOp,
+ emitc::SubscriptOp, emitc::VariableOp>(variableDef))
return emitOpError() << "requires first operand (" << variable
- << ") to be a get_global, subscript or variable";
+ << ") to be a get_global, member, member of pointer, "
+ "subscript or variable";
Value value = getValue();
if (variable.getType() != value.getType())
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index eda8d5c9ad8cb..1dadb9dd691e7 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -183,6 +183,12 @@ struct CppEmitter {
// Returns the textual representation of a subscript operation.
std::string getSubscriptName(emitc::SubscriptOp op);
+ // Returns the textual representation of a member (of object) operation.
+ std::string createMemberAccess(emitc::MemberOp op);
+
+ // Returns the textual representation of a member of pointer operation.
+ std::string createMemberAccess(emitc::MemberOfPtrOp op);
+
/// Return the existing or a new label of a Block.
StringRef getOrCreateName(Block &block);
@@ -278,8 +284,8 @@ struct CppEmitter {
/// Determine whether expression \p op should be emitted in a deferred way.
static bool hasDeferredEmission(Operation *op) {
- return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp,
- emitc::SubscriptOp>(op);
+ return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
+ emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
}
/// Determine whether expression \p expressionOp should be emitted inline, i.e.
@@ -1125,6 +1131,22 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
return out;
}
+std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
+ std::string out;
+ llvm::raw_string_ostream ss(out);
+ ss << getOrCreateName(op.getOperand());
+ ss << "." << op.getMember();
+ return out;
+}
+
+std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
+ std::string out;
+ llvm::raw_string_ostream ss(out);
+ ss << getOrCreateName(op.getOperand());
+ ss << "->" << op.getMember();
+ return out;
+}
+
void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) {
if (!valueMapper.count(value))
valueMapper.insert(value, str.str());
@@ -1501,6 +1523,14 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
cacheDeferredOpResult(op.getResult(), op.getValue());
return success();
})
+ .Case<emitc::MemberOp>([&](auto op) {
+ cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
+ return success();
+ })
+ .Case<emitc::MemberOfPtrOp>([&](auto op) {
+ cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
+ return success();
+ })
.Case<emitc::SubscriptOp>([&](auto op) {
cacheDeferredOpResult(op.getResult(), getSubscriptName(op));
return success();
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index e9b11421882f9..4181b726593e4 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -235,7 +235,7 @@ func.func @test_misplaced_yield() {
// -----
func.func @test_assign_to_non_variable(%arg1: f32, %arg2: f32) {
- // expected-error @+1 {{'emitc.assign' op requires first operand (<block argument> of type 'f32' at index: 1) to be a get_global, subscript or variable}}
+ // expected-error @+1 {{'emitc.assign' op requires first operand (<block argument> of type 'f32' at index: 1) to be a get_global, member, member of pointer, subscript or variable}}
emitc.assign %arg1 : f32 to %arg2 : f32
return
}
@@ -450,3 +450,19 @@ func.func @use_global() {
%0 = emitc.get_global @myglobal : f32
return
}
+
+// -----
+
+func.func @member(%arg0: i32) {
+ // expected-error @+1 {{'emitc.member' op operand #0 must be EmitC opaque type, but got 'i32'}}
+ %0 = "emitc.member" (%arg0) {member = "a"} : (i32) -> i32
+ return
+}
+
+// -----
+
+func.func @member_of_ptr(%arg0: i32) {
+ // expected-error @+1 {{'emitc.member_of_ptr' op operand #0 must be EmitC opaque type or EmitC pointer type, but got 'i32}}
+ %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (i32) -> i32
+ return
+}
diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir
index 1d3ca5c9bc939..20ac077e4402b 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -254,3 +254,10 @@ func.func @assign_global(%arg0 : i32) {
emitc.assign %arg0 : i32 to %0 : i32
return
}
+
+func.func @member_access(%arg0: !emitc.opaque<"mystruct">, %arg1: !emitc.opaque<"mystruct_ptr">, %arg2: !emitc.ptr<!emitc.opaque<"mystruct">>) {
+ %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.opaque<"mystruct">) -> i32
+ %1 = "emitc.member_of_ptr" (%arg1) {member = "a"} : (!emitc.opaque<"mystruct_ptr">) -> i32
+ %2 = "emitc.member_of_ptr" (%arg2) {member = "a"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
+ return
+}
diff --git a/mlir/test/Target/Cpp/member.mlir b/mlir/test/Target/Cpp/member.mlir
new file mode 100644
index 0000000000000..1b4a3dcab879d
--- /dev/null
+++ b/mlir/test/Target/Cpp/member.mlir
@@ -0,0 +1,34 @@
+// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT
+
+func.func @member(%arg0: !emitc.opaque<"mystruct">, %arg1: i32) {
+ %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.opaque<"mystruct">) -> i32
+ emitc.assign %arg1 : i32 to %0 : i32
+
+ %1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.opaque<"mystruct">) -> i32
+ %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
+ emitc.assign %1 : i32 to %2 : i32
+
+ return
+}
+
+// CPP-DEFAULT: void member(mystruct [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: [[V0:[^ ]*]].a = [[V1:[^ ]*]];
+// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]];
+// CPP-DEFAULT-NEXT: [[V2:[^ ]*]] = [[V0:[^ ]*]].b;
+
+
+func.func @member_of_pointer(%arg0: !emitc.ptr<!emitc.opaque<"mystruct">>, %arg1: i32) {
+ %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
+ emitc.assign %arg1 : i32 to %0 : i32
+
+ %1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
+ %2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
+ emitc.assign %1 : i32 to %2 : i32
+
+ return
+}
+
+// CPP-DEFAULT: void member_of_pointer(mystruct* [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) {
+// CPP-DEFAULT-NEXT: [[V0:[^ ]*]]->a = [[V1:[^ ]*]];
+// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]];
+// CPP-DEFAULT-NEXT: [[V2:[^ ]*]] = [[V0:[^ ]*]]->b;
More information about the Mlir-commits
mailing list