Commit Graph

245 Commits

Author SHA1 Message Date
River Riddle a77cd55dea [mlir] Add support for specifying printing flags when adding an op to a Diagnostic
This removes edge cases where the default flags we want to use
during printing (e.g. local scope, eliding attributes, etc.)
get missed/dropped.

Differential Revision: https://reviews.llvm.org/D111761
2021-10-18 15:07:55 +00:00
Uday Bondhugula 05fb26062c [MLIR] Fix assert crash when an unregistered dialect op is encountered
Fix assert crash when an unregistered dialect op is encountered during
parsing and `-allow-unregistered-dialect' isn't on. Instead, emit an
error.

While on this, clean up "registered" vs "loaded" on `getDialect()` and
local clang-tidy warnings.

https://llvm.discourse.group/t/assert-behavior-on-unregistered-dialect-ops/4402

Differential Revision: https://reviews.llvm.org/D111628
2021-10-14 15:43:53 +05:30
Mehdi Amini 00b7d95182 Stop stripping the `std.` prefix when printing operations in a region with a defined default dialect
This fixes round-trip / ambiguity when an operation in the standard dialect would
have the same name as an operation in the default dialect.

Differential Revision: https://reviews.llvm.org/D111204
2021-10-06 02:36:14 +00:00
River Riddle 531206310a [mlir:OpAsm] Factor out the common bits of (Op/Dialect)Asm(Parser/Printer)
This has a few benefits:
* It allows for defining parsers/printer code blocks that
  can be shared between operations and attribute/types.
* It removes the weird duplication of generic parser/printer hooks,
  which means that newly added hooks only require touching one class.

Differential Revision: https://reviews.llvm.org/D110375
2021-09-24 20:12:19 +00:00
River Riddle 0cb5d7fc7f [mlir] Add value_begin/value_end methods to DenseElementsAttr
Currently DenseElementsAttr only exposes the ability to get the full range of values for a given type T, but there are many situations where we just want the beginning/end iterator. This revision adds proper value_begin/value_end methods for all of the supported T types, and also cleans up a bit of the interface.

Differential Revision: https://reviews.llvm.org/D104173
2021-09-21 01:57:43 +00:00
Uday Bondhugula a91cfd1990 [MLIR] Improve op parse error message for AtLeastNOperands trait
Improve parse error message for "at least N operands" op trait.

Differential Revision: https://reviews.llvm.org/D109747
2021-09-14 15:01:51 +05:30
Mehdi Amini 387f95541b Add a new interface allowing to set a default dialect to be used for printing/parsing regions
Currently the builtin dialect is the default namespace used for parsing
and printing. As such module and func don't need to be prefixed.
In the case of some dialects that defines new regions for their own
purpose (like SpirV modules for example), it can be beneficial to
change the default dialect in order to improve readability.

Differential Revision: https://reviews.llvm.org/D107236
2021-08-31 17:52:40 +00:00
Mehdi Amini c41b16c26b Change ASM Op printer to print the operation name in the framework instead of leaving it up to each individual operation
This aligns the printer with the parser contract: the operation isn't part of the user-controllable part of the syntax.

Differential Revision: https://reviews.llvm.org/D108804
2021-08-31 17:52:40 +00:00
River Riddle aea3026ea7 [mlir] Move the Operation use iteration utilities to ResultRange
This allows for iterating and interacting with the uses of a specific subset of
results as opposed to just the full range.

Differential Revision: https://reviews.llvm.org/D108586
2021-08-25 09:27:35 +00:00
River Riddle 4e103a12d9 [mlir] Add support for VariadicOfVariadic operands
This revision adds native ODS support for VariadicOfVariadic operand
groups. An example of this is the SwitchOp, which has a variadic number
of nested operand ranges for each of the case statements, where the
number of case statements is variadic. Builtin ODS support allows for
generating proper accessors for the nested operand ranges, builder
support, and declarative format support. VariadicOfVariadic operands
are supported by providing a segment attribute to use to store the
operand groups, mapping similarly to the AttrSizedOperand trait
(but with a user defined attribute name).

`build` methods for VariadicOfVariadic operand expect inputs of the
form `ArrayRef<ValueRange>`. Accessors for the variadic ranges
return a new `OperandRangeRange` type, which represents a
contiguous range of `OperandRange`. In the declarative assembly
format, VariadicOfVariadic operands and types are by default
formatted as a comma delimited list of value lists:
`(<value>, <value>), (), (<value>)`.

Differential Revision: https://reviews.llvm.org/D107774
2021-08-23 20:32:31 +00:00
River Riddle f8479d9de5 [mlir] Set the namespace of the BuiltinDialect to 'builtin'
Historically the builtin dialect has had an empty namespace. This has unfortunately created a very awkward situation, where many utilities either have to special case the empty namespace, or just don't work at all right now. This revision adds a namespace to the builtin dialect, and starts to cleanup some of the utilities to no longer handle empty namespaces. For now, the assembly form of builtin operations does not require the `builtin.` prefix. (This should likely be re-evaluated though)

Differential Revision: https://reviews.llvm.org/D105149
2021-07-28 21:00:10 +00:00
Mehdi Amini 0f9e6451a8 Defend early against operation created without a registered dialect
Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D105961
2021-07-15 03:52:32 +00:00
Mehdi Amini 3e25ea709c Revert "Defend early against operation created without a registered dialect"
This reverts commit 58018858e8.

The Python bindings test are broken.
2021-07-15 03:31:44 +00:00
Mehdi Amini 58018858e8 Defend early against operation created without a registered dialect
Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D105961
2021-07-15 03:02:52 +00:00
River Riddle 36b538f583 [mlir][NFC] Move several small methods from .cpp to .h to allow more aggressive inlining
Differential Revision: https://reviews.llvm.org/D104756
2021-06-23 00:52:26 +00:00
Chris Lattner bde21b6245 [Verifier] Significantly speed up IsolatedFromAbove checking. NFC.
The implementation had a couple of problems, including checking
"isProperAncestor" in an inefficient way.  It also recursed into
other "isolated from above" ops.  In the case of CIRCT, we get
three levels of isolated ops:

  mlir::ModuleOp
    firrtl::CircuitOp
       firrtl::FModuleOp

The verification for module would recurse into the circuits and
fmodules checking them.  The verifier hook for circuit would
recurse into all the modules reverifying them, fmoduleop would
then reverify them.  The same happens for mlir::ModuleOp and Func.

While here, fix an old design problem: IsolatedFromAbove checking
was implemented by a method on the Region class, which isn't
actually general and isn't used by anything else.  Move it over
to be a trait impl verifier method like the others and specialize
it for its task.

Differential Revision: https://reviews.llvm.org/D103345
2021-05-28 16:13:45 -07:00
Mehdi Amini a360a9786f Fix deletion of operations through the rewriter in a pattern matching a consumer operation
This allows for the conversion to match `A(B()) -> C()` with a pattern matching
`A` and marking `B` for deletion.

Also add better assertions when an operation is erased while still having uses.

Differential Revision: https://reviews.llvm.org/D99442
2021-03-30 22:02:14 +00:00
Alex Zinenko 5fac87d1bc [mlir] verify that operand/result_segment_sizes attributes have i32 element
This is an assumption that is made in numerous places in the code. In
particular, in the code generated by mlir-tblgen for operand/result accessors
in ops with attr-sized operand or result lists. Make sure to verify this
assumption.

Note that the operation traits are verified before running the custom op
verifier, which can expect the trait verifier to have passed, but some traits
may be verified before the AttrSizedOperand/ResultTrait and should not make
such assumptions.

Reviewed By: mehdi_amini

Differential Revision: https://reviews.llvm.org/D99183
2021-03-23 18:26:31 +01:00
Frederik Gossen 2a71f95767 [MLIR] Allow compatible shapes in `Elementwise` operations
Differential Revision: https://reviews.llvm.org/D98186
2021-03-15 09:56:20 +01:00
Tres Popp 25a20b8aa6 [mlir] Correct verifyCompatibleShapes
verifyCompatibleShapes is not transitive. Create an n-ary version and
update SameOperandShapes and SameOperandAndResultShapes traits to use
it.

Differential Revision: https://reviews.llvm.org/D98331
2021-03-11 13:04:10 +01:00
River Riddle 3dfa86149e [mlir][IR] Refactor the internal implementation of Value
The current implementation of Value involves a pointer int pair with several different kinds of owners, i.e. BlockArgumentImpl*, Operation *, TrailingOpResult*. This design arose from the desire to save memory overhead for operations that have a very small number of results (generally 0-2). There are, unfortunately, many problematic aspects of the current implementation that make Values difficult to work with or just inefficient.

Operation result types are stored as a separate array on the Operation. This is very inefficient for many reasons: we use TupleType for multiple results, which can lead to huge amounts of memory usage if multi-result operations change types frequently(they do). It also means that simple methods like Value::getType/Value::setType now require complex logic to get to the desired type.

Value only has one pointer bit free, severely limiting the ability to use it in things like PointerUnion/PointerIntPair. Given that we store the kind of a Value along with the "owner" pointer, we only leave one bit free for users of Value. This creates situations where we end up nesting PointerUnions to be able to use Value in one.

As noted above, most of the methods in Value need to branch on at least 3 different cases which is both inefficient, possibly error prone, and verbose. The current storage of results also creates problems for utilities like ValueRange/TypeRange, which want to efficiently store base pointers to ranges (of which Operation* isn't really useful as one).

This revision greatly simplifies the implementation of Value by the introduction of a new ValueImpl class. This class contains all of the state shared between all of the various derived value classes; i.e. the use list, the type, and the kind. This shared implementation class provides several large benefits:

* Most of the methods on value are now branchless, and often one-liners.

* The "kind" of the value is now stored in ValueImpl instead of Value
This frees up all of Value's pointer bits, allowing for users to take full advantage of PointerUnion/PointerIntPair/etc. It also allows for storing more operation results as "inline", 6 now instead of 2, freeing up 1 word per new inline result.

* Operation result types are now stored in the result, instead of a side array
This drops the size of zero-result operations by 1 word. It also removes the memory crushing use of TupleType for operations results (which could lead up to hundreds of megabytes of "dead" TupleTypes in the context). This also allowed restructured ValueRange, making it simpler and one word smaller.

This revision does come with two conceptual downsides:
* Operation::getResultTypes no longer returns an ArrayRef<Type>
This conceptually makes some usages slower, as the iterator increment is slightly more complex.
* OpResult::getOwner is slightly more expensive, as it now requires a little bit of arithmetic

From profiling, neither of the conceptual downsides have resulted in any perceivable hit to performance. Given the advantages of the new design, most compiles are slightly faster.

Differential Revision: https://reviews.llvm.org/D97804
2021-03-03 14:33:37 -08:00
Frederik Gossen bcc9b371e4 Split `ElementwiseMappable` trait into four more precise traits.
Some elementwise operations are not scalarizable, vectorizable, or tensorizable.
Split `ElementwiseMappable` trait into the following, more precise traits.
  - `Elementwise`
  - `Scalarizable`
  - `Vectorizable`
  - `Tensorizable`
This allows for reuse of `Elementwise` in dialects like HLO.

Differential Revision: https://reviews.llvm.org/D97674
2021-03-02 15:31:19 +01:00
Jacques Pienaar 87e05eb03b Revert "Remove use of tuple for multiresult type storage"
This reverts commit 08f0764ff5.
2021-03-01 10:39:41 -08:00
Jacques Pienaar 08f0764ff5 Remove use of tuple for multiresult type storage
Move the results in line with the op instead. This results in each
operation having its own types recorded vs single tuple type, but comes
at benefit that every mutation doesn't incurs uniquing. Ran into cases
where updating result type of operation led to very large memory usage.

Differential Revision: https://reviews.llvm.org/D97652
2021-03-01 09:30:24 -08:00
River Riddle e6260ad043 [mlir] Simplify various pieces of code now that Identifier has access to the Context/Dialect
This also exposed a bug in Dialect loading where it was not correctly identifying identifiers that had the dialect namespace as a prefix.

Differential Revision: https://reviews.llvm.org/D97431
2021-02-26 18:00:05 -08:00
River Riddle 65a3197a8f [mlir] Refactor InterfaceMap to use a sorted vector of interfaces, as opposed to a DenseMap
A majority of operations have a very small number of interfaces, which means that the cost of using a hash map is generally larger for interface lookups than just a binary search. In the future when there are a number of operations with large amounts of interfaces, we can switch to a hybrid approach that optimizes lookups based on the number of interfaces. For now, however, a binary search is the best approach.

This dropped compile time on a largish TF MLIR module by 20%(half a second).

Differential Revision: https://reviews.llvm.org/D96085
2021-02-23 14:36:45 -08:00
River Riddle fe7c0d90b2 [mlir][IR] Remove the concept of `OperationProperties`
These properties were useful for a few things before traits had a better integration story, but don't really carry their weight well these days. Most of these properties are already checked via traits in most of the code. It is better to align the system around traits, and improve the performance/cost of traits in general.

Differential Revision: https://reviews.llvm.org/D96088
2021-02-09 12:00:15 -08:00
Tres Popp c2c83e97c3 Revert "Revert "Reorder MLIRContext location in BuiltinAttributes.h""
This reverts commit 511dd4f438 along with
a couple fixes.

Original message:
Now the context is the first, rather than the last input.

This better matches the rest of the infrastructure and makes
it easier to move these types to being declaratively specified.

Phabricator: https://reviews.llvm.org/D96111
2021-02-08 10:39:58 +01:00
Tres Popp 511dd4f438 Revert "Reorder MLIRContext location in BuiltinAttributes.h"
This reverts commit 7827753f98.
2021-02-08 09:32:42 +01:00
Tres Popp 7827753f98 Reorder MLIRContext location in BuiltinAttributes.h
Now the context is the first, rather than the last input.

This better matches the rest of the infrastructure and makes
it easier to move these types to being declaratively specified.

Differential Revision: https://reviews.llvm.org/D96111
2021-02-08 09:28:09 +01:00
Christian Sigg 8827e07aaf Remove deprecated methods from OpState.
Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D95123
2021-01-21 21:29:08 +01:00
River Riddle 6ccf2d62b4 [mlir] Add an interface for Cast-Like operations
A cast-like operation is one that converts from a set of input types to a set of output types. The arity of the inputs may be from 0-N, whereas the arity of the outputs may be anything from 1-N. Cast-like operations are removable in cases where they produce a "no-op", i.e when the input types and output types match 1-1.

Differential Revision: https://reviews.llvm.org/D94831
2021-01-20 16:28:17 -08:00
Christian Sigg c3529a5b08 [mlir] Mark methods from mlir::OpState that just forward to mlir::Operation as deprecated.
The functions will be removed by January 20th.

All call sites within MLIR have been converted in previous changes.

Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D94191
2021-01-07 09:08:47 +01:00
River Riddle fc5cf50e89 [mlir] Remove the MutableDictionaryAttr class
This class used to serve a few useful purposes:
* Allowed containing a null DictionaryAttr
* Provided some simple mutable API around a DictionaryAttr

The first of which is no longer an issue now that there is much better caching support for attributes in general, and a cache in the context for empty dictionaries. The second results in more trouble than it's worth because it mutates the internal dictionary on every action, leading to a potentially large number of dictionary copies. NamedAttrList is a much better alternative for the second use case, and should be modified as needed to better fit it's usage as a DictionaryAttrBuilder.

Differential Revision: https://reviews.llvm.org/D93442
2020-12-17 17:18:42 -08:00
Sean Silva 129d6e554e [mlir] Move `std.tensor_cast` -> `tensor.cast`.
This is almost entirely mechanical.

Differential Revision: https://reviews.llvm.org/D93357
2020-12-17 16:06:56 -08:00
River Riddle 1b97cdf885 [mlir][IR][NFC] Move context/location parameters of builtin Type::get methods to the start of the parameter list
This better matches the rest of the infrastructure, is much simpler, and makes it easier to move these types to being declaratively specified.

Differential Revision: https://reviews.llvm.org/D93432
2020-12-17 13:01:36 -08:00
River Riddle 47364f95e8 [mlir][IR] Move the storage for results to before the Operation instead of after.
Trailing objects are really nice for storing additional data inline with the main class, and is something that we heavily take advantage of for Operation(and many other classes). To get the address of the inline data you need to compute the address by doing some pointer arithmetic taking into account any objects stored before the object you want to access. Most classes keep the count of the number of objects, so this is relatively cheap to compute. This is not the case for results though, which have two different types(inline and trailing) that are not necessarily as cheap to compute as the count for other objects. This revision moves the storage for results to before the operation and stores them in reverse order. This allows for getting results to still be very fast given that they are never iterated directly in order, and also greatly improves the speed when accessing the other trailing objects of an operation(operands/regions/blocks/etc).

This reduced compile time when compiling a decently sized mlir module by about ~400ms, or 2.17s -> 1.76s.

Differential Revision: https://reviews.llvm.org/D92687
2020-12-04 21:01:42 -08:00
River Riddle 09f7a55fad [mlir][Types][NFC] Move all of the builtin Type classes to BuiltinTypes.h
This is part of a larger refactoring the better congregates the builtin structures under the BuiltinDialect. This also removes the problematic "standard" naming that clashes with the "standard" dialect, which is not defined within IR/. A temporary forward is placed in StandardTypes.h to allow time for downstream users to replaced references.

Differential Revision: https://reviews.llvm.org/D92435
2020-12-03 18:02:10 -08:00
River Riddle abfd1a8b3b [mlir][PDL] Add support for PDL bytecode and expose PDL support to OwningRewritePatternList
PDL patterns are now supported via a new `PDLPatternModule` class. This class contains a ModuleOp with the pdl::PatternOp operations representing the patterns, as well as a collection of registered C++ functions for native constraints/creations/rewrites/etc. that may be invoked via the pdl patterns. Instances of this class are added to an OwningRewritePatternList in the same fashion as C++ RewritePatterns, i.e. via the `insert` method.

The PDL bytecode is an in-memory representation of the PDL interpreter dialect that can be efficiently interpreted/executed. The representation of the bytecode boils down to a code array(for opcodes/memory locations/etc) and a memory buffer(for storing attributes/operations/values/any other data necessary). The bytecode operations are effectively a 1-1 mapping to the PDLInterp dialect operations, with a few exceptions in cases where the in-memory representation of the bytecode can be more efficient than the MLIR representation. For example, a generic `AreEqual` bytecode op can be used to represent AreEqualOp, CheckAttributeOp, and CheckTypeOp.

The execution of the bytecode is split into two phases: matching and rewriting. When matching, all of the matched patterns are collected to avoid the overhead of re-running parts of the matcher. These matched patterns are then considered alongside the native C++ patterns, which rewrite immediately in-place via `RewritePattern::matchAndRewrite`,  for the given root operation. When a PDL pattern is matched and has the highest benefit, it is passed back to the bytecode to execute its rewriter.

Differential Revision: https://reviews.llvm.org/D89107
2020-12-01 15:05:50 -08:00
Alex Zinenko 9bb5bff570 [mlir] Add an assertion on creating an Operation with null result types
Null types are commonly used as an error marker. Catch them in the constructor
of Operation if they are present in the result type list, as otherwise this
could lead to further surprising behavior when querying op result types.

Fix AsyncToLLVM and StandardToLLVM that were using null types when constructing
operations.

Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D91770
2020-11-19 22:28:38 +01:00
Sean Silva b4fa28b408 [mlir] Add ElementwiseMappable trait and apply it to std elementwise ops.
This patch adds an `ElementwiseMappable` trait as discussed in the RFC
here:
https://llvm.discourse.group/t/rfc-std-elementwise-ops-on-tensors/2113/23

This trait can power a number of transformations and analyses.
A subsequent patch adds a convert-elementwise-to-linalg pass exhibits
how this trait allows writing generic transformations.
See https://reviews.llvm.org/D90354 for that patch.

This trait slightly changes some verifier messages, but the diagnostics
are usually about as good. I fiddled with the ordering of the trait in
the .td file trait lists to minimize the changes here.

Differential Revision: https://reviews.llvm.org/D90731
2020-11-10 13:44:44 -08:00
River Riddle b870d9ec83 [mlir] Optimize Op definitions and registration to optimize for code size
This revision refactors the base Op/AbstractOperation classes to reduce the amount of generated code size when defining a new operation. The current scheme involves taking the address of functions defined directly on Op and Trait classes. This is problematic because even when these functions are empty/unused we still result in these functions being defined in the main executable. In this revision, we switch to using SFINAE and template type filtering to remove remove functions that are not needed/used. For example, if an operation does not define a custom `print` method we shouldn't define a templated `printAssembly` method for it. The same applies to parsing/folding/verification/etc. This dropped MLIR code size for a large downstream library by ~10%(~1 mb in an opt build).

Differential Revision: https://reviews.llvm.org/D90196
2020-11-02 14:39:43 -08:00
ahmedsabie 7dff6b818b [MLIR] Add idempotent trait folding
This trait simply adds a fold of f(f(x)) = f(x) when an operation is labelled as idempotent

Reviewed By: rriddle, andyly

Differential Revision: https://reviews.llvm.org/D89421
2020-10-16 15:51:04 +00:00
Geoffrey Martin-Noble b49787df9a Remove unused SideEffectInterfaces header
This change removes an unnecessary header introduced in
https://github.com/llvm/llvm-project/commit/c0b3abd19a3e.

Differential Revision: https://reviews.llvm.org/D89347
2020-10-13 15:22:00 -07:00
ahmedsabie c0b3abd19a [MLIR] Add a foldTrait() mechanism to allow traits to define folding and test it with an Involution trait
This is the same diff as https://reviews.llvm.org/D88809/ except side effect
free check is removed for involution and a FIXME is added until the dependency
is resolved for shared builds. The old diff has more details on possible fixes.

Reviewed By: rriddle, andyly

Differential Revision: https://reviews.llvm.org/D89333
2020-10-13 21:26:21 +00:00
James Molloy 8bdbe29519 [mlir] Fix bug in computing operation order
When attempting to compute a differential orderIndex we were calculating the
bailout condition correctly, but then an errant "+ 1" meant the orderIndex we
created was invalid.

Added test.

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D89115
2020-10-09 12:18:52 +01:00
Mehdi Amini 5367a8b67f Revert "[MLIR] Add a foldTrait() mechanism to allow traits to define folding and test it with an Involution trait"
This reverts commit 1ceaffd95a.

The build is broken with  -DBUILD_SHARED_LIBS=ON ; seems like a possible
layering issue to investigate:

tools/mlir/lib/IR/CMakeFiles/obj.MLIRIR.dir/Operation.cpp.o: In function `mlir::MemoryEffectOpInterface::hasNoEffect(mlir::Operation*)':
Operation.cpp:(.text._ZN4mlir23MemoryEffectOpInterface11hasNoEffectEPNS_9OperationE[_ZN4mlir23MemoryEffectOpInterface11hasNoEffectEPNS_9OperationE]+0x9c): undefined reference to `mlir::MemoryEffectOpInterface::getEffects(llvm::SmallVectorImpl<mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect> >&)'
2020-10-09 06:16:42 +00:00
ahmedsabie 1ceaffd95a [MLIR] Add a foldTrait() mechanism to allow traits to define folding and test it with an Involution trait
This change allows folds to be done on a newly introduced involution trait rather than having to manually rewrite this optimization for every instance of an involution

Reviewed By: rriddle, andyly, stephenneuendorffer

Differential Revision: https://reviews.llvm.org/D88809
2020-10-09 03:25:53 +00:00
Rahul Joshi 8893d0816c [MLIR] Change Operation::create() methods to use Value/Type/Block ranges.
- Introduce a new BlockRange class to represent range of blocks (constructible from
  an ArrayRef<Block *> or a SuccessorRange);
- Change Operation::create() methods to use TypeRange for result types, ValueRange for
  operands and BlockRange for successors.

Differential Revision: https://reviews.llvm.org/D86985
2020-09-08 14:19:05 -07:00
Mehdi Amini 01700c45eb Store an Identifier instead of a StringRef for the OperationName inside an AbstractOperation (NFC)
Instead of storing a StringRef, we keep an Identifier which otherwise requires a lock on the context to retrieve.
This will allow to get an Identifier for any registered Operation for "free".

Reviewed By: rriddle

Differential Revision: https://reviews.llvm.org/D86994
2020-09-02 19:10:56 +00:00