1<!--===- docs/RuntimeDescriptor.md 2 3 Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 See https://llvm.org/LICENSE.txt for license information. 5 SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 7--> 8 9## Concept 10The properties that characterize data values and objects in Fortran 11programs must sometimes be materialized when the program runs. 12 13Some properties are known during compilation and constant during 14execution, yet must be reified anyway for execution in order to 15drive the interfaces of a language support library or the mandated 16interfaces of interoperable (i.e., C) procedure calls. 17 18Note that many Fortran intrinsic subprograms have interfaces 19that are more flexible and generic than actual Fortran subprograms 20can be, so properties that must be known during compilation and 21are constant during execution may still need to be materialized 22for calls to the library, even if only by modifying names to 23distinguish types or their kind specializations. 24 25Other properties are deferred to execution, and need to be represented 26to serve the needs of compiled code and the run time support library. 27 28Previous implementations of Fortran have typically defined a small 29sheaf of _descriptor_ data structures for this purpose, and attached 30these descriptors as additional hidden arguments, type components, 31and local variables so as to convey dynamic characteristics between 32subprograms and between user code and the run-time support library. 33 34### References 35References are to the 12-2017 draft of the Fortran 2018 standard 36(N2146). 37 38Section 15.4.2.2 can be interpreted as a decent list of things that 39might need descriptors or other hidden state passed across a 40subprogram call, since such features (apart from assumed-length 41`CHARACTER` function results) trigger a requirement for the 42subprogram to have an explicit interface visible to their callers. 43 44Section 15.5.2 has good laundry lists of situations that can arise 45across subprogram call boundaries. 46 47## A survey of dynamic characteristics 48 49### Length of assumed-length `CHARACTER` function results (B.3.6) 50``` 51CHARACTER*8 :: FOO 52PRINT *, FOO('abcdefghijklmnopqrstuvwxyz') 53... 54CHARACTER*(*) FUNCTION FOO(STR) 55 CHARACTER*26 STR 56 FOO=STR 57END 58``` 59 60prints `abcdefgh` because the length parameter of the character type 61of the result of `FOO` is passed across the call -- even in the absence 62of an explicit interface! 63 64### Assumed length type parameters (7.2) 65Dummy arguments and associate names for `SELECT TYPE` can have assumed length 66type parameters, which are denoted by asterisks (not colons). 67Their values come from actual arguments or the associated expression (resp.). 68 69### Explicit-shape arrays (8.5.8.2) 70The expressions used for lower and upper bounds must be captured and remain 71invariant over the scope of an array, even if they contain references to 72variables that are later modified. 73 74Explicit-shape arrays can be dummy arguments, "adjustable" local variables, 75and components of derived type (using specification expressions in terms 76of constants and KIND type parameters). 77 78### Leading dimensions of assumed-size arrays (8.5.8.5) 79``` 80SUBROUTINE BAR(A) 81 REAL A(2,3,*) 82END 83``` 84The total size and final dimension's extent do not constitute dynamic 85properties. 86The called subprogram has no means to extract the extent of the 87last (major) dimension, and may not depend upon it implicitly by using 88the array in any context that demands a known shape. 89 90The values of the expressions used as the bounds of the dimensions 91that appear prior to 92the last dimension are, however, effectively captured on entry to the 93subprogram, and remain invariant even if the variables that appear in 94those expressions have their values modified later. 95This is similar to the requirements for an explicit-shape array. 96 97### Some function results 981. Deferred-shape 992. Deferred length type parameter values 1003. Stride information for `POINTER` results 101 102Note that while function result variables can have the `ALLOCATABLE` 103attribute, the function itself and the value returned to the caller 104do not possess the attribute. 105 106### Assumed-shape arrays 107The extents of the dimensions of assumed-shape dummy argument arrays 108are conveyed from those of the actual effective arguments. 109The bounds, however, are not. The called subprogram can define the 110lower bound to be a value other than 1, but that is a local effect 111only. 112 113### Deferred-shape arrays 114The extents and bounds of `POINTER` and `ALLOCATABLE` arrays are 115established by pointer assignments and `ALLOCATE` statements. 116Note that dummy arguments and function results that are `POINTER` 117or `ALLOCATABLE` can be deferred-shape, not assumed-shape -- one cannot 118supply a lower bound expression as a local effect. 119 120### Strides 121Some arrays can have discontiguous (or negative) strides. 122These include assumed-shape dummy arguments and deferred-shape 123`POINTER` variables, components, and function results. 124 125Fortran disallows some conceivable cases that might otherwise 126require implied strides, such as passing an array of an extended 127derived type as an actual argument that corresponds to a 128nonpolymorphic dummy array of a base type, or the similar 129case of pointer assignment to a base of an extended derived type. 130 131Other arrays, including `ALLOCATABLE`, can be assured to 132be contiguous, and do not necessarily need to manage or 133convey dynamic stride information. 134`CONTIGUOUS` dummy arguments and `POINTER` arrays need not 135record stride information either. 136(The standard notes that a `CONTIGUOUS POINTER` occupies a 137number of storage units that is distinct from that required 138to hold a non-`CONTIGUOUS` pointer.) 139 140Note that Fortran distinguishes the `CONTIGUOUS` attribute from 141the concept of being known or required to be _simply contiguous_ (9.5.4), 142which includes `CONTIGUOUS` entities as well as many others, and 143the concept of actually _being_ contiguous (8.5.7) during execution. 144I believe that the property of being simply contiguous implies 145that an entity is known at compilation time to not require the 146use or maintenance of hidden stride values. 147 148### Derived type component initializers 149Fortran allows components of derived types to be declared with 150initial values that are to be assigned to the components when an 151instance of the derived type is created. 152These include `ALLOCATABLE` components, which are always initialized 153to a deallocated state. 154 155These can be implemented with constructor subroutines, inline 156stores or block copies from static initializer blocks, or a sequence 157of sparse offset/size/value component initializers to be emplaced 158by the run-time library. 159 160N.B. Fortran allows kind type parameters to appear in component 161initialization constant expressions, but not length type parameters, 162so the initialization values are constants. 163 164N.B. Initialization is not assignment, and cannot be implemented 165with assignments to uninitialized derived type instances from 166static constant initializers. 167 168### Polymorphic `CLASS()`, `CLASS(*)`, and `TYPE(*)` 169Type identification for `SELECT TYPE`. 170Default initializers (see above). 171Offset locations of `ALLOCATABLE` and polymorphic components. 172Presence of `FINAL` procedures. 173Mappings to overridable type-bound specific procedures. 174 175### Deferred length type parameters 176Derived types with length type parameters, and `CHARACTER`, may be used 177with the values of those parameters deferred to execution. 178Their actual values must be maintained as characteristics of the dynamic 179type that is associated with a value or object 180. 181A single copy of the deferred length type parameters suffices for 182all of the elements of an array of that parameterized derived type. 183 184### Components whose types and/or shape depends on length type parameters 185Non-pointer, non-allocatable components whose types or shapes are expressed 186in terms of length type parameters will probably have to be implemented as 187if they had deferred type and/or shape and were `ALLOCATABLE`. 188The derived type instance constructor must allocate them and possibly 189initialize them; the instance destructor must deallocate them. 190 191### Assumed rank arrays 192Rank is almost always known at compilation time and would be redundant 193in most circumstances if also managed dynamically. 194`DIMENSION(..)` dummy arguments (8.5.8.7), however, are a recent feature 195with which the rank of a whole array is dynamic outside the cases of 196a `SELECT RANK` construct. 197 198The lower bounds of the dimensions of assumed rank arrays 199are always 1. 200 201### Cached invariant subexpressions for addressing 202Implementations of Fortran have often maintained precalculated integer 203values to accelerate subscript computations. 204For example, given `REAL*8 :: A(2:4,3:5)`, the data reference `A(I,J)` 205resolves to something like `&A + 8*((I-2)+3*(J-3))`, and this can be 206effectively reassociated to `&A - 88 + 8*I + 24*J` 207or `&A - 88 + 8*(I + 3*J)`. 208When the offset term and coefficients are not compile-time constants, 209they are at least invariant and can be precomputed. 210 211In the cases of dummy argument arrays, `POINTER`, and `ALLOCATABLE`, 212these addressing invariants could be managed alongside other dynamic 213information like deferred extents and lower bounds to avoid their 214recalculation. 215It's not clear that it's worth the trouble to do so, since the 216expressions are invariant and cheap. 217 218### Coarray state (8.5.6) 219A _coarray_ is an `ALLOCATABLE` variable or component, or statically 220allocated variable (`SAVE` attribute explicit or implied), or dummy 221argument whose ultimate effective argument is one of such things. 222 223Each image in a team maintains its portion of each coarray and can 224access those portions of the coarray that are maintained by other images 225in the team. 226Allocations and deallocations are synchronization events at which 227the several images can exchange whatever information is needed by 228the underlying intercommunication interface to access the data 229of their peers. 230(Strictly speaking, an implementation could synchronize 231images at allocations and deallocations with simple barriers, and defer 232the communication of remote access information until it is needed for a 233given coarray on a given image, so long as it could be acquired in a 234"one-sided" fashion.) 235 236### Presence of `OPTIONAL` dummy arguments 237Typically indicated with null argument addresses. 238Note that `POINTER` and `ALLOCATABLE` objects can be passed to 239non-`POINTER` non-`ALLOCATABLE` dummy arguments, and their 240association or allocation status (resp.) determines the presence 241of the dummy argument. 242 243### Stronger contiguity enforcement or indication 244Some implementations of Fortran guarantee that dummy argument arrays 245are, or have been made to be, contiguous on one or more dimensions 246when the language does not require them to be so (8.5.7 p2). 247Others pass a flag to identify contiguous arrays (or could pass the 248number of contiguous leading dimensions, although I know of no such 249implementation) so that optimizing transformations that depend on 250contiguity can be made conditional with multiple-version code generation 251and selected during execution. 252 253In the absence of a contiguity guarantee or flag, the called side 254would have to determine contiguity dynamically, if it cares, 255by calculating addresses of elements in the array whose subscripts 256differ by exactly 1 on exactly 1 dimension of interest, and checking 257whether that difference exactly matches the byte size of the type times 258the product of the extents of any prior dimensions. 259 260### Host instances for dummy procedures and procedure pointers 261A static link or other means of accessing the imported state of the 262host procedure must be available when an internal procedure is 263used as an actual argument or as a pointer assignment target. 264 265### Alternate returns 266Subroutines (only) with alternate return arguments need a 267means, such as the otherwise unused function return value, by which 268to distinguish and identify the use of an alternate `RETURN` statement. 269The protocol can be a simple nonzero integer that drives a switch 270in the caller, or the caller can pass multiple return addresses as 271arguments for the callee to substitute on the stack for the original 272return address in the event of an alternate `RETURN`. 273 274## Implementation options 275 276### A note on array descriptions 277Some arrays require dynamic management of distinct combinations of 278values per dimension. 279 280One can extract the extent on a dimension from its bounds, or extract 281the upper bound from the extent and the lower bound. Having distinct 282extent and upper bound would be redundant. 283 284Contiguous arrays can assume a stride of 1 on each dimension. 285 286Assumed-shape and assumed-size dummy argument arrays need not convey 287lower bounds. 288 289So there are examples of dimensions with 290 * extent only (== upper bound): `CONTIGUOUS` assumed-shape, explict shape and multidimensional assumed-size with constant lower bound 291 * lower bound and either extent or upper bound: `ALLOCATABLE`, `CONTIGUOUS` `POINTER`, general explicit-shape and multidimensional assumed-size 292 * extent (== upper bound) and stride: general (non-`CONTIGUOUS`) assumed-shape 293 * lower bound, stride, and either extent or upper bound: general (non-`CONTIGUOUS`) `POINTER`, assumed-rank 294 295and these cases could be accompanied by precomputed invariant 296addressing subexpressions to accelerate indexing calculations. 297 298### Interoperability requirements 299 300Fortran 2018 requires that a Fortran implementation supply a header file 301`ISO_Fortran_binding.h` for use in C and C++ programs that defines and 302implements an interface to Fortran objects from the _interoperable_ 303subset of Fortran objects and their types suitable for use when those 304objects are passed to C functions. 305This interface mandates a fat descriptor that is passed by address, 306containing (at least) 307 * a data base address 308 * explicit rank and type 309 * flags to distinguish `POINTER` and `ALLOCATABLE` 310 * elemental byte size, and 311 * (per-dimension) lower bound, extent, and byte stride 312 313The requirements on the interoperability API do not mandate any 314support for features like derived type component initialization, 315automatic deallocation of `ALLOCATABLE` components, finalization, 316derived type parameters, data contiguity flags, &c. 317But neither does the Standard preclude inclusion of additional 318interfaces to describe and support such things. 319 320Given a desire to fully support the Fortran 2018 language, we need 321to either support the interoperability requirements as a distinct 322specialization of the procedure call protocol, or use the 323`ISO_Fortran_binding.h` header file requirements as a subset basis for a 324complete implementation that adds representations for all the 325missing capabilities, which would be isolated and named so as 326to prevent user C code from relying upon them. 327 328### Design space 329There is a range of possible options for representing the 330properties of values and objects during the execution of Fortran 331programs. 332 333At one extreme, the amount of dynamic information is minimized, 334and is packaged in custom data structures or additional arguments 335for each situation to convey only the values that are unknown at 336compilation time and actually needed at execution time. 337 338At the other extreme, data values and objects are described completely, 339including even the values of properties are known at compilation time. 340This is not as silly as it sounds -- e.g., Fortran array descriptors 341have historically materialized the number of dimensions they cover, even 342though rank will be (nearly) always be a known constant during compilation. 343 344When data are packaged, their containers can be self-describing to 345some degree. 346Description records can have tag values or strings. 347Their fields can have presence flags or identifying tags, and fields 348need not have fixed offsets or ordering. 349This flexibility can increase binary compatibility across revisions 350of the run-time support library, and is convenient for debugging 351that library. 352However, it is not free. 353 354Further, the requirements of the representation of dynamic 355properties of values and objects depend on the execution model: 356specifically, are the complicated semantics of intrinsic assignment, 357deallocation, and finalization of allocatables implemented entirely 358in the support library, in generated code for non-recursive cases, 359or by means of a combination of the two approaches? 360 361Consider how to implement the following: 362``` 363TYPE :: LIST 364 REAL :: HEAD 365 TYPE(LIST), ALLOCATABLE :: REST 366END TYPE LIST 367TYPE(LIST), ALLOCATABLE :: A, B 368... 369A = B 370``` 371 372Fortran requires that `A`'s arbitrary-length linked list be deleted and 373replaced with a "deep copy" of `B`'s. 374So either a complicated pair of loops must be generated by the compiler, 375or a sophisticated run time support library needs to be driven with 376an expressive representation of type information. 377 378## Proposal 379We need to write `ISO_Fortran_binding.h` in any event. 380It is a header that is published for use in user C code for interoperation 381with compiled Fortran and the Fortran run time support library. 382 383There is a sole descriptor structure defined in `ISO_Fortran_binding.h`. 384It is suitable for characterizing scalars and array sections of intrinsic 385types. 386It is essentially a "fat" data pointer that encapsulates a raw data pointer, 387a type code, rank, elemental byte size, and per-dimension bounds and stride. 388 389Please note that the mandated interoperable descriptor includes the data 390pointer. 391This design in the Standard precludes the use of static descriptors that 392could be associated with dynamic base addresses. 393 394The F18 runtime cannot use just the mandated interoperable 395`struct CFI_cdesc_t` argument descriptor structure as its 396all-purpose data descriptor. 397It has no information about derived type components, overridable 398type-bound procedure bindings, type parameters, &c. 399 400However, we could extend the standard interoperable argument descriptor. 401The `struct CFI_cdesc_t` structure is not of fixed size, but we 402can efficiently locate the first address after an instance of the 403standard descriptor and attach our own data record there to 404hold what we need. 405There's at least one unused padding byte in the standard argument 406descriptor that can be used to hold a flag indicating the presence 407of the addenda. 408 409The definitions of our additional run time data structures must 410appear in a header file that is distinct from `ISO_Fortran_binding.h`, 411and they should never be used by user applications. 412 413This expanded descriptor structure can serve, at least initially for 414simplicity, as the sole representation of `POINTER` variables and 415components, `ALLOCATABLE` variables and components, and derived type 416instances, including length parameter values. 417 418An immediate concern with this concept is the amount of space and 419initialization time that would be wasted when derived type components 420needing a descriptor would have to be accompanied by an instance 421of the general descriptor. 422(In the linked list example close above, what could be done with a 423single pointer for the `REST` component would become at least 424a four-word dynamic structure.) 425This concern is amplified when derived type instances 426are allocated as arrays, since the overhead is per-element. 427 428We can reduce this wastage in two ways. 429First, when the content of the component's descriptor is constant 430at compilation apart from its base address, a static descriptor 431can be placed in read-only storage and attached to the description 432of the derived type's components. 433Second, we could eventually optimize the storage requirements by 434omitting all static fields from the dynamic descriptor, and 435expand the compressed dynamic descriptor during execution when 436needed. 437