1313#ifndef PROPERTIES
1414#define PROPERTIES
1515
16+ include "mlir/IR/Constraints.td"
17+
1618// Base class for defining properties.
1719class 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
225233class 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;
0 commit comments