This is an archive of the discontinued LLVM Phabricator instance.

[flang] Document and use intrinsic subroutine argument intents
ClosedPublic

Authored by jeanPerier on Oct 15 2020, 7:59 AM.

Details

Summary

Check INTENT(OUT)/INTENT(INOUT) constraints for actual argument
of intrinsic procedure calls.

  • Adding a common::Intent field to the IntrinsicDummyArgument

in the intrinsic table.

  • Propagating it to the DummyDataObject intent field so that it can

later be used in CheckExplicitDataArg semantic checks.

  • Add related tests.
  • Fix regression (C846 false error), C846 INTENT(OUT) rule does not apply to intrinsic call. Propagate the information that we are in an intrinsic call up to CheckExplicitDataArg (that is doing this check). Still enforce C846 on intrinsics other than MOVE_ALLOC (for which allocatable coarrays are explicitly allowed) since it's not clear it is allowed in all intrinsics and allowing this would lead to runtime penalties in the intrinsic runtime.

Note 1: The added intent field is useless for all intrinsic
functions since none of them have intent out/inout arguments (I think,
but did not thoroughly checked). Since the table is not that small, the
change leads in a ~10ko increase in intrinsics.cpp.o (RL mode, gcc 8.3).
Since we are talking a bout a 0.03% space increase and that I am not sure how true
it is that all intrinsic functions will always have intent in arguments,
I ruled that this was OK.

Note 2: For the C846 fix, I considered adding an "Intrinsic" attribute
to characteristics::Procedure Attr, it worked but then seemed like a
bad idea to me since we would think that we are in an intrinsic call
when calling bar in the program below since characteristic built from
an intrinsic name can be used for user procedure.

subroutine foo(bar)
  procedure(acos) bar
  y = bar(x)
end subroutine

Diff Detail

Event Timeline

jeanPerier created this revision.Oct 15 2020, 7:59 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 15 2020, 7:59 AM
jeanPerier requested review of this revision.Oct 15 2020, 7:59 AM
PeteSteinfeld accepted this revision.Oct 15 2020, 9:13 AM

All builds, tests, and looks good.

This revision is now accepted and ready to land.Oct 15 2020, 9:13 AM
klausler added inline comments.Oct 15 2020, 9:27 AM
flang/include/flang/Evaluate/characteristics.h
236

Another possibility: implement a GetIntent(), then implement HasIntent() using GetIntent() or with comparisons.

flang/lib/Semantics/check-call.cpp
316

Are all ALLOCATABLE coarrays really acceptable as actual arguments to INTENT(OUT) intrinsic subroutine arguments?

Change DummyArgument::HasIntent to DummyArgument::GetIntent.

jeanPerier marked an inline comment as done.Oct 16 2020, 1:21 AM
jeanPerier added inline comments.
flang/include/flang/Evaluate/characteristics.h
236

Thanks, GetIntent is more flexible. I dropped HasIntent since it does not bring much on top of GetIntent for the use site in lowering.

flang/lib/Semantics/check-call.cpp
316

What I am sure of is that C846 does not apply to intrinsic procedure, and that is is clearly OK for some intrinsic subroutine to have ALLOCATBLE coarrays as actual argument of INTENT(OUT) intrinsic arguments.

What I am not sure of is that it is OK in all intrinsic subroutine. e.g.: is it OK for COUNT argument of SYSTEM_CLOCK to get a coarray allocatable argument ? I can't find a rule that prevents it given C846 clearly does not apply for SYSTEM_CLOCK and SYSTEM_CLOCK says nothing about coarray/coindexed arguments.

I can't find narrower sort of allocable coarrays that would always be forbidden in intrinsic subroutine INTENT(OUT) arguments. Maybe coindexed objects should always be banned from INTENT(OUT), but the problem seems orthogonal to allocatables, all INTENT(OUT) intrinsic argument specific that implicitly tells that coarray are ok (by restricting things on their coranks) bans coindexed objects, whether their base is allocatable or not. Even then, it seems left to each intrinsic to define this (since some are explicitly banning them).

My conclusion from this is that we cannot derive a generic rules about allocatable coarrays in INTENT(OUT) intrinsic subroutine argument that we could enforce here. However, we may want to strengthen case by case intrinsic checks in intrinsic.cpp. For instance its clear coindexed objects are not OK in move_alloc and we are not complaining about this (both before or after this patch).

Why I am sure it is OK for at least some intrinsics
C846 :

An INTENT (OUT) dummy argument of a nonintrinsic procedure shall not be an allocatable coarray or
have a subobject that is an allocatable coarray.

MOVE_ALLOC TO argument that is INTENT(OUT) clearly accepts allocatable coarray actual arguments (16.9.137):

TO be type compatible (7.3.2.3) with FROM and have the same rank and corank.
It shall be allocatable and shall not be a coindexed object.
It shall be polymorphic if FROM is polymorphic. It is an INTENT (OUT) argument.
Each nondeferred parameter of the declared type of TO shall have the same value as the corresponding parameter of the declared type of FROM.

Why I am not sure this is OK for all subroutines
I can't find something that clearly forbids it, but I agree it's weird to allow it in all intrinsic subroutines.

Regrading the actual <-> dummy association rules, they are rules that prevents allocatable coindexed objects to be passed to intent(out)/intent(intout), but nothing regarding coarrays arguments (My understanding is that coarray are not coindexed objects):

15.5.2.4 .6 If the actual argument is a coindexed object with an allocatable ultimate component, the dummy argument shall have the INTENT (IN) or the VALUE attribute.
15.5.2.6 If the actual argument is a coindexed object, the dummy argument shall have the INTENT (IN) attribute.

It looks like it's up to each intrinsic definition in the standard to rule what's allowed here. However, I feel like there may be gaps in the "old" subroutines that may not have been updated regarding coarrays. The atomic subroutine all specify that coindexed object are not OK for their STAT argument that is INTENT(OUT). However, no such restriction is given for the STATUS field of GET_COMMAND for instance. That sounds weird to me. I am surprised allocable coarrays are something we would want in SYSTEM_CLOCK arguments, supporting this would bring some implementation complexity here.

klausler accepted this revision.Oct 16 2020, 10:24 AM
klausler added inline comments.
flang/lib/Semantics/check-call.cpp
316

Anything that can change the address of a coarray allocatable on an image implies synchronization, it's pretty heavyweight.

Can we allow INTENT(OUT) ALLOCATABLE coarrays only where they are explicitly allowed and necessary (MOVE_ALLOC) and disallow them otherwise?

jeanPerier marked an inline comment as done.

Only allow INTENT(OUT) allocatable coarrays in intrinsics where they are
explicitly allowed intstead of all intrinsics.

jeanPerier marked an inline comment as done.Oct 19 2020, 4:15 AM
jeanPerier added inline comments.
flang/lib/Semantics/check-call.cpp
316

Sounds like a safer approach. I have modified the patch to only allow this in MOVE_ALLOC.

jeanPerier edited the summary of this revision. (Show Details)Oct 19 2020, 4:19 AM
This revision was landed with ongoing or failed builds.Oct 20 2020, 5:11 AM
This revision was automatically updated to reflect the committed changes.
jeanPerier marked an inline comment as done.