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,13 @@ class Property<string storageTypeParam = "", string desc = ""> {
6365 return convertFromAttribute($_storage, $_attr, $_diag);
6466 }];
6567
68+ // The verification predicate for this property. Defaults to the true predicate,
69+ // since properties are always their expected type.
70+ // Within the predicate, `$_self` is an instance of the **interface**
71+ // type of the property. Setting this field to ? will also result in a
72+ // true predicate but is not recommended, as it breaks composability.
73+ Pred predicate = TruePred;
74+
6675 // The call expression to hash the property.
6776 //
6877 // Format:
@@ -150,8 +159,8 @@ class Property<string storageTypeParam = "", string desc = ""> {
150159 return ::mlir::failure();
151160 }];
152161
153- // Base definition for the property. (Will be) used for `OptionalProperty` and
154- // such cases, analogously to `baseAttr`.
162+ // Base definition for the property. Used to look through `OptionalProperty`
163+ // for some format generation, as with the `baseAttr` field on attributes .
155164 Property baseProperty = ?;
156165
157166 // Default value for the property within its storage. This should be an expression
@@ -224,8 +233,7 @@ def I64Property : IntProperty<"int64_t">;
224233
225234class EnumProperty<string storageTypeParam, string desc = "", string default = ""> :
226235 Property<storageTypeParam, desc> {
227- // TODO: take advantage of EnumAttrInfo and the like to make this share nice
228- // parsing code with EnumAttr.
236+ // TODO: implement predicate for enum validity.
229237 let writeToMlirBytecode = [{
230238 $_writer.writeVarInt(static_cast<uint64_t>($_storage));
231239 }];
@@ -330,6 +338,59 @@ def UnitProperty : Property<"bool", "unit property"> {
330338 }];
331339}
332340
341+ //===----------------------------------------------------------------------===//
342+ // Property field overwrites
343+
344+ /// Class for giving a property a default value.
345+ /// This doesn't change anything about the property other than giving it a default
346+ /// which can be used by ODS to elide printing.
347+ class DefaultValuedProperty<Property p, string default = "", string storageDefault = ""> : Property<p.storageType, p.summary> {
348+ let defaultValue = default;
349+ let storageTypeValueOverride = storageDefault;
350+ let baseProperty = p;
351+ // Keep up to date with `Property` above.
352+ let summary = p.summary;
353+ let description = p.description;
354+ let storageType = p.storageType;
355+ let interfaceType = p.interfaceType;
356+ let convertFromStorage = p.convertFromStorage;
357+ let assignToStorage = p.assignToStorage;
358+ let convertToAttribute = p.convertToAttribute;
359+ let convertFromAttribute = p.convertFromAttribute;
360+ let predicate = p.predicate;
361+ let hashProperty = p.hashProperty;
362+ let parser = p.parser;
363+ let optionalParser = p.optionalParser;
364+ let printer = p.printer;
365+ let readFromMlirBytecode = p.readFromMlirBytecode;
366+ let writeToMlirBytecode = p.writeToMlirBytecode;
367+ }
368+
369+ /// Apply the predicate `pred` to the property `p`, ANDing it with any
370+ /// predicates it may already have. If `newSummary` is provided, replace the
371+ /// summary of `p` with `newSummary`.
372+ class ConfinedProperty<Property p, Pred pred, string newSummary = "">
373+ : Property<p.storageType, !if(!empty(newSummary), p.summary, newSummary)> {
374+ let predicate = !if(!ne(p.predicate, TruePred), And<[p.predicate, pred]>, pred);
375+ let baseProperty = p;
376+ // Keep up to date with `Property` above.
377+ let description = p.description;
378+ let storageType = p.storageType;
379+ let interfaceType = p.interfaceType;
380+ let convertFromStorage = p.convertFromStorage;
381+ let assignToStorage = p.assignToStorage;
382+ let convertToAttribute = p.convertToAttribute;
383+ let convertFromAttribute = p.convertFromAttribute;
384+ let hashProperty = p.hashProperty;
385+ let parser = p.parser;
386+ let optionalParser = p.optionalParser;
387+ let printer = p.printer;
388+ let readFromMlirBytecode = p.readFromMlirBytecode;
389+ let writeToMlirBytecode = p.writeToMlirBytecode;
390+ let defaultValue = p.defaultValue;
391+ let storageTypeValueOverride = p.storageTypeValueOverride;
392+ }
393+
333394//===----------------------------------------------------------------------===//
334395// Primitive property combinators
335396
@@ -342,14 +403,35 @@ class _makePropStorage<Property prop, string name> {
342403 true : "") # ";";
343404}
344405
406+ /// Construct a `Pred`icate `ret` that wraps the predicate of the underlying
407+ /// property `childProp` with:
408+ ///
409+ /// [](childProp.storageType& s) {
410+ /// return [](childProp.interfaceType i) {
411+ /// return leafSubst(childProp.predicate, "$_self" to "i");
412+ /// }(childProp.convertFromStorage(s))
413+ /// }
414+ ///
415+ /// and then appends `prefix` and `suffix`.
416+ class _makeStorageWrapperPred<Property wrappedProp> {
417+ Pred ret =
418+ Concat<
419+ "[](" # "const " # wrappedProp.storageType
420+ # "& baseStore) -> bool { return []("
421+ # wrappedProp.interfaceType # " baseIface) -> bool { return (",
422+ SubstLeaves<"$_self", "baseIface", wrappedProp.predicate>,
423+ "); }(" # !subst("$_storage", "baseStore", wrappedProp.convertFromStorage)
424+ # "); }">;
425+ }
426+
345427/// The generic class for arrays of some other property, which is stored as a
346428/// `SmallVector` of that property. This uses an `ArrayAttr` as its attribute form
347429/// though subclasses can override this, as is the case with IntArrayAttr below.
348430/// Those wishing to use a non-default number of SmallVector elements should
349431/// subclass `ArrayProperty`.
350- class ArrayProperty<Property elem = Property<>, string desc = ""> :
351- Property<"::llvm::SmallVector<" # elem.storageType # ">", desc> {
352- let summary = "array of " # elem.summary;
432+ class ArrayProperty<Property elem = Property<>, string newSummary = ""> :
433+ Property<"::llvm::SmallVector<" # elem.storageType # ">",
434+ !if(!empty(newSummary), "array of " # elem.summary, newSummary)> {
353435 let interfaceType = "::llvm::ArrayRef<" # elem.storageType # ">";
354436 let convertFromStorage = "::llvm::ArrayRef<" # elem.storageType # ">{$_storage}";
355437 let assignToStorage = "$_storage.assign($_value.begin(), $_value.end())";
@@ -382,6 +464,10 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
382464 return ::mlir::ArrayAttr::get($_ctxt, elems);
383465 }];
384466
467+ let predicate = !if(!eq(elem.predicate, TruePred),
468+ TruePred,
469+ Concat<"::llvm::all_of($_self, ", _makeStorageWrapperPred<elem>.ret, ")">);
470+
385471 defvar theParserBegin = [{
386472 auto& storage = $_storage;
387473 auto parseElemFn = [&]() -> ::mlir::ParseResult {
@@ -463,8 +549,8 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
463549 }]);
464550}
465551
466- class IntArrayProperty<string storageTypeParam = "" , string desc = ""> :
467- ArrayProperty<IntProperty<storageTypeParam, desc> > {
552+ class IntArrayProperty<Property elem , string newSummary= ""> :
553+ ArrayProperty<elem, newSummary > {
468554 // Bring back the trivial conversions we don't get in the general case.
469555 let convertFromAttribute = [{
470556 return convertFromAttribute($_storage, $_attr, $_diag);
@@ -474,30 +560,6 @@ class IntArrayProperty<string storageTypeParam = "", string desc = ""> :
474560 }];
475561}
476562
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-
501563/// An optional property, stored as an std::optional<p.storageType>
502564/// interfaced with as an std::optional<p.interfaceType>..
503565/// The syntax is `none` (or empty string if elided) for an absent value or
@@ -575,6 +637,11 @@ class OptionalProperty<Property p, bit canDelegateParsing = 1>
575637 return ::mlir::ArrayAttr::get($_ctxt, {attr});
576638 }];
577639
640+ let predicate = !if(!ne(p.predicate, TruePred),
641+ Or<[CPred<"!$_self.has_value()">,
642+ SubstLeaves<"$_self", "(*($_self))", p.predicate>]>,
643+ TruePred);
644+
578645 defvar delegatedParserBegin = [{
579646 if (::mlir::succeeded($_parser.parseOptionalKeyword("none"))) {
580647 $_storage = std::nullopt;
0 commit comments