1//===-- OpBase.td - Base op definition file ----------------*- 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 is the base operation definition file.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef OP_BASE
14#define OP_BASE
15
16include "mlir/IR/DialectBase.td"
17
18//===----------------------------------------------------------------------===//
19// Common utilities for defining TableGen mechanisms
20//===----------------------------------------------------------------------===//
21
22// A workaround for the inability to define functions in Tablegen.
23//
24// The template parameter defines a string that can be extracted from an
25// instance of this class by accessing the "result" member. Subclasses can take
26// their own template parameters as function "arguments" and use them to
27// populate result.
28// For example, if it didn't already exist, a concat function could be defined
29// like:
30//
31// class StrConcat<list<string> strings> :
32//     StrFunc<!foldl("", strings, prev, cur, prev # cur)>
33//
34// and then called like
35//
36// StrConcat<["a", "b", "c"]>.result
37//
38// to get the string "abc"
39class StrFunc<string r> {
40  string result = r;
41}
42
43// Helper for marking deprecated classes or defs. To mark a def as deprecated,
44// mix in the `Deprecate` class with a reason.
45class Deprecated<string reason> {
46  string odsDeprecated = reason;
47}
48
49//===----------------------------------------------------------------------===//
50// Predicate definitions
51//===----------------------------------------------------------------------===//
52
53// Base class for logical predicates.
54//
55// Predicates are used to compose constraints (see next section for details).
56// There are two categories of predicates:
57//
58// 1. CPred: the primitive leaf predicate.
59// 2. Compound predicate: a predicate composed from child predicates using
60//    predicate combiners ("conjunction", "disjunction", "negation" or
61//    "substitution").
62class Pred;
63
64// A logical predicate wrapping any C expression.
65//
66// This is the basis for composing more complex predicates. It is the "atom"
67// predicate from the perspective of TableGen and the "interface" between
68// TableGen and C++. What is inside is already C++ code, which will be treated
69// as opaque strings with special placeholders to be substituted.
70//
71// ## Special placeholders
72//
73// Special placeholders can be used to refer to entities in the context where
74// this predicate is used. They serve as "hooks" to the enclosing environment.
75// The following special placeholders are supported in constraints for an op:
76//
77// * `$_builder` will be replaced by a mlir::Builder instance.
78// * `$_op` will be replaced by the current operation.
79// * `$_self` will be replaced with the entity this predicate is attached to.
80//   E.g., `BoolAttr` is an attribute constraint that wraps a
81//   `CPred<"$_self.isa<BoolAttr>()">` (see the following sections for details).
82//   Then for `F32:$attr`,`$_self` will be replaced by `$attr`.
83//   For type constraints, it's a little bit special since we want the
84//   constraints on each type definition reads naturally and we want to attach
85//   type constraints directly to an operand/result, $_self will be replaced
86//   by the operand/result's type. E.g., for `F32` in `F32:$operand`, its
87//   `$_self` will be expanded as `getOperand(...).getType()`.
88//
89// One thing to be noticed, while using these placeholders in the C expression,
90// the type of placeholder is only guaranteed to be the base type. For example,
91// if you have a predicate in the form `CPred<"CheckType($_self)">, the argument
92// type of the function `CheckType` should be `mlir::Type`.
93class CPred<code pred> : Pred {
94  code predExpr = "(" # pred # ")";
95}
96
97// Kinds of predicate combiners.  These must closely match the predicates
98// implemented by the C++ backend (tblgen::PredCombinerKind).
99class PredCombinerKind;
100def PredCombinerAnd : PredCombinerKind;
101def PredCombinerOr : PredCombinerKind;
102def PredCombinerNot : PredCombinerKind;
103def PredCombinerSubstLeaves : PredCombinerKind;
104def PredCombinerConcat : PredCombinerKind;
105
106// A predicate that combines other predicates as defined by PredCombinerKind.
107// Instantiated below.
108class CombinedPred<PredCombinerKind k, list<Pred> c> : Pred {
109  PredCombinerKind kind = k;
110  list<Pred> children = c;
111}
112
113// Predicate combiners
114
115// A predicate that holds if all of its children hold.  Always holds for zero
116// children.
117class And<list<Pred> children> : CombinedPred<PredCombinerAnd, children>;
118
119// A predicate that holds if any of its children hold.  Never holds for zero
120// children.
121class Or<list<Pred> children> : CombinedPred<PredCombinerOr, children>;
122
123// A predicate that holds if its child does not.
124class Neg<Pred child> : CombinedPred<PredCombinerNot, [child]>;
125
126// A predicate that substitutes "pat" with "repl" in predicate calls of the
127// leaves of the predicate tree (i.e., not CombinedPred).
128//
129// This is plain string substitution without regular expressions or captures.
130// New predicates with more complex logical can be introduced should the need
131// arise.
132class SubstLeaves<string pat, string repl, Pred child>
133    : CombinedPred<PredCombinerSubstLeaves, [child]> {
134  string pattern = pat;
135  string replacement = repl;
136}
137
138// A predicate that prepends `pre` and appends `suf` to the final predicate
139// string composed from `child`. This is plain string concatenation and there
140// will be no substitution happening for `pre` and `suf`.
141class Concat<string pre, Pred child, string suf> :
142    CombinedPred<PredCombinerConcat, [child]> {
143  string prefix = pre;
144  string suffix = suf;
145}
146
147//===----------------------------------------------------------------------===//
148// Constraint definitions
149//===----------------------------------------------------------------------===//
150
151// TODO: Merge Constraints into Pred.
152
153// Base class for named constraints.
154//
155// An op's operands/attributes/results can have various requirements, e.g.,
156// having certain types, having values inside a certain range, and so on.
157// Besides, for a graph rewrite rule, the source pattern used to match against
158// the existing graph has conditions, like the op's operand must be of a more
159// constrained subtype, the attribute must have a certain value, and so on.
160//
161// These requirements and conditions are modeled using this class. Records of
162// this class are used to generate verification code in op verifier, and
163// matching code in pattern matcher.
164//
165// Constraints are predicates with descriptive names, to facilitate inspection,
166// provide nice error messages, etc.
167class Constraint<Pred pred, string desc = ""> {
168  // The predicates that this constraint requires.
169  Pred predicate = pred;
170  // User-readable one line summary used in error reporting messages. If empty,
171  // a generic message will be used.
172  string summary = desc;
173}
174
175// Subclasses used to differentiate different constraint kinds. These are used
176// as markers for the TableGen backend to handle different constraint kinds
177// differently if needed. Constraints not deriving from the following subclasses
178// are considered as uncategorized constraints.
179
180// Subclass for constraints on a type.
181class TypeConstraint<Pred predicate, string summary = "",
182                     string cppClassNameParam = "::mlir::Type"> :
183    Constraint<predicate, summary> {
184  // The name of the C++ Type class if known, or Type if not.
185  string cppClassName = cppClassNameParam;
186}
187
188// Subclass for constraints on an attribute.
189class AttrConstraint<Pred predicate, string summary = ""> :
190    Constraint<predicate, summary>;
191
192// Subclass for constraints on a region.
193class RegionConstraint<Pred predicate, string summary = ""> :
194    Constraint<predicate, summary>;
195
196// Subclass for constraints on a successor.
197class SuccessorConstraint<Pred predicate, string summary = ""> :
198    Constraint<predicate, summary>;
199
200// How to use these constraint categories:
201//
202// * Use TypeConstraint to specify
203//   * Constraints on an op's operand/result definition
204//   * Further constraints to match an op's operand/result in source pattern
205//
206// * Use Attr (a subclass for AttrConstraint) for
207//   * Constraints on an op's attribute definition
208// * Use AttrConstraint to specify
209//   * Further constraints to match an op's attribute in source pattern
210//
211// * Use uncategorized constraint to specify
212//   * Multi-entity constraints in rewrite rules
213
214//===----------------------------------------------------------------------===//
215// Common predicates
216//===----------------------------------------------------------------------===//
217
218// Whether a type is a VectorType.
219// Explicitly disallow 0-D vectors for now until we have good enough coverage.
220def IsVectorTypePred : And<[CPred<"$_self.isa<::mlir::VectorType>()">,
221                            CPred<"$_self.cast<::mlir::VectorType>().getRank() > 0">]>;
222
223// Temporary vector type clone that allows gradual transition to 0-D vectors.
224// TODO: Remove this when all ops support 0-D vectors.
225def IsVectorOfAnyRankTypePred : CPred<"$_self.isa<::mlir::VectorType>()">;
226
227// Whether a type is a fixed-length VectorType.
228def IsFixedVectorTypePred : CPred<[{$_self.isa<::mlir::VectorType>() &&
229                                  !$_self.cast<VectorType>().isScalable()}]>;
230
231// Whether a type is a scalable VectorType.
232def IsScalableVectorTypePred : CPred<[{$_self.isa<::mlir::VectorType>() &&
233                                   $_self.cast<VectorType>().isScalable()}]>;
234
235// Whether a type is a TensorType.
236def IsTensorTypePred : CPred<"$_self.isa<::mlir::TensorType>()">;
237
238// Whether a type is a MemRefType.
239def IsMemRefTypePred : CPred<"$_self.isa<::mlir::MemRefType>()">;
240
241// Whether a type is an UnrankedMemRefType
242def IsUnrankedMemRefTypePred
243        : CPred<"$_self.isa<::mlir::UnrankedMemRefType>()">;
244
245// Whether a type is an UnrankedTensorType
246def IsUnrankedTensorTypePred
247        : CPred<"$_self.isa<::mlir::UnrankedTensorType>()">;
248
249// Whether a type is a BaseMemRefType
250def IsBaseMemRefTypePred
251        : CPred<"$_self.isa<::mlir::BaseMemRefType>()">;
252
253// Whether a type is a ShapedType.
254def IsShapedTypePred : CPred<"$_self.isa<::mlir::ShapedType>()">;
255
256// For a ShapedType, verify that it has a static shape.
257def HasStaticShapePred :
258        CPred<"$_self.cast<::mlir::ShapedType>().hasStaticShape()">;
259
260// Whether a type is a TupleType.
261def IsTupleTypePred : CPred<"$_self.isa<::mlir::TupleType>()">;
262
263//===----------------------------------------------------------------------===//
264// Type definitions
265//===----------------------------------------------------------------------===//
266
267// A type, carries type constraints.
268class Type<Pred condition, string descr = "",
269           string cppClassName = "::mlir::Type"> :
270    TypeConstraint<condition, descr, cppClassName> {
271  string description = "";
272  string builderCall = "";
273}
274
275// Allows providing an alternative name and summary to an existing type def.
276class TypeAlias<Type t, string summary = t.summary> :
277    Type<t.predicate, summary, t.cppClassName> {
278  let description = t.description;
279  let builderCall = t.builderCall;
280}
281
282// A type of a specific dialect.
283class DialectType<Dialect d, Pred condition, string descr = "",
284                  string cppClassName = "::mlir::Type"> :
285    Type<condition, descr, cppClassName> {
286  Dialect dialect = d;
287}
288
289// A variadic type constraint. It expands to zero or more of the base type. This
290// class is used for supporting variadic operands/results.
291class Variadic<Type type> : TypeConstraint<type.predicate, type.summary,
292                                           type.cppClassName> {
293  Type baseType = type;
294  int minSize = 0;
295}
296
297// A nested variadic type constraint. It expands to zero or more variadic ranges
298// of the base type. This class is used for supporting variadic operands and
299// results. `variadicSegmentAttrName` should correspond to the name of an
300// I32ElementsAttr argument that provides the sizes of the inner variadic
301// operand groups.
302class VariadicOfVariadic<Type type, string variadicSegmentAttrName>
303    : Variadic<type> {
304  string segmentAttrName = variadicSegmentAttrName;
305}
306
307// An optional type constraint. It expands to either zero or one of the base
308// type. This class is used for supporting optional operands/results.
309class Optional<Type type> : TypeConstraint<type.predicate, type.summary,
310                                           type.cppClassName> {
311  Type baseType = type;
312}
313
314// A type that can be constructed using MLIR::Builder.
315// Note that this does not "inherit" from Type because it would require
316// duplicating Type subclasses for buildable and non-buildable cases to avoid
317// diamond "inheritance".
318// TODO: we may extend this to a more general 'Buildable' trait, making some
319// Types and some Attrs buildable.
320class BuildableType<code builder> {
321  // The builder call to invoke (if specified) to construct the BuildableType.
322  code builderCall = builder;
323}
324
325// A type that's buildable iff the type passed as an argument is buildable.
326// This is intended for use by types like container types, which are only
327// buildable if the type of their elements is buildable.
328class SameBuildabilityAs<Type type, code builder> {
329  code builderCall = !if(!empty(type.builderCall), "", builder);
330}
331
332// Any type at all.
333def AnyType : Type<CPred<"true">, "any type">;
334
335// None type
336def NoneType : Type<CPred<"$_self.isa<::mlir::NoneType>()">, "none type",
337                    "::mlir::NoneType">,
338      BuildableType<"$_builder.getType<::mlir::NoneType>()">;
339
340// Any type from the given list
341class AnyTypeOf<list<Type> allowedTypes, string summary = "",
342                string cppClassName = "::mlir::Type"> : Type<
343    // Satisfy any of the allowed type's condition
344    Or<!foreach(allowedtype, allowedTypes, allowedtype.predicate)>,
345    !if(!eq(summary, ""),
346        !interleave(!foreach(t, allowedTypes, t.summary), " or "),
347        summary),
348    cppClassName>;
349
350// Integer types.
351
352// Any integer type irrespective of its width and signedness semantics.
353def AnyInteger : Type<CPred<"$_self.isa<::mlir::IntegerType>()">, "integer",
354                      "::mlir::IntegerType">;
355
356// Any integer type (regardless of signedness semantics) of a specific width.
357class AnyI<int width>
358    : Type<CPred<"$_self.isInteger(" # width # ")">, width # "-bit integer"> {
359  int bitwidth = width;
360}
361
362class AnyIntOfWidths<list<int> widths> :
363    AnyTypeOf<!foreach(w, widths, AnyI<w>),
364              !interleave(widths, "/") # "-bit integer",
365              "::mlir::IntegerType">;
366
367def AnyI1  : AnyI<1>;
368def AnyI8  : AnyI<8>;
369def AnyI16 : AnyI<16>;
370def AnyI32 : AnyI<32>;
371def AnyI64 : AnyI<64>;
372
373// Any signless integer type irrespective of its width.
374def AnySignlessInteger : Type<
375  CPred<"$_self.isSignlessInteger()">, "signless integer",
376        "::mlir::IntegerType">;
377
378// Signless integer type of a specific width.
379class I<int width>
380    : Type<CPred<"$_self.isSignlessInteger(" # width # ")">,
381                  width # "-bit signless integer", "::mlir::IntegerType">,
382      BuildableType<"$_builder.getIntegerType(" # width # ")"> {
383  int bitwidth = width;
384}
385
386class SignlessIntOfWidths<list<int> widths> :
387    AnyTypeOf<!foreach(w, widths, I<w>),
388              !interleave(widths, "/") # "-bit signless integer">;
389
390def I1  : I<1>;
391def I8  : I<8>;
392def I16 : I<16>;
393def I32 : I<32>;
394def I64 : I<64>;
395
396// Any signed integer type irrespective of its width.
397def AnySignedInteger : Type<
398  CPred<"$_self.isSignedInteger()">, "signed integer">;
399
400// Signed integer type of a specific width.
401class SI<int width>
402    : Type<CPred<"$_self.isSignedInteger(" # width # ")">,
403                  width # "-bit signed integer", "::mlir::IntegerType">,
404      BuildableType<
405        "$_builder.getIntegerType(" # width # ", /*isSigned=*/true)"> {
406  int bitwidth = width;
407}
408
409class SignedIntOfWidths<list<int> widths> :
410    AnyTypeOf<!foreach(w, widths, SI<w>),
411              !interleave(widths, "/") # "-bit signed integer">;
412
413def SI1  : SI<1>;
414def SI8  : SI<8>;
415def SI16 : SI<16>;
416def SI32 : SI<32>;
417def SI64 : SI<64>;
418
419// Any unsigned integer type irrespective of its width.
420def AnyUnsignedInteger : Type<
421  CPred<"$_self.isUnsignedInteger()">, "unsigned integer">;
422
423// Unsigned integer type of a specific width.
424class UI<int width>
425    : Type<CPred<"$_self.isUnsignedInteger(" # width # ")">,
426                  width # "-bit unsigned integer", "::mlir::IntegerType">,
427      BuildableType<
428        "$_builder.getIntegerType(" # width # ", /*isSigned=*/false)"> {
429  int bitwidth = width;
430}
431
432class UnsignedIntOfWidths<list<int> widths> :
433    AnyTypeOf<!foreach(w, widths, UI<w>),
434              !interleave(widths, "/") # "-bit unsigned integer">;
435
436def UI1  : UI<1>;
437def UI8  : UI<8>;
438def UI16 : UI<16>;
439def UI32 : UI<32>;
440def UI64 : UI<64>;
441
442// Index type.
443def Index : Type<CPred<"$_self.isa<::mlir::IndexType>()">, "index",
444                 "::mlir::IndexType">,
445            BuildableType<"$_builder.getIndexType()">;
446
447// Any signless integer type or index type.
448def AnySignlessIntegerOrIndex : Type<CPred<"$_self.isSignlessIntOrIndex()">,
449                                     "signless integer or index">;
450
451// Floating point types.
452
453// Any float type irrespective of its width.
454def AnyFloat : Type<CPred<"$_self.isa<::mlir::FloatType>()">, "floating-point",
455                    "::mlir::FloatType">;
456
457// Float type of a specific width.
458class F<int width>
459    : Type<CPred<"$_self.isF" # width # "()">,
460           width # "-bit float", "::mlir::FloatType">,
461      BuildableType<"$_builder.getF" # width # "Type()"> {
462  int bitwidth = width;
463}
464
465class FloatOfWidths<list<int> widths> :
466    AnyTypeOf<!foreach(w, widths, F<w>),
467              !interleave(widths, "/") # "-bit float">;
468
469def F16 : F<16>;
470def F32 : F<32>;
471def F64 : F<64>;
472def F80 : F<80>;
473def F128 : F<128>;
474
475def BF16 : Type<CPred<"$_self.isBF16()">, "bfloat16 type">,
476           BuildableType<"$_builder.getBF16Type()">;
477
478class Complex<Type type>
479    : Type<And<[
480          CPred<"$_self.isa<::mlir::ComplexType>()">,
481          SubstLeaves<"$_self",
482                      "$_self.cast<::mlir::ComplexType>().getElementType()",
483           type.predicate>]>,
484           "complex type with " # type.summary # " elements",
485           "::mlir::ComplexType">,
486      SameBuildabilityAs<type, "::mlir::ComplexType::get($_builder.get" # type #
487                               "Type())"> {
488  Type elementType = type;
489}
490
491def AnyComplex : Type<CPred<"$_self.isa<::mlir::ComplexType>()">,
492                      "complex-type", "::mlir::ComplexType">;
493
494class OpaqueType<string dialect, string name, string summary>
495  : Type<CPred<"isOpaqueTypeWithName($_self, \""#dialect#"\", \""#name#"\")">,
496         summary, "::mlir::OpaqueType">,
497    BuildableType<"::mlir::OpaqueType::get("
498                  "$_builder.getStringAttr(\"" # dialect # "\"), \""
499                  # name # "\")">;
500
501// Function Type
502
503// Any function type.
504def FunctionType : Type<CPred<"$_self.isa<::mlir::FunctionType>()">,
505                              "function type", "::mlir::FunctionType">;
506
507// A container type is a type that has another type embedded within it.
508class ContainerType<Type etype, Pred containerPred, code elementTypeCall,
509                    string descr, string cppClassName = "::mlir::Type"> :
510    // First, check the container predicate.  Then, substitute the extracted
511    // element into the element type checker.
512    Type<And<[containerPred,
513                SubstLeaves<"$_self", !cast<string>(elementTypeCall),
514                etype.predicate>]>,
515         descr # " of " # etype.summary # " values", cppClassName>;
516
517class ShapedContainerType<list<Type> allowedTypes,
518                          Pred containerPred, string descr,
519                          string cppClassName = "::mlir::Type"> :
520    Type<And<[containerPred,
521              Concat<"[](::mlir::Type elementType) { return ",
522                SubstLeaves<"$_self", "elementType",
523                AnyTypeOf<allowedTypes>.predicate>,
524                "; }($_self.cast<::mlir::ShapedType>().getElementType())">]>,
525         descr # " of " # AnyTypeOf<allowedTypes>.summary # " values", cppClassName>;
526
527// Whether a shaped type is ranked.
528def HasRankPred : CPred<"$_self.cast<::mlir::ShapedType>().hasRank()">;
529
530// Whether a shaped type has one of the specified ranks.
531class HasAnyRankOfPred<list<int> ranks> : And<[
532    HasRankPred,
533    Or<!foreach(rank, ranks,
534                CPred<[{$_self.cast<::mlir::ShapedType>().getRank()
535                         == }]
536                      # rank>)>]>;
537
538// Vector types.
539
540class VectorOf<list<Type> allowedTypes> :
541  ShapedContainerType<allowedTypes, IsVectorTypePred, "vector",
542                      "::mlir::VectorType">;
543
544// Temporary vector type clone that allows gradual transition to 0-D vectors.
545// TODO: Remove this when all ops support 0-D vectors.
546class VectorOfAnyRankOf<list<Type> allowedTypes> :
547  ShapedContainerType<allowedTypes, IsVectorOfAnyRankTypePred, "vector",
548                      "::mlir::VectorType">;
549
550class FixedVectorOf<list<Type> allowedTypes> :
551  ShapedContainerType<allowedTypes, IsFixedVectorTypePred,
552          "fixed-length vector", "::mlir::VectorType">;
553
554class ScalableVectorOf<list<Type> allowedTypes> :
555  ShapedContainerType<allowedTypes, IsScalableVectorTypePred,
556          "scalable vector", "::mlir::VectorType">;
557
558// Whether the number of elements of a vector is from the given
559// `allowedRanks` list
560class IsVectorOfRankPred<list<int> allowedRanks> :
561  And<[IsVectorTypePred,
562       Or<!foreach(allowedlength, allowedRanks,
563                   CPred<[{$_self.cast<::mlir::VectorType>().getRank()
564                           == }]
565                         # allowedlength>)>]>;
566
567// Any vector where the rank is from the given `allowedRanks` list
568class VectorOfRank<list<int> allowedRanks> : Type<
569  IsVectorOfRankPred<allowedRanks>,
570  " of ranks " # !interleave(allowedRanks, "/"), "::mlir::VectorType">;
571
572// Any vector where the rank is from the given `allowedRanks` list and the type
573// is from the given `allowedTypes` list
574class VectorOfRankAndType<list<int> allowedRanks,
575                          list<Type> allowedTypes> : Type<
576  And<[VectorOf<allowedTypes>.predicate,
577       VectorOfRank<allowedRanks>.predicate]>,
578  VectorOf<allowedTypes>.summary # VectorOfRank<allowedRanks>.summary,
579  "::mlir::VectorType">;
580
581// Whether the number of elements of a vector is from the given
582// `allowedLengths` list
583class IsVectorOfLengthPred<list<int> allowedLengths> :
584  And<[IsVectorTypePred,
585       Or<!foreach(allowedlength, allowedLengths,
586                   CPred<[{$_self.cast<::mlir::VectorType>().getNumElements()
587                           == }]
588                         # allowedlength>)>]>;
589
590// Whether the number of elements of a fixed-length vector is from the given
591// `allowedLengths` list
592class IsFixedVectorOfLengthPred<list<int> allowedLengths> :
593  And<[IsFixedVectorTypePred,
594       Or<!foreach(allowedlength, allowedLengths,
595                   CPred<[{$_self.cast<::mlir::VectorType>().getNumElements()
596                           == }]
597                         # allowedlength>)>]>;
598
599// Whether the number of elements of a scalable vector is from the given
600// `allowedLengths` list
601class IsScalableVectorOfLengthPred<list<int> allowedLengths> :
602  And<[IsScalableVectorTypePred,
603       Or<!foreach(allowedlength, allowedLengths,
604                   CPred<[{$_self.cast<::mlir::VectorType>().getNumElements()
605                           == }]
606                         # allowedlength>)>]>;
607
608// Any vector where the number of elements is from the given
609// `allowedLengths` list
610class VectorOfLength<list<int> allowedLengths> : Type<
611  IsVectorOfLengthPred<allowedLengths>,
612  " of length " # !interleave(allowedLengths, "/"),
613  "::mlir::VectorType">;
614
615// Any fixed-length vector where the number of elements is from the given
616// `allowedLengths` list
617class FixedVectorOfLength<list<int> allowedLengths> : Type<
618  IsFixedVectorOfLengthPred<allowedLengths>,
619  " of length " # !interleave(allowedLengths, "/"),
620  "::mlir::VectorType">;
621
622// Any scalable vector where the number of elements is from the given
623// `allowedLengths` list
624class ScalableVectorOfLength<list<int> allowedLengths> : Type<
625  IsScalableVectorOfLengthPred<allowedLengths>,
626  " of length " # !interleave(allowedLengths, "/"),
627  "::mlir::VectorType">;
628
629// Any vector where the number of elements is from the given
630// `allowedLengths` list and the type is from the given `allowedTypes`
631// list
632class VectorOfLengthAndType<list<int> allowedLengths,
633                            list<Type> allowedTypes> : Type<
634  And<[VectorOf<allowedTypes>.predicate,
635       VectorOfLength<allowedLengths>.predicate]>,
636  VectorOf<allowedTypes>.summary # VectorOfLength<allowedLengths>.summary,
637  "::mlir::VectorType">;
638
639// Any fixed-length vector where the number of elements is from the given
640// `allowedLengths` list and the type is from the given `allowedTypes` list
641class FixedVectorOfLengthAndType<list<int> allowedLengths,
642                                    list<Type> allowedTypes> : Type<
643  And<[FixedVectorOf<allowedTypes>.predicate,
644       FixedVectorOfLength<allowedLengths>.predicate]>,
645  FixedVectorOf<allowedTypes>.summary #
646  FixedVectorOfLength<allowedLengths>.summary,
647  "::mlir::VectorType">;
648
649// Any scalable vector where the number of elements is from the given
650// `allowedLengths` list and the type is from the given `allowedTypes` list
651class ScalableVectorOfLengthAndType<list<int> allowedLengths,
652                                    list<Type> allowedTypes> : Type<
653  And<[ScalableVectorOf<allowedTypes>.predicate,
654       ScalableVectorOfLength<allowedLengths>.predicate]>,
655  ScalableVectorOf<allowedTypes>.summary #
656  ScalableVectorOfLength<allowedLengths>.summary,
657  "::mlir::VectorType">;
658
659def AnyVector : VectorOf<[AnyType]>;
660// Temporary vector type clone that allows gradual transition to 0-D vectors.
661def AnyVectorOfAnyRank : VectorOfAnyRankOf<[AnyType]>;
662
663def AnyFixedVector : FixedVectorOf<[AnyType]>;
664
665def AnyScalableVector : ScalableVectorOf<[AnyType]>;
666
667// Shaped types.
668
669def AnyShaped: ShapedContainerType<[AnyType], IsShapedTypePred, "shaped",
670                                   "::mlir::ShapedType">;
671
672//===----------------------------------------------------------------------===//
673// Tensor types.
674
675// Unranked tensor type whose element type is from the given
676// `allowedTypes` list.
677class UnrankedTensorOf<list<Type> allowedTypes>
678  : ShapedContainerType<allowedTypes, IsUnrankedTensorTypePred,
679      "unranked.tensor", "::mlir::UnrankedTensorType">;
680
681// Any tensor type whose element type is from the given `allowedTypes`
682// list, and which additionally satisfies an optional list of predicates.
683//
684// TODO: use `Constraint` instead of `Pred`, so we can generate a better
685// default summary (a la `Confined`).
686class TensorOf<
687    list<Type> allowedTypes,
688    list<Pred> preds = [],
689    string summary = "tensor">
690  : ShapedContainerType<allowedTypes,
691      And<!listconcat([IsTensorTypePred], preds)>,
692      summary, "::mlir::TensorType">;
693
694def AnyTensor  : TensorOf<[AnyType]>;
695
696def I1Tensor   : TensorOf<[I1]>;
697def I8Tensor   : TensorOf<[I8]>;
698def I16Tensor  : TensorOf<[I16]>;
699def I32Tensor  : TensorOf<[I32]>;
700def I64Tensor  : TensorOf<[I64]>;
701def IndexTensor: TensorOf<[Index]>;
702
703def BF16Tensor : TensorOf<[BF16]>;
704def F16Tensor  : TensorOf<[F16]>;
705def F32Tensor  : TensorOf<[F32]>;
706def F64Tensor  : TensorOf<[F64]>;
707
708class RankedTensorOf<
709    list<Type> allowedTypes,
710    list<Pred> preds = [],
711    string summary = "ranked tensor">
712  : TensorOf<allowedTypes, !listconcat([HasRankPred], preds), summary>;
713
714def AnyRankedTensor : RankedTensorOf<[AnyType]>;
715
716// Ranked tensor type with one of the specified types and ranks.
717class TensorRankOf<list<Type> allowedTypes, list<int> ranks>
718  : TensorOf<allowedTypes,
719      [HasAnyRankOfPred<ranks>],
720      !interleave(!foreach(rank, ranks, rank # "D"), "/") # " tensor">;
721
722class 0DTensorOf<list<Type> allowedTypes> : TensorRankOf<allowedTypes, [0]>;
723class 1DTensorOf<list<Type> allowedTypes> : TensorRankOf<allowedTypes, [1]>;
724class 2DTensorOf<list<Type> allowedTypes> : TensorRankOf<allowedTypes, [2]>;
725class 3DTensorOf<list<Type> allowedTypes> : TensorRankOf<allowedTypes, [3]>;
726class 4DTensorOf<list<Type> allowedTypes> : TensorRankOf<allowedTypes, [4]>;
727
728class StaticShapeTensorOf<list<Type> allowedTypes>
729  : TensorOf<allowedTypes, [HasStaticShapePred], "statically shaped tensor">;
730
731def AnyStaticShapeTensor : StaticShapeTensorOf<[AnyType]>;
732
733//===----------------------------------------------------------------------===//
734// Memref type.
735
736// Unranked Memref type
737class UnrankedMemRefOf<list<Type> allowedTypes> :
738    ShapedContainerType<allowedTypes,
739                        IsUnrankedMemRefTypePred, "unranked.memref",
740                        "::mlir::UnrankedMemRefType">;
741
742def AnyUnrankedMemRef : UnrankedMemRefOf<[AnyType]>;
743
744// Memrefs are blocks of data with fixed type and rank.
745class MemRefOf<list<Type> allowedTypes> :
746    ShapedContainerType<allowedTypes, IsMemRefTypePred, "memref",
747                        "::mlir::MemRefType">;
748
749def AnyMemRef : MemRefOf<[AnyType]>;
750
751class RankedOrUnrankedMemRefOf<list<Type> allowedTypes>:
752    AnyTypeOf<[UnrankedMemRefOf<allowedTypes>, MemRefOf<allowedTypes>]>;
753
754def AnyRankedOrUnrankedMemRef: AnyTypeOf<[AnyUnrankedMemRef, AnyMemRef]>;
755
756// Memref declarations handle any memref, independent of rank, size, (static or
757// dynamic), layout, or memory space.
758def I1MemRef  : MemRefOf<[I1]>;
759def I8MemRef  : MemRefOf<[I8]>;
760def I16MemRef : MemRefOf<[I16]>;
761def I32MemRef : MemRefOf<[I32]>;
762def I64MemRef : MemRefOf<[I64]>;
763
764def BF16MemRef : MemRefOf<[BF16]>;
765def F16MemRef  : MemRefOf<[F16]>;
766def F32MemRef  : MemRefOf<[F32]>;
767def F64MemRef  : MemRefOf<[F64]>;
768
769// TODO: Have an easy way to add another constraint to a type.
770class MemRefRankOf<list<Type> allowedTypes, list<int> ranks> :
771    Type<And<[MemRefOf<allowedTypes>.predicate, HasAnyRankOfPred<ranks>]>,
772         !interleave(!foreach(rank, ranks, rank # "D"), "/") # " " #
773         MemRefOf<allowedTypes>.summary,
774         "::mlir::MemRefType">;
775
776class StaticShapeMemRefOf<list<Type> allowedTypes>
777    : Type<And<[MemRefOf<allowedTypes>.predicate, HasStaticShapePred]>,
778           "statically shaped " # MemRefOf<allowedTypes>.summary,
779           "::mlir::MemRefType">;
780
781def AnyStaticShapeMemRef : StaticShapeMemRefOf<[AnyType]>;
782
783// For a MemRefType, verify that it has strides.
784def HasStridesPred : CPred<[{ isStrided($_self.cast<::mlir::MemRefType>()) }]>;
785
786class StridedMemRefOf<list<Type> allowedTypes>
787    : Type<And<[MemRefOf<allowedTypes>.predicate, HasStridesPred]>,
788           "strided " # MemRefOf<allowedTypes>.summary>;
789
790def AnyStridedMemRef : StridedMemRefOf<[AnyType]>;
791
792class AnyStridedMemRefOfRank<int rank> :
793  Type<And<[AnyStridedMemRef.predicate,
794            MemRefRankOf<[AnyType], [rank]>.predicate]>,
795       AnyStridedMemRef.summary # " of rank " # rank>;
796
797class StridedMemRefRankOf<list<Type> allowedTypes, list<int> ranks> :
798    Type<And<[MemRefOf<allowedTypes>.predicate, HasAnyRankOfPred<ranks>]>,
799         !interleave(!foreach(rank, ranks, rank # "D"), "/") # " " #
800         MemRefOf<allowedTypes>.summary>;
801
802// This represents a generic tuple without any constraints on element type.
803def AnyTuple : Type<IsTupleTypePred, "tuple", "::mlir::TupleType">;
804
805// A container type that has other types embedded in it, but (unlike
806// ContainerType) can hold elements with a mix of types. Requires a call that
807// produces a list of all elements' types.
808class MixedContainerType<Type etype, Pred containerPred, code elementTypesCall,
809                         string descr> :
810    Type<
811        And<[
812            containerPred,
813            Concat<
814                "::llvm::all_of(" # elementTypesCall # ", [](Type t) { "
815                "return t && (",
816                SubstLeaves<"$_self", "t", etype.predicate>,
817                "); })"
818            >
819        ]>,
820        descr # " with any combination of " # etype.summary # " values"> {
821  // The type of elements in the container.
822  Type elementType = etype;
823
824  // Call to retrieve.
825  code getElementTypesCall = elementTypesCall;
826}
827
828// A Tuple that holds a mix of elements of the allowed types.
829class TupleOf<list<Type> allowedTypes>
830    : MixedContainerType<AnyTypeOf<allowedTypes>, IsTupleTypePred,
831                         "$_self.cast<::mlir::TupleType>().getTypes()",
832                         "tuple">;
833
834// A Tuple with arbitrary nesting, where all elements are a mix of the allowed
835// types.
836class NestedTupleOf<list<Type> allowedTypes> :
837    MixedContainerType<AnyTypeOf<allowedTypes>, IsTupleTypePred,
838                       "getFlattenedTypes($_self.cast<::mlir::TupleType>())",
839                       "nested tuple">;
840
841//===----------------------------------------------------------------------===//
842// Common type constraints
843//===----------------------------------------------------------------------===//
844// Type constraint for types that are "like" some type or set of types T, that is
845// they're either a T, a vector of Ts, or a tensor of Ts
846class TypeOrContainer<Type allowedType, string name> : TypeConstraint<Or<[
847  allowedType.predicate, VectorOf<[allowedType]>.predicate,
848  TensorOf<[allowedType]>.predicate]>,
849  name>;
850
851// Temporary constraint to allow gradual transition to supporting 0-D vectors.
852// TODO: Remove this when all ops support 0-D vectors.
853class TypeOrContainerOfAnyRank<Type allowedType, string name> : TypeConstraint<Or<[
854  allowedType.predicate, VectorOfAnyRankOf<[allowedType]>.predicate,
855  TensorOf<[allowedType]>.predicate]>,
856  name>;
857
858
859// Type constraint for bool-like types: bools, vectors of bools, tensors of
860// bools.
861def BoolLike : TypeOrContainer<I1, "bool-like">;
862
863def BoolLikeOfAnyRank : TypeOrContainerOfAnyRank<I1, "bool-like">;
864
865// Type constraint for signless-integer-like types: signless integers, indices,
866// vectors of signless integers or indices, tensors of signless integers.
867def SignlessIntegerLike : TypeOrContainer<AnySignlessIntegerOrIndex,
868    "signless-integer-like">;
869
870def SignlessIntegerLikeOfAnyRank : TypeOrContainerOfAnyRank<
871    AnySignlessIntegerOrIndex,
872    "signless-integer-like">;
873
874// Type constraint for float-like types: floats, vectors or tensors thereof.
875def FloatLike : TypeOrContainer<AnyFloat, "floating-point-like">;
876
877// Type constraint for signless-integer-like or float-like types.
878def SignlessIntegerOrFloatLike : TypeConstraint<Or<[
879    SignlessIntegerLike.predicate, FloatLike.predicate]>,
880    "signless-integer-like or floating-point-like">;
881
882//===----------------------------------------------------------------------===//
883// Attribute definitions
884//===----------------------------------------------------------------------===//
885
886//===----------------------------------------------------------------------===//
887// Base attribute definition
888
889// Base class for all attributes.
890class Attr<Pred condition, string summary = ""> :
891    AttrConstraint<condition, summary> {
892  code storageType = ?; // The backing mlir::Attribute type
893  code returnType = ?;  // The underlying C++ value type
894
895  // The call expression to convert from the storage type to the return
896  // type. For example, an enum can be stored as an int but returned as an
897  // enum class.
898  //
899  // Format: $_self will be expanded to the attribute.
900  //
901  // For example, `$_self.getValue().getSExtValue()` for `IntegerAttr val` will
902  // expand to `getAttrOfType<IntegerAttr>("val").getValue().getSExtValue()`.
903  code convertFromStorage = "$_self.getValue()";
904
905  // The call expression to build an attribute from a constant value.
906  //
907  // Format: $0 will be expanded to the constant value of the attribute.
908  //
909  // For example, `$_builder.getStringAttr("$0")` for `StringAttr:"foo"` will
910  // expand to `builder.getStringAttr("foo")`.
911  string constBuilderCall = ?;
912
913  // Default value for attribute.
914  // Requires a constBuilderCall defined.
915  string defaultValue = ?;
916
917  // The value type of this attribute. This corresponds to the mlir::Type that
918  // this attribute returns via `getType()`.
919  Type valueType = ?;
920
921  // Whether the attribute is optional. Typically requires a custom
922  // convertFromStorage method to handle the case where the attribute is
923  // not present.
924  bit isOptional = 0;
925
926  // What is the base-level Attr instantiation that this Attr is built upon.
927  // Unset means this is a base-level Attr.
928  //
929  // This field is used by attribute wrapper classes (DefaultValuedAttr,
930  // OptionalAttr, etc.) to retrieve the base-level attribute definition.
931  // This can be used for getting its name; otherwise, we will see
932  // "anonymous_<number>" as the attribute def name because of template
933  // instantiation.
934  // TOOD(b/132458159): deduplicate the fields in attribute wrapper classes.
935  Attr baseAttr = ?;
936
937  // The fully-qualified C++ namespace where the generated class lives.
938  string cppNamespace = "";
939
940  // The full description of this attribute.
941  string description = "";
942}
943
944// An attribute of a specific dialect.
945class DialectAttr<Dialect d, Pred condition, string summary = ""> :
946    Attr<condition, summary> {
947  Dialect dialect = d;
948  let cppNamespace = d.cppNamespace;
949}
950
951//===----------------------------------------------------------------------===//
952// Attribute modifier definition
953
954// Decorates an attribute to have an (unvalidated) default value if not present.
955class DefaultValuedAttr<Attr attr, string val> :
956    Attr<attr.predicate, attr.summary> {
957  // Construct this attribute with the input attribute and change only
958  // the default value.
959  // Note: this has to be kept up to date with Attr above.
960  let storageType = attr.storageType;
961  let returnType = attr.returnType;
962  let convertFromStorage = attr.convertFromStorage;
963  let constBuilderCall = attr.constBuilderCall;
964  let defaultValue = val;
965  let valueType = attr.valueType;
966
967  let baseAttr = attr;
968}
969
970// Decorates an attribute as optional. The return type of the generated
971// attribute accessor method will be Optional<>.
972class OptionalAttr<Attr attr> : Attr<attr.predicate, attr.summary> {
973  // Rewrite the attribute to be optional.
974  // Note: this has to be kept up to date with Attr above.
975  let storageType = attr.storageType;
976  let returnType = "::llvm::Optional<" # attr.returnType #">";
977  let convertFromStorage = "$_self ? " # returnType # "(" #
978                           attr.convertFromStorage # ") : (::llvm::None)";
979  let valueType = attr.valueType;
980  let isOptional = 1;
981
982  let baseAttr = attr;
983}
984
985// Default-valued string-based attribute. Wraps the default value in escaped
986// quotes.
987class DefaultValuedStrAttr<Attr attr, string val>
988    : DefaultValuedAttr<attr, "\"" # val # "\"">;
989
990//===----------------------------------------------------------------------===//
991// Primitive attribute kinds
992
993// A generic attribute that must be constructed around a specific buildable type
994// `attrValType`. Backed by MLIR attribute kind `attrKind`.
995class TypedAttrBase<Type attrValType, string attrKind, Pred condition,
996                    string descr> :
997    Attr<condition, descr> {
998  let constBuilderCall = "$_builder.get" # attrKind # "(" #
999                         attrValType.builderCall # ", $0)";
1000  let storageType = "::mlir::" # attrKind;
1001  let valueType = attrValType;
1002}
1003
1004// Any attribute.
1005def AnyAttr : Attr<CPred<"true">, "any attribute"> {
1006  let storageType = "::mlir::Attribute";
1007  let returnType = "::mlir::Attribute";
1008  let convertFromStorage = "$_self";
1009  let constBuilderCall = "$0";
1010}
1011
1012// Any attribute from the given list
1013class AnyAttrOf<list<Attr> allowedAttrs, string summary = "",
1014                string cppClassName = "::mlir::Attribute",
1015                string fromStorage = "$_self"> : Attr<
1016    // Satisfy any of the allowed attribute's condition
1017    Or<!foreach(allowedattr, allowedAttrs, allowedattr.predicate)>,
1018    !if(!eq(summary, ""),
1019        !interleave(!foreach(t, allowedAttrs, t.summary), " or "),
1020        summary)> {
1021    let returnType = cppClassName;
1022    let convertFromStorage = fromStorage;
1023}
1024
1025def BoolAttr : Attr<CPred<"$_self.isa<::mlir::BoolAttr>()">, "bool attribute"> {
1026  let storageType = [{ ::mlir::BoolAttr }];
1027  let returnType = [{ bool }];
1028  let valueType = I1;
1029  let constBuilderCall = "$_builder.getBoolAttr($0)";
1030}
1031
1032// Index attribute.
1033def IndexAttr :
1034    TypedAttrBase<
1035      Index, "IntegerAttr",
1036      And<[CPred<"$_self.isa<::mlir::IntegerAttr>()">,
1037           CPred<"$_self.cast<::mlir::IntegerAttr>().getType()"
1038                 ".isa<::mlir::IndexType>()">]>,
1039      "index attribute"> {
1040  let returnType = [{ ::llvm::APInt }];
1041}
1042
1043// Base class for any integer (regardless of signedness semantics) attributes
1044// of fixed width.
1045class AnyIntegerAttrBase<AnyI attrValType, string descr> :
1046    TypedAttrBase<
1047      attrValType, "IntegerAttr",
1048      And<[CPred<"$_self.isa<::mlir::IntegerAttr>()">,
1049           CPred<"$_self.cast<::mlir::IntegerAttr>().getType()."
1050                 "isInteger(" # attrValType.bitwidth # ")">]>,
1051      descr> {
1052  let returnType = [{ ::llvm::APInt }];
1053  let constBuilderCall = ?;
1054}
1055
1056def AnyI1Attr  : AnyIntegerAttrBase<AnyI1,  "1-bit integer attribute">;
1057def AnyI8Attr  : AnyIntegerAttrBase<AnyI8,  "8-bit integer attribute">;
1058def AnyI16Attr : AnyIntegerAttrBase<AnyI16, "16-bit integer attribute">;
1059def AnyI32Attr : AnyIntegerAttrBase<AnyI32, "32-bit integer attribute">;
1060def AnyI64Attr : AnyIntegerAttrBase<AnyI64, "64-bit integer attribute">;
1061
1062def APIntAttr : Attr<CPred<"$_self.isa<::mlir::IntegerAttr>()">,
1063                     "arbitrary integer attribute"> {
1064  let storageType = [{ ::mlir::IntegerAttr }];
1065  let returnType = [{ ::mlir::APInt }];
1066}
1067
1068// Base class for signless integer attributes of fixed width.
1069class SignlessIntegerAttrBase<I attrValType, string descr> :
1070    TypedAttrBase<
1071      attrValType, "IntegerAttr",
1072      And<[CPred<"$_self.isa<::mlir::IntegerAttr>()">,
1073           CPred<"$_self.cast<::mlir::IntegerAttr>().getType()."
1074                 "isSignlessInteger(" # attrValType.bitwidth # ")">]>,
1075      descr> {
1076  let returnType = [{ ::llvm::APInt }];
1077}
1078// Base class for signless integer attributes of fixed width that have a
1079// corresponding C++ type.
1080class TypedSignlessIntegerAttrBase<I attrValType, string retType, string descr>
1081    : SignlessIntegerAttrBase<attrValType, descr> {
1082  let returnType = retType;
1083  let convertFromStorage = "$_self.getValue().getZExtValue()";
1084}
1085
1086def I1Attr  : TypedSignlessIntegerAttrBase<
1087    I1,  "bool",     "1-bit signless integer attribute">;
1088def I8Attr  : TypedSignlessIntegerAttrBase<
1089    I8,  "uint8_t",  "8-bit signless integer attribute">;
1090def I16Attr : TypedSignlessIntegerAttrBase<
1091    I16, "uint16_t", "16-bit signless integer attribute">;
1092def I32Attr : TypedSignlessIntegerAttrBase<
1093    I32, "uint32_t", "32-bit signless integer attribute">;
1094def I64Attr : TypedSignlessIntegerAttrBase<
1095    I64, "uint64_t", "64-bit signless integer attribute">;
1096
1097// Base class for signed integer attributes of fixed width.
1098class SignedIntegerAttrBase<SI attrValType, string descr> :
1099    TypedAttrBase<
1100      attrValType, "IntegerAttr",
1101      And<[CPred<"$_self.isa<::mlir::IntegerAttr>()">,
1102           CPred<"$_self.cast<::mlir::IntegerAttr>().getType()."
1103                 "isSignedInteger(" # attrValType.bitwidth # ")">]>,
1104      descr> {
1105  let returnType = [{ ::llvm::APInt }];
1106}
1107// Base class for signed integer attributes of fixed width that have a
1108// corresponding C++ type.
1109class TypedSignedIntegerAttrBase<SI attrValType, string retType, string descr>
1110    : SignedIntegerAttrBase<attrValType, descr> {
1111  let returnType = retType;
1112  let convertFromStorage = "$_self.getValue().getSExtValue()";
1113}
1114
1115def SI1Attr  : TypedSignedIntegerAttrBase<
1116    SI1,  "bool",    "1-bit signed integer attribute">;
1117def SI8Attr  : TypedSignedIntegerAttrBase<
1118    SI8,  "int8_t",  "8-bit signed integer attribute">;
1119def SI16Attr : TypedSignedIntegerAttrBase<
1120    SI16, "int16_t", "16-bit signed integer attribute">;
1121def SI32Attr : TypedSignedIntegerAttrBase<
1122    SI32, "int32_t", "32-bit signed integer attribute">;
1123def SI64Attr : TypedSignedIntegerAttrBase<
1124    SI64, "int64_t", "64-bit signed integer attribute">;
1125
1126// Base class for unsigned integer attributes of fixed width.
1127class UnsignedIntegerAttrBase<UI attrValType, string descr> :
1128    TypedAttrBase<
1129      attrValType, "IntegerAttr",
1130      And<[CPred<"$_self.isa<::mlir::IntegerAttr>()">,
1131           CPred<"$_self.cast<::mlir::IntegerAttr>().getType()."
1132                 "isUnsignedInteger(" # attrValType.bitwidth # ")">]>,
1133      descr> {
1134  let returnType = [{ ::llvm::APInt }];
1135}
1136// Base class for unsigned integer attributes of fixed width that have a
1137// corresponding C++ type.
1138class TypedUnsignedIntegerAttrBase<UI attrValType, string retType, string descr>
1139    : UnsignedIntegerAttrBase<attrValType, descr> {
1140  let returnType = retType;
1141  let convertFromStorage = "$_self.getValue().getZExtValue()";
1142}
1143
1144def UI1Attr  : TypedUnsignedIntegerAttrBase<
1145    UI1,  "bool",     "1-bit unsigned integer attribute">;
1146def UI8Attr  : TypedUnsignedIntegerAttrBase<
1147    UI8,  "uint8_t",  "8-bit unsigned integer attribute">;
1148def UI16Attr : TypedUnsignedIntegerAttrBase<
1149    UI16, "uint16_t", "16-bit unsigned integer attribute">;
1150def UI32Attr : TypedUnsignedIntegerAttrBase<
1151    UI32, "uint32_t", "32-bit unsigned integer attribute">;
1152def UI64Attr : TypedUnsignedIntegerAttrBase<
1153    UI64, "uint64_t", "64-bit unsigned integer attribute">;
1154
1155// Base class for float attributes of fixed width.
1156class FloatAttrBase<F attrValType, string descr> :
1157    TypedAttrBase<attrValType, "FloatAttr",
1158              And<[CPred<"$_self.isa<::mlir::FloatAttr>()">,
1159                     CPred<"$_self.cast<::mlir::FloatAttr>().getType().isF" #
1160                           attrValType.bitwidth # "()">]>,
1161              descr> {
1162  let returnType = [{ ::llvm::APFloat }];
1163}
1164
1165def F32Attr : FloatAttrBase<F32, "32-bit float attribute">;
1166def F64Attr : FloatAttrBase<F64, "64-bit float attribute">;
1167
1168// An attribute backed by a string type.
1169class StringBasedAttr<Pred condition, string descr> : Attr<condition, descr> {
1170  let constBuilderCall = "$_builder.getStringAttr($0)";
1171  let storageType = [{ ::mlir::StringAttr }];
1172  let returnType = [{ ::llvm::StringRef }];
1173  let valueType = NoneType;
1174}
1175
1176def StrAttr : StringBasedAttr<CPred<"$_self.isa<::mlir::StringAttr>()">,
1177                              "string attribute">;
1178
1179// A string attribute that represents the name of a symbol.
1180def SymbolNameAttr : StringBasedAttr<CPred<"$_self.isa<::mlir::StringAttr>()">,
1181                                     "string attribute">;
1182
1183// String attribute that has a specific value type.
1184class TypedStrAttr<Type ty>
1185    : StringBasedAttr<CPred<"$_self.isa<::mlir::StringAttr>()">,
1186                            "string attribute"> {
1187  let valueType = ty;
1188}
1189
1190// Base class for attributes containing types. Example:
1191//   def IntTypeAttr : TypeAttrBase<"IntegerType", "integer type attribute">
1192// defines a type attribute containing an integer type.
1193class TypeAttrBase<string retType, string summary> :
1194    Attr<And<[
1195      CPred<"$_self.isa<::mlir::TypeAttr>()">,
1196      CPred<"$_self.cast<::mlir::TypeAttr>().getValue().isa<"
1197            # retType # ">()">]>,
1198    summary> {
1199  let storageType = [{ ::mlir::TypeAttr }];
1200  let returnType = retType;
1201  let valueType = NoneType;
1202  let convertFromStorage = "$_self.getValue().cast<" # retType # ">()";
1203}
1204
1205def TypeAttr : TypeAttrBase<"::mlir::Type", "any type attribute"> {
1206  let constBuilderCall = "::mlir::TypeAttr::get($0)";
1207}
1208
1209class TypeAttrOf<Type ty>
1210   : TypeAttrBase<ty.cppClassName, "type attribute of " # ty.summary> {
1211  let constBuilderCall = "::mlir::TypeAttr::get($0)";
1212}
1213
1214// The mere presence of unit attributes has a meaning.  Therefore, unit
1215// attributes are always treated as optional and accessors to them return
1216// "true" if the attribute is present and "false" otherwise.
1217def UnitAttr : Attr<CPred<"$_self.isa<::mlir::UnitAttr>()">, "unit attribute"> {
1218  let storageType = [{ ::mlir::UnitAttr }];
1219  let constBuilderCall = "$_builder.getUnitAttr()";
1220  let convertFromStorage = "$_self != nullptr";
1221  let returnType = "bool";
1222  let valueType = NoneType;
1223  let isOptional = 1;
1224}
1225
1226//===----------------------------------------------------------------------===//
1227// Composite attribute kinds
1228
1229class DictionaryAttrBase<Pred condition, string summary> :
1230    Attr<condition, summary> {
1231  let storageType = [{ ::mlir::DictionaryAttr }];
1232  let returnType = [{ ::mlir::DictionaryAttr }];
1233  let valueType = NoneType;
1234  let convertFromStorage = "$_self";
1235}
1236
1237def DictionaryAttr
1238    : DictionaryAttrBase<CPred<"$_self.isa<::mlir::DictionaryAttr>()">,
1239                               "dictionary of named attribute values">;
1240
1241class ElementsAttrBase<Pred condition, string summary> :
1242    Attr<condition, summary> {
1243  let storageType = [{ ::mlir::ElementsAttr }];
1244  let returnType = [{ ::mlir::ElementsAttr }];
1245  let convertFromStorage = "$_self";
1246}
1247
1248def ElementsAttr : ElementsAttrBase<CPred<"$_self.isa<::mlir::ElementsAttr>()">,
1249                                    "constant vector/tensor attribute">;
1250
1251class IntElementsAttrBase<Pred condition, string summary> :
1252    ElementsAttrBase<And<[CPred<"$_self.isa<::mlir::DenseIntElementsAttr>()">,
1253                          condition]>,
1254                     summary> {
1255  let storageType = [{ ::mlir::DenseIntElementsAttr }];
1256  let returnType = [{ ::mlir::DenseIntElementsAttr }];
1257
1258  let convertFromStorage = "$_self";
1259}
1260
1261class DenseArrayAttrBase<string denseAttrName, string cppType, string summaryName> :
1262    ElementsAttrBase<CPred<"$_self.isa<::mlir::" # denseAttrName # ">()">,
1263                     summaryName # " dense array attribute"> {
1264  let storageType = "::mlir::" # denseAttrName;
1265  let returnType = "::llvm::ArrayRef<" # cppType # ">";
1266}
1267def DenseI8ArrayAttr : DenseArrayAttrBase<"DenseI8ArrayAttr", "int8_t", "i8">;
1268def DenseI16ArrayAttr : DenseArrayAttrBase<"DenseI16ArrayAttr", "int16_t", "i16">;
1269def DenseI32ArrayAttr : DenseArrayAttrBase<"DenseI32ArrayAttr", "int32_t", "i32">;
1270def DenseI64ArrayAttr : DenseArrayAttrBase<"DenseI64ArrayAttr", "int64_t", "i64">;
1271def DenseF32ArrayAttr : DenseArrayAttrBase<"DenseF32ArrayAttr", "float", "f32">;
1272def DenseF64ArrayAttr : DenseArrayAttrBase<"DenseF64ArrayAttr", "double", "f64">;
1273
1274def IndexElementsAttr
1275    : IntElementsAttrBase<CPred<[{$_self.cast<::mlir::DenseIntElementsAttr>()
1276                                      .getType()
1277                                      .getElementType()
1278                                      .isIndex()}]>,
1279                          "index elements attribute">;
1280
1281def AnyIntElementsAttr : IntElementsAttrBase<CPred<"true">, "integer elements attribute">;
1282
1283class IntElementsAttrOf<int width> : IntElementsAttrBase<
1284  CPred<"$_self.cast<::mlir::DenseIntElementsAttr>().getType()."
1285        "getElementType().isInteger(" # width # ")">,
1286  width # "-bit integer elements attribute">;
1287
1288def AnyI32ElementsAttr : IntElementsAttrOf<32>;
1289def AnyI64ElementsAttr : IntElementsAttrOf<64>;
1290
1291class SignlessIntElementsAttr<int width> : IntElementsAttrBase<
1292  CPred<"$_self.cast<::mlir::DenseIntElementsAttr>().getType()."
1293        "getElementType().isSignlessInteger(" # width # ")">,
1294  width # "-bit signless integer elements attribute"> {
1295
1296  // Note that this is only constructing scalar elements attribute.
1297  let constBuilderCall = "::mlir::DenseElementsAttr::get("
1298    "::mlir::RankedTensorType::get({}, "
1299                                  "$_builder.getIntegerType(" # width # ")), "
1300    "::llvm::makeArrayRef($0)).cast<::mlir::DenseIntElementsAttr>()";
1301}
1302
1303def I32ElementsAttr : SignlessIntElementsAttr<32>;
1304def I64ElementsAttr : SignlessIntElementsAttr<64>;
1305
1306// A `width`-bit signless integer elements attribute. The attribute should be
1307// ranked and has a shape as specified in `dims`.
1308class RankedSignlessIntElementsAttr<int width, list<int> dims> :
1309    SignlessIntElementsAttr<width> {
1310  // Check that this has the specified shape.
1311  let predicate = And<[
1312    SignlessIntElementsAttr<width>.predicate,
1313    CPred<"$_self.cast<::mlir::DenseIntElementsAttr>().getType().getShape() == "
1314        "::mlir::ArrayRef<int64_t>({" # !interleave(dims, ", ") # "})">]>;
1315
1316  let summary = width # "-bit signless int elements attribute of shape [" #
1317                !interleave(dims, ", ") # "]";
1318
1319  let constBuilderCall = "::mlir::DenseIntElementsAttr::get("
1320    "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
1321    "}, $_builder.getIntegerType(" # width # ")), ::llvm::makeArrayRef($0))";
1322}
1323
1324class RankedI32ElementsAttr<list<int> dims> :
1325    RankedSignlessIntElementsAttr<32, dims>;
1326class RankedI64ElementsAttr<list<int> dims> :
1327    RankedSignlessIntElementsAttr<64, dims>;
1328
1329class FloatElementsAttr<int width> : ElementsAttrBase<
1330  CPred<"$_self.isa<::mlir::DenseFPElementsAttr>() &&"
1331      "$_self.cast<::mlir::DenseElementsAttr>().getType()."
1332      "getElementType().isF" # width # "()">,
1333  width # "-bit float elements attribute"> {
1334
1335  let storageType = [{ ::mlir::DenseElementsAttr }];
1336  let returnType = [{ ::mlir::DenseElementsAttr }];
1337
1338  // Note that this is only constructing scalar elements attribute.
1339  let constBuilderCall = "::mlir::DenseElementsAttr::get("
1340    "::mlir::RankedTensorType::get({}, $_builder.getF" # width # "Type()),"
1341    "::llvm::makeArrayRef($0))";
1342  let convertFromStorage = "$_self";
1343}
1344
1345def F64ElementsAttr : FloatElementsAttr<64>;
1346
1347// A `width`-bit floating point elements attribute. The attribute should be
1348// ranked and has a shape as specified in `dims`.
1349class RankedFloatElementsAttr<int width, list<int> dims> : ElementsAttrBase<
1350  CPred<"$_self.isa<::mlir::DenseFPElementsAttr>() &&"
1351      "$_self.cast<::mlir::DenseFPElementsAttr>().getType()."
1352      "getElementType().isF" # width # "() && "
1353      // Check that this is ranked and has the specified shape.
1354      "$_self.cast<::mlir::DenseFPElementsAttr>().getType().hasRank() && "
1355      "$_self.cast<::mlir::DenseFPElementsAttr>().getType().getShape() == "
1356      "::mlir::ArrayRef<int64_t>({" # !interleave(dims, ", ") # "})">,
1357  width # "-bit float elements attribute of shape [" #
1358  !interleave(dims, ", ") # "]"> {
1359
1360  let storageType = [{ ::mlir::DenseFPElementsAttr }];
1361  let returnType = [{ ::mlir::DenseFPElementsAttr }];
1362
1363  let constBuilderCall = "::mlir::DenseElementsAttr::get("
1364    "::mlir::RankedTensorType::get({" # !interleave(dims, ", ") #
1365    "}, $_builder.getF" # width # "Type()), "
1366    "::llvm::makeArrayRef($0)).cast<::mlir::DenseFPElementsAttr>()";
1367  let convertFromStorage = "$_self";
1368}
1369
1370class RankedF32ElementsAttr<list<int> dims> : RankedFloatElementsAttr<32, dims>;
1371class RankedF64ElementsAttr<list<int> dims> : RankedFloatElementsAttr<64, dims>;
1372
1373def StringElementsAttr : ElementsAttrBase<
1374  CPred<"$_self.isa<::mlir::DenseStringElementsAttr>()" >,
1375  "string elements attribute"> {
1376
1377  let storageType = [{ ::mlir::DenseElementsAttr }];
1378  let returnType = [{ ::mlir::DenseElementsAttr }];
1379
1380  let convertFromStorage = "$_self";
1381}
1382
1383// Attributes containing affine maps.
1384def AffineMapAttr : Attr<
1385CPred<"$_self.isa<::mlir::AffineMapAttr>()">, "AffineMap attribute"> {
1386  let storageType = [{::mlir::AffineMapAttr }];
1387  let returnType = [{ ::mlir::AffineMap }];
1388  let valueType = Index;
1389  let constBuilderCall = "::mlir::AffineMapAttr::get($0)";
1390}
1391
1392// Base class for array attributes.
1393class ArrayAttrBase<Pred condition, string summary> : Attr<condition, summary> {
1394  let storageType = [{ ::mlir::ArrayAttr }];
1395  let returnType = [{ ::mlir::ArrayAttr }];
1396  let valueType = NoneType;
1397  let convertFromStorage = "$_self";
1398  let constBuilderCall = "$_builder.getArrayAttr($0)";
1399}
1400
1401def ArrayAttr : ArrayAttrBase<CPred<"$_self.isa<::mlir::ArrayAttr>()">,
1402                              "array attribute">;
1403
1404// Base class for array attributes whose elements are of the same kind.
1405// `element` specifies the element attribute kind stored in this array.
1406class TypedArrayAttrBase<Attr element, string summary>: ArrayAttrBase<
1407    And<[
1408      // Guarantee this is an ArrayAttr first
1409      CPred<"$_self.isa<::mlir::ArrayAttr>()">,
1410      // Guarantee all elements satisfy the constraints from `element`
1411      Concat<"::llvm::all_of($_self.cast<::mlir::ArrayAttr>(), "
1412                            "[&](::mlir::Attribute attr) { return attr && (",
1413                               SubstLeaves<"$_self", "attr", element.predicate>,
1414                            "); })">]>,
1415    summary> {
1416
1417  Attr elementAttr = element;
1418}
1419
1420def AffineMapArrayAttr : TypedArrayAttrBase<AffineMapAttr,
1421                                      "AffineMap array attribute"> {
1422  let constBuilderCall = "$_builder.getAffineMapArrayAttr($0)";
1423}
1424
1425def BoolArrayAttr : TypedArrayAttrBase<BoolAttr,
1426                                      "1-bit boolean array attribute"> {
1427  let constBuilderCall = "$_builder.getBoolArrayAttr($0)";
1428}
1429def I32ArrayAttr : TypedArrayAttrBase<I32Attr,
1430                                      "32-bit integer array attribute"> {
1431  let constBuilderCall = "$_builder.getI32ArrayAttr($0)";
1432}
1433def I64ArrayAttr : TypedArrayAttrBase<I64Attr,
1434                                      "64-bit integer array attribute"> {
1435  let constBuilderCall = "$_builder.getI64ArrayAttr($0)";
1436}
1437// Variant of I64ArrayAttr whose user accessor is SmallVector<in64_t>.
1438def I64SmallVectorArrayAttr :
1439    TypedArrayAttrBase<I64Attr, "64-bit integer array attribute"> {
1440  let returnType = [{ ::llvm::SmallVector<int64_t, 8> }];
1441  let convertFromStorage = [{
1442    llvm::to_vector<4>(
1443      llvm::map_range($_self.getAsRange<mlir::IntegerAttr>(),
1444      [](IntegerAttr attr) { return attr.getInt(); }));
1445  }];
1446  let constBuilderCall = "$_builder.getI64ArrayAttr($0)";
1447}
1448def F32ArrayAttr : TypedArrayAttrBase<F32Attr, "32-bit float array attribute"> {
1449  let constBuilderCall = "$_builder.getF32ArrayAttr($0)";
1450}
1451def F64ArrayAttr : TypedArrayAttrBase<F64Attr, "64-bit float array attribute"> {
1452  let constBuilderCall = "$_builder.getF64ArrayAttr($0)";
1453}
1454def StrArrayAttr : TypedArrayAttrBase<StrAttr, "string array attribute"> {
1455  let constBuilderCall = "$_builder.getStrArrayAttr($0)";
1456}
1457def TypeArrayAttr : TypedArrayAttrBase<TypeAttr, "type array attribute"> {
1458  let constBuilderCall = "$_builder.getTypeArrayAttr($0)";
1459}
1460def IndexListArrayAttr :
1461  TypedArrayAttrBase<I64ArrayAttr, "Array of 64-bit integer array attributes">;
1462
1463// Attributes containing symbol references.
1464def SymbolRefAttr : Attr<CPred<"$_self.isa<::mlir::SymbolRefAttr>()">,
1465                        "symbol reference attribute"> {
1466  let storageType = [{ ::mlir::SymbolRefAttr }];
1467  let returnType = [{ ::mlir::SymbolRefAttr }];
1468  let valueType = NoneType;
1469  let constBuilderCall =
1470    "::mlir::SymbolRefAttr::get($_builder.getContext(), $0)";
1471  let convertFromStorage = "$_self";
1472}
1473
1474def FlatSymbolRefAttr : Attr<CPred<"$_self.isa<::mlir::FlatSymbolRefAttr>()">,
1475                                   "flat symbol reference attribute"> {
1476  let storageType = [{ ::mlir::FlatSymbolRefAttr }];
1477  let returnType = [{ ::llvm::StringRef }];
1478  let valueType = NoneType;
1479  let constBuilderCall =
1480    "::mlir::SymbolRefAttr::get($_builder.getContext(), $0)";
1481  let convertFromStorage = "$_self.getValue()";
1482}
1483
1484def SymbolRefArrayAttr :
1485  TypedArrayAttrBase<SymbolRefAttr, "symbol ref array attribute"> {
1486  let constBuilderCall = ?;
1487}
1488
1489def FlatSymbolRefArrayAttr :
1490  TypedArrayAttrBase<FlatSymbolRefAttr, "flat symbol ref array attribute"> {
1491  let constBuilderCall = ?;
1492}
1493
1494//===----------------------------------------------------------------------===//
1495// Derive attribute kinds
1496
1497// DerivedAttr are attributes whose value is computed from properties
1498// of the operation. They do not require additional storage and are
1499// materialized as needed.
1500// Note: All derived attributes should be materializable as an Attribute. E.g.,
1501// do not use DerivedAttr for things that could not have been stored as
1502// Attribute.
1503//
1504class DerivedAttr<code ret, code b, code convert = ""> :
1505    Attr<CPred<"true">, "derived attribute"> {
1506  let returnType = ret;
1507  code body = b;
1508
1509  // Specify how to convert from the derived attribute to an attribute.
1510  //
1511  // ## Special placeholders
1512  //
1513  // Special placeholders can be used to refer to entities during conversion:
1514  //
1515  // * `$_builder` will be replaced by a mlir::Builder instance.
1516  // * `$_ctxt` will be replaced by the MLIRContext* instance.
1517  // * `$_self` will be replaced with the derived attribute (value produces
1518  //    `returnType`).
1519  let convertFromStorage = convert;
1520}
1521
1522// Derived attribute that returns a mlir::Type.
1523class DerivedTypeAttr<code body> : DerivedAttr<"::mlir::Type", body> {
1524  let convertFromStorage = "::mlir::TypeAttr::get($_self)";
1525}
1526
1527//===----------------------------------------------------------------------===//
1528// Constant attribute kinds
1529
1530// Represents a constant attribute of specific Attr type. A constant
1531// attribute can be specified only of attributes that have a constant
1532// builder call defined. The constant value is specified as a string.
1533//
1534// If used as a constraint, it generates a matcher on a constant attribute by
1535// using the constant value builder of the attribute and the value.
1536class ConstantAttr<Attr attribute, string val> : AttrConstraint<
1537    CPred<"$_self == " # !subst("$0", val, attribute.constBuilderCall)>,
1538    "constant attribute " # val> {
1539  Attr attr = attribute;
1540  string value = val;
1541}
1542
1543class ConstF32Attr<string val> : ConstantAttr<F32Attr, val>;
1544def ConstBoolAttrFalse : ConstantAttr<BoolAttr, "false">;
1545def ConstBoolAttrTrue : ConstantAttr<BoolAttr, "true">;
1546def ConstUnitAttr : ConstantAttr<UnitAttr, "unit">;
1547
1548// Constant string-based attribute. Wraps the desired string in escaped quotes.
1549class ConstantStrAttr<Attr attribute, string val>
1550    : ConstantAttr<attribute, "\"" # val # "\"">;
1551
1552//===----------------------------------------------------------------------===//
1553// Common attribute constraints
1554//===----------------------------------------------------------------------===//
1555
1556// A general mechanism to further confine the given `attr` with all the
1557// `constraints`. This allows to compose complex constraints out of a series
1558// of more primitive ones.
1559class Confined<Attr attr, list<AttrConstraint> constraints> : Attr<
1560    And<!listconcat([attr.predicate],
1561                      !foreach(pred, constraints, pred.predicate))>,
1562    !foldl(/*init*/attr.summary, /*list*/constraints,
1563           prev, cur, prev # " " # cur.summary)> {
1564  let storageType = attr.storageType;
1565  let returnType = attr.returnType;
1566  let convertFromStorage = attr.convertFromStorage;
1567  let constBuilderCall = attr.constBuilderCall;
1568  let defaultValue = attr.defaultValue;
1569  let valueType = attr.valueType;
1570  let isOptional = attr.isOptional;
1571
1572  let baseAttr = attr;
1573}
1574
1575// An AttrConstraint that holds if all attr constraints specified in
1576// 'constraints' hold.
1577class AllAttrConstraintsOf<list<AttrConstraint> constraints> : AttrConstraint<
1578    And<!listconcat([!head(constraints).predicate],
1579                      !foreach(pred, !tail(constraints), pred.predicate))>,
1580    !interleave(!foreach(con, constraints, con.summary), " and ")> {
1581}
1582
1583class IntMinValue<int n> : AttrConstraint<
1584    CPred<"$_self.cast<::mlir::IntegerAttr>().getInt() >= " # n>,
1585    "whose minimum value is " # n>;
1586
1587class IntMaxValue<int n> : AttrConstraint<
1588    CPred<"$_self.cast<::mlir::IntegerAttr>().getInt() <= " # n>,
1589    "whose maximum value is " # n>;
1590
1591def IntNonNegative : AttrConstraint<
1592    CPred<"!$_self.cast<::mlir::IntegerAttr>().getValue().isNegative()">,
1593    "whose value is non-negative">;
1594
1595def IntPositive : AttrConstraint<
1596    CPred<"$_self.cast<::mlir::IntegerAttr>().getValue().isStrictlyPositive()">,
1597    "whose value is positive">;
1598
1599class ArrayMinCount<int n> : AttrConstraint<
1600    CPred<"$_self.cast<::mlir::ArrayAttr>().size() >= " # n>,
1601    "with at least " # n # " elements">;
1602
1603class ArrayCount<int n> : AttrConstraint<
1604    CPred<"$_self.cast<::mlir::ArrayAttr>().size() == " #n>,
1605    "with exactly " # n # " elements">;
1606
1607class IntArrayNthElemEq<int index, int value> : AttrConstraint<
1608    And<[
1609      CPred<"$_self.cast<::mlir::ArrayAttr>().size() > " # index>,
1610      CPred<"$_self.cast<::mlir::ArrayAttr>()[" # index # "]"
1611        ".cast<::mlir::IntegerAttr>().getInt() == " # value>
1612       ]>,
1613    "whose " # index # "-th element must be " # value>;
1614
1615class IntArrayNthElemMinValue<int index, int min> : AttrConstraint<
1616    And<[
1617      CPred<"$_self.cast<::mlir::ArrayAttr>().size() > " # index>,
1618      CPred<"$_self.cast<::mlir::ArrayAttr>()[" # index # "]"
1619        ".cast<::mlir::IntegerAttr>().getInt() >= " # min>
1620        ]>,
1621    "whose " # index # "-th element must be at least " # min>;
1622
1623def IsNullAttr : AttrConstraint<
1624    CPred<"!$_self">, "empty attribute (for optional attributes)">;
1625
1626// An attribute constraint on FlatSymbolRefAttr that requires that the
1627// reference point to an op of `opClass` within the closest parent with a symbol
1628// table.
1629// TODO: Add support for nested symbol references.
1630class ReferToOp<string opClass> : AttrConstraint<
1631    CPred<"isa_and_nonnull<" # opClass # ">("
1632            "::mlir::SymbolTable::lookupNearestSymbolFrom("
1633              "&$_op, $_self.cast<::mlir::FlatSymbolRefAttr>().getAttr()))">,
1634    "referencing to a '" # opClass # "' symbol">;
1635
1636//===----------------------------------------------------------------------===//
1637// Region definitions
1638//===----------------------------------------------------------------------===//
1639
1640class Region<Pred condition, string descr = ""> :
1641    RegionConstraint<condition, descr>;
1642
1643// Any region.
1644def AnyRegion : Region<CPred<"true">, "any region">;
1645
1646// A region with the given number of blocks.
1647class SizedRegion<int numBlocks> : Region<
1648  CPred<"::llvm::hasNItems($_self, " # numBlocks # ")">,
1649  "region with " # numBlocks # " blocks">;
1650
1651// A region with at least the given number of blocks.
1652class MinSizedRegion<int numBlocks> : Region<
1653  CPred<"::llvm::hasNItemsOrMore($_self, " # numBlocks # ")">,
1654  "region with at least " # numBlocks # " blocks">;
1655
1656// A variadic region constraint. It expands to zero or more of the base region.
1657class VariadicRegion<Region region>
1658  : Region<region.predicate, region.summary>;
1659
1660//===----------------------------------------------------------------------===//
1661// Successor definitions
1662//===----------------------------------------------------------------------===//
1663
1664class Successor<Pred condition, string descr = ""> :
1665    SuccessorConstraint<condition, descr>;
1666
1667// Any successor.
1668def AnySuccessor : Successor<?, "any successor">;
1669
1670// A variadic successor constraint. It expands to zero or more of the base
1671// successor.
1672class VariadicSuccessor<Successor successor>
1673  : Successor<successor.predicate, successor.summary>;
1674
1675
1676//===----------------------------------------------------------------------===//
1677// Trait definitions
1678//===----------------------------------------------------------------------===//
1679
1680// Trait represents a trait regarding an attribute, operation, or type.
1681class Trait;
1682
1683// Define a Trait corresponding to a list of Traits, this allows for specifying
1684// a list of traits as trait. Avoids needing to do `[Traits, ...] # ListOfTraits
1685// # [Others, ...]` while still allowing providing convenient groupings.
1686class TraitList<list<Trait> props> : Trait {
1687  list<Trait> traits = props;
1688}
1689
1690// NativeTrait corresponds to the MLIR C++ trait mechanism. The purpose to wrap
1691// around C++ symbol string with this class is to make traits specified for
1692// entities in TableGen less alien and more integrated.
1693class NativeTrait<string name, string entityType> : Trait {
1694  string trait = name;
1695  string cppNamespace = "::mlir::" # entityType # "Trait";
1696}
1697
1698// ParamNativeTrait corresponds to the template-parameterized traits in the C++
1699// implementation. MLIR uses nested class templates to implement such traits
1700// leading to constructs of the form "TraitName<Parameters>::Impl". Use the
1701// value in `prop` as the trait name and the value in `params` as parameters to
1702// construct the native trait class name.
1703class ParamNativeTrait<string prop, string params, string entityType>
1704    : NativeTrait<prop # "<" # params # ">::Impl", entityType>;
1705
1706// GenInternalTrait is a trait that does not have direct C++ mapping but affects
1707// an entities definition generator internals, like how operation builders and
1708// operand/attribute/result getters are generated.
1709class GenInternalTrait<string prop, string entityType> : Trait {
1710  string trait = "::mlir::" # entityType # "Trait::" # prop;
1711}
1712
1713// PredTrait is a trait implemented by way of a predicate on an entity.
1714class PredTrait<string descr, Pred pred> : Trait {
1715  string summary = descr;
1716  Pred predicate = pred;
1717}
1718
1719//===----------------------------------------------------------------------===//
1720// OpTrait definitions
1721//===----------------------------------------------------------------------===//
1722
1723// A trait that describes the structure of operation will be marked with
1724// `StructuralOpTrait` and they will be verified first.
1725class StructuralOpTrait;
1726
1727// These classes are used to define operation specific traits.
1728class NativeOpTrait<string name, list<Trait> traits = []>
1729    : NativeTrait<name, "Op"> {
1730  // Specify the list of traits that need to be verified before the verification
1731  // of this NativeOpTrait.
1732  list<Trait> dependentTraits = traits;
1733}
1734class ParamNativeOpTrait<string prop, string params,
1735                         list<Trait> traits = []>
1736    : ParamNativeTrait<prop, params, "Op"> {
1737  // Specify the list of traits that need to be verified before the verification
1738  // of this ParamNativeOpTrait.
1739  list<Trait> dependentTraits = traits;
1740}
1741class GenInternalOpTrait<string prop, list<Trait> traits = []>
1742    : GenInternalTrait<prop, "Op"> {
1743  // Specify the list of traits that need to be verified before the verification
1744  // of this GenInternalOpTrait.
1745  list<Trait> dependentTraits = traits;
1746}
1747class PredOpTrait<string descr, Pred pred, list<Trait> traits = []>
1748    : PredTrait<descr, pred> {
1749  // Specify the list of traits that need to be verified before the verification
1750  // of this PredOpTrait.
1751  list<Trait> dependentTraits = traits;
1752}
1753
1754// Op defines an affine scope.
1755def AffineScope : NativeOpTrait<"AffineScope">;
1756// Op defines an automatic allocation scope.
1757def AutomaticAllocationScope :
1758  NativeOpTrait<"AutomaticAllocationScope">;
1759// Op supports operand broadcast behavior.
1760def ResultsBroadcastableShape :
1761  NativeOpTrait<"ResultsBroadcastableShape">;
1762// X op Y == Y op X
1763def Commutative  : NativeOpTrait<"IsCommutative">;
1764// op op X == op X (unary) / X op X == X (binary)
1765// FIXME: Idempotent should depend on SameOperandsAndResultType
1766def Idempotent : NativeOpTrait<"IsIdempotent">;
1767// op op X == X
1768// FIXME: Involution should depend on SameOperandsAndResultType
1769def Involution : NativeOpTrait<"IsInvolution">;
1770// Op behaves like a constant.
1771def ConstantLike : NativeOpTrait<"ConstantLike">;
1772// Op is isolated from above.
1773def IsolatedFromAbove : NativeOpTrait<"IsIsolatedFromAbove">;
1774// Op results are float or vectors/tensors thereof.
1775def ResultsAreFloatLike : NativeOpTrait<"ResultsAreFloatLike">;
1776// Op has the same operand type.
1777def SameTypeOperands : NativeOpTrait<"SameTypeOperands">;
1778// Op has same shape for all operands.
1779def SameOperandsShape : NativeOpTrait<"SameOperandsShape">;
1780// Op has same operand and result shape.
1781def SameOperandsAndResultShape :
1782  NativeOpTrait<"SameOperandsAndResultShape">;
1783// Op has the same element type (or type itself, if scalar) for all operands.
1784def SameOperandsElementType :
1785  NativeOpTrait<"SameOperandsElementType">;
1786// Op has the same operand and result element type (or type itself, if scalar).
1787def SameOperandsAndResultElementType :
1788  NativeOpTrait<"SameOperandsAndResultElementType">;
1789// Op is a terminator.
1790def Terminator : NativeOpTrait<"IsTerminator">;
1791// Op can be safely normalized in the presence of MemRefs with
1792// non-identity maps.
1793def MemRefsNormalizable : NativeOpTrait<"MemRefsNormalizable">;
1794// Op is elementwise on tensor/vector operands and results.
1795def Elementwise : NativeOpTrait<"Elementwise">;
1796// Elementwise op can be applied to scalars instead tensor/vector operands.
1797def Scalarizable : NativeOpTrait<"Scalarizable", [Elementwise]>;
1798// Elementwise op can be applied to all-vector operands.
1799def Vectorizable : NativeOpTrait<"Vectorizable", [Elementwise]>;
1800// Elementwise op can be applied to all-tensor operands.
1801def Tensorizable : NativeOpTrait<"Tensorizable", [Elementwise]>;
1802
1803// Group together `Elementwise`, `Scalarizable`, `Vectorizable`, and
1804// `Tensorizable` for convenience.
1805def ElementwiseMappable : TraitList<[
1806    Elementwise,
1807    Scalarizable,
1808    Vectorizable,
1809    Tensorizable,
1810]>;
1811
1812// Op's regions have a single block.
1813def SingleBlock : NativeOpTrait<"SingleBlock">, StructuralOpTrait;
1814
1815// Op's regions have a single block with the specified terminator.
1816class SingleBlockImplicitTerminator<string op>
1817    : ParamNativeOpTrait<"SingleBlockImplicitTerminator", op>,
1818      StructuralOpTrait;
1819
1820// Op's regions don't have terminator.
1821def NoTerminator : NativeOpTrait<"NoTerminator">, StructuralOpTrait;
1822
1823// Op's parent operation is the provided one.
1824class HasParent<string op>
1825    : ParamNativeOpTrait<"HasParent", op>, StructuralOpTrait;
1826
1827class ParentOneOf<list<string> ops>
1828    : ParamNativeOpTrait<"HasParent", !interleave(ops, ", ")>,
1829      StructuralOpTrait;
1830
1831// Op result type is derived from the first attribute. If the attribute is an
1832// subclass of `TypeAttrBase`, its value is used, otherwise, the type of the
1833// attribute content is used.
1834def FirstAttrDerivedResultType :
1835  GenInternalOpTrait<"FirstAttrDerivedResultType">;
1836
1837// TODO: Turn the following into normal traits and generate verification for
1838// them.
1839
1840// All variadic operands of the op have the same number of values.
1841// A variadic operand contains an array of values whose array size is only
1842// known at runtime. This trait requires all variadic operands of an op
1843// to have the same array size.
1844def SameVariadicOperandSize : GenInternalOpTrait<"SameVariadicOperandSize">;
1845// All variadic results of the op have the same number of values.
1846// A variadic result contains an array of values whose array size is only
1847// known at runtime. This trait requires all variadic results of an op
1848// to have the same array size.
1849def SameVariadicResultSize : GenInternalOpTrait<"SameVariadicResultSize">;
1850
1851// Uses an attribute named `operand_segment_sizes` to specify how many actual
1852// operand each ODS-declared operand (variadic or not) corresponds to.
1853// This trait is used for ops that have multiple variadic operands but do
1854// not know statically their size relationship. The attribute must be a 1D
1855// vector that has the same number of elements as the number of ODS declared
1856// operands. That means even if some operands are non-variadic, the attribute
1857// still need to have an element for its size, which is always 1.
1858def AttrSizedOperandSegments :
1859  NativeOpTrait<"AttrSizedOperandSegments">, StructuralOpTrait;
1860// Similar to AttrSizedOperandSegments, but used for results. The attribute
1861// should be named as `result_segment_sizes`.
1862def AttrSizedResultSegments  :
1863  NativeOpTrait<"AttrSizedResultSegments">, StructuralOpTrait;
1864
1865// Op attached regions have no arguments
1866def NoRegionArguments : NativeOpTrait<"NoRegionArguments">, StructuralOpTrait;
1867
1868//===----------------------------------------------------------------------===//
1869// OpInterface definitions
1870//===----------------------------------------------------------------------===//
1871
1872// Marker used to identify the argument list for an op or interface method.
1873def ins;
1874
1875// This class represents a typed argument with optional default value for C
1876// function signatures, e.g. builders or methods.
1877class CArg<string ty, string value = ""> {
1878  string type = ty;
1879  string defaultValue = value;
1880}
1881
1882// InterfaceTrait corresponds to a specific 'Interface' class defined in C++.
1883// The purpose to wrap around C++ symbol string with this class is to make
1884// interfaces specified for ops in TableGen less alien and more integrated.
1885class InterfaceTrait<string name> : NativeTrait<"", ""> {
1886  let trait = name # "::Trait";
1887  let cppNamespace = "";
1888
1889  // An optional code block containing extra declarations to place in the
1890  // interface trait declaration.
1891  code extraTraitClassDeclaration = "";
1892}
1893
1894// OpInterfaceTrait corresponds to a specific 'OpInterface' class defined in
1895// C++. The purpose to wrap around C++ symbol string with this class is to make
1896// interfaces specified for ops in TableGen less alien and more integrated.
1897class OpInterfaceTrait<string name, code verifyBody = [{}],
1898                       list<Trait> traits = []>
1899    : InterfaceTrait<name> {
1900  // Specify the body of the verification function. `$_op` will be replaced with
1901  // the operation being verified.
1902  code verify = verifyBody;
1903
1904  // A bit indicating if the verifier needs to access the ops in the regions. If
1905  // it set to `1`, the region ops will be verified before invoking this
1906  // verifier.
1907  bit verifyWithRegions = 0;
1908
1909  // Specify the list of traits that need to be verified before the verification
1910  // of this OpInterfaceTrait.
1911  list<Trait> dependentTraits = traits;
1912}
1913
1914// This class represents a single, optionally static, interface method.
1915// Note: non-static interface methods have an implicit parameter, either
1916// $_op/$_attr/$_type corresponding to an instance of the derived value.
1917class InterfaceMethod<string desc, string retTy, string methodName,
1918                      dag args = (ins), code methodBody = [{}],
1919                      code defaultImplementation = [{}]> {
1920  // A human-readable description of what this method does.
1921  string description = desc;
1922
1923  // The name of the interface method.
1924  string name = methodName;
1925
1926  // The c++ type-name of the return type.
1927  string returnType = retTy;
1928
1929  // A dag of string that correspond to the arguments of the method.
1930  dag arguments = args;
1931
1932  // An optional body to the method.
1933  code body = methodBody;
1934
1935  // An optional default implementation of the method.
1936  code defaultBody = defaultImplementation;
1937}
1938
1939// This class represents a single static interface method.
1940class StaticInterfaceMethod<string desc, string retTy, string methodName,
1941                            dag args = (ins), code methodBody = [{}],
1942                            code defaultImplementation = [{}]>
1943    : InterfaceMethod<desc, retTy, methodName, args, methodBody,
1944                      defaultImplementation>;
1945
1946// Interface represents a base interface.
1947class Interface<string name> {
1948  // A human-readable description of what this interface does.
1949  string description = "";
1950
1951  // The name given to the c++ interface class.
1952  string cppInterfaceName = name;
1953
1954  // The C++ namespace that this interface should be placed into.
1955  //
1956  // To specify nested namespaces, use "::" as the delimiter, e.g., given
1957  // "A::B", ops will be placed in `namespace A { namespace B { <def> } }`.
1958  string cppNamespace = "";
1959
1960  // The list of methods defined by this interface.
1961  list<InterfaceMethod> methods = [];
1962
1963  // An optional code block containing extra declarations to place in the
1964  // interface declaration.
1965  code extraClassDeclaration = "";
1966
1967  // An optional code block containing extra declarations to place in both
1968  // the interface and trait declaration.
1969  code extraSharedClassDeclaration = "";
1970}
1971
1972// AttrInterface represents an interface registered to an attribute.
1973class AttrInterface<string name> : Interface<name>, InterfaceTrait<name>,
1974	Attr<CPred<"$_self.isa<"
1975		# !if(!empty(cppNamespace),"", cppNamespace # "::") # name # ">()">,
1976			name # " instance">
1977{
1978	let storageType = !if(!empty(cppNamespace), "", cppNamespace # "::") # name;
1979	let returnType = storageType;
1980	let convertFromStorage = "$_self";
1981}
1982
1983// OpInterface represents an interface registered to an operation.
1984class OpInterface<string name> : Interface<name>, OpInterfaceTrait<name>;
1985
1986// TypeInterface represents an interface registered to a type.
1987class TypeInterface<string name> : Interface<name>, InterfaceTrait<name>,
1988	Type<CPred<"$_self.isa<"
1989		# !if(!empty(cppNamespace),"", cppNamespace # "::") # name # ">()">,
1990			name # " instance",
1991				!if(!empty(cppNamespace),"", cppNamespace # "::") # name>;
1992
1993// Whether to declare the interface methods in the user entity's header. This
1994// class simply wraps an Interface but is used to indicate that the method
1995// declarations should be generated. This class takes an optional set of methods
1996// that should have declarations generated even if the method has a default
1997// implementation.
1998class DeclareInterfaceMethods<list<string> overridenMethods = []> {
1999    // This field contains a set of method names that should always have their
2000    // declarations generated. This allows for generating declarations for
2001    // methods with default implementations that need to be overridden.
2002    list<string> alwaysOverriddenMethods = overridenMethods;
2003}
2004class DeclareAttrInterfaceMethods<AttrInterface interface,
2005                                  list<string> overridenMethods = []>
2006      : DeclareInterfaceMethods<overridenMethods>,
2007        AttrInterface<interface.cppInterfaceName> {
2008    let description = interface.description;
2009    let cppInterfaceName = interface.cppInterfaceName;
2010    let cppNamespace = interface.cppNamespace;
2011    let methods = interface.methods;
2012}
2013class DeclareOpInterfaceMethods<OpInterface interface,
2014                                list<string> overridenMethods = []>
2015      : DeclareInterfaceMethods<overridenMethods>,
2016        OpInterface<interface.cppInterfaceName> {
2017    let description = interface.description;
2018    let cppInterfaceName = interface.cppInterfaceName;
2019    let cppNamespace = interface.cppNamespace;
2020    let methods = interface.methods;
2021}
2022class DeclareTypeInterfaceMethods<TypeInterface interface,
2023                                  list<string> overridenMethods = []>
2024      : DeclareInterfaceMethods<overridenMethods>,
2025        TypeInterface<interface.cppInterfaceName> {
2026    let description = interface.description;
2027    let cppInterfaceName = interface.cppInterfaceName;
2028    let cppNamespace = interface.cppNamespace;
2029    let methods = interface.methods;
2030}
2031
2032//===----------------------------------------------------------------------===//
2033// Op definitions
2034//===----------------------------------------------------------------------===//
2035
2036// Marker used to identify the result list for an op.
2037def outs;
2038
2039// Marker used to identify the region list for an op.
2040def region;
2041
2042// Marker used to identify the successor list for an op.
2043def successor;
2044
2045// Class for defining a custom builder.
2046//
2047// TableGen generates several generic builders for each op by default (see
2048// comment in the `Op` class). If the default generated ones cannot cover
2049// some use case, custom builders can be defined using instances of this class.
2050//
2051// The signature of the builder is always
2052//
2053// ```c++
2054// static void build(::mlir::OpBuilder &builder, ::mlir::OperationState &state,
2055//                   <other-parameters>...) {
2056//   <body>...
2057// }
2058// ```
2059//
2060// To define a custom builder, the parameter list (*excluding* the
2061// `OpBuilder &builder, OperationState &state` part) and body should be passed
2062// in as separate template arguments to this class. The parameter list is a
2063// TableGen DAG with `ins` operation with named arguments, which has either:
2064//   - string initializers ("Type":$name) to represent a typed parameter, or
2065//   - CArg-typed initializers (CArg<"Type", "default">:$name) to represent a
2066//     typed parameter that may have a default value.
2067// The type string is used verbatim to produce code and, therefore, must be a
2068// valid C++ type. It is used inside the C++ namespace of the parent Op's
2069// dialect; explicit namespace qualification like `::mlir` may be necessary if
2070// Ops are not placed inside the `mlir` namespace. The default value string is
2071// used verbatim to produce code and must be a valid C++ initializer the given
2072// type. For example, the following signature specification
2073//
2074// ```
2075// OpBuilder<(ins "int":$integerArg, CArg<"float", "3.0f">:$floatArg)>
2076// ```
2077//
2078// has an integer parameter and a float parameter with a default value.
2079//
2080// If an empty string is passed in for `body`, then *only* the builder
2081// declaration will be generated; this provides a way to define complicated
2082// builders entirely in C++.
2083class OpBuilder<dag p, code b = ""> {
2084  dag dagParams = p;
2085  code body = b;
2086}
2087
2088// A base decorator class that may optionally be added to OpVariables.
2089class OpVariableDecorator;
2090
2091// Class for providing additional information on the variables, i.e. arguments
2092// and results, of an operation.
2093class OpVariable<Constraint varConstraint, string desc = "",
2094                 list<OpVariableDecorator> varDecorators = []> {
2095  // The constraint, either attribute or type, of the argument.
2096  Constraint constraint = varConstraint;
2097
2098  // One-line human-readable description of the argument.
2099  string summary = desc;
2100
2101  // The list of decorators for this variable, e.g. side effects.
2102  list<OpVariableDecorator> decorators = varDecorators;
2103}
2104class Arg<Constraint constraint, string desc = "",
2105          list<OpVariableDecorator> decorators = []>
2106  : OpVariable<constraint, desc, decorators>;
2107class Res<Constraint constraint, string desc = "",
2108          list<OpVariableDecorator> decorators = []>
2109  : OpVariable<constraint, desc, decorators>;
2110
2111// Base class for all ops.
2112class Op<Dialect dialect, string mnemonic, list<Trait> props = []> {
2113  // The dialect of the op.
2114  Dialect opDialect = dialect;
2115
2116  // The mnemonic of the op.
2117  string opName = mnemonic;
2118
2119  // The C++ namespace to use for this op.
2120  string cppNamespace = dialect.cppNamespace;
2121
2122  // One-line human-readable description of what the op does.
2123  string summary = "";
2124
2125  // Additional, longer human-readable description of what the op does.
2126  string description = "";
2127
2128  // Dag containing the arguments of the op. Default to 0 arguments.
2129  dag arguments = (ins);
2130
2131  // The list of results of the op. Default to 0 results.
2132  dag results = (outs);
2133
2134  // The list of regions of the op. Default to 0 regions.
2135  dag regions = (region);
2136
2137  // The list of successors of the op. Default to 0 successors.
2138  dag successors = (successor);
2139
2140  // Attribute getters can be added to the op by adding an Attr member
2141  // with the name and type of the attribute. E.g., adding int attribute
2142  // with name "value" and type "i32":
2143  //   I32Attr value;
2144
2145  // Define the hooks used for building, parsing, printing, verification.
2146
2147  // Custom builder.
2148  // In addition to the custom builder provided here, and unless
2149  // skipDefaultBuilders is set, two default builders are generated, with the
2150  // following signatures:
2151  //
2152  // ```c++
2153  // static void build(OpBuilder &, OperationState &odsState,
2154  //                   Type <result0-name>, Type <result1-name>, ...,
2155  //                   Value <arg0-name>, Value <arg1-name>, ...,
2156  //                   Attribute <attr0-name>, Attribute <attr1-name>, ...);
2157  // ```
2158  // * where the attributes follow the same declaration order as in the op.
2159  //
2160  // ```c++
2161  // static void build(OpBuilder &, OperationState &odsState,
2162  //                   TypeRange resultTypes,
2163  //                   ValueRange operands,
2164  //                   ArrayRef<NamedAttribute> attributes);
2165  // ```
2166  list<OpBuilder> builders = ?;
2167
2168  // Avoid generating default build functions.  Custom builders must be
2169  // provided.
2170  bit skipDefaultBuilders = 0;
2171
2172  // Custom assembly format.
2173  /// This field corresponds to a declarative description of the assembly format
2174  /// for this operation. If populated, the `hasCustomAssemblyFormat` field is
2175  /// ignored.
2176  string assemblyFormat = ?;
2177  /// This field indicates that the operation has a custom assembly format
2178  /// implemented in C++. When set to `1` a `parse` and `print` method are generated
2179  /// on the operation class. The operation should implement these methods to
2180  /// support the custom format of the operation. The methods have the form:
2181  ///   * ParseResult parse(OpAsmParser &parser, OperationState &result)
2182  ///   * void print(OpAsmPrinter &p)
2183  bit hasCustomAssemblyFormat = 0;
2184
2185  // A bit indicating if the operation has additional invariants that need to
2186  // verified (aside from those verified by other ODS constructs). If set to `1`,
2187  // an additional `LogicalResult verify()` declaration will be generated on the
2188  // operation class. The operation should implement this method and verify the
2189  // additional necessary invariants. This verifier shouldn't access any nested
2190  // operations because those operations may ill-formed. Use the
2191  // `hasRegionVerifier` below instead.
2192  bit hasVerifier = 0;
2193
2194  // A bit indicating if the operation has additional invariants that need to
2195  // verified and which associate with regions (aside from those verified by the
2196  // traits). If set to `1`, an additional `LogicalResult verifyRegions()`
2197  // declaration will be generated on the operation class. The operation should
2198  // implement this method and verify the additional necessary invariants
2199  // associated with regions. Note that this method is invoked after all the
2200  // region ops are verified.
2201  bit hasRegionVerifier = 0;
2202
2203  // Whether this op has associated canonicalization patterns.
2204  bit hasCanonicalizer = 0;
2205
2206  // Whether this op has a static "canonicalize" method to perform "match and
2207  // rewrite patterns".
2208  bit hasCanonicalizeMethod = 0;
2209
2210  // Whether this op has a folder.
2211  bit hasFolder = 0;
2212
2213  // Op traits.
2214  // Note: The list of traits will be uniqued by ODS.
2215  list<Trait> traits = props;
2216
2217  // Additional code that will be added to the public part of the generated
2218  // C++ code of the op declaration.
2219  code extraClassDeclaration = ?;
2220
2221  // Additional code that will be added to the generated source file. The
2222  // generated code is placed inside the op's C++ namespace. `$cppClass` is
2223  // replaced by the op's C++ class name.
2224  code extraClassDefinition = ?;
2225}
2226
2227// The arguments of an op.
2228class Arguments<dag args> {
2229  dag arguments = args;
2230}
2231
2232// The results of an op.
2233class Results<dag rets> {
2234  dag results = rets;
2235}
2236
2237//===----------------------------------------------------------------------===//
2238// Common op type constraints
2239//===----------------------------------------------------------------------===//
2240
2241// These traits are for verifying properties of an op that require knowledge of
2242// multiple arguments or results. For verifying properties of a single argument
2243// or result, prefer operand type constraints.
2244
2245// These traits often require including "mlir/IR/TypeUtilities.h".
2246
2247// TODO: Improve the autogenerated error messages.
2248
2249class Rank<string name> :
2250    StrFunc<"$" # name # ".getType().cast<::mlir::ShapedType>().getRank()">;
2251
2252class Shape<string name> :
2253    StrFunc<"$" # name # ".getType().cast<::mlir::ShapedType>().getShape()">;
2254
2255class ElementCount<string name> :
2256  StrFunc<"$" # name # ".getType().cast<::mlir::ShapedType>()"
2257                                 ".getNumElements()">;
2258
2259class ElementType<string name> : StrFunc<"getElementTypeOrSelf($" # name # ")">;
2260
2261class AllMatchPred<list<string> values> :
2262    CPred<"::llvm::is_splat(::llvm::makeArrayRef({"
2263          # !interleave(values, ", ") #"}))">;
2264
2265class AllMatch<list<string> values, string summary> :
2266    PredOpTrait<summary, AllMatchPred<values>>;
2267
2268// TODO: Only works for non-variadic.
2269class AllMatchSameOperatorPred<list<string> names, string operator> :
2270    AllMatchPred<!foreach(n, names, !subst("$_self", "$" # n, operator))>;
2271
2272class AllMatchSameOperatorTrait<list<string> names, string operator,
2273                                string summary> :
2274    PredOpTrait<
2275        "all of {" # !interleave(names, ", ") # "} have same " # summary,
2276        AllMatchSameOperatorPred<names, operator>> {
2277  list<string> values = names;
2278}
2279
2280class AllElementCountsMatch<list<string> names> :
2281    AllMatchSameOperatorTrait<names, ElementCount<"_self">.result,
2282                              "element count">;
2283
2284class AllElementTypesMatch<list<string> names> :
2285    AllMatchSameOperatorTrait<names, ElementType<"_self">.result,
2286                              "element type">;
2287
2288class AllRanksMatch<list<string> names> :
2289    AllMatchSameOperatorTrait<names, Rank<"_self">.result, "rank">;
2290
2291class AllShapesMatch<list<string> names> :
2292    AllMatchSameOperatorTrait<names, Shape<"_self">.result, "shape">;
2293
2294class AllTypesMatch<list<string> names> :
2295    AllMatchSameOperatorTrait<names, "$_self.getType()", "type">;
2296
2297// A type constraint that denotes `transform(lhs.getType()) == rhs.getType()`.
2298// An optional comparator function may be provided that changes the above form
2299// into: `comparator(transform(lhs.getType()), rhs.getType())`.
2300class TypesMatchWith<string summary, string lhsArg, string rhsArg,
2301                     string transform, string comparator = "std::equal_to<>()">
2302  : PredOpTrait<summary, CPred<
2303      comparator # "(" #
2304      !subst("$_self", "$" # lhsArg # ".getType()", transform) #
2305      ", $" # rhsArg # ".getType())">> {
2306  string lhs = lhsArg;
2307  string rhs = rhsArg;
2308  string transformer = transform;
2309}
2310
2311// Special variant of `TypesMatchWith` that provides a comparator suitable for
2312// ranged arguments.
2313class RangedTypesMatchWith<string summary, string lhsArg, string rhsArg,
2314                           string transform>
2315  : TypesMatchWith<summary, lhsArg, rhsArg, transform, "llvm::equal">;
2316
2317// Type Constraint operand `idx`'s Element type is `type`.
2318class TCopVTEtIs<int idx, Type type> : And<[
2319   CPred<"$_op.getNumOperands() > " # idx>,
2320   SubstLeaves<"$_self", "$_op.getOperand(" # idx # ").getType()",
2321     IsShapedTypePred>,
2322   SubstLeaves<"$_self", "getElementTypeOrSelf($_op.getOperand(" # idx # "))",
2323     type.predicate>]>;
2324
2325// Predicate to verify that a named argument or result's element type matches a
2326// given type.
2327class TypeIsPred<string name, Type type> :
2328   SubstLeaves<"$_self", "$" # name # ".getType()", type.predicate>;
2329class TypeIs<string name, Type type> : PredOpTrait<
2330  "'" # name # "' is " # type.summary, TypeIsPred<name, type>>;
2331
2332// Predicate to verify that a named argument or result's element type matches a
2333// given type.
2334class ElementTypeIsPred<string name, Type type> : And<[
2335   SubstLeaves<"$_self", "$" # name # ".getType()", IsShapedTypePred>,
2336   SubstLeaves<"$_self", "getElementTypeOrSelf($" # name # ")",
2337     type.predicate>]>;
2338class ElementTypeIs<string name, Type type> : PredOpTrait<
2339  "'" # name # "' is " # type.summary, ElementTypeIsPred<name, type>>;
2340
2341// Predicate to verify that the i'th operand and the j'th operand have the same
2342// elemental type.
2343// Type Constraint operand `i`'s Element type is Same As operand `j`'s Element
2344// type.
2345class TCopVTEtIsSameAs<int i, int j> : And<[
2346    CPred<"$_op.getNumOperands() > " # !if(!gt(i,j),i,j)>,
2347    SubstLeaves<"$_self", "$_op.getOperand(" # i # ").getType()",
2348      IsShapedTypePred>,
2349    SubstLeaves<"$_self", "$_op.getOperand(" # j # ").getType()",
2350      IsShapedTypePred>,
2351    CPred<"::mlir::getElementTypeOrSelf($_op.getOperand(" # i # ")) == "
2352          "::mlir::getElementTypeOrSelf($_op.getOperand(" # j # "))">]>;
2353
2354// Predicate to verify that the i'th result and the j'th operand exist and has
2355// shaped types.
2356class TCOpResIsShapedTypePred<int i, int j> : And<[
2357    CPred<"$_op.getNumResults() > " # i>,
2358    CPred<"$_op.getNumOperands() > " # j>,
2359    SubstLeaves<"$_self", "$_op.getResult(" # i # ").getType()",
2360      IsShapedTypePred>,
2361    SubstLeaves<"$_self", "$_op.getOperand(" # j # ").getType()",
2362      IsShapedTypePred>]>;
2363
2364// Predicate to verify that the i'th result and the j'th operand have the same
2365// type.
2366class TCresIsSameAsOpBase<int i, int j> :
2367    CPred<"$_op.getResult(" # i # ").getType() == "
2368          "$_op.getOperand(" # j # ").getType()">;
2369
2370// Basic Predicate to verify that the i'th result and the j'th operand have the
2371// same elemental type.
2372class TCresVTEtIsSameAsOpBase<int i, int j> :
2373    CPred<"getElementTypeOrSelf($_op.getResult(" # i # ")) == "
2374          "getElementTypeOrSelf($_op.getOperand(" # j # "))">;
2375
2376// Predicate to verify that the i'th result and the j'th operand have the same
2377// elemental type.
2378// Type Constraint result`i`'s Element type is Same As Operand `j`'s Element
2379// type.
2380class TCresVTEtIsSameAsOp<int i, int j> : And<[
2381    TCOpResIsShapedTypePred<i, j>,
2382    TCresVTEtIsSameAsOpBase<i, j>]>;
2383
2384// Predicate to verify that the opId'th operand can be broadcasted to the type
2385// of the resId'th result.
2386class TCOpIsBroadcastableToRes<int opId, int resId> : And<[
2387    TCOpResIsShapedTypePred<opId, resId>,
2388    CPred<"::mlir::OpTrait::util::getBroadcastedType("
2389                  "$_op.getOperand(" # opId # ").getType(), "
2390                  "$_op.getResult(" # resId # ").getType())">]>;
2391
2392// Predicate to verify that all the operands at the given `indices`
2393// have the same element type.
2394// Type Constraint operands' Element type are all Same At the given `indices`.
2395// We query the operands' types into a list and check they are all the same.
2396// Precondition:
2397// 1) all operands involved are of shaped type and
2398// 2) the indices are not out of range.
2399class TCopVTEtAreSameAt<list<int> indices> : CPred<
2400  "::llvm::is_splat(::llvm::map_range("
2401      "::mlir::ArrayRef<unsigned>({" # !interleave(indices, ", ") # "}), "
2402      "[this](unsigned i) { return getElementTypeOrSelf(this->getOperand(i)); "
2403      "}))">;
2404
2405#endif // OP_BASE
2406