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