This is an archive of the discontinued LLVM Phabricator instance.

[mlir][TilingInterface] Fix a crash in PartialTilingInterface for some inputs
Needs ReviewPublic

Authored by vmurali on Nov 9 2022, 12:20 PM.

Details

Summary

Previously, mlir-opt crashes for the following example:

mlir-opt --test-transform-dialect-interpreter Test.mlir

Test.mlir:

func.func @reduction_bug(%arg0: tensor<32x32xi32>, %arg1: tensor<32xi32>, %out: tensor<32xi32>) -> tensor<32xi32> {
  %red = linalg.generic {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d2)>,
                                          affine_map<(d0, d1, d2) -> (d1)>,
                                          affine_map<(d0, d1, d2) -> (d0)>],
   iterator_types = ["parallel", "parallel", "reduction"]} ins(%arg0, %arg1 : tensor<32x32xi32>, tensor<32xi32>) outs(%out : tensor<32xi32>) {
    ^bb0(%a: i32, %b: i32, %c: i32):
      %r2 = arith.addi %c, %a : i32
      linalg.yield %r2 : i32
    } -> tensor<32xi32>
  return %red : tensor<32xi32>
}

transform.sequence failures(propagate) {
^bb0(%arg1: !pdl.operation):
  %0 = transform.structured.match ops{["linalg.generic"]} in %arg1
  %1, %2, %3 = transform.structured.tile_reduction_using_scf %0 { tile_sizes = [0, 0, 8] }
}

It was because the result tensor's rank was supposed to be exactly one less than the number of loops. This differential makes it fail gracefully.

Diff Detail

Event Timeline

vmurali created this revision.Nov 9 2022, 12:20 PM
vmurali requested review of this revision.Nov 9 2022, 12:20 PM
vmurali edited the summary of this revision. (Show Details)Nov 9 2022, 2:22 PM
vmurali edited the summary of this revision. (Show Details)
vmurali edited the summary of this revision. (Show Details)Nov 9 2022, 2:26 PM

Let's find a way to add a negative test for this :)

Let's find a way to add a negative test for this :)

I tried transform.sequence failures(suppress). It still fails with the same error. Any idea how to make transform ignore errors (by bailing out without doing any transformation)?

Let's find a way to add a negative test for this :)

I tried transform.sequence failures(suppress). It still fails with the same error. Any idea how to make transform ignore errors (by bailing out without doing any transformation)? @nicolasvasilache

vmurali updated this revision to Diff 476251.Nov 17 2022, 3:37 PM
vmurali edited the summary of this revision. (Show Details)
vmurali updated this revision to Diff 476254.Nov 17 2022, 3:41 PM
vmurali edited the summary of this revision. (Show Details)
Herald added a project: Restricted Project. · View Herald TranscriptNov 17 2022, 3:41 PM
vmurali updated this revision to Diff 476256.Nov 17 2022, 3:43 PM
vmurali updated this revision to Diff 476257.Nov 17 2022, 3:45 PM

suppress can only suppress silenceable failures, which can be ignored and leave the IR in a valid state.
Definite failures cannot be suppressed as they leave the IR in an invalid state.

What you may want is to refactor the transform to safelyreturn a silenceable failure in your use case.

suppress can only suppress silenceable failures, which can be ignored and leave the IR in a valid state.
Definite failures cannot be suppressed as they leave the IR in an invalid state.

What you may want is to refactor the transform to safelyreturn a silenceable failure in your use case.

I want to suppress a match failure (see changes in this differential). The transform pipeline should technically see the match failure and fail to perform any subsequent transformations (like how a normal pass pipeline would). I just want it to not bail out in the very end, and instead return the state the IR was in before the pipeline was applied.

More generally, if I have to apply different pipelines in some priority order (the first one to succeed will change the IR, and the rest of the pipelines will not be applied), how do I do that? (In my case, the second pipeline is a no-op transformation.)

suppress can only suppress silenceable failures, which can be ignored and leave the IR in a valid state.
Definite failures cannot be suppressed as they leave the IR in an invalid state.

What you may want is to refactor the transform to safelyreturn a silenceable failure in your use case.

I want to suppress a match failure (see changes in this differential).

mlir::scf::tileReductionUsingScf returns a failure to its caller which turns it into a definite error that you cannot recover from.
As I wrote earlier, What you may want is to refactor the transform to safely return a silenceable failure in your use case..
This means making mlir::scf::tileReductionUsingScf return "more information" than a binary success/fail and us that in the transform op.
The part that is annoying is that the whole MLIR infra is very binary in its return results (i.e. there is no difference between a match failure and an execution failure, both are failures and there is no type guarantee that IR is in a correct state)

The transform pipeline should technically see the match failure and fail to perform any subsequent transformations (like how a normal pass pipeline would).

There is no transform pipeline, just a list of transforms that are applied unconditionally.
This is very much unlike any "normal pass pipeline".
You may want to use transform.alternatives which will clone and try its branches until the first one succeeds.

I just want it to not bail out in the very end, and instead return the state the IR was in before the pipeline was applied.
More generally, if I have to apply different pipelines in some priority order (the first one to succeed will change the IR, and the rest of the pipelines will not be applied), how do I do that? (In my case, the second pipeline is a no-op transformation.)

transform.alternatives is likely what you are looking for ,then.

mlir/test/Dialect/Linalg/transform-tile-reduction.mlir
216

you may want to add a comment that this is supposed to fail gracefully and not change the IR

222

double comments here and below