| Previous | Contents | Index |
Indirect procedure calls follow nearly the same sequence as direct calls (see Section 4.7.3.1), except that the branch target is established indirectly. This sequence is illustrated in Figure 4-4.
Figure 4-4 Indirect Procedure Calls
Parameters are passed in a combination of general registers, floating-point registers, and memory, as described below, and as illustrated in Figure 4-5.
The parameter list is formed by placing each individual parameter into fixed-size elements of the parameter list, referred to as parameter slots. Each parameter slot is 64 bits wide; parameters larger than 64 bits are placed in as many consecutive parameter slots as are needed to contain the entire parameter. The rules for allocation and alignment of parameter slots are described in Section 4.7.5.1.
The contents of the first eight parameter slots are always passed in registers, while the remaining parameters are always passed on the memory stack, beginning at the caller's stack pointer plus 16 bytes. The caller uses up to eight of the registers in the output region of its register stack for integer and VAX floating-point parameters, and up to eight floating-point registers for IEEE floating-point parameters. The maximum number of registers used is eight.
Figure 4-5 Parameter Passing in Registers and Memory
To accommodate variable argument lists in the C language, there is a fixed correspondence between parameter slots; the first parameter slot is always in either the first general output register or the first floating-point register (never both), the second parameter slot is always in the second general output register or the second floating-point register (never both), and so on. This allows a procedure to spill its register parameters easily to memory to form the argument home area before stepping through the parameter list with a pointer. The Argument Information register (AI) makes this possible, as explained in Section 4.7.5.3.
A procedure can assume that the NaT bits on its incoming general
register arguments are clear, and that the incoming floating-point
register arguments are not NaTVals. A procedure making a call must
ensure only that registers containing actual parameters are clear of
NaT bits or NaTVals; registers not used for actual parameters are
undefined.
4.7.5 Parameter Passing Mechanisms
This OpenVMS calling standard defines three classes of argument items according to the mechanism used to pass the argument:
Argument items are not self-defining; interpretation of each argument item depends on agreement between the calling and called procedures.
This standard does not dictate which passing mechanism must be used by a given language compiler. Language semantics and interoperability considerations might require different mechanisms in different situations.
An immediate value argument item contains the value of the data item. The argument item, or the value contained in it, is directly associated with the parameter.
A reference argument item contains the address of a data item such as a scalar, string, array, record, or procedure. This data item is associated with the parameter.
A descriptor argument item contains the address of a descriptor, which contains structural information about the argument's type (such as array bounds) and the address of a data item. This data item is associated with the parameter.
Requirements for using the argument passing mechanisms follow:
Note that extended floating values are not passed using the immediate value mechanism; rather, they are passed using the by reference mechanism. (However, when by value semantics is required, it may be necessary to make a copy of the actual parameter and pass a reference to that copy in order to avoid improper alias effects.)
Also note that when a record is passed by immediate value, the
component types are not material to how the argument is aligned; the
record will always be quadword aligned.
4.7.5.1 Allocation of Parameter Slots
Parameter slots are allocated for each parameter, based on the parameter passing mechanism, type, and size, treating each parameter in sequence, from left to right. The rules for allocating parameter slots and placing the contents within the slot are given in Table 4-9. The allocation column of the table indicates how parameter slots are allocated to each type of parameter.
| Type | Size (Bits) | Number of Slots |
|---|---|---|
| Integer, small set | 1-64 | 1 |
| Address/pointer (including all types passed by reference or descriptor) | 64 | 1 |
| IEEE single-precision floating-point (S_floating) | 32 | 1 |
| IEEE single-precision floating-point complex (S_floating) | 64 | 2 |
| IEEE double-precision floating-point (T_floating) | 64 | 1 |
| IEEE double-precision floating-point complex (T_floating) | 128 | 2 |
| IEEE quad-precision floating-point (X_floating) | 64 (by reference) | 1 |
| IEEE quad-precision floating-point complex (X_floating) | 64 (by reference) | 1 |
| Aggregates (noncomplex) | any | (size+63)/64 |
| VAX single-precision floating-point (F_floating) | 32 | 1 |
| VAX single-precision floating-point complex (F_floating) | 64 | 2 |
| VAX double-precision floating-point (D_ & G_floating) | 64 | 1 |
| VAX double-precision floating-point complex (D_ & G_floating) | 128 | 2 |
These rules are applied based on the type of the parameter after any type-promotion rules specified by the language have been applied. For example, a short integer passed without a function prototype in C is promoted to the int type, and is then passed according to the rules for the int type. |
OpenVMS does not support passing the Itanium double-precision extended floating-point type (__float80), although that type may be used from time to time in code generation sequences.
This placement policy does not ensure that parameters greater than 64
bits in size will fall on a natural alignment boundary if passed in
memory. Such parameters may need to be copied by the called procedure
into an aligned temporary prior to use, or accessed in a way that does
not depend on natural alignment.
4.7.5.2 Normal Register Parameters
The first eight parameter slots (64 bytes) are passed in registers, according to the rules in this section.
When IEEE floating-point parameters are passed in floating-point registers, they are passed in the register format, rounded to the appropriate precision. They are never passed in the general registers unless part of an aggregate, in which case they are passed in the aggregate memory format. When VAX floating-point parameters are passed in general registers, they are passed in memory format.
Parameters allocated beyond the eighth parameter slot are never passed in registers.
Unsigned integral (except unsigned 32-bit), set, and VAX floating-point values passed in registers are zero-filled; signed integral values as well as unsigned 32-bit integral values are sign-extended to 64 bits. For all other types passed in the general registers, unused bits are undefined.
Bit 31 is replicated in bits 32--63, even for unsigned 32-bit integers. |
The rules contained in this section are summarized in Tables 4-10 and 4-11.
| Data Type ( OpenVMS Names) | Type Designator1 | Data Size (bytes) | Register Extension Type | Memory Extension Type |
|---|---|---|---|---|
| Byte logical | DSC$K_DTYPE_BU | 1 | Zero64 | Zero64 |
| Word logical | DSC$K_DTYPE_WU | 2 | Zero64 | Zero64 |
| Longword logical | DSC$K_DTYPE_LU | 4 | Sign64 | Sign64 |
| Quadword logical | DSC$K_DTYPE_QU | 8 | Data64 | Data64 |
| Byte integer | DSC$K_DTYPE_B | 1 | Sign64 | Sign64 |
| Word integer | DSC$K_DTYPE_W | 2 | Sign64 | Sign64 |
| Longword integer | DSC$K_DTYPE_L | 4 | Sign64 | Sign64 |
| Quadword integer | DSC$K_DTYPE_Q | 8 | Data64 | Data64 |
| F_floating | DSC$K_DTYPE_F | 4 | VAXF64 | Data32 |
| D_floating | DSC$K_DTYPE_D | 8 | VAXDG64 | Data64 |
| G_floating | DSC$K_DTYPE_G | 8 | VAXDG64 | Data64 |
| F_floating complex | DSC$K_DTYPE_FC | 2 * 4 | 2*VAXF64 | 2 * Data32 |
| D_floating complex | DSC$K_DTYPE_DC | 2 * 8 | 2*VAXDG64 | 2 * Data64 |
| G_floating complex | DSC$K_DTYPE_GC | 2 * 8 | 2*VAXDG64 | 2 * Data64 |
| S_floating | DSC$K_DTYPE_FS | 4 | Hard | Data32 |
| T_floating | DSC$K_DTYPE_FT | 8 | Hard | Data64 |
| X_floating | DSC$K_DTYPE_FX | 16 | N/A | N/A |
| S_floating complex | DSC$K_DTYPE_FSC | 2 * 4 | 2 * Hard | 2 * Data32 |
| T_floating complex | DSC$K_DTYPE_FTC | 2 * 8 | 2 * Hard | 2 * Data64 |
| X_floating complex | DSC$K_DTYPE_FXC | 2 * 16 | N/A | N/A |
| Small structures of 8 bytes or less | N/A | <=8 | Nostd | Nostd |
| Small arrays of 8 bytes or less | N/A | <=8 | Nostd | Nostd |
| 32-bit address | N/A | 4 | Sign64 | Sign64 |
| 64-bit address | N/A | 8 | Data64 | Data64 |
Table 4-11 contains the defined meanings for the memory extension type symbols used in Table 4-10.
| Sign Extension Type | Defined Function |
|---|---|
| Sign64 | Sign-extended to 64 bits. |
| Zero64 | Zero-extended to 64 bits. |
| Data32 | Data is 32 bits. The state of bits <63:32> is unpredictable. |
| 2 * Data32 | Two single-precision parts of the complex value are stored in memory as independent floating-point values (each handled as Data32). |
| Data64 | Data is 64 bits. |
| 2 * Data64 | Two double-precision parts of the complex value are stored in memory as independent floating-point values (each handled as Data64). |
| VAXF64 | Data is 64 bits. Low-order 32 bits are the same as the F_floating memory format and the high-order 32 bits are zero. (Used only in a general register, never in a floating-point register.) |
| VAXDG64 | Data is 64 bits. Uses the corresponding D_floating or G_floating memory format. (Used only in a general register, never in a floating-point register.) |
| 2*VAXF64 | Two single-precision parts of the complex value are stored in memory as independent floating-point values (each handled as VAXF64). |
| 2*VAXDG64 | Two double-precision parts of the complex value are stored in memory as independent floating-point values (each handled as VAXDG64). |
| Hard | Passed in the layout defined by the hardware SRM. |
| 2 * Hard | Two floating-point parts of the complex value are stored in a pair of registers as independent floating-point values (each handled as Hard). |
| Nostd | State of all high-order bits not occupied by the data is unpredictable across a call or return. |
| Previous | Next | Contents | Index |