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