New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support calling assumed length dummy procedure #1393
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few nits ...
I can confirm that, aside from the nits, all builds, tests, and looks good. But you should probably get someone more familiar with the code to approve.
flang/lib/Lower/CallInterface.cpp
Outdated
// array function with assumed length (f18 forbides defining such | ||
// interfaces). Hence, passing the length is most likely useless, but stick | ||
// with ifort/nag/xlf interface here. | ||
if (std::optional<Fortran::evaluate::DynamicType> type = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but this is really pretty strange. Why wouldn't the argument have the type () -> !fir.boxchar<k>
or (!fir.ref<!fir.char<k,l>>, index) -> !fir.boxchar<k>
(since a character return value is also a hidden argument)? The actual argument must be a function that returns a boxchar
, right? It can never just be a value of boxchar
type (which cannot be called).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would () -> !fir.boxchar<k>
carry the length value on top of the function address ? Are you thinking of making () -> !fir.boxchar<k>
a tuple like fir.boxchar under the hood ? Why not, but then we would need special op to create these addresses + length tuple like emboxchar and a way to extract the length.
end interface | ||
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QPbar1) : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1> | ||
! CHECK: %[[VAL_1:.*]] = arith.constant 7 : i64 | ||
! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : ((!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>) -> !fir.ref<!fir.char<1,?>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cast is lossy and odd looking to me. It is lossy in that we have a function pointer and are converting it to a data pointer, which loses information that the pointer is to code and not data. Subsequently, the IR has no way to reason about this value correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, what do you see as an alternative here ? It is currently not possible to create a fir.embox_char with a function address. Should we allow that to avoid the cast or should we create a new operation here (other alternatives welcomed if you see any) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @schweitzpgi and @psteinfeld for the review. I have updated all the code comments and applied the small modifications.
@schweitzpgi I understand you are against using fir.boxchar as a tuple <function address , result length if know in the siganture> ? I can look into using an actual mlir tuple type here to keep the function type visible in the tuple. However this will require deeper change: A new case to handle in argument lowering and a modification in codegen to deal with the tuple like fir.boxchar<> (I liked the idea of using fir.boxchar to avoid having to add special handling in codegen). Does that sounds a better solution to you ?
flang/lib/Lower/CallInterface.cpp
Outdated
// array function with assumed length (f18 forbides defining such | ||
// interfaces). Hence, passing the length is most likely useless, but stick | ||
// with ifort/nag/xlf interface here. | ||
if (std::optional<Fortran::evaluate::DynamicType> type = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would () -> !fir.boxchar<k>
carry the length value on top of the function address ? Are you thinking of making () -> !fir.boxchar<k>
a tuple like fir.boxchar under the hood ? Why not, but then we would need special op to create these addresses + length tuple like emboxchar and a way to extract the length.
@schweitzpgi , I have updated the PR to lower the character dummy procedure argument to a Note that the function address type in the tuple remains poor (
|
061f1c4
to
15deaf4
Compare
Rebased to solve conflicts and added comments in Character.h. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gave it a quick look. LGTM.
When passing a character procedure as a dummy procedure, the result length must be passed along the function address. This is to cover the cases where the dummy procedure is declared with assumed length inside the scope that will call it (it will need the length to allocate the result on the caller side). To be compatible with other Fortran compiler, this length must be appended after all other argument just like character objects (fir.boxchar). A fir.boxchar cannot be used to implement this feature because it is meant to take an object address, not a function address. Instead, argument like `tuple<function type, integer type> {fir.char_proc}` will be recognized as being character dummy procedure in FIR. That way lowering does not have to do the argument split. This patch adds tools in Character.h to create this type and tuple values as well as to recognize them and extract its tuple members. It also updates the target rewrite pass to split these arguments like fir.boxchar. See: #1393
Lowering was not able to compile the following kind of program: ``` subroutine foo(bar) character*(*) :: bar print *, bar() end subroutine ``` This resulted in error `missing length for character`. To support this kind of program, pass the result character dummy procedure as character dummy objects: with its length. This matches nvfortran, ifort, nag and xlf behavior (but not gfortran that does not support the above code). This is done by using the tuple<function address, length> added in the Optimnizer to implement character dummy procedure and let codegen split and order the argument so that in call like `foo(c1, bar, c2)` with `c1` and `c2` F77 like characters, the result length of `bar` is placed between the one of `c1` and `c2` after all other arguments. Three places are impacted: - The function interface lowering (mustPassDummyProcedureAsBoxChar is the central place that can completely disable this feature On and Off). - When placing a call to a dummy procedure, use the tuple length as a last resort if present in the interface. - When passing a procedure designator, forward the length for character function based on mustPassDummyProcedureAsBoxChar. See: #1393
15deaf4
to
a306179
Compare
When passing a character procedure as a dummy procedure, the result length must be passed along the function address. This is to cover the cases where the dummy procedure is declared with assumed length inside the scope that will call it (it will need the length to allocate the result on the caller side). To be compatible with other Fortran compiler, this length must be appended after all other argument just like character objects (fir.boxchar). A fir.boxchar cannot be used to implement this feature because it is meant to take an object address, not a function address. Instead, argument like `tuple<function type, integer type> {fir.char_proc}` will be recognized as being character dummy procedure in FIR. That way lowering does not have to do the argument split. This patch adds tools in Character.h to create this type and tuple values as well as to recognize them and extract its tuple members. It also updates the target rewrite pass to split these arguments like fir.boxchar. See: flang-compiler#1393
When passing a character procedure as a dummy procedure, the result length must be passed along the function address. This is to cover the cases where the dummy procedure is declared with assumed length inside the scope that will call it (it will need the length to allocate the result on the caller side). To be compatible with other Fortran compiler, this length must be appended after all other argument just like character objects (fir.boxchar). A fir.boxchar cannot be used to implement this feature because it is meant to take an object address, not a function address. Instead, argument like `tuple<function type, integer type> {fir.char_proc}` will be recognized as being character dummy procedure in FIR. That way lowering does not have to do the argument split. This patch adds tools in Character.h to create this type and tuple values as well as to recognize them and extract its tuple members. It also updates the target rewrite pass to split these arguments like fir.boxchar. See: #1393
Patch for optimizer related change in LLVM: https://reviews.llvm.org/D118108 |
When passing a character procedure as a dummy procedure, the result length must be passed along the function address. This is to cover the cases where the dummy procedure is declared with assumed length inside the scope that will call it (it will need the length to allocate the result on the caller side). To be compatible with other Fortran compiler, this length must be appended after all other argument just like character objects (fir.boxchar). A fir.boxchar cannot be used to implement this feature because it is meant to take an object address, not a function address. Instead, argument like `tuple<function type, integer type> {fir.char_proc}` will be recognized as being character dummy procedure in FIR. That way lowering does not have to do the argument split. This patch adds tools in Character.h to create this type and tuple values as well as to recognize them and extract its tuple members. It also updates the target rewrite pass to split these arguments like fir.boxchar. This part is part of fir-dev upstreaming. It was reviwed previously in: flang-compiler#1393 Differential Revision: https://reviews.llvm.org/D118108
When passing a character procedure as a dummy procedure, the result length must be passed along the function address. This is to cover the cases where the dummy procedure is declared with assumed length inside the scope that will call it (it will need the length to allocate the result on the caller side). To be compatible with other Fortran compiler, this length must be appended after all other argument just like character objects (fir.boxchar). A fir.boxchar cannot be used to implement this feature because it is meant to take an object address, not a function address. Instead, argument like `tuple<function type, integer type> {fir.char_proc}` will be recognized as being character dummy procedure in FIR. That way lowering does not have to do the argument split. This patch adds tools in Character.h to create this type and tuple values as well as to recognize them and extract its tuple members. It also updates the target rewrite pass to split these arguments like fir.boxchar. This part is part of fir-dev upstreaming. It was reviwed previously in: flang-compiler#1393 Differential Revision: https://reviews.llvm.org/D118108
When passing a character procedure as a dummy procedure, the result length must be passed along the function address. This is to cover the cases where the dummy procedure is declared with assumed length inside the scope that will call it (it will need the length to allocate the result on the caller side). To be compatible with other Fortran compiler, this length must be appended after all other argument just like character objects (fir.boxchar). A fir.boxchar cannot be used to implement this feature because it is meant to take an object address, not a function address. Instead, argument like `tuple<function type, integer type> {fir.char_proc}` will be recognized as being character dummy procedure in FIR. That way lowering does not have to do the argument split. This patch adds tools in Character.h to create this type and tuple values as well as to recognize them and extract its tuple members. It also updates the target rewrite pass to split these arguments like fir.boxchar. This part is part of fir-dev upstreaming. It was reviwed previously in: flang-compiler/f18-llvm-project#1393 Differential Revision: https://reviews.llvm.org/D118108
Lowering was not able to compile the following kind of program:
This resulted in error
missing length for character
.To support this kind of program, pass the result character dummy procedure as
character dummy objects: with its length. This matches nvfortran, ifort,
nag and xlf behavior (but not gfortran that does not support the above
code).
This is done by using fir.boxchar. The rational for using it instead of
manually mangling the length argument is that in call like
foo(c1, bar, c2)
withc1
andc2
F77 like characters, the resultlength of
bar
must be placed between the one ofc1
andc2
afterall other arguments. fir.boxchar guarantees exactly that.
Three places are impacted:
the central place that can completly disable this feature On and Off).
as a last resort if present in the interface.
function based on mustPassDummyProcedureAsBoxChar.