[Mlir-commits] [mlir] [mlir][IR] Add `getPropertyFromAttr` and `setPropertyFromAttr` methods. (PR #150060)
Fabian Mora
llvmlistbot at llvm.org
Tue Jul 22 10:35:25 PDT 2025
https://github.com/fabianmcg updated https://github.com/llvm/llvm-project/pull/150060
>From dd612d6bf70e80eba41afc7e9f655d0d0280221f Mon Sep 17 00:00:00 2001
From: Fabian Mora <fabian.mora-cordero at amd.com>
Date: Tue, 22 Jul 2025 15:21:46 +0000
Subject: [PATCH 1/2] [mlir][IR] Add `getPropertyFromAttr` and
`setPropertyFromAttr` methods.
---
mlir/include/mlir/IR/ExtensibleDialect.h | 11 ++
mlir/include/mlir/IR/OpDefinition.h | 21 +++
mlir/include/mlir/IR/Operation.h | 17 +++
mlir/include/mlir/IR/OperationSupport.h | 45 ++++++
mlir/lib/IR/MLIRContext.cpp | 14 ++
mlir/lib/IR/Operation.cpp | 15 ++
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 121 ++++++++++++----
mlir/unittests/IR/OpPropertiesTest.cpp | 144 ++++++++++++++++++++
8 files changed, 364 insertions(+), 24 deletions(-)
diff --git a/mlir/include/mlir/IR/ExtensibleDialect.h b/mlir/include/mlir/IR/ExtensibleDialect.h
index 955faaad9408b..fd8ea760eb9fe 100644
--- a/mlir/include/mlir/IR/ExtensibleDialect.h
+++ b/mlir/include/mlir/IR/ExtensibleDialect.h
@@ -493,6 +493,17 @@ class DynamicOpDefinition : public OperationName::Impl {
return failure();
}
Attribute getPropertiesAsAttr(Operation *op) final { return {}; }
+
+ LogicalResult
+ setPropertyFromAttr(OperationName opName, OpaqueProperties properties,
+ StringRef name, Attribute attr,
+ function_ref<InFlightDiagnostic()> emitError) final {
+ emitError() << "extensible Dialects don't support properties";
+ return failure();
+ }
+ FailureOr<Attribute> getPropertyAsAttr(Operation *op, StringRef name) final {
+ return failure();
+ }
void copyProperties(OpaqueProperties lhs, OpaqueProperties rhs) final {}
bool compareProperties(OpaqueProperties, OpaqueProperties) final { return false; }
llvm::hash_code hashProperties(OpaqueProperties prop) final { return {}; }
diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h
index 883ece32967e4..2e610ec21000c 100644
--- a/mlir/include/mlir/IR/OpDefinition.h
+++ b/mlir/include/mlir/IR/OpDefinition.h
@@ -1758,6 +1758,17 @@ class Op : public OpState, public Traits<ConcreteType>... {
function_ref<InFlightDiagnostic()> emitError) {
return setPropertiesFromAttribute(prop, attr, emitError);
}
+ /// Convert the provided attribute to a property and assigned it to the
+ /// corresponding property. This default implementation forwards to a free
+ /// function `setPropertiesFromAttribute` that can be looked up with ADL in
+ /// the namespace where the properties are defined. It can also be overridden
+ /// in the derived ConcreteOp.
+ template <typename PropertiesTy>
+ static LogicalResult
+ setPropertyFromAttr(PropertiesTy &prop, StringRef name, Attribute attr,
+ function_ref<InFlightDiagnostic()> emitError) {
+ return setPropertyFromAttribute(prop, name, attr, emitError);
+ }
/// Convert the provided properties to an attribute. This default
/// implementation forwards to a free function `getPropertiesAsAttribute` that
/// can be looked up with ADL in the namespace where the properties are
@@ -1767,6 +1778,16 @@ class Op : public OpState, public Traits<ConcreteType>... {
const PropertiesTy &prop) {
return getPropertiesAsAttribute(ctx, prop);
}
+ /// Convert the provided named property to an attribute. This default
+ /// implementation forwards to a free function `getPropertiesAsAttribute` that
+ /// can be looked up with ADL in the namespace where the properties are
+ /// defined. It can also be overridden in the derived ConcreteOp.
+ template <typename PropertiesTy>
+ static FailureOr<Attribute> getPropertyAsAttr(MLIRContext *ctx,
+ const PropertiesTy &prop,
+ StringRef name) {
+ return getPropertyAsAttribute(ctx, prop, name);
+ }
/// Hash the provided properties. This default implementation forwards to a
/// free function `computeHash` that can be looked up with ADL in the
/// namespace where the properties are defined. It can also be overridden in
diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h
index fa8a4873572ce..42ab61c055bc3 100644
--- a/mlir/include/mlir/IR/Operation.h
+++ b/mlir/include/mlir/IR/Operation.h
@@ -920,6 +920,12 @@ class alignas(8) Operation final
/// operation. Returns an empty attribute if no properties are present.
Attribute getPropertiesAsAttribute();
+ /// Return a named property converted to an attribute.
+ /// This is expensive, and mostly useful when dealing with unregistered
+ /// operations or in language bindings. Returns failure if there's no property
+ /// under such name.
+ FailureOr<Attribute> getPropertyAsAttribute(StringRef name);
+
/// Set the properties from the provided attribute.
/// This is an expensive operation that can fail if the attribute is not
/// matching the expectations of the properties for this operation. This is
@@ -930,6 +936,17 @@ class alignas(8) Operation final
setPropertiesFromAttribute(Attribute attr,
function_ref<InFlightDiagnostic()> emitError);
+ /// Set a named property from the provided attribute.
+ /// This is an expensive operation that can fail if the attribute is not
+ /// matching the expectations of the properties for this operation. This is
+ /// mostly useful for unregistered operations, used when parsing the
+ /// generic format, or in language bindings. An optional diagnostic emitter
+ /// can be passed in for richer errors, if none is passed then behavior is
+ /// undefined in error case.
+ LogicalResult
+ setPropertyFromAttribute(StringRef name, Attribute attr,
+ function_ref<InFlightDiagnostic()> emitError);
+
/// Copy properties from an existing other properties object. The two objects
/// must be the same type.
void copyProperties(OpaqueProperties rhs);
diff --git a/mlir/include/mlir/IR/OperationSupport.h b/mlir/include/mlir/IR/OperationSupport.h
index 1ff7c56ddca38..7aadcca8f1232 100644
--- a/mlir/include/mlir/IR/OperationSupport.h
+++ b/mlir/include/mlir/IR/OperationSupport.h
@@ -139,6 +139,12 @@ class OperationName {
setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute,
function_ref<InFlightDiagnostic()> emitError) = 0;
virtual Attribute getPropertiesAsAttr(Operation *) = 0;
+ virtual LogicalResult
+ setPropertyFromAttr(OperationName, OpaqueProperties, StringRef name,
+ Attribute,
+ function_ref<InFlightDiagnostic()> emitError) = 0;
+ virtual FailureOr<Attribute> getPropertyAsAttr(Operation *,
+ StringRef name) = 0;
virtual void copyProperties(OpaqueProperties, OpaqueProperties) = 0;
virtual bool compareProperties(OpaqueProperties, OpaqueProperties) = 0;
virtual llvm::hash_code hashProperties(OpaqueProperties) = 0;
@@ -220,6 +226,11 @@ class OperationName {
setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute,
function_ref<InFlightDiagnostic()> emitError) final;
Attribute getPropertiesAsAttr(Operation *) final;
+ LogicalResult
+ setPropertyFromAttr(OperationName, OpaqueProperties, StringRef name,
+ Attribute,
+ function_ref<InFlightDiagnostic()> emitError) final;
+ FailureOr<Attribute> getPropertyAsAttr(Operation *, StringRef name) final;
void copyProperties(OpaqueProperties, OpaqueProperties) final;
bool compareProperties(OpaqueProperties, OpaqueProperties) final;
llvm::hash_code hashProperties(OpaqueProperties) final;
@@ -441,6 +452,20 @@ class OperationName {
emitError);
}
+ /// Return an op property converted to an Attribute.
+ FailureOr<Attribute> getOpPropertyAsAttribute(Operation *op,
+ StringRef name) const {
+ return getImpl()->getPropertyAsAttr(op, name);
+ }
+
+ /// Define an op property from the provided Attribute.
+ LogicalResult setOpPropertyFromAttribute(
+ OperationName opName, OpaqueProperties properties, StringRef name,
+ Attribute attr, function_ref<InFlightDiagnostic()> emitError) const {
+ return getImpl()->setPropertyFromAttr(opName, properties, name, attr,
+ emitError);
+ }
+
void copyOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const {
return getImpl()->copyProperties(lhs, rhs);
}
@@ -650,6 +675,26 @@ class RegisteredOperationName : public OperationName {
}
return {};
}
+ LogicalResult
+ setPropertyFromAttr(OperationName opName, OpaqueProperties properties,
+ StringRef name, Attribute attr,
+ function_ref<InFlightDiagnostic()> emitError) final {
+ if constexpr (hasProperties) {
+ auto p = properties.as<Properties *>();
+ return ConcreteOp::setPropertyFromAttr(*p, name, attr, emitError);
+ }
+ emitError() << "this operation does not support properties";
+ return failure();
+ }
+ FailureOr<Attribute> getPropertyAsAttr(Operation *op,
+ StringRef name) final {
+ if constexpr (hasProperties) {
+ auto concreteOp = cast<ConcreteOp>(op);
+ return ConcreteOp::getPropertyAsAttr(concreteOp->getContext(),
+ concreteOp.getProperties(), name);
+ }
+ return failure();
+ }
bool compareProperties(OpaqueProperties lhs, OpaqueProperties rhs) final {
if constexpr (hasProperties) {
return *lhs.as<Properties *>() == *rhs.as<Properties *>();
diff --git a/mlir/lib/IR/MLIRContext.cpp b/mlir/lib/IR/MLIRContext.cpp
index 06ec1c85fb4d5..7b49a945c549b 100644
--- a/mlir/lib/IR/MLIRContext.cpp
+++ b/mlir/lib/IR/MLIRContext.cpp
@@ -901,6 +901,20 @@ Attribute
OperationName::UnregisteredOpModel::getPropertiesAsAttr(Operation *op) {
return *op->getPropertiesStorage().as<Attribute *>();
}
+LogicalResult OperationName::UnregisteredOpModel::setPropertyFromAttr(
+ OperationName opName, OpaqueProperties properties, StringRef name,
+ Attribute attr, function_ref<InFlightDiagnostic()> emitError) {
+ assert(false &&
+ "`setPropertyFromAttr` doesn't work with unregistered operations.");
+ return failure();
+}
+FailureOr<Attribute>
+OperationName::UnregisteredOpModel::getPropertyAsAttr(Operation *op,
+ StringRef name) {
+ assert(false &&
+ "`getPropertyAsAttr` doesn't work with unregistered operations.");
+ return failure();
+}
void OperationName::UnregisteredOpModel::copyProperties(OpaqueProperties lhs,
OpaqueProperties rhs) {
*lhs.as<Attribute *>() = *rhs.as<Attribute *>();
diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp
index 8bcfa465e4a22..edd2efedf5a45 100644
--- a/mlir/lib/IR/Operation.cpp
+++ b/mlir/lib/IR/Operation.cpp
@@ -351,6 +351,12 @@ Attribute Operation::getPropertiesAsAttribute() {
return *getPropertiesStorage().as<Attribute *>();
return info->getOpPropertiesAsAttribute(this);
}
+FailureOr<Attribute> Operation::getPropertyAsAttribute(StringRef name) {
+ std::optional<RegisteredOperationName> info = getRegisteredInfo();
+ assert(info &&
+ "`getPropertyAsAttribute` only works for registered operations.");
+ return info->getOpPropertyAsAttribute(this, name);
+}
LogicalResult Operation::setPropertiesFromAttribute(
Attribute attr, function_ref<InFlightDiagnostic()> emitError) {
std::optional<RegisteredOperationName> info = getRegisteredInfo();
@@ -361,6 +367,15 @@ LogicalResult Operation::setPropertiesFromAttribute(
return info->setOpPropertiesFromAttribute(
this->getName(), this->getPropertiesStorage(), attr, emitError);
}
+LogicalResult Operation::setPropertyFromAttribute(
+ StringRef name, Attribute attr,
+ function_ref<InFlightDiagnostic()> emitError) {
+ std::optional<RegisteredOperationName> info = getRegisteredInfo();
+ assert(info &&
+ "`setPropertyFromAttribute` only works for registered operations.");
+ return info->setOpPropertyFromAttribute(
+ this->getName(), this->getPropertiesStorage(), name, attr, emitError);
+}
void Operation::copyProperties(OpaqueProperties rhs) {
name.copyOpProperties(getPropertiesStorage(), rhs);
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index f35cfa6826388..d370f975ff2d7 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1411,7 +1411,7 @@ void OpEmitter::genPropertiesSupport() {
attrOrProperties.push_back(&emitHelper.getOperandSegmentsSize().value());
if (emitHelper.getResultSegmentsSize())
attrOrProperties.push_back(&emitHelper.getResultSegmentsSize().value());
- auto &setPropMethod =
+ auto &setPropsMethod =
opClass
.addStaticMethod(
"::llvm::LogicalResult", "setPropertiesFromAttr",
@@ -1421,12 +1421,31 @@ void OpEmitter::genPropertiesSupport() {
"::llvm::function_ref<::mlir::InFlightDiagnostic()>",
"emitError"))
->body();
- auto &getPropMethod =
+ auto &getPropsMethod =
opClass
.addStaticMethod("::mlir::Attribute", "getPropertiesAsAttr",
MethodParameter("::mlir::MLIRContext *", "ctx"),
MethodParameter("const Properties &", "prop"))
->body();
+ auto &setPropMethod =
+ opClass
+ .addStaticMethod(
+ "::llvm::LogicalResult", "setPropertyFromAttr",
+ MethodParameter("Properties &", "prop"),
+ MethodParameter("llvm::StringRef", "name"),
+ MethodParameter("::mlir::Attribute", "attr"),
+ MethodParameter(
+ "::llvm::function_ref<::mlir::InFlightDiagnostic()>",
+ "emitError"))
+ ->body();
+ auto &getPropMethod =
+ opClass
+ .addStaticMethod("llvm::FailureOr<::mlir::Attribute>",
+ "getPropertyAsAttr",
+ MethodParameter("::mlir::MLIRContext *", "ctx"),
+ MethodParameter("const Properties &", "prop"),
+ MethodParameter("llvm::StringRef", "name"))
+ ->body();
auto &hashMethod =
opClass
.addStaticMethod("llvm::hash_code", "computePropertiesHash",
@@ -1468,7 +1487,7 @@ void OpEmitter::genPropertiesSupport() {
// Convert the property to the attribute form.
- setPropMethod << R"decl(
+ setPropsMethod << R"decl(
::mlir::DictionaryAttr dict = ::llvm::dyn_cast<::mlir::DictionaryAttr>(attr);
if (!dict) {
emitError() << "expected DictionaryAttr to set properties";
@@ -1480,9 +1499,9 @@ void OpEmitter::genPropertiesSupport() {
::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) -> ::mlir::LogicalResult {{
{0}
};
- {1};
+ {1}
)decl";
- const char *attrGetNoDefaultFmt = R"decl(;
+ const char *attrGetNoDefaultFmt = R"decl(
if (attr && ::mlir::failed(setFromAttr(prop.{0}, attr, emitError)))
return ::mlir::failure();
)decl";
@@ -1515,22 +1534,33 @@ void OpEmitter::genPropertiesSupport() {
}
fctx.withBuilder(odsBuilder);
- setPropMethod << "{\n"
+ setPropsMethod << "{\n"
+ << formatv(
+ propFromAttrFmt,
+ tgfmt(prop.getConvertFromAttributeCall(),
+ &fctx.addSubst("_attr", propertyAttr)
+ .addSubst("_storage", propertyStorage)
+ .addSubst("_diag", propertyDiag)),
+ getAttr);
+ if (prop.hasStorageTypeValueOverride()) {
+ setPropsMethod << formatv(attrGetDefaultFmt, name,
+ prop.getStorageTypeValueOverride());
+ } else if (prop.hasDefaultValue()) {
+ setPropsMethod << formatv(attrGetDefaultFmt, name,
+ tgfmt(prop.getDefaultValue(), &fctx));
+ } else {
+ setPropsMethod << formatv(attrGetNoDefaultFmt, name);
+ }
+ setPropsMethod << " }\n";
+ setPropMethod << formatv(" if (name == \"{0}\") {{", name)
<< formatv(propFromAttrFmt,
tgfmt(prop.getConvertFromAttributeCall(),
&fctx.addSubst("_attr", propertyAttr)
.addSubst("_storage", propertyStorage)
.addSubst("_diag", propertyDiag)),
- getAttr);
- if (prop.hasStorageTypeValueOverride()) {
- setPropMethod << formatv(attrGetDefaultFmt, name,
- prop.getStorageTypeValueOverride());
- } else if (prop.hasDefaultValue()) {
- setPropMethod << formatv(attrGetDefaultFmt, name,
- tgfmt(prop.getDefaultValue(), &fctx));
- } else {
- setPropMethod << formatv(attrGetNoDefaultFmt, name);
- }
+ "");
+ setPropMethod << formatv(attrGetNoDefaultFmt, name);
+ setPropMethod << " return ::mlir::success();\n";
setPropMethod << " }\n";
} else {
const auto *namedAttr =
@@ -1548,7 +1578,7 @@ void OpEmitter::genPropertiesSupport() {
os << " if (!attr) attr = dict.get(\"result_segment_sizes\");";
}
- setPropMethod << formatv(R"decl(
+ setPropsMethod << formatv(R"decl(
{{
auto &propStorage = prop.{0};
{1}
@@ -1563,16 +1593,38 @@ void OpEmitter::genPropertiesSupport() {
}
}
)decl",
- name, getAttr);
+ name, getAttr);
+ setPropMethod << formatv(R"decl(
+ if (name == "{0}") {{
+ auto &propStorage = prop.{0};
+ if (attr == nullptr) {{
+ propStorage = nullptr;
+ return ::mlir::success();
+ }
+ auto convertedAttr = ::llvm::dyn_cast<std::remove_reference_t<decltype(propStorage)>>(attr);
+ if (convertedAttr) {{
+ propStorage = convertedAttr;
+ return ::mlir::success();
+ } else {{
+ emitError() << "Invalid attribute `{0}` in property conversion: " << attr;
+ return ::mlir::failure();
}
}
- setPropMethod << " return ::mlir::success();\n";
+)decl",
+ name);
+ }
+ }
+ setPropsMethod << " return ::mlir::success();\n";
+ setPropMethod << " return emitError() << \"`\" << name << \"` is not an op "
+ "property\";\n";
// Convert the attribute form to the property.
- getPropMethod << " ::mlir::SmallVector<::mlir::NamedAttribute> attrs;\n"
- << " ::mlir::Builder odsBuilder{ctx};\n";
- const char *propToAttrFmt = R"decl(
+ getPropsMethod << " ::mlir::SmallVector<::mlir::NamedAttribute> attrs;\n"
+ << " ::mlir::Builder odsBuilder{ctx};\n";
+ getPropMethod << " ::mlir::Builder odsBuilder{ctx};\n"
+ << " (void)odsBuilder;\n";
+ const char *propsToAttrFmt = R"decl(
{
const auto &propStorage = prop.{0};
auto attr = [&]() -> ::mlir::Attribute {{
@@ -1580,6 +1632,15 @@ void OpEmitter::genPropertiesSupport() {
}();
attrs.push_back(odsBuilder.getNamedAttr("{0}", attr));
}
+)decl";
+ const char *propToAttrFmt = R"decl(
+ if (name == "{0}") {
+ const auto &propStorage = prop.{0};
+ auto attr = [&]() -> ::mlir::Attribute {{
+ {1}
+ }();
+ return attr;
+ }
)decl";
for (const auto &attrOrProp : attrOrProperties) {
if (const auto *namedProperty =
@@ -1587,6 +1648,11 @@ void OpEmitter::genPropertiesSupport() {
StringRef name = namedProperty->name;
auto &prop = namedProperty->prop;
FmtContext fctx;
+ getPropsMethod << formatv(
+ propsToAttrFmt, name,
+ tgfmt(prop.getConvertToAttributeCall(),
+ &fctx.addSubst("_ctxt", "ctx")
+ .addSubst("_storage", propertyStorage)));
getPropMethod << formatv(
propToAttrFmt, name,
tgfmt(prop.getConvertToAttributeCall(),
@@ -1597,21 +1663,28 @@ void OpEmitter::genPropertiesSupport() {
const auto *namedAttr =
llvm::dyn_cast_if_present<const AttributeMetadata *>(attrOrProp);
StringRef name = namedAttr->attrName;
- getPropMethod << formatv(R"decl(
+ getPropsMethod << formatv(R"decl(
{{
const auto &propStorage = prop.{0};
if (propStorage)
attrs.push_back(odsBuilder.getNamedAttr("{0}",
propStorage));
}
+)decl",
+ name);
+ getPropMethod << formatv(R"decl(
+ if (name == "{0}") {{
+ return prop.{0};
+ }
)decl",
name);
}
- getPropMethod << R"decl(
+ getPropsMethod << R"decl(
if (!attrs.empty())
return odsBuilder.getDictionaryAttr(attrs);
return {};
)decl";
+ getPropMethod << " return ::mlir::failure();";
// Hashing for the property
diff --git a/mlir/unittests/IR/OpPropertiesTest.cpp b/mlir/unittests/IR/OpPropertiesTest.cpp
index 4759735d99605..b735210ed8ee1 100644
--- a/mlir/unittests/IR/OpPropertiesTest.cpp
+++ b/mlir/unittests/IR/OpPropertiesTest.cpp
@@ -13,6 +13,9 @@
#include "gtest/gtest.h"
#include <optional>
+#include "../../test/lib/Dialect/Test/TestDialect.h"
+#include "../../test/lib/Dialect/Test/TestOps.h"
+
using namespace mlir;
namespace {
@@ -78,6 +81,43 @@ setPropertiesFromAttribute(TestProperties &prop, Attribute attr,
return success();
}
+/// Convert an attribute to a TestProperties struct, optionally emit errors
+/// through the provided diagnostic if any. This is used for example during
+/// parsing with the generic format.
+static LogicalResult
+setPropertyFromAttribute(TestProperties &prop, StringRef name, Attribute attr,
+ function_ref<InFlightDiagnostic()> emitError) {
+ if (name == "a") {
+ auto v = dyn_cast<IntegerAttr>(attr);
+ if (!v)
+ return failure();
+ prop.a = v.getValue().getSExtValue();
+ return success();
+ }
+ if (name == "b") {
+ auto v = dyn_cast<FloatAttr>(attr);
+ if (!v)
+ return failure();
+ prop.a = v.getValue().convertToFloat();
+ return success();
+ }
+ if (name == "array") {
+ auto v = dyn_cast<DenseI64ArrayAttr>(attr);
+ if (!v)
+ return failure();
+ prop.array.assign(v.asArrayRef().begin(), v.asArrayRef().end());
+ return success();
+ }
+ if (name == "label") {
+ auto v = dyn_cast<StringAttr>(attr);
+ if (!v)
+ return failure();
+ prop.label = std::make_shared<std::string>(v.getValue());
+ return success();
+ }
+ return failure();
+}
+
/// Convert a TestProperties struct to a DictionaryAttr, this is used for
/// example during printing with the generic format.
static Attribute getPropertiesAsAttribute(MLIRContext *ctx,
@@ -92,6 +132,20 @@ static Attribute getPropertiesAsAttribute(MLIRContext *ctx,
return b.getDictionaryAttr(attrs);
}
+/// Convert a named property in TestProperties struct to an attribute, this is
+/// used for example during printing with the generic format.
+static FailureOr<Attribute> getPropertyAsAttribute(MLIRContext *ctx,
+ const TestProperties &prop,
+ StringRef name) {
+ Builder b{ctx};
+ return llvm::StringSwitch<FailureOr<Attribute>>(name)
+ .Case("a", b.getI32IntegerAttr(prop.a))
+ .Case("b", b.getF32FloatAttr(prop.b))
+ .Case("array", b.getDenseI64ArrayAttr(prop.array))
+ .Case("label", b.getStringAttr(prop.label ? *prop.label : "<nullptr>"))
+ .Default(failure());
+}
+
inline llvm::hash_code computeHash(const TestProperties &prop) {
// We hash `b` which is a float using its underlying array of char:
unsigned char const *p = reinterpret_cast<unsigned char const *>(&prop.b);
@@ -419,4 +473,94 @@ TEST(OpPropertiesTest, withoutPropertiesDiscardableAttrs) {
EXPECT_TRUE(hash(op.get()) == hash(reparsed.get()));
}
+TEST(OpPropertiesTest, PropertiesAsAttrs) {
+ MLIRContext context;
+ context.getOrLoadDialect<TestOpPropertiesDialect>();
+ ParserConfig config(&context);
+ // Parse the operation with some properties.
+ OwningOpRef<Operation *> op = parseSourceString(mlirSrc, config);
+ ASSERT_TRUE(op.get() != nullptr);
+ auto opWithProp = dyn_cast<OpWithProperties>(op.get());
+ ASSERT_TRUE(opWithProp);
+ {
+ // Check the attr dict.
+ std::string output;
+ llvm::raw_string_ostream os(output);
+ opWithProp->getPropertiesAsAttribute().print(os);
+ ASSERT_STREQ("{a = -42 : i32, "
+ "array = array<i64: 40, 41>, "
+ "b = -4.200000e+01 : f32, "
+ "label = \"bar foo\"}",
+ output.c_str());
+ }
+ auto getAttr = [&](FailureOr<Attribute> attr) {
+ EXPECT_TRUE(succeeded(attr));
+ return *attr;
+ };
+ // Get and mutate single properties.
+ auto a = cast<IntegerAttr>(getAttr(op->getPropertyAsAttribute("a")));
+ auto label = cast<StringAttr>(getAttr(op->getPropertyAsAttribute("label")));
+ std::string newLabel = label.getValue().str() + " " +
+ std::to_string(a.getValue().getSExtValue());
+ {
+ EXPECT_TRUE(succeeded(op->setPropertyFromAttribute(
+ "label", StringAttr::get(&context, newLabel),
+ [&]() { return op->emitError(); })));
+ std::string output;
+ llvm::raw_string_ostream os(output);
+ opWithProp.print(os);
+ StringRef view(output);
+ EXPECT_TRUE(view.contains("label = \"bar foo -42\""));
+ }
+ // Expect error because the named prop doesn't exist.
+ EXPECT_TRUE(failed(
+ op->setPropertyFromAttribute("s", a, [&]() { return op->emitError(); })));
+}
+
+TEST(OpPropertiesTest, TblgenOpProperties) {
+ MLIRContext context;
+ context.getOrLoadDialect<test::TestDialect>();
+ ParserConfig config(&context);
+ // Parse the operation with some properties.
+ OwningOpRef<Operation *> op = parseSourceString(R"mlir(
+ test.with_properties a = 32, b = "foo", c = "bar",
+ flag = true, array = [1, 2, 3, 4], array32 = [5, 6]
+ )mlir",
+ config);
+ ASSERT_TRUE(op.get() != nullptr);
+ auto opWithProp = dyn_cast<test::TestOpWithProperties>(op.get());
+ ASSERT_TRUE(opWithProp);
+ {
+ // Check the attr dict.
+ std::string output;
+ llvm::raw_string_ostream os(output);
+ opWithProp->getPropertiesAsAttribute().print(os);
+ StringRef view(output);
+ EXPECT_TRUE(view.contains("a = 32"));
+ EXPECT_TRUE(view.contains("b = \"foo\""));
+ }
+ {
+ // Modify a prop.
+ std::string output;
+ llvm::raw_string_ostream os(output);
+ ASSERT_TRUE(succeeded(opWithProp->setPropertyFromAttribute(
+ "a", IntegerAttr::get(IntegerType::get(&context, 32), 42),
+ [&]() { return opWithProp->emitError(); })));
+ opWithProp->print(os);
+ StringRef view(output);
+ EXPECT_FALSE(view.contains("a = 32"));
+ EXPECT_TRUE(view.contains("a = 42"));
+ EXPECT_TRUE(view.contains("b = \"foo\""));
+ }
+ {
+ // Get a prop.
+ std::string output;
+ llvm::raw_string_ostream os(output);
+ FailureOr<Attribute> prop = opWithProp->getPropertyAsAttribute("flag");
+ ASSERT_TRUE(succeeded(prop));
+ auto flagAttr = dyn_cast_or_null<BoolAttr>(*prop);
+ ASSERT_TRUE(flagAttr);
+ EXPECT_TRUE(flagAttr.getValue());
+ }
+}
} // namespace
>From afee7ccc7647fde829d5dcf08237f2af40e56742 Mon Sep 17 00:00:00 2001
From: Fabian Mora <fabian.mora-cordero at amd.com>
Date: Tue, 22 Jul 2025 17:35:01 +0000
Subject: [PATCH 2/2] fix typo
---
mlir/unittests/IR/OpPropertiesTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/unittests/IR/OpPropertiesTest.cpp b/mlir/unittests/IR/OpPropertiesTest.cpp
index b735210ed8ee1..5241717a564af 100644
--- a/mlir/unittests/IR/OpPropertiesTest.cpp
+++ b/mlir/unittests/IR/OpPropertiesTest.cpp
@@ -98,7 +98,7 @@ setPropertyFromAttribute(TestProperties &prop, StringRef name, Attribute attr,
auto v = dyn_cast<FloatAttr>(attr);
if (!v)
return failure();
- prop.a = v.getValue().convertToFloat();
+ prop.b = v.getValue().convertToFloat();
return success();
}
if (name == "array") {
More information about the Mlir-commits
mailing list