Skip to content

Commit e8b571f

Browse files
committed
[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.
1 parent 20deaa1 commit e8b571f

File tree

8 files changed

+417
-40
lines changed

8 files changed

+417
-40
lines changed

mlir/include/mlir/IR/Properties.td

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#ifndef PROPERTIES
1414
#define PROPERTIES
1515

16+
include "mlir/IR/Constraints.td"
17+
1618
// Base class for defining properties.
1719
class Property<string storageTypeParam = "", string desc = ""> {
1820
// User-readable one line summary used in error reporting messages. If empty,
@@ -63,6 +65,12 @@ class Property<string storageTypeParam = "", string desc = ""> {
6365
return convertFromAttribute($_storage, $_attr, $_diag);
6466
}];
6567

68+
// The verification predicate for this property. Defaults to And<[]>,
69+
// which is trivially true, since properties are always their expected type.
70+
// Within the predicate, `$_self` is an instance of the **interface**
71+
// type of the property.
72+
Pred predicate = ?;
73+
6674
// The call expression to hash the property.
6775
//
6876
// Format:
@@ -150,8 +158,8 @@ class Property<string storageTypeParam = "", string desc = ""> {
150158
return ::mlir::failure();
151159
}];
152160

153-
// Base definition for the property. (Will be) used for `OptionalProperty` and
154-
// such cases, analogously to `baseAttr`.
161+
// Base definition for the property. Used to look through `OptionalProperty`
162+
// for some format generation, as with the `baseAttr` field on attributes.
155163
Property baseProperty = ?;
156164

157165
// Default value for the property within its storage. This should be an expression
@@ -224,8 +232,7 @@ def I64Property : IntProperty<"int64_t">;
224232

225233
class EnumProperty<string storageTypeParam, string desc = "", string default = ""> :
226234
Property<storageTypeParam, desc> {
227-
// TODO: take advantage of EnumAttrInfo and the like to make this share nice
228-
// parsing code with EnumAttr.
235+
// TODO: implement predicate for enum validity.
229236
let writeToMlirBytecode = [{
230237
$_writer.writeVarInt(static_cast<uint64_t>($_storage));
231238
}];
@@ -330,6 +337,56 @@ def UnitProperty : Property<"bool", "unit property"> {
330337
}];
331338
}
332339

340+
//===----------------------------------------------------------------------===//
341+
// Property field overwrites
342+
343+
/// Class for giving a property a default value.
344+
/// This doesn't change anything about the property other than giving it a default
345+
/// which can be used by ODS to elide printing.
346+
class DefaultValuedProperty<Property p, string default = "", string storageDefault = ""> : Property<p.storageType, p.summary> {
347+
let defaultValue = default;
348+
let storageTypeValueOverride = storageDefault;
349+
let baseProperty = p;
350+
// Keep up to date with `Property` above.
351+
let summary = p.summary;
352+
let description = p.description;
353+
let storageType = p.storageType;
354+
let interfaceType = p.interfaceType;
355+
let convertFromStorage = p.convertFromStorage;
356+
let assignToStorage = p.assignToStorage;
357+
let convertToAttribute = p.convertToAttribute;
358+
let convertFromAttribute = p.convertFromAttribute;
359+
let predicate = p.predicate;
360+
let hashProperty = p.hashProperty;
361+
let parser = p.parser;
362+
let optionalParser = p.optionalParser;
363+
let printer = p.printer;
364+
let readFromMlirBytecode = p.readFromMlirBytecode;
365+
let writeToMlirBytecode = p.writeToMlirBytecode;
366+
}
367+
368+
class ConfinedProperty<Property p, Pred pred, string newSummary = "">
369+
: Property<p.storageType, !if(!empty(newSummary), p.summary, newSummary)> {
370+
let predicate = !if(!initialized(p.predicate), And<[p.predicate, pred]>, pred);
371+
let baseProperty = p;
372+
// Keep up to date with `Property` above.
373+
let description = p.description;
374+
let storageType = p.storageType;
375+
let interfaceType = p.interfaceType;
376+
let convertFromStorage = p.convertFromStorage;
377+
let assignToStorage = p.assignToStorage;
378+
let convertToAttribute = p.convertToAttribute;
379+
let convertFromAttribute = p.convertFromAttribute;
380+
let hashProperty = p.hashProperty;
381+
let parser = p.parser;
382+
let optionalParser = p.optionalParser;
383+
let printer = p.printer;
384+
let readFromMlirBytecode = p.readFromMlirBytecode;
385+
let writeToMlirBytecode = p.writeToMlirBytecode;
386+
let defaultValue = p.defaultValue;
387+
let storageTypeValueOverride = p.storageTypeValueOverride;
388+
}
389+
333390
//===----------------------------------------------------------------------===//
334391
// Primitive property combinators
335392

