This is an archive of the discontinued LLVM Phabricator instance.

[flang] Lower type-bound procedure call needing dynamic dispatch to fir.dispatch
ClosedPublic

Authored by clementval on Oct 11 2022, 1:09 AM.

Details

Summary

Lower call with polymorphic entities to fir.dispatch operation. This patch only
focus one lowering with simple scalar polymorphic entities. A follow-up patch
will deal with allocatble, pointer and array of polymorphic entities as they
require box manipulation for the passed-object.

Diff Detail

Event Timeline

clementval created this revision.Oct 11 2022, 1:09 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptOct 11 2022, 1:09 AM
Herald added a subscriber: mehdi_amini. · View Herald Transcript
clementval requested review of this revision.Oct 11 2022, 1:09 AM
jeanPerier added inline comments.Oct 11 2022, 3:40 AM
flang/lib/Lower/ConvertExpr.cpp
2756

What about changing the if (ultimateSymbol.attrs().test(Fortran::semantics::Attr::NOPASS) into if ( std::optional<unsigned> passArg = caller.getPassArgIndex()) { ... (and reverse the regions) so that there is no questions about "*passArg" being safe ?

flang/lib/Lower/Mangler.cpp
159

This may be introducing some weird collision risks.

As I understand it, we do not care about the mangling here since dispatch uses the fortran name. I guess you need this because the CallInterface wants to declare some fir.func op that is not actually used.

The collision risk I see should be illustrated by the program below that I think will hit a bad convert from fir.ref<f32> to fir.box<> in a piece of code that has nothing to do with your changes.

module m
  type p1
    integer :: a
    integer :: b
  contains
    procedure, nopass :: foo => bar
  end type

contains
  subroutine check_dispatch(p, x)
      class(p1) :: p
      real :: x(:)
      call p%foo(x)
  end subroutine
  subroutine bar(x)
    real :: x(:)
  end subroutine 
end module

 real :: x
 ! unrelated to foo from module m, yet due to function name clash in MLIR,
 ! I think it will collide and use the same argument types of bar,
 ! trying to cast the argument to a fir.box as if the mismatch was a simple implicit interface issue.
 call foo(x) 
end

My suggestion is to skip the func creation in the CalllerInterface (like this done for function pointers).

flang/lib/Optimizer/Builder/FIRBuilder.cpp
472

OK, the pattern you showed me makes more sense to me now. But this code is broken for now here, right ? How can the new embox get the correct dynamic type from the original fir.coordinate_of fir.class base ?

clementval added inline comments.Oct 11 2022, 3:44 AM
flang/lib/Lower/ConvertExpr.cpp
2756

Yeah it works too. I'll update it.

flang/lib/Lower/Mangler.cpp
159

Right it was needed only because of the func creation. I'll just skip it.

flang/lib/Optimizer/Builder/FIRBuilder.cpp
472

Yes this is left over from a previous attempt. I'll remove it from this patch and add it back when it is functional.

clementval marked 2 inline comments as done.

Address review comments

clementval marked an inline comment as done.Oct 11 2022, 5:16 AM
clementval added inline comments.
flang/lib/Lower/Mangler.cpp
159

Using the actual procedure name for mangling should also work and avoid collision.

Jean is the expert on the content, but I can confirm that all builds and tests correctly and looks good.

jeanPerier added inline comments.Oct 12 2022, 12:53 AM
flang/lib/Lower/Mangler.cpp
159

Why not, but then I think this should use return mangleName(procBinding.symbol(), keepExternalInScope) so that the scope is correctly mangled. Otherwise, I think this may still conflict if you update "bar" in my example above to be called "foo" (BTW, I think you can use the lambda argument directly for the details instead of getting it back from the ultimate symbol).

One point where I am less sure of, is what would happen with DEFERRED procedures. They do not exist (the type extending the abstract type will actually define the bindings). So I am not sure if this can lead to some weird scenario. I could not find one, because I think whatever conflicting procedure in that case would be declared before the dispatch call is processed (because it would not be possible to call a procedure with such name with an implicit procedure, and only implicit call lead to "on the fly" func declaration attempts).

You might still want to double check this is OK:

module m
  interface
    subroutine bar(x)
      real :: x(:)
    end subroutine
  end interface
  type, abstract :: p1
    integer :: a
    integer :: b
  contains
    procedure(bar), deferred, nopass :: foo 
  end type

contains
  subroutine check_dispatch(p, x)
      class(p1) :: p
      real :: x(:)
      call p%foo(x)
  end subroutine

  subroutine foo(x)
    real :: x
  end subroutine
end module

 use m
 real :: x
 call foo(x) 
end

Address review comment

clementval added inline comments.Oct 12 2022, 2:34 AM
flang/lib/Lower/Mangler.cpp
159

I updated to return mangleName. I'm not finding one either. The above example behave correctly with the current lowering so I guess we should be fine unless we find another corner case.

clementval marked an inline comment as done.Oct 12 2022, 2:34 AM

Add test with deferred tbp

jeanPerier accepted this revision.Oct 12 2022, 6:20 AM

LGTM, thanks for addressing the comments.

This revision is now accepted and ready to land.Oct 12 2022, 6:20 AM