Commit Graph

269 Commits

Author SHA1 Message Date
River Riddle 6810c8bdc1 Moving the IR printing and execution timing options out of mlir-opt and into lib/Pass. We now expose two methods: registerPassManagerCLOptions and applyPassManagerCLOptions; to allow for multiple different users (mlir-opt, etc.) to opt-in to this common functionality.
PiperOrigin-RevId: 238836911
2019-03-29 17:21:50 -07:00
Jacques Pienaar 14489b5a8a Remove unnecessary headers from mlir-opt.
PiperOrigin-RevId: 238639013
2019-03-29 17:20:12 -07:00
River Riddle 076a7350e2 Add an instrumentation for conditionally printing the IR before and after pass execution. This instrumentation can be added directly to the PassManager via 'enableIRPrinting'. mlir-opt exposes access to this instrumentation via the following flags:
* print-ir-before=(comma-separated-pass-list)
  - Print the IR before each of the passes provided within the pass list.
* print-ir-before-all
  - Print the IR before every pass in the pipeline.
* print-ir-after=(comma-separated-pass-list)
  - Print the IR after each of the passes provided within the pass list.
* print-ir-after-all
  - Print the IR after every pass in the pipeline.
* print-ir-module-scope
  - Always print the Module IR, even for non module passes.

PiperOrigin-RevId: 238523649
2019-03-29 17:19:57 -07:00
River Riddle 6558f80c8d Refactor pass timing so that it is toggled on the passmanager via 'enableTiming'. This also makes the pipeline view the default display mode.
PiperOrigin-RevId: 238079916
2019-03-29 17:15:42 -07:00
River Riddle 0cc212f2b7 Ensure that pass timing is the last added pass instrumentation. This also updates the PassInstrumentor to iterate in reverse for the "after" hooks. This ensures that the instrumentations run in a stack like fashion.
PiperOrigin-RevId: 237840808
2019-03-29 17:11:56 -07:00
River Riddle e46ba31c66 Add a new instrumentation for timing pass and analysis execution. This is made available in mlir-opt via the 'pass-timing' and 'pass-timing-display' flags. The 'pass-timing-display' flag toggles between the different available display modes for the timing results. The current display modes are 'list' and 'pipeline', with 'list' representing the default.
Below shows the output for an example mlir-opt command line.

mlir-opt foo.mlir -verify-each=false -cse -canonicalize -cse -cse -pass-timing

list view (-pass-timing-display=list):
* In this mode the results are displayed in a list sorted by total time; with each pass/analysis instance aggregated into one unique result. This mode is similar to the output of 'time-passes' in llvm-opt.

===-------------------------------------------------------------------------===
                      ... Pass execution timing report ...
