Commit Graph

131 Commits

Author SHA1 Message Date
River Riddle 792d1c25e4 Implement value type abstraction for attributes.
This is done by changing Attribute to be a POD interface around an underlying pointer storage and adding in-class support for isa/dyn_cast/cast.

PiperOrigin-RevId: 218764173
2019-03-29 13:39:19 -07:00
Uday Bondhugula 80610c2f49 Introduce Fourier-Motzkin variable elimination + other cleanup/support
- Introduce Fourier-Motzkin variable elimination to eliminate a dimension from
  a system of linear equalities/inequalities. Update isEmpty to use this.
  Since FM is only exact on rational/real spaces, an emptiness check based on
  this is guaranteed to be exact whenever it says the underlying set is empty;
  if it says, it's not empty, there may still be no integer points in it.
  Also, supports a version that computes "dark shadows".

- Test this by checking for "always false" conditionals in if statements.

- Unique IntegerSet's that are small (few constraints, few variables). This
  basically means the canonical empty set and other small sets that are
  likely commonly used get uniqued; allows checking for the canonical empty set
  by pointer. IntegerSet::kUniquingThreshold gives the threshold constraint size
  for uniqui'ing.

- rename simplify-affine-expr -> simplify-affine-structures

Other cleanup

- IntegerSet::numConstraints, AffineMap::numResults are no longer needed;
  remove them.
- add copy assignment operators for AffineMap, IntegerSet.
- rename Invalid() -> Null() on AffineExpr, AffineMap, IntegerSet
- Misc cleanup for FlatAffineConstraints API

PiperOrigin-RevId: 218690456
2019-03-29 13:38:24 -07:00
Lei Zhang 52a0e58bdb Change typedef to using to be consistent across the codebase
Google C++ style guide also prefers using to typedef.

PiperOrigin-RevId: 218541849
2019-03-29 13:37:55 -07:00
Feng Liu 3d7ab2d265 Add support to opaque elements attributes
For some of the constant vector / tesor, if the compiler doesn't need to
interpret their elements content, they can be stored in this class to save the
serialize / deserialize cost.

syntax:

`opaque<` tensor-type `,` opaque-string `>`

opaque-string ::= `0x` [0-9a-fA-F]*
PiperOrigin-RevId: 218399426
2019-03-29 13:36:45 -07:00
Chris Lattner 9eedf6adb1 Replace the "OperationSet" abstraction with a new Dialect abstraction. This is
a step forward because now every AbstractOperation knows which Dialect it is
associated with, enabling things in the future like "constant folding
hooks" which will be important for layering.  This is also a bit nicer on
the registration side of things.

PiperOrigin-RevId: 218104230
2019-03-29 13:34:37 -07:00
Feng Liu c5a3a5e4ca Use APFloat for FloatAttribute
We should be able to represent arbitrary precision Float-point values inside
the IR, so compiler optimizations, such as constant folding can be done
independently on the compiling platform.

This CL also added a new field, AttrValueGetter, to the Attr class definition
for TableGen. This field is used to customize which mlir::Attr getter method to
get the defined PrimitiveType.

PiperOrigin-RevId: 218034983
2019-03-29 13:34:09 -07:00
Feng Liu 03b48999b6 Add support to constant sparse tensor / vector attribute
The SparseElementsAttr uses (COO) Coordinate List encoding to represents a
sparse tensor / vector. Specifically, the coordinates and values are stored as
two dense elements attributes. The first dense elements attribute is a 2-D
attribute with shape [N, ndims], which contains the indices of the elements
with nonzero values in the constant vector/tensor. The second elements
attribute is a 1-D attribute list with shape [N], which supplies the values for
each element in the first elements attribute. ndims is the rank of the
vector/tensor and N is the total nonzero elements.

The syntax is:

`sparse<` (tensor-type | vector-type)`, ` indices-attribute-list, values-attribute-list `>`

Example: a sparse tensor

sparse<vector<3x4xi32>, [[0, 0], [1, 2]], [1, 2]> represents the dense tensor

[[1, 0, 0, 0]
 [0, 0, 2, 0]
 [0, 0, 0, 0]]

PiperOrigin-RevId: 217764319
2019-03-29 13:32:55 -07:00
Feng Liu b5b90e5465 Add support to constant dense vector/tensor attribute.
The syntax of dense vecor/tensor attribute value is

