This is an archive of the discontinued LLVM Phabricator instance.

[flang] Reset lbounds for allocatable function results.
ClosedPublic

Authored by vzakhari on Jul 24 2023, 4:28 PM.

Details

Summary

With HLFIR the lbounds for the ALLOCATABLE result are taken
from the mutable box created for the result, so the non-default
lbounds might be propagated further causing incorrect result, e.g.:

program p
  real, allocatable :: p5(:)
  allocate(p5, source=real_init())
  print *, lbound(p5, 1) ! must print 1, but prints 7
contains
  function real_init()
    real, allocatable :: real_init(:)
    allocate(real_init(7:8))
  end function real_init
end program p

With FIR lowering the box passed for source has explicit lower
bound 1 at the call site, but the runtime box initialized by
real_init call still has lower bound 7. I am not sure if
the runtime box initialized b real_init will ever be accessed
in a debugger via Fortran variable names, but I think that
having the right runtime bounds that can be accessible via
examining registers/stack might be good in general. So I decided
to update the runtime bounds at the point of return.

This change "fixes" the test above for HLFIR, but we may still
have a problem at the call site. I am not sure, though, where
the right fix should be.

Diff Detail

Event Timeline

vzakhari created this revision.Jul 24 2023, 4:28 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 24 2023, 4:28 PM
vzakhari requested review of this revision.Jul 24 2023, 4:28 PM

Hi @jeanPerier, can you please take a look when you have time? I am not sure whether this is the right solution.

jeanPerier accepted this revision.Sep 4 2023, 6:24 AM

Your patch makes sense to me.

My initial plan was to do it on the caller side by "moving" the result into an hlfir.expr here (via hlfir.as_expr with the move flag set): https://github.com/llvm/llvm-project/blob/ab340f97f92a7f8ae5b0df02410552a86aebc295/flang/lib/Lower/ConvertCall.cpp#L1210
But this will create some hassle for the finalization of the allocatable, if any (currently inserted here) , because finalization can currently only be done with entities in memory (maybe hlfir.destroy could be given a flag to indicate that finalization is required).

Regarding your fixme, from it semantic point of view, rather than a late catch-up, it would be nice if expressions that are not variables are lowered into hlfir.expr / trivial scalars in HLFIR, but I would first check that this is good from an optimization point of view (i.e., that hlfir.expr manipulation does not increase the number of array copies).

So I think your patch is the best solution right now, and if we see benefits to promoting in-memory function results to hlfir.expr, then we should move the lower bound clean-up at that point on the caller side (IMHO, the fact that the descriptor passed "leaks" the result variable lower bound is not a big issue since it is not associated to a variable name on the caller side. Similarly, the incoming descriptor for an assumed shape lacks the local lower bounds on the callee side, we cannot guarantee that the lower bounds from the register in the call are meaningful at every point of the call).

This revision is now accepted and ready to land.Sep 4 2023, 6:24 AM
tblah accepted this revision.Sep 5 2023, 4:28 AM

LGTM too. Thanks!