J3/05-271 Date: 21 October 2005 TO: J3 From: Craig Rasmussen Subject: Interoperability of pointers, allocatables and assumed-shape arrays Number: Title: Interoperability of pointers, allocatables, and assumed-shape arrays Submitted By: Craig Rasmussen Status: For consideration Reference: 05-159 Basic Functionality: Extensions to C Interop that allow arguments that are pointers, allocatables, and assumed-shape arrays to be interoperable. Rationale: C interoperability provides a mechanism to share array data between Fortran and C. However, even with C interop, it is still necessary for users to implement a translation layer between C and Fortran assumed-shape array data structures. Under some circumstances, it may even be necessary to make temporary copies of array data in this translation layer. In the translation layer, for each array-valued parameter in a BIND(C) procedure, a user needs to pass the address of the array as well as each value of the array shape as integer procedure parameters. For BIND(C) procedures taking many array arguments, the resulting argument list can be exceptionally long. In addition, data marshaling in the translation layer can be a performance hit. Estimated Impact: Small impact for the standard and probably small to moderate impact for the processors. Detailed Specification: The processor will be required to supply, for each companion C processor, a C header file and C functions (or macros) implementing the C prototypes shown below. In C, descriptors for assumed-shape, allocatable, and Fortran pointer objects are represented by opaque types. The C functions specified by these prototypes allow C programmers to create and destroy memory for descriptors, functions to get and set parameters in a descriptor, and functions to allocate and deallocate the memory described by the descriptors. Memory for allocatable arrays may be allocated using the provided memory allocation functions. Memory for assumed-shape array actual arguments and pointer objects may also be allocated in C using other techniques such as malloc(). Memory allocated by means other than Fortran shall not be deallocated in a Fortran procedure. Separate opaque types are defined for the assumed-shape, allocatable, and pointer cases. Type and function names containing _ASSUMED_ are used with assumed-shape arguments, names containing _ALLOC_ are used with allocatable arguments, and names containing _POINTER_ are used with pointer arguments. The rank may be specified as 0 for allocatable and pointer descriptors, in which case the corresponding Fortran object shall be a scalar. If the rank is 0, the pointers to the shape and stride arrays in the same reference are not used and may have any value. If the base_addr parameter in the FDesc_Alloc_Create or FDesc_Alloc_Reset functions is NULL, the resulting descriptor represents an unallocated object. If the base_addr parameter in the FDesc_Pointer_Create or FDesc_Pointer_Reset is NULL, the resulting descriptor represents an unassociated pointer. A Fortran procedure interface which has assumed-shape, allocatable, or 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 an array descriptor handle as the actual argument corresponding to an assumed-shape, allocatable, or pointer dummy argument. 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. Such an argument must have interoperable type and type parameters. Note to implementors. A C function that is called from a Fortran procedure will be passed a descriptor handle of the type appropriate for the corresponding dummy argument in the interface for the called function. Fortran programmers will call the BIND(C) procedure in the normal fashion. Note to implementors. It is expected that a processor implementation will typedef a descriptor handle as a pointer to a descriptor. /** * FDesc.h - name of include file declaring descriptor typedefs * and prototypes */ /** * * Opaque types for stride values and the size of extents. * * F_stride_t * F_extent_t * */ /** * Opaque objects representing descriptor handles. * * FDesc_Assumed_t * FDesc_Pointer_t * FDesc_Alloc_t * */ /** * The value of a descriptor handle if an error occurs in a * descriptor Create routine and on return from a descriptor * Destroy routine. * * FDESC_NULL * */ /** * Allocation, deallocation and reset routines for descriptors */ /** * Create a descriptor and initialize its data. * * Memory for the descriptor must be freed by a subsequent call to * FDesc_Assumed_Destroy, FDesc_Pointer_Destroy, or FDesc_Alloc_Destroy. * * @param fdesc contains address of descriptor handle on return or * FDESC_NULL if an error occurs. * @param base_addr the base address of the array or scalar object. * @param elem_size the size of an array element or scalar object (in bytes). * @param rank the rank of the array; 0 if object is scalar. * @param shape array[rank] containing the array shape. * @param stride array[rank] containing the distance between successive * array elements for each dimension (in bytes). * @return 0 if successful (nonzero on error). */ int FDesc_Assumed_Create(FDesc_Assumed_t * restrict fdesc, void * restrict base_addr, size_t elem_size, unsigned int rank, const F_extent_t shape[restrict], const F_stride_t stride[restrict] ); int FDesc_Pointer_Create(FDesc_Pointer_t * restrict fdesc, void * base_addr, size_t elem_size, unsigned int rank, const F_extent_t shape[restrict], const F_stride_t stride[restrict] ); int FDesc_Alloc_Create(FDesc_Alloc_t * restrict fdesc, void * restrict base_addr, size_t elem_size, unsigned int rank; const F_extent_t shape[restrict] ); /** * Set the elements of a descriptor. These functions allow descriptor * memory to be reused. Neither the rank nor element size of an * array associated with the descriptor may change. * * @param fdesc descriptor handle. * @param base_addr the base address of the array or scalar object. * @param shape array[rank] containing the array shape (in elements). * If base_addr is NULL, the contents of shape are ignored * and the descriptor shape values are set to 0. * @param stride array[rank] containing the distance between successive * array elements for each dimension (in bytes). * If base_addr is NULL, the contents of stride are ignored * and the descriptor stride values are set to 0. * @return 0 if successful (nonzero on error). */ int FDesc_Assumed_Reset(FDesc_Assumed_t fdesc, void * restrict base_addr, const F_extent_t shape[restrict], const F_stride_t stride[restrict] ); int FDesc_Pointer_Reset(FDesc_Pointer_t fdesc, void * base_addr, const F_extent_t shape[restrict], const F_stride_t stride[restrict] ); int FDesc_Alloc_Reset(FDesc_Alloc_t fdesc, void * restrict base_addr, const F_extent_t shape[restrict] ); /** * Frees memory for a descriptor. * * @param fdesc address of a descriptor handle; set to FDESC_NULL * on return. * @return 0 if successful (nonzero on error). */ int FDesc_Assumed_Destroy(FDesc_Assumed_t * restrict fdesc); int FDesc_Pointer_Destroy(FDesc_Pointer_t * restrict fdesc); int FDesc_Alloc_Destroy(FDesc_Alloc_t * restrict fdesc); /** * Routines to allocate and deallocate array or scalar object memory */ /** * Returns a value appropriate for use as base_addr in Create and * and Reset routines. Memory allocated by these routines may be * deallocated by a Fortran procedure or by the deallocation routines * below, but deallocation shall not be done twice. * * @param size amount of memory to allocate, in bytes. * @return pointer to allocated memory, or NULL if the * memory allocation fails. */ void * FDesc_Assumed_Allocate(size_t size); void * FDesc_Pointer_Allocate(size_t size); void * FDesc_Alloc_Allocate(size_t size); /** * Frees memory previously allocated with FDesc_Alloc_Allocate, * FDesc_Pointer_Allocate, or FDesc_Assumed_Allocate. * FDesc_Alloc_Deallocate and FDesc_Pointer_Deallocate may be * used to deallocate memory previously allocated by a Fortran * procedure. * * @param fdesc descriptor handle. The base_addr in the * descriptor is set to NULL on return. * @return 0 is successful (nonzero on error). */ int FDesc_Assumed_Deallocate(FDesc_Assumed_t fdesc); int FDesc_Pointer_Deallocate(FDesc_Pointer_t fdesc); int FDesc_Alloc_Deallocate(FDesc_Alloc_t fdesc); /** * Accessors * * @param fdesc descriptor handle. */ /** Returns true if the pointer is associated (false otherwise). */ _Bool FDesc_Associated(FDesc_Pointer_t fdesc); /** Returns true if the object is allocated (false otherwise). */ _Bool FDesc_Allocated(FDesc_Alloc_t fdesc); /** Returns the rank of the array described by a descriptor */ int FDesc_Assumed_Rank(FDesc_Assumed_t fdesc); int FDesc_Pointer_Rank(FDesc_Pointer_t fdesc); int FDesc_Alloc_Rank(FDesc_Alloc_t fdesc); /** * Return the address, shape, and stride information in a descriptor. * * @param fdesc descriptor handle. * @param base_addr contains the address of the array or scalar object on return. * @param shape array[rank] containing the array shape on return * (in elements). If the rank is 0, shape is not returned. * @param stride array[rank] containing the distance between successive * array elements for each dimension (in bytes) on return. * If rank is 0, stride is not returned. * @return 0 if successful (nonzero on error). */ int FDesc_Assumed_Get(FDesc_Assumed_t fdesc, void ** base_addr, F_extent_t shape[restrict], F_stride_t stride[restrict] ); int FDesc_Pointer_Get(FDesc_Pointer_t fdesc, void ** base_addr, F_extent_t shape[restrict], F_stride_t stride[restrict] ); int FDesc_Alloc_Get(FDesc_Alloc_t fdesc, void ** restrict base_addr, F_extent_t shape[restrict], F_stride_t stride[restrict] ); /** End of FDesc.h */ History: Paper 04-371r2 meeting 169 Submitted 05-159 171 Accepted as complete