`dense<` (tensor-type | vector-type)`,` attribute-list`>`

and

attribute-list ::= `[` attribute-list (`, ` attribute-list)* `]`.

The construction of the dense vector/tensor attribute takes a vector/tensor
type and a character array as arguments. The size of the input array should be
larger than the size specified by the type argument. It also assumes the
elements of the vector or tensor have been trunked to the data type sizes in
the input character array, so it extends the trunked data to 64 bits when it is
retrieved.

PiperOrigin-RevId: 217762811
2019-03-29 13:32:41 -07:00
Jacques Pienaar d8917d80a8 Fail if operation name contains null char.
The null char is allowed in a string but not in an operation's name, so fail
parsing in the latter case.

PiperOrigin-RevId: 217138049
2019-03-29 13:30:22 -07:00
Jacques Pienaar 826f5c1c04 Avoid leak when parsing fails and BasicBlock has no use/function.
Associate BasicBlocks with the function being parsed to avoid leaks in the case of parse failures. Associating with the function means that we can no longer determine if defined/fwd declared simply by considering if a BasicBlock has an associated function, so track forward declared block references explicitly (this should also allow flagging multiple undeclared fwd references). Split out getting the named block from defining it, in the case of definition move the block to the end of the function.

Also destroy all forward reference placeholders in FunctionParser.

Return parse failure in parseAttributeDict if there is no left brace instead of
asserting.

PiperOrigin-RevId: 217049507
2019-03-29 13:30:06 -07:00
Jacques Pienaar 764fd035b0 Split BuiltinOps out of StandardOps.
* Move Return, Constant and AffineApply out into BuiltinOps;
* BuiltinOps are always registered, while StandardOps follow the same dynamic registration;
* Kept isValidX in MLValue as we don't have a verify on AffineMap so need to keep it callable from Parser (I wanted to move it to be called in verify instead);

PiperOrigin-RevId: 216592527
2019-03-29 13:28:12 -07:00
Nicolas Vasilache b04f881dcb [MLIR] IntegerSet value type
This CL applies the same pattern as AffineMap to IntegerSet: a simple struct
that acts as the storage is allocated in the bump pointer. The IntegerSet is
immutable and accessed everywhere by value.

Note that unlike AffineMap, it is not possible to remove the MLIRContext
parameter when constructing an IntegerSet for now. One possible way to achieve
this would be to add an enum to distinguish between the mathematically empty
set, the universe set and other sets.

This is left for future discussion.

PiperOrigin-RevId: 216545361
2019-03-29 13:27:19 -07:00
Feng Liu 5e3cca906a Add support to constant splat vector/tensor attribute.
This attribute represents a reference to a splat vector or tensor, where all
the elements have the same value. The syntax of the attribute is:

`splat<` (tensor-type | vector-type)`,` attribute-value `>`

PiperOrigin-RevId: 216537997
2019-03-29 13:27:05 -07:00
Chris Lattner fd06c6bc4e Change the representation of an operation name to be either an
AbstractOperation* or an Identifier.  This makes it possible to get to stuff in
AbstractOperation faster than going through a hash table lookup.  This makes
constant folding a bit faster now, but will become more important with
subsequent changes.

PiperOrigin-RevId: 216476772
2019-03-29 13:26:51 -07:00
Feng Liu 84a0c40261 Support `getShape`, `hasStaticShape` and `getDimSize` methods for all the Vector and Tensor Types.
PiperOrigin-RevId: 216447553
2019-03-29 13:26:38 -07:00
Nicolas Vasilache 1d3e7e2616 [MLIR] AffineMap value type
This CL applies the same pattern as AffineExpr to AffineMap: a simple struct
that acts as the storage is allocated in the bump pointer. The AffineMap is
immutable and accessed everywhere by value.

PiperOrigin-RevId: 216445930
2019-03-29 13:26:24 -07:00
Jacques Pienaar 2df03be621 Fix some leak and crash found via fuzzing.
Tried adding a fuzzer target (cl/216378253) and ran into a few problems, and fixing two of these.

