This is an archive of the discontinued LLVM Phabricator instance.

[mlir][CFGToSCF] Visit subregions in CFGToSCF pass
ClosedPublic

Authored by Hardcode84 on Aug 19 2023, 2:28 PM.

Details

Summary

This is useful when user already have partially-scf'ed IR or other ops with nested regions (e.g. linalg.generic).

Diff Detail

Event Timeline

Hardcode84 created this revision.Aug 19 2023, 2:28 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 19 2023, 2:28 PM
Hardcode84 requested review of this revision.Aug 19 2023, 2:28 PM
Hardcode84 edited the summary of this revision. (Show Details)
zero9178 added a comment.EditedAug 20 2023, 2:36 AM

There is one concern that I have with this change, which is that if the subregion were to contain an infinite loop, forcing the creation of an unreachable terminator, the interface implementation would currently create a func.return with a poison value which IIRC is only allowed to be nested within a func.func.
Since the interface implementation cannot know (I think no such interface exists at the moment) what kind of terminator is required, it'd lead to invalid IR.
Example IR:

func.func private  @foo()

func.func @nested_region() {
  scf.execute_region {
    cf.br ^bb0
  ^bb0:
    func.call @foo() : () -> ()
    cf.br ^bb0
  }
  return
}

A solution to this would ideally be a ub.unreachable op. An interface or trait returning or helping build an appropiate terminator for a region op would also help but a lot more intrusive I imagine.

There is one concern that I have with this change, which is that if the subregion were to contain an infinite loop, forcing the creation of an unreachable terminator, the interface implementation would currently create a func.return with a poison value which IIRC is only allowed to be nested within a func.func.
Since the interface implementation cannot know (I think no such interface exists at the moment) what kind of terminator is required, it'd lead to invalid IR.
Example IR:

func.func private  @foo()

func.func @nested_region() {
  scf.execute_region {
    cf.br ^bb0
  ^bb0:
    func.call @foo() : () -> ()
    cf.br ^bb0
  }
  return
}

A solution to this would ideally be a ub.unreachable op. An interface or trait returning or helping build an appropiate terminator for a region op would also help but a lot more intrusive I imagine.

I've checked it and pass actually fails gracefully in this case, although error message is not very informative

Expected 'func.func' as top level operation

So, I think if pass fails gracefully and we change error message to smth like Cannot create unreachable terminator for 'opname' it should be fine.

So, I think if pass fails gracefully and we change error message to smth like Cannot create unreachable terminator for 'opname' it should be fine.

Yeah I think that the implementation of a ub.unreachable shouldn't be a block for this either and creating a nicer error message would be great.
I do think that this should be documented however and if possible, that overriding the interface and using the transformCFGToSCF function manually ideally mentioned as an alternative.
One of the reason the interface and separate function exist is because I figured it was impossible to fit every downstream scenario with just an upstream pass, so creating the tools for people to make their own passes was important.

improve error message and pass docs

zero9178 accepted this revision.Aug 20 2023, 6:04 AM

LGTM

mlir/include/mlir/Conversion/Passes.td
310 ↗(On Diff #551821)
This revision is now accepted and ready to land.Aug 20 2023, 6:04 AM
This revision was automatically updated to reflect the committed changes.
Hardcode84 marked an inline comment as done.Aug 20 2023, 10:36 AM