[Mlir-commits] [mlir] [MLIR][SCF] Add an API to fuse consumer to a producer within scf loop (PR #88712)

Abhishek Varma llvmlistbot at llvm.org
Wed May 15 04:10:57 PDT 2024


Abhishek-Varma wrote:

>> 4. Now, the old candidate slice should be replaced by the cloned loop's candidate slice - this again requires you to traverse through the loop structure to find out exactly which insert slice op is going to be the new "old" candidate slice op

> Could you detail this with an example if possible?

Hi @Yun-Fly , sure.
What I meant above was that the API is based on `candidateSliceOp` : `fuseConsumerOfSlice(candidateSliceOp)`.

Now, assume this input IR (for sake of discussion let's just take single output def-chain) :-
```
%a = scf.for
         {
             %b  = scf.for
             {
                 . . .
                 %c = scf.for {
                      %candidateSlice = <CANDIDATE SLICE OF INTEREST>
                      scf.yield %candidateSlice
                 }
                 scf.yield %c
             }
             scf.yield %b
         }

%op1 = tensor.empty
%op2 = ..
...
%user = <USER OF %a -> which is essentially the actual "consumer" of %candidateSlice> this also uses other operand like %op1, %op2,... etc.
```

Now, since the API is invoked with `%candidateSlice` - after the point 3 I enlisted in the [above comment thread's pointers](https://github.com/llvm/llvm-project/pull/88712#issuecomment-2104441680) the state of the IR will become :-

```
%a = scf.for
         {
             %b  = scf.for
             {
                 . . .
                 %c = scf.for {
                      %candidateSlice = <CANDIDATE SLICE OF INTEREST>
                      scf.yield %candidateSlice
                 }
                 scf.yield %c
             }
             scf.yield %b
         }

%op1 = tensor.empty
%op2 = ..
...

%new_a = scf.for
         {
             %new_b  = scf.for
             {
                 . . .
                 %new_c = scf.for {
                      %new_candidateSlice = <CANDIDATE SLICE OF INTEREST>
                      scf.yield %new_candidateSlice
                 }
                 scf.yield %new_c
             }
             scf.yield %new_b
         }
%user = <USER OF %a -> which is essentially the actual "consumer" of %candidateSlice> this also uses other operand like %op1, %op2,... etc.
```

This was done to ensure that when we fuse the consumer the other operands should DOMINATE their use. Handling this THIS way for now seemed like a clean solution, else this in itself is another can of worms.

Now, the original invocation was `fuseConsumerOfSlice(%candidateSlice)`, which should now revolve around `%new_candidateSlice`.

After merging such big def-chains we need to know WHICH new candidate slice is 1:1 of the previous one. Involve multiple yielding `scf.for` and this already becomes too complex to handle at the moment.

Also, when I tried implementing the "fetch actual consumer" logic - I maintained the `OpResult`'s resultNumber as I went through the use-def-chains.

Let me know your thoughts. It's anyway better to deal with this in future if such use case arises. :)

https://github.com/llvm/llvm-project/pull/88712


More information about the Mlir-commits mailing list