[Mlir-commits] [mlir] [mlir] Add predicates to tablegen-defined properties (PR #120176)
Krzysztof Drewniak
llvmlistbot at llvm.org
Tue Dec 17 19:46:13 PST 2024
https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/120176
>From 987a7d0b83a56e40f76d555e26842f7be481f7a0 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Wed, 27 Nov 2024 18:54:40 -0800
Subject: [PATCH 1/4] [mlir] Add predicates to tablegen-defined properties
Give the properties from tablegen a `predicate` field that holds the
predicate that the property needs to satisfy, if one exists, and hook
that field up to verifier generation.
---
mlir/include/mlir/IR/Properties.td | 129 +++++++++++----
mlir/include/mlir/TableGen/Property.h | 5 +
mlir/lib/TableGen/Property.cpp | 14 +-
mlir/test/IR/test-op-property-predicates.mlir | 148 ++++++++++++++++++
mlir/test/lib/Dialect/Test/TestOps.td | 32 +++-
.../mlir-tblgen/op-properties-predicates.td | 72 +++++++++
mlir/test/mlir-tblgen/op-properties.td | 2 +-
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 55 +++++++
8 files changed, 417 insertions(+), 40 deletions(-)
create mode 100644 mlir/test/IR/test-op-property-predicates.mlir
create mode 100644 mlir/test/mlir-tblgen/op-properties-predicates.td
diff --git a/mlir/include/mlir/IR/Properties.td b/mlir/include/mlir/IR/Properties.td
index 0becf7d0098356..63ba0fda2ac979 100644
--- a/mlir/include/mlir/IR/Properties.td
+++ b/mlir/include/mlir/IR/Properties.td
@@ -13,6 +13,8 @@
#ifndef PROPERTIES
#define PROPERTIES
+include "mlir/IR/Constraints.td"
+
// Base class for defining properties.
class Property<string storageTypeParam = "", string desc = ""> {
// User-readable one line summary used in error reporting messages. If empty,
@@ -63,6 +65,12 @@ class Property<string storageTypeParam = "", string desc = ""> {
return convertFromAttribute($_storage, $_attr, $_diag);
}];
+ // The verification predicate for this property. Defaults to And<[]>,
+ // which is trivially true, since properties are always their expected type.
+ // Within the predicate, `$_self` is an instance of the **interface**
+ // type of the property.
+ Pred predicate = ?;
+
// The call expression to hash the property.
//
// Format:
@@ -150,8 +158,8 @@ class Property<string storageTypeParam = "", string desc = ""> {
return ::mlir::failure();
}];
- // Base definition for the property. (Will be) used for `OptionalProperty` and
- // such cases, analogously to `baseAttr`.
+ // Base definition for the property. Used to look through `OptionalProperty`
+ // for some format generation, as with the `baseAttr` field on attributes.
Property baseProperty = ?;
// Default value for the property within its storage. This should be an expression
@@ -224,8 +232,7 @@ def I64Property : IntProperty<"int64_t">;
class EnumProperty<string storageTypeParam, string desc = "", string default = ""> :
Property<storageTypeParam, desc> {
- // TODO: take advantage of EnumAttrInfo and the like to make this share nice
- // parsing code with EnumAttr.
+ // TODO: implement predicate for enum validity.
let writeToMlirBytecode = [{
$_writer.writeVarInt(static_cast<uint64_t>($_storage));
}];
@@ -330,6 +337,56 @@ def UnitProperty : Property<"bool", "unit property"> {
}];
}
+//===----------------------------------------------------------------------===//
+// Property field overwrites
+
+/// Class for giving a property a default value.
+/// This doesn't change anything about the property other than giving it a default
+/// which can be used by ODS to elide printing.
+class DefaultValuedProperty<Property p, string default = "", string storageDefault = ""> : Property<p.storageType, p.summary> {
+ let defaultValue = default;
+ let storageTypeValueOverride = storageDefault;
+ let baseProperty = p;
+ // Keep up to date with `Property` above.
+ let summary = p.summary;
+ let description = p.description;
+ let storageType = p.storageType;
+ let interfaceType = p.interfaceType;
+ let convertFromStorage = p.convertFromStorage;
+ let assignToStorage = p.assignToStorage;
+ let convertToAttribute = p.convertToAttribute;
+ let convertFromAttribute = p.convertFromAttribute;
+ let predicate = p.predicate;
+ let hashProperty = p.hashProperty;
+ let parser = p.parser;
+ let optionalParser = p.optionalParser;
+ let printer = p.printer;
+ let readFromMlirBytecode = p.readFromMlirBytecode;
+ let writeToMlirBytecode = p.writeToMlirBytecode;
+}
+
+class ConfinedProperty<Property p, Pred pred, string newSummary = "">
+ : Property<p.storageType, !if(!empty(newSummary), p.summary, newSummary)> {
+ let predicate = !if(!initialized(p.predicate), And<[p.predicate, pred]>, pred);
+ let baseProperty = p;
+ // Keep up to date with `Property` above.
+ let description = p.description;
+ let storageType = p.storageType;
+ let interfaceType = p.interfaceType;
+ let convertFromStorage = p.convertFromStorage;
+ let assignToStorage = p.assignToStorage;
+ let convertToAttribute = p.convertToAttribute;
+ let convertFromAttribute = p.convertFromAttribute;
+ let hashProperty = p.hashProperty;
+ let parser = p.parser;
+ let optionalParser = p.optionalParser;
+ let printer = p.printer;
+ let readFromMlirBytecode = p.readFromMlirBytecode;
+ let writeToMlirBytecode = p.writeToMlirBytecode;
+ let defaultValue = p.defaultValue;
+ let storageTypeValueOverride = p.storageTypeValueOverride;
+}
+
//===----------------------------------------------------------------------===//
// Primitive property combinators
@@ -342,14 +399,37 @@ class _makePropStorage<Property prop, string name> {
true : "") # ";";
}
+/// Construct a `Pred`icate `ret` that wraps the predicate of the underlying
+/// property `childProp` with:
+///
+/// [](childProp.storageType& s) {
+/// return [](childProp.interfaceType i) {
+/// return leafSubst(childProp.predicate, "$_self" to "i");
+/// }(childProp.convertFromStorage(s))
+/// }
+///
+/// and then appends `prefix` and `suffix`.
+class _makeChildWrapperPred<string prefix, Property wrappedProp, string suffix> {
+ Pred ret =
+ !if(!initialized(wrappedProp.predicate),
+ Concat<
+ prefix # "[]("
+ # "const " # wrappedProp.storageType # "& baseStore) -> bool { return []("
+ # wrappedProp.interfaceType # " baseIface) -> bool { return (",
+ SubstLeaves<"$_self", "baseIface", wrappedProp.predicate>,
+ "); }(" # !subst("$_storage", "baseStore", wrappedProp.convertFromStorage)
+ # "); }" # suffix
+ >, ?);
+}
+
/// The generic class for arrays of some other property, which is stored as a
/// `SmallVector` of that property. This uses an `ArrayAttr` as its attribute form
/// though subclasses can override this, as is the case with IntArrayAttr below.
/// Those wishing to use a non-default number of SmallVector elements should
/// subclass `ArrayProperty`.
-class ArrayProperty<Property elem = Property<>, string desc = ""> :
- Property<"::llvm::SmallVector<" # elem.storageType # ">", desc> {
- let summary = "array of " # elem.summary;
+class ArrayProperty<Property elem = Property<>, string newSummary = ""> :
+ Property<"::llvm::SmallVector<" # elem.storageType # ">",
+ !if(!empty(newSummary), "array of " # elem.summary, newSummary)> {
let interfaceType = "::llvm::ArrayRef<" # elem.storageType # ">";
let convertFromStorage = "::llvm::ArrayRef<" # elem.storageType # ">{$_storage}";
let assignToStorage = "$_storage.assign($_value.begin(), $_value.end())";
@@ -382,6 +462,8 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
return ::mlir::ArrayAttr::get($_ctxt, elems);
}];
+ let predicate = _makeChildWrapperPred<"::llvm::all_of($_self, ", elem, ")">.ret;
+
defvar theParserBegin = [{
auto& storage = $_storage;
auto parseElemFn = [&]() -> ::mlir::ParseResult {
@@ -463,8 +545,8 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
}]);
}
-class IntArrayProperty<string storageTypeParam = "", string desc = ""> :
- ArrayProperty<IntProperty<storageTypeParam, desc>> {
+class IntArrayProperty<Property elem, string newSummary=""> :
+ ArrayProperty<elem, newSummary> {
// Bring back the trivial conversions we don't get in the general case.
let convertFromAttribute = [{
return convertFromAttribute($_storage, $_attr, $_diag);
@@ -474,30 +556,6 @@ class IntArrayProperty<string storageTypeParam = "", string desc = ""> :
}];
}
-/// Class for giving a property a default value.
-/// This doesn't change anything about the property other than giving it a default
-/// which can be used by ODS to elide printing.
-class DefaultValuedProperty<Property p, string default = "", string storageDefault = ""> : Property<p.storageType, p.summary> {
- let defaultValue = default;
- let storageTypeValueOverride = storageDefault;
- let baseProperty = p;
- // Keep up to date with `Property` above.
- let summary = p.summary;
- let description = p.description;
- let storageType = p.storageType;
- let interfaceType = p.interfaceType;
- let convertFromStorage = p.convertFromStorage;
- let assignToStorage = p.assignToStorage;
- let convertToAttribute = p.convertToAttribute;
- let convertFromAttribute = p.convertFromAttribute;
- let hashProperty = p.hashProperty;
- let parser = p.parser;
- let optionalParser = p.optionalParser;
- let printer = p.printer;
- let readFromMlirBytecode = p.readFromMlirBytecode;
- let writeToMlirBytecode = p.writeToMlirBytecode;
-}
-
/// An optional property, stored as an std::optional<p.storageType>
/// interfaced with as an std::optional<p.interfaceType>..
/// The syntax is `none` (or empty string if elided) for an absent value or
@@ -575,6 +633,11 @@ class OptionalProperty<Property p, bit canDelegateParsing = 1>
return ::mlir::ArrayAttr::get($_ctxt, {attr});
}];
+ let predicate = !if(!initialized(p.predicate),
+ Or<[CPred<"!$_self.has_value()">,
+ SubstLeaves<"$_self", "(*($_self))", p.predicate>]>,
+ ?);
+
defvar delegatedParserBegin = [{
if (::mlir::succeeded($_parser.parseOptionalKeyword("none"))) {
$_storage = std::nullopt;
diff --git a/mlir/include/mlir/TableGen/Property.h b/mlir/include/mlir/TableGen/Property.h
index 702e6756e6a95c..386159191ef1f4 100644
--- a/mlir/include/mlir/TableGen/Property.h
+++ b/mlir/include/mlir/TableGen/Property.h
@@ -27,6 +27,7 @@ namespace mlir {
namespace tblgen {
class Dialect;
class Type;
+class Pred;
// Wrapper class providing helper methods for accessing MLIR Property defined
// in TableGen. This class should closely reflect what is defined as class
@@ -74,6 +75,10 @@ class Property {
return convertFromAttributeCall;
}
+ // Return the property's predicate. Properties that didn't come from
+ // tablegen (the hardcoded ones) have the null predicate.
+ Pred getPredicate() const;
+
// Returns the method call which parses this property from textual MLIR.
StringRef getParserCall() const { return parserCall; }
diff --git a/mlir/lib/TableGen/Property.cpp b/mlir/lib/TableGen/Property.cpp
index b86b87df91c607..13851167ddaf75 100644
--- a/mlir/lib/TableGen/Property.cpp
+++ b/mlir/lib/TableGen/Property.cpp
@@ -14,6 +14,7 @@
#include "mlir/TableGen/Property.h"
#include "mlir/TableGen/Format.h"
#include "mlir/TableGen/Operator.h"
+#include "mlir/TableGen/Predicate.h"
#include "llvm/TableGen/Record.h"
using namespace mlir;
@@ -68,8 +69,8 @@ Property::Property(StringRef summary, StringRef description,
StringRef writeToMlirBytecodeCall,
StringRef hashPropertyCall, StringRef defaultValue,
StringRef storageTypeValueOverride)
- : summary(summary), description(description), storageType(storageType),
- interfaceType(interfaceType),
+ : def(nullptr), summary(summary), description(description),
+ storageType(storageType), interfaceType(interfaceType),
convertFromStorageCall(convertFromStorageCall),
assignToStorageCall(assignToStorageCall),
convertToAttributeCall(convertToAttributeCall),
@@ -91,6 +92,15 @@ StringRef Property::getPropertyDefName() const {
return def->getName();
}
+Pred Property::getPredicate() const {
+ if (!def)
+ return Pred();
+ const llvm::RecordVal *maybePred = def->getValue("predicate");
+ if (!maybePred || !maybePred->getValue())
+ return Pred();
+ return Pred(maybePred->getValue());
+}
+
Property Property::getBaseProperty() const {
if (const auto *defInit =
llvm::dyn_cast<llvm::DefInit>(def->getValueInit("baseProperty"))) {
diff --git a/mlir/test/IR/test-op-property-predicates.mlir b/mlir/test/IR/test-op-property-predicates.mlir
new file mode 100644
index 00000000000000..4dba420bc8f825
--- /dev/null
+++ b/mlir/test/IR/test-op-property-predicates.mlir
@@ -0,0 +1,148 @@
+// RUN: mlir-opt -split-input-file -verify-diagnostics %s
+
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'scalar' failed to satiisfy constraint: non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = -1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'optional' failed to satiisfy constraint: optional non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [-1 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'defaulted' failed to satiisfy constraint: non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = -1 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'more_constrained' failed to satiisfy constraint: between 0 and 5}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 100 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'array' failed to satiisfy constraint: array of non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [-1 : i64],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_unconstrained' failed to satiisfy constraint: non-empty array of int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_constrained' failed to satiisfy constraint: non-empty array of non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_constrained' failed to satiisfy constraint: non-empty array of non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [-1 : i64],
+ non_empty_optional = [[7 : i64]],
+ unconstrained = 8 : i64}>
+
+// -----
+
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_optional' failed to satiisfy constraint: optional non-empty array of non-negative int64_t}}
+test.op_with_property_predicates <{
+ scalar = 1 : i64,
+ optional = [2 : i64],
+ defaulted = 3 : i64,
+ more_constrained = 4 : i64,
+ array = [],
+ non_empty_unconstrained = [5: i64],
+ non_empty_constrained = [6 : i64],
+ non_empty_optional = [[]],
+ unconstrained = 8 : i64}>
diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index d24d52f356d88f..384139d9c32c02 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -2998,7 +2998,7 @@ def TestOpWithProperties : TEST_Op<"with_properties"> {
StrAttr:$b, // Attributes can directly be used here.
StringProperty:$c,
BoolProperty:$flag,
- IntArrayProperty<"int64_t">:$array // example of an array
+ IntArrayProperty<I64Property>:$array // example of an array
);
}
@@ -3040,15 +3040,15 @@ def TestOpWithEmptyProperties : TEST_Op<"empty_properties"> {
def TestOpUsingPropertyInCustom : TEST_Op<"using_property_in_custom"> {
let assemblyFormat = "custom<UsingPropertyInCustom>($prop) attr-dict";
- let arguments = (ins IntArrayProperty<"int64_t">:$prop);
+ let arguments = (ins IntArrayProperty<I64Property>:$prop);
}
def TestOpUsingPropertyInCustomAndOther
: TEST_Op<"using_property_in_custom_and_other"> {
let assemblyFormat = "custom<UsingPropertyInCustom>($prop) prop-dict attr-dict";
let arguments = (ins
- IntArrayProperty<"int64_t">:$prop,
- IntProperty<"int64_t">:$other
+ IntArrayProperty<I64Property>:$prop,
+ I64Property:$other
);
}
@@ -3253,6 +3253,30 @@ def TestOpWithArrayProperties : TEST_Op<"with_array_properties"> {
);
}
+def NonNegativeI64Property : ConfinedProperty<I64Property,
+ CPred<"$_self >= 0">, "non-negative int64_t">;
+
+class NonEmptyArray<Property p> : ConfinedProperty
+ <ArrayProperty<p>, Neg<CPred<"$_self.empty()">>,
+ "non-empty array of " # p.summary>;
+
+def OpWithPropertyPredicates : TEST_Op<"op_with_property_predicates"> {
+ let arguments = (ins
+ NonNegativeI64Property:$scalar,
+ OptionalProperty<NonNegativeI64Property>:$optional,
+ DefaultValuedProperty<NonNegativeI64Property, "0">:$defaulted,
+ ConfinedProperty<NonNegativeI64Property,
+ CPred<"$_self <= 5">, "between 0 and 5">:$more_constrained,
+ ArrayProperty<NonNegativeI64Property>:$array,
+ NonEmptyArray<I64Property>:$non_empty_unconstrained,
+ NonEmptyArray<NonNegativeI64Property>:$non_empty_constrained,
+ // Test applying predicates when the fromStorage() on the optional<> isn't trivial.
+ OptionalProperty<NonEmptyArray<NonNegativeI64Property>>:$non_empty_optional,
+ I64Property:$unconstrained
+ );
+ let assemblyFormat = "attr-dict prop-dict";
+}
+
//===----------------------------------------------------------------------===//
// Test Dataflow
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/mlir-tblgen/op-properties-predicates.td b/mlir/test/mlir-tblgen/op-properties-predicates.td
new file mode 100644
index 00000000000000..0a036e9f0cae51
--- /dev/null
+++ b/mlir/test/mlir-tblgen/op-properties-predicates.td
@@ -0,0 +1,72 @@
+// RUN: mlir-tblgen -gen-op-defs -I %S/../../include %s | FileCheck %s
+
+include "mlir/IR/Constraints.td"
+include "mlir/IR/EnumAttr.td"
+include "mlir/IR/OpBase.td"
+include "mlir/IR/Properties.td"
+
+def Test_Dialect : Dialect {
+ let name = "test";
+ let cppNamespace = "foobar";
+}
+class NS_Op<string mnemonic, list<Trait> traits = []> :
+ Op<Test_Dialect, mnemonic, traits>;
+
+def NonNegativeI64Property : ConfinedProperty<I64Property,
+ CPred<"$_self >= 0">, "non-negative int64_t">;
+
+class NonEmptyArray<Property p> : ConfinedProperty
+ <ArrayProperty<p>, Neg<CPred<"$_self.empty()">>,
+ "non-empty array of " # p.summary>;
+
+def OpWithPredicates : NS_Op<"op_with_predicates"> {
+ let arguments = (ins
+ NonNegativeI64Property:$scalar,
+ OptionalProperty<NonNegativeI64Property>:$optional,
+ DefaultValuedProperty<NonNegativeI64Property, "0">:$defaulted,
+ ConfinedProperty<NonNegativeI64Property,
+ CPred<"$_self <= 5">, "between 0 and 5">:$moreConstrained,
+ ArrayProperty<NonNegativeI64Property>:$array,
+ NonEmptyArray<I64Property>:$non_empty_unconstrained,
+ NonEmptyArray<NonNegativeI64Property>:$non_empty_constrained,
+ // Test applying predicates when the fromStorage() on the optional<> isn't trivial.
+ OptionalProperty<NonEmptyArray<NonNegativeI64Property>>:$non_empty_optional,
+ I64Property:$unconstrained
+ );
+}
+
+// CHECK-LABEL: OpWithPredicates::verifyInvariantsImpl()
+// CHECK: int64_t tblgen_scalar = this->getScalar(); (void)tblgen_scalar;
+// CHECK: if (!((tblgen_scalar >= 0)))
+// CHECK-NEXT: return emitOpError("property 'scalar' failed to satiisfy constraint: non-negative int64_t");
+
+// CHECK: std::optional<int64_t> tblgen_optional = this->getOptional(); (void)tblgen_optional;
+// CHECK: if (!(((!tblgen_optional.has_value())) || (((*(tblgen_optional)) >= 0))))
+// CHECK-NEXT: return emitOpError("property 'optional' failed to satiisfy constraint: optional non-negative int64_t");
+
+// CHECK: int64_t tblgen_defaulted = this->getDefaulted(); (void)tblgen_defaulted;
+// CHECK: if (!((tblgen_defaulted >= 0)))
+// CHECK-NEXT: return emitOpError("property 'defaulted' failed to satiisfy constraint: non-negative int64_t");
+
+// CHECK: int64_t tblgen_moreConstrained = this->getMoreConstrained(); (void)tblgen_moreConstrained;
+// CHECK: if (!(((tblgen_moreConstrained >= 0)) && ((tblgen_moreConstrained <= 5))))
+// CHECK-NEXT: return emitOpError("property 'moreConstrained' failed to satiisfy constraint: between 0 and 5");
+
+// CHECK: ::llvm::ArrayRef<int64_t> tblgen_array = this->getArray(); (void)tblgen_array;
+// CHECK: if (!(::llvm::all_of(tblgen_array, [](const int64_t& baseStore) -> bool { return [](int64_t baseIface) -> bool { return ((baseIface >= 0)); }(baseStore); })))
+// CHECK-NEXT: return emitOpError("property 'array' failed to satiisfy constraint: array of non-negative int64_t");
+
+// CHECK: ::llvm::ArrayRef<int64_t> tblgen_nonEmptyUnconstrained = this->getNonEmptyUnconstrained(); (void)tblgen_nonEmptyUnconstrained;
+// CHECK: if (!(!((tblgen_nonEmptyUnconstrained.empty()))))
+// CHECK-NEXT: return emitOpError("property 'non_empty_unconstrained' failed to satiisfy constraint: non-empty array of int64_t");
+
+// CHECK: ::llvm::ArrayRef<int64_t> tblgen_nonEmptyConstrained = this->getNonEmptyConstrained(); (void)tblgen_nonEmptyConstrained;
+// CHECK: if (!((::llvm::all_of(tblgen_nonEmptyConstrained, [](const int64_t& baseStore) -> bool { return [](int64_t baseIface) -> bool { return ((baseIface >= 0)); }(baseStore); })) && (!((tblgen_nonEmptyConstrained.empty())))))
+// CHECK-NEXT: return emitOpError("property 'non_empty_constrained' failed to satiisfy constraint: non-empty array of non-negative int64_t");
+
+// CHECK: std::optional<::llvm::ArrayRef<int64_t>> tblgen_nonEmptyOptional = this->getNonEmptyOptional(); (void)tblgen_nonEmptyOptional;
+// CHECK: (!(((!tblgen_nonEmptyOptional.has_value())) || ((::llvm::all_of((*(tblgen_nonEmptyOptional)), [](const int64_t& baseStore) -> bool { return [](int64_t baseIface) -> bool { return ((baseIface >= 0)); }(baseStore); })) && (!(((*(tblgen_nonEmptyOptional)).empty()))))))
+// CHECK-NEXT: return emitOpError("property 'non_empty_optional' failed to satiisfy constraint: optional non-empty array of non-negative int64_t");
+
+// CHECK-NOT: int64_t tblgen_unconstrained
+// CHECK: return ::mlir::success();
diff --git a/mlir/test/mlir-tblgen/op-properties.td b/mlir/test/mlir-tblgen/op-properties.td
index 918583c9f4ed4b..bf32ce42cf6fbf 100644
--- a/mlir/test/mlir-tblgen/op-properties.td
+++ b/mlir/test/mlir-tblgen/op-properties.td
@@ -20,7 +20,7 @@ def OpWithAttr : NS_Op<"op_with_attr">{
// Test required and optional properties
// ---
-def DefaultI64Array : IntArrayProperty<"int64_t"> {
+def DefaultI64Array : IntArrayProperty<I64Property> {
let defaultValue = "::llvm::ArrayRef<int64_t>{}";
let storageTypeValueOverride = "::llvm::SmallVector<int64_t>{}";
}
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 30a2d4da573dc5..6a93d5e9c397dc 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1033,6 +1033,60 @@ while (true) {{
emitVerifier(namedAttr.attr, namedAttr.name, getVarName(namedAttr.name));
}
+static void genPropertyVerifier(const OpOrAdaptorHelper &emitHelper,
+ FmtContext &ctx, MethodBody &body) {
+
+ // Code to get a reference to a property into a variable to avoid multiple
+ // evaluations while verifying a property.
+ // {0}: Property variable name.
+ // {1}: Property name, with the first letter capitalized, to find the getter.
+ // {2}: Property interface type.
+ const char *const fetchProperty = R"(
+ {2} {0} = this->get{1}(); (void){0};
+)";
+
+ // Code to verify that the predicate of a property holds. Embeds the
+ // condition inline.
+ // {0}: Property condition code, pre-tgfmt()'d.
+ // {1}: Emit error prefix.
+ // {2}: Property name.
+ // {3}: Property description.
+ const char *const verifyProperty = R"(
+ if (!({0}))
+ return {1}"property '{2}' failed to satiisfy constraint: {3}");
+)";
+
+ // Prefix variables with `tblgen_` to avoid hiding the attribute accessor.
+ const auto getVarName = [&](const NamedProperty &prop) {
+ std::string varName =
+ convertToCamelFromSnakeCase(prop.name, /*capitalizeFirst=*/false);
+ return (tblgenNamePrefix + Twine(varName)).str();
+ };
+
+ body.indent();
+ for (const NamedProperty &prop : emitHelper.getOp().getProperties()) {
+ Pred predicate = prop.prop.getPredicate();
+ // Null predicate, nothing to verify.
+ if (predicate == Pred())
+ continue;
+
+ std::string rawCondition = predicate.getCondition();
+ bool needsOp = StringRef(rawCondition).contains("$_op");
+ if (needsOp && !emitHelper.isEmittingForOp())
+ continue;
+
+ std::string varName = getVarName(prop);
+ std::string getterName =
+ convertToCamelFromSnakeCase(prop.name, /*capitalizeFirst=*/true);
+ body << formatv(fetchProperty, varName, getterName,
+ prop.prop.getInterfaceType());
+ body << formatv(verifyProperty, tgfmt(rawCondition, &ctx.withSelf(varName)),
+ emitHelper.emitErrorPrefix(), prop.name,
+ prop.prop.getSummary());
+ }
+ body.unindent();
+}
+
/// Include declarations specified on NativeTrait
static std::string formatExtraDeclarations(const Operator &op) {
SmallVector<StringRef> extraDeclarations;
@@ -3726,6 +3780,7 @@ void OpEmitter::genVerifier() {
bool useProperties = emitHelper.hasProperties();
populateSubstitutions(emitHelper, verifyCtx);
+ genPropertyVerifier(emitHelper, verifyCtx, implBody);
genAttributeVerifier(emitHelper, verifyCtx, implBody, staticVerifierEmitter,
useProperties);
genOperandResultVerifier(implBody, op.getOperands(), "operand");
>From 3238de521d7ad489ec5f461efca903e813caa99c Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Tue, 17 Dec 2024 19:39:32 -0800
Subject: [PATCH 2/4] Review comments
---
mlir/include/mlir/IR/Constraints.td | 6 +++
mlir/include/mlir/IR/Properties.td | 40 ++++++++++---------
mlir/lib/TableGen/Predicate.cpp | 10 +++++
mlir/test/IR/test-op-property-predicates.mlir | 18 ++++-----
.../mlir-tblgen/op-properties-predicates.td | 33 +++++++--------
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 10 +++--
6 files changed, 70 insertions(+), 47 deletions(-)
diff --git a/mlir/include/mlir/IR/Constraints.td b/mlir/include/mlir/IR/Constraints.td
index 13223aa8abcdaa..62bc84c3870636 100644
--- a/mlir/include/mlir/IR/Constraints.td
+++ b/mlir/include/mlir/IR/Constraints.td
@@ -93,6 +93,12 @@ class Or<list<Pred> children> : CombinedPred<PredCombinerOr, children>;
// A predicate that holds if its child does not.
class Neg<Pred child> : CombinedPred<PredCombinerNot, [child]>;
+// A predicate that is always true.
+defvar TruePred = And<[]>;
+
+// A predicate that is always false.
+defvar False = Or<[]>;
+
// A predicate that substitutes "pat" with "repl" in predicate calls of the
// leaves of the predicate tree (i.e., not CombinedPred).
//
diff --git a/mlir/include/mlir/IR/Properties.td b/mlir/include/mlir/IR/Properties.td
index 63ba0fda2ac979..3cbef7fe1901e5 100644
--- a/mlir/include/mlir/IR/Properties.td
+++ b/mlir/include/mlir/IR/Properties.td
@@ -65,11 +65,12 @@ class Property<string storageTypeParam = "", string desc = ""> {
return convertFromAttribute($_storage, $_attr, $_diag);
}];
- // The verification predicate for this property. Defaults to And<[]>,
- // which is trivially true, since properties are always their expected type.
+ // The verification predicate for this property. Defaults to the true predicate,
+ // since properties are always their expected type.
// Within the predicate, `$_self` is an instance of the **interface**
- // type of the property.
- Pred predicate = ?;
+ // type of the property. Setting this field to ? will also result in a
+ // true predicate but is not recommended, as it breaks composability.
+ Pred predicate = TruePred;
// The call expression to hash the property.
//
@@ -365,9 +366,12 @@ class DefaultValuedProperty<Property p, string default = "", string storageDefau
let writeToMlirBytecode = p.writeToMlirBytecode;
}
+/// Apply the predicate `pred` to the property `p`, ANDing it with any
+/// predicates it may already have. If `newSummary` is provided, replace the
+/// summary of `p` with `newSummary`.
class ConfinedProperty<Property p, Pred pred, string newSummary = "">
: Property<p.storageType, !if(!empty(newSummary), p.summary, newSummary)> {
- let predicate = !if(!initialized(p.predicate), And<[p.predicate, pred]>, pred);
+ let predicate = !if(!ne(p.predicate, TruePred), And<[p.predicate, pred]>, pred);
let baseProperty = p;
// Keep up to date with `Property` above.
let description = p.description;
@@ -409,17 +413,15 @@ class _makePropStorage<Property prop, string name> {
/// }
///
/// and then appends `prefix` and `suffix`.
-class _makeChildWrapperPred<string prefix, Property wrappedProp, string suffix> {
+class _makeStoragedWrapperPred<Property wrappedProp> {
Pred ret =
- !if(!initialized(wrappedProp.predicate),
- Concat<
- prefix # "[]("
- # "const " # wrappedProp.storageType # "& baseStore) -> bool { return []("
- # wrappedProp.interfaceType # " baseIface) -> bool { return (",
- SubstLeaves<"$_self", "baseIface", wrappedProp.predicate>,
- "); }(" # !subst("$_storage", "baseStore", wrappedProp.convertFromStorage)
- # "); }" # suffix
- >, ?);
+ Concat<
+ "[](" # "const " # wrappedProp.storageType
+ # "& baseStore) -> bool { return []("
+ # wrappedProp.interfaceType # " baseIface) -> bool { return (",
+ SubstLeaves<"$_self", "baseIface", wrappedProp.predicate>,
+ "); }(" # !subst("$_storage", "baseStore", wrappedProp.convertFromStorage)
+ # "); }">;
}
/// The generic class for arrays of some other property, which is stored as a
@@ -462,7 +464,9 @@ class ArrayProperty<Property elem = Property<>, string newSummary = ""> :
return ::mlir::ArrayAttr::get($_ctxt, elems);
}];
- let predicate = _makeChildWrapperPred<"::llvm::all_of($_self, ", elem, ")">.ret;
+ let predicate = !if(!eq(elem.predicate, TruePred),
+ TruePred,
+ Concat<"::llvm::all_of($_self, ", _makeStoragedWrapperPred<elem>.ret, ")">);
defvar theParserBegin = [{
auto& storage = $_storage;
@@ -633,10 +637,10 @@ class OptionalProperty<Property p, bit canDelegateParsing = 1>
return ::mlir::ArrayAttr::get($_ctxt, {attr});
}];
- let predicate = !if(!initialized(p.predicate),
+ let predicate = !if(!ne(p.predicate, TruePred),
Or<[CPred<"!$_self.has_value()">,
SubstLeaves<"$_self", "(*($_self))", p.predicate>]>,
- ?);
+ TruePred);
defvar delegatedParserBegin = [{
if (::mlir::succeeded($_parser.parseOptionalKeyword("none"))) {
diff --git a/mlir/lib/TableGen/Predicate.cpp b/mlir/lib/TableGen/Predicate.cpp
index f71dd0bd35f86c..e5cfc074d09f4e 100644
--- a/mlir/lib/TableGen/Predicate.cpp
+++ b/mlir/lib/TableGen/Predicate.cpp
@@ -235,6 +235,16 @@ propagateGroundTruth(PredNode *node,
return node;
}
+ if (node->kind == PredCombinerKind::And && node->children.empty()) {
+ node->kind = PredCombinerKind::True;
+ return node;
+ }
+
+ if (node->kind == PredCombinerKind::Or && node->children.empty()) {
+ node->kind = PredCombinerKind::False;
+ return node;
+ }
+
// Otherwise, look at child nodes.
// Move child nodes into some local variable so that they can be optimized
diff --git a/mlir/test/IR/test-op-property-predicates.mlir b/mlir/test/IR/test-op-property-predicates.mlir
index 4dba420bc8f825..3a4e2972948a43 100644
--- a/mlir/test/IR/test-op-property-predicates.mlir
+++ b/mlir/test/IR/test-op-property-predicates.mlir
@@ -23,7 +23,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'scalar' failed to satiisfy constraint: non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'scalar' failed to satisfy constraint: non-negative int64_t}}
test.op_with_property_predicates <{
scalar = -1 : i64,
optional = [2 : i64],
@@ -37,7 +37,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'optional' failed to satiisfy constraint: optional non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'optional' failed to satisfy constraint: optional non-negative int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [-1 : i64],
@@ -51,7 +51,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'defaulted' failed to satiisfy constraint: non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'defaulted' failed to satisfy constraint: non-negative int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
@@ -65,7 +65,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'more_constrained' failed to satiisfy constraint: between 0 and 5}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'more_constrained' failed to satisfy constraint: between 0 and 5}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
@@ -79,7 +79,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'array' failed to satiisfy constraint: array of non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'array' failed to satisfy constraint: array of non-negative int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
@@ -93,7 +93,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_unconstrained' failed to satiisfy constraint: non-empty array of int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_unconstrained' failed to satisfy constraint: non-empty array of int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
@@ -107,7 +107,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_constrained' failed to satiisfy constraint: non-empty array of non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_constrained' failed to satisfy constraint: non-empty array of non-negative int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
@@ -121,7 +121,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_constrained' failed to satiisfy constraint: non-empty array of non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_constrained' failed to satisfy constraint: non-empty array of non-negative int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
@@ -135,7 +135,7 @@ test.op_with_property_predicates <{
// -----
-// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_optional' failed to satiisfy constraint: optional non-empty array of non-negative int64_t}}
+// expected-error @+1 {{'test.op_with_property_predicates' op property 'non_empty_optional' failed to satisfy constraint: optional non-empty array of non-negative int64_t}}
test.op_with_property_predicates <{
scalar = 1 : i64,
optional = [2 : i64],
diff --git a/mlir/test/mlir-tblgen/op-properties-predicates.td b/mlir/test/mlir-tblgen/op-properties-predicates.td
index 0a036e9f0cae51..fa06e14fb19986 100644
--- a/mlir/test/mlir-tblgen/op-properties-predicates.td
+++ b/mlir/test/mlir-tblgen/op-properties-predicates.td
@@ -36,37 +36,38 @@ def OpWithPredicates : NS_Op<"op_with_predicates"> {
}
// CHECK-LABEL: OpWithPredicates::verifyInvariantsImpl()
-// CHECK: int64_t tblgen_scalar = this->getScalar(); (void)tblgen_scalar;
+// Note: for test readibility, we capture [[maybe_unused]] into the variable maybe_unused
+// CHECK: [[maybe_unused:\[\[maybe_unused\]\]]] int64_t tblgen_scalar = this->getScalar();
// CHECK: if (!((tblgen_scalar >= 0)))
-// CHECK-NEXT: return emitOpError("property 'scalar' failed to satiisfy constraint: non-negative int64_t");
+// CHECK-NEXT: return emitOpError("property 'scalar' failed to satisfy constraint: non-negative int64_t");
-// CHECK: std::optional<int64_t> tblgen_optional = this->getOptional(); (void)tblgen_optional;
+// CHECK: [[maybe_unused]] std::optional<int64_t> tblgen_optional = this->getOptional();
// CHECK: if (!(((!tblgen_optional.has_value())) || (((*(tblgen_optional)) >= 0))))
-// CHECK-NEXT: return emitOpError("property 'optional' failed to satiisfy constraint: optional non-negative int64_t");
+// CHECK-NEXT: return emitOpError("property 'optional' failed to satisfy constraint: optional non-negative int64_t");
-// CHECK: int64_t tblgen_defaulted = this->getDefaulted(); (void)tblgen_defaulted;
+// CHECK: [[maybe_unused]] int64_t tblgen_defaulted = this->getDefaulted();
// CHECK: if (!((tblgen_defaulted >= 0)))
-// CHECK-NEXT: return emitOpError("property 'defaulted' failed to satiisfy constraint: non-negative int64_t");
+// CHECK-NEXT: return emitOpError("property 'defaulted' failed to satisfy constraint: non-negative int64_t");
-// CHECK: int64_t tblgen_moreConstrained = this->getMoreConstrained(); (void)tblgen_moreConstrained;
+// CHECK: [[maybe_unused]] int64_t tblgen_moreConstrained = this->getMoreConstrained();
// CHECK: if (!(((tblgen_moreConstrained >= 0)) && ((tblgen_moreConstrained <= 5))))
-// CHECK-NEXT: return emitOpError("property 'moreConstrained' failed to satiisfy constraint: between 0 and 5");
+// CHECK-NEXT: return emitOpError("property 'moreConstrained' failed to satisfy constraint: between 0 and 5");
-// CHECK: ::llvm::ArrayRef<int64_t> tblgen_array = this->getArray(); (void)tblgen_array;
+// CHECK: [[maybe_unused]] ::llvm::ArrayRef<int64_t> tblgen_array = this->getArray();
// CHECK: if (!(::llvm::all_of(tblgen_array, [](const int64_t& baseStore) -> bool { return [](int64_t baseIface) -> bool { return ((baseIface >= 0)); }(baseStore); })))
-// CHECK-NEXT: return emitOpError("property 'array' failed to satiisfy constraint: array of non-negative int64_t");
+// CHECK-NEXT: return emitOpError("property 'array' failed to satisfy constraint: array of non-negative int64_t");
-// CHECK: ::llvm::ArrayRef<int64_t> tblgen_nonEmptyUnconstrained = this->getNonEmptyUnconstrained(); (void)tblgen_nonEmptyUnconstrained;
+// CHECK: [[maybe_unused]] ::llvm::ArrayRef<int64_t> tblgen_nonEmptyUnconstrained = this->getNonEmptyUnconstrained();
// CHECK: if (!(!((tblgen_nonEmptyUnconstrained.empty()))))
-// CHECK-NEXT: return emitOpError("property 'non_empty_unconstrained' failed to satiisfy constraint: non-empty array of int64_t");
+// CHECK-NEXT: return emitOpError("property 'non_empty_unconstrained' failed to satisfy constraint: non-empty array of int64_t");
-// CHECK: ::llvm::ArrayRef<int64_t> tblgen_nonEmptyConstrained = this->getNonEmptyConstrained(); (void)tblgen_nonEmptyConstrained;
+// CHECK: [[maybe_unused]] ::llvm::ArrayRef<int64_t> tblgen_nonEmptyConstrained = this->getNonEmptyConstrained();
// CHECK: if (!((::llvm::all_of(tblgen_nonEmptyConstrained, [](const int64_t& baseStore) -> bool { return [](int64_t baseIface) -> bool { return ((baseIface >= 0)); }(baseStore); })) && (!((tblgen_nonEmptyConstrained.empty())))))
-// CHECK-NEXT: return emitOpError("property 'non_empty_constrained' failed to satiisfy constraint: non-empty array of non-negative int64_t");
+// CHECK-NEXT: return emitOpError("property 'non_empty_constrained' failed to satisfy constraint: non-empty array of non-negative int64_t");
-// CHECK: std::optional<::llvm::ArrayRef<int64_t>> tblgen_nonEmptyOptional = this->getNonEmptyOptional(); (void)tblgen_nonEmptyOptional;
+// CHECK: [[maybe_unused]] std::optional<::llvm::ArrayRef<int64_t>> tblgen_nonEmptyOptional = this->getNonEmptyOptional();
// CHECK: (!(((!tblgen_nonEmptyOptional.has_value())) || ((::llvm::all_of((*(tblgen_nonEmptyOptional)), [](const int64_t& baseStore) -> bool { return [](int64_t baseIface) -> bool { return ((baseIface >= 0)); }(baseStore); })) && (!(((*(tblgen_nonEmptyOptional)).empty()))))))
-// CHECK-NEXT: return emitOpError("property 'non_empty_optional' failed to satiisfy constraint: optional non-empty array of non-negative int64_t");
+// CHECK-NEXT: return emitOpError("property 'non_empty_optional' failed to satisfy constraint: optional non-empty array of non-negative int64_t");
// CHECK-NOT: int64_t tblgen_unconstrained
// CHECK: return ::mlir::success();
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 6a93d5e9c397dc..78c97110c93828 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1042,18 +1042,18 @@ static void genPropertyVerifier(const OpOrAdaptorHelper &emitHelper,
// {1}: Property name, with the first letter capitalized, to find the getter.
// {2}: Property interface type.
const char *const fetchProperty = R"(
- {2} {0} = this->get{1}(); (void){0};
+ [[maybe_unused]] {2} {0} = this->get{1}();
)";
// Code to verify that the predicate of a property holds. Embeds the
// condition inline.
- // {0}: Property condition code, pre-tgfmt()'d.
+ // {0}: Property condition code, with tgfmt() applied.
// {1}: Emit error prefix.
// {2}: Property name.
// {3}: Property description.
const char *const verifyProperty = R"(
if (!({0}))
- return {1}"property '{2}' failed to satiisfy constraint: {3}");
+ return {1}"property '{2}' failed to satisfy constraint: {3}");
)";
// Prefix variables with `tblgen_` to avoid hiding the attribute accessor.
@@ -1063,7 +1063,6 @@ static void genPropertyVerifier(const OpOrAdaptorHelper &emitHelper,
return (tblgenNamePrefix + Twine(varName)).str();
};
- body.indent();
for (const NamedProperty &prop : emitHelper.getOp().getProperties()) {
Pred predicate = prop.prop.getPredicate();
// Null predicate, nothing to verify.
@@ -1071,10 +1070,13 @@ static void genPropertyVerifier(const OpOrAdaptorHelper &emitHelper,
continue;
std::string rawCondition = predicate.getCondition();
+ if (rawCondition == "true")
+ continue;
bool needsOp = StringRef(rawCondition).contains("$_op");
if (needsOp && !emitHelper.isEmittingForOp())
continue;
+ auto scope = body.scope("{\n", "}\n", /*indent=*/true);
std::string varName = getVarName(prop);
std::string getterName =
convertToCamelFromSnakeCase(prop.name, /*capitalizeFirst=*/true);
>From d146c79cfa5ab2f8713edbf33f05a650a0f35359 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Tue, 17 Dec 2024 19:43:31 -0800
Subject: [PATCH 3/4] Fix typo
---
mlir/include/mlir/IR/Properties.td | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mlir/include/mlir/IR/Properties.td b/mlir/include/mlir/IR/Properties.td
index 3cbef7fe1901e5..df630ada78d358 100644
--- a/mlir/include/mlir/IR/Properties.td
+++ b/mlir/include/mlir/IR/Properties.td
@@ -413,7 +413,7 @@ class _makePropStorage<Property prop, string name> {
/// }
///
/// and then appends `prefix` and `suffix`.
-class _makeStoragedWrapperPred<Property wrappedProp> {
+class _makeStorageWrapperPred<Property wrappedProp> {
Pred ret =
Concat<
"[](" # "const " # wrappedProp.storageType
@@ -466,7 +466,7 @@ class ArrayProperty<Property elem = Property<>, string newSummary = ""> :
let predicate = !if(!eq(elem.predicate, TruePred),
TruePred,
- Concat<"::llvm::all_of($_self, ", _makeStoragedWrapperPred<elem>.ret, ")">);
+ Concat<"::llvm::all_of($_self, ", _makeStorageWrapperPred<elem>.ret, ")">);
defvar theParserBegin = [{
auto& storage = $_storage;
>From 12a6e243ef0b646eab991d55accc1c2da9883709 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Tue, 17 Dec 2024 19:45:59 -0800
Subject: [PATCH 4/4] Remove stray unindent
---
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 78c97110c93828..a970cbc5cacebe 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -1086,7 +1086,6 @@ static void genPropertyVerifier(const OpOrAdaptorHelper &emitHelper,
emitHelper.emitErrorPrefix(), prop.name,
prop.prop.getSummary());
}
- body.unindent();
}
/// Include declarations specified on NativeTrait
More information about the Mlir-commits
mailing list