===-------------------------------------------------------------------------===
  Total Execution Time: 0.0097 seconds (0.0096 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.0051 ( 58.3%)   0.0001 ( 12.2%)   0.0052 ( 53.8%)   0.0052 ( 53.8%)  Canonicalizer
   0.0025 ( 29.1%)   0.0005 ( 58.2%)   0.0031 ( 31.9%)   0.0031 ( 32.0%)  CSE
   0.0011 ( 12.6%)   0.0003 ( 29.7%)   0.0014 ( 14.3%)   0.0014 ( 14.2%)  DominanceInfo
   0.0087 (100.0%)   0.0009 (100.0%)   0.0097 (100.0%)   0.0096 (100.0%)  Total

pipeline view (-pass-timing-display=pipeline):
* In this mode the results are displayed in a nested pipeline view that mirrors the internal pass pipeline that is being executed in the pass manager. This view is useful for understanding specifically which parts of the pipeline are taking the most time, and can also be used to identify when analyses are being invalidated and recomputed.

===-------------------------------------------------------------------------===
                      ... Pass execution timing report ...
===-------------------------------------------------------------------------===
  Total Execution Time: 0.0082 seconds (0.0081 wall clock)

   ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Name ---
   0.0042 (100.0%)   0.0039 (100.0%)   0.0082 (100.0%)   0.0081 (100.0%)  Function Pipeline
   0.0005 ( 11.6%)   0.0008 ( 21.1%)   0.0013 ( 16.1%)   0.0013 ( 16.2%)    CSE
   0.0002 (  5.0%)   0.0004 (  9.3%)   0.0006 (  7.0%)   0.0006 (  7.0%)      (A) DominanceInfo
   0.0026 ( 61.8%)   0.0018 ( 45.6%)   0.0044 ( 54.0%)   0.0044 ( 54.1%)    Canonicalizer
   0.0005 ( 11.7%)   0.0005 ( 13.0%)   0.0010 ( 12.3%)   0.0010 ( 12.4%)    CSE
   0.0003 (  6.1%)   0.0003 (  8.3%)   0.0006 (  7.2%)   0.0006 (  7.1%)      (A) DominanceInfo
   0.0002 (  3.8%)   0.0001 (  2.8%)   0.0003 (  3.3%)   0.0003 (  3.3%)    CSE
   0.0042 (100.0%)   0.0039 (100.0%)   0.0082 (100.0%)   0.0081 (100.0%)  Total

PiperOrigin-RevId: 237825367
2019-03-29 17:11:25 -07:00
River Riddle f427bddd06 Update the PassManager infrastructure to return Status instead of bool.
PiperOrigin-RevId: 237261205
2019-03-29 17:05:51 -07:00
River Riddle 50efe0fc85 Add a 'verifyPasses' flag to the PassManager that specifies if the IR should be verified after each pass. This also adds a "verify-each" flag to mlir-opt to optionally disable running the verifier after each pass.
PiperOrigin-RevId: 236703760
2019-03-29 16:55:35 -07:00
River Riddle ed5fe2098b Remove PassResult and have the runOnFunction/runOnModule functions return void instead. To signal a pass failure, passes should now invoke the 'signalPassFailure' method. This provides the equivalent functionality when needed, but isn't an intrusive part of the API like PassResult.
PiperOrigin-RevId: 236202029
2019-03-29 16:50:44 -07:00
River Riddle 091ff3dc3f Add support for registering pass pipelines to the PassRegistry. This is done by providing a static registration facility PassPipelineRegistration that works similarly to PassRegistration except for it also takes a function that will add necessary passes to a provided PassManager.
void pipelineBuilder(PassManager &pm) {
      pm.addPass(new MyPass());
      pm.addPass(new MyOtherPass());
  }

  static PassPipelineRegistration Unused("unused", "Unused pass", pipelineBuilder);

This is also useful for registering specializations of existing passes:

  Pass *createFooPass10() { return new FooPass(10); }

  static PassPipelineRegistration Unused("unused", "Unused pass", createFooPass10);

PiperOrigin-RevId: 235996282
2019-03-29 16:48:29 -07:00
River Riddle c6c534493d Port all of the existing passes over to the new pass manager infrastructure. This is largely NFC.
PiperOrigin-RevId: 235952357
2019-03-29 16:47:14 -07:00
River Riddle 48ccae2476 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
2019-03-29 16:32:56 -07:00
Lei Zhang ac5a50e1e4 Extract openInputFile() into Support/FileUtilities
Multiple binaries have the needs to open input files. Use this function
to de-duplicate the code.

Also changed openOutputFile() to return errors using std::string since
it is a library call and accessing I/O in library call is not friendly.

PiperOrigin-RevId: 228878221
2019-03-29 15:09:11 -07:00
Chris Lattner 4fbcd1ac52 Minor renamings: Trim the "Stmt" prefix off
StmtSuccessorIterator/StmtSuccessorIterator, and rename and move the
CFGFunctionViewGraph pass to ViewFunctionGraph.

This is step 13/n towards merging instructions and statements, NFC.

PiperOrigin-RevId: 227069438
2019-03-29 14:40:51 -07:00
Chris Lattner 776b035646 Eliminate the Instruction, BasicBlock, CFGFunction, MLFunction, and ExtFunction classes, using the Statement/StmtBlock hierarchy and Function instead.
This *only* changes the internal data structures, it does not affect the user visible syntax or structure of MLIR code.  Function gets new "isCFG()" sorts of predicates as a transitional measure.

This patch is gross in a number of ways, largely in an effort to reduce the amount of mechanical churn in one go.  It introduces a bunch of using decls to keep the old names alive for now, and a bunch of stuff needs to be renamed.

This is step 10/n towards merging instructions and statements, NFC.

PiperOrigin-RevId: 227044402
2019-03-29 14:39:49 -07:00
Jacques Pienaar 057984d05d Move print op stats pass to analysis.
Move PrintOpStatsPass out of tools and to other passes (moved to Analysis as it
doesn't modify the program but it is different than the other analysis passes
as it is only consumer at present is the user).

PiperOrigin-RevId: 227018996
2019-03-29 14:39:19 -07:00
Jacques Pienaar f24628b1f0 Fix off by one in OpStats.
PiperOrigin-RevId: 223977444
2019-03-29 14:16:25 -07:00
Jacques Pienaar d0590caa90 Add op stats pass to mlir-opt.
op-stats pass currently returns the number of occurrences of different operations in a Module. Useful for verifying transformation properties (e.g., 3 ops of specific dialect, 0 of another), but probably not useful outside of that so keeping it local to mlir-opt. This does not consider op attributes when counting.

PiperOrigin-RevId: 222259727
2019-03-29 14:02:46 -07:00
Jacques Pienaar f10f48ee63 Convert MLIR DiagnosticKind to LLVM DiagKind when emitting diagnostic via mlir-opt.
PiperOrigin-RevId: 222147297
2019-03-29 14:02:02 -07:00
Smit Hinsu a894bfdfd6 Update split marker for split-input-file option to be more restrictive
This is to allow usage of comment blocks along with splits in test cases.
For example, "Function Control Flow Lowering" comment block in
raise-control-flow.mlir

TESTED with existing unit tests

PiperOrigin-RevId: 221214451
2019-03-29 13:56:05 -07:00
River Riddle 2fa4bc9fc8 Implement value type abstraction for locations.
Value type abstraction for locations differ from others in that a Location can NOT be null. NOTE: dyn_cast returns an Optional<T>.

PiperOrigin-RevId: 220682078
2019-03-29 13:52:31 -07:00
Jacques Pienaar 6f0fb22723 Add static pass registration
Add static pass registration and change mlir-opt to use it. Future work is needed to refactor the registration for PassManager usage.

Change build targets to alwayslink to enforce registration.

PiperOrigin-RevId: 220390178
2019-03-29 13:49:34 -07:00
Uday Bondhugula 6cd5d5c544 Introduce loop tiling code generation (hyper-rectangular case)
- simple perfectly nested band tiling with fixed tile sizes.
- only the hyper-rectangular case is handled, with other limitations of
  getIndexSet applying (constant loop bounds, etc.);  once
  the latter utility is extended, tiled code generation should become more
  general.
- Add FlatAffineConstraints::isHyperRectangular()

PiperOrigin-RevId: 220324933
2019-03-29 13:49:05 -07:00
Jacques Pienaar 5e01000d46 Start TFLite legalizer pass
Start of TFLite legalizer pass. Currently focussed on macro expanding ops, limited to what is registered directly in a separate pass (this should instead be a general pass), no querying of what gets produced, the matching is string based instead of using the ops proper (the matching TF ops should be defined) etc. This is a step to enable prototyping. In addition to the above shortcomings, the legalizer is very verbose in this form and should instead be driven by autogenerated patterns (same is true for the op builders too). But this starts from the explicit form and extracting out commonality in follow up.

Add definition for tfl.relu for basic selection of fused relu add.

PiperOrigin-RevId: 220287087
2019-03-29 13:48:50 -07:00
MLIR Team 239e328913 Adds MemRefDependenceCheck analysis pass, plus multiple dependence check tests.
Adds equality constraints to dependence constraint system for accesses using dims/symbols where the defining operation of the dim/symbol is a constant.

PiperOrigin-RevId: 219814740
2019-03-29 13:48:05 -07:00
MLIR Team f28e4df666 Adds a dependence check to test whether two accesses to the same memref access the same element.
- Builds access functions and iterations domains for each access.
- Builds dependence polyhedron constraint system which has equality constraints for equated access functions and inequality constraints for iteration domain loop bounds.
- Runs elimination on the dependence polyhedron to test if no dependence exists between the accesses.
- Adds a trivial LoopFusion transformation pass with a simple test policy to test dependence between accesses to the same memref in adjacent loops.
- The LoopFusion pass will be extended in subsequent CLs.

PiperOrigin-RevId: 219630898
2019-03-29 13:47:13 -07:00
Uday Bondhugula 8201e19e3d Introduce memref bound checking.
Introduce analysis to check memref accesses (in MLFunctions) for out of bound
ones. It works as follows:

$ mlir-opt -memref-bound-check test/Transforms/memref-bound-check.mlir

/tmp/single.mlir:10:12: error: 'load' op memref out of upper bound access along dimension tensorflow/mlir#1
      %x = load %A[%idxtensorflow/mlir#0, %idxtensorflow/mlir#1] : memref<9 x 9 x i32>
           ^
/tmp/single.mlir:10:12: error: 'load' op memref out of lower bound access along dimension tensorflow/mlir#1
      %x = load %A[%idxtensorflow/mlir#0, %idxtensorflow/mlir#1] : memref<9 x 9 x i32>
           ^
/tmp/single.mlir:10:12: error: 'load' op memref out of upper bound access along dimension tensorflow/mlir#2
      %x = load %A[%idxtensorflow/mlir#0, %idxtensorflow/mlir#1] : memref<9 x 9 x i32>
           ^
/tmp/single.mlir:10:12: error: 'load' op memref out of lower bound access along dimension tensorflow/mlir#2
      %x = load %A[%idxtensorflow/mlir#0, %idxtensorflow/mlir#1] : memref<9 x 9 x i32>
           ^
/tmp/single.mlir:12:12: error: 'load' op memref out of upper bound access along dimension tensorflow/mlir#1
      %y = load %B[%idy] : memref<128 x i32>
           ^
/tmp/single.mlir:12:12: error: 'load' op memref out of lower bound access along dimension tensorflow/mlir#1
      %y = load %B[%idy] : memref<128 x i32>
           ^
#map0 = (d0, d1) -> (d0, d1)
#map1 = (d0, d1) -> (d0 * 128 - d1)
mlfunc @test() {
  %0 = alloc() : memref<9x9xi32>
  %1 = alloc() : memref<128xi32>
  for %i0 = -1 to 9 {
    for %i1 = -1 to 9 {
      %2 = affine_apply #map0(%i0, %i1)
      %3 = load %0[%2tensorflow/mlir#0, %2tensorflow/mlir#1] : memref<9x9xi32>
      %4 = affine_apply #map1(%i0, %i1)
      %5 = load %1[%4] : memref<128xi32>
    }
  }
  return
}

- Improves productivity while manually / semi-automatically developing MLIR for
  testing / prototyping; also provides an indirect way to catch errors in
  transformations.

- This pass is an easy way to test the underlying affine analysis
  machinery including low level routines.

Some code (in getMemoryRegion()) borrowed from @andydavis cl/218263256.

While on this:

- create mlir/Analysis/Passes.h; move Pass.h up from mlir/Transforms/ to mlir/

- fix a bug in AffineAnalysis.cpp::toAffineExpr

TODO: extend to non-constant loop bounds (straightforward). Will transparently
work for all accesses once floordiv, mod, ceildiv are supported in the
AffineMap -> FlatAffineConstraints conversion.
PiperOrigin-RevId: 219397961
2019-03-29 13:46:08 -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
Nicolas Vasilache 3013dadb7c [MLIR] Basic infrastructure for vectorization test
This CL implements a very simple loop vectorization **test** and the basic
infrastructure to support it.

The test simply consists in:
1. matching the loops in the MLFunction and all the Load/Store operations
nested under the loop;
2. testing whether all the Load/Store are contiguous along the innermost
memory dimension along that particular loop. If any reference is
non-contiguous (i.e. the ForStmt SSAValue appears in the expression), then
the loop is not-vectorizable.

The simple test above can gradually be extended with more interesting
behaviors to account for the fact that a layout permutation may exist that
enables contiguity etc. All these will come in due time but it is worthwhile
noting that the test already supports detection of outer-vetorizable loops.

In implementing this test, I also added a recursive MLFunctionMatcher and some
sugar that can capture patterns
such as `auto gemmLike = Doall(Doall(Red(LoadStore())))` and allows iterating
on the matched IR structures. For now it just uses in order traversal but
post-order DFS will be useful in the future once IR rewrites start occuring.

One may note that the memory management design decision follows a different
pattern from MLIR. After evaluating different designs and how they quickly
increase cognitive overhead, I decided to opt for the simplest solution in my
view: a class-wide (threadsafe) RAII context.

This way, a pass that needs MLFunctionMatcher can just have its own locally
scoped BumpPtrAllocator and everything is cleaned up when the pass is destroyed.
If passes are expected to have a longer lifetime, then the contexts can easily
be scoped inside the runOnMLFunction call and storage lifetime reduced.
Lastly, whatever the scope of threading (module, function, pass), this is
expected to also be future-proof wrt concurrency (but this is a detail atm).

PiperOrigin-RevId: 217622889
2019-03-29 13:32:13 -07:00
Chris Lattner 9e3b928e32 Implement a super sketched out pattern match/rewrite framework and a sketched
out canonicalization pass to drive it, and a simple (x-x) === 0 pattern match
as a test case.

There is a tremendous number of improvements that need to land, and the
matcher/rewriter and patterns will be split out of this file, but this is a
starting point.

PiperOrigin-RevId: 216788604
2019-03-29 13:29:07 -07:00
Uday Bondhugula 82e55750d2 Add target independent standard DMA ops: dma.start, dma.wait
Add target independent standard DMA ops: dma.start, dma.wait. Update pipeline
data transfer to use these to detect DMA ops.

While on this
- return failure from mlir-opt::performActions if a pass generates invalid output
- improve error message for verify 'n' operand traits

PiperOrigin-RevId: 216429885
2019-03-29 13:26:10 -07:00
MLIR Team fe490043b0 Affine map composition.
*) Implements AffineValueMap forward substitution for AffineApplyOps.
*) Adds ComposeAffineMaps transformation pass, which composes affine maps for all loads/stores in an MLFunction.
*) Adds multiple affine map composition tests.

PiperOrigin-RevId: 216216446
2019-03-29 13:24:59 -07:00
Uday Bondhugula 041817a45e Introduce loop body skewing / loop pipelining / loop shifting utility.
- loopBodySkew shifts statements of a loop body by stmt-wise delays, and is
  typically meant to be used to:
  - allow overlap of non-blocking start/wait until completion operations with
    other computation
  - allow shifting of statements (for better register
    reuse/locality/parallelism)
  - software pipelining (when applied to the innermost loop)
- an additional argument specifies whether to unroll the prologue and epilogue.
- add method to check SSA dominance preservation.
- add a fake loop pipeline pass to test this utility.

Sample input/output are below. While on this, fix/add following:

- fix minor bug in getAddMulPureAffineExpr
- add additional builder methods for common affine map cases
- fix const_operand_iterator's for ForStmt, etc. When there is no such thing
  as 'const MLValue', the iterator shouldn't be returning const MLValue's.
  Returning MLValue is const correct.

Sample input/output examples:

1) Simplest case: shift second statement by one.

Input:

for %i = 0 to 7 {
  %y = "foo"(%i) : (affineint) -> affineint
  %x = "bar"(%i) : (affineint) -> affineint
}

Output:

#map0 = (d0) -> (d0 - 1)
mlfunc @loop_nest_simple1() {
  %c8 = constant 8 : affineint
  %c0 = constant 0 : affineint
  %0 = "foo"(%c0) : (affineint) -> affineint
  for %i0 = 1 to 7 {
    %1 = "foo"(%i0) : (affineint) -> affineint
    %2 = affine_apply #map0(%i0)
    %3 = "bar"(%2) : (affineint) -> affineint
  }
  %4 = affine_apply #map0(%c8)
  %5 = "bar"(%4) : (affineint) -> affineint
  return
}

2) DMA overlap: shift dma.wait and compute by one.

Input
  for %i = 0 to 7 {
    %pingpong = affine_apply (d0) -> (d0 mod 2) (%i)
    "dma.enqueue"(%pingpong) : (affineint) -> affineint
    %pongping = affine_apply (d0) -> (d0 mod 2) (%i)
    "dma.wait"(%pongping) : (affineint) -> affineint
    "compute1"(%pongping) : (affineint) -> affineint
  }

Output

#map0 = (d0) -> (d0 mod 2)
#map1 = (d0) -> (d0 - 1)
#map2 = ()[s0] -> (s0 + 7)
mlfunc @loop_nest_dma() {
  %c8 = constant 8 : affineint
  %c0 = constant 0 : affineint
  %0 = affine_apply #map0(%c0)
  %1 = "dma.enqueue"(%0) : (affineint) -> affineint
  for %i0 = 1 to 7 {
    %2 = affine_apply #map0(%i0)
    %3 = "dma.enqueue"(%2) : (affineint) -> affineint
    %4 = affine_apply #map1(%i0)
    %5 = affine_apply #map0(%4)
    %6 = "dma.wait"(%5) : (affineint) -> affineint
    %7 = "compute1"(%5) : (affineint) -> affineint
  }
  %8 = affine_apply #map1(%c8)
  %9 = affine_apply #map0(%8)
  %10 = "dma.wait"(%9) : (affineint) -> affineint
  %11 = "compute1"(%9) : (affineint) -> affineint
  return
}

3) With arbitrary affine bound maps:

