[Mlir-commits] [mlir] [mlir][emitc] Adding a reflection option to the class (PR #146133)
Jaden Angella
llvmlistbot at llvm.org
Fri Jun 27 12:21:48 PDT 2025
https://github.com/Jaddyen updated https://github.com/llvm/llvm-project/pull/146133
>From a469dc0b2b79be876f43214024c1efdc44ed7e19 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Thu, 26 Jun 2025 21:28:05 +0000
Subject: [PATCH 1/3] Started on the buffer_map
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 40 +++++++++++++++++++
.../EmitC/Transforms/WrapFuncInClass.cpp | 23 ++++++++---
2 files changed, 58 insertions(+), 5 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 91ee89919e58e..69076261ddd2d 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -1679,4 +1679,44 @@ def EmitC_GetFieldOp
let assemblyFormat = "$field_name `:` type($result) attr-dict";
}
+def BufferMapOp
+ : EmitC_Op<"buffer_map", [Pure,
+ DeclareOpInterfaceMethods<OpAsmOpInterface>]> {
+ let summary = "Creates a buffer map for field access";
+ let description = [{
+ The `emitc.buffer_map` operation generates a C++ std::map that maps field names
+ to their memory addresses for efficient runtime field access. This operation
+ collects fields with buffer attributes and creates the necessary lookup
+ infrastructure.
+
+ Example:
+
+ ```mlir
+ emitc.buffer_map reflection_map [ @field1, @field2, @field3 ]
+ ```
+
+ This generates C++ code like:
+
+ ```cpp
+ const std::map<std::string, char*> _reflection_map {
+ { "field1", reinterpret_cast<char*>(&field1) },
+ { "field2", reinterpret_cast<char*>(&field2) },
+ { "field3", reinterpret_cast<char*>(&field3) }
+ };
+
+ char* getBufferForName(const std::string& name) const {
+ auto it = _reflection_map.find(name);
+ return (it == _reflection_map.end()) ? nullptr : it->second;
+ }
+ ```
+ }];
+
+ let arguments = (ins SymbolNameAttr:$sym_name,
+ Arg<OptionalAttr<ArrayAttr>, "field names">:$fields);
+
+ let results = (outs);
+ let builders = [];
+ let assemblyFormat = "$sym_name $fields attr-dict";
+}
+
#endif // MLIR_DIALECT_EMITC_IR_EMITC
diff --git a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
index 17d436f6df028..4f2ecfb640d2a 100644
--- a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
+++ b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
@@ -53,22 +53,35 @@ class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
ClassOp newClassOp = rewriter.create<ClassOp>(funcOp.getLoc(), className);
SmallVector<std::pair<StringAttr, TypeAttr>> fields;
+ SmallVector<Attribute> bufferFieldAttrs;
rewriter.createBlock(&newClassOp.getBody());
rewriter.setInsertionPointToStart(&newClassOp.getBody().front());
auto argAttrs = funcOp.getArgAttrs();
for (auto [idx, val] : llvm::enumerate(funcOp.getArguments())) {
StringAttr fieldName;
- Attribute argAttr = nullptr;
fieldName = rewriter.getStringAttr("fieldName" + std::to_string(idx));
- if (argAttrs && idx < argAttrs->size())
- argAttr = (*argAttrs)[idx];
-
+ if (argAttrs && idx < argAttrs->size()) {
+ mlir::DictionaryAttr dictAttr =
+ dyn_cast_or_null<mlir::DictionaryAttr>((*argAttrs)[idx]);
+ const mlir::Attribute namedAttribute =
+ dictAttr.getNamed(attributeName)->getValue();
+
+ auto name =
+ cast<mlir::StringAttr>(cast<mlir::ArrayAttr>(namedAttribute)[0]);
+ bufferFieldAttrs.push_back(name);
+ }
TypeAttr typeAttr = TypeAttr::get(val.getType());
fields.push_back({fieldName, typeAttr});
rewriter.create<emitc::FieldOp>(funcOp.getLoc(), fieldName, typeAttr,
- argAttr);
+ nullptr);
+ }
+
+ if (!bufferFieldAttrs.empty()) {
+ ArrayAttr fieldsArrayAttr = rewriter.getArrayAttr(bufferFieldAttrs);
+ rewriter.create<emitc::BufferMapOp>(funcOp.getLoc(), "reflection_map",
+ fieldsArrayAttr);
}
rewriter.setInsertionPointToEnd(&newClassOp.getBody().front());
>From ec067c786d205206cfaf4ea3b5d94df9fce68e92 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Fri, 27 Jun 2025 18:26:28 +0000
Subject: [PATCH 2/3] Remove sym_name
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 16 +++++++---------
.../Dialect/EmitC/Transforms/WrapFuncInClass.cpp | 3 +--
2 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 69076261ddd2d..919648dc7fb1d 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -1692,16 +1692,16 @@ def BufferMapOp
Example:
```mlir
- emitc.buffer_map reflection_map [ @field1, @field2, @field3 ]
+ emitc.buffer_map [ @field1, @field2, @field3 ]
```
This generates C++ code like:
```cpp
- const std::map<std::string, char*> _reflection_map {
- { "field1", reinterpret_cast<char*>(&field1) },
- { "field2", reinterpret_cast<char*>(&field2) },
- { "field3", reinterpret_cast<char*>(&field3) }
+ const std::map<std::string, char*> _buffer_map {
+ { "some_feature", reinterpret_cast<char*>(&some_feature) },
+ { "another_feature", reinterpret_cast<char*>(&another_feature) },
+ { "input_tense", reinterpret_cast<char*>(&input_tense) }
};
char* getBufferForName(const std::string& name) const {
@@ -1711,12 +1711,10 @@ def BufferMapOp
```
}];
- let arguments = (ins SymbolNameAttr:$sym_name,
- Arg<OptionalAttr<ArrayAttr>, "field names">:$fields);
+ let arguments = (ins Arg<OptionalAttr<ArrayAttr>, "field names">:$fields);
let results = (outs);
- let builders = [];
- let assemblyFormat = "$sym_name $fields attr-dict";
+ let assemblyFormat = "$fields attr-dict";
}
#endif // MLIR_DIALECT_EMITC_IR_EMITC
diff --git a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
index 4f2ecfb640d2a..b4fd50fa4fd95 100644
--- a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
+++ b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
@@ -80,8 +80,7 @@ class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
if (!bufferFieldAttrs.empty()) {
ArrayAttr fieldsArrayAttr = rewriter.getArrayAttr(bufferFieldAttrs);
- rewriter.create<emitc::BufferMapOp>(funcOp.getLoc(), "reflection_map",
- fieldsArrayAttr);
+ rewriter.create<emitc::BufferMapOp>(funcOp.getLoc(), fieldsArrayAttr);
}
rewriter.setInsertionPointToEnd(&newClassOp.getBody().front());
>From 8e44f857ca02b18f94276875b992806144ef2573 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Fri, 27 Jun 2025 19:21:27 +0000
Subject: [PATCH 3/3] Corrected the attrs use in fields
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 7 ++-----
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 3 ---
mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp | 6 ++----
mlir/test/Dialect/EmitC/wrap_emitc_func_in_class.mlir | 7 ++++---
4 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 919648dc7fb1d..f5d163a45b08e 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -1644,17 +1644,14 @@ def EmitC_FieldOp : EmitC_Op<"field", [Symbol]> {
Example:
```mlir
- // Example with an attribute:
- emitc.field @fieldName0 : !emitc.array<1xf32> {emitc.opaque = "another_feature"}
// Example with no attribute:
emitc.field @fieldName0 : !emitc.array<1xf32>
```
}];
- let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$type,
- OptionalAttr<AnyAttr>:$attrs);
+ let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$type);
- let assemblyFormat = [{ $sym_name `:` $type ($attrs^)? attr-dict}];
+ let assemblyFormat = [{ $sym_name `:` $type attr-dict}];
let hasVerifier = 1;
}
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 27298e892e599..b0ff4ed7bb688 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -1415,9 +1415,6 @@ LogicalResult FieldOp::verify() {
if (!symName || symName.getValue().empty())
return emitOpError("field must have a non-empty symbol name");
- if (!getAttrs())
- return success();
-
return success();
}
diff --git a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
index b4fd50fa4fd95..3e627708c6f3e 100644
--- a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
+++ b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
@@ -68,14 +68,12 @@ class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
const mlir::Attribute namedAttribute =
dictAttr.getNamed(attributeName)->getValue();
- auto name =
- cast<mlir::StringAttr>(cast<mlir::ArrayAttr>(namedAttribute)[0]);
+ auto name = cast<mlir::StringAttr>(namedAttribute);
bufferFieldAttrs.push_back(name);
}
TypeAttr typeAttr = TypeAttr::get(val.getType());
fields.push_back({fieldName, typeAttr});
- rewriter.create<emitc::FieldOp>(funcOp.getLoc(), fieldName, typeAttr,
- nullptr);
+ rewriter.create<emitc::FieldOp>(funcOp.getLoc(), fieldName, typeAttr);
}
if (!bufferFieldAttrs.empty()) {
diff --git a/mlir/test/Dialect/EmitC/wrap_emitc_func_in_class.mlir b/mlir/test/Dialect/EmitC/wrap_emitc_func_in_class.mlir
index c67a0c197fcd9..364840adb3e5f 100644
--- a/mlir/test/Dialect/EmitC/wrap_emitc_func_in_class.mlir
+++ b/mlir/test/Dialect/EmitC/wrap_emitc_func_in_class.mlir
@@ -19,9 +19,10 @@ module attributes { } {
// CHECK: module {
// CHECK-NEXT: emitc.class @modelClass {
-// CHECK-NEXT: emitc.field @fieldName0 : !emitc.array<1xf32> {emitc.name_hint = "another_feature"}
-// CHECK-NEXT: emitc.field @fieldName1 : !emitc.array<1xf32> {emitc.name_hint = "some_feature"}
-// CHECK-NEXT: emitc.field @fieldName2 : !emitc.array<1xf32> {emitc.name_hint = "output_0"}
+// CHECK-NEXT: emitc.field @fieldName0 : !emitc.array<1xf32>
+// CHECK-NEXT: emitc.field @fieldName1 : !emitc.array<1xf32>
+// CHECK-NEXT: emitc.field @fieldName2 : !emitc.array<1xf32>
+// CHECK-NEXT: emitc.buffer_map ["another_feature", "some_feature", "output_0"]
// CHECK-NEXT: emitc.func @execute() {
// CHECK-NEXT: get_field @fieldName0 : !emitc.array<1xf32>
// CHECK-NEXT: get_field @fieldName1 : !emitc.array<1xf32>
More information about the Mlir-commits
mailing list