This is an archive of the discontinued LLVM Phabricator instance.

[flang] Fix function result rewrite for CPTR type
ClosedPublic

Authored by peixin on Nov 7 2022, 5:54 AM.

Details

Summary

Not all derived type can be taken as abstract result. The CPTR type
should be treated as return by value so to interoperable with C
functions. Fix the function result rewrite for CPTR type, but it
should be generalized for all derived types. The ABI of
interoperability with C for derived type is architecture dependent,
which should be supported later.

Diff Detail

Event Timeline

peixin created this revision.Nov 7 2022, 5:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptNov 7 2022, 5:54 AM
peixin requested review of this revision.Nov 7 2022, 5:54 AM

Thanks so much for working on this. Aside from a few comments on function names and grammar in comments, all builds and tests correctly and looks good to me.

I've also verified that this fixes the test case in issue #58772.

@jeanPerier, can you also please take a look at this patch?

flang/lib/Optimizer/Transforms/AbstractResult.cpp
61–62

It looks like the function getNewFuncResultType is specific to functions that return CPTR types. If so, I recommend that this be reflected in the name -- perhaps getCptrFuncResultType?

Also, I would reword the comment as follows:

/// This is for function result types that are of type C_PTR from ISO_C_BINDING.  Follow the
/// ABI for interoperability with C.
109

"derived type" should read "derived types".

192

"derived type" should read "derived types".

325

"derived type" should read "derived types".

peixin planned changes to this revision.Nov 7 2022, 5:12 PM

Will support AddrOfOp rewrite, too. It is for procedure passed as argument.

peixin updated this revision to Diff 473911.Nov 8 2022, 1:00 AM

Address the comments and add support for AddrOp rewrite.

jeanPerier added inline comments.Nov 8 2022, 2:06 AM
flang/lib/Optimizer/Transforms/AbstractResult.cpp
149

Shouldn't this be callOp.getOperands().begin() +1 to skip the function address that was already added above ?
If so, I think the !isResultBuiltinCPtr could just guard newOperands.push_back(arg);.

flang/test/Fir/abstract-results.fir
90

Why not using fir.ref<None> so that it is sure the ABI matches what is done for a void* return type in C ?

peixin added inline comments.Nov 8 2022, 2:51 AM
flang/lib/Optimizer/Transforms/AbstractResult.cpp
149

Did you comment this when you read the last update? I think this has been updated.

flang/test/Fir/abstract-results.fir
90

The test case happened to return a C pointer. It does seem to be more reasonable to return fir.ref<None> for a c_ptr. However, for general purpose of ABI of returning a derived type with only one component with the type i64, the ABI for the derived type returned is i64. Finally, there will be no isa_builtin_cptr_type check for c_ptr. Instead, it will be replaced with checking the derived type. At that time, we need to i64 for c_ptr return value.

Thanks for the quick fix!

All builds and tests correctly and looks good to me. I've also verified that this fixes issue #58849.

Please wait for @jeanPerier to approve before merging.

jeanPerier accepted this revision.Nov 8 2022, 8:04 AM
jeanPerier added inline comments.
flang/lib/Optimizer/Transforms/AbstractResult.cpp
149

Yes, looks good now.

flang/test/Fir/abstract-results.fir
90

Let's discuss this outside of this change. I feel C_PTR is special enough so that we should not treat it as a struct {i64} in function interface. I just feel using fir.ref<None> will ensure it is OK regardless of the ABI (it is likely i64 works with most, but it would just be simpler to use fir.ref<None> than to verify this assumption for every ABI).

Then, I am not entirely clear where you are going with the next change extending this to single component derived types. Is this only in the BIND(C) context or for all functions ? For BIND(C), I agree we may have to go down that rabbit hole, and it won't be fun to replicate the C ABI generated by clang for structs, that I guess is likely target dependent.
Outside of the BIND(C) context, it is not clear to me what would be the reason for doing this (ifort and nvfortran are not doing this I believe). I would stay away from it (the only issue I see is that in the abstract result rewrite pass you do not have a way to tell if a function type is bind(C) or not, and with indirect calls, there may not be a funcOp declaration to tell that).

This revision is now accepted and ready to land.Nov 8 2022, 8:04 AM
This revision was automatically updated to reflect the committed changes.