Shift last two statements by two.

Input:

  for %i = %N to ()[s0] -> (s0 + 7)()[%N] {
    %y = "foo"(%i) : (affineint) -> affineint
    %x = "bar"(%i) : (affineint) -> affineint
    %z = "foo_bar"(%i) : (affineint) -> (affineint)
    "bar_foo"(%i) : (affineint) -> (affineint)
  }

Output

#map0 = ()[s0] -> (s0 + 1)
#map1 = ()[s0] -> (s0 + 2)
#map2 = ()[s0] -> (s0 + 7)
#map3 = (d0) -> (d0 - 2)
#map4 = ()[s0] -> (s0 + 8)
#map5 = ()[s0] -> (s0 + 9)

  for %i0 = %arg0 to #map0()[%arg0] {
    %0 = "foo"(%i0) : (affineint) -> affineint
    %1 = "bar"(%i0) : (affineint) -> affineint
  }
  for %i1 = #map1()[%arg0] to #map2()[%arg0] {
    %2 = "foo"(%i1) : (affineint) -> affineint
    %3 = "bar"(%i1) : (affineint) -> affineint
    %4 = affine_apply #map3(%i1)
    %5 = "foo_bar"(%4) : (affineint) -> affineint
    %6 = "bar_foo"(%4) : (affineint) -> affineint
  }
  for %i2 = #map4()[%arg0] to #map5()[%arg0] {
    %7 = affine_apply #map3(%i2)
    %8 = "foo_bar"(%7) : (affineint) -> affineint
    %9 = "bar_foo"(%7) : (affineint) -> affineint
  }