PiperOrigin-RevId: 216425403
2019-03-29 13:25:56 -07:00
Nicolas Vasilache 8ebb6ff171 [MLIR] Sketch AffineExpr value type
This CL sketches what it takes for AffineExpr to fully have by-value semantics
and not be a not-so-smart pointer anymore.

This essentially makes the underyling class a simple storage struct and
implements the operations on the value type directly. Since there is no
forwarding of operations anymore, we can full isolate the storage class and
make a hard visibility barrier by moving detail::AffineExpr into
AffineExprDetail.h.

AffineExprDetail.h is only included where storage-related information is
needed.

PiperOrigin-RevId: 216385459
2019-03-29 13:25:42 -07:00
Nicolas Vasilache 6707c7bea1 [MLIR] AffineExpr final cleanups
This CL:
1. performs the global codemod AffineXExpr->AffineXExprClass and
AffineXExprRef -> AffineXExpr;
2. simplifies function calls by removing the redundant MLIRContext parameter;
3. adds missing binary operator versions of scalar op AffineExpr where it
makes sense.

PiperOrigin-RevId: 216242674
2019-03-29 13:25:14 -07:00
Nicolas Vasilache ce2edea135 [MLIR] Cleanup AffineExpr
This CL introduces a series of cleanups for AffineExpr value types:
1. to make it clear that the value types should be used, the pointer
AffineExpr types are put in the detail namespace. Unfortunately, since the
value type operator-> only forwards to the underlying pointer type, we
still
need to expose this in the include file for now;
2. AffineExprKind is ok to use, it thus comes out of detail and thus of
AffineExpr
3. getAffineDimExpr, getAffineSymbolExpr, getAffineConstantExpr are
similarly
extracted as free functions and their naming is mande consistent across
Builder, MLContext and AffineExpr
4. AffineBinaryOpEx::simplify functions are made into static free
functions.
In particular it is moved away from AffineMap.cpp where it does not belong
5. operator AffineExprType is made explicit
6. uses the binary operators everywhere possible
7. drops the pointer usage everywhere outside of AffineExpr.cpp,
MLIRContext.cpp and AsmPrinter.cpp

PiperOrigin-RevId: 216207212
2019-03-29 13:24:45 -07:00
Nicolas Vasilache 4911978f7e [MLIR] Value types for AffineXXXExpr
This CL makes AffineExprRef into a value type.

Notably:
1. drops llvm isa, cast, dyn_cast on pointer type and uses member functions on
the value type. It may be possible to still use classof  (in a followup CL)
2. AffineBaseExprRef aggressively casts constness away: if we mean the type is
immutable then let's jump in with both feet;
3. Drop implicit casts to the underlying pointer type because that always
results in surprising behavior and is not needed in practice once enough
cleanup has been applied.

The remaining negative I see is that we still need to mix operator. and
operator->. There is an ugly solution that forwards the methods but that ends
up duplicating the class hierarchy which I tried to avoid as much as
possible. But maybe it's not that bad anymore since AffineExpr.h would still
contain a single class hierarchy (the duplication would be impl detail in.cpp)

PiperOrigin-RevId: 216188003
2019-03-29 13:24:31 -07:00
Chris Lattner d2d89cbc19 Rename affineint type to index type. The name 'index' may not be perfect, but is better than the old name. Here is some justification:
1) affineint (as it is named) is not a type suitable for general computation (e.g. the multiply/adds in an integer matmul).  It has undefined width and is undefined on overflow.  They are used as the indices for forstmt because they are intended to be used as indexes inside the loop.

2) It can be used in both cfg and ml functions, and in cfg functions.  As you mention, “symbols” are not affine, and we use affineint values for symbols.

3) Integers aren’t affine, the algorithms applied to them can be. :)

4) The only suitable use for affineint in MLIR is for indexes and dimension sizes (i.e. the bounds of those indexes).

PiperOrigin-RevId: 216057974
2019-03-29 13:24:16 -07:00
Nicolas Vasilache b55b407601 [RFC][MLIR] Use AffineExprRef in place of AffineExpr* in IR
This CL starts by replacing AffineExpr* with value-type AffineExprRef in a few
places in the IR. By a domino effect that is pretty telling of the
inconsistencies in the codebase, const is removed where it makes sense.

The rationale is that the decision was concisously made that unique'd types
have pointer semantics without const specifier. This is fine but we should be
consistent. In the end, the only logical invariant is that there should never
be such a thing as a const AffineExpr*, const AffineMap* or const IntegerSet*
in our codebase.

