diff --git a/flang/include/flang/Optimizer/Dialect/CanonicalizationPatterns.td b/flang/include/flang/Optimizer/Dialect/CanonicalizationPatterns.td --- a/flang/include/flang/Optimizer/Dialect/CanonicalizationPatterns.td +++ b/flang/include/flang/Optimizer/Dialect/CanonicalizationPatterns.td @@ -15,6 +15,7 @@ #define FORTRAN_FIR_REWRITE_PATTERNS include "mlir/IR/OpBase.td" +include "mlir/IR/PatternBase.td" include "mlir/Dialect/Arithmetic/IR/ArithmeticOps.td" include "mlir/Dialect/StandardOps/IR/Ops.td" include "flang/Optimizer/Dialect/FIROps.td" diff --git a/flang/include/flang/Optimizer/Dialect/FIRTypes.td b/flang/include/flang/Optimizer/Dialect/FIRTypes.td --- a/flang/include/flang/Optimizer/Dialect/FIRTypes.td +++ b/flang/include/flang/Optimizer/Dialect/FIRTypes.td @@ -13,6 +13,7 @@ #ifndef FIR_DIALECT_FIR_TYPES #define FIR_DIALECT_FIR_TYPES +include "mlir/IR/AttrTypeBase.td" include "flang/Optimizer/Dialect/FIRDialect.td" //===----------------------------------------------------------------------===// diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -1896,6 +1896,11 @@ std::vector getAllDerivedDefinitions( ArrayRef ClassNames) const; + /// Get all the concrete records that inherit from specified class, if the + /// class is defined. Returns an empty vector if the class is not defined. + std::vector + getAllDerivedDefinitionsIfDefined(StringRef ClassName) const; + void dump() const; }; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -2733,11 +2733,10 @@ } } -// We cache the record vectors for single classes. Many backends request -// the same vectors multiple times. -std::vector RecordKeeper::getAllDerivedDefinitions( - StringRef ClassName) const { - +std::vector +RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const { + // We cache the record vectors for single classes. Many backends request + // the same vectors multiple times. auto Pair = ClassRecordsMap.try_emplace(ClassName); if (Pair.second) Pair.first->second = getAllDerivedDefinitions(makeArrayRef(ClassName)); @@ -2768,6 +2767,12 @@ return Defs; } +std::vector +RecordKeeper::getAllDerivedDefinitionsIfDefined(StringRef ClassName) const { + return getClass(ClassName) ? getAllDerivedDefinitions(ClassName) + : std::vector(); +} + Init *MapResolver::resolve(Init *VarName) { auto It = Map.find(VarName); if (It == Map.end()) diff --git a/mlir/examples/toy/Ch3/mlir/ToyCombine.td b/mlir/examples/toy/Ch3/mlir/ToyCombine.td --- a/mlir/examples/toy/Ch3/mlir/ToyCombine.td +++ b/mlir/examples/toy/Ch3/mlir/ToyCombine.td @@ -14,6 +14,7 @@ #ifndef TOY_COMBINE #define TOY_COMBINE +include "mlir/IR/PatternBase.td" include "toy/Ops.td" /// Note: The DRR definition used for defining patterns is shown below: diff --git a/mlir/examples/toy/Ch4/mlir/ToyCombine.td b/mlir/examples/toy/Ch4/mlir/ToyCombine.td --- a/mlir/examples/toy/Ch4/mlir/ToyCombine.td +++ b/mlir/examples/toy/Ch4/mlir/ToyCombine.td @@ -14,6 +14,7 @@ #ifndef TOY_COMBINE #define TOY_COMBINE +include "mlir/IR/PatternBase.td" include "toy/Ops.td" /// Note: The DRR definition used for defining patterns is shown below: diff --git a/mlir/examples/toy/Ch5/mlir/ToyCombine.td b/mlir/examples/toy/Ch5/mlir/ToyCombine.td --- a/mlir/examples/toy/Ch5/mlir/ToyCombine.td +++ b/mlir/examples/toy/Ch5/mlir/ToyCombine.td @@ -14,6 +14,7 @@ #ifndef TOY_COMBINE #define TOY_COMBINE +include "mlir/IR/PatternBase.td" include "toy/Ops.td" /// Note: The DRR definition used for defining patterns is shown below: diff --git a/mlir/examples/toy/Ch6/mlir/ToyCombine.td b/mlir/examples/toy/Ch6/mlir/ToyCombine.td --- a/mlir/examples/toy/Ch6/mlir/ToyCombine.td +++ b/mlir/examples/toy/Ch6/mlir/ToyCombine.td @@ -14,6 +14,7 @@ #ifndef TOY_COMBINE #define TOY_COMBINE +include "mlir/IR/PatternBase.td" include "toy/Ops.td" /// Note: The DRR definition used for defining patterns is shown below: diff --git a/mlir/examples/toy/Ch7/mlir/ToyCombine.td b/mlir/examples/toy/Ch7/mlir/ToyCombine.td --- a/mlir/examples/toy/Ch7/mlir/ToyCombine.td +++ b/mlir/examples/toy/Ch7/mlir/ToyCombine.td @@ -14,6 +14,7 @@ #ifndef TOY_COMBINE #define TOY_COMBINE +include "mlir/IR/PatternBase.td" include "toy/Ops.td" /// Note: The DRR definition used for defining patterns is shown below: diff --git a/mlir/include/mlir/Dialect/Async/IR/AsyncTypes.td b/mlir/include/mlir/Dialect/Async/IR/AsyncTypes.td --- a/mlir/include/mlir/Dialect/Async/IR/AsyncTypes.td +++ b/mlir/include/mlir/Dialect/Async/IR/AsyncTypes.td @@ -13,6 +13,7 @@ #ifndef MLIR_DIALECT_ASYNC_IR_ASYNCTYPES #define MLIR_DIALECT_ASYNC_IR_ASYNCTYPES +include "mlir/IR/AttrTypeBase.td" include "mlir/Dialect/Async/IR/AsyncDialect.td" //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCAttributes.td @@ -13,6 +13,7 @@ #ifndef MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES #define MLIR_DIALECT_EMITC_IR_EMITCATTRIBUTES +include "mlir/IR/AttrTypeBase.td" include "mlir/Dialect/EmitC/IR/EmitCBase.td" //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td --- a/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td +++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitCTypes.td @@ -14,6 +14,7 @@ #ifndef MLIR_DIALECT_EMITC_IR_EMITCTYPES #define MLIR_DIALECT_EMITC_IR_EMITCTYPES +include "mlir/IR/AttrTypeBase.td" include "mlir/Dialect/EmitC/IR/EmitCBase.td" //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -9,9 +9,9 @@ #ifndef LLVMIR_ATTRDEFS #define LLVMIR_ATTRDEFS +include "mlir/IR/AttrTypeBase.td" include "mlir/Dialect/LLVMIR/LLVMOpBase.td" - // All of the attributes will extend this class. class LLVM_Attr : AttrDef; diff --git a/mlir/include/mlir/Dialect/PDL/IR/PDLTypes.td b/mlir/include/mlir/Dialect/PDL/IR/PDLTypes.td --- a/mlir/include/mlir/Dialect/PDL/IR/PDLTypes.td +++ b/mlir/include/mlir/Dialect/PDL/IR/PDLTypes.td @@ -13,6 +13,7 @@ #ifndef MLIR_DIALECT_PDL_IR_PDLTYPES #define MLIR_DIALECT_PDL_IR_PDLTYPES +include "mlir/IR/AttrTypeBase.td" include "mlir/Dialect/PDL/IR/PDLDialect.td" //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.td b/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.td --- a/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.td +++ b/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.td @@ -9,6 +9,7 @@ #ifndef SPARSETENSOR_ATTRDEFS #define SPARSETENSOR_ATTRDEFS +include "mlir/IR/AttrTypeBase.td" include "mlir/Dialect/SparseTensor/IR/SparseTensorBase.td" include "mlir/IR/TensorEncoding.td" diff --git a/mlir/include/mlir/IR/AttrTypeBase.td b/mlir/include/mlir/IR/AttrTypeBase.td new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/IR/AttrTypeBase.td @@ -0,0 +1,387 @@ +//===-- AttrTypeBase.td - Base Attr/Type definition file ---*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains the base set of constructs for defining Attribute and +// Type classes. +// +//===----------------------------------------------------------------------===// + +#ifndef ATTRTYPEBASE_TD +#define ATTRTYPEBASE_TD + +include "mlir/IR/OpBase.td" + +//-------------------------------------------------------------------------===// +// AttrTrait definitions +//===----------------------------------------------------------------------===// + +// These classes are used to define attribute specific traits. +class NativeAttrTrait : NativeTrait; +class ParamNativeAttrTrait + : ParamNativeTrait; +class GenInternalAttrTrait : GenInternalTrait; +class PredAttrTrait : PredTrait; + +//===----------------------------------------------------------------------===// +// TypeTrait definitions +//===----------------------------------------------------------------------===// + +// These classes are used to define type specific traits. +class NativeTypeTrait : NativeTrait; +class ParamNativeTypeTrait + : ParamNativeTrait; +class GenInternalTypeTrait : GenInternalTrait; +class PredTypeTrait : PredTrait; + +//===----------------------------------------------------------------------===// +// Builders +//===----------------------------------------------------------------------===// + +// Class for defining a custom getter. +// +// TableGen generates several generic getter methods for each attribute and type +// by default, corresponding to the specified dag parameters. If the default +// generated ones cannot cover some use case, custom getters can be defined +// using instances of this class. +// +// The signature of the `get` is always either: +// +// ```c++ +// static get(MLIRContext *context, ...) { +// ... +// } +// ``` +// +// or: +// +// ```c++ +// static get(MLIRContext *context, ...); +// ``` +// +// To define a custom getter, the parameter list and body should be passed +// in as separate template arguments to this class. The parameter list is a +// TableGen DAG with `ins` operation with named arguments, which has either: +// - string initializers ("Type":$name) to represent a typed parameter, or +// - CArg-typed initializers (CArg<"Type", "default">:$name) to represent a +// typed parameter that may have a default value. +// The type string is used verbatim to produce code and, therefore, must be a +// valid C++ type. It is used inside the C++ namespace of the parent Type's +// dialect; explicit namespace qualification like `::mlir` may be necessary if +// Types are not placed inside the `mlir` namespace. The default value string is +// used verbatim to produce code and must be a valid C++ initializer the given +// type. For example, the following signature specification +// +// ``` +// AttrOrTypeBuilder<(ins "int":$integerArg, CArg<"float", "3.0f">:$floatArg)> +// ``` +// +// has an integer parameter and a float parameter with a default value. +// +// If an empty string is passed in for `body`, then *only* the builder +// declaration will be generated; this provides a way to define complicated +// builders entirely in C++. If a `body` string is provided, the `Base::get` +// method should be invoked using `$_get`, e.g.: +// +// ``` +// AttrOrTypeBuilder<(ins "int":$integerArg, CArg<"float", "3.0f">:$floatArg), [{ +// return $_get($_ctxt, integerArg, floatArg); +// }]> +// ``` +// +// This is necessary because the `body` is also used to generate `getChecked` +// methods, which have a different underlying `Base::get*` call. +// +class AttrOrTypeBuilder { + dag dagParams = parameters; + code body = bodyCode; + + // The context parameter can be inferred from one of the other parameters and + // is not implicitly added to the parameter list. + bit hasInferredContextParam = 0; +} +class AttrBuilder + : AttrOrTypeBuilder; +class TypeBuilder + : AttrOrTypeBuilder; + +// A class of AttrOrTypeBuilder that is able to infer the MLIRContext parameter +// from one of the other builder parameters. Instances of this builder do not +// have `MLIRContext *` implicitly added to the parameter list. +class AttrOrTypeBuilderWithInferredContext + : TypeBuilder { + let hasInferredContextParam = 1; +} +class AttrBuilderWithInferredContext + : AttrOrTypeBuilderWithInferredContext; +class TypeBuilderWithInferredContext + : AttrOrTypeBuilderWithInferredContext; + +//===----------------------------------------------------------------------===// +// Definitions +//===----------------------------------------------------------------------===// + +// Define a new attribute or type, named `name`, that inherits from the given +// C++ base class. +class AttrOrTypeDef defTraits, + string baseCppClass> { + // The name of the C++ base class to use for this def. + string cppBaseClassName = baseCppClass; + + // Additional, longer human-readable description of what the def does. + string description = ""; + + // Name of storage class to generate or use. + string storageClass = name # valueType # "Storage"; + + // Namespace (withing dialect c++ namespace) in which the storage class + // resides. + string storageNamespace = "detail"; + + // Specify if the storage class is to be generated. + bit genStorageClass = 1; + + // Specify that the generated storage class has a constructor which is written + // in C++. + bit hasStorageCustomConstructor = 0; + + // The list of parameters for this type. Parameters will become both + // parameters to the get() method and storage class member variables. + // + // The format of this dag is: + // (ins + // "":$param1Name, + // "":$param2Name, + // AttrOrTypeParameter<"c++ type", "param description">:$param3Name) + // AttrOrTypeParameters (or more likely one of their subclasses) are required + // to add more information about the parameter, specifically: + // - Documentation + // - Code to allocate the parameter (if allocation is needed in the storage + // class constructor) + // + // For example: + // (ins "int":$width, + // ArrayRefParameter<"bool", "list of bools">:$yesNoArray) + // + // (ArrayRefParameter is a subclass of AttrOrTypeParameter which has + // allocation code for re-allocating ArrayRefs. It is defined below.) + dag parameters = (ins); + + // Custom builder methods. + // In addition to the custom builders provided here, and unless + // skipDefaultBuilders is set, a default builder is generated with the + // following signature: + // + // ```c++ + // static get(MLIRContext *, ); + // ``` + // + // Note that builders should only be provided when a def has parameters. + list builders = ?; + + // The list of traits attached to this def. + list traits = defTraits; + + // Use the lowercased name as the keyword for parsing/printing. Specify only + // if you want tblgen to generate declarations and/or definitions of + // the printer/parser. + string mnemonic = ?; + + // If 'mnemonic' specified, + // If null, generate just the declarations. + // If a non-empty code block, just use that code as the definition code. + // Error if an empty code block. + code printer = ?; + code parser = ?; + + // Custom assembly format. Requires 'mnemonic' to be specified. Cannot be + // specified at the same time as either 'printer' or 'parser'. The generated + // printer requires 'genAccessors' to be true. + string assemblyFormat = ?; + + // If set, generate accessors for each parameter. + bit genAccessors = 1; + + // Avoid generating default get/getChecked functions. Custom get methods must + // be provided. + bit skipDefaultBuilders = 0; + + // Generate the verify and getChecked methods. + bit genVerifyDecl = 0; + + // Extra code to include in the class declaration. + code extraClassDeclaration = [{}]; +} + +// Define a new attribute, named `name`, belonging to `dialect` that inherits +// from the given C++ base class. +class AttrDef traits = [], + string baseCppClass = "::mlir::Attribute"> + : DialectAttr, /*descr*/"">, + AttrOrTypeDef<"Attr", name, traits, baseCppClass> { + // The name of the C++ Attribute class. + string cppClassName = name # "Attr"; + let storageType = dialect.cppNamespace # "::" # name # "Attr"; + + // The underlying C++ value type + let returnType = dialect.cppNamespace # "::" # cppClassName; + + // Make it possible to use such attributes as parameters for other attributes. + string cppType = dialect.cppNamespace # "::" # cppClassName; + + // The call expression to convert from the storage type to the return + // type. For example, an enum can be stored as an int but returned as an + // enum class. + // + // Format: $_self will be expanded to the attribute. + // + // For example, `$_self.getValue().getSExtValue()` for `IntegerAttr val` will + // expand to `getAttrOfType("val").getValue().getSExtValue()`. + let convertFromStorage = "$_self.cast<" # dialect.cppNamespace # + "::" # cppClassName # ">()"; + + // A code block used to build the value 'Type' of an Attribute when + // initializing its storage instance. This field is optional, and if not + // present the attribute will have its value type set to `NoneType`. This code + // block may reference any of the attributes parameters via + // `$_()">; +} + +// Define a new type, named `name`, belonging to `dialect` that inherits from +// the given C++ base class. +class TypeDef traits = [], + string baseCppClass = "::mlir::Type"> + : DialectType, /*descr*/"", name # "Type">, + AttrOrTypeDef<"Type", name, traits, baseCppClass> { + // Make it possible to use such type as parameters for other types. + string cppType = dialect.cppNamespace # "::" # cppClassName; + + // A constant builder provided when the type has no parameters. + let builderCall = !if(!empty(parameters), + "$_builder.getType<" # dialect.cppNamespace # + "::" # cppClassName # ">()", + ""); + // The predicate for when this def is used as a constraint. + let predicate = CPred<"$_self.isa<" # dialect.cppNamespace # + "::" # cppClassName # ">()">; +} + +//===----------------------------------------------------------------------===// +// Parameters +//===----------------------------------------------------------------------===// + +// 'Parameters' should be subclasses of this or simple strings (which is a +// shorthand for AttrOrTypeParameter<"C++Type">). +class AttrOrTypeParameter { + // Custom memory allocation code for storage constructor. + code allocator = ?; + // Comparator used to compare two instances for equality. By default, it uses + // the C++ equality operator. + code comparator = ?; + // The C++ type of this parameter. + string cppType = type; + // The C++ type of the accessor for this parameter. + string cppAccessorType = !if(!empty(accessorType), type, accessorType); + // The C++ storage type of of this parameter if it is a reference, e.g. + // `std::string` for `StringRef` or `SmallVector` for `ArrayRef`. + string cppStorageType = ?; + // One-line human-readable description of the argument. + string summary = desc; + // The format string for the asm syntax (documentation only). + string syntax = ?; + // The default parameter parser is `::mlir::FieldParser::parse($_parser)`, + // which returns `FailureOr`. Specialize `FieldParser` to support parsing + // for your type. Or you can provide a customer printer. For attributes, + // "$_type" will be replaced with the required attribute type. + string parser = ?; + // The default parameter printer is `$_printer << $_self`. Overload the stream + // operator of `AsmPrinter` as necessary to print your type. Or you can + // provide a custom printer. + string printer = ?; + // Mark a parameter as optional. The C++ type of parameters marked as optional + // must be default constructible and be contextually convertible to `bool`. + // Any `Optional` and any attribute type satisfies these requirements. + bit isOptional = 0; + // Provide a default value for the parameter. Parameters with default values + // are considered optional. If a value was not parsed for the parameter, it + // will be set to the default value. Parameters equal to their default values + // are elided when printing. Equality is checked using the `comparator` field, + // which by default is the C++ equality operator. The current MLIR context is + // made available through `$_ctx`, e.g., for constructing default values for + // attributes and types. + string defaultValue = ?; +} +class AttrParameter + : AttrOrTypeParameter; +class TypeParameter + : AttrOrTypeParameter; + +// For StringRefs, which require allocation. +class StringRefParameter : + AttrOrTypeParameter<"::llvm::StringRef", desc> { + let allocator = [{$_dst = $_allocator.copyInto($_self);}]; + let printer = [{$_printer << '"' << $_self << '"';}]; + let cppStorageType = "std::string"; +} + +// For APFloats, which require comparison. +class APFloatParameter : + AttrOrTypeParameter<"::llvm::APFloat", desc> { + let comparator = "$_lhs.bitwiseIsEqual($_rhs)"; +} + +// For standard ArrayRefs, which require allocation. +class ArrayRefParameter : + AttrOrTypeParameter<"::llvm::ArrayRef<" # arrayOf # ">", desc> { + let allocator = [{$_dst = $_allocator.copyInto($_self);}]; + let cppStorageType = "::llvm::SmallVector<" # arrayOf # ">"; +} + +// For classes which require allocation and have their own allocateInto method. +class SelfAllocationParameter : + AttrOrTypeParameter { + let allocator = [{$_dst = $_self.allocateInto($_allocator);}]; +} + +// For ArrayRefs which contain things which allocate themselves. +class ArrayRefOfSelfAllocationParameter : + AttrOrTypeParameter<"::llvm::ArrayRef<" # arrayOf # ">", desc> { + let allocator = [{ + llvm::SmallVector<}] # arrayOf # [{, 4> tmpFields; + for (size_t i = 0, e = $_self.size(); i < e; ++i) + tmpFields.push_back($_self[i].allocateInto($_allocator)); + $_dst = $_allocator.copyInto(ArrayRef<}] # arrayOf # [{>(tmpFields)); + }]; +} + +// An optional parameter. +class OptionalParameter : + AttrOrTypeParameter { + let isOptional = 1; +} + +// A parameter with a default value. +class DefaultValuedParameter : + AttrOrTypeParameter { + let isOptional = 1; + let defaultValue = value; +} + +// This is a special parameter used for AttrDefs that represents a `mlir::Type` +// that is also used as the value `Type` of the attribute. Only one parameter +// of the attribute may be of this type. +class AttributeSelfTypeParameter : + AttrOrTypeParameter {} + +#endif // ATTRTYPEBASE_TD diff --git a/mlir/include/mlir/IR/BuiltinAttributes.td b/mlir/include/mlir/IR/BuiltinAttributes.td --- a/mlir/include/mlir/IR/BuiltinAttributes.td +++ b/mlir/include/mlir/IR/BuiltinAttributes.td @@ -14,6 +14,7 @@ #ifndef BUILTIN_ATTRIBUTES #define BUILTIN_ATTRIBUTES +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/BuiltinDialect.td" include "mlir/IR/BuiltinAttributeInterfaces.td" include "mlir/IR/SubElementInterfaces.td" diff --git a/mlir/include/mlir/IR/BuiltinLocationAttributes.td b/mlir/include/mlir/IR/BuiltinLocationAttributes.td --- a/mlir/include/mlir/IR/BuiltinLocationAttributes.td +++ b/mlir/include/mlir/IR/BuiltinLocationAttributes.td @@ -13,6 +13,7 @@ #ifndef BUILTIN_LOCATION_ATTRIBUTES_TD #define BUILTIN_LOCATION_ATTRIBUTES_TD +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/BuiltinDialect.td" // Base class for Builtin dialect location attributes. diff --git a/mlir/include/mlir/IR/BuiltinTypes.td b/mlir/include/mlir/IR/BuiltinTypes.td --- a/mlir/include/mlir/IR/BuiltinTypes.td +++ b/mlir/include/mlir/IR/BuiltinTypes.td @@ -14,6 +14,7 @@ #ifndef BUILTIN_TYPES #define BUILTIN_TYPES +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/BuiltinDialect.td" include "mlir/IR/BuiltinTypeInterfaces.td" include "mlir/IR/SubElementInterfaces.td" diff --git a/mlir/include/mlir/IR/EnumAttr.td b/mlir/include/mlir/IR/EnumAttr.td --- a/mlir/include/mlir/IR/EnumAttr.td +++ b/mlir/include/mlir/IR/EnumAttr.td @@ -6,10 +6,10 @@ // //===----------------------------------------------------------------------===// -#ifndef ENUM_ATTR -#define ENUM_ATTR +#ifndef ENUMATTR_TD +#define ENUMATTR_TD -include "mlir/IR/OpBase.td" +include "mlir/IR/AttrTypeBase.td" // A C++ enum as an attribute parameter. The parameter implements a parser and // printer for the enum by dispatching calls to `stringToSymbol` and @@ -93,4 +93,4 @@ let assemblyFormat = "$value"; } -#endif // ENUM_ATTR +#endif // ENUMATTR_TD diff --git a/mlir/include/mlir/IR/OpBase.td b/mlir/include/mlir/IR/OpBase.td --- a/mlir/include/mlir/IR/OpBase.td +++ b/mlir/include/mlir/IR/OpBase.td @@ -1997,28 +1997,6 @@ Pred predicate = pred; } -//===----------------------------------------------------------------------===// -// TypeTrait definitions -//===----------------------------------------------------------------------===// - -// These classes are used to define type specific traits. -class NativeTypeTrait : NativeTrait; -class ParamNativeTypeTrait - : ParamNativeTrait; -class GenInternalTypeTrait : GenInternalTrait; -class PredTypeTrait : PredTrait; - -//===----------------------------------------------------------------------===// -// AttrTrait definitions -//===----------------------------------------------------------------------===// - -// These classes are used to define attribute specific traits. -class NativeAttrTrait : NativeTrait; -class ParamNativeAttrTrait - : ParamNativeTrait; -class GenInternalAttrTrait : GenInternalTrait; -class PredAttrTrait : PredTrait; - //===----------------------------------------------------------------------===// // OpTrait definitions //===----------------------------------------------------------------------===// @@ -2507,13 +2485,6 @@ dag results = rets; } -//===----------------------------------------------------------------------===// -// Common value constraints -//===----------------------------------------------------------------------===// - -def HasNoUseOf: Constraint< - CPred<"$_self.use_empty()">, "has no use">; - //===----------------------------------------------------------------------===// // Common op type constraints //===----------------------------------------------------------------------===// @@ -2682,538 +2653,4 @@ "[this](unsigned i) { return getElementTypeOrSelf(this->getOperand(i)); " "}))">; -//===----------------------------------------------------------------------===// -// Pattern definitions -//===----------------------------------------------------------------------===// - -// Marker used to identify the delta value added to the default benefit value. -def addBenefit; - -// Base class for op+ -> op+ rewrite rules. These allow declaratively -// specifying rewrite rules. -// -// A rewrite rule contains two components: a source pattern and one or more -// result patterns. Each pattern is specified as a (recursive) DAG node (tree) -// in the form of `(node arg0, arg1, ...)`. -// -// The `node` are normally MLIR ops, but it can also be one of the directives -// listed later in this section. -// -// ## Symbol binding -// -// In the source pattern, `argN` can be used to specify matchers (e.g., using -// type/attribute type constraints, etc.) and bound to a name for later use. -// We can also bind names to op instances to reference them later in -// multi-entity constraints. Operands in the source pattern can have -// the same name. This bounds one operand to the name while verifying -// the rest are all equal. -// -// -// In the result pattern, `argN` can be used to refer to a previously bound -// name, with potential transformations (e.g., using tAttr, etc.). `argN` can -// itself be nested DAG node. We can also bound names to ops to reference -// them later in other result patterns. -// -// For example, -// -// ``` -// def : Pattern<(OneResultOp1:$op1 $arg0, $arg1, $arg0), -// [(OneResultOp2:$op2 $arg0, $arg1), -// (OneResultOp3 $op2 (OneResultOp4))], -// [(HasStaticShapePred $op1)]>; -// ``` -// -// First `$arg0` and '$arg1' are bound to the `OneResultOp1`'s first -// and second arguments and used later to build `OneResultOp2`. Second '$arg0' -// is verified to be equal to the first '$arg0' operand. -// `$op1` is bound to `OneResultOp1` and used to check whether the result's -// shape is static. `$op2` is bound to `OneResultOp2` and used to -// build `OneResultOp3`. -// -// ## Multi-result op -// -// To create multi-result ops in result pattern, you can use a syntax similar -// to uni-result op, and it will act as a value pack for all results: -// -// ``` -// def : Pattern<(ThreeResultOp ...), -// [(TwoResultOp ...), (OneResultOp ...)]>; -// ``` -// -// Then `TwoResultOp` will replace the first two values of `ThreeResultOp`. -// -// You can also use `$__N` to explicitly access the N-th result. -// ``` -// def : Pattern<(FiveResultOp ...), -// [(TwoResultOp1:$res1__1 ...), (replaceWithValue $res1__0), -// (TwoResultOp2:$res2 ...), (replaceWithValue $res2__1)]>; -// ``` -// -// Then the values generated by `FiveResultOp` will be replaced by -// -// * `FiveResultOp`#0: `TwoResultOp1`#1 -// * `FiveResultOp`#1: `TwoResultOp1`#0 -// * `FiveResultOp`#2: `TwoResultOp2`#0 -// * `FiveResultOp`#3: `TwoResultOp2`#1 -// * `FiveResultOp`#4: `TwoResultOp2`#1 -class Pattern results, list preds = [], - dag benefitAdded = (addBenefit 0)> { - dag sourcePattern = source; - // Result patterns. Each result pattern is expected to replace one result - // of the root op in the source pattern. In the case of more result patterns - // than needed to replace the source op, only the last N results generated - // by the last N result pattern is used to replace a N-result source op. - // So that the beginning result patterns can be used to generate additional - // ops to aid building the results used for replacement. - list resultPatterns = results; - // Multi-entity constraints. Each constraint here involves multiple entities - // matched in source pattern and places further constraints on them as a - // whole. - list constraints = preds; - // The delta value added to the default benefit value. The default value is - // the number of ops in the source pattern. The rule with the highest final - // benefit value will be applied first if there are multiple rules matches. - // This delta value can be either positive or negative. - dag benefitDelta = benefitAdded; -} - -// Form of a pattern which produces a single result. -class Pat preds = [], - dag benefitAdded = (addBenefit 0)> : - Pattern; - -// Native code call wrapper. This allows invoking an arbitrary C++ expression -// to create an op operand/attribute or replace an op result. -// -// ## Placeholders -// -// If used as a DAG leaf, i.e., `(... NativeCodeCall<"...">:$arg, ...)`, -// the wrapped expression can take special placeholders listed below: -// -// * `$_builder` will be replaced by the current `mlir::PatternRewriter`. -// * `$_self` will be replaced by the defining operation in a source pattern. -// E.g., `NativeCodeCall<"Foo($_self, &$0)> I32Attr:$attr)>`, `$_self` will be -// replaced with the defining operation of the first operand of OneArgOp. -// -// If used as a DAG node, i.e., `(NativeCodeCall<"..."> , ..., )`, -// then positional placeholders are also supported; placeholder `$N` in the -// wrapped C++ expression will be replaced by ``. -// -// ## Bind multiple results -// -// To bind multi-results and access the N-th result with `$__N`, specify -// the number of return values in the template. Note that only `Value` type is -// supported for multiple results binding. - -class NativeCodeCall { - string expression = expr; - int numReturns = returns; -} - -class NativeCodeCallVoid : NativeCodeCall; - -def ConstantLikeMatcher : NativeCodeCall<"::mlir::success(" - "::mlir::matchPattern($_self->getResult(0), ::mlir::m_Constant(&$0)))">; - -//===----------------------------------------------------------------------===// -// Rewrite directives -//===----------------------------------------------------------------------===// - -// Directive used in result pattern to indicate that no new op are generated, -// so to replace the matched DAG with an existing SSA value. -def replaceWithValue; - -// Directive used in result patterns to specify the location of the generated -// op. This directive must be used as a trailing argument to op creation or -// native code calls. -// -// Usage: -// * Create a named location: `(location "myLocation")` -// * Copy the location of a captured symbol: `(location $arg)` -// * Create a fused location: `(location "metadata", $arg0, $arg1)` - -def location; - -// Directive used in result patterns to specify return types for a created op. -// This allows ops to be created without relying on type inference with -// `OpTraits` or an op builder with deduction. -// -// This directive must be used as a trailing argument to op creation. -// -// Specify one return type with a string literal: -// -// ``` -// (AnOp $val, (returnType "$_builder.getI32Type()")) -// ``` -// -// Pass a captured value to copy its return type: -// -// ``` -// (AnOp $val, (returnType $val)); -// ``` -// -// Pass a native code call inside a DAG to create a new type with arguments. -// -// ``` -// (AnOp $val, -// (returnType (NativeCodeCall<"$_builder.getTupleType({$0})"> $val))); -// ``` -// -// Specify multiple return types with multiple of any of the above. - -def returnType; - -// Directive used to specify the operands may be matched in either order. When -// two adjacents are marked with `either`, it'll try to match the operands in -// either ordering of constraints. Example: -// -// ``` -// (TwoArgOp (either $firstArg, (AnOp $secondArg))) -// ``` -// The above pattern will accept either `"test.TwoArgOp"(%I32Arg, %AnOpArg)` and -// `"test.TwoArgOp"(%AnOpArg, %I32Arg)`. -// -// Only operand is supported with `either` and note that an operation with -// `Commutative` trait doesn't imply that it'll have the same behavior than -// `either` while pattern matching. -def either; - -//===----------------------------------------------------------------------===// -// Attribute and Type generation -//===----------------------------------------------------------------------===// - -// Class for defining a custom getter. -// -// TableGen generates several generic getter methods for each attribute and type -// by default, corresponding to the specified dag parameters. If the default -// generated ones cannot cover some use case, custom getters can be defined -// using instances of this class. -// -// The signature of the `get` is always either: -// -// ```c++ -// static get(MLIRContext *context, ...) { -// ... -// } -// ``` -// -// or: -// -// ```c++ -// static get(MLIRContext *context, ...); -// ``` -// -// To define a custom getter, the parameter list and body should be passed -// in as separate template arguments to this class. The parameter list is a -// TableGen DAG with `ins` operation with named arguments, which has either: -// - string initializers ("Type":$name) to represent a typed parameter, or -// - CArg-typed initializers (CArg<"Type", "default">:$name) to represent a -// typed parameter that may have a default value. -// The type string is used verbatim to produce code and, therefore, must be a -// valid C++ type. It is used inside the C++ namespace of the parent Type's -// dialect; explicit namespace qualification like `::mlir` may be necessary if -// Types are not placed inside the `mlir` namespace. The default value string is -// used verbatim to produce code and must be a valid C++ initializer the given -// type. For example, the following signature specification -// -// ``` -// AttrOrTypeBuilder<(ins "int":$integerArg, CArg<"float", "3.0f">:$floatArg)> -// ``` -// -// has an integer parameter and a float parameter with a default value. -// -// If an empty string is passed in for `body`, then *only* the builder -// declaration will be generated; this provides a way to define complicated -// builders entirely in C++. If a `body` string is provided, the `Base::get` -// method should be invoked using `$_get`, e.g.: -// -// ``` -// AttrOrTypeBuilder<(ins "int":$integerArg, CArg<"float", "3.0f">:$floatArg), [{ -// return $_get($_ctxt, integerArg, floatArg); -// }]> -// ``` -// -// This is necessary because the `body` is also used to generate `getChecked` -// methods, which have a different underlying `Base::get*` call. -// -class AttrOrTypeBuilder { - dag dagParams = parameters; - code body = bodyCode; - - // The context parameter can be inferred from one of the other parameters and - // is not implicitly added to the parameter list. - bit hasInferredContextParam = 0; -} -class AttrBuilder - : AttrOrTypeBuilder; -class TypeBuilder - : AttrOrTypeBuilder; - -// A class of AttrOrTypeBuilder that is able to infer the MLIRContext parameter -// from one of the other builder parameters. Instances of this builder do not -// have `MLIRContext *` implicitly added to the parameter list. -class AttrOrTypeBuilderWithInferredContext - : TypeBuilder { - let hasInferredContextParam = 1; -} -class AttrBuilderWithInferredContext - : AttrOrTypeBuilderWithInferredContext; -class TypeBuilderWithInferredContext - : AttrOrTypeBuilderWithInferredContext; - -// Define a new attribute or type, named `name`, that inherits from the given -// C++ base class. -class AttrOrTypeDef defTraits, - string baseCppClass> { - // The name of the C++ base class to use for this def. - string cppBaseClassName = baseCppClass; - - // Additional, longer human-readable description of what the def does. - string description = ""; - - // Name of storage class to generate or use. - string storageClass = name # valueType # "Storage"; - - // Namespace (withing dialect c++ namespace) in which the storage class - // resides. - string storageNamespace = "detail"; - - // Specify if the storage class is to be generated. - bit genStorageClass = 1; - - // Specify that the generated storage class has a constructor which is written - // in C++. - bit hasStorageCustomConstructor = 0; - - // The list of parameters for this type. Parameters will become both - // parameters to the get() method and storage class member variables. - // - // The format of this dag is: - // (ins - // "":$param1Name, - // "":$param2Name, - // AttrOrTypeParameter<"c++ type", "param description">:$param3Name) - // AttrOrTypeParameters (or more likely one of their subclasses) are required - // to add more information about the parameter, specifically: - // - Documentation - // - Code to allocate the parameter (if allocation is needed in the storage - // class constructor) - // - // For example: - // (ins "int":$width, - // ArrayRefParameter<"bool", "list of bools">:$yesNoArray) - // - // (ArrayRefParameter is a subclass of AttrOrTypeParameter which has - // allocation code for re-allocating ArrayRefs. It is defined below.) - dag parameters = (ins); - - // Custom builder methods. - // In addition to the custom builders provided here, and unless - // skipDefaultBuilders is set, a default builder is generated with the - // following signature: - // - // ```c++ - // static get(MLIRContext *, ); - // ``` - // - // Note that builders should only be provided when a def has parameters. - list builders = ?; - - // The list of traits attached to this def. - list traits = defTraits; - - // Use the lowercased name as the keyword for parsing/printing. Specify only - // if you want tblgen to generate declarations and/or definitions of - // the printer/parser. - string mnemonic = ?; - - // If 'mnemonic' specified, - // If null, generate just the declarations. - // If a non-empty code block, just use that code as the definition code. - // Error if an empty code block. - code printer = ?; - code parser = ?; - - // Custom assembly format. Requires 'mnemonic' to be specified. Cannot be - // specified at the same time as either 'printer' or 'parser'. The generated - // printer requires 'genAccessors' to be true. - string assemblyFormat = ?; - - // If set, generate accessors for each parameter. - bit genAccessors = 1; - - // Avoid generating default get/getChecked functions. Custom get methods must - // be provided. - bit skipDefaultBuilders = 0; - - // Generate the verify and getChecked methods. - bit genVerifyDecl = 0; - - // Extra code to include in the class declaration. - code extraClassDeclaration = [{}]; -} - -// Define a new attribute, named `name`, belonging to `dialect` that inherits -// from the given C++ base class. -class AttrDef traits = [], - string baseCppClass = "::mlir::Attribute"> - : DialectAttr, /*descr*/"">, - AttrOrTypeDef<"Attr", name, traits, baseCppClass> { - // The name of the C++ Attribute class. - string cppClassName = name # "Attr"; - let storageType = dialect.cppNamespace # "::" # name # "Attr"; - - // The underlying C++ value type - let returnType = dialect.cppNamespace # "::" # cppClassName; - - // Make it possible to use such attributes as parameters for other attributes. - string cppType = dialect.cppNamespace # "::" # cppClassName; - - // The call expression to convert from the storage type to the return - // type. For example, an enum can be stored as an int but returned as an - // enum class. - // - // Format: $_self will be expanded to the attribute. - // - // For example, `$_self.getValue().getSExtValue()` for `IntegerAttr val` will - // expand to `getAttrOfType("val").getValue().getSExtValue()`. - let convertFromStorage = "$_self.cast<" # dialect.cppNamespace # - "::" # cppClassName # ">()"; - - // A code block used to build the value 'Type' of an Attribute when - // initializing its storage instance. This field is optional, and if not - // present the attribute will have its value type set to `NoneType`. This code - // block may reference any of the attributes parameters via - // `$_()">; -} - -// Define a new type, named `name`, belonging to `dialect` that inherits from -// the given C++ base class. -class TypeDef traits = [], - string baseCppClass = "::mlir::Type"> - : DialectType, /*descr*/"", name # "Type">, - AttrOrTypeDef<"Type", name, traits, baseCppClass> { - // Make it possible to use such type as parameters for other types. - string cppType = dialect.cppNamespace # "::" # cppClassName; - - // A constant builder provided when the type has no parameters. - let builderCall = !if(!empty(parameters), - "$_builder.getType<" # dialect.cppNamespace # - "::" # cppClassName # ">()", - ""); - // The predicate for when this def is used as a constraint. - let predicate = CPred<"$_self.isa<" # dialect.cppNamespace # - "::" # cppClassName # ">()">; -} - -// 'Parameters' should be subclasses of this or simple strings (which is a -// shorthand for AttrOrTypeParameter<"C++Type">). -class AttrOrTypeParameter { - // Custom memory allocation code for storage constructor. - code allocator = ?; - // Comparator used to compare two instances for equality. By default, it uses - // the C++ equality operator. - code comparator = ?; - // The C++ type of this parameter. - string cppType = type; - // The C++ type of the accessor for this parameter. - string cppAccessorType = !if(!empty(accessorType), type, accessorType); - // The C++ storage type of of this parameter if it is a reference, e.g. - // `std::string` for `StringRef` or `SmallVector` for `ArrayRef`. - string cppStorageType = ?; - // One-line human-readable description of the argument. - string summary = desc; - // The format string for the asm syntax (documentation only). - string syntax = ?; - // The default parameter parser is `::mlir::FieldParser::parse($_parser)`, - // which returns `FailureOr`. Specialize `FieldParser` to support parsing - // for your type. Or you can provide a customer printer. For attributes, - // "$_type" will be replaced with the required attribute type. - string parser = ?; - // The default parameter printer is `$_printer << $_self`. Overload the stream - // operator of `AsmPrinter` as necessary to print your type. Or you can - // provide a custom printer. - string printer = ?; - // Mark a parameter as optional. The C++ type of parameters marked as optional - // must be default constructible and be contextually convertible to `bool`. - // Any `Optional` and any attribute type satisfies these requirements. - bit isOptional = 0; - // Provide a default value for the parameter. Parameters with default values - // are considered optional. If a value was not parsed for the parameter, it - // will be set to the default value. Parameters equal to their default values - // are elided when printing. Equality is checked using the `comparator` field, - // which by default is the C++ equality operator. The current MLIR context is - // made available through `$_ctx`, e.g., for constructing default values for - // attributes and types. - string defaultValue = ?; -} -class AttrParameter - : AttrOrTypeParameter; -class TypeParameter - : AttrOrTypeParameter; - -// For StringRefs, which require allocation. -class StringRefParameter : - AttrOrTypeParameter<"::llvm::StringRef", desc> { - let allocator = [{$_dst = $_allocator.copyInto($_self);}]; - let printer = [{$_printer << '"' << $_self << '"';}]; - let cppStorageType = "std::string"; -} - -// For APFloats, which require comparison. -class APFloatParameter : - AttrOrTypeParameter<"::llvm::APFloat", desc> { - let comparator = "$_lhs.bitwiseIsEqual($_rhs)"; -} - -// For standard ArrayRefs, which require allocation. -class ArrayRefParameter : - AttrOrTypeParameter<"::llvm::ArrayRef<" # arrayOf # ">", desc> { - let allocator = [{$_dst = $_allocator.copyInto($_self);}]; - let cppStorageType = "::llvm::SmallVector<" # arrayOf # ">"; -} - -// For classes which require allocation and have their own allocateInto method. -class SelfAllocationParameter : - AttrOrTypeParameter { - let allocator = [{$_dst = $_self.allocateInto($_allocator);}]; -} - -// For ArrayRefs which contain things which allocate themselves. -class ArrayRefOfSelfAllocationParameter : - AttrOrTypeParameter<"::llvm::ArrayRef<" # arrayOf # ">", desc> { - let allocator = [{ - llvm::SmallVector<}] # arrayOf # [{, 4> tmpFields; - for (size_t i = 0, e = $_self.size(); i < e; ++i) - tmpFields.push_back($_self[i].allocateInto($_allocator)); - $_dst = $_allocator.copyInto(ArrayRef<}] # arrayOf # [{>(tmpFields)); - }]; -} - -// An optional parameter. -class OptionalParameter : - AttrOrTypeParameter { - let isOptional = 1; -} - -// A parameter with a default value. -class DefaultValuedParameter : - AttrOrTypeParameter { - let isOptional = 1; - let defaultValue = value; -} - -// This is a special parameter used for AttrDefs that represents a `mlir::Type` -// that is also used as the value `Type` of the attribute. Only one parameter -// of the attribute may be of this type. -class AttributeSelfTypeParameter : - AttrOrTypeParameter {} - #endif // OP_BASE diff --git a/mlir/include/mlir/IR/PatternBase.td b/mlir/include/mlir/IR/PatternBase.td new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/IR/PatternBase.td @@ -0,0 +1,221 @@ +//===-- PatternBase.td - Base pattern definition file ------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This files contains all of the base constructs for defining DRR patterns. +// +//===----------------------------------------------------------------------===// + +#ifndef PATTERNBASE_TD +#define PATTERNBASE_TD + +include "mlir/IR/OpBase.td" + +//===----------------------------------------------------------------------===// +// Pattern definitions +//===----------------------------------------------------------------------===// + +// Marker used to identify the delta value added to the default benefit value. +def addBenefit; + +// Base class for op+ -> op+ rewrite rules. These allow declaratively +// specifying rewrite rules. +// +// A rewrite rule contains two components: a source pattern and one or more +// result patterns. Each pattern is specified as a (recursive) DAG node (tree) +// in the form of `(node arg0, arg1, ...)`. +// +// The `node` are normally MLIR ops, but it can also be one of the directives +// listed later in this section. +// +// ## Symbol binding +// +// In the source pattern, `argN` can be used to specify matchers (e.g., using +// type/attribute type constraints, etc.) and bound to a name for later use. +// We can also bind names to op instances to reference them later in +// multi-entity constraints. Operands in the source pattern can have +// the same name. This bounds one operand to the name while verifying +// the rest are all equal. +// +// +// In the result pattern, `argN` can be used to refer to a previously bound +// name, with potential transformations (e.g., using tAttr, etc.). `argN` can +// itself be nested DAG node. We can also bound names to ops to reference +// them later in other result patterns. +// +// For example, +// +// ``` +// def : Pattern<(OneResultOp1:$op1 $arg0, $arg1, $arg0), +// [(OneResultOp2:$op2 $arg0, $arg1), +// (OneResultOp3 $op2 (OneResultOp4))], +// [(HasStaticShapePred $op1)]>; +// ``` +// +// First `$arg0` and '$arg1' are bound to the `OneResultOp1`'s first +// and second arguments and used later to build `OneResultOp2`. Second '$arg0' +// is verified to be equal to the first '$arg0' operand. +// `$op1` is bound to `OneResultOp1` and used to check whether the result's +// shape is static. `$op2` is bound to `OneResultOp2` and used to +// build `OneResultOp3`. +// +// ## Multi-result op +// +// To create multi-result ops in result pattern, you can use a syntax similar +// to uni-result op, and it will act as a value pack for all results: +// +// ``` +// def : Pattern<(ThreeResultOp ...), +// [(TwoResultOp ...), (OneResultOp ...)]>; +// ``` +// +// Then `TwoResultOp` will replace the first two values of `ThreeResultOp`. +// +// You can also use `$__N` to explicitly access the N-th result. +// ``` +// def : Pattern<(FiveResultOp ...), +// [(TwoResultOp1:$res1__1 ...), (replaceWithValue $res1__0), +// (TwoResultOp2:$res2 ...), (replaceWithValue $res2__1)]>; +// ``` +// +// Then the values generated by `FiveResultOp` will be replaced by +// +// * `FiveResultOp`#0: `TwoResultOp1`#1 +// * `FiveResultOp`#1: `TwoResultOp1`#0 +// * `FiveResultOp`#2: `TwoResultOp2`#0 +// * `FiveResultOp`#3: `TwoResultOp2`#1 +// * `FiveResultOp`#4: `TwoResultOp2`#1 +class Pattern results, list preds = [], + dag benefitAdded = (addBenefit 0)> { + dag sourcePattern = source; + // Result patterns. Each result pattern is expected to replace one result + // of the root op in the source pattern. In the case of more result patterns + // than needed to replace the source op, only the last N results generated + // by the last N result pattern is used to replace a N-result source op. + // So that the beginning result patterns can be used to generate additional + // ops to aid building the results used for replacement. + list resultPatterns = results; + // Multi-entity constraints. Each constraint here involves multiple entities + // matched in source pattern and places further constraints on them as a + // whole. + list constraints = preds; + // The delta value added to the default benefit value. The default value is + // the number of ops in the source pattern. The rule with the highest final + // benefit value will be applied first if there are multiple rules matches. + // This delta value can be either positive or negative. + dag benefitDelta = benefitAdded; +} + +// Form of a pattern which produces a single result. +class Pat preds = [], + dag benefitAdded = (addBenefit 0)> : + Pattern; + +// Native code call wrapper. This allows invoking an arbitrary C++ expression +// to create an op operand/attribute or replace an op result. +// +// ## Placeholders +// +// If used as a DAG leaf, i.e., `(... NativeCodeCall<"...">:$arg, ...)`, +// the wrapped expression can take special placeholders listed below: +// +// * `$_builder` will be replaced by the current `mlir::PatternRewriter`. +// * `$_self` will be replaced by the defining operation in a source pattern. +// E.g., `NativeCodeCall<"Foo($_self, &$0)> I32Attr:$attr)>`, `$_self` will be +// replaced with the defining operation of the first operand of OneArgOp. +// +// If used as a DAG node, i.e., `(NativeCodeCall<"..."> , ..., )`, +// then positional placeholders are also supported; placeholder `$N` in the +// wrapped C++ expression will be replaced by ``. +// +// ## Bind multiple results +// +// To bind multi-results and access the N-th result with `$__N`, specify +// the number of return values in the template. Note that only `Value` type is +// supported for multiple results binding. + +class NativeCodeCall { + string expression = expr; + int numReturns = returns; +} + +class NativeCodeCallVoid : NativeCodeCall; + +def ConstantLikeMatcher : NativeCodeCall<"::mlir::success(" + "::mlir::matchPattern($_self->getResult(0), ::mlir::m_Constant(&$0)))">; + +//===----------------------------------------------------------------------===// +// Rewrite directives +//===----------------------------------------------------------------------===// + +// Directive used in result pattern to indicate that no new op are generated, +// so to replace the matched DAG with an existing SSA value. +def replaceWithValue; + +// Directive used in result patterns to specify the location of the generated +// op. This directive must be used as a trailing argument to op creation or +// native code calls. +// +// Usage: +// * Create a named location: `(location "myLocation")` +// * Copy the location of a captured symbol: `(location $arg)` +// * Create a fused location: `(location "metadata", $arg0, $arg1)` + +def location; + +// Directive used in result patterns to specify return types for a created op. +// This allows ops to be created without relying on type inference with +// `OpTraits` or an op builder with deduction. +// +// This directive must be used as a trailing argument to op creation. +// +// Specify one return type with a string literal: +// +// ``` +// (AnOp $val, (returnType "$_builder.getI32Type()")) +// ``` +// +// Pass a captured value to copy its return type: +// +// ``` +// (AnOp $val, (returnType $val)); +// ``` +// +// Pass a native code call inside a DAG to create a new type with arguments. +// +// ``` +// (AnOp $val, +// (returnType (NativeCodeCall<"$_builder.getTupleType({$0})"> $val))); +// ``` +// +// Specify multiple return types with multiple of any of the above. + +def returnType; + +// Directive used to specify the operands may be matched in either order. When +// two adjacents are marked with `either`, it'll try to match the operands in +// either ordering of constraints. Example: +// +// ``` +// (TwoArgOp (either $firstArg, (AnOp $secondArg))) +// ``` +// The above pattern will accept either `"test.TwoArgOp"(%I32Arg, %AnOpArg)` and +// `"test.TwoArgOp"(%AnOpArg, %I32Arg)`. +// +// Only operand is supported with `either` and note that an operation with +// `Commutative` trait doesn't imply that it'll have the same behavior than +// `either` while pattern matching. +def either; + +//===----------------------------------------------------------------------===// +// Common value constraints +//===----------------------------------------------------------------------===// + +def HasNoUseOf: Constraint< + CPred<"$_self.use_empty()">, "has no use">; + +#endif // PATTERNBASE_TD diff --git a/mlir/lib/Conversion/GPUToNVVM/GPUToNVVM.td b/mlir/lib/Conversion/GPUToNVVM/GPUToNVVM.td --- a/mlir/lib/Conversion/GPUToNVVM/GPUToNVVM.td +++ b/mlir/lib/Conversion/GPUToNVVM/GPUToNVVM.td @@ -13,6 +13,7 @@ #ifndef MLIR_CONVERSION_GPUTONVVM_TD #define MLIR_CONVERSION_GPUTONVVM_TD +include "mlir/IR/PatternBase.td" include "mlir/Dialect/GPU/GPUOps.td" include "mlir/Dialect/LLVMIR/NVVMOps.td" diff --git a/mlir/lib/Conversion/GPUToROCDL/GPUToROCDL.td b/mlir/lib/Conversion/GPUToROCDL/GPUToROCDL.td --- a/mlir/lib/Conversion/GPUToROCDL/GPUToROCDL.td +++ b/mlir/lib/Conversion/GPUToROCDL/GPUToROCDL.td @@ -13,6 +13,7 @@ #ifndef MLIR_CONVERSION_GPUTOROCDL_TD #define MLIR_CONVERSION_GPUTOROCDL_TD +include "mlir/IR/PatternBase.td" include "mlir/Dialect/GPU/GPUOps.td" include "mlir/Dialect/LLVMIR/ROCDLOps.td" diff --git a/mlir/lib/Conversion/ShapeToStandard/ShapeToStandard.td b/mlir/lib/Conversion/ShapeToStandard/ShapeToStandard.td --- a/mlir/lib/Conversion/ShapeToStandard/ShapeToStandard.td +++ b/mlir/lib/Conversion/ShapeToStandard/ShapeToStandard.td @@ -13,6 +13,7 @@ #ifndef MLIR_CONVERSION_SHAPETOSTANDARD_TD #define MLIR_CONVERSION_SHAPETOSTANDARD_TD +include "mlir/IR/PatternBase.td" include "mlir/Dialect/Shape/IR/ShapeOps.td" def BroadcastableStringAttr : NativeCodeCall<[{ diff --git a/mlir/lib/Dialect/Arithmetic/IR/ArithmeticCanonicalization.td b/mlir/lib/Dialect/Arithmetic/IR/ArithmeticCanonicalization.td --- a/mlir/lib/Dialect/Arithmetic/IR/ArithmeticCanonicalization.td +++ b/mlir/lib/Dialect/Arithmetic/IR/ArithmeticCanonicalization.td @@ -9,6 +9,7 @@ #ifndef ARITHMETIC_PATTERNS #define ARITHMETIC_PATTERNS +include "mlir/IR/PatternBase.td" include "mlir/Dialect/Arithmetic/IR/ArithmeticOps.td" // Add two integer attributes and create a new one with the result. diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.td b/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.td --- a/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.td +++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.td @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +include "mlir/IR/PatternBase.td" include "mlir/Dialect/SPIRV/IR/SPIRVOps.td" //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/Shape/IR/ShapeCanonicalization.td b/mlir/lib/Dialect/Shape/IR/ShapeCanonicalization.td --- a/mlir/lib/Dialect/Shape/IR/ShapeCanonicalization.td +++ b/mlir/lib/Dialect/Shape/IR/ShapeCanonicalization.td @@ -1,3 +1,4 @@ +include "mlir/IR/PatternBase.td" include "mlir/Dialect/Shape/IR/ShapeOps.td" include "mlir/Dialect/Tensor/IR/TensorOps.td" diff --git a/mlir/test/lib/Dialect/Test/TestAttrDefs.td b/mlir/test/lib/Dialect/Test/TestAttrDefs.td --- a/mlir/test/lib/Dialect/Test/TestAttrDefs.td +++ b/mlir/test/lib/Dialect/Test/TestAttrDefs.td @@ -15,6 +15,7 @@ // To get the test dialect definition. include "TestDialect.td" +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/BuiltinAttributeInterfaces.td" include "mlir/IR/SubElementInterfaces.td" diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td --- a/mlir/test/lib/Dialect/Test/TestOps.td +++ b/mlir/test/lib/Dialect/Test/TestOps.td @@ -14,6 +14,7 @@ include "mlir/IR/EnumAttr.td" include "mlir/IR/OpBase.td" include "mlir/IR/OpAsmInterface.td" +include "mlir/IR/PatternBase.td" include "mlir/IR/RegionKindInterface.td" include "mlir/IR/SymbolInterfaces.td" include "mlir/Interfaces/CallInterfaces.td" diff --git a/mlir/test/mlir-tblgen/attr-or-type-format-invalid.td b/mlir/test/mlir-tblgen/attr-or-type-format-invalid.td --- a/mlir/test/mlir-tblgen/attr-or-type-format-invalid.td +++ b/mlir/test/mlir-tblgen/attr-or-type-format-invalid.td @@ -1,5 +1,6 @@ // RUN: mlir-tblgen -gen-typedef-defs -I %S/../../include -asmformat-error-is-fatal=false %s 2>&1 | FileCheck %s +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" def Test_Dialect : Dialect { diff --git a/mlir/test/mlir-tblgen/attr-or-type-format.td b/mlir/test/mlir-tblgen/attr-or-type-format.td --- a/mlir/test/mlir-tblgen/attr-or-type-format.td +++ b/mlir/test/mlir-tblgen/attr-or-type-format.td @@ -1,6 +1,7 @@ // RUN: mlir-tblgen -gen-attrdef-defs -I %S/../../include %s | FileCheck %s --check-prefix=ATTR // RUN: mlir-tblgen -gen-typedef-defs -I %S/../../include %s | FileCheck %s --check-prefix=TYPE +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" /// Test that attribute and type printers and parsers are correctly generated. diff --git a/mlir/test/mlir-tblgen/attrdefs.td b/mlir/test/mlir-tblgen/attrdefs.td --- a/mlir/test/mlir-tblgen/attrdefs.td +++ b/mlir/test/mlir-tblgen/attrdefs.td @@ -1,6 +1,7 @@ // RUN: mlir-tblgen -gen-attrdef-decls -I %S/../../include %s | FileCheck %s --check-prefix=DECL // RUN: mlir-tblgen -gen-attrdef-defs -I %S/../../include %s | FileCheck %s --check-prefix=DEF +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" // DECL: #ifdef GET_ATTRDEF_CLASSES diff --git a/mlir/test/mlir-tblgen/default-type-attr-print-parser.td b/mlir/test/mlir-tblgen/default-type-attr-print-parser.td --- a/mlir/test/mlir-tblgen/default-type-attr-print-parser.td +++ b/mlir/test/mlir-tblgen/default-type-attr-print-parser.td @@ -1,6 +1,7 @@ // RUN: mlir-tblgen -gen-attrdef-defs -I %S/../../include %s | FileCheck %s --check-prefix=ATTR // RUN: mlir-tblgen -gen-typedef-defs -I %S/../../include %s | FileCheck %s --check-prefix=TYPE +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" /// Test that attribute and type printers and parsers are correctly generated. diff --git a/mlir/test/mlir-tblgen/expect-symbol.td b/mlir/test/mlir-tblgen/expect-symbol.td --- a/mlir/test/mlir-tblgen/expect-symbol.td +++ b/mlir/test/mlir-tblgen/expect-symbol.td @@ -1,6 +1,7 @@ // RUN: not mlir-tblgen -gen-rewriters -I %S/../../include %s 2>&1 | FileCheck %s include "mlir/IR/OpBase.td" +include "mlir/IR/PatternBase.td" def Test_Dialect : Dialect { let name = "test"; diff --git a/mlir/test/mlir-tblgen/op-attribute.td b/mlir/test/mlir-tblgen/op-attribute.td --- a/mlir/test/mlir-tblgen/op-attribute.td +++ b/mlir/test/mlir-tblgen/op-attribute.td @@ -2,6 +2,7 @@ // RUN: mlir-tblgen -gen-op-defs -I %S/../../include %s | FileCheck %s --check-prefix=DEF // RUN: mlir-tblgen -print-records -I %S/../../include %s | FileCheck %s --check-prefix=RECORD +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" def Test_Dialect : Dialect { diff --git a/mlir/test/mlir-tblgen/op-decl-and-defs.td b/mlir/test/mlir-tblgen/op-decl-and-defs.td --- a/mlir/test/mlir-tblgen/op-decl-and-defs.td +++ b/mlir/test/mlir-tblgen/op-decl-and-defs.td @@ -4,6 +4,7 @@ // RUN: mlir-tblgen -gen-op-defs -I %S/../../include %s | FileCheck %s --check-prefix=DEFS +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" include "mlir/Interfaces/InferTypeOpInterface.td" include "mlir/Interfaces/SideEffectInterfaces.td" diff --git a/mlir/test/mlir-tblgen/rewriter-errors.td b/mlir/test/mlir-tblgen/rewriter-errors.td --- a/mlir/test/mlir-tblgen/rewriter-errors.td +++ b/mlir/test/mlir-tblgen/rewriter-errors.td @@ -7,6 +7,7 @@ // RUN: not mlir-tblgen -gen-rewriters -I %S/../../include -DERROR7 %s 2>&1 | FileCheck --check-prefix=ERROR7 %s include "mlir/IR/OpBase.td" +include "mlir/IR/PatternBase.td" // Check using the dialect name as the namespace def A_Dialect : Dialect { diff --git a/mlir/test/mlir-tblgen/rewriter-indexing.td b/mlir/test/mlir-tblgen/rewriter-indexing.td --- a/mlir/test/mlir-tblgen/rewriter-indexing.td +++ b/mlir/test/mlir-tblgen/rewriter-indexing.td @@ -1,6 +1,7 @@ // RUN: mlir-tblgen -gen-rewriters -I %S/../../include %s | FileCheck %s include "mlir/IR/OpBase.td" +include "mlir/IR/PatternBase.td" def Test_Dialect : Dialect { let name = "test"; diff --git a/mlir/test/mlir-tblgen/rewriter-static-matcher.td b/mlir/test/mlir-tblgen/rewriter-static-matcher.td --- a/mlir/test/mlir-tblgen/rewriter-static-matcher.td +++ b/mlir/test/mlir-tblgen/rewriter-static-matcher.td @@ -1,6 +1,7 @@ // RUN: mlir-tblgen -gen-rewriters -I %S/../../include %s | FileCheck %s include "mlir/IR/OpBase.td" +include "mlir/IR/PatternBase.td" def Test_Dialect : Dialect { let name = "test"; diff --git a/mlir/test/mlir-tblgen/typedefs.td b/mlir/test/mlir-tblgen/typedefs.td --- a/mlir/test/mlir-tblgen/typedefs.td +++ b/mlir/test/mlir-tblgen/typedefs.td @@ -1,6 +1,7 @@ // RUN: mlir-tblgen -gen-typedef-decls -I %S/../../include %s | FileCheck %s --check-prefix=DECL // RUN: mlir-tblgen -gen-typedef-defs -I %S/../../include %s | FileCheck %s --check-prefix=DEF +include "mlir/IR/AttrTypeBase.td" include "mlir/IR/OpBase.td" // DECL: #ifdef GET_TYPEDEF_CLASSES diff --git a/mlir/test/python/python_test_ops.td b/mlir/test/python/python_test_ops.td --- a/mlir/test/python/python_test_ops.td +++ b/mlir/test/python/python_test_ops.td @@ -9,6 +9,7 @@ #ifndef PYTHON_TEST_OPS #define PYTHON_TEST_OPS +include "mlir/IR/AttrTypeBase.td" include "mlir/Bindings/Python/Attributes.td" include "mlir/IR/OpBase.td" include "mlir/Interfaces/InferTypeOpInterface.td" diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp --- a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp +++ b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp @@ -652,8 +652,8 @@ /// A specialized generator for AttrDefs. struct AttrDefGenerator : public DefGenerator { AttrDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os) - : DefGenerator(records.getAllDerivedDefinitions("AttrDef"), os, "Attr", - "Attribute", + : DefGenerator(records.getAllDerivedDefinitionsIfDefined("AttrDef"), os, + "Attr", "Attribute", /*isAttrGenerator=*/true, /*needsDialectParserPrinter=*/ !records.getAllDerivedDefinitions("DialectAttr").empty()) { @@ -662,8 +662,9 @@ /// A specialized generator for TypeDefs. struct TypeDefGenerator : public DefGenerator { TypeDefGenerator(const llvm::RecordKeeper &records, raw_ostream &os) - : DefGenerator(records.getAllDerivedDefinitions("TypeDef"), os, "Type", - "Type", /*isAttrGenerator=*/false, + : DefGenerator(records.getAllDerivedDefinitionsIfDefined("TypeDef"), os, + "Type", "Type", + /*isAttrGenerator=*/false, /*needsDialectParserPrinter=*/ !records.getAllDerivedDefinitions("DialectType").empty()) { } diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp --- a/mlir/tools/mlir-tblgen/OpDocGen.cpp +++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp @@ -337,11 +337,11 @@ static void emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) { std::vector opDefs = getRequestedOpDefinitions(recordKeeper); std::vector typeDefs = - recordKeeper.getAllDerivedDefinitions("DialectType"); + recordKeeper.getAllDerivedDefinitionsIfDefined("DialectType"); std::vector typeDefDefs = - recordKeeper.getAllDerivedDefinitions("TypeDef"); + recordKeeper.getAllDerivedDefinitionsIfDefined("TypeDef"); std::vector attrDefDefs = - recordKeeper.getAllDerivedDefinitions("AttrDef"); + recordKeeper.getAllDerivedDefinitionsIfDefined("AttrDef"); std::set dialectsWithDocs;