xref: /llvm-project/mlir/include/mlir/IR/CommonAttrConstraints.td (revision 8d6b24167b7bdc7ac9c969abe73be857bbcf2b5a)
1//===-- CommonAttrConstraints.td - Common Attr Constraints--*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains commonly used attr constraints.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef COMMON_ATTR_CONSTRAINTS_TD
14#define COMMON_ATTR_CONSTRAINTS_TD
15
16include "mlir/IR/Constraints.td"
17include "mlir/IR/CommonTypeConstraints.td"
18include "mlir/IR/DialectBase.td"
19
20//===----------------------------------------------------------------------===//
21// Attribute definitions
22//===----------------------------------------------------------------------===//
23
24//===----------------------------------------------------------------------===//
25// Base attribute definition
26
27// Base class for all attributes.
28class Attr<Pred condition, string summary = ""> :
29    AttrConstraint<condition, summary> {
30  code storageType = ?; // The backing mlir::Attribute type
31  code returnType = ?;  // The underlying C++ value type
32
33  // The call expression to convert from the storage type to the return
34  // type. For example, an enum can be stored as an int but returned as an
35  // enum class.
36  //
37  // Format: $_self will be expanded to the attribute.
38  //
39  // For example, `$_self.getValue().getSExtValue()` for `IntegerAttr val` will
40  // expand to `getAttrOfType<IntegerAttr>("val").getValue().getSExtValue()`.
41  code convertFromStorage = "$_self.getValue()";
42
43  // The call expression to build an attribute from a constant value.
44  //
45  // Format: $0 will be expanded to the constant value of the attribute.
46  //
47  // For example, `$_builder.getStringAttr("$0")` for `StringAttr:"foo"` will
48  // expand to `builder.getStringAttr("foo")`.
49  string constBuilderCall = ?;
50
51  // Default value for attribute.
52  // Requires a constBuilderCall defined.
53  string defaultValue = ?;
54
55  // The value type of this attribute. This corresponds to the mlir::Type that
56  // this attribute returns via `getType()`.
57  Type valueType = ?;
58
59  // Whether the attribute is optional. Typically requires a custom
60  // convertFromStorage method to handle the case where the attribute is
61  // not present.
62  bit isOptional = 0;
63
64  // What is the base-level Attr instantiation that this Attr is built upon.
65  // Unset means this is a base-level Attr.
66  //
67  // This field is used by attribute wrapper classes (DefaultValuedAttr,
68  // OptionalAttr, etc.) to retrieve the base-level attribute definition.
69  // This can be used for getting its name; otherwise, we will see
70  // "anonymous_<number>" as the attribute def name because of template
71  // instantiation.
72  // TOOD(b/132458159): deduplicate the fields in attribute wrapper classes.
73  Attr baseAttr = ?;
74
75  // The fully-qualified C++ namespace where the generated class lives.
76  string cppNamespace = "";
77
78  // The full description of this attribute.
79  string description = "";
80}
81
82// An attribute of a specific dialect.
83class DialectAttr<Dialect d, Pred condition, string summary = ""> :
84    Attr<condition, summary> {
85  Dialect dialect = d;
86  let cppNamespace = d.cppNamespace;
87}
88
89//===----------------------------------------------------------------------===//
90// Attribute modifier definition
91
92// Decorates an attribute to have an (unvalidated) default value if not present.
93class DefaultValuedAttr<Attr attr, string val> :
94    Attr<attr.predicate, attr.summary> {
95  // Construct this attribute with the input attribute and change only
96  // the default value.
97  // Note: this has to be kept up to date with Attr above.
98  let storageType = attr.storageType;
99  let returnType = attr.returnType;
100  let convertFromStorage = attr.convertFromStorage;
101  let constBuilderCall = attr.constBuilderCall;
102  let defaultValue = val;
103  let valueType = attr.valueType;
104
105  let baseAttr = attr;
106}
107
108// Decorates an optional attribute to have an (unvalidated) default value
109// return by ODS generated accessors if not present.
110class DefaultValuedOptionalAttr<Attr attr, string val> :
111    Attr<attr.predicate, attr.summary> {
112  // Construct this attribute with the input attribute and change only
113  // the default value.
114  // Note: this has to be kept up to date with Attr above.
115  let storageType = attr.storageType;
116  let returnType = attr.returnType;
117  let convertFromStorage = attr.convertFromStorage;
118  let constBuilderCall = attr.constBuilderCall;
119  let defaultValue = val;
120  let valueType = attr.valueType;
121  let isOptional = 1;
122
123  let baseAttr = attr;
124}
125
126// Decorates an attribute as optional. The return type of the generated
127// attribute accessor method will be Optional<>.
128class OptionalAttr<Attr attr> : Attr<attr.predicate, attr.summary> {
129  // Rewrite the attribute to be optional.
130  // Note: this has to be kept up to date with Attr above.
131  let storageType = attr.storageType;
132  let returnType = "::std::optional<" # attr.returnType #">";
133  let convertFromStorage = "$_self ? " # returnType # "(" #
134                           attr.convertFromStorage # ") : (::std::nullopt)";
135  let valueType = attr.valueType;
136  let isOptional = 1;
137
138  let baseAttr = attr;
139}
140
141// Default-valued string-based attribute. Wraps the default value in escaped
142// quotes.
143class DefaultValuedStrAttr<Attr attr, string val>
144    : DefaultValuedAttr<attr, "\"" # val # "\"">;
145class DefaultValuedOptionalStrAttr<Attr attr, string val>
146    : DefaultValuedOptionalAttr<attr, "\"" # val # "\"">;
147
148//===----------------------------------------------------------------------===//
149// Primitive attribute kinds
150
151// A generic attribute that must be constructed around a specific buildable type
152// `attrValType`. Backed by MLIR attribute kind `attrKind`.
153class TypedAttrBase<Type attrValType, string attrKind, Pred condition,
154                    string descr> :
155    Attr<condition, descr> {
156  let constBuilderCall = "$_builder.get" # attrKind # "(" #
157                         attrValType.builderCall # ", $0)";
158  let storageType = "::mlir::" # attrKind;
159  let valueType = attrValType;
160}
161
162// Any attribute.
163def AnyAttr : Attr<CPred<"true">, "any attribute"> {
164  let storageType = "::mlir::Attribute";
165  let returnType = "::mlir::Attribute";
166  let convertFromStorage = "$_self";
167  let constBuilderCall = "$0";
168}
169
170// Any attribute from the given list
171class AnyAttrOf<list<Attr> allowedAttrs, string summary = "",
172                string cppType = "::mlir::Attribute",
173                string fromStorage = "$_self"> : Attr<
174    // Satisfy any of the allowed attribute's condition
175    Or<!foreach(allowedattr, allowedAttrs, allowedattr.predicate)>,
176    !if(!eq(summary, ""),
177        !interleave(!foreach(t, allowedAttrs, t.summary), " or "),
178        summary)> {
179    let returnType = cppType;
180    let convertFromStorage = fromStorage;
181    list<Attr> allowedAttributes = allowedAttrs;
182}
183
184def LocationAttr : Attr<CPred<"::llvm::isa<::mlir::LocationAttr>($_self)">,
185                        "location attribute">;
186
187def BoolAttr : Attr<CPred<"::llvm::isa<::mlir::BoolAttr>($_self)">, "bool attribute"> {
188  let storageType = [{ ::mlir::BoolAttr }];
189  let returnType = [{ bool }];
190  let valueType = I1;
191  let constBuilderCall = "$_builder.getBoolAttr($0)";
192}
193
194// Index attribute.
195def IndexAttr :
196    TypedAttrBase<
197      Index, "IntegerAttr",
198      And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">,
199           CPred<"::llvm::isa<::mlir::IndexType>(::llvm::cast<::mlir::IntegerAttr>($_self).getType())">]>,
200      "index attribute"> {
201  let returnType = [{ ::llvm::APInt }];
202}
203
204// Base class for any integer (regardless of signedness semantics) attributes
205// of fixed width.
206class AnyIntegerAttrBase<AnyI attrValType, string descr> :
207    TypedAttrBase<
208      attrValType, "IntegerAttr",
209      And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">,
210           CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()."
211                 "isInteger(" # attrValType.bitwidth # ")">]>,
212      descr> {
213  let returnType = [{ ::llvm::APInt }];
214  let constBuilderCall = ?;
215}
216
217def AnyI1Attr  : AnyIntegerAttrBase<AnyI1,  "1-bit integer attribute">;
218def AnyI8Attr  : AnyIntegerAttrBase<AnyI8,  "8-bit integer attribute">;
219def AnyI16Attr : AnyIntegerAttrBase<AnyI16, "16-bit integer attribute">;
220def AnyI32Attr : AnyIntegerAttrBase<AnyI32, "32-bit integer attribute">;
221def AnyI64Attr : AnyIntegerAttrBase<AnyI64, "64-bit integer attribute">;
222
223def APIntAttr : Attr<CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">,
224                     "arbitrary integer attribute"> {
225  let storageType = [{ ::mlir::IntegerAttr }];
226  let returnType = [{ ::mlir::APInt }];
227}
228
229// Base class for signless integer attributes of fixed width.
230class SignlessIntegerAttrBase<I attrValType, string descr> :
231    TypedAttrBase<
232      attrValType, "IntegerAttr",
233      And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">,
234           CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()."
235                 "isSignlessInteger(" # attrValType.bitwidth # ")">]>,
236      descr> {
237  let returnType = [{ ::llvm::APInt }];
238}
239// Base class for signless integer attributes of fixed width that have a
240// corresponding C++ type.
241class TypedSignlessIntegerAttrBase<I attrValType, string retType, string descr>
242    : SignlessIntegerAttrBase<attrValType, descr> {
243  let returnType = retType;
244  let convertFromStorage = "$_self.getValue().getZExtValue()";
245}
246
247def I1Attr  : TypedSignlessIntegerAttrBase<
248    I1,  "bool",     "1-bit signless integer attribute">;
249def I8Attr  : TypedSignlessIntegerAttrBase<
250    I8,  "uint8_t",  "8-bit signless integer attribute">;
251def I16Attr : TypedSignlessIntegerAttrBase<
252    I16, "uint16_t", "16-bit signless integer attribute">;
253def I32Attr : TypedSignlessIntegerAttrBase<
254    I32, "uint32_t", "32-bit signless integer attribute">;
255def I64Attr : TypedSignlessIntegerAttrBase<
256    I64, "uint64_t", "64-bit signless integer attribute">;
257
258// Base class for signed integer attributes of fixed width.
259class SignedIntegerAttrBase<SI attrValType, string descr> :
260    TypedAttrBase<
261      attrValType, "IntegerAttr",
262      And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">,
263           CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()."
264                 "isSignedInteger(" # attrValType.bitwidth # ")">]>,
265      descr> {
266  let returnType = [{ ::llvm::APInt }];
267}
268// Base class for signed integer attributes of fixed width that have a
269// corresponding C++ type.
270class TypedSignedIntegerAttrBase<SI attrValType, string retType, string descr>
271    : SignedIntegerAttrBase<attrValType, descr> {
272  let returnType = retType;
273  let convertFromStorage = "$_self.getValue().getSExtValue()";
274}
275
276def SI1Attr  : TypedSignedIntegerAttrBase<
277    SI1,  "bool",    "1-bit signed integer attribute">;
278def SI8Attr  : TypedSignedIntegerAttrBase<
279    SI8,  "int8_t",  "8-bit signed integer attribute">;
280def SI16Attr : TypedSignedIntegerAttrBase<
281    SI16, "int16_t", "16-bit signed integer attribute">;
282def SI32Attr : TypedSignedIntegerAttrBase<
283    SI32, "int32_t", "32-bit signed integer attribute">;
284def SI64Attr : TypedSignedIntegerAttrBase<
285    SI64, "int64_t", "64-bit signed integer attribute">;
286
287// Base class for unsigned integer attributes of fixed width.
288class UnsignedIntegerAttrBase<UI attrValType, string descr> :
289    TypedAttrBase<
290      attrValType, "IntegerAttr",
291      And<[CPred<"::llvm::isa<::mlir::IntegerAttr>($_self)">,
292           CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getType()."
293                 "isUnsignedInteger(" # attrValType.bitwidth # ")">]>,
294      descr> {
295  let returnType = [{ ::llvm::APInt }];
296}
297// Base class for unsigned integer attributes of fixed width that have a
298// corresponding C++ type.
299class TypedUnsignedIntegerAttrBase<UI attrValType, string retType, string descr>
300    : UnsignedIntegerAttrBase<attrValType, descr> {
301  let returnType = retType;
302  let convertFromStorage = "$_self.getValue().getZExtValue()";
303}
304
305def UI1Attr  : TypedUnsignedIntegerAttrBase<
306    UI1,  "bool",     "1-bit unsigned integer attribute">;
307def UI8Attr  : TypedUnsignedIntegerAttrBase<
308    UI8,  "uint8_t",  "8-bit unsigned integer attribute">;
309def UI16Attr : TypedUnsignedIntegerAttrBase<
310    UI16, "uint16_t", "16-bit unsigned integer attribute">;
311def UI32Attr : TypedUnsignedIntegerAttrBase<
312    UI32, "uint32_t", "32-bit unsigned integer attribute">;
313def UI64Attr : TypedUnsignedIntegerAttrBase<
314    UI64, "uint64_t", "64-bit unsigned integer attribute">;
315
316// Base class for float attributes of fixed width.
317class FloatAttrBase<F attrValType, string descr> :
318    TypedAttrBase<attrValType, "FloatAttr",
319              And<[CPred<"::llvm::isa<::mlir::FloatAttr>($_self)">,
320                     CPred<"::llvm::cast<::mlir::FloatAttr>($_self).getType().isF" #
321                           attrValType.bitwidth # "()">]>,
322              descr> {
323  let returnType = [{ ::llvm::APFloat }];
324}
325
326def F32Attr : FloatAttrBase<F32, "32-bit float attribute">;
327def F64Attr : FloatAttrBase<F64, "64-bit float attribute">;
328
329// An attribute backed by a string type.
330class StringBasedAttr<Pred condition, string descr> : Attr<condition, descr> {
331  let constBuilderCall = "$_builder.getStringAttr($0)";
332  let storageType = [{ ::mlir::StringAttr }];
333  let returnType = [{ ::llvm::StringRef }];
334  let valueType = NoneType;
335}
336
337def StrAttrPred : CPred<"::llvm::isa<::mlir::StringAttr>($_self)">;
338
339def StrAttr : StringBasedAttr<StrAttrPred, "string attribute">;
340
341// A string attribute that represents the name of a symbol.
342def SymbolNameAttr : StringBasedAttr<StrAttrPred, "string attribute">;
343
344// String attribute that has a specific value type.
345class TypedStrAttr<Type ty>
346    : StringBasedAttr<And<[StrAttrPred,
347        SubstLeaves<"$_self", "::mlir::cast<StringAttr>($_self).getType()",
348                    ty.predicate>]>,
349        "string attribute of " # ty.summary> {
350  let valueType = ty;
351}
352
353// Base class for attributes containing types. Example:
354//   def IntTypeAttr : TypeAttrBase<"IntegerType", "integer type attribute">
355// defines a type attribute containing an integer type.
356class TypeAttrBase<string retType, string summary,
357                        Pred typePred = CPred<"true">> :
358    Attr<And<[
359      CPred<"::llvm::isa<::mlir::TypeAttr>($_self)">,
360      CPred<"::llvm::isa<" # retType # ">(::llvm::cast<::mlir::TypeAttr>($_self).getValue())">,
361      SubstLeaves<"$_self",
362                    "::llvm::cast<::mlir::TypeAttr>($_self).getValue()", typePred>]>,
363    summary> {
364  let storageType = [{ ::mlir::TypeAttr }];
365  let returnType = retType;
366  let valueType = NoneType;
367  let convertFromStorage = "::llvm::cast<" # retType # ">($_self.getValue())";
368}
369
370def TypeAttr : TypeAttrBase<"::mlir::Type", "any type attribute"> {
371  let constBuilderCall = "::mlir::TypeAttr::get($0)";
372}
373
374class TypeAttrOf<Type ty>
375   : TypeAttrBase<ty.cppType, "type attribute of " # ty.summary,
376                    ty.predicate> {
377  let constBuilderCall = "::mlir::TypeAttr::get($0)";
378}
379
380// The mere presence of unit attributes has a meaning.  Therefore, unit
381// attributes are always treated as optional and accessors to them return
382// "true" if the attribute is present and "false" otherwise.
383def UnitAttr : Attr<CPred<"::llvm::isa<::mlir::UnitAttr>($_self)">, "unit attribute"> {
384  let storageType = [{ ::mlir::UnitAttr }];
385  let constBuilderCall = "(($0) ? $_builder.getUnitAttr() : nullptr)";
386  let convertFromStorage = "$_self != nullptr";
387  let returnType = "bool";
388  let defaultValue = "false";
389  let valueType = NoneType;
390  let isOptional = 1;
391}
392
393//===----------------------------------------------------------------------===//
394// Composite attribute kinds
395
396class DictionaryAttrBase<Pred condition, string summary> :
397    Attr<condition, summary> {
398  let storageType = [{ ::mlir::DictionaryAttr }];
399  let constBuilderCall = "$_builder.getDictionaryAttr($0)";
400  let returnType = [{ ::mlir::DictionaryAttr }];
401  let valueType = NoneType;
402  let convertFromStorage = "$_self";
403}
404
405def DictionaryAttr
406    : DictionaryAttrBase<CPred<"::llvm::isa<::mlir::DictionaryAttr>($_self)">,
407                               "dictionary of named attribute values">;
408
409class ElementsAttrBase<Pred condition, string summary> :
410    Attr<condition, summary> {
411  let storageType = [{ ::mlir::ElementsAttr }];
412  let returnType = [{ ::mlir::ElementsAttr }];
413  let convertFromStorage = "$_self";
414}
415
416def ElementsAttr : ElementsAttrBase<CPred<"::llvm::isa<::mlir::ElementsAttr>($_self)">,
417                                    "constant vector/tensor attribute">;
418
419class IntElementsAttrBase<Pred condition, string summary> :
420    ElementsAttrBase<And<[CPred<"::llvm::isa<::mlir::DenseIntElementsAttr>($_self)">,
421                          condition]>,
422                     summary> {
423  let storageType = [{ ::mlir::DenseIntElementsAttr }];
424  let returnType = [{ ::mlir::DenseIntElementsAttr }];
425
426  let convertFromStorage = "$_self";
427}
428
429class DenseArrayAttrBase<string denseAttrName, string cppType, string summaryName> :
430    ElementsAttrBase<CPred<"::llvm::isa<::mlir::" # denseAttrName # ">($_self)">,
431                     summaryName # " dense array attribute"> {
432  let storageType = "::mlir::" # denseAttrName;
433  let returnType = "::llvm::ArrayRef<" # cppType # ">";
434  let constBuilderCall = "$_builder.get" # denseAttrName # "($0)";
435}
436def DenseBoolArrayAttr : DenseArrayAttrBase<"DenseBoolArrayAttr", "bool", "i1">;
437def DenseI8ArrayAttr : DenseArrayAttrBase<"DenseI8ArrayAttr", "int8_t", "i8">;
438def DenseI16ArrayAttr : DenseArrayAttrBase<"DenseI16ArrayAttr", "int16_t", "i16">;
439def DenseI32ArrayAttr : DenseArrayAttrBase<"DenseI32ArrayAttr", "int32_t", "i32">;
440def DenseI64ArrayAttr : DenseArrayAttrBase<"DenseI64ArrayAttr", "int64_t", "i64">;
441def DenseF32ArrayAttr : DenseArrayAttrBase<"DenseF32ArrayAttr", "float", "f32">;
442def DenseF64ArrayAttr : DenseArrayAttrBase<"DenseF64ArrayAttr", "double", "f64">;
443
444def IndexElementsAttr
445    : IntElementsAttrBase<CPred<[{::llvm::cast<::mlir::DenseIntElementsAttr>($_self)
446                                      .getType()
447                                      .getElementType()
448                                      .isIndex()}]>,
449                          "index elements attribute">;
450
451def AnyIntElementsAttr : IntElementsAttrBase<CPred<"true">, "integer elements attribute">;
452
453class IntElementsAttrOf<int width> : IntElementsAttrBase<
454  CPred<"::llvm::cast<::mlir::DenseIntElementsAttr>($_self).getType()."
455        "getElementType().isInteger(" # width # ")">,
456  width # "-bit integer elements attribute">;
457
458def AnyI32ElementsAttr : IntElementsAttrOf<32>;
459def AnyI64ElementsAttr : IntElementsAttrOf<64>;
460
461class SignlessIntElementsAttr<int width> : IntElementsAttrBase<
462  CPred<"::llvm::cast<::mlir::DenseIntElementsAttr>($_self).getType()."
463        "getElementType().isSignlessInteger(" # width # ")">,
464  width # "-bit signless integer elements attribute"> {
465
466  // Note that this is only constructing scalar elements attribute.
467  let constBuilderCall = "::llvm::cast<::mlir::DenseIntElementsAttr>("
468  "::mlir::DenseElementsAttr::get("
469    "::mlir::RankedTensorType::get({}, $_builder.getIntegerType(" # width # ")), "
470    "::llvm::ArrayRef($0)))";
471}
472
473def I32ElementsAttr : SignlessIntElementsAttr<32>;
474def I64ElementsAttr : SignlessIntElementsAttr<64>;
475
476// A `width`-bit signless integer elements attribute. The attribute should be
477// ranked and has a shape as specified in `dims`.
478class RankedSignlessIntElementsAttr<int width, list<int> dims> :
479    SignlessIntElementsAttr<width> {
480  // Check that this has the specified shape.
481  let predicate = And<[
482    SignlessIntElementsAttr<width>.predicate,
483    CPred<"::llvm::cast<::mlir::DenseIntElementsAttr>($_self).getType().getShape() == "
484        "::mlir::ArrayRef<int64_t>({" # !interleave(dims, ", ") # "})">]>;
485
486  let summary = width # "-bit signless int elements attribute of shape [" #
487                !interleave(dims, ", ") # "]";
488
489  let constBuilderCall = "::mlir::DenseIntElementsAttr::get("
490    "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
491    "}, $_builder.getIntegerType(" # width # ")), ::llvm::ArrayRef($0))";
492}
493
494class RankedI32ElementsAttr<list<int> dims> :
495    RankedSignlessIntElementsAttr<32, dims>;
496class RankedI64ElementsAttr<list<int> dims> :
497    RankedSignlessIntElementsAttr<64, dims>;
498
499class FloatElementsAttr<int width> : ElementsAttrBase<
500  CPred<"::llvm::isa<::mlir::DenseFPElementsAttr>($_self) &&"
501      "::llvm::cast<::mlir::DenseElementsAttr>($_self).getType()."
502      "getElementType().isF" # width # "()">,
503  width # "-bit float elements attribute"> {
504
505  let storageType = [{ ::mlir::DenseElementsAttr }];
506  let returnType = [{ ::mlir::DenseElementsAttr }];
507
508  // Note that this is only constructing scalar elements attribute.
509  let constBuilderCall = "::mlir::DenseElementsAttr::get("
510    "::mlir::RankedTensorType::get({}, $_builder.getF" # width # "Type()),"
511    "::llvm::ArrayRef($0))";
512  let convertFromStorage = "$_self";
513}
514
515def F64ElementsAttr : FloatElementsAttr<64>;
516
517// A `width`-bit floating point elements attribute. The attribute should be
518// ranked and has a shape as specified in `dims`.
519class RankedFloatElementsAttr<int width, list<int> dims> : ElementsAttrBase<
520  CPred<"::llvm::isa<::mlir::DenseFPElementsAttr>($_self) &&"
521      "::llvm::cast<::mlir::DenseFPElementsAttr>($_self).getType()."
522      "getElementType().isF" # width # "() && "
523      // Check that this is ranked and has the specified shape.
524      "::llvm::cast<::mlir::DenseFPElementsAttr>($_self).getType().hasRank() && "
525      "::llvm::cast<::mlir::DenseFPElementsAttr>($_self).getType().getShape() == "
526      "::mlir::ArrayRef<int64_t>({" # !interleave(dims, ", ") # "})">,
527  width # "-bit float elements attribute of shape [" #
528  !interleave(dims, ", ") # "]"> {
529
530  let storageType = [{ ::mlir::DenseFPElementsAttr }];
531  let returnType = [{ ::mlir::DenseFPElementsAttr }];
532
533  let constBuilderCall = "::llvm::cast<::mlir::DenseFPElementsAttr>("
534  "::mlir::DenseElementsAttr::get("
535    "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
536    "}, $_builder.getF" # width # "Type()), "
537    "::llvm::ArrayRef($0)))";
538  let convertFromStorage = "$_self";
539}
540
541class RankedF32ElementsAttr<list<int> dims> : RankedFloatElementsAttr<32, dims>;
542class RankedF64ElementsAttr<list<int> dims> : RankedFloatElementsAttr<64, dims>;
543
544def StringElementsAttr : ElementsAttrBase<
545  CPred<"::llvm::isa<::mlir::DenseStringElementsAttr>($_self)" >,
546  "string elements attribute"> {
547
548  let storageType = [{ ::mlir::DenseElementsAttr }];
549  let returnType = [{ ::mlir::DenseElementsAttr }];
550
551  let convertFromStorage = "$_self";
552}
553
554// Attributes containing affine maps.
555def AffineMapAttr : Attr<
556CPred<"::llvm::isa<::mlir::AffineMapAttr>($_self)">, "AffineMap attribute"> {
557  let storageType = [{::mlir::AffineMapAttr }];
558  let returnType = [{ ::mlir::AffineMap }];
559  let valueType = Index;
560  let constBuilderCall = "::mlir::AffineMapAttr::get($0)";
561}
562
563// Attributes containing integer sets.
564def IntegerSetAttr : Attr<
565CPred<"::llvm::isa<::mlir::IntegerSetAttr>($_self)">, "IntegerSet attribute"> {
566  let storageType = [{::mlir::IntegerSetAttr }];
567  let returnType = [{ ::mlir::IntegerSet }];
568  let valueType = NoneType;
569  let constBuilderCall = "::mlir::IntegerSetAttr::get($0)";
570}
571
572// Base class for array attributes.
573class ArrayAttrBase<Pred condition, string summary> : Attr<condition, summary> {
574  let storageType = [{ ::mlir::ArrayAttr }];
575  let returnType = [{ ::mlir::ArrayAttr }];
576  let valueType = NoneType;
577  let convertFromStorage = "$_self";
578  let constBuilderCall = "$_builder.getArrayAttr($0)";
579}
580
581def ArrayAttr : ArrayAttrBase<CPred<"::llvm::isa<::mlir::ArrayAttr>($_self)">,
582                              "array attribute">;
583
584// Base class for array attributes whose elements are of the same kind.
585// `element` specifies the element attribute kind stored in this array.
586class TypedArrayAttrBase<Attr element, string summary>: ArrayAttrBase<
587    And<[
588      // Guarantee this is an ArrayAttr first
589      CPred<"::llvm::isa<::mlir::ArrayAttr>($_self)">,
590      // Guarantee all elements satisfy the constraints from `element`
591      Concat<"::llvm::all_of(::llvm::cast<::mlir::ArrayAttr>($_self), "
592                            "[&](::mlir::Attribute attr) { return attr && (",
593                               SubstLeaves<"$_self", "attr", element.predicate>,
594                            "); })">]>,
595    summary> {
596
597  Attr elementAttr = element;
598}
599
600def LocationArrayAttr : TypedArrayAttrBase<LocationAttr,
601                                           "location array attribute">;
602
603def AffineMapArrayAttr : TypedArrayAttrBase<AffineMapAttr,
604                                      "AffineMap array attribute"> {
605  let constBuilderCall = "$_builder.getAffineMapArrayAttr($0)";
606}
607
608def BoolArrayAttr : TypedArrayAttrBase<BoolAttr,
609                                      "1-bit boolean array attribute"> {
610  let constBuilderCall = "$_builder.getBoolArrayAttr($0)";
611}
612def I32ArrayAttr : TypedArrayAttrBase<I32Attr,
613                                      "32-bit integer array attribute"> {
614  let constBuilderCall = "$_builder.getI32ArrayAttr($0)";
615}
616def I64ArrayAttr : TypedArrayAttrBase<I64Attr,
617                                      "64-bit integer array attribute"> {
618  let constBuilderCall = "$_builder.getI64ArrayAttr($0)";
619}
620// Variant of I64ArrayAttr whose user accessor is SmallVector<in64_t>.
621def I64SmallVectorArrayAttr :
622    TypedArrayAttrBase<I64Attr, "64-bit integer array attribute"> {
623  let returnType = [{ ::llvm::SmallVector<int64_t, 8> }];
624  let convertFromStorage = [{
625    llvm::to_vector<4>(
626      llvm::map_range($_self.getAsRange<mlir::IntegerAttr>(),
627      [](mlir::IntegerAttr attr) { return attr.getInt(); }));
628  }];
629  let constBuilderCall = "$_builder.getI64ArrayAttr($0)";
630}
631def F32ArrayAttr : TypedArrayAttrBase<F32Attr, "32-bit float array attribute"> {
632  let constBuilderCall = "$_builder.getF32ArrayAttr($0)";
633}
634def F64ArrayAttr : TypedArrayAttrBase<F64Attr, "64-bit float array attribute"> {
635  let constBuilderCall = "$_builder.getF64ArrayAttr($0)";
636}
637def StrArrayAttr : TypedArrayAttrBase<StrAttr, "string array attribute"> {
638  let constBuilderCall = "$_builder.getStrArrayAttr($0)";
639}
640def TypeArrayAttr : TypedArrayAttrBase<TypeAttr, "type array attribute"> {
641  let constBuilderCall = "$_builder.getTypeArrayAttr($0)";
642}
643def IndexListArrayAttr :
644  TypedArrayAttrBase<I64ArrayAttr, "Array of 64-bit integer array attributes">;
645def DictArrayAttr :
646  TypedArrayAttrBase<DictionaryAttr, "Array of dictionary attributes">;
647
648// Attributes containing symbol references.
649def SymbolRefAttr : Attr<CPred<"::llvm::isa<::mlir::SymbolRefAttr>($_self)">,
650                        "symbol reference attribute"> {
651  let storageType = [{ ::mlir::SymbolRefAttr }];
652  let returnType = [{ ::mlir::SymbolRefAttr }];
653  let valueType = NoneType;
654  let constBuilderCall =
655    "::mlir::SymbolRefAttr::get($_builder.getContext(), $0)";
656  let convertFromStorage = "$_self";
657}
658
659def FlatSymbolRefAttr : Attr<CPred<"::llvm::isa<::mlir::FlatSymbolRefAttr>($_self)">,
660                                   "flat symbol reference attribute"> {
661  let storageType = [{ ::mlir::FlatSymbolRefAttr }];
662  let returnType = [{ ::llvm::StringRef }];
663  let valueType = NoneType;
664  let constBuilderCall =
665    "::mlir::SymbolRefAttr::get($_builder.getContext(), $0)";
666  let convertFromStorage = "$_self.getValue()";
667}
668
669def SymbolRefArrayAttr :
670  TypedArrayAttrBase<SymbolRefAttr, "symbol ref array attribute"> {
671  let constBuilderCall = ?;
672}
673
674def FlatSymbolRefArrayAttr :
675  TypedArrayAttrBase<FlatSymbolRefAttr, "flat symbol ref array attribute"> {
676  let constBuilderCall = ?;
677}
678
679//===----------------------------------------------------------------------===//
680// Derive attribute kinds
681
682// DerivedAttr are attributes whose value is computed from properties
683// of the operation. They do not require additional storage and are
684// materialized as needed.
685// Note: All derived attributes should be materializable as an Attribute. E.g.,
686// do not use DerivedAttr for things that could not have been stored as
687// Attribute.
688//
689class DerivedAttr<code ret, code b, code convert = ""> :
690    Attr<CPred<"true">, "derived attribute"> {
691  let returnType = ret;
692  code body = b;
693
694  // Specify how to convert from the derived attribute to an attribute.
695  //
696  // ## Special placeholders
697  //
698  // Special placeholders can be used to refer to entities during conversion:
699  //
700  // * `$_builder` will be replaced by a mlir::Builder instance.
701  // * `$_ctxt` will be replaced by the MLIRContext* instance.
702  // * `$_self` will be replaced with the derived attribute (value produces
703  //    `returnType`).
704  let convertFromStorage = convert;
705}
706
707// Derived attribute that returns a mlir::Type.
708class DerivedTypeAttr<code body> : DerivedAttr<"::mlir::Type", body> {
709  let convertFromStorage = "::mlir::TypeAttr::get($_self)";
710}
711
712//===----------------------------------------------------------------------===//
713// Constant attribute kinds
714
715// Represents a constant attribute of specific Attr type. A constant
716// attribute can be specified only of attributes that have a constant
717// builder call defined. The constant value is specified as a string.
718//
719// If used as a constraint, it generates a matcher on a constant attribute by
720// using the constant value builder of the attribute and the value.
721class ConstantAttr<Attr attribute, string val> : AttrConstraint<
722    CPred<"$_self == " # !subst("$0", val, attribute.constBuilderCall)>,
723    "constant attribute " # val> {
724  Attr attr = attribute;
725  string value = val;
726}
727
728class ConstF32Attr<string val> : ConstantAttr<F32Attr, val>;
729def ConstBoolAttrFalse : ConstantAttr<BoolAttr, "false">;
730def ConstBoolAttrTrue : ConstantAttr<BoolAttr, "true">;
731def ConstUnitAttr : ConstantAttr<UnitAttr, "true">;
732
733// Constant string-based attribute. Wraps the desired string in escaped quotes.
734class ConstantStrAttr<Attr attribute, string val>
735    : ConstantAttr<attribute, "\"" # val # "\"">;
736
737//===----------------------------------------------------------------------===//
738// Common attribute constraints
739//===----------------------------------------------------------------------===//
740
741// A general mechanism to further confine the given `attr` with all the
742// `constraints`. This allows to compose complex constraints out of a series
743// of more primitive ones.
744class ConfinedAttr<Attr attr, list<AttrConstraint> constraints> : Attr<
745    And<!listconcat([attr.predicate],
746                      !foreach(pred, constraints, pred.predicate))>,
747    !foldl(/*init*/attr.summary, /*list*/constraints,
748           prev, cur, prev # " " # cur.summary)> {
749  let storageType = attr.storageType;
750  let returnType = attr.returnType;
751  let convertFromStorage = attr.convertFromStorage;
752  let constBuilderCall = attr.constBuilderCall;
753  let defaultValue = attr.defaultValue;
754  let valueType = attr.valueType;
755  let isOptional = attr.isOptional;
756
757  let baseAttr = attr;
758
759  list<AttrConstraint> attrConstraints = constraints;
760}
761
762// An AttrConstraint that holds if all attr constraints specified in
763// 'constraints' hold.
764class AllAttrOf<list<AttrConstraint> constraints> : AttrConstraint<
765    And<!listconcat([!head(constraints).predicate],
766                    !foreach(pred, !tail(constraints), pred.predicate))>,
767    !interleave(!foreach(con, constraints, con.summary), " and ")> {
768}
769
770class IntNEQValue<int n> : AttrConstraint<
771    CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getInt() != " # n>,
772    "whose value is not " # n>;
773
774class IntMinValue<int n> : AttrConstraint<
775    CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getInt() >= " # n>,
776    "whose minimum value is " # n>;
777
778class IntMaxValue<int n> : AttrConstraint<
779    CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getInt() <= " # n>,
780    "whose maximum value is " # n>;
781
782def IntNonNegative : AttrConstraint<
783    CPred<"!::llvm::cast<::mlir::IntegerAttr>($_self).getValue().isNegative()">,
784    "whose value is non-negative">;
785
786def IntPositive : AttrConstraint<
787    CPred<"::llvm::cast<::mlir::IntegerAttr>($_self).getValue().isStrictlyPositive()">,
788    "whose value is positive">;
789
790class ArrayMaxCount<int n> : AttrConstraint<
791    CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() <= " # n>,
792    "with at most " # n # " elements">;
793
794class ArrayMinCount<int n> : AttrConstraint<
795    CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() >= " # n>,
796    "with at least " # n # " elements">;
797
798class ArrayCount<int n> : AttrConstraint<
799    CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() == " #n>,
800    "with exactly " # n # " elements">;
801
802class DenseArrayCount<int n> : AttrConstraint<
803    CPred<"::llvm::cast<::mlir::DenseArrayAttr>($_self).size() == " #n>,
804    "with exactly " # n # " elements">;
805
806class DenseArrayMaxCt<int n> : AttrConstraint<
807    CPred<"::llvm::cast<::mlir::DenseArrayAttr>($_self).size() <= " # n>,
808    "with at most " # n # " elements">;
809
810class DenseArrayMinCt<int n> : AttrConstraint<
811    CPred<"::llvm::cast<::mlir::DenseArrayAttr>($_self).size() >= " # n>,
812    "with at least " # n # " elements">;
813
814class DenseArrayStrictlyPositive<DenseArrayAttrBase arrayType> : AttrConstraint<
815  CPred<"::llvm::all_of(::llvm::cast<" # arrayType #">($_self).asArrayRef(), "
816                        "[&](auto v) { return v > 0; })">,
817  "whose value is positive">;
818
819class DenseArrayNonNegative<DenseArrayAttrBase arrayType> : AttrConstraint<
820  CPred<"::llvm::all_of(::llvm::cast<" # arrayType #">($_self).asArrayRef(), "
821                        "[&](auto v) { return v >= 0; })">,
822  "whose value is non-negative">;
823
824class DenseArraySorted<DenseArrayAttrBase arrayType> : AttrConstraint<
825    CPred<"llvm::is_sorted(::llvm::cast<" # arrayType # ">($_self).asArrayRef())">,
826    "should be in non-decreasing order">;
827
828class DenseArrayStrictlySorted<DenseArrayAttrBase arrayType> : AttrConstraint<
829    And<[
830      CPred<"llvm::is_sorted(::llvm::cast<" # arrayType # ">($_self).asArrayRef())">,
831      // Check that no two adjacent elements are the same.
832      CPred<"[](" # arrayType.returnType # " a) {\n"
833        "return std::adjacent_find(std::begin(a), std::end(a)) == "
834        "std::end(a);\n"
835        "}(::llvm::cast<" # arrayType # ">($_self).asArrayRef())"
836      >]>,
837    "should be in increasing order">;
838
839class IntArrayNthElemEq<int index, int value> : AttrConstraint<
840    And<[
841      CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>,
842      CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)["
843            # index # "]).getInt() == "  # value>
844       ]>,
845    "whose " # index # "-th element must be " # value>;
846
847class IntArrayNthElemMinValue<int index, int min> : AttrConstraint<
848    And<[
849      CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>,
850      CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)["
851            # index # "]).getInt() >= " # min>
852        ]>,
853    "whose " # index # "-th element must be at least " # min>;
854
855class IntArrayNthElemMaxValue<int index, int max> : AttrConstraint<
856    And<[
857      CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>,
858      CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)["
859            # index # "]).getInt() <= " # max>
860        ]>,
861    "whose " # index # "-th element must be at most " # max>;
862
863class IntArrayNthElemInRange<int index, int min, int max> : AttrConstraint<
864    And<[
865      CPred<"::llvm::cast<::mlir::ArrayAttr>($_self).size() > " # index>,
866      CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)["
867            # index # "]).getInt() >= " # min>,
868      CPred<"::llvm::cast<::mlir::IntegerAttr>(::llvm::cast<::mlir::ArrayAttr>($_self)["
869            # index # "]).getInt() <= " # max>
870        ]>,
871    "whose " # index # "-th element must be at least " # min # " and at most " # max>;
872
873def IsNullAttr : AttrConstraint<
874    CPred<"!$_self">, "empty attribute (for optional attributes)">;
875
876#endif // COMMON_ATTR_CONSTRAINTS_TD
877