Some routines and calls in external Fortran classes are compiled using the Fortran parameter passing convention. This section describes how this is achieved. Routines without bodies in external Fortran classes and Fortran routines (routines whose return types and all arguments are Fortran types) are compiled as described below. The explanation is done in terms of mapping the original Sather signatures to C prototypes. All Fortran types are assumed to have corresponding C types defined. For example, F_INTEGER class maps onto F_INTEGER C type. See unnamedlink for details on how this could be achieved in a portable fashion. The examples are used to illustrate parameter passing only - the actual binding of function names is irrelevant for this purpose.
Routines that return F_INTEGER, F_REAL, F_LOGICAL, and F_DOUBLE map to C functions that return corresponding C types. A routine that returns F_COMPLEX or F_DOUBLE_COMPLEX is equivalent to a C routine with an extra initial arguments preceding other arguments in the argument list. This initial argument points to the storage for the return value.
F_COMPLEX foo(i:F_INTEGER,a:F_REAL); -- this Sather signature is equivalent to void foo(F_COMPLEX* ret_val, F_INTEGER* i_address, F_REAL* a_address) |
A routine that returns F_CHARACTER is mapped to a C routine with two additional arguments: a pointer to the data, and a string size, always set to 1 in the case of F_CHARACTER.
F_CHARACTER foo(i:F_INTEGER, a:F_REAL); -- this Sather signature maps to void foo(F_CHARACTER* address, F_LENGTH size, F_INTEGER* i_address, F_REAL* a_address); |
Similarly, a routine returning F_STRING is equivalent to a C routine with two additional initial arguments, a data pointer and a string length[1]
F_STRING foo(i:F_INTEGER, a:F_REAL); -- this Sather signature maps to void foo(F_CHARACTER* address, F_LENGTH size, F_INTEGER* i, F_REAL* a); |
[1] The current Sather 1.1 implementation disallows returning Fortran strings of size greater than 32 bytes. This restriction may be lifted in the future releases.
All Fortran arguments are passed by reference. In addition, for each argument of type F_CHARACTER or F_STRING, an extra parameter whose value is the length of the string is appended to the end of the argument list.
foo(i:F_INTEGER,c:F_CHARACTER,a:F_REAL):F_INTEGER -- this is mapped to F_INTEGER foo(F_INTEGER* i_address, F_CHARACTER*c_address, F_REAL* a_address, F_LENGTH c_length); -- all calls have c_length set to 1 |
foo(i:F_INTEGER,s:F_STRING,a:F_REAL):F_INTEGER -- this is mapped to F_INTEGER foo(F_INTEGER* i_address, F_CHARACTER* s_address, F_REAL* a_address, F_LENGTH s_length); -- propoer s_length is supplied by the caller |
Additional string length arguments are passed by value. If there are more than one F_CHARACTER or F_STRING arguments, the lengths are appended to the end of the list in the textual order of string arguments:
foo(s1:F_STRING,i:F_INTEGER,s2:F_STRING,a:F_REAL); -- this is mapped to void foo(F_CHARACTER* s1_address, F_INTEGER* i_address, F_CHARACTER* s2_address, F_REAL a_address, F_LENGTH s1_length, F_LENGTH s2_length); |
Sather signatures that have F_HANDLER arguments correspond to C integer functions whose return value represents the alternate return to take. The actual handlers are not passed to the Fortran code. Instead, code to do the branching based on the return value is emitted by the Sather compiler to conform to the alternate return semantics.
Arguments of type F_ROUT are passed as function pointers.
Thus, the entire C argument list including additional arguments consists of:
one additional argument due to F_COMPLEX or F_DOUBLE_COMPLEX return type, or two additional arguments due to F_CHARACTER or F_STRING return type
references to "normal" arguments corresponding to a Sather signature argument list
additional arguments for each F_CHARACTER or F_STRING argument in the Sather signature
The following example combines all rules
foo(s1:F_STRING, i:F_INTEGER, a:F_REAL, c:F_CHARACTER):F_COMPLEX -- is mapped to void foo(F_COMPLEX* ret_address, F_CHARACTER* s1_address, F_INTEGER* i_address, F_REAL* a_address, F_CHARACTER* c_address, F_LENGTH s1_length, F_LENGTH c_length); -- all Sather calls have c_length set to 1 |
Sather 1.1 provides the extra flexibility of 'out' and 'inout' argument modes for Fortran calls. The Sather compiler ensures that the semantics of 'out' and 'inout' is preserved even when calls cross the Sather language boundaries. In particular, the changes to such arguments are not observed until the call is complete - thus the interlanguage calls have the same semantics as regular Sather calls.
This additional mechanism makes the semantics of some arguments visually explicit and consequently helps catch some bugs caused by the modification of 'in' arguments (all Fortran arguments are passed by reference, and Fortran code can potentially modify all arguments without restrictions.) A special compiler option may enable checking the invariance of Fortran 'in' arguments[2].
[2] The ICSI Sather 1.1 compiler currently does not implement this functionality.
In the case of calling Fortran code, the Sather compiler ensures that the value/result semantics is preserved by the caller - the Sather compiler has no control over external Fortran code. This may involve copying 'inout' arguments to temporaries and passing references to these temporaries to Fortran. In the case of Sather routines that are called from Fortran, the Sather compiler emits a special prologue for such routines to ensure the value/result semantics for the Fortran caller. In summary, the value/result semantics for external calls to Fortran is ensured by the caller, and for Sather routines that are meant to be called by Fortran it is implemented by the callee.
This example suggests how a signature for a routine that swaps two integers:
SUBROUTINE SWAP(A,B) INTEGER A,B -- a Sather signature may look like swap(inout a:F_INTEGER, inout b:F_INTEGER); |
Note that using argument modes in this example makes the semantics of the routine more obvious.
In the following example, compiling the program with all checks on may reveal a bug due to the incorrect modification of the vector sizes:
SUBROUTINE ADD_VECTORS(A,B,RES,size) REAL A(*),B(*),RES(*) INTEGER SIZE -- Sather signature add_vectors(a,b,res:F_ARRAY{F_REAL}, size:F_INTEGER) -- size is an 'in' parameter and cannot be modified by Fortran code |
In addition to extra debugging capabilities, 'in' arguments are passed slightly more efficiently than 'out' and 'inout' arguments.
F_ROUT and F_HANDLER types cannot be "out" or "inout" arguments.