2019-08-24 04:42:13 +08:00
|
|
|
<!--
|
|
|
|
Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
-->
|
|
|
|
|
|
|
|
## Procedure reference implementation protocol
|
|
|
|
|
|
|
|
Fortran function and subroutine references are complicated.
|
|
|
|
This document attempts to collect the requirements imposed by the 2018
|
|
|
|
standard (and legacy extensions) on programs and implementations, work
|
|
|
|
through the implications of the various features, and propose both a
|
|
|
|
runtime model and compiler design.
|
|
|
|
|
|
|
|
All section, requirement, and constraint numbers herein pertain to
|
|
|
|
the Fortran 2018 standard.
|
|
|
|
|
|
|
|
This note does not consider calls to intrinsic procedures, statement
|
|
|
|
functions, or calls to internal runtime support library routines.
|
|
|
|
|
|
|
|
## Interfaces
|
|
|
|
|
|
|
|
Referenced procedures may or may not have declared interfaces
|
|
|
|
available to their call sites.
|
|
|
|
|
|
|
|
Calls to procedures with some post-'77 features require an explicit interface
|
|
|
|
(15.4.2.2):
|
|
|
|
* keyword arguments
|
|
|
|
* procedures that are `ELEMENTAL` or `BIND(C)`
|
|
|
|
* procedures that are required to be `PURE` due to the context of the call
|
|
|
|
(specification expression, `DO CONCURRENT`, `FORALL`)
|
|
|
|
* dummy arguments with these attributes: `ALLOCATABLE`, `POINTER`,
|
|
|
|
`VALUE`, `TARGET`, `OPTIONAL`, `ASYNCHRONOUS`, `VOLATILE`
|
2019-08-24 06:22:53 +08:00
|
|
|
(but *not* `CONTIGUOUS` or `INTENT()`!)
|
2019-08-24 04:42:13 +08:00
|
|
|
* dummy arguments that are coarrays, have assumed-shape/-rank,
|
|
|
|
have parameterized derived types, &/or are polymorphic
|
|
|
|
* function results that are arrays, `ALLOCATABLE`, `POINTER`,
|
|
|
|
or have derived types with any length parameters that are
|
|
|
|
neither constant nor assumed
|
|
|
|
|
|
|
|
Module procedures, internal procedures, procedure pointers,
|
|
|
|
type-bound procedures, and recursive references by a procedure to itself
|
|
|
|
always have explicit interfaces.
|
|
|
|
|
|
|
|
Other uses of procedures besides calls may also require explicit interfaces,
|
|
|
|
such as procedure pointer assignment, type-bound procedure bindings, &c.
|
|
|
|
|
|
|
|
### Implicit interfaces
|
|
|
|
|
|
|
|
In the absence of any characteristic or context that requires an
|
|
|
|
explicit interface (see above), a top-level function or subroutine
|
|
|
|
can be called via its implicit interface.
|
|
|
|
Each of the arguments can be passed as a simple address, including
|
|
|
|
dummy procedures.
|
|
|
|
Procedures that *can* be called via an implicit interface can
|
|
|
|
enjoy more thorough checking
|
|
|
|
by semantics when they do have a visible external interface, but must be
|
|
|
|
compiled as if all calls to them were through the implicit interface.
|
|
|
|
|
|
|
|
Procedures that can be called via an implicit interface should respect
|
|
|
|
the naming conventions and ABI, if any, used for Fortran '77 programs
|
|
|
|
on the target architecture, so that portable libraries can be compiled
|
|
|
|
and used by distinct implementations (and versions of implementations)
|
|
|
|
of Fortran.
|
|
|
|
|
|
|
|
Note that functions with implicit interfaces still have known result
|
|
|
|
types, possibly by means of implicit typing of their names.
|
|
|
|
They can also be `CHARACTER(*)` assumed-length character functions.
|
|
|
|
|
|
|
|
In other words: procedures that can be referenced with implicit interfaces
|
|
|
|
have argument lists that comprise only addresses of actual arguments,
|
|
|
|
the length of an assumed-length `CHARACTER(*)` result, and links to
|
|
|
|
of host variable blocks for dummy procedures (see below), and they can
|
|
|
|
return only scalar values of intrinsic types.
|
|
|
|
None of their arguments or results are implemented with descriptors.
|
|
|
|
|
2019-08-24 06:22:53 +08:00
|
|
|
Note that `INTENT` and `CONTIGUOUS` attributes do not, by themselves,
|
|
|
|
require the use of explicit interface; neither do dummy procedures.
|
|
|
|
Analyses of calls to procedures with implicit interfaces must make
|
|
|
|
allowances or impose restrictions capable of dealing with any of the
|
|
|
|
invisible `INTENT` and `CONTIGUOUS` attributes of dummy arguments
|
|
|
|
in the called procedure.
|
|
|
|
|
2019-08-24 04:42:13 +08:00
|
|
|
## Protocol overview
|
|
|
|
|
|
|
|
Here is a summary script of all of the actions that may need to be taken
|
|
|
|
by the calling procedure and its referenced procedure to effect
|
|
|
|
the call, entry, exit, and return steps of the procedure reference
|
|
|
|
protocol.
|
|
|
|
The order of these steps is not particularly strict, and we have
|
|
|
|
some design alternatives that are explored further below.
|
|
|
|
|
|
|
|
### Before the call:
|
2019-08-24 05:35:38 +08:00
|
|
|
|
2019-08-24 04:42:13 +08:00
|
|
|
1. Compute &/or copy into temporary storage the values of
|
|
|
|
some actual argument expressions and designators (see below).
|
|
|
|
1. Create and populate descriptors for assumed-shape/-rank arrays,
|
|
|
|
parameterized derived types with length, polymorphic types,
|
2019-08-24 05:35:38 +08:00
|
|
|
coarrays, and non-`POINTER` actual arguments (that are`TARGET`
|
2019-08-24 06:22:53 +08:00
|
|
|
or procedures) associated with `INTENT(IN) POINTER`
|
2019-08-24 05:35:38 +08:00
|
|
|
dummy arrays (15.5.2.7, C.10.4).
|
|
|
|
1. Possibly allocate function result storage,
|
2019-08-24 06:22:53 +08:00
|
|
|
when its size can be known by all callers; function results that are
|
2019-08-24 04:42:13 +08:00
|
|
|
neither `POINTER` nor `ALLOCATABLE` must have explicit shapes (C816).
|
|
|
|
1. Create and populate a descriptor for the function result, if it
|
|
|
|
needs one (deferred-shape/-length `POINTER`, any `ALLOCATABLE`,
|
|
|
|
parameterized derived type with non-constant length parameters, &c.).
|
|
|
|
1. Capture the values of host-escaping local objects in memory;
|
|
|
|
package them into single address (for calls to internal procedures &
|
|
|
|
for calls that pass internal procedures as arguments).
|
|
|
|
1. Resolve the target procedure's polymorphic binding, if any.
|
|
|
|
1. Marshal actual argument addresses/values into registers.
|
|
|
|
1. Marshal extra arguments for assumed-length `CHARACTER` result length,
|
|
|
|
function result descriptor, target host variable link, &/or dummy
|
|
|
|
procedure host variable links
|
|
|
|
1. Jump.
|
|
|
|
|
|
|
|
### On entry:
|
|
|
|
1. Shuffle `ENTRY` dummy arguments & jump to common entry point.
|
2019-08-24 05:35:38 +08:00
|
|
|
1. Complete `VALUE` copying if this step will not always be done
|
|
|
|
by the caller (as I think it should be).
|
2019-08-24 06:35:18 +08:00
|
|
|
1. Finalize &/or re-initialize `INTENT(OUT)` non-pointer
|
2019-08-24 05:35:38 +08:00
|
|
|
actual arguments (see below).
|
2019-08-24 06:22:53 +08:00
|
|
|
1. Optionally compact assumed-shape arguments for contiguity on one
|
|
|
|
or more leading dimensions to improve SIMD vectorization, if not
|
|
|
|
`TARGET` and not already sufficiently contiguous.
|
|
|
|
(PGI does this in the caller, whether the callee needs it or not.)
|
2019-08-24 04:42:13 +08:00
|
|
|
1. Complete allocation of function result storage, if that has
|
|
|
|
not been done by the caller.
|
|
|
|
1. Initialize components of derived type local variables,
|
|
|
|
including the function result.
|
|
|
|
|
|
|
|
Execute the callee, populating the function result or selecting
|
|
|
|
the subroutine's alternate return.
|
|
|
|
|
|
|
|
### On exit:
|
|
|
|
1. Clean up local scope (finalization, deallocation)
|
|
|
|
1. Deallocate `VALUE` argument temporaries.
|
|
|
|
(But don't finalize them; see 7.5.6.3(3)).
|
|
|
|
1. Replace any assumed-shape argument data that were compacted on
|
2019-08-24 06:22:53 +08:00
|
|
|
entry for partial contiguity for SIMD vectorization, if possibly
|
|
|
|
modified across the call (never when `INTENT(IN)` or `VALUE`).
|
2019-08-24 04:42:13 +08:00
|
|
|
1. Identify alternate `RETURN` to caller.
|
|
|
|
1. Marshal results.
|
|
|
|
1. Jump
|
|
|
|
|
|
|
|
### On return to the caller:
|
2019-08-24 06:22:53 +08:00
|
|
|
1. Save the result registers, if any.
|
2019-08-24 04:42:13 +08:00
|
|
|
1. Copy actual argument array designator data that was copied into
|
|
|
|
a temporary back into its original storage (see below).
|
|
|
|
1. Complete deallocation of actual argument temporaries (not `VALUE`).
|
2019-08-24 06:35:18 +08:00
|
|
|
1. Reload definable host-escaping local objects from memory, if they
|
|
|
|
were saved to memory by the host before the call.
|
2019-08-24 04:42:13 +08:00
|
|
|
1. `GO TO` alternate return, if any.
|
|
|
|
1. Use the function result in an expression.
|
|
|
|
1. Eventually, finalize &/or deallocate the function result.
|
|
|
|
|
|
|
|
## The messy details
|
|
|
|
|
|
|
|
### Copying actual argument values into temporary storage
|
|
|
|
|
|
|
|
There are several conditions that require the compiler to generate
|
|
|
|
code that allocates and populates temporary storage for an actual
|
|
|
|
argument.
|
|
|
|
|
|
|
|
First, actual arguments that are expressions, not designators, obviously
|
|
|
|
need to be computed and captured into memory in order to be passed
|
|
|
|
by reference.
|
|
|
|
This includes parenthesized designators like `(X)` as an important
|
|
|
|
special case, which are expressions in Fortran.
|
2019-08-24 06:22:53 +08:00
|
|
|
(This case also technically includes constants, but those are better
|
2019-08-24 06:35:18 +08:00
|
|
|
implemented by passing addresses in read-only memory when the interface
|
|
|
|
is explicit.)
|
2019-08-24 06:22:53 +08:00
|
|
|
The dummy argument cannot be known to have `INTENT(OUT)` or
|
|
|
|
`INTENT(IN OUT)`.
|
2019-08-24 04:42:13 +08:00
|
|
|
|
|
|
|
Small scalar or elemental `VALUE` arguments may be passed in registers.
|
|
|
|
Multiple elemental `VALUE` arguments might be packed into SIMD registers.
|
|
|
|
|
2019-08-24 06:22:53 +08:00
|
|
|
Actual arguments that are designators, not expressions, must also
|
|
|
|
be copied into temporaries in the following situations.
|
2019-08-24 04:42:13 +08:00
|
|
|
|
|
|
|
1. Coindexed objects need to be copied into the local image.
|
2019-08-24 06:22:53 +08:00
|
|
|
This can get very involved if they contain `ALLOCATABLE`
|
2019-08-24 04:42:13 +08:00
|
|
|
components, which also need to be copied, along with their
|
|
|
|
`ALLOCATABLE` components, and may be best implemented with a runtime
|
2019-08-24 06:22:53 +08:00
|
|
|
library routine working off a description of the type.
|
2019-08-24 04:42:13 +08:00
|
|
|
1. Actual arguments associated with dummies with the `VALUE`
|
|
|
|
attribute need to copied; this could be done on either
|
|
|
|
side of the call, but there are optimization opportunities
|
|
|
|
on the caller's side.
|
|
|
|
1. In non-elemental calls, the values of array sections with
|
|
|
|
vector-valued subscripts need to be compacted into temporaries.
|
|
|
|
These actual arguments are not definable, and they are not allowed to
|
|
|
|
be associated with non-`VALUE` dummy arguments with the attributes
|
|
|
|
`INTENT(IN)`, `INTENT(IN OUT)`, `ASYNCHRONOUS`, or `VOLATILE`
|
2019-08-24 06:22:53 +08:00
|
|
|
(15.4.2.4(21)); `INTENT()` can't always be checked.
|
|
|
|
1. Non-simply-contiguous (9.5.4) arrays being passed to non-`POINTER`
|
|
|
|
dummy arguments that must be contiguous due to a `CONTIGUOUS`
|
|
|
|
attribute, implicit interface, or not being assumed-shape/-rank.
|
2019-08-24 04:42:13 +08:00
|
|
|
This should be a runtime decision, so that actual arguments
|
|
|
|
that turn out to be contiguous can be passed cheaply.
|
2019-08-24 06:22:53 +08:00
|
|
|
This rule does not apply to coarray dummies, whose actual arguments
|
|
|
|
are required to be simply contiguous when this rule would otherwise
|
|
|
|
force the use of a temporary (15.5.2.8); neither does it apply
|
|
|
|
to `ASYNCHRONOUS` and `VOLATILE` actual arguments, which are
|
|
|
|
disallowed when it matters (C1539, C1540).
|
|
|
|
*Only temporaries created by this contiguity requirement are
|
|
|
|
subject to being copied back to the original variable after
|
|
|
|
the call* (see below).
|
|
|
|
|
|
|
|
While we are unlikely to want to _needlessly_ use a temporary for
|
2019-08-24 05:35:38 +08:00
|
|
|
an actual argument that does not require one for any of these
|
|
|
|
reasons above, we are specifically disallowed from doing so
|
|
|
|
by the standard in cases where pointers to the original target
|
|
|
|
data are required to be valid across the call (15.5.2.4(9-10)).
|
2019-08-24 06:22:53 +08:00
|
|
|
In particular, compaction of assumed-shape arrays for contiguity
|
|
|
|
on the leading dimension to ease SIMD vectorization cannot be
|
|
|
|
done safely for `TARGET` dummies.
|
2019-08-24 05:35:38 +08:00
|
|
|
|
2019-08-24 06:22:53 +08:00
|
|
|
Actual arguments associated with known `INTENT(OUT)` dummies that
|
|
|
|
require allocation of a temporary -- and this can only be for reasons of
|
2019-08-24 05:35:38 +08:00
|
|
|
contiguity -- don't have to populate it, but they do have to perform
|
|
|
|
minimal initialization of any `ALLOCATABLE` components so that
|
|
|
|
the runtime doesn't crash when the callee finalizes and deallocates
|
|
|
|
them.
|
|
|
|
Note that calls to implicit interfaces must conservatively allow
|
|
|
|
for the use of `INTENT(OUT)` by the callee.
|
2019-08-24 04:42:13 +08:00
|
|
|
|
2019-08-24 06:22:53 +08:00
|
|
|
Except for `VALUE` and known `INTENT(IN)` dummy arguments, the original
|
2019-08-24 04:42:13 +08:00
|
|
|
contents of local designators that have been compacted into temporaries
|
|
|
|
could optionally have their `ALLOCATABLE` components invalidated
|
|
|
|
across the call as an aid to debugging.
|
|
|
|
|
2019-08-24 06:22:53 +08:00
|
|
|
Except for `VALUE` and known `INTENT(IN)` dummy arguments, the contents of
|
2019-08-24 04:42:13 +08:00
|
|
|
the temporary storage will be copied back into the actual argument
|
|
|
|
designator after control returns from the procedure, and it may be necessary
|
|
|
|
to preserve addresses (or the values of subscripts and cosubscripts
|
|
|
|
needed to recalculate them) of the actual argument designator, or its
|
|
|
|
elements, in additional temporary storage if they can't be safely or
|
|
|
|
quickly recomputed after the call.
|
|
|
|
|
2019-08-24 05:35:38 +08:00
|
|
|
|
2019-08-24 04:42:13 +08:00
|
|
|
### `INTENT(OUT)` preparation
|
2019-08-24 05:35:38 +08:00
|
|
|
|
2019-08-24 04:42:13 +08:00
|
|
|
Actual arguments that are associated with `INTENT(OUT)`
|
|
|
|
dummy arguments are required to be definable.
|
2019-08-24 05:35:38 +08:00
|
|
|
This cannot always be checked, as the use of `INTENT(OUT)`
|
|
|
|
does not by itself mandate the use of an explicit interface.
|
2019-08-24 04:42:13 +08:00
|
|
|
|
2019-08-24 05:35:38 +08:00
|
|
|
`INTENT(OUT)` arguments are finalized (as if) on entry to the called
|
2019-08-24 04:42:13 +08:00
|
|
|
procedure. In particular, in calls to elemental procedures,
|
|
|
|
the elements of an array are finalized by a scalar or elemental
|
|
|
|
`FINAL` procedure (7.5.6.3(7)).
|
|
|
|
|
2019-08-24 05:35:38 +08:00
|
|
|
Derived type components that are `ALLOCATABLE` are finalized
|
|
|
|
and deallocated.
|
|
|
|
Components with initializers are (re)initialized.
|
2019-08-24 04:42:13 +08:00
|
|
|
|
|
|
|
The preparation of actual arguments for `INTENT(OUT)` could be
|
|
|
|
done on either side of the call. If the preparation is
|
|
|
|
done by the caller, there is an optimization opportunity
|
|
|
|
in situations where unmodified incoming `INTENT(OUT)` dummy
|
|
|
|
arguments are being passed onward as outgoing `INTENT(OUT)`
|
|
|
|
arguments.
|
|
|
|
|
|
|
|
### Copying temporary storage back into actual argument designators
|
|
|
|
|
2019-08-24 06:22:53 +08:00
|
|
|
Except for `VALUE` and known `INTENT(IN)` dummy arguments and array sections
|
2019-08-24 04:42:13 +08:00
|
|
|
with vector-valued subscripts (15.5.2.4(21)), temporary storage into
|
|
|
|
which actual argument data were compacted for contiguity before the call
|
|
|
|
must be redistributed back to its original storage by the caller after
|
|
|
|
the return.
|
|
|
|
|
|
|
|
In conjunction with saved cosubscript values, a standard descriptor
|
|
|
|
suffices to represent a pointer to the original storage into which the
|
|
|
|
temporary data should be redistributed.
|
|
|
|
|
|
|
|
Note that coindexed objects with `ALLOCATABLE` ultimate components
|
|
|
|
are required to be associated only with dummy arguments with the
|
|
|
|
`VALUE` &/or `INTENT(IN)` attributes (15.6.2.4(6)), so there is no
|
|
|
|
requirement that the local image somehow reallocate remote storage
|
|
|
|
when copying the data back.
|
|
|
|
|
|
|
|
### Host association linkage
|
|
|
|
|
|
|
|
Calls to dummy procedures and procedure pointers that resolve to
|
|
|
|
internal procedures need to pass an additional argument that
|
|
|
|
addresses on block of storage in the stack frame of the their
|
|
|
|
host subprogram that was active at the time they were passed as an
|
|
|
|
actual argument or associated with a procedure pointer.
|
|
|
|
This is similar to a static link in implementations of programming
|
|
|
|
languages with nested subprograms, although Fortran only allows
|
|
|
|
one level of nesting.
|
|
|
|
|
|
|
|
The host subprogram objects that are visible to any of their internal
|
|
|
|
subprograms need to be resident in memory across any calls to them
|
|
|
|
(direct or not). Any host subprogram object that might be defined
|
|
|
|
during a call to an internal subprogram needs to be reloaded after
|
|
|
|
a call or reside permanently in memory.
|
|
|
|
A simple conservative analysis of the internal subprograms can
|
|
|
|
identify all of these escaping objects and their definable subset.
|
|
|
|
|
|
|
|
The address of the host subprogram storage used to hold the escaping
|
|
|
|
objects needs to be saved alongside the code address(es) that
|
|
|
|
represent a procedure pointer.
|
|
|
|
It also needs to be conveyed alongside the actual argument for a
|
|
|
|
dummy procedure.
|
|
|
|
|
|
|
|
For subprograms that can be called with an implicit interface,
|
|
|
|
we cannot use a "procedure pointer descriptor" to represent an
|
|
|
|
actual argument for a dummy procedure -- a Fortran '77 routine
|
|
|
|
with an `EXTERNAL` dummy argument expects to receive a single
|
|
|
|
address. Instead, when passing an actual procedure on a call
|
|
|
|
to a procedure that can be called with an implicit interface,
|
|
|
|
we will need to use additional arguments to convey the host
|
|
|
|
storage link addresses.
|
|
|
|
|
|
|
|
## Further topics to document
|
|
|
|
|
|
|
|
### Target resolution
|
|
|
|
* polymorphic bindings
|
|
|
|
* procedure pointers
|
|
|
|
* dummy procedures
|
|
|
|
* generic resolution
|
|
|
|
|
|
|
|
### Arguments
|
|
|
|
* Alternate return specifiers
|
|
|
|
* `%VAL()` and `%REF()`
|
|
|
|
* Unrestricted specific intrinsic functions as actual arguments
|
2019-08-24 06:22:53 +08:00
|
|
|
* Check definability of known `INTENT(OUT)` and `INTENT(IN OUT)` actuals.
|
2019-08-24 05:35:38 +08:00
|
|
|
* Whether lower bounds in argument descriptors should be
|
|
|
|
initialized (they shouldn't be used)
|
2019-08-24 04:42:13 +08:00
|
|
|
|
|
|
|
### Naming
|
2019-08-24 06:22:53 +08:00
|
|
|
* Modules and submodules
|
|
|
|
* Procedures that can be called with implicit interfaces
|
|
|
|
* Procedures that must be called with explicit interfaces (possibly
|
|
|
|
with versioning)
|
2019-08-24 04:42:13 +08:00
|
|
|
* SIMD vs. scalar versions of `ELEMENTAL` procedures
|
|
|
|
* Unrestricted specific intrinsic functions (and perhaps SIMD variants)
|
|
|
|
|
|
|
|
### Other
|
|
|
|
* SIMD variants of `ELEMENTAL` procedures (& unrestricted specific intrinsics)
|
|
|
|
* Interoperable procedures
|
|
|
|
* Multiple code addresses for dummy procedures
|
|
|
|
* Elemental calls with array arguments
|