//===-- CommonAttrConstraints.td - Common Attr Constraints--*- tablegen -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains commonly used attr constraints. // //===----------------------------------------------------------------------===// #ifndef COMMON_ATTR_CONSTRAINTS_TD #define COMMON_ATTR_CONSTRAINTS_TD include "mlir/IR/Constraints.td" include "mlir/IR/CommonTypeConstraints.td" include "mlir/IR/DialectBase.td" //===----------------------------------------------------------------------===// // Attribute definitions //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Base attribute definition //===----------------------------------------------------------------------===// // Base class for all attributes. class Attr : AttrConstraint { code storageType = ?; // The backing mlir::Attribute type code returnType = ?; // The underlying C++ value type // The call expression to convert from the storage type to the return // type. For example, an enum can be stored as an int but returned as an // enum class. // // Format: $_self will be expanded to the attribute. // // For example, `$_self.getValue().getSExtValue()` for `IntegerAttr val` will // expand to `getAttrOfType("val").getValue().getSExtValue()`. code convertFromStorage = "$_self.getValue()"; // The call expression to build an attribute from a constant value. // // Format: $0 will be expanded to the constant value of the attribute. // // For example, `$_builder.getStringAttr("$0")` for `StringAttr:"foo"` will // expand to `builder.getStringAttr("foo")`. string constBuilderCall = ?; // Default value for attribute. // Requires a constBuilderCall defined. // // Format: `$_builder` will be expanded to the relevant builder, e.g. to allow // access to the current context. string defaultValue = ?; // The value type of this attribute. This corresponds to the mlir::Type that // this attribute returns via `getType()`. Type valueType = ?; // Whether the attribute is optional. Typically requires a custom // convertFromStorage method to handle the case where the attribute is // not present. bit isOptional = 0; // What is the base-level Attr instantiation that this Attr is built upon. // Unset means this is a base-level Attr. // // This field is used by attribute wrapper classes (DefaultValuedAttr, // OptionalAttr, etc.) to retrieve the base-level attribute definition. // This can be used for getting its name; otherwise, we will see // "anonymous_" as the attribute def name because of template // instantiation. // TOOD(b/132458159): deduplicate the fields in attribute wrapper classes. Attr baseAttr = ?; // The fully-qualified C++ namespace where the generated class lives. string cppNamespace = ""; // The full description of this attribute. string description = ""; } // An attribute of a specific dialect. class DialectAttr : Attr { Dialect dialect = d; let cppNamespace = d.cppNamespace; } //===----------------------------------------------------------------------===// // Attribute modifier definition //===----------------------------------------------------------------------===// // Decorates an attribute to have an (unvalidated) default value if not present. class DefaultValuedAttr : Attr { // Construct this attribute with the input attribute and change only // the default value. // Note: this has to be kept up to date with Attr above. let storageType = attr.storageType; let returnType = attr.returnType; let convertFromStorage = attr.convertFromStorage; let constBuilderCall = attr.constBuilderCall; let defaultValue = val; let valueType = attr.valueType; let baseAttr = attr; } // Decorates an optional attribute to have an (unvalidated) default value // return by ODS generated accessors if not present. class DefaultValuedOptionalAttr : Attr { // Construct this attribute with the input attribute and change only // the default value. // Note: this has to be kept up to date with Attr above. let storageType = attr.storageType; let returnType = attr.returnType; let convertFromStorage = attr.convertFromStorage; let constBuilderCall = attr.constBuilderCall; let defaultValue = val; let valueType = attr.valueType; let isOptional = 1; let baseAttr = attr; } // Decorates an attribute as optional. The return type of the generated // attribute accessor method will be Optional<>. class OptionalAttr : Attr { // Rewrite the attribute to be optional. // Note: this has to be kept up to date with Attr above. let storageType = attr.storageType; let returnType = "::std::optional<" # attr.returnType #">"; let convertFromStorage = "$_self ? " # returnType # "(" # attr.convertFromStorage # ") : (::std::nullopt)"; let valueType = attr.valueType; let isOptional = 1; let baseAttr = attr; } // Default-valued string-based attribute. Wraps the default value in escaped // quotes. class DefaultValuedStrAttr : DefaultValuedAttr; class DefaultValuedOptionalStrAttr : DefaultValuedOptionalAttr; //===----------------------------------------------------------------------===// // Primitive attribute kinds //===----------------------------------------------------------------------===// // A generic attribute that must be constructed around a specific buildable type // `attrValType`. Backed by MLIR attribute kind `attrKind`. class TypedAttrBase : Attr { let constBuilderCall = "$_builder.get" # attrKind # "(" # attrValType.builderCall # ", $0)"; let storageType = "::mlir::" # attrKind; let valueType = attrValType; } // Any attribute. def AnyAttr : Attr, "any attribute"> { let storageType = "::mlir::Attribute"; let returnType = "::mlir::Attribute"; let convertFromStorage = "$_self"; let constBuilderCall = "$0"; } // Any attribute from the given list class AnyAttrOf allowedAttrs, string summary = "", string cppType = "::mlir::Attribute", string fromStorage = "$_self"> : Attr< // Satisfy any of the allowed attribute's condition Or, !if(!eq(summary, ""), !interleave(!foreach(t, allowedAttrs, t.summary), " or "), summary)> { let returnType = cppType; let convertFromStorage = fromStorage; list allowedAttributes = allowedAttrs; } def LocationAttr : Attr($_self)">, "location attribute"> { let storageType = [{ ::mlir::LocationAttr }]; let returnType = [{ ::mlir::Location }]; let convertFromStorage = "::mlir::Location($_self)"; let constBuilderCall = "(::mlir::LocationAttr)$0"; } def BoolAttr : Attr($_self)">, "bool attribute"> { let storageType = [{ ::mlir::BoolAttr }]; let returnType = [{ bool }]; let valueType = I1; let constBuilderCall = "$_builder.getBoolAttr($0)"; } // Index attribute. def IndexAttr : TypedAttrBase< Index, "IntegerAttr", And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">, CPred<"::llvm::isa<::mlir::IndexType>(::llvm::cast<::mlir::IntegerAttr>($_self).getType())">]>, "index attribute"> { let returnType = [{ ::llvm::APInt }]; } // Base class for any integer (regardless of signedness semantics) attributes // of fixed width. class AnyIntegerAttrBase : TypedAttrBase< attrValType, "IntegerAttr", And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">, CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()." "isInteger(" # attrValType.bitwidth # ")">]>, descr> { let returnType = [{ ::llvm::APInt }]; let constBuilderCall = ?; } def AnyI1Attr : AnyIntegerAttrBase; def AnyI8Attr : AnyIntegerAttrBase; def AnyI16Attr : AnyIntegerAttrBase; def AnyI32Attr : AnyIntegerAttrBase; def AnyI64Attr : AnyIntegerAttrBase; def APIntAttr : Attr($_self)">, "arbitrary integer attribute"> { let storageType = [{ ::mlir::IntegerAttr }]; let returnType = [{ ::mlir::APInt }]; } // Base class for signless integer attributes of fixed width. class SignlessIntegerAttrBase : TypedAttrBase< attrValType, "IntegerAttr", And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">, CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()." "isSignlessInteger(" # attrValType.bitwidth # ")">]>, descr> { let returnType = [{ ::llvm::APInt }]; } // Base class for signless integer attributes of fixed width that have a // corresponding C++ type. class TypedSignlessIntegerAttrBase : SignlessIntegerAttrBase { let returnType = retType; let convertFromStorage = "$_self.getValue().getZExtValue()"; } def I1Attr : TypedSignlessIntegerAttrBase< I1, "bool", "1-bit signless integer attribute">; def I8Attr : TypedSignlessIntegerAttrBase< I8, "uint8_t", "8-bit signless integer attribute">; def I16Attr : TypedSignlessIntegerAttrBase< I16, "uint16_t", "16-bit signless integer attribute">; def I32Attr : TypedSignlessIntegerAttrBase< I32, "uint32_t", "32-bit signless integer attribute">; def I64Attr : TypedSignlessIntegerAttrBase< I64, "uint64_t", "64-bit signless integer attribute">; // Base class for signed integer attributes of fixed width. class SignedIntegerAttrBase : TypedAttrBase< attrValType, "IntegerAttr", And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">, CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()." "isSignedInteger(" # attrValType.bitwidth # ")">]>, descr> { let returnType = [{ ::llvm::APInt }]; } // Base class for signed integer attributes of fixed width that have a // corresponding C++ type. class TypedSignedIntegerAttrBase : SignedIntegerAttrBase { let returnType = retType; let convertFromStorage = "$_self.getValue().getSExtValue()"; } def SI1Attr : TypedSignedIntegerAttrBase< SI1, "bool", "1-bit signed integer attribute">; def SI8Attr : TypedSignedIntegerAttrBase< SI8, "int8_t", "8-bit signed integer attribute">; def SI16Attr : TypedSignedIntegerAttrBase< SI16, "int16_t", "16-bit signed integer attribute">; def SI32Attr : TypedSignedIntegerAttrBase< SI32, "int32_t", "32-bit signed integer attribute">; def SI64Attr : TypedSignedIntegerAttrBase< SI64, "int64_t", "64-bit signed integer attribute">; // Base class for unsigned integer attributes of fixed width. class UnsignedIntegerAttrBase : TypedAttrBase< attrValType, "IntegerAttr", And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">, CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()." "isUnsignedInteger(" # attrValType.bitwidth # ")">]>, descr> { let returnType = [{ ::llvm::APInt }]; } // Base class for unsigned integer attributes of fixed width that have a // corresponding C++ type. class TypedUnsignedIntegerAttrBase : UnsignedIntegerAttrBase { let returnType = retType; let convertFromStorage = "$_self.getValue().getZExtValue()"; } def UI1Attr : TypedUnsignedIntegerAttrBase< UI1, "bool", "1-bit unsigned integer attribute">; def UI8Attr : TypedUnsignedIntegerAttrBase< UI8, "uint8_t", "8-bit unsigned integer attribute">; def UI16Attr : TypedUnsignedIntegerAttrBase< UI16, "uint16_t", "16-bit unsigned integer attribute">; def UI32Attr : TypedUnsignedIntegerAttrBase< UI32, "uint32_t", "32-bit unsigned integer attribute">; def UI64Attr : TypedUnsignedIntegerAttrBase< UI64, "uint64_t", "64-bit unsigned integer attribute">; // Base class for float attributes of fixed width. class FloatAttrBase : TypedAttrBase($_self)">, CPred<"::llvm::cast<::mlir::FloatAttr>($_self).getType().isF" # attrValType.bitwidth # "()">]>, descr> { let returnType = [{ ::llvm::APFloat }]; } def F16Attr : FloatAttrBase; def F32Attr : FloatAttrBase; def F64Attr : FloatAttrBase; def BF16Attr : TypedAttrBase($_self)">, CPred<"::llvm::cast<::mlir::FloatAttr>($_self).getType().isBF16()">]>, "16-bit bfloat attribute"> { let returnType = [{ ::llvm::APFloat }]; } // An attribute backed by a string type. class StringBasedAttr : Attr { let constBuilderCall = "$_builder.getStringAttr($0)"; let storageType = [{ ::mlir::StringAttr }]; let returnType = [{ ::llvm::StringRef }]; let valueType = NoneType; } def StrAttrPred : CPred<"::llvm::isa<::mlir::StringAttr>($_self)">; def StrAttr : StringBasedAttr; // A string attribute that represents the name of a symbol. def SymbolNameAttr : StringBasedAttr; // String attribute that has a specific value type. class TypedStrAttr : StringBasedAttr($_self).getType()", ty.predicate>]>, "string attribute of " # ty.summary> { let valueType = ty; } // Base class for attributes containing types. Example: // def IntTypeAttr : TypeAttrBase<"IntegerType", "integer type attribute"> // defines a type attribute containing an integer type. class TypeAttrBase> : Attr($_self)">, CPred<"::llvm::isa<" # retType # ">(::llvm::cast<::mlir::TypeAttr>($_self).getValue())">, SubstLeaves<"$_self", "::llvm::cast<::mlir::TypeAttr>($_self).getValue()", typePred>]>, summary> { let storageType = [{ ::mlir::TypeAttr }]; let returnType = retType; let valueType = NoneType; let convertFromStorage = "::llvm::cast<" # retType # ">($_self.getValue())"; } def TypeAttr : TypeAttrBase<"::mlir::Type", "any type attribute"> { let constBuilderCall = "::mlir::TypeAttr::get($0)"; } class TypeAttrOf : TypeAttrBase { let constBuilderCall = "::mlir::TypeAttr::get($0)"; } // The mere presence of unit attributes has a meaning. Therefore, unit // attributes are always treated as optional and accessors to them return // "true" if the attribute is present and "false" otherwise. def UnitAttr : Attr($_self)">, "unit attribute"> { let storageType = [{ ::mlir::UnitAttr }]; let constBuilderCall = "(($0) ? $_builder.getUnitAttr() : nullptr)"; let convertFromStorage = "$_self != nullptr"; let returnType = "bool"; let defaultValue = "false"; let valueType = NoneType; let isOptional = 1; } //===----------------------------------------------------------------------===// // Composite attribute kinds //===----------------------------------------------------------------------===// class DictionaryAttrBase : Attr { let storageType = [{ ::mlir::DictionaryAttr }]; let constBuilderCall = "$_builder.getDictionaryAttr($0)"; let returnType = [{ ::mlir::DictionaryAttr }]; let valueType = NoneType; let convertFromStorage = "$_self"; } def DictionaryAttr : DictionaryAttrBase($_self)">, "dictionary of named attribute values">; class ElementsAttrBase : Attr { let storageType = [{ ::mlir::ElementsAttr }]; let returnType = [{ ::mlir::ElementsAttr }]; let convertFromStorage = "$_self"; } def ElementsAttr : ElementsAttrBase($_self)">, "constant vector/tensor attribute">; class IntElementsAttrBase : ElementsAttrBase($_self)">, condition]>, summary> { let storageType = [{ ::mlir::DenseIntElementsAttr }]; let returnType = [{ ::mlir::DenseIntElementsAttr }]; let convertFromStorage = "$_self"; } class DenseArrayAttrBase : ElementsAttrBase($_self)">, summaryName # " dense array attribute"> { let storageType = "::mlir::" # denseAttrName; let returnType = "::llvm::ArrayRef<" # cppType # ">"; let constBuilderCall = "$_builder.get" # denseAttrName # "($0)"; } def DenseBoolArrayAttr : DenseArrayAttrBase<"DenseBoolArrayAttr", "bool", "i1">; def DenseI8ArrayAttr : DenseArrayAttrBase<"DenseI8ArrayAttr", "int8_t", "i8">; def DenseI16ArrayAttr : DenseArrayAttrBase<"DenseI16ArrayAttr", "int16_t", "i16">; def DenseI32ArrayAttr : DenseArrayAttrBase<"DenseI32ArrayAttr", "int32_t", "i32">; def DenseI64ArrayAttr : DenseArrayAttrBase<"DenseI64ArrayAttr", "int64_t", "i64">; def DenseF32ArrayAttr : DenseArrayAttrBase<"DenseF32ArrayAttr", "float", "f32">; def DenseF64ArrayAttr : DenseArrayAttrBase<"DenseF64ArrayAttr", "double", "f64">; def IndexElementsAttr : IntElementsAttrBase($_self) .getType() .getElementType() .isIndex()}]>, "index elements attribute">; def AnyIntElementsAttr : IntElementsAttrBase, "integer elements attribute">; class IntElementsAttrOf : IntElementsAttrBase< CPred<"::llvm::cast<::mlir::DenseIntElementsAttr>($_self).getType()." "getElementType().isInteger(" # width # ")">, width # "-bit integer elements attribute">; def AnyI32ElementsAttr : IntElementsAttrOf<32>; def AnyI64ElementsAttr : IntElementsAttrOf<64>; class SignlessIntElementsAttr : IntElementsAttrBase< CPred<"::llvm::cast<::mlir::DenseIntElementsAttr>($_self).getType()." "getElementType().isSignlessInteger(" # width # ")">, width # "-bit signless integer elements attribute"> { // Note that this is only constructing scalar elements attribute. let constBuilderCall = "::llvm::cast<::mlir::DenseIntElementsAttr>(" "::mlir::DenseElementsAttr::get(" "::mlir::RankedTensorType::get({}, $_builder.getIntegerType(" # width # ")), " "::llvm::ArrayRef($0)))"; } def I32ElementsAttr : SignlessIntElementsAttr<32>; def I64ElementsAttr : SignlessIntElementsAttr<64>; // A `width`-bit signless integer elements attribute. The attribute should be // ranked and has a shape as specified in `dims`. class RankedSignlessIntElementsAttr dims> : SignlessIntElementsAttr { // Check that this has the specified shape. let predicate = And<[ SignlessIntElementsAttr.predicate, CPred<"::llvm::cast<::mlir::DenseIntElementsAttr>($_self).getType().getShape() == " "::mlir::ArrayRef({" # !interleave(dims, ", ") # "})">]>; let summary = width # "-bit signless int elements attribute of shape [" # !interleave(dims, ", ") # "]"; let constBuilderCall = "::mlir::DenseIntElementsAttr::get(" "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") # "}, $_builder.getIntegerType(" # width # ")), ::llvm::ArrayRef($0))"; } class RankedI32ElementsAttr dims> : RankedSignlessIntElementsAttr<32, dims>; class RankedI64ElementsAttr dims> : RankedSignlessIntElementsAttr<64, dims>; class FloatElementsAttr : ElementsAttrBase< CPred<"::llvm::isa<::mlir::DenseFPElementsAttr>($_self) &&" "::llvm::cast<::mlir::DenseElementsAttr>($_self).getType()." "getElementType().isF" # width # "()">, width # "-bit float elements attribute"> { let storageType = [{ ::mlir::DenseElementsAttr }]; let returnType = [{ ::mlir::DenseElementsAttr }]; // Note that this is only constructing scalar elements attribute. let constBuilderCall = "::mlir::DenseElementsAttr::get(" "::mlir::RankedTensorType::get({}, $_builder.getF" # width # "Type())," "::llvm::ArrayRef($0))"; let convertFromStorage = "$_self"; } def F64ElementsAttr : FloatElementsAttr<64>; // A `width`-bit floating point elements attribute. The attribute should be // ranked and has a shape as specified in `dims`. class RankedFloatElementsAttr dims> : ElementsAttrBase< CPred<"::llvm::isa<::mlir::DenseFPElementsAttr>($_self) &&" "::llvm::cast<::mlir::DenseFPElementsAttr>($_self).getType()." "getElementType().isF" # width # "() && " // Check that this is ranked and has the specified shape. "::llvm::cast<::mlir::DenseFPElementsAttr>($_self).getType().hasRank() && " "::llvm::cast<::mlir::DenseFPElementsAttr>($_self).getType().getShape() == " "::mlir::ArrayRef({" # !interleave(dims, ", ") # "})">, width # "-bit float elements attribute of shape [" # !interleave(dims, ", ") # "]"> { let storageType = [{ ::mlir::DenseFPElementsAttr }]; let returnType = [{ ::mlir::DenseFPElementsAttr }]; let constBuilderCall = "::llvm::cast<::mlir::DenseFPElementsAttr>(" "::mlir::DenseElementsAttr::get(" "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") # "}, $_builder.getF" # width # "Type()), " "::llvm::ArrayRef($0)))"; let convertFromStorage = "$_self"; } class RankedF32ElementsAttr dims> : RankedFloatElementsAttr<32, dims>; class RankedF64ElementsAttr dims> : RankedFloatElementsAttr<64, dims>; def StringElementsAttr : ElementsAttrBase< CPred<"::llvm::isa<::mlir::DenseStringElementsAttr>($_self)" >, "string elements attribute"> { let storageType = [{ ::mlir::DenseElementsAttr }]; let returnType = [{ ::mlir::DenseElementsAttr }]; let convertFromStorage = "$_self"; } // Attributes containing affine maps. def AffineMapAttr : Attr< CPred<"::llvm::isa<::mlir::AffineMapAttr>($_self)">, "AffineMap attribute"> { let storageType = [{::mlir::AffineMapAttr }]; let returnType = [{ ::mlir::AffineMap }]; let valueType = Index; let constBuilderCall = "::mlir::AffineMapAttr::get($0)"; } // Attributes containing integer sets. def IntegerSetAttr : Attr< CPred<"::llvm::isa<::mlir::IntegerSetAttr>($_self)">, "IntegerSet attribute"> { let storageType = [{::mlir::IntegerSetAttr }]; let returnType = [{ ::mlir::IntegerSet }]; let valueType = NoneType; let constBuilderCall = "::mlir::IntegerSetAttr::get($0)"; } // Base class for array attributes. class ArrayAttrBase : Attr { let storageType = [{ ::mlir::ArrayAttr }]; let returnType = [{ ::mlir::ArrayAttr }]; let valueType = NoneType; let convertFromStorage = "$_self"; let constBuilderCall = "$_builder.getArrayAttr($0)"; } def ArrayAttr : ArrayAttrBase($_self)">, "array attribute">; // Base class for array attributes whose elements are of the same kind. // `element` specifies the element attribute kind stored in this array. class TypedArrayAttrBase: ArrayAttrBase< And<[ // Guarantee this is an ArrayAttr first CPred<"::llvm::isa<::mlir::ArrayAttr>($_self)">, // Guarantee all elements satisfy the constraints from `element` Concat<"::llvm::all_of(::llvm::cast<::mlir::ArrayAttr>($_self), " "[&](::mlir::Attribute attr) { return attr && (", SubstLeaves<"$_self", "attr", element.predicate>, "); })">]>, summary> { Attr elementAttr = element; } def LocationArrayAttr : TypedArrayAttrBase; def AffineMapArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getAffineMapArrayAttr($0)"; } def BoolArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getBoolArrayAttr($0)"; } def I32ArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getI32ArrayAttr($0)"; } def I64ArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getI64ArrayAttr($0)"; } // Variant of I64ArrayAttr whose user accessor is SmallVector. def I64SmallVectorArrayAttr : TypedArrayAttrBase { let returnType = [{ ::llvm::SmallVector }]; let convertFromStorage = [{ llvm::to_vector<4>( llvm::map_range($_self.getAsRange(), [](mlir::IntegerAttr attr) { return attr.getInt(); })); }]; let constBuilderCall = "$_builder.getI64ArrayAttr($0)"; } def F32ArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getF32ArrayAttr($0)"; } def F64ArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getF64ArrayAttr($0)"; } def StrArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getStrArrayAttr($0)"; } def TypeArrayAttr : TypedArrayAttrBase { let constBuilderCall = "$_builder.getTypeArrayAttr($0)"; } def IndexListArrayAttr : TypedArrayAttrBase; def DictArrayAttr : TypedArrayAttrBase; // Attributes containing symbol references. def SymbolRefAttr : Attr($_self)">, "symbol reference attribute"> { let storageType = [{ ::mlir::SymbolRefAttr }]; let returnType = [{ ::mlir::SymbolRefAttr }]; let valueType = NoneType; let constBuilderCall = "::mlir::SymbolRefAttr::get($_builder.getContext(), $0)"; let convertFromStorage = "$_self"; } def FlatSymbolRefAttr : Attr($_self)">, "flat symbol reference attribute"> { let storageType = [{ ::mlir::FlatSymbolRefAttr }]; let returnType = [{ ::llvm::StringRef }]; let valueType = NoneType; let constBuilderCall = "::mlir::SymbolRefAttr::get($_builder.getContext(), $0)"; let convertFromStorage = "$_self.getValue()"; } def SymbolRefArrayAttr : TypedArrayAttrBase { let constBuilderCall = ?; } def FlatSymbolRefArrayAttr : TypedArrayAttrBase { let constBuilderCall = ?; } //===----------------------------------------------------------------------===// // Derive attribute kinds //===----------------------------------------------------------------------===// // DerivedAttr are attributes whose value is computed from properties // of the operation. They do not require additional storage and are // materialized as needed. // Note: All derived attributes should be materializable as an Attribute. E.g., // do not use DerivedAttr for things that could not have been stored as // Attribute. // class DerivedAttr : Attr, "derived attribute"> { let returnType = ret; code body = b; // Specify how to convert from the derived attribute to an attribute. // // ## Special placeholders // // Special placeholders can be used to refer to entities during conversion: // // * `$_builder` will be replaced by a mlir::Builder instance. // * `$_ctxt` will be replaced by the MLIRContext* instance. // * `$_self` will be replaced with the derived attribute (value produces // `returnType`). let convertFromStorage = convert; } // Derived attribute that returns a mlir::Type. class DerivedTypeAttr : DerivedAttr<"::mlir::Type", body> { let convertFromStorage = "::mlir::TypeAttr::get($_self)"; } //===----------------------------------------------------------------------===// // Constant attribute kinds //===----------------------------------------------------------------------===// // Represents a constant attribute of specific Attr type. A constant // attribute can be specified only of attributes that have a constant // builder call defined. The constant value is specified as a string. // // If used as a constraint, it generates a matcher on a constant attribute by // using the constant value builder of the attribute and the value. class ConstantAttr : AttrConstraint< CPred<"$_self == " # !subst("$0", val, attribute.constBuilderCall)>, "constant attribute " # val> { Attr attr = attribute; string value = val; } class ConstF32Attr : ConstantAttr; def ConstBoolAttrFalse : ConstantAttr; def ConstBoolAttrTrue : ConstantAttr; def ConstUnitAttr : ConstantAttr; // Constant string-based attribute. Wraps the desired string in escaped quotes. class ConstantStrAttr : ConstantAttr; //===----------------------------------------------------------------------===// // Common attribute constraints //===----------------------------------------------------------------------===// // A general mechanism to further confine the given `attr` with all the // `constraints`. This allows to compose complex constraints out of a series // of more primitive ones. class ConfinedAttr constraints> : Attr< And, !foldl(/*init*/attr.summary, /*list*/constraints, prev, cur, prev # " " # cur.summary)> { let storageType = attr.storageType; let returnType = attr.returnType; let convertFromStorage = attr.convertFromStorage; let constBuilderCall = attr.constBuilderCall; let defaultValue = attr.defaultValue; let valueType = attr.valueType; let isOptional = attr.isOptional; let baseAttr = attr; list attrConstraints = constraints; } // An AttrConstraint that holds if all attr constraints specified in // 'constraints' hold. class AllAttrOf constraints> : AttrConstraint< And, !interleave(!foreach(con, constraints, con.summary), " and ")> { } class IntNEQValue : AttrConstraint< CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getInt() != " # n>, "whose value is not " # n>; class IntMinValue : AttrConstraint< CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getInt() >= " # n>, "whose minimum value is " # n>; class IntMaxValue : AttrConstraint< CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getInt() <= " # n>, "whose maximum value is " # n>; def IntNonNegative : AttrConstraint< CPred<"!::llvm::cast<::mlir::IntegerAttr>($_self).getValue().isNegative()">, "whose value is non-negative">; def IntPositive : AttrConstraint< CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getValue().isStrictlyPositive()">, "whose value is positive">; def IntPowerOf2 : AttrConstraint< CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getValue().isPowerOf2()">, "whose value is a power of two > 0">; def IntPositivePowerOf2 : AllAttrOf<[IntPositive, IntPowerOf2]>; class IntValidAlignment: ConfinedAttr; class IntIsOneOf values> : AttrConstraint< CPred<"::llvm::is_contained({" # !interleave(!foreach(val, values, val), ", ") # "}, ::llvm::cast<::mlir::IntegerAttr>($_self).getInt())">, "whose value is one of {" # !interleave(!foreach(val, values, val), ", ") # "}">; class ArrayMaxCount : AttrConstraint< CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() <= " # n>, "with at most " # n # " elements">; class ArrayMinCount : AttrConstraint< CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() >= " # n>, "with at least " # n # " elements">; class ArrayCount : AttrConstraint< CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() == " #n>, "with exactly " # n # " elements">; class DenseArrayCount : AttrConstraint< CPred<"::llvm::cast<::mlir::DenseArrayAttr>($_self).size() == " #n>, "with exactly " # n # " elements">; class DenseArrayMaxCt : AttrConstraint< CPred<"::llvm::cast<::mlir::DenseArrayAttr>($_self).size() <= " # n>, "with at most " # n # " elements">; class DenseArrayMinCt : AttrConstraint< CPred<"::llvm::cast<::mlir::DenseArrayAttr>($_self).size() >= " # n>, "with at least " # n # " elements">; class DenseArrayStrictlyPositive : AttrConstraint< CPred<"::llvm::all_of(::llvm::cast<" # arrayType #">($_self).asArrayRef(), " "[&](auto v) { return v > 0; })">, "whose value is positive">; class DenseArrayNonNegative : AttrConstraint< CPred<"::llvm::all_of(::llvm::cast<" # arrayType #">($_self).asArrayRef(), " "[&](auto v) { return v >= 0; })">, "whose value is non-negative">; class DenseArraySorted : AttrConstraint< CPred<"llvm::is_sorted(::llvm::cast<" # arrayType # ">($_self).asArrayRef())">, "should be in non-decreasing order">; class DenseArrayStrictlySorted : AttrConstraint< And<[ CPred<"llvm::is_sorted(::llvm::cast<" # arrayType # ">($_self).asArrayRef())">, // Check that no two adjacent elements are the same. CPred<"[](" # arrayType.returnType # " a) {\n" "return std::adjacent_find(std::begin(a), std::end(a)) == " "std::end(a);\n" "}(::llvm::cast<" # arrayType # ">($_self).asArrayRef())" >]>, "should be in increasing order">; class IntArrayNthElemEq : AttrConstraint< And<[ CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>, CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)[" # index # "]).getInt() == " # value> ]>, "whose " # index # "-th element must be " # value>; class IntArrayNthElemMinValue : AttrConstraint< And<[ CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>, CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)[" # index # "]).getInt() >= " # min> ]>, "whose " # index # "-th element must be at least " # min>; class IntArrayNthElemMaxValue : AttrConstraint< And<[ CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>, CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)[" # index # "]).getInt() <= " # max> ]>, "whose " # index # "-th element must be at most " # max>; class IntArrayNthElemInRange : AttrConstraint< And<[ CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>, CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)[" # index # "]).getInt() >= " # min>, CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)[" # index # "]).getInt() <= " # max> ]>, "whose " # index # "-th element must be at least " # min # " and at most " # max>; def IsNullAttr : AttrConstraint< CPred<"!$_self">, "empty attribute (for optional attributes)">; #endif // COMMON_ATTR_CONSTRAINTS_TD