diff --git a/mlir/docs/OpDefinitions.md b/mlir/docs/OpDefinitions.md --- a/mlir/docs/OpDefinitions.md +++ b/mlir/docs/OpDefinitions.md @@ -1,11 +1,11 @@ # Operation Definition Specification (ODS) In addition to specializing the `mlir::Op` C++ template, MLIR also supports -defining operations in a table-driven manner. This is achieved via -[TableGen][TableGen], which is both a generic language and its tooling to +defining operations and data types in a table-driven manner. This is achieved +via [TableGen][TableGen], which is both a generic language and its tooling to maintain records of domain-specific information. Facts regarding an operation -are specified concisely into a TableGen record, which will be expanded into an -equivalent `mlir::Op` C++ template specialization at compiler build time. +are specified concisely into a TableGen record, which will be expanded into +an equivalent `mlir::Op` C++ template specialization at compiler build time. This manual explains in detail all the available mechanisms for defining operations in such a table-driven manner. It aims to be a specification instead @@ -1412,6 +1412,156 @@ } ``` +## TypeDefs + +MLIR defines the TypeDef class hierarchy to enable generation of data types +from their specifications. A type is defined by specializing the TypeDef +class with concrete contents for all the fields it requires. For example, an +integer type could be defined as: + +```tablegen +// All of the types will extend this class. +class Test_Type : TypeDef { } + +// An alternate int type. +def IntegerType : Test_Type<"TestInteger"> { + let mnemonic = "int"; + + let summary = "An integer type with special semantics"; + + let description = [{ +An alternate integer type. This type differentiates itself from the std int by +not having a SignednessSemantics parameter, just a width. + }]; + + let parameters = ( + ins + "unsigned":$width + ); + + // We define the printer inline. + let printer = [{ + $_printer << "int<" << getImpl()->width << ">"; + }]; + + // The parser is defined here also. + let parser = [{ + if (parser.parseLess()) return Type(); + int width; + if ($_parser.parseInteger(width)) return Type(); + if ($_parser.parseGreater()) return Type(); + return get(ctxt, width); + }]; +``` + +### Type name + +The name of the C++ class which gets generated defaults to +`Type` (e.g. `TestIntegerType` in the above example). This +can be overridden via the the `cppClassName` field. The field `mnemonic` is +to specify the asm name for parsing. It is optional and not specifying it +will imply that no parser or printer methods are attached to this class. + +### Type documentation + +The `summary` and `description` fields exist and are to be used the same way +is in Operations. Namely, the summary should be a one-liner and `description` +should be a longer explanation. + +### Type parameters + +The `parameters` field is a list of the types parameters. If no parameters +are specified (the default), this type is considered a singleton type. +Parameters are in the `"c++Type":$paramName` format. +To use C++ types as parameters which need allocation in the storage +constructor, there are two options: + +- Set `hasCustomStorageConstructor` will generate the TypeStorage class with +a constructor which is just declared -- no definition -- so you can write it +yourself. +- Use a `TypeParameter` tablegen class instead of the "c++Type" string. + +### TypeParameter tablegen class + +This is used to further specify attributes about each of the types +parameters. It includes documentation (`description` and `syntax`), the C++ +type to use, and a custom allocator to use in the storage constructor method. + +```tablegen +// DO NOT DO THIS! +let parameters = (ins + "ArrayRef":$dims); +``` + +The default storage constructor blindly copies fields by value. It does not +know anything about the types. In this case, the ArrayRef requires +allocation with `dims = allocator.copyInto(dims)`. + +You can specify the necessary constuctor by specializing the `TypeParameter` +tblgen class: + +```tablegen +class ArrayRefIntParam : + TypeParameter<"::llvm::ArrayRef", "Array of ints"> { + let allocator = [{$_dst = $_allocator.copyInto($_self);}]; +} + +... + +let parameters = (ins + ArrayRefIntParam:$dims); +``` + +The `allocator` code block has the following substitutions: +- `$_allocator` is the TypeStorageAllocator in which to allocate objects. +- `$_dst` is the variable in which to place the allocated data. + +MLIR includes several specialized classes for common situations: +- `StringRefParameter` for StringRefs. +- `ArrayRefParameter` for ArrayRefs of value +types +- `SelfAllocationParameter` for C++ classes which contain +a method called `allocateInto(StorageAllocator allocator)` to allocate itself +into `allocator`. +- `ArrayRefOfSelfAllocationParameter` for arrays +of objects which self-allocate as per the last specialization. + +If we were to use one of these included specializations: + +```tablegen +let parameters = (ins + ArrayRefParameter<"int", "The dimensions">:$dims); +``` + +### Parsing and printing + +If a mnemonic is specified, the `printer` and `parser` code fields are active. The rules for both are: +- If null, generate just the declaration. +- If non-null and non-empty, use the code in the definition. The `$_printer` +or `$_parser` substitutions are valid and should be used. +- It is an error to have an empty code block. + +### Other fields + +- If the `genStorageClass` field is set to 1 (the default) a storage class is +generated with member variables corresponding to each of the specified +`parameters`. +- If the `genAccessors` field is 1 (the default) accessor methods will be +generated on the Type class (e.g. `int getWidth() const` in the example +above). +- If the `genVerifyInvariantsDecl` field is set, a declaration for a method +`static LogicalResult verifyConstructionInvariants(Location, parameters...)` +is added to the class as well as a `getChecked(Location, parameters...)` +method which gets the result of `verifyConstructionInvariants` before calling +`get`. +- The `storageClass` field can be used to set the name of the storage class. +- The `storageNamespace` field is used to set the namespace where the storage +class should sit. Defaults to "detail". +- The `extraClassDeclaration` field is used to include extra code in the +class declaration. + + + ## Debugging Tips ### Run `mlir-tblgen` to see the generated content