@@ -342,14 +399,37 @@ class _makePropStorage<Property prop, string name> {
342399
true : "") # ";";
343400
}
344401

402+
/// Construct a `Pred`icate `ret` that wraps the predicate of the underlying
403+
/// property `childProp` with:
404+
///
405+
/// [](childProp.storageType& s) {
406+
/// return [](childProp.interfaceType i) {
407+
/// return leafSubst(childProp.predicate, "$_self" to "i");
408+
/// }(childProp.convertFromStorage(s))
409+
/// }
410+
///
411+
/// and then appends `prefix` and `suffix`.
412+
class _makeChildWrapperPred<string prefix, Property wrappedProp, string suffix> {
413+
Pred ret =
414+
!if(!initialized(wrappedProp.predicate),
415+
Concat<
416+
prefix # "[]("
417+
# "const " # wrappedProp.storageType # "& baseStore) -> bool { return []("
418+
# wrappedProp.interfaceType # " baseIface) -> bool { return (",
419+
SubstLeaves<"$_self", "baseIface", wrappedProp.predicate>,
420+
"); }(" # !subst("$_storage", "baseStore", wrappedProp.convertFromStorage)
421+
# "); }" # suffix
422+
>, ?);
423+
}
424+
345425
/// The generic class for arrays of some other property, which is stored as a
346426
/// `SmallVector` of that property. This uses an `ArrayAttr` as its attribute form
347427
/// though subclasses can override this, as is the case with IntArrayAttr below.
348428
/// Those wishing to use a non-default number of SmallVector elements should
349429
/// subclass `ArrayProperty`.
350-
class ArrayProperty<Property elem = Property<>, string desc = ""> :
351-
Property<"::llvm::SmallVector<" # elem.storageType # ">", desc> {
352-
let summary = "array of " # elem.summary;
430+
class ArrayProperty<Property elem = Property<>, string newSummary = ""> :
431+
Property<"::llvm::SmallVector<" # elem.storageType # ">",
432+
!if(!empty(newSummary), "array of " # elem.summary, newSummary)> {
353433
let interfaceType = "::llvm::ArrayRef<" # elem.storageType # ">";
354434
let convertFromStorage = "::llvm::ArrayRef<" # elem.storageType # ">{$_storage}";
355435
let assignToStorage = "$_storage.assign($_value.begin(), $_value.end())";
@@ -382,6 +462,8 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
382462
return ::mlir::ArrayAttr::get($_ctxt, elems);
383463
}];
384464

465+
let predicate = _makeChildWrapperPred<"::llvm::all_of($_self, ", elem, ")">.ret;
466+
385467
defvar theParserBegin = [{
386468
auto& storage = $_storage;
387469
auto parseElemFn = [&]() -> ::mlir::ParseResult {
@@ -463,8 +545,8 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
463545
}]);
464546
}
465547