This CL takes a number of shortcuts to killing const with fire, in particular
forcing const AffineExprRef to return the underlying non-const
AffineExpr*. This will be removed once AffineExpr* has disappeared in
containers but for now such shortcuts allow a bit of sanity in this long quest
for cleanups.

The **only** places where const AffineExpr*, const AffineMap* or const
IntegerSet* may still appear is by transitive needs from containers,
comparison operators etc.

There is still one major thing remaining here: figure out why cast/dyn_cast
return me a const AffineXXX*, which in turn requires a bunch of ugly
const_casts. I suspect this is due to the classof
taking const AffineXXXExpr*. I wonder whether this is a side effect of 1., if
it is coming from llvm itself (I'd doubt it) or something else (clattner@?)

In light of this, the whole discussion about const makes total sense to me now
and I would systematically apply the rule that in the end, we should never
have any const XXX in our codebase for unique'd types (assuming we can remove
them all in containers and no additional constness constraint is added on us
from the outside world).

PiperOrigin-RevId: 215811554
2019-03-29 13:23:05 -07:00
Nicolas Vasilache 544f5e7a9b [MLIR] Remove uses of AffineExpr* outside of IR
This CL uniformizes the uses of AffineExprWrap outside of IR.
The public API of AffineExpr builder is modified to only use AffineExprWrap.
A few places access AffineExprWrap.expr, this is only while the API is in
transition to easily keep track (i.e. make expr private and let the compiler
track the errors).

Parser.cpp exhibits patterns that are dependent on nullptr values so
converting it is left for another CL.

PiperOrigin-RevId: 215642005
2019-03-29 13:22:35 -07:00
Uday Bondhugula ec35e51f6d Change loop step to be a positive integral constant
Changing this per discussion on mlir-team. Spec updated.

PiperOrigin-RevId: 214868483
2019-03-29 13:21:13 -07:00
Feng Liu 948dea045b Supports TF Complex64/Complex128 types in the tf/mlir roundtrip pass.
Alternatively, we can defined a TFComplexType with a width parameter in the
mlir, then both types can be converted to the same mlir type with different width (like IntegerType).
We chose to use a direct mapping because there are only two TF Complex types.

PiperOrigin-RevId: 213856651
2019-03-29 13:17:02 -07:00
Feng Liu 5f69643cbf Support TF Variant type in the tf/mlir roundtrip pass.
PiperOrigin-RevId: 213748573
2019-03-29 13:16:18 -07:00
Feng Liu 4bc5dc9602 Handle the TF resource data type in the TF/XLA roundtrip pass.
PiperOrigin-RevId: 213650346
2019-03-29 13:16:03 -07:00
Feng Liu 7e004efae2 Add function attributes for ExtFunction, CFGFunction and MLFunction.
PiperOrigin-RevId: 213540509
2019-03-29 13:15:35 -07:00
Chris Lattner e1257e8978 Change unranked tensor syntax from tensor<??f32> to tensor<*xf32> per
discussion on the list.

PiperOrigin-RevId: 212838226
2019-03-29 13:13:42 -07:00
Chris Lattner a21f2f453d Introduce pretty syntax for shape_cast as discussed on the list last week.
PiperOrigin-RevId: 212823681
2019-03-29 13:13:29 -07:00
Uday Bondhugula a7611790f8 Add misc builder convenience methods for AffineMap's, for statement's.
Use these methods to simplify existing code. Rename getConstantMap
getConstantAffineMap. Move declarations to group similar ones together.

PiperOrigin-RevId: 212814829
2019-03-29 13:13:15 -07:00
Uday Bondhugula 64812a56c7 Extend getConstantTripCount to deal with a larger subset of loop bounds; make loop
unroll/unroll-and-jam more powerful; add additional affine expr builder methods

- use previously added analysis/simplification to infer multiple of unroll
  factor trip counts, making loop unroll/unroll-and-jam more general.

- for loop unroll, support bounds that are single result affine map's with the
  same set of operands. For unknown loop bounds, loop unroll will now work as
  long as trip count can be determined to be a multiple of unroll factor.

- extend getConstantTripCount to deal with single result affine map's with the
  same operands. move it to mlir/Analysis/LoopAnalysis.cpp

- add additional builder utility methods for affine expr arithmetic
  (difference, mod/floordiv/ceildiv w.r.t postitive constant). simplify code to
  use the utility methods.

- move affine analysis routines to AffineAnalysis.cpp/.h from
  AffineStructures.cpp/.h.

- Rename LoopUnrollJam to LoopUnrollAndJam to match class name.

- add an additional simplification for simplifyFloorDiv, simplifyCeilDiv

- Rename AffineMap::getNumOperands() getNumInputs: an affine map by itself does
  not have operands. Operands are passed to it through affine_apply, from loop
  bounds/if condition's, etc., operands are stored in the latter.

This should be sufficiently powerful for now as far as unroll/unroll-and-jam go for TPU
code generation, and can move to other analyses/transformations.

Loop nests like these are now unrolled without any cleanup loop being generated.

  for %i = 1 to 100 {
    // unroll factor 4: no cleanup loop will be generated.
    for %j = (d0) -> (d0) (%i) to (d0) -> (5*d0 + 3) (%i) {
      %x = "foo"(%j) : (affineint) -> i32
    }
  }

  for %i = 1 to 100 {
    // unroll factor 4: no cleanup loop will be generated.
    for %j = (d0) -> (d0) (%i) to (d0) -> (d0 - d mod 4 - 1) (%i) {
      %y = "foo"(%j) : (affineint) -> i32
    }
  }

  for %i = 1 to 100 {
    for %j = (d0) -> (d0) (%i) to (d0) -> (d0 + 128) (%i) {
      %x = "foo"() : () -> i32
    }
  }

TODO(bondhugula): extend this to LoopUnrollAndJam as well in the next CL (with minor
changes).

PiperOrigin-RevId: 212661212
2019-03-29 13:13:00 -07:00
Jacques Pienaar 8ad7e2b8fa Update error message for invalid operand token while parsing operand list.
Previously the error could mislead into thinking it was a parser bug instead of the input being erroneous. Update to make it clearer.

PiperOrigin-RevId: 212271145
2019-03-29 13:12:31 -07:00
Chris Lattner c2f987b664 rework the custom op verifier hooks to use the diagnostic emission
infrastructure, instead of returning a const char*.  This allows custom
formatting and more interesting diagnostics.

This patch regresses the error message quality from the control flow
lowering pass, I'll address this in a subsequent patch.

PiperOrigin-RevId: 212210681
2019-03-29 13:12:18 -07:00
Jacques Pienaar cf9aba2b2b Check for absence of delimiters when delimiters is None and fixed number of operands expected.
Ensure delimiters are absent where not expected. This is only checked in the case where operand count is known. This allows for the currently accepted case where there is a operand list with no delimiter and variable number of operands (which could be empty), followed by a delimited operand list.

PiperOrigin-RevId: 212202064
2019-03-29 13:12:03 -07:00
Jacques Pienaar d101fb937b Return error status when number of operands don't match while parsing.
Previously an error would be emitted but parsing would continue as false was being returned.

PiperOrigin-RevId: 212192167
2019-03-29 13:11:49 -07:00
Jacques Pienaar 9afa796d42 Change SourgeMgr to const reference in Parser/Lexer.
SourceMgr is not be mutated during parsing/lexing.

PiperOrigin-RevId: 212145759
2019-03-29 13:11:35 -07:00
Chris Lattner 348f31a4fa Add location specifier to MLIR Functions, and:
- Compress the identifier/kind of a Function into a single word.
 - Eliminate otherFailure from verifier now that we always have a location
 - Eliminate the error string from the verifier now that we always have
   locations.
 - Simplify the parser's handling of fn forward references, using the location
   tracked by the function.

PiperOrigin-RevId: 211985101
2019-03-29 13:10:55 -07:00
Jacques Pienaar b7fc834856 Add parseSourceString method to make it easy for clients to parse a string to a module.
PiperOrigin-RevId: 211354628
2019-03-29 13:09:04 -07:00
Chris Lattner 6dc2a34dcf Continue revising diagnostic handling to simplify and generalize it, and improve related infra.
- Add a new -verify mode to the mlir-opt tool that allows writing test cases
   for optimization and other passes that produce diagnostics.
 - Refactor existing the -check-parser-errors flag to mlir-opt into a new
   -split-input-file option which is orthogonal to -verify.
 - Eliminate the special error hook the parser maintained and use the standard
   MLIRContext's one instead.
 - Enhance the default MLIRContext error reporter to print file/line/col of
   errors when it is available.
 - Add new createChecked() methods to the builder that create ops and invoke
   the verify hook on them, use this to detected unhandled code in the
   RaiseControlFlow pass.
 - Teach mlir-opt about expected-error @+, it previously only worked with @-

PiperOrigin-RevId: 211305770
2019-03-29 13:08:51 -07:00
Tatiana Shpeisman 1a56ee7093 Implement operands for the 'if' statement.
This CL also includes two other minor changes:
- change the implemented syntax from 'if (cond)' to 'if cond', as specified by MLIR spec.
- a minor fix to the implementation of the ForStmt.

PiperOrigin-RevId: 210618122
2019-03-29 13:07:16 -07:00
Chris Lattner adf48e1bd2 Introduce a new Location abstraction to represent location data in a structured
(and more useful) way rather than hacking up a pile of attributes for it.  In
the future this will grow to represent inlined locations, fusion cases etc, but
for now we start with simple Unknown and File/Line/Col locations.  NFC.

PiperOrigin-RevId: 210485775
2019-03-29 13:06:49 -07:00
Nicolas Vasilache a124e9c4a5 Avoid hardcoded 4096 constant
This commit creates a static constexpr limit for the IntegerType
bitwidth and uses it. The check had to be moved because Token is
not aware of IR/Type and it was a sign the abstraction leaked:
bitwidth limit is not a property of the Token but of the IntegerType.

Added a positive and a negative test at the limit.

PiperOrigin-RevId: 210388192
2019-03-29 13:06:36 -07:00
Nicolas Vasilache 6cc9786c3e Uniformize access pattern to state.
We seem to be using *& quite consistently across the codebase.
Replacing 2 occurences of **.

With this, `grep -R "\*\*" .` does not return instances of
accesses  to state anymore.

PiperOrigin-RevId: 210385345
2019-03-29 13:06:22 -07:00
Nicolas Vasilache b70d3d662e Remove dead declaration
Stumbled upon this while I was reading code

PiperOrigin-RevId: 210385303
2019-03-29 13:06:09 -07:00
Tatiana Shpeisman d32a28c520 Implement operands for the lower and upper bounds of the for statement.
This revamps implementation of the loop bounds in the ForStmt, using general representation that supports operands. The frequent case of constant bounds is supported
via special access methods.

This also includes:
- Operand iterators for the Statement class.
- OpPointer::is() method to query the class of the Operation.
- Support for the bound shorthand notation parsing and printing.
- Validity checks for the bound operands used as dim ids and symbols

I didn't mean this CL to be so large. It just happened this way, as one thing led to another.

PiperOrigin-RevId: 210204858
2019-03-29 13:05:16 -07:00
Chris Lattner dfc58848e3 Two unrelated API cleanups: remove the location processing stuff from custom op
parser hooks, as it has been subsumed by a simpler and cleaner mechanism.
Second, remove the "Inst" suffixes from a few methods in CFGFuncBuilder since
they are redundant and this is inconsistent with the other builders.  NFC.

PiperOrigin-RevId: 210006263
2019-03-29 13:04:47 -07:00
Chris Lattner 956e0f7e21 Push location information more tightly into the IR, providing space for every
operation and statement to have a location, and make it so a location is
required to be specified whenever you make one (though a null location is still
allowed).  This is to encourage compiler authors to propagate loc info
properly, allowing our failability story to work well.

This is still a WIP - it isn't clear if we want to continue abusing Attribute
for location information, or whether we should introduce a new class heirarchy
to do so.  This is good step along the way, and unblocks some of the tf/xla
work that builds upon it.

PiperOrigin-RevId: 210001406
2019-03-29 13:04:33 -07:00
Chris Lattner d42ecea381 Clean up the op builder APIs, and simplify the implementation of ops by making
OperationState contain a context and have the generic builder mechanics handle
the job of initializing the OperationState and setting the op name.  NFC.

PiperOrigin-RevId: 209869948
2019-03-29 13:04:06 -07:00