Skip to content

Commit

Permalink
Merged master:f402e682d0ef into amd-gfx:ba721ee79db8
Browse files Browse the repository at this point in the history
Local branch amd-gfx ba721ee Merged master:094e9f4779eb into amd-gfx:bac148f43ef0
Remote branch master f402e68 [MLIR] ODS TypeDefs: getChecked() and internal enhancements
  • Loading branch information
Sw authored and Sw committed Oct 19, 2020
2 parents ba721ee + f402e68 commit 7e7f257
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 40 deletions.
17 changes: 17 additions & 0 deletions llvm/utils/TableGen/X86FoldTablesEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ class X86FoldTablesEmitter {

OS << "0 },\n";
}

bool operator<(const X86FoldTableEntry &RHS) const {
bool LHSpseudo = RegInst->TheDef->getValueAsBit("isPseudo");
bool RHSpseudo = RHS.RegInst->TheDef->getValueAsBit("isPseudo");
if (LHSpseudo != RHSpseudo)
return LHSpseudo;

return RegInst->TheDef->getName() < RHS.RegInst->TheDef->getName();
}
};

typedef std::vector<X86FoldTableEntry> FoldTable;
Expand Down Expand Up @@ -647,6 +656,14 @@ void X86FoldTablesEmitter::run(formatted_raw_ostream &OS) {
&(Target.getInstruction(MemInstIter)), Entry.Strategy);
}

// Sort the tables before printing.
llvm::sort(Table2Addr);
llvm::sort(Table0);
llvm::sort(Table1);
llvm::sort(Table2);
llvm::sort(Table3);
llvm::sort(Table4);

// Print all tables.
printTable(Table2Addr, "Table2Addr", OS);
printTable(Table0, "Table0", OS);
Expand Down
175 changes: 171 additions & 4 deletions mlir/docs/OpDefinitions.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -1412,6 +1412,173 @@ llvm::Optional<MyBitEnum> symbolizeMyBitEnum(uint32_t value) {
}
```

## Type Definitions

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<string name> : TypeDef<Test_Dialect, name> { }
// 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
standard integer type 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
`<classParamName>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
as 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` to generate the TypeStorage class with
a constructor which is just declared -- no definition -- so you can write it
yourself.
- Use the `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<int>":$dims);
```

The default storage constructor blindly copies fields by value. It does not
know anything about the types. In this case, the ArrayRef<int> 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<int>", "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<descriptionOfParam>` for StringRefs.
- `ArrayRefParameter<arrayOf, descriptionOfParam>` for ArrayRefs of value
types
- `SelfAllocationParameter<descriptionOfParam>` for C++ classes which contain
a method called `allocateInto(StorageAllocator &allocator)` to allocate
itself into `allocator`.
- `ArrayRefOfSelfAllocationParameter<arrayOf, descriptionOfParam>` 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.

For each dialect, two "dispatch" functions will be created: one for parsing
and one for printing. You should add calls to these in your
`Dialect::printType` and `Dialect::parseType` methods. They are created in
the dialect's namespace and their function signatures are:
```c++
Type generatedTypeParser(MLIRContext* ctxt, DialectAsmParser& parser,
StringRef mnemonic);
LogicalResult generatedTypePrinter(Type type, DialectAsmPrinter& printer);
```
The mnemonic, parser, and printer fields are optional. If they're not
defined, the generated code will not include any parsing or printing code and
omit the type from the dispatch functions above. In this case, the dialect
author is responsible for parsing/printing the types in `Dialect::printType`
and `Dialect::parseType`.
### 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
Expand Down
3 changes: 2 additions & 1 deletion mlir/test/lib/Dialect/Test/TestTypeDefs.td
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ def IntegerType : Test_Type<"TestInteger"> {
int width;
if ($_parser.parseInteger(width)) return Type();
if ($_parser.parseGreater()) return Type();
return get(ctxt, signedness, width);
Location loc = $_parser.getEncodedSourceLoc($_parser.getNameLoc());
return getChecked(loc, signedness, width);
}];

// Any extra code one wants in the type's class declaration.
Expand Down
2 changes: 1 addition & 1 deletion mlir/test/mlir-tblgen/typedefs.td
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def B_CompoundTypeA : TestType<"CompoundA"> {

// DECL-LABEL: class CompoundAType: public ::mlir::Type
// DECL: static ::mlir::LogicalResult verifyConstructionInvariants(Location loc, int widthOfSomething, ::mlir::test::SimpleTypeA exampleTdType, SomeCppStruct exampleCppType, ::llvm::ArrayRef<int> dims);
// DECL: static CompoundAType getChecked(Location loc, int widthOfSomething, ::mlir::test::SimpleTypeA exampleTdType, SomeCppStruct exampleCppType, ::llvm::ArrayRef<int> dims);
// DECL: static ::mlir::Type getChecked(Location loc, int widthOfSomething, ::mlir::test::SimpleTypeA exampleTdType, SomeCppStruct exampleCppType, ::llvm::ArrayRef<int> dims);
// DECL: static ::llvm::StringRef getMnemonic() { return "cmpnd_a"; }
// DECL: static ::mlir::Type parse(::mlir::MLIRContext* ctxt, ::mlir::DialectAsmParser& parser);
// DECL: void print(::mlir::DialectAsmPrinter& printer) const;
Expand Down
Loading

0 comments on commit 7e7f257

Please sign in to comment.