466-
class IntArrayProperty<string storageTypeParam = "", string desc = ""> :
467-
ArrayProperty<IntProperty<storageTypeParam, desc>> {
548+
class IntArrayProperty<Property elem, string newSummary=""> :
549+
ArrayProperty<elem, newSummary> {
468550
// Bring back the trivial conversions we don't get in the general case.
469551
let convertFromAttribute = [{
470552
return convertFromAttribute($_storage, $_attr, $_diag);
@@ -474,30 +556,6 @@ class IntArrayProperty<string storageTypeParam = "", string desc = ""> :
474556
}];
475557
}
476558

477-
/// Class for giving a property a default value.
478-
/// This doesn't change anything about the property other than giving it a default
479-
/// which can be used by ODS to elide printing.
480-
class DefaultValuedProperty<Property p, string default = "", string storageDefault = ""> : Property<p.storageType, p.summary> {
481-
let defaultValue = default;
482-
let storageTypeValueOverride = storageDefault;
483-
let baseProperty = p;
484-
// Keep up to date with `Property` above.
485-
let summary = p.summary;
486-
let description = p.description;
487-
let storageType = p.storageType;
488-
let interfaceType = p.interfaceType;
489-
let convertFromStorage = p.convertFromStorage;
490-
let assignToStorage = p.assignToStorage;
491-
let convertToAttribute = p.convertToAttribute;
492-
let convertFromAttribute = p.convertFromAttribute;
493-
let hashProperty = p.hashProperty;
494-
let parser = p.parser;
495-
let optionalParser = p.optionalParser;
496-
let printer = p.printer;
497-
let readFromMlirBytecode = p.readFromMlirBytecode;
498-
let writeToMlirBytecode = p.writeToMlirBytecode;
499-
}
500-
501559
/// An optional property, stored as an std::optional<p.storageType>
502560
/// interfaced with as an std::optional<p.interfaceType>..
503561
/// 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>
575633
return ::mlir::ArrayAttr::get($_ctxt, {attr});
576634
}];
577635

636+
let predicate = !if(!initialized(p.predicate),
637+
Or<[CPred<"!$_self.has_value()">,
638+
SubstLeaves<"$_self", "(*($_self))", p.predicate>]>,
639+
?);
640+
578641
defvar delegatedParserBegin = [{
579642
if (::mlir::succeeded($_parser.parseOptionalKeyword("none"))) {
580643
$_storage = std::nullopt;

mlir/include/mlir/TableGen/Property.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace mlir {
2727
namespace tblgen {
2828
class Dialect;
2929
class Type;
30+
class Pred;
3031

3132
// Wrapper class providing helper methods for accessing MLIR Property defined
3233
// in TableGen. This class should closely reflect what is defined as class
@@ -74,6 +75,10 @@ class Property {
7475
return convertFromAttributeCall;
7576
}
7677

78+
// Return the property's predicate. Properties that didn't come from
79+
// tablegen (the hardcoded ones) have the null predicate.
80+
Pred getPredicate() const;
81+
7782
// Returns the method call which parses this property from textual MLIR.
7883
StringRef getParserCall() const { return parserCall; }
7984

mlir/lib/TableGen/Property.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "mlir/TableGen/Property.h"
1515
#include "mlir/TableGen/Format.h"
1616
#include "mlir/TableGen/Operator.h"
17+
#include "mlir/TableGen/Predicate.h"
1718
#include "llvm/TableGen/Record.h"
1819

1920
using namespace mlir;
@@ -68,8 +69,8 @@ Property::Property(StringRef summary, StringRef description,
6869
StringRef writeToMlirBytecodeCall,
6970
StringRef hashPropertyCall, StringRef defaultValue,
7071
StringRef storageTypeValueOverride)
71-
: summary(summary), description(description), storageType(storageType),
72-
interfaceType(interfaceType),
72+
: def(nullptr), summary(summary), description(description),
73+
storageType(storageType), interfaceType(interfaceType),
7374
convertFromStorageCall(convertFromStorageCall),
7475
assignToStorageCall(assignToStorageCall),
7576
convertToAttributeCall(convertToAttributeCall),
@@ -91,6 +92,15 @@ StringRef Property::getPropertyDefName() const {
9192
return def->getName();
9293
}
9394

95+
Pred Property::getPredicate() const {
96+
if (!def)
97+
return Pred();
98+
const llvm::RecordVal *maybePred = def->getValue("predicate");
99+
if (!maybePred || !maybePred->getValue())
100+
return Pred();
101+
return Pred(maybePred->getValue());
102+
}
103+
94104
Property Property::getBaseProperty() const {
95105
if (const auto *defInit =
96106
llvm::dyn_cast<llvm::DefInit>(def->getValueInit("baseProperty"))) {

0 commit comments

Comments
 (0)