4) Shift one by zero, second by one, third by two

  for %i = 0 to 7 {
    %y = "foo"(%i) : (affineint) -> affineint
    %x = "bar"(%i) : (affineint) -> affineint
    %z = "foobar"(%i) : (affineint) -> affineint
  }

#map0 = (d0) -> (d0 - 1)
#map1 = (d0) -> (d0 - 2)
#map2 = ()[s0] -> (s0 + 7)

  %c9 = constant 9 : affineint
  %c8 = constant 8 : affineint
  %c1 = constant 1 : affineint
  %c0 = constant 0 : affineint
  %0 = "foo"(%c0) : (affineint) -> affineint
  %1 = "foo"(%c1) : (affineint) -> affineint
  %2 = affine_apply #map0(%c1)
  %3 = "bar"(%2) : (affineint) -> affineint
  for %i0 = 2 to 7 {
    %4 = "foo"(%i0) : (affineint) -> affineint
    %5 = affine_apply #map0(%i0)
    %6 = "bar"(%5) : (affineint) -> affineint
    %7 = affine_apply #map1(%i0)
    %8 = "foobar"(%7) : (affineint) -> affineint
  }
  %9 = affine_apply #map0(%c8)
  %10 = "bar"(%9) : (affineint) -> affineint
  %11 = affine_apply #map1(%c8)
  %12 = "foobar"(%11) : (affineint) -> affineint
  %13 = affine_apply #map1(%c9)
  %14 = "foobar"(%13) : (affineint) -> affineint

