Skip to content

[mlir] Add predicates to tablegen-defined properties #120176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions mlir/include/mlir/IR/Constraints.td
Original file line number Diff line number Diff line change
Expand Up @@ -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).
//
Expand Down
133 changes: 100 additions & 33 deletions mlir/include/mlir/IR/Properties.td
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -63,6 +65,13 @@ class Property<string storageTypeParam = "", string desc = ""> {
return convertFromAttribute($_storage, $_attr, $_diag);
}];

// 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. 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.
//
// Format:
Expand Down Expand Up @@ -150,8 +159,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
Expand Down Expand Up @@ -224,8 +233,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));
}];
Expand Down Expand Up @@ -330,6 +338,59 @@ 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;
}

/// 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(!ne(p.predicate, TruePred), 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

Expand All @@ -342,14 +403,35 @@ 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 _makeStorageWrapperPred<Property wrappedProp> {
Pred ret =
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
/// `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())";
Expand Down Expand Up @@ -382,6 +464,10 @@ class ArrayProperty<Property elem = Property<>, string desc = ""> :
return ::mlir::ArrayAttr::get($_ctxt, elems);
}];

let predicate = !if(!eq(elem.predicate, TruePred),
TruePred,
Concat<"::llvm::all_of($_self, ", _makeStorageWrapperPred<elem>.ret, ")">);

defvar theParserBegin = [{
auto& storage = $_storage;
auto parseElemFn = [&]() -> ::mlir::ParseResult {
Expand Down Expand Up @@ -463,8 +549,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);
Expand All @@ -474,30 +560,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
Expand Down Expand Up @@ -575,6 +637,11 @@ class OptionalProperty<Property p, bit canDelegateParsing = 1>
return ::mlir::ArrayAttr::get($_ctxt, {attr});
}];

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"))) {
$_storage = std::nullopt;
Expand Down
5 changes: 5 additions & 0 deletions mlir/include/mlir/TableGen/Property.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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; }

Expand Down
10 changes: 10 additions & 0 deletions mlir/lib/TableGen/Predicate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions mlir/lib/TableGen/Property.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand All @@ -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"))) {
Expand Down
Loading
Loading