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