5) SSA dominance violated; no shifting if a shift is specified for the second
statement.

  for %i = 0 to 7 {
    %x = "foo"(%i) : (affineint) -> affineint
    "bar"(%x) : (affineint) -> affineint
  }

PiperOrigin-RevId: 214975731
2019-03-29 13:21:26 -07:00
Chris Lattner c706e0b1b5 Add support for expected-warning and expected-note markers in mlir-opt -verify
mode.  We even diagnose mistakes nicely (aside from the a/an vowel confusion
which isn't worth worrying about):

test/IR/invalid.mlir split at line tensorflow/mlir#399:8:34: error: 'note' diagnostic emitted when expecting a 'error'
  %x = "bar"() : () -> i32    // expected-error {{operand defined here}}
                                 ^

PiperOrigin-RevId: 214773208
2019-03-29 13:20:46 -07:00
Jacques Pienaar f54861fc4a Add MLIR (addf) -> MLIR HLO thin slice.
Super thin slice that can convert a MLIR program (with addfs) to MLIR HLO dialect. Add this as translations to mlir-translate. Also add hlo::AddOp op and HLO op registration.

PiperOrigin-RevId: 214480409
2019-03-29 13:18:34 -07:00
Jacques Pienaar e5354c2404 Add op registry for registering MLIR ops.
Instead of linking in different initializeMLIRContext functions, add a registry mechanism and function to initialize all registered ops in a given MLIRContext. Initialize all registered ops along with the StandardOps when constructing a MLIRContext.

PiperOrigin-RevId: 214073842
2019-03-29 13:17:49 -07:00
Chris Lattner 82eb284a53 Implement support for constant folding operations and a simple constant folding
optimization pass:

 - Give the ability for operations to implement a constantFold hook (a simple
   one for single-result ops as well as general support for multi-result ops).
 - Implement folding support for constant and addf.
 - Implement support in AbstractOperation and Operation to make this usable by
   clients.
 - Implement a very simple constant folding pass that does top down folding on
   CFG and ML functions, with a testcase that exercises all the above stuff.

Random cleanups:
 - Improve the build APIs for ConstantOp.
 - Stop passing "-o -" to mlir-opt in the testsuite, since that is the default.

PiperOrigin-RevId: 213749809
2019-03-29 13:16:33 -07:00
Jacques Pienaar fb3116f59e Add PassResult and have passes return PassResult to indicate failure/success.
For FunctionPass's for passes that want to stop upon error encountered.

PiperOrigin-RevId: 213058651
2019-03-29 13:13:55 -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
Chris Lattner 6337af082b Improve location reporting in the verifier for return instructions and other
terminators.  Improve mlir-opt to print better location info in the split-files
case.

Before:

error: unexpected error: branch has 2 operands, but target block has 1
  br bb1(%0tensorflow/mlir#1, %0tensorflow/mlir#0 : i17, i1)
  ^

after:

invalid.mlir split at line tensorflow/mlir#305:6:3: error: unexpected error: branch has 2 operands, but target block has 1
  br bb1(%0tensorflow/mlir#1, %0tensorflow/mlir#0 : i17, i1)
  ^

It still isn't optimal (it would be better to have just the original file and
line number but is a step forward, and doing the optimal thing would be a lot
more complicated.

PiperOrigin-RevId: 211917067
2019-03-29 13:10:38 -07:00
Chris Lattner b18c770d90 Teach RaiseControlFlow to handle IfOp's with partially infered shapes,
inserting shape_casts as necessary.

Along the way:
 - Add some missing accessors to the AtLeastNOperands trait.
 - Implement shape_cast / ShapeCastOp standard op.
 - Improve handling of errors in mlir-opt, making it easier to understand
   errors when invalid IR is rejected by the verifier.

PiperOrigin-RevId: 211897877
2019-03-29 13:10:24 -07:00
Chris Lattner 5f11f68405 Several minor infra improvements:
- Make the tf-lower-control flow handle error cases better.  Add a testcase
   that (currently) fails due to type mismatches.
 - Factor more code in the verifier for basic block argument checking, and
   check more invariants.
 - Fix a crasher in the asmprinter on null instructions (which only occurs on
   invalid code).
 - Fix a bug handling conditional branches with no block operands, it would
   access &operands[0] instead of using operands.data().
 - Enhance the mlir-opt driver to use the verifier() in a non-crashing mode,
   allowing issues to be reported as diagnostics.

PiperOrigin-RevId: 211818291
2019-03-29 13:10:11 -07:00
Jacques Pienaar 95f31d53d5 Add GraphTraits and DOTGraphTraits for CFGFunction in debug builds.
Enable using GraphWriter to dump graphviz in debug mode (kept to debug builds completely as this is only for debugging). Add option to mlir-opt to print CFGFunction after every transform in debug mode.

PiperOrigin-RevId: 211578699
2019-03-29 13:09:31 -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
Uday Bondhugula 0122a99cbb Affine expression analysis and simplification.
Outside of IR/
- simplify a MutableAffineMap by flattening the affine expressions
- add a simplify affine expression pass that uses this analysis
- update the FlatAffineConstraints API (to be used in the next CL)

In IR:
- add isMultipleOf and getKnownGCD for AffineExpr, and make the in-IR
  simplication of simplifyMod simpler and more powerful.
- rename the AffineExpr visitor methods to distinguish b/w visiting and
  walking, and to simplify API names based on context.

The next CL will use some of these for the loop unrolling/unroll-jam to make
the detection for the need of cleanup loop powerful/non-trivial.

A future CL will finally move this simplification to FlatAffineConstraints to
make it more powerful. For eg., currently, even if a mod expr appearing in a
part of the expression tree can't be simplified, the whole thing won't be
simplified.

PiperOrigin-RevId: 211012256
2019-03-29 13:07:44 -07:00
Uday Bondhugula e9fb4b492d Introduce loop unroll jam transformation.
- for test purposes, the unroll-jam pass unroll jams the first outermost loop.

While on this:
- fix StmtVisitor to allow overriding of function to iterate walk over children
  of a stmt.

PiperOrigin-RevId: 210644813
2019-03-29 13:07:30 -07:00
Chris Lattner acd5bd98d1 First steps towards TF/XLA control flow lowering: functional if lowering.
- Implement support for the TensorFlow 'If' op, the first TF op definition.
 - Fill in some missing basic infra, including the ability to split a basic block, the ability to create a branch with operands, etc.
 - Implement basic lowering for some simple forms of If, where the condition is a zero-D bool tensor and when all the types line up.  Future patches will generalize this.

There is still much to be done here.  I'd like to get some example graphs coming from the converter to play with to direct this work.

PiperOrigin-RevId: 210198760
2019-03-29 13:05:01 -07:00
Uday Bondhugula 00bed4bd99 Extend loop unrolling to unroll by a given factor; add builder for affine
apply op.

- add builder for AffineApplyOp (first one for an operation that has
  non-zero operands)
- add support for loop unrolling by a given factor; uses the affine apply op
  builder.

While on this, change 'step' of ForStmt to be 'unsigned' instead of
AffineConstantExpr *. Add setters for ForStmt lb, ub, step.

Sample Input:

// CHECK-LABEL: mlfunc @loop_nest_unroll_cleanup() {
mlfunc @loop_nest_unroll_cleanup() {
  for %i = 1 to 100 {
    for %j = 0 to 17 {
      %x = "addi32"(%j, %j) : (affineint, affineint) -> i32
      %y = "addi32"(%x, %x) : (i32, i32) -> i32
    }
  }
  return
}

Output:

$ mlir-opt -loop-unroll -unroll-factor=4 /tmp/single2.mlir
#map0 = (d0) -> (d0 + 1)
#map1 = (d0) -> (d0 + 2)
#map2 = (d0) -> (d0 + 3)
mlfunc @loop_nest_unroll_cleanup() {
  for %i0 = 1 to 100 {
    for %i1 = 0 to 17 step 4 {
      %0 = "addi32"(%i1, %i1) : (affineint, affineint) -> i32
      %1 = "addi32"(%0, %0) : (i32, i32) -> i32
      %2 = affine_apply #map0(%i1)
      %3 = "addi32"(%2, %2) : (affineint, affineint) -> i32
      %4 = affine_apply #map1(%i1)
      %5 = "addi32"(%4, %4) : (affineint, affineint) -> i32
      %6 = affine_apply #map2(%i1)
      %7 = "addi32"(%6, %6) : (affineint, affineint) -> i32
    }
    for %i2 = 16 to 17 {
      %8 = "addi32"(%i2, %i2) : (affineint, affineint) -> i32
      %9 = "addi32"(%8, %8) : (i32, i32) -> i32
    }
  }
  return
}

PiperOrigin-RevId: 209676220
2019-03-29 13:03:38 -07:00
Chris Lattner d9290db5fe Finish support for function attributes, and improve lots of things:
- Have the parser rewrite forward references to their resolved values at the
   end of parsing.
 - Implement verifier support for detecting malformed function attrs.
 - Add efficient query for (in general, recursive) attributes to tell if they
   contain a function.

As part of this, improve other general infrastructure:
 - Implement support for verifying OperationStmt's in ml functions, refactoring
   and generalizing support for operations in the verifier.
 - Refactor location handling code in mlir-opt to have the non-error expecting
   form of mlir-opt invocations to report error locations precisely.
 - Fix parser to detect verifier failures and report them through errorReporter
   instead of printing the error and crashing.

This regresses the location info for verifier errors in the parser that were
previously ascribed to the function.  This will get resolved in future patches
by adding support for function attributes, which we can use to manage location
information.

PiperOrigin-RevId: 209600980
2019-03-29 13:03:11 -07:00
Jacques Pienaar ec1cfe2268 [mlir-opt] Enable defining which operations are defined at link time.
Previously mlir-opt had initializeMLIRContext function that added certain ops to the OperationSet of the context. But for different tests we'd want to register different ops. Make initializeMLIRContext an extern function so that the context initialization/set of ops to register can be determined at link time. This allows out-of-tree operations to easily expand the custom parsing/printing while still using mlir-opt.

PiperOrigin-RevId: 209078315
2019-03-29 13:01:47 -07:00
Uday Bondhugula 3e92be9c71 Move Pass.{h,cpp} from lib/IR/ to lib/Transforms/.
PiperOrigin-RevId: 208571437
2019-03-29 12:59:07 -07:00
Uday Bondhugula d8490d8d4f Loop unrolling pass update
- fix/complete forStmt cloning for unrolling to work for outer loops
- create IV const's only when needed
- test outer loop unrolling by creating a short trip count unroll pass for
  loops with trip counts <= <parameter>
- add unrolling test cases for multiple op results, outer loop unrolling
- fix/clean up StmtWalker class while on this
- switch unroll loop iterator values from i32 to affineint

PiperOrigin-RevId: 207645967
2019-03-29 12:56:16 -07:00
Chris Lattner ed9fa46413 Continue wiring up diagnostic reporting infrastructure, still WIP.
- Implement a diagnostic hook in one of the paths in mlir-opt which
   captures and reports the diagnostics nicely.
 - Have the parser capture simple location information from the parser
   indicating where each op came from in the source .mlir file.
 - Add a verifyDominance() method to MLFuncVerifier to demo this, resolving b/112086163
 - Add some PrettyStackTrace handlers to make crashes in the testsuite easier
   to track down.

PiperOrigin-RevId: 207488548
2019-03-29 12:55:34 -07:00
MLIR Team fe7356c43b Internal change
PiperOrigin-RevId: 206652744
2019-03-29 12:49:23 -07:00
Chris Lattner 782c348c00 Change mlir-opt.cpp to take a list of passes to run, simplifying the driver
code.  Change printing of affine map's to not print a space between the dim and
symbol list.

PiperOrigin-RevId: 206505419
2019-03-29 12:47:38 -07:00
Chris Lattner 12adbeb872 Prepare for implementation of TensorFlow passes:
- Sketch out a TensorFlow/IR directory that will hold op definitions and common TF support logic.  We will eventually have TensorFlow/TF2HLO, TensorFlow/Grappler, TensorFlow/TFLite, etc.
 - Add sketches of a Switch/Merge op definition, including some missing stuff like the TwoResults trait.  Add a skeleton of a pass to raise this form.
 - Beef up the Pass/FunctionPass definitions slightly, moving the common code out of LoopUnroll.cpp into a new IR/Pass.cpp file.
 - Switch ConvertToCFG.cpp to be a ModulePass.
 - Allow _ to start bare identifiers, since this is important for TF attributes.

PiperOrigin-RevId: 206502517
2019-03-29 12:47:25 -07:00
Uday Bondhugula a0abd666a7 Sketch out loop unrolling transformation.
- Implement a full loop unroll for innermost loops.
- Use it to implement a pass that unroll all the innermost loops of all
  mlfunction's in a module. ForStmt's parsed currently have constant trip
  counts (and constant loop bounds).
- Implement StmtVisitor based (Visitor pattern)

Loop IVs aren't currently parsed and represented as SSA values. Replacing uses
of loop IVs in unrolled bodies is thus a TODO. Class comments are sparse at some places - will add them after one round of comments.

A cmd-line flag triggers this for now.

Original:

mlfunc @loops() {
  for x = 1 to 100 step 2 {
    for x = 1 to 4 {
      "Const"(){value: 1} : () -> ()
    }
  }
  return
}

After unrolling:

mlfunc @loops() {
  for x = 1 to 100 step 2 {
    "Const"(){value: 1} : () -> ()
    "Const"(){value: 1} : () -> ()
    "Const"(){value: 1} : () -> ()
    "Const"(){value: 1} : () -> ()
  }
  return
}

PiperOrigin-RevId: 205933235
2019-03-29 12:43:01 -07:00
Tatiana Shpeisman 1b24c48b91 Scaffolding for convertToCFG pass that replaces all instances of ML functions with equivalent CFG functions. Traverses module MLIR, generates CFG functions (empty for now) and removes ML functions. Adds Transforms library and tests.
PiperOrigin-RevId: 205848367
2019-03-29 12:41:15 -07:00
James Molloy 4144c302db [mlir] Add basic block arguments
This patch adds support for basic block arguments including parsing and printing.

In doing so noticed that `ssa-id-and-type` is undefined in the MLIR spec; suggested an implementation in the spec doc.

PiperOrigin-RevId: 205593369
2019-03-29 12:38:20 -07:00
Jacques Pienaar c90de70329 Expand check-parser-errors to match multiple errrors per line.
* check-parser-errors can match multiple errors per line;
* Add offset notation to expected-error;

PiperOrigin-RevId: 203625348
2019-03-29 12:30:35 -07:00
Jacques Pienaar 2057b454dc Add default error reporter for parser.
Add a default error reporter for the parser that uses the SourceManager to print the error. Also and OptResult enum (mirroring ParseResult) to make the behavior self-documenting.

PiperOrigin-RevId: 203173647
2019-03-29 12:27:57 -07:00
Jacques Pienaar c7fe8c38a5 Report parsing error check failures wrt file being parsed.
For checking parse errors, the input file is split and failures reported per memory buffer. Simply reporting the errors loses the mapping back to the original file. Change the reporting to instead relate the error reported back to the original file.

Use SourceMgr's PrintMessage consistently for errors and relates back to file being parsed.

PiperOrigin-RevId: 202136152
2019-03-29 12:26:16 -07:00
Jacques Pienaar 39a33a2568 Change error verification of parser error checking.
Change from using FileCheck to directly verifying the message (simple substring checking) and line number of the error.

PiperOrigin-RevId: 201955181
2019-03-29 12:26:02 -07:00
Jacques Pienaar b11a95350f Change Lexer and Parser to take diagnostic reporter function.
Add diagnostic reporter function to lexer/parser and use that from mlir-opt to report errors instead of having the lexer/parser print the errors.

PiperOrigin-RevId: 201892004
2019-03-29 12:25:48 -07:00
Jacques Pienaar a5fb2f47e1 Add negative parsing tests using mlir-opt.
Add parsing tests with errors. Follows direct path of splitting file into test groups (using a marker) and parsing each section individually. The expected errors are checked using FileCheck and parser error does not result in terminating parsing the rest of the file if check-parser-error.

This is an interim approach until refactoring lexer/parser.

PiperOrigin-RevId: 201867941
2019-03-29 12:25:23 -07:00
Chris Lattner 49795d166f Introduce IR support for MLIRContext, primitive types, function types, and
vector types.

tensors and memref types are still TODO, and would be a good starter project
for someone.

PiperOrigin-RevId: 201782748
2019-03-29 12:24:32 -07:00
Chris Lattner 9b9f7ff5d4 Implement enough of a lexer and parser for MLIR to parse extfunc's without
arguments.

PiperOrigin-RevId: 201706570
2019-03-29 12:24:05 -07:00
Chris Lattner 5fc587ecf8 Continue sketching out basic infrastructure, including an input and output
filename, and printing of trivial stuff.  There is no parser yet, so the
input file is ignored.

PiperOrigin-RevId: 201596916
2019-03-29 12:23:51 -07:00
Chris Lattner 9603f9fe35 Sketch out a new repository for the mlir project (go/mlir).
PiperOrigin-RevId: 201540159
2019-03-29 12:23:24 -07:00