Alex Zinenko [Fri, 22 Feb 2019 15:45:55 +0000 (07:45 -0800)]
Document the conversion into the LLVM IR dialect
Add a documentation page on the key points of the conversion to LLVM IR. This
focuses on the aspects of conversion that are relevant for integration of the
LLVM IR dialect (and produced LLVM IR that is mostly a one-to-one translation)
into other projects. In particular, it describes the type conversion rules and
the memref model supporting dynamic sizes.
PiperOrigin-RevId:
235190772
Brian Patton [Fri, 22 Feb 2019 09:02:24 +0000 (01:02 -0800)]
Add a test example of calling a builtin function.
PiperOrigin-RevId:
235149430
Alex Zinenko [Fri, 22 Feb 2019 09:00:25 +0000 (01:00 -0800)]
Add documentation for the LLVM IR dialect
The LLVM IR pass was bootstrapped without user documentation, following LLVM's
language reference and existing conversions between MLIR standard operations
and LLVM IR instructions. Provide concise documentation of the LLVM IR dialect
operations. This documentation does not describe the semantics of the
operations, which should match that of LLVM IR, but highlights the structural
differences in operation definitions, in particular using attributes instead of
constant-only values. It also describes pseudo-operations that exist only to
make the LLVM IR dialect self-contained within MLIR.
While it could have been possible to generate operation description from
TableGen, this opts for a more concise format where groups of related
operations are described together.
PiperOrigin-RevId:
235149136
River Riddle [Fri, 22 Feb 2019 02:01:09 +0000 (18:01 -0800)]
Define a PassID class to use when defining a pass. This allows for the type used for the ID field to be self documenting. It also allows for the compiler to know the set alignment of the ID object, which is useful for storing pointer identifiers within llvm data structures.
PiperOrigin-RevId:
235107957
Alex Zinenko [Thu, 21 Feb 2019 14:30:53 +0000 (06:30 -0800)]
Lower standard DivF and RemF operations to the LLVM IR dialect
Add support for lowering DivF and RemF to LLVM::FDiv and LLMV::FRem
respectively. The lowering is a trivial one-to-one transformation.
The corresponding operations already existed in the LLVM IR dialect and can be
lowered to the LLVM IR proper. Add the necessary tests for scalar and vector
forms.
PiperOrigin-RevId:
234984608
Sergei Lebedev [Thu, 21 Feb 2019 11:09:51 +0000 (03:09 -0800)]
Exposed division and remainder operations in EDSC
This change introduces three new operators in EDSC: Div (also exposed
via Expr.__div__ aka /) -- floating-point division, FloorDiv and CeilDiv
for flooring/ceiling index division.
The lowering to LLVM will be implemented in b/
124872679.
PiperOrigin-RevId:
234963217
Alex Zinenko [Thu, 21 Feb 2019 10:36:51 +0000 (02:36 -0800)]
EDSC: support call instructions
Introduce support for binding MLIR functions as constant expressions. Standard
constant operation supports functions as possible constant values.
Provide C APIs to look up existing named functions in an MLIR module and expose
them to the Python bindings. Provide Python bindings to declare a function in
an MLIR module without defining it and to add a definition given a function
declaration. These declarations are useful when attempting to link MLIR
modules with, e.g., the standard library.
Introduce EDSC support for direct and indirect calls to other MLIR functions.
Internally, an indirect call is always emitted to leverage existing support for
delayed construction of MLIR Values using EDSC Exprs. If the expression is
bound to a constant function (looked up or declared beforehand), MLIR constant
folding will be able to replace an indirect call by a direct call. Currently,
only zero- and one-result functions are supported since we don't have support
for multi-valued expressions in EDSC.
Expose function calling interface to Python bindings on expressions by defining
a `__call__` function accepting a variable number of arguments.
PiperOrigin-RevId:
234959444
Uday Bondhugula [Wed, 20 Feb 2019 22:12:21 +0000 (14:12 -0800)]
Update / cleanup pass documentation + Langref alloc examples
PiperOrigin-RevId:
234866323
Jacques Pienaar [Wed, 20 Feb 2019 20:01:42 +0000 (12:01 -0800)]
Fix unused errors in opt build.
PiperOrigin-RevId:
234841678
Uday Bondhugula [Wed, 20 Feb 2019 19:54:35 +0000 (11:54 -0800)]
Print debug message better + switch a dma-generate cl opt to uint64_t
PiperOrigin-RevId:
234840316
Uday Bondhugula [Wed, 20 Feb 2019 19:02:25 +0000 (11:02 -0800)]
Fix for getMemRefSizeInBytes: unsigned -> uint64_t
PiperOrigin-RevId:
234829637
Jacques Pienaar [Wed, 20 Feb 2019 18:50:26 +0000 (10:50 -0800)]
Create OpTrait base class & allow operation predicate OpTraits.
* Introduce a OpTrait class in C++ to wrap the TableGen definition;
* Introduce PredOpTrait and rename previous usage of OpTrait to NativeOpTrait;
* PredOpTrait allows specifying a trait of the operation by way of predicate on the operation. This will be used in future to create reusable set of trait building blocks in the definition of operations. E.g., indicating whether to operands have the same type and allowing locally documenting op requirements by trait composition.
- Some of these building blocks could later evolve into known fixed set as LLVMs backends do, but that can be considered with more data.
* Use the modelling to address one verify TODO in a very local manner.
This subsumes the current custom verify specification which will be removed in a separate mechanical CL.
PiperOrigin-RevId:
234827169
Ben Vanik [Wed, 20 Feb 2019 17:22:56 +0000 (09:22 -0800)]
Adding -mlir-print-internal-attributes to print attributes with ':' prefixes.
This enables lit testing of passes that add internal attributes.
PiperOrigin-RevId:
234809949
Alex Zinenko [Wed, 20 Feb 2019 16:08:16 +0000 (08:08 -0800)]
Allow Builder to create function-type constants
A recent change made ConstantOp::build accept a NumericAttr or assert that a
generic Attribute is in fact a NumericAttr. The rationale behind the change
was that NumericAttrs have a type that can be used as the result type of the
constant operation. FunctionAttr also has a type, and it is valid to construct
function-typed constants as exercised by the parser.mlir test. Relax
ConstantOp::build back to take a generic Attribute. In the overload that only
takes an attribute, assert that the Attribute is either a NumericAttr or a
FunctionAttr, because it is necessary to extract the type. In the overload
that takes both type type and the attribute, delegate the attribute type
checking to ConstantOp::verify to prevent non-Builder-based Op construction
mechanisms from creating invalid IR.
PiperOrigin-RevId:
234798569
Alex Zinenko [Wed, 20 Feb 2019 15:08:50 +0000 (07:08 -0800)]
EDSC: emit composed affine maps again
The recent rework of MLIREmitter switched to using the generic call to
`builder.createOperation` from OperationState instead of individual customized
calls to `builder.create<>`. As a result, regular non-composed affine apply
operations where emitted. Introduce a special case in Expr::build to always
create composed affine maps instead, as it used to be the case before the
rework.
Such special-casing goes against the idea of EDSC generality and extensibility.
Instead, we should consider declaring the composed form canonical for
affine.apply operations and using the builder support for creating operations
and canonicalizing them immediately (ongoing effort).
PiperOrigin-RevId:
234790129
Alex Zinenko [Wed, 20 Feb 2019 14:54:53 +0000 (06:54 -0800)]
EDSC: introduce min/max only usable inside for upper/lower bounds of a loop
Introduce a type-safe way of building a 'for' loop with max/min bounds in EDSC.
Define new types MaxExpr and MinExpr in C++ EDSC API and expose them to Python
bindings. Use values of these type to construct 'for' loops with max/min in
newly introduced overloads of the `edsc::For` factory function. Note that in C
APIs, we still must expose MaxMinFor as a different function because C has no
overloads. Also note that MaxExpr and MinExpr do _not_ derive from Expr
because they are not allowed to be used in a regular Expr context (which may
produce `affine.apply` instructions not expecting `min` or `max`).
Factory functions `Min` and `Max` in Python can be further overloaded to
produce chains of comparisons and selects on non-index types. This is not
trivial in C++ since overloaded functions cannot differ by the return type only
(`MaxExpr` or `Expr`) and making `MaxExpr` derive from `Expr` defies the
purpose of type-safe construction.
PiperOrigin-RevId:
234786131
Alex Zinenko [Wed, 20 Feb 2019 14:54:36 +0000 (06:54 -0800)]
EDSC: support multi-expression loop bounds
MLIR supports 'for' loops with lower(upper) bound defined by taking a
maximum(minimum) of a list of expressions, but does not have first-class affine
constructs for the maximum(minimum). All these expressions must have affine
provenance, similarly to a single-expression bound. Add support for
constructing such loops using EDSC. The expression factory function is called
`edsc::MaxMinFor` to (1) highlight that the maximum(minimum) operation is
applied to the lower(upper) bound expressions and (2) differentiate it from a
`edsc::For` that creates multiple perfectly nested loops (and should arguably
be called `edsc::ForNest`).
PiperOrigin-RevId:
234785996
Alex Zinenko [Wed, 20 Feb 2019 09:54:07 +0000 (01:54 -0800)]
EDSC: create constants as expressions
Introduce a functionality to create EDSC expressions from typed constants.
This complements the current functionality that uses "unbound" expressions and
binds them to a specific constant before emission. It comes in handy in cases
where we want to check if something is a constant early during construciton
rather than late during emission, for example multiplications and divisions in
affine expressions. This is also consistent with MLIR vision of constants
being defined by an operation (rather than being special kinds of values in the
IR) by exposing this operation as EDSC expression.
PiperOrigin-RevId:
234758020
Nicolas Vasilache [Wed, 20 Feb 2019 08:41:42 +0000 (00:41 -0800)]
[EDSC] Fix Stmt::operator= and allow DimOp in For loops
This CL fixes 2 recent issues with EDSCs:
1. the type of the LHS in Stmt::operator=(Expr rhs) should be the same as the (asserted unique) return type;
2. symbols coming from DimOp should be admissible as lower / upper bounds in For
The relevant tests are added.
PiperOrigin-RevId:
234750249
Uday Bondhugula [Wed, 20 Feb 2019 02:17:19 +0000 (18:17 -0800)]
Extend/improve getSliceBounds() / complete TODO + update unionBoundingBox
- compute slices precisely where the destination iteration depends on multiple source
iterations (instead of over-approximating to the whole source loop extent)
- update unionBoundingBox to deal with input with non-matching symbols
- reenable disabled backend test case
PiperOrigin-RevId:
234714069
River Riddle [Wed, 20 Feb 2019 01:17:46 +0000 (17:17 -0800)]
NFC: Refactor the files related to passes.
* PassRegistry is split into its own source file.
* Pass related files are moved to a new library 'Pass'.
PiperOrigin-RevId:
234705771
Uday Bondhugula [Tue, 19 Feb 2019 18:33:41 +0000 (10:33 -0800)]
DMA placement update - hoist loops invariant DMAs
- hoist DMAs past all loops immediately surrounding the region that the latter
is invariant on - do this at DMA generation time itself
PiperOrigin-RevId:
234628447
Nicolas Vasilache [Tue, 19 Feb 2019 18:27:04 +0000 (10:27 -0800)]
[EDSC] Remove dead code in MLIREmitter.cpp
cl/
234609882 made EDSCs typed on construction (instead of typed on emission).
This CL cleans up some leftover dead code.
PiperOrigin-RevId:
234627105
Uday Bondhugula [Tue, 19 Feb 2019 18:26:53 +0000 (10:26 -0800)]
Update pass documentation + improve/fix some comments
- add documentation for passes
- improve / fix outdated doc comments
PiperOrigin-RevId:
234627076
River Riddle [Tue, 19 Feb 2019 17:33:11 +0000 (09:33 -0800)]
Add a generic pattern matcher for matching constant values produced by an operation with zero operands and a single result.
PiperOrigin-RevId:
234616691
Alex Zinenko [Tue, 19 Feb 2019 17:08:59 +0000 (09:08 -0800)]
EDSC: clean up type casting mechanism
Originally, edsc::Expr had a long enum edsc::ExprKind with all supported types
of operations. Recent Expr extensibility support removed the need to specify
supported types in advance. Replace the no-longer-used blocks of enum values
reserved for unary/binary/ternary/variadic expressions with simple values (it
is still useful to know if an expression is, e.g., binary to access it through
a simpler API).
Furthermore, wrap string-comparison now used to identify specific ops into an
`Expr::is_op<>` function template, that acts similarly to `Instruction::isa<>`.
Introduce `{Unary,Binary,Ternary,Variadic}Expr::make<> ` function template that
creates a Expression emitting the MLIR Op specified as template argument.
PiperOrigin-RevId:
234612916
Alex Zinenko [Tue, 19 Feb 2019 16:51:52 +0000 (08:51 -0800)]
EDSC: make Expr typed and extensible
Expose the result types of edsc::Expr, which are now stored for all types of
Exprs and not only for the variadic ones. Require return types when an Expr is
constructed, if it will ever have some. An empty return type list is
interpreted as an Expr that does not create a value (e.g. `return` or `store`).
Conceptually, all edss::Exprs are now typed, with the type being a (potentially
empty) tuple of return types. Unbound expressions and Bindables must now be
constructed with a specific type they will take. This makes EDSC less
evidently type-polymorphic, but we can still write generic code such as
Expr sumOfSquares(Expr lhs, Expr rhs) { return lhs * lhs + rhs * rhs; }
and use it to construct different typed expressions as
sumOfSquares(Bindable(IndexType::get(ctx)), Bindable(IndexType::get(ctx)));
sumOfSquares(Bindable(FloatType::getF32(ctx)),
Bindable(FloatType::getF32(ctx)));
On the positive side, we get the following.
1. We can now perform type checking when constructing Exprs rather than during
MLIR emission. Nevertheless, this is still duplicates the Op::verify()
until we can factor out type checking from that.
2. MLIREmitter is significantly simplified.
3. ExprKind enum is only used for actual kinds of expressions. Data structures
are converging with AbstractOperation, and the users can now create a
VariadicExpr("canonical_op_name", {types}, {exprs}) for any operation, even
an unregistered one without having to extend the enum and make pervasive
changes to EDSCs.
On the negative side, we get the following.
1. Typed bindables are more verbose, even in Python.
2. We lose the ability to do print debugging for higher-level EDSC abstractions
that are implemented as multiple MLIR Ops, for example logical disjunction.
This is the step 2/n towards making EDSC extensible.
***
Move MLIR Op construction from MLIREmitter::emitExpr to Expr::build since Expr
now has sufficient information to build itself.
This is the step 3/n towards making EDSC extensible.
Both of these strive to minimize the amount of irrelevant changes. In
particular, this introduces more complex pretty-printing for affine and binary
expression to make sure tests continue to pass. It also relies on string
comparison to identify specific operations that an Expr produces.
PiperOrigin-RevId:
234609882
Lei Zhang [Tue, 19 Feb 2019 15:15:59 +0000 (07:15 -0800)]
[TableGen] Support using Variadic<Type> in results
This CL extended TableGen Operator class to provide accessors for information on op
results.
In OpDefinitionGen, added checks to make sure only the last result can be variadic,
and adjusted traits and builders generation to consider variadic results.
PiperOrigin-RevId:
234596124
Alex Zinenko [Tue, 19 Feb 2019 08:53:16 +0000 (00:53 -0800)]
EDSC: introduce support for blocks
EDSC currently implement a block as a statement that is itself a list of
statements. This suffers from two modeling problems: (1) these blocks are not
addressable, i.e. one cannot create an instruction where thus constructed block
is a successor; (2) they support block nesting, which is not supported by MLIR
blocks. Furthermore, emitting such "compound statement" (misleadingly named
`Block` in Python bindings) does not actually produce a new Block in the IR.
Implement support for creating actual IR Blocks in EDSC. In particular, define
a new StmtBlock EDSC class that is neither an Expr nor a Stmt but contains a
list of Stmts. Additionally, StmtBlock may have (early-) typed arguments.
These arguments are Bindable expressions that can be used inside the block.
Provide two calls in the MLIREmitter, `emitBlock` that actually emits a new
block and `emitBlockBody` that only emits the instructions contained in the
block without creating a new block. In the latter case, the instructions must
not use block arguments.
Update Python bindings to make it clear when instruction emission happens
without creating a new block.
PiperOrigin-RevId:
234556474
Lei Zhang [Mon, 18 Feb 2019 15:21:12 +0000 (07:21 -0800)]
[TableGen] Fix discrepancy between parameter meaning and code logic
The parameter to emitStandaloneParamBuilder() was renamed from hasResultType to
isAllSameType, which is the opposite boolean value. The logic should be changed
to make them consistent.
Also re-ordered some methods in Operator. And few other tiny improvements.
PiperOrigin-RevId:
234478316
Uday Bondhugula [Sat, 16 Feb 2019 01:54:49 +0000 (17:54 -0800)]
Misc. updates/fixes to analysis utils used for DMA generation; update DMA
generation pass to make it drop certain assumptions, complete TODOs.
- multiple fixes for getMemoryFootprintBytes
- pass loopDepth correctly from getMemoryFootprintBytes()
- use union while computing memory footprints
- bug fixes for addAffineForOpDomain
- take into account loop step
- add domains of other loop IVs in turn that might have been used in the bounds
- dma-generate: drop assumption of "non-unit stride loops being tile space loops
and skipping those and recursing to inner depths"; DMA generation is now purely
based on available fast mem capacity and memory footprint's calculated
- handle memory region compute failures/bailouts correctly from dma-generate
- loop tiling cleanup/NFC
- update some debug and error messages to use emitNote/emitError in
pipeline-data-transfer pass - NFC
PiperOrigin-RevId:
234245969
MLIR Team [Sat, 16 Feb 2019 01:12:19 +0000 (17:12 -0800)]
Support fusing producer loop nests which write to a memref which is live out, provided that the write region of the consumer loop nest to the same memref is a super set of the producer's write region.
PiperOrigin-RevId:
234240958
Alex Zinenko [Fri, 15 Feb 2019 19:07:23 +0000 (11:07 -0800)]
EDSC: properly construct FunctionTypes
The existing implementation of makeFunctionType in EDSC contains a bug: the
array of input types is overwritten using output types passed as arguments and
the array of output types is never filled in. This leads to all sorts of
incorrect memory behavior. Fill in the array of output types using the proper
argument.
PiperOrigin-RevId:
234177221
Alex Zinenko [Fri, 15 Feb 2019 18:50:28 +0000 (10:50 -0800)]
ExecutionEngine: provide utils for running CLI-configured LLVM passes
A recent change introduced a possibility to run LLVM IR transformation during
JIT-compilation in the ExecutionEngine. Provide helper functions that
construct IR transformers given either clang-style optimization levels or a
list passes to run. The latter wraps the LLVM command line option parser to
parse strings rather than actual command line arguments. As a result, we can
run either of
mlir-cpu-runner -O3 input.mlir
mlir-cpu-runner -some-mlir-pass -llvm-opts="-llvm-pass -other-llvm-pass"
to combine different transformations. The transformer builder functions are
provided as a separate library that depends on LLVM pass libraries unlike the
main execution engine library. The library can be used for integrating MLIR
execution engine into external frameworks.
PiperOrigin-RevId:
234173493
MLIR Team [Fri, 15 Feb 2019 17:32:18 +0000 (09:32 -0800)]
LoopFusion: perform a series of loop interchanges to increase the loop depth at which slices of producer loop nests can be fused into constumer loop nests.
*) Adds utility to LoopUtils to perform loop interchange of two AffineForOps.
*) Adds utility to LoopUtils to sink a loop to a specified depth within a loop nest, using a series of loop interchanges.
*) Computes dependences between all loads and stores in the loop nest, and classifies each loop as parallel or sequential.
*) Computes loop interchange permutation required to sink sequential loops (and raise parallel loop nests) while preserving relative order among them.
*) Checks each dependence against the permutation to make sure that dependences would not be violated by the loop interchange transformation.
*) Calls loop interchange in LoopFusion pass on consumer loop nests before fusing in producers, sinking loops with loop carried dependences deeper into the consumer loop nest.
*) Adds and updates related unit tests.
PiperOrigin-RevId:
234158370
Lei Zhang [Fri, 15 Feb 2019 17:01:05 +0000 (09:01 -0800)]
[TableGen] Rename Operand to Value to prepare sharing between operand and result
We specify op operands and results in TableGen op definition using the same syntax.
They should be modelled similarly in TableGen driver wrapper classes.
PiperOrigin-RevId:
234153332
Alex Zinenko [Fri, 15 Feb 2019 14:25:30 +0000 (06:25 -0800)]
LLVM dialect conversion and target: support indirect calls
Add support for converting MLIR `call_indirect` instructions to the LLVM IR
dialect. In LLVM IR, the same instruction is used for direct and indirect
calls. In the dialect, we have `llvm.call` and `llvm.call0` to work around the
absence of the void type in MLIR. For direct calls, the callee is stored as
instruction attribute. Use the same pair of instructions for indirect calls by
omitting the callee attribute. In the MLIR to LLVM IR translator, check the
presence of attribute to decide whether to construct a direct or an indirect
call using different LLVM IR Builder functions.
Add support for converting constants of function type to the LLVM IR dialect
and for translating them to the LLVM IR proper. The `llvm.constant` operation
works similarly to other types: its attribute has MLIR function type but the
value it produces has LLVM IR function type wrapped in the dialect type. While
lowering, look up the pointer to the converted function in the corresponding
mapping.
PiperOrigin-RevId:
234132351
Alex Zinenko [Fri, 15 Feb 2019 13:06:15 +0000 (05:06 -0800)]
Dialect conversion: decouple function signature conversion from type conversion
Function types are built-in in MLIR and affect the validity of the IR itself.
However, advanced target dialects such as the LLVM IR dialect may include
custom function types. Until now, dialect conversion was expecting function
types not to be converted to the custom type: although the signatures was
allowed to change, the outer type must have been an mlir::FunctionType. This
effectively prevented dialect conversion from creating instructions that
operate on values of the custom function type.
Dissociate function signature conversion from general type conversion.
Function signature conversion must still produce an mlir::FunctionType and is
used in places where built-in types are required to make IR valid. General
type conversion is used for SSA values, including function and block arguments
and function results.
Exercise this behavior in the LLVM IR dialect conversion by converting function
types to LLVM IR function pointer types. The pointer to a function is chosen
to provide consistent lowering of higher-order functions: while it is possible
to have a value of function type, it is not possible to create a function type
accepting a returning another function type.
PiperOrigin-RevId:
234124494
MLIR Team [Thu, 14 Feb 2019 21:25:46 +0000 (13:25 -0800)]
Update direction vector computation to use FlatAffineConstraints::getLower/UpperBounds.
Update FlatAffineConstraints::getLower/UpperBounds to project to the identifier for which bounds are being computed. This change enables computing bounds on an identifier which were previously dependent on the bounds of another identifier.
PiperOrigin-RevId:
234017514
Uday Bondhugula [Thu, 14 Feb 2019 20:24:18 +0000 (12:24 -0800)]
Add -tile-sizes command line option for loop tiling; clean up cl options for
for dma-generate, loop-unroll.
- add -tile-sizes command line option for loop tiling to specify different tile
sizes for loops in a band
- clean up command line options for loop-unroll, dma-generate (remove
cl::hidden)
PiperOrigin-RevId:
234006232
Lei Zhang [Thu, 14 Feb 2019 19:01:08 +0000 (11:01 -0800)]
[TFLite] Fuse AddOp into preceding convolution ops
If we see an add op adding a constant value to a convolution op with constant
bias, we can fuse the add into the convolution op by constant folding the
bias and the add op's constant operand.
This CL also removes dangling RewriterGen check that prevents us from using
nested DAG nodes in result patterns, which is already supported.
PiperOrigin-RevId:
233989654
Lei Zhang [Thu, 14 Feb 2019 18:54:50 +0000 (10:54 -0800)]
[TableGen] Use deduced result types for build() of suitable ops
For ops with the SameOperandsAndResultType trait, we know that all result types
should be the same as the first operand's type. So we can generate a build()
method without requiring result types as parameters and also invoke this method
when constructing such ops during expanding rewrite patterns.
Similarly for ops have broadcast behavior, we can define build() method to use
the deduced type as the result type. So we can also calling into this build()
method when constructing ops in RewriterGen.
PiperOrigin-RevId:
233988307
Alex Zinenko [Thu, 14 Feb 2019 13:18:18 +0000 (05:18 -0800)]
EDSC: fix unused-wariable warning when compiling without assertions
In LowerEDSCTestPass, there are two range-for loops that only do assertions on
the loop variable. With assertions disabled, the variable becomes unused and
triggers a warning promoted to error. Cast it to void in the loop to supress
the warning.
PiperOrigin-RevId:
233936171
Alex Zinenko [Wed, 13 Feb 2019 23:30:24 +0000 (15:30 -0800)]
Reimplement LLVM IR translation to use the MLIR LLVM IR dialect
Original implementation of the translation from MLIR to LLVM IR operated on the
Standard+BuiltIn dialect, with a later addition of the SuperVector dialect.
This required the translation to be aware of a potetially large number of other
dialects as the infrastructure extended. With the recent introduction of the
LLVM IR dialect into MLIR, the translation can be switched to only translate
the LLVM IR dialect, and the translation of the operations becomes largely
mechanical.
The reimplementation of the translator follows the lines of the original
translator in function and basic block conversion. In particular, block
arguments are converted to LLVM IR PHI nodes, which are connected to their
sources after all blocks of a function had been converted. Thanks to LLVM IR
types being wrapped in the MLIR LLVM dialect type, type conversion is
simplified to only convert function types, all other types are simply
unwrapped. Individual instructions are constructed using the LLVM IRBuilder,
which has a great potential for being table-generated from the LLVM IR dialect
operation definitions.
The input of the test/Target/llvmir.mlir is updated to use the MLIR LLVM IR
dialect. While it is now redundant with the dialect conversion test, the point
of the exercise is to guarantee exactly the same LLVM IR is emitted. (Only the
name of the allocation function is changed from `__mlir_alloc` to `alloc` in
the CHECK lines.) It will be simplified in a follow-up commit.
PiperOrigin-RevId:
233842306
Jacques Pienaar [Wed, 13 Feb 2019 22:30:40 +0000 (14:30 -0800)]
Add pattern constraints.
Enable matching pattern only if constraint is met. Start with type constraints and more general C++ constraints.
PiperOrigin-RevId:
233830768
Alex Zinenko [Wed, 13 Feb 2019 08:54:55 +0000 (00:54 -0800)]
EDSC: unify Expr storage
EDSC expressions evolved to have different types of underlying storage.
Separate classes are used for unary, binary, ternary and variadic expressions.
The latter covers all the needs of the three special cases. Remove these
special cases and use a single ExprStorage class everywhere while maintaining
the same APIs at the Expr level (ExprStorage is an internal implementation
class).
This is step 1/n to converging EDSC expressions and Ops and making EDSCs
support custom operations.
PiperOrigin-RevId:
233704912
Alex Zinenko [Tue, 12 Feb 2019 21:47:25 +0000 (13:47 -0800)]
LLVM IR Dialect: port DimOp lowering from the translator
DimOp is converted to a constant LLVM IR dialect operation for static
dimensions and to an access to the dynamic size info stored in the memref
descriptor for the dynamic dimensions. This behavior is consistent with the
existing mlir-translator.
This completes the porting of MLIR -> LLVM lowering to the dialect conversion
infrastructure.
PiperOrigin-RevId:
233665634
River Riddle [Tue, 12 Feb 2019 20:55:40 +0000 (12:55 -0800)]
Add langref descriptions for the attribute values supported in MLIR.
PiperOrigin-RevId:
233661338
Uday Bondhugula [Tue, 12 Feb 2019 20:08:01 +0000 (12:08 -0800)]
Generate dealloc's for alloc's of pipeline-data-transfer
- for the DMA transfers being pipelined through double buffering, generate
deallocs for the double buffers being alloc'ed
This change is along the lines of cl/
233502632. We initially wanted to experiment with
scoped allocation - so the deallocation's were usually not necessary; however, they are
needed even with scoped allocations in some situations - for eg. when the enclosing loop
gets unrolled. The dealloc serves as an end of lifetime marker.
PiperOrigin-RevId:
233653463
River Riddle [Tue, 12 Feb 2019 19:08:04 +0000 (11:08 -0800)]
Make IndexType a standard type instead of a builtin. This also cleans up some unnecessary factory methods on the Type class.
PiperOrigin-RevId:
233640730
Alex Zinenko [Tue, 12 Feb 2019 17:31:20 +0000 (09:31 -0800)]
LLVM IR Dialect: add select op and lower standard select to it
This is a similar one-to-one mapping.
PiperOrigin-RevId:
233621006
Alex Zinenko [Tue, 12 Feb 2019 11:39:24 +0000 (03:39 -0800)]
EDSC: move Expr and Stmt construction operators to a namespace
In the current state, edsc::Expr and edsc::Stmt overload operators to construct
other Exprs and Stmts. This includes some unconventional overloads of the
`operator==` to create a comparison expression and of the `operator!` to create
a negation expression. This situation could lead to unpleasant surprises where
the code does not behave like expected. Make all Expr and Stmt construction
operators free functions and move them to the `edsc::op` namespace. Callers
willing to use these operators must explicitly include them with the `using`
declaration. This can be done in some local scope.
Additionally, we currently emit signed comparisons for order-comparison
operators. With namespaces, we can later introduce two sets of operators in
different namespace, e.g. `edsc::op::sign` and `edsc::op::unsign` to clearly
state which kind of comparison is implied.
PiperOrigin-RevId:
233578674
Alex Zinenko [Tue, 12 Feb 2019 11:34:52 +0000 (03:34 -0800)]
EDSC: support 'for' loops with dynamic bounds
The existing implementation in EDSC of 'for' loops in MLIREmitter is
unnecessarily restricted to constant bounds. The underlying AffineForOp can be
constructed from (a list of) Values and AffineMaps instead of constants. Its
verifier will check that the "affine provenance" conditions, i.e. that the
values used in the loop conditions are defined in such a way that they can be
analyzed by affine passes, are respected. One can use non-constant values in
affine loop bounds in conjunction with a single-dimensional identity affine
map. Implement this in MLIREmitter while maintaining the special case for
constant bounds that leads to significantly simpler generated IR when
applicable.
Test this change using the EDSC lowering test pass to inject code emitted from
EDSC into functions with predefined names.
PiperOrigin-RevId:
233578220
Tatiana Shpeisman [Tue, 12 Feb 2019 06:51:34 +0000 (22:51 -0800)]
Add dialect-specific decoding for opaque constants.
Associates opaque constants with a particular dialect. Adds general mechanism to register dialect-specific hooks defined in external components. Adds hooks to decode opaque tensor constant and extract an element of an opaque tensor constant.
This CL does not change the existing mechanism for registering constant folding hook yet. One thing at a time.
PiperOrigin-RevId:
233544757
Jacques Pienaar [Tue, 12 Feb 2019 06:24:22 +0000 (22:24 -0800)]
Fix incorrect type in iterator.
PiperOrigin-RevId:
233542711
Uday Bondhugula [Tue, 12 Feb 2019 00:33:53 +0000 (16:33 -0800)]
Generate dealloc's for the alloc's of dma-generate.
- for the DMA buffers being allocated (and their tags), generate corresponding deallocs
- minor related update to replaceAllMemRefUsesWith and PipelineDataTransfer pass
Code generation for DMA transfers was being done with the initial simplifying
assumption that the alloc's would map to scoped allocations, and so no
deallocations would be necessary. Drop this assumption to generalize. Note that
even with scoped allocations, unrolling loops that have scoped allocations
could create a series of allocations and exhaustion of fast memory. Having a
end of lifetime marker like a dealloc in fact allows creating new scopes if
necessary when lowering to a backend and still utilize scoped allocation.
DMA buffers created by -dma-generate are guaranteed to have either
non-overlapping lifetimes or nested lifetimes.
PiperOrigin-RevId:
233502632
Uday Bondhugula [Mon, 11 Feb 2019 23:43:26 +0000 (15:43 -0800)]
Fix + cleanup for getMemRefRegion()
- determine symbols for the memref region correctly
- this wasn't exposed earlier since we didn't have any test cases where the
portion of the nest being DMAed for was non-hyperrectangular (i.e., bounds of
one IV depending on other IVs within that part)
PiperOrigin-RevId:
233493872
Jacques Pienaar [Sun, 10 Feb 2019 22:14:08 +0000 (14:14 -0800)]
Add binary broadcastable builder.
* Add common broadcastable binary adder in TF ops and use for a few ops;
- Adding Sub, Mul here
* Change the prepare lowering to use TF variants;
* Add some more legalization patterns;
PiperOrigin-RevId:
233310952
Lei Zhang [Sun, 10 Feb 2019 01:38:24 +0000 (17:38 -0800)]
[TFLite] Add rewrite pattern to fuse conv ops with Relu6 op
* Fixed tfl.conv_2d and tfl.depthwise_conv_2d to have fused activation
function attribute
* Fixed RewriterGen crash: trying to get attribute match template when
the matcher is unspecified (UnsetInit)
PiperOrigin-RevId:
233241755
Lei Zhang [Sat, 9 Feb 2019 14:45:55 +0000 (06:45 -0800)]
[TableGen] Support nested DAG nodes in result result op arguments
This CL allowed developers to write result ops having nested DAG nodes as their
arguments. Now we can write
```
def : Pat<(...), (AOp (BOp, ...), AOperand)>
```
PiperOrigin-RevId:
233207225
Lei Zhang [Sat, 9 Feb 2019 14:36:23 +0000 (06:36 -0800)]
[TableGen] Assign created ops to variables and rewrite with PatternRewriter::replaceOp()
Previously we were using PatternRewrite::replaceOpWithNewOp() to both create the new op
inline and rewrite the matched op. That does not work well if we want to generate multiple
ops in a sequence. To support that, this CL changed to assign each newly created op to a
separate variable.
This CL also refactors how PatternEmitter performs the directive dispatch logic.
PiperOrigin-RevId:
233206819
Alex Zinenko [Fri, 8 Feb 2019 18:20:01 +0000 (10:20 -0800)]
Convert MemRefCastOp to the LLVM IR dialect
Add support for converting `memref_cast` operations into the LLVM IR dialect.
This goes beyond want is currently implemented in the MLIR standard ops to LLVM
IR translation, but follows the general principles of the memref descriptors.
A memref cast creates a new descriptor containing the same buffer pointer but a
potentially different number of dynamic sizes (as many as dynamic dimensions in
the target memref type). The lowering copies the buffer pointer to the new
descriptor and inserts dynamic sizes to it. If the size is static in the
source type, a constant value is inserted as the dynamic size, otherwise a
dynamic value is copied from the source descriptor, taking into account the
difference in dynamic size positions in the descriptor.
PiperOrigin-RevId:
233082035
River Riddle [Fri, 8 Feb 2019 17:52:26 +0000 (09:52 -0800)]
Remove the restriction that only registered terminator operations may terminate a block and have block operands. This allows for any operation to hold block operands. It also introduces the notion that unregistered operations may terminate a block. As such, the 'isTerminator' api on Instruction has been split into 'isKnownTerminator' and 'isKnownNonTerminator'.
PiperOrigin-RevId:
233076831
Alex Zinenko [Fri, 8 Feb 2019 16:59:23 +0000 (08:59 -0800)]
Cleanups in ExecutionEngine.
Make sure the module is always passed to the optimization layer.
Drop unused default argument for the IR transformation and remove the function
that was only used in this default argument. The transformation wrapper
constructor already checks for the null function, so the caller can just pass
`{}` if they don't want any transformation (no callers currently need this).
PiperOrigin-RevId:
233068817
Alex Zinenko [Fri, 8 Feb 2019 13:26:20 +0000 (05:26 -0800)]
Port load/store op translation to LLVM IR dialect lowering
Implement the lowering of memref load and store standard operations into the
LLVM IR dialect. This largely follows the existing mechanism in
MLIR-to-LLVM-IR translation for the sake of compatibility. A memref value is
transformed into a memref descriptor value which holds the pointer to the
underlying data buffer and the dynamic memref sizes. The data buffer is
contiguous. Accesses to multidimensional memrefs are linearized in row-major
form. In linear address computation, statically known sizes are used as
constants while dynamic sizes are extracted from the memref descriptor.
PiperOrigin-RevId:
233043846
Uday Bondhugula [Thu, 7 Feb 2019 22:24:18 +0000 (14:24 -0800)]
Automated rollback of changelist
232728977.
PiperOrigin-RevId:
232944889
Smit Hinsu [Thu, 7 Feb 2019 20:56:12 +0000 (12:56 -0800)]
Handle dynamic shapes in Broadcastable op trait
That allows TensorFlow Add and Div ops to use Broadcastable op trait instead of
more restrictive SameValueType op trait.
That in turn allows TensorFlow ops to be registered by defining GET_OP_LIST and
including the generated ops file. Currently, tf-raise-control-flow pass tests
are using dynamic shapes in tf.Add op and AddOp can't be registered without
supporting the dynamic shapes.
TESTED with unit tests
PiperOrigin-RevId:
232927998
River Riddle [Thu, 7 Feb 2019 20:29:31 +0000 (12:29 -0800)]
Add verification for AffineApply/AffineFor/AffineIf dimension and symbol operands. This also allows a DimOp to be a valid dimension identifier if its operand is a valid dimension identifier.
PiperOrigin-RevId:
232923468
Jacques Pienaar [Thu, 7 Feb 2019 20:28:48 +0000 (12:28 -0800)]
Add tf.LeakyRelu.
* Add tf.LeakyRelu op definition + folders (well one is really canonicalizer)
* Change generated error message to use attribute description instead;
* Change the return type of F32Attr to be APFloat - internally it is already
stored as APFloat so let the caller decides if they want to convert it or
not. I could see varying opinions here though :) (did not change i32attr
similarly)
PiperOrigin-RevId:
232923358
Alex Zinenko [Thu, 7 Feb 2019 18:13:50 +0000 (10:13 -0800)]
Disallow zero dimensions in vectors and memrefs
Aggregate types where at least one dimension is zero do not fully make sense as
they cannot contain any values (their total size is zero). However, TensorFlow
and XLA support tensors with zero sizes, so we must support those too. This is
relatively safe since, unlike vectors and memrefs, we don't have first-class
element accessors for MLIR tensors.
To support sparse element attributes of vector types that have no non-zero
elements, make sure that index and value element attributes have tensor type so
that we never need to create a zero vector type internally. Note that this is
already consistent with the inline documentation of the sparse elements
attribute. Users of the sparse elements attribute should not rely on the
storage schema anyway.
PiperOrigin-RevId:
232896707
Alex Zinenko [Thu, 7 Feb 2019 16:36:50 +0000 (08:36 -0800)]
Disallow hexadecimal literals in type declarations
Existing IR syntax is ambiguous in type declarations in presence of zero sizes.
In particular, `0x1` in the type size can be interpreted as either a
hexadecimal literal corresponding to 1, or as two distinct decimal literals
separated by an `x` for sizes. Furthermore, the shape `<0xi32>` fails lexing
because it is expected to be an integer literal.
Fix the lexer to treat `0xi32` as an integer literal `0` followed by a bare
identifier `xi32` (look one character ahead and early return instead of
erroring out).
Disallow hexadecimal literals in type declarations and forcibly split the token
into multiple parts while parsing the type. Note that the splitting trick has
been already present to separate the element type from the preceding `x`
character.
PiperOrigin-RevId:
232880373
River Riddle [Thu, 7 Feb 2019 16:26:31 +0000 (08:26 -0800)]
Modify the canonicalizations of select and muli to use the fold hook.
This also extends the greedy pattern rewrite driver to add the operands of folded operations back to the worklist.
PiperOrigin-RevId:
232878959
Alex Zinenko [Thu, 7 Feb 2019 16:12:14 +0000 (08:12 -0800)]
ExecutionEngine: provide a hook for LLVM IR passes
The current ExecutionEngine flow generates the LLVM IR from MLIR and
JIT-compiles it as is without any transformation. It thus misses the
opportunity to perform optimizations supported by LLVM or collect statistics
about the module. Modify the Orc JITter to perform transformations on the LLVM
IR. Accept an optional LLVM module transformation function when constructing
the ExecutionEngine and use it while JIT-compiling. This prevents MLIR
ExecutionEngine from depending on LLVM passes; its clients should depend on the
passes they require.
PiperOrigin-RevId:
232877060
Uday Bondhugula [Thu, 7 Feb 2019 05:54:18 +0000 (21:54 -0800)]
Automated rollback of changelist
232717775.
PiperOrigin-RevId:
232807986
River Riddle [Wed, 6 Feb 2019 23:21:02 +0000 (15:21 -0800)]
When canonicalizing only erase the operation after calling the 'fold' hook if replacement results were supplied. This fixes a bug where the operation would always get erased, even if it was modified in place.
PiperOrigin-RevId:
232757964
River Riddle [Wed, 6 Feb 2019 20:59:50 +0000 (12:59 -0800)]
Rename the 'if' operation in the AffineOps dialect to 'affine.if' and namespace
the AffineOps dialect with 'affine'.
PiperOrigin-RevId:
232728977
Lei Zhang [Wed, 6 Feb 2019 20:27:30 +0000 (12:27 -0800)]
Add constant build() method not requiring result type
Instead, we deduce the result type from the given attribute.
This is in preparation for generating constant ops with TableGen.
PiperOrigin-RevId:
232723467
Stella Laurenzo [Wed, 6 Feb 2019 20:26:11 +0000 (12:26 -0800)]
Implement Quantization dialect and minimal UniformQuantizedType.
PiperOrigin-RevId:
232723240
Alex Zinenko [Wed, 6 Feb 2019 20:04:58 +0000 (12:04 -0800)]
Port alloc/dealloc LLVM IR conversion into the LLVM IR dialect lowering
Implement the lowering of memref allocation and deallocation standard
operations into the LLVM IR dialect. This largely follows the existing
mechanism in MLIR-to-LLVM-IR translation for the sake of compatibility.
A memref value is transformed into a memref descriptor value which holds the
pointer to the underlying data buffer and the dynamic memref sizes. The buffer
is allocated using `malloc` and freed using `free`. The lowering inserts
declarations of these functions if necessary. Memref descriptors are values of
the LLVM IR structure type wrapped into an MLIR LLVM dialect type. The pointer
to the buffer and the individual sizes are accessed using `extractvalue` and
`insertvalue` LLVM IR instructions.
PiperOrigin-RevId:
232719419
River Riddle [Wed, 6 Feb 2019 19:58:03 +0000 (11:58 -0800)]
NFC: Rename the 'for' operation in the AffineOps dialect to 'affine.for'. The is the second step to adding a namespace to the AffineOps dialect.
PiperOrigin-RevId:
232717775
River Riddle [Wed, 6 Feb 2019 19:36:16 +0000 (11:36 -0800)]
Address post submit review comments for removing Block::findInstPositionInBlock.
PiperOrigin-RevId:
232713514
River Riddle [Wed, 6 Feb 2019 19:08:18 +0000 (11:08 -0800)]
NFC: Rename affine_apply to affine.apply. This is the first step to adding a namespace to the affine dialect.
PiperOrigin-RevId:
232707862
MLIR Team [Wed, 6 Feb 2019 19:01:10 +0000 (11:01 -0800)]
Adds the ability to compute the MemRefRegion of a sliced loop nest. Utilizes this feature during loop fusion cost computation, to compute what the write region of a fusion candidate loop nest slice would be (without having to materialize the slice or change the IR).
*) Adds parameter to public API of MemRefRegion::compute for passing in the slice loop bounds to compute the memref region of the loop nest slice.
*) Exposes public method MemRefRegion::getRegionSize for computing the size of the memref region in bytes.
PiperOrigin-RevId:
232706165
Jacques Pienaar [Wed, 6 Feb 2019 18:57:50 +0000 (10:57 -0800)]
Address follow on comments for quickstart doc.
PiperOrigin-RevId:
232705423
River Riddle [Wed, 6 Feb 2019 18:54:57 +0000 (10:54 -0800)]
Remove findInstPositionInBlock from the Block api.
PiperOrigin-RevId:
232704766
Lei Zhang [Wed, 6 Feb 2019 13:06:11 +0000 (05:06 -0800)]
[TableGen] Model variadic operands using Variadic<Type>
Previously, we were using the trait mechanism to specify that an op has variadic operands.
That led a discrepancy between how we handle ops with deterministic number of operands.
Besides, we have no way to specify the constraints and match against the variadic operands.
This CL introduced Variadic<Type> as a way to solve the above issues.
PiperOrigin-RevId:
232656104
River Riddle [Wed, 6 Feb 2019 04:55:28 +0000 (20:55 -0800)]
Move the AffineFor loop bound folding to a canonicalization pattern on the AffineForOp.
PiperOrigin-RevId:
232610715
River Riddle [Wed, 6 Feb 2019 04:41:52 +0000 (20:41 -0800)]
Emit a parser error when the min/max prefix is missing from a multi value AffineFor loop bound AffineMap.
PiperOrigin-RevId:
232609693
River Riddle [Wed, 6 Feb 2019 01:00:13 +0000 (17:00 -0800)]
Refactor the affine analysis by moving some functionality to IR and some to AffineOps. This is important for allowing the affine dialect to define canonicalizations directly on the operations instead of relying on transformation passes, e.g. ComposeAffineMaps. A summary of the refactoring:
* AffineStructures has moved to IR.
* simplifyAffineExpr/simplifyAffineMap/getFlattenedAffineExpr have moved to IR.
* makeComposedAffineApply/fullyComposeAffineMapAndOperands have moved to AffineOps.
* ComposeAffineMaps is replaced by AffineApplyOp::canonicalize and deleted.
PiperOrigin-RevId:
232586468
River Riddle [Wed, 6 Feb 2019 00:29:25 +0000 (16:29 -0800)]
Define the initial g3doc for the Affine dialect.
PiperOrigin-RevId:
232581506
Smit Hinsu [Tue, 5 Feb 2019 20:02:53 +0000 (12:02 -0800)]
Add derived type attributes for TensorFlow ops generated by TableGen
Motivation for this change is to remove redundant TF type attributes for
TensorFlow ops. For example, tf$T: "tfdtype$DT_FLOAT". Type attributes can be derived using the MLIR operand or result MLIR types, attribute names and their mapping. This will also allow constant folding of instructions generated within MLIR (and not imported from TensorFlow) without adding type attributes for the instruction.
Derived attributes are populated while exporting MLIR to TF GraphDef using
auto-generated populators. Populators are only available for the ops that are generated by the TableGen.
Also, fixed Operator::getNumArgs method to exclude derived attributes as they are not
part of the arguments.
TESTED with unit test
PiperOrigin-RevId:
232531561
Alex Zinenko [Tue, 5 Feb 2019 19:47:02 +0000 (11:47 -0800)]
Print parens around the return type of a function if it is also a function type
Existing type syntax contains the following productions:
function-type ::= type-list-parens `->` type-list
type-list ::= type | type-list-parens
type ::= <..> | function-type
Due to these rules, when the parser sees `->` followed by `(`, it cannot
disambiguate if `(` starts a parenthesized list of function result types, or a
parenthesized list of operands of another function type, returned from the
current function. We would need an unknown amount of lookahead to try to find
the `->` at the right level of function nesting to differentiate between type
lists and singular function types.
Instead, require the result type of the function that is a function type itself
to be always parenthesized, at the syntax level. Update the spec and the
parser to correspond to the production rule names used in the spec (although it
would have worked without modifications). Fix the function type parsing bug in
the process, as it used to accept the non-parenthesized list of types for
arguments, disallowed by the spec.
PiperOrigin-RevId:
232528361
Jacques Pienaar [Tue, 5 Feb 2019 16:26:02 +0000 (08:26 -0800)]
MLIR graph rewrite using pattern quickstart doc.
Start quickstart guide of how to define ops + specify patterns for rewrite.
PiperOrigin-RevId:
232490287
Sergei Lebedev [Tue, 5 Feb 2019 16:17:34 +0000 (08:17 -0800)]
Implemented __invert__, __and__ and __or__ in the EDSC Python bindings
This allows to use bitwise operators as logical (accounting for differences
in precedence).
PiperOrigin-RevId:
232489024
Alex Zinenko [Tue, 5 Feb 2019 15:12:46 +0000 (07:12 -0800)]
Print non-default attribute types in optional attr dictionary
In optional attribute dictionary used, among others, in the generic form of the
ops, attribute types for integers and floats are omitted. This could lead to
inconsistencies when round-tripping the IR, in particular the attributes are
created with incorrect types after parsing (integers default to i64, floats
default to f64). Provide API to emit a trailing type after the attribute for
integers and floats. Use it while printing the optional attribute dictionary.
Omitting types for i64 and f64 is a pragmatic decision that minimizes changes
in tests. We may want to reconsider in the future and always print types of
attributes in the generic form.
PiperOrigin-RevId:
232480116
MLIR Team [Tue, 5 Feb 2019 14:57:08 +0000 (06:57 -0800)]
Loop fusion improvements:
*) After a private memref buffer is created for a fused loop nest, dependences on the old memref are reduced, which can open up fusion opportunities. In these cases, users of the old memref are added back to the worklist to be reconsidered for fusion.
*) Fixed a bug in fusion insertion point dependence check where the memref being privatized was being skipped from the check.
PiperOrigin-RevId:
232477853
Sergei Lebedev [Tue, 5 Feb 2019 14:18:01 +0000 (06:18 -0800)]
Implemented __eq__ and __ne__ in EDSC Python bindings
PiperOrigin-RevId:
232473201
Uday Bondhugula [Tue, 5 Feb 2019 00:36:33 +0000 (16:36 -0800)]
Remove stray debug output - NFC
PiperOrigin-RevId:
232390076
River Riddle [Tue, 5 Feb 2019 00:24:44 +0000 (16:24 -0800)]
Remove InstWalker and move all instruction walking to the api facilities on Function/Block/Instruction.
PiperOrigin-RevId:
232388113
River Riddle [Tue, 5 Feb 2019 00:15:13 +0000 (16:15 -0800)]
NFC: Move AffineApplyOp to the AffineOps dialect. This also moves the isValidDim/isValidSymbol methods from Value to the AffineOps dialect.
PiperOrigin-RevId:
232386632