J3/05-281r1 Date: November 11, 2005 To: J3 From: Aleksandar Donev Subject: Specification, syntax, and edits for interoperability of optional, assumed-shape, allocatable, and pointer dummy arguments References: WG5 worklist item j3-041 (J3/05-271, J3/05-277) ----------------------------------------------------------------------- Summary: -------- Provide extensions to C Interop that allow for interoperable Fortran procedures that have data pointer, allocatable, assumed-shape array, or optional dummy arguments. Specification and Syntax: ------------------------- A Fortran procedure interface which has assumed-shape, allocatable, or data pointer dummy arguments, is interoperable with a C function prototype where the corresponding formal parameter has type FDesc_Assumed_t, FDesc_Alloc_t or FDesc_Pointer_t, respectively. That is to say, a C function calling a Fortran procedure with the BIND(C) attribute will pass a descriptor handle as the actual argument corresponding to an assumed-shape, allocatable, or data pointer dummy argument. Such an argument must have interoperable type and type parameters. The value FDESC_NULL is provided to represent (uninitialized) null descriptor handles. Depending on the details of the processor's Fortran descriptors, the procedure may be required to merge additional information into the descriptor based on the declaration of the dummy argument, or to create a local representation based on the information in the descriptor. If the dummy argument is deallocated, allocated, or has its pointer association status changed in the procedure, the descriptor shall be modified to reflect the new state of the argument on return from the Fortran procedure. Note to implementors. It is expected that a processor implementation will typedef a descriptor handle as a pointer to a descriptor. A procedure interface which has OPTIONAL dummy arguments can have the BIND(C) attribute and be interoperable. The VALUE attribute is not allowed for optional dummy arguments in a BIND(C) interface. The interoperable C prototype is the same as if the OPTIONAL attribute were not present, the only difference is the function reference on the C side. Namely, a C caller specifies a missing actual argument in a function reference by passing a NULL data pointer as the argument value if the corresponding dummy argument is a data object, or a NULL procedure pointer as the argument value if the corresponding dummy argument is a procedure. If the dummy is an optional assumed-shape, allocatable, or pointer dummy argument, the C caller can use FDESC_NULL as an actual argument. A Fortran procedure, as usual, omits the actual argument in the procedure reference. Edits: ------ Note: < and > are used to delimit italic font. << and >> are used to delimit bold font. {and} are used to delimit C code font (Courier). All page and line numbers refer to j3/04-007. ______________ [xiii] Introduction, the list of new Fortran 2008 features should include Interoperability enhancements: Interoperability of optional, assumed-shape, allocatable, and pointer dummy arguments. ______________ [73:25] In C530, replace "The ALLOCATABLE, POINTER, or OPTIONAL attribute shall not be specified" with "The VALUE and OPTIONAL attributes shall not both be specified" ______________ [400:14] Replace "any dummy argument without the VALUE attribute" with "any dummy argument that is not pointer, allocatable, or assumed-shape, and does not have the VALUE attribute" [400:17] Delete the trailing "and" [400:17+] Add additional items (5+1) any assumed-shape dummy argument is of interoperable type and corresponds to a formal parameter of the prototype that is an assumed-shape descriptor handle (15.5.1.1); (5+2) any pointer dummy argument is of interoperable type and corresponds to a formal parameter of the prototype that is a pointer descriptor handle (15.5.1.1); (5+3) any allocatable dummy argument is of interoperable type and corresponds to a formal parameter of the prototype that is an allocatable descriptor handle (15.5.1.1); [400:20+] Add sentence "Interoperability of procedures and procedure interfaces that have assumed-shape, allocatable, or pointer dummy arguments, is described in Section 15.5, and optional dummy arguments are discussed in Section 15.6." ______________ Add section "15.5 Interoperability of Assumed-Shape, Pointer and Allocatable Dummy Arguments" Fortran assumed-shape dummy arrays, array pointers, and allocatable arrays, are not interoperable with C arrays. This standard provides means for companion processors to directly reference Fortran procedures that have assumed-shape, data pointer, or allocatable dummy arguments, by using opaque descriptor handles (Section 15.7). For regularity, scalar data pointer and allocatable dummy arguments are included and treated as arrays of rank zero. Section 15.7 defines a header file with types, constants, and function prototypes, used to manipulate descriptor handles. In a procedure reference in C, the actual argument corresponding to an assumed-shape, pointer, or allocatable dummy argument shall be a descriptor handle describing an array of the appropriate rank and type. The descriptor handle shall not be null unless the dummy argument is OPTIONAL (section 15.6). For allocatable or pointer dummy arguments, the descriptor handle reflects changes in the allocation or pointer association status upon return from the procedure. If a Fortran procedure reference causes a procedure defined by means other than Fortran to be called, the Fortran processor supplies an appropriate descriptor handle as the actual argument corresponding to an assumed-shape, allocatable, or data pointer dummy argument. That procedure shall not modify an assumed-shape descriptor, and shall modify a pointer or allocatable descriptor only by using the functions described in sections 15.5.2.3, 15.5.2.4 and 15.5.2.5. ______________ Note 1. Procedures with an interface that has an assumed-shape, pointer, or allocatable dummy argument can be defined by means other than Fortran, and referenced from Fortran programs. The processor constructs the appropriate descriptor handles for the actual arguments. However, such procedures must obey the semantics of Fortran programs, for example, assumed-shape array descriptors must not be modified, Fortran anti-aliasing rules must be satisfied, etc. ______________ Note 2. For example, the Fortran procedure with the interface SUBROUTINE MY_MATMUL(A,B,C) BIND(C,NAME="MatMul") ! Perform the matrix multiplication C=A*B USE, INTRINSIC :: ISO_C_BINDING REAL(C_DOUBLE), DIMENSION(:,:), INTENT(IN) :: A, B REAL(C_DOUBLE), DIMENSION(:,:), INTENT(OUT) :: C C=MATMUL(A,B) END SUBROUTINE can be called from a C program as follows (without careful error checking): include "fdesc.h" void MatMul(FDesc_Assumed_t, FDesc_Assumed_t, FDesc_Assumed_t); /* The interoperable prototype */ FDesc_Assumed_t A_desc, B_desc, C_desc; /* The opaque descriptor handles */ double AB[100][100][2]; /* A and B are interweaved parts of a rank-3 array */ double *C; /* The result will be dynamically allocated */ F_extent_t shape[2] = {100,100}; F_stride_t stride[2] = {2*sizeof(double),2*sizeof(double)}; FDesc_Assumed_Create(&A_desc,&AB[0,0,0],sizeof(double),2,shape,stride); FDesc_Assumed_Create(&B_desc,&AB[0,0,1],sizeof(double),2,shape,stride); C=(void*)malloc(100*100*sizeof(double)); /* Dynamically allocate memory */ FDesc_Assumed_Create(&C_desc,(void*)C,sizeof(double),2,shape,stride); ReadValues(AB) /* Assign initial values to A, B */ MatMul(A,B,C); /* Perform C=A*B for 100x100 arrays */ ______________ 15.5.1 Opaque types and values defined in The processor shall provide a header file, , written in the C programming language. This file shall declare the C prototypes in Section 15.5.2. This file shall also define necessary C types for descriptor handles used as function parameters in the C prototypes. 15.5.1.1 Descriptor handles Data in array descriptors shall be made accessible to C via descriptor handle. A scalar C object of type FDesc_Assumed_t is an <>; other descriptor handles are FDesc_Pointer_t, a <> and FDesc_Alloc_t, an <>. Descriptor handles can be used in C programs to access or manipulate descriptors for assumed-shape array, data pointer, or allocatable dummy arguments of interoperable Fortran procedures. The header file shall also define a constant FDESC_NULL that is the value of a <>. This constant may be assigned to a descriptor handle. FDESC_NULL is the value assigned to a descriptor handle if an error occurs in a descriptor create (15.5.2.1), in a destroy function (15.5.2.2), as well as the value that can be used to signal that an actual argument is not present (15.6). 15.5.1.2 Stride and extent types The header file shall define two new integer types, F_stride_t, used for array stride information, and F_extent_t, used for array extents. 15.5.2 Function prototypes Functions described in this section can be used to manipulate descriptor handles. The functions described in 15.5.2.1 create descriptors and return a handle for the created descriptor. Once a descriptor is created the rank and type shall not be changed. The descriptor shall be destroyed using the functions in 15.5.2.2. Before using the descriptor handle in a reference to a Fortran procedure, the descriptor shall be initialized using the appropriate function in 15.5.2.3. Storage for the array can be allocated by the Fortran processor using the functions in 15.5.2.4, and deallocated using the functions in 15.5.2.5. Inquiry functions for descriptors are provided in 15.5.2.6, 15.5.2.7, 15.5.2.8 and 15.5.2.9. If the descriptor handle is used as an actual argument in a reference to an interoperable Fortran procedure, the corresponding dummy argument shall have the same type and rank as the type and rank of the object described by the descriptor. 15.5.2.1 Descriptor creation <> int FDesc_Assumed_Create ( FDesc_Assumed_t * restrict fdesc, size_t elem_size, unsigned int rank ); <> Creates an assumed-shape descriptor. The descriptor shall be destroyed by a subsequent call to FDesc_Assumed_Destroy. int FDesc_Pointer_Create ( FDesc_Pointer_t * restrict fdesc, size_t elem_size, unsigned int rank, ); <> Creates a pointer descriptor and sets the initial pointer association status to disassociated. The descriptor shall be destroyed by a subsequent call to FDesc_Pointer_Destroy. int FDesc_Alloc_Create ( FDesc_Alloc_t * restrict fdesc, size_t elem_size, unsigned int rank, ); <> Creates an allocatable descriptor and sets the initial allocation status to not allocated. The descriptor shall be destroyed by a subsequent call to FDesc_Alloc_Destroy. <> fdesc shall be the pointer to a descriptor handle of the specified type. Upon return its value is the address of the created handle or FDESC_NULL if an error occurs. elem_size shall be the size of an array element in bytes. rank shall be the rank of the object. <> The result value is 0 if successful or nonzero if an error occurs. [Add Note] The C type must be interoperable. The C sizeof operator (6.5.3.4) can be used to obtain the appropriate value of {elem_size}. [End Note] 15.5.2.2 Descriptor deallocation int FDesc_Assumed_Destroy ( FDesc_Assumed_t * restrict fdesc ); <> Destroys an assumed-shape descriptor previously created with a call to FDesc_Assumed_Create. int FDesc_Pointer_Destroy ( FDesc_Pointer_t * restrict fdesc ); <> Destroys a pointer descriptor previously created with a call to FDesc_Pointer_Create. int FDesc_Alloc_Destroy ( FDesc_Alloc_t * restrict fdesc ); <> Destroys an allocatable descriptor previously created with a call to FDesc_Alloc_Create. <> fdesc shall be the address of a non-null descriptor handle of the specified type. Its value is FDESC_NULL on return. <> The result value is 0 if successful or nonzero if an error occurs. _______________________________________________________________________ 15.5.2.3 Descriptor Modification <> int FDesc_Assumed_Set ( FDesc_Assumed_t fdesc, void * restrict base_addr, const F_extent_t shape[restrict], const F_stride_t stride[restrict] ); <> Sets the elements of an assumed-shape descriptor. The value of {base_addr} shall not be NULL. int FDesc_Pointer_Set ( FDesc_Pointer_t fdesc, void * base_addr, const F_extent_t shape[restrict], const F_extent_t lbound[restrict], const F_stride_t stride[restrict] ); <> Sets the elements of a pointer descriptor. If base_addr is NULL, the pointer association status becomes not associated and {shape}, {lbound} and {stride} are ignored. <> fdesc shall be a descriptor handle of the specified type. base_addr shall be a pointer to an object. shape shall be an array containing the shape of the object. The shape array shall contain at least {rank} elements, unless {base_addr} is NULL. The th element corresponds to the extent of the th dimension of the corresponding Fortran object. lbound shall be an array containing the lower bounds of the object in elements. It shall contain at least {rank} elements unless {base_addr} is NULL. stride shall be an array containing the distance in bytes between successive elements for each dimension. The stride array shall contain at least {rank} number of elements, unless {base_addr} is NULL. <> The result value shall be 0 if successful or nonzero if an error occurs. [Add Note] Note that the ordering of corresponding indices is reversed between Fortran and C arrays (15.2.5). The argument is in Fortran order. For example, if one wanted to create a descriptor for the C array declared as double array[10][5]; the appropriate {shape} would be {5,10}. [End Note] 15.5.2.4 Memory allocation Functions described below allocate objects as with the ALLOCATE statement. Such an object shall be deallocated in a subsequent call to the corresponding function in 15.5.2.5 or in a DEALLOCATE statement. <> int FDesc_Assumed_Allocate ( FDesc_Assumed_t fdesc, const F_extent_t shape[restrict] ); <> Sets the elements of an assumed-shape descriptor and allocates the object. The object shall be deallocated in a subsequent call to FDesc_Assumed_Deallocate. int FDesc_Pointer_Allocate ( FDesc_Pointer_t fdesc, const F_extent_t shape[restrict], const F_extent_t lbound[restrict] ); <> Sets the elements of a pointer descriptor and allocates the object. The object shall be deallocated in a subsequent call to FDesc_Pointer_Deallocate or in a DEALLOCATE statement. int FDesc_Alloc_Allocate ( FDesc_Alloc_t fdesc, const F_extent_t shape[restrict], const F_extent_t lbound[restrict] ); <> Sets the elements of an allocatable descriptor and allocates memory for the array. The object shall be deallocated in a subsequent call to FDesc_Alloc_Deallocate or in a DEALLOCATE statement. <> fdesc shall be a descriptor handle of the specified type. shape shall be an array containing the shape of the array object in elements. The shape array shall contain at least {rank} elements. The th element corresponds to the extent of the th dimension of the corresponding Fortran array. lbound shall be an array containing the lower bounds of the array object in elements. The {lbound} array shall contain at least least {rank} elements. stride shall be an array containing the distance in bytes between successive array elements for each dimension. The {stride} array shall contain at least {rank} number of elements. <> The result value is 0 if successful or nonzero if an error occurs. 15.5.2.5 Memory deallocation Functions described below deallocate objects as with the DEALLOCATE statement. Such an object shall have been allocated in a previous call to the corresponding function in 15.5.2.4 or in an ALLOCATE statement. <> int FDesc_Assumed_Deallocate ( FDesc_Assumed_t fdesc ); <> Deallocates memory previously allocated with FDesc_Assumed_Allocate. int FDesc_Pointer_Deallocate ( FDesc_Pointer_t fdesc ); <> Deallocates memory previously allocated with FDesc_Pointer_Allocate or in an ALLOCATE statement. int FDesc_Alloc_Deallocate ( FDesc_Alloc_t fdesc ); <> Deallocates memory previously allocated with FDesc_Alloc_Allocate or in an ALLOCATE statement. <> fdesc shall be a descriptor handle of the specified type. <> The result value is 0 if successful or nonzero if an error occurs. 15.5.2.6 Pointer association status <> _Bool FDesc_Associated ( FDesc_Pointer_t fdesc ); <> Returns the association status of a pointer. <> fdesc shall be a descriptor handle of the specified type. <> The result value is {true} if the pointer is associated or {false} otherwise. 15.5.2.7 Array allocation status <> _Bool FDesc_Allocated ( FDesc_Alloc_t fdesc ); <> Returns the allocation status of an allocatable object. <> fdesc shall be a descriptor handle of the specified type. <> The result value is {true} if the array is allocated or {false} otherwise. 15.5.2.8 Array rank <> int FDesc_Assumed_Rank ( FDesc_Assumed_t fdesc ); <> Returns the rank of an assumed-shape array. int FDesc_Pointer_Rank ( FDesc_Pointer_t fdesc ); <> Returns the rank of a pointer. int FDesc_Alloc_Rank ( FDesc_Alloc_t fdesc ); <> Returns the rank of an allocatable object. <> fdesc shall be a descriptor handle of the specified type. <> The result value is the rank of the array or pointer object described by {fdesc}. 15.5.2.9 Descriptor access functions <> int FDesc_Assumed_Get ( Desc_Assumed_t fdesc, void ** base_addr, F_extent_t shape[restrict], F_extent_t lbound[restrict], F_stride_t stride[restrict] ); <> Returns address, shape, lower bounds, and stride information for the assumed-shape array described by {fdesc}. int FDesc_Pointer_Get ( FDesc_Pointer_t fdesc, void ** base_addr, F_extent_t shape[restrict], F_extent_t lbound[restrict], F_stride_t stride[restrict] ); <> Returns address, shape, lower bounds, and stride information for the pointer described by {fdesc}. int FDesc_Alloc_Get ( FDesc_Alloc_t fdesc, void ** restrict base_addr, F_extent_t shape[restrict], F_extent_t lbound[restrict], ); <> Returns address, shape, and lower bounds information for the allocatable object described by {fdesc}. <> fdesc shall be a descriptor handle of the specified type. base_addr shall be a pointer containing the address of the object described by {fdesc} on return. shape shall be an array containing the shape of the object on return. It shall contain at least {rank} elements. lbound shall be an array containing the lower bounds of object on return. It shall contain at least {rank} elements. stride shall be an array containing the distance in bytes between successive elements for each dimension on return. It shall contain at least {rank} elements. <> The result value is 0 if successful or nonzero if an error occurs. ______________ Add section "15.6 Interoperability of Optional Dummy Arguments" An interoperable Fortran procedure can have OPTIONAL dummy arguments. The VALUE attribute cannot be combined with the OPTIONAL attribute. If such a procedure is referenced in C and the actual argument corresponding to that dummy argument is a) a null pointer, and the dummy argument is interoperable; or b) a null descriptor handle, and the dummy argument is an assumed-shape array, allocatable variable, or data pointer; then the dummy argument is not present (12.4.1.6), otherwise, it is present. If a Fortran procedure reference causes a procedure defined by means other than Fortran to be called, the Fortran processor shall supply NULL for a nonpresent actual argument corresponding to an interoperable dummy argument, or FDESC_NULL for a nonpresent actual argument corresponding to an assumed-shape, allocatable, or data pointer dummy argument. ______________ History: ------------------------------------------------------------------ Optional: Paper 04-373 meeting 169 Submitted 171 Accepted as complete ------------------------------------------------------------------ Pointers, allocatables, and assumed-shape arrays: Paper 04-371r2 meeting 169 Submitted 05-159 171 Accepted as complete ------------------------------------------------------------------ 174 Merged two papers and edits added