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 a parameter.
A reference argument item contains the address of a data item, such as a scalar, string, array, record, or procedure. That data item is associated with a 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. That data item is associated with a parameter.
An argument item can be used to pass arguments by immediate value, by reference, and by descriptor. Any combination of these mechanisms in an argument list is permitted.
Although the argument items form a logically contiguous sequence, they are, in practice, mapped to integer and floating-point registers and to memory in a fashion that can produce a physically discontiguous argument list. Registers $16 - $21 and $f16 - $f21 are used to pass the first six items of the argument item sequence. Additional argument items must be passed in a memory argument list that must be located at 0(SP) at the time of the call.
Table 4-1 specifies the standard locations in which argument items can be passed.
Argument Item | Integer Registers | Floating-point Registers | Stack |
---|---|---|---|
1 | $16 | $f16 | - |
2 | $17 | $f17 | - |
3 | $18 | $f18 | - |
4 | $19 | $f19 | - |
5 | $20 | $f20 | - |
6 | $21 | $f21 | - |
7 ... n | 0(SP) ... (n-7)*8(SP) |
The following general rules determine the location of any specific argument:
Generally, it is not possible to tell statically whether a particular argument is an integer or floating-point argument. Therefore, it is necessary to store integer and floating-point register argument contents in this structure. However, it is sometimes possible to determine statically that there are no floating-point arguments anywhere either in registers or on the stack. In this case, the first six entries can be omitted. To facilitate this special case, the address used to reference this structure is always the address of the first integer argument position.
The C-language type va_list is used to iterate through a variable argument list. The va_list type can be defined as follows:
typedef struct { char *base; int offset; } va_list;
Arguments passed by immediate value cannot be omitted unless a default value is supplied by the language. (This restriction makes it possible for called procedures to distinguish an omitted immediate argument from an immediate value argument with the value 0.)
Trailing null or omitted arguments, for example CALL SUB(A,,), are passed by the same rules as those for embedded null or omitted arguments.
Table 4-2 defines the various data type requirements for size and their extension to set or clear unused bits.
Data Type | Type Designator (bytes) | Data Size Type | Register Extension Type | Memory Extension |
---|---|---|---|---|
Byte logical | BU | 1 | Zero64 | Zero64 |
Word logical | WU | 2 | Zero64 | Zero64 |
Longword logical | LU | 4 | Sign64 | Sign64 |
Quadword logical | QU | 8 | Data64 | Data64 |
Byte integer | B | 1 | Sign64 | Sign64 |
Word integer | W | 2 | Sign64 | Sign64 |
Longword integer | L | 4 | Sign64 | Sign64 |
Quadword integer | Q | 8 | Data64 | Data64 |
F floating | F | 4 | Hard | Data32 |
D floating | D | 8 | Hard | Data64 |
G floating | G | 8 | Hard | Data64 |
F floating complex | FC | 2*4 | 2*Hard | 2*Data32 |
D floating complex | DC | 2*8 | 2*Hard | 2*Data64 |
G floating complex | GC | 2*8 | 2*Hard | 2*Data64 |
IEEE floating single S | FS | 4 | Hard | Data32 |
IEEE floating double T | FT | 8 | Hard | Data64 |
IEEE floating extended X | FX | 16 | n/a | n/a |
IEEE floating single S complex | FSC | 2*4 | 2*Hard | 2*Data32 |
IEEE floating double T complex | FTC | 2*8 | 2*Hard | 2*Data64 |
IEEE floating extended X complex | FXC | 2*16 | n/a | n/a |
Structures | N/A | Nostd | Nostd | |
Small arrays of 8 bytes or less | N/A | [le ] 8 | Nostd | Nostd |
32-bit address | N/A | 4 | Sign64 | Sign64 |
64-bit address | N/A | 8 | Data64 | Data64 |
The following table contains the definitions for the extension type symbols used in Table 4-2:
Sign Extension Type | Definition |
---|---|
Sign32 | Sign-extended to 32 bits. The state of bits <63:32> is unpredictable. |
Sign64 | Sign-extended to 64 bits. |
Zero32 | Zero-extended to 32 bits. The state of bits <63:32> is unpredictable. |
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 with 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 with each handled as Data64. |
Hard | Passed in the layout defined by the Alpha Architecture Reference Manual. |
2 * Hard | Two double-precision parts of the complex value are stored in a pair of registers as independent floating-point values with each handled as Hard. |
Nostd | The state of all high-order bits not occupied by the data is unpredictable across a call or return. |
Sign64, when applied to a longword logical, duplicates bit 31 through bits <63:32>. This duplication can cause the 64-bit integer value to appear negative. However, careful use of 32-bit arithmetic and 64-bit logical instructions (with no right shifts) will preserve the 32-bit unsigned nature of the argument. Note
Because of the varied rules for sign extension of data when passed as arguments, calling and called routines must agree on the data type of each argument. No implicit data type conversions can be assumed between the calling procedure and the called procedure.
An argument can be passed by immediate value only if the argument is one of the following:
No form of string, array, or complex data type can be passed by immediate value in a standard call.
A standard immediate argument item must fill all 64 bits. Therefore, unused high-order bits of all data types (excluding records and Data32 items) must be zero-extended or sign-extended as appropriate, depending on the data type to fill all unused bits, as specified in Table 4-2.
Record values that are larger than 64 bits can be passed by immediate value if the following conditions are met:
Nonrecord argument values that are larger than 64 bits can be passed by immediate value using nonstandard conventions, similar to those used for passing records. Thus, for example, a 26-byte string could be passed by value in four integer registers.
Nonparametric arguments (that is, arguments for which associated information such as string size and array bounds is not required) may be passed by reference in a standard call.
Parametric arguments (that is, arguments for which associated information such as string size and array bounds must be passed to the caller) may be passed by reference followed by one or more immediate arguments for the parametric values. (The parametric values do not need to immediately follow the reference arguments to which they apply.)
This standard does not define interlanguage conventions for calls with parametric arguments. Note
Parametric arguments (that is, arguments for which associated information such as string size and array bounds must be passed to the caller) can be passed by a single descriptor.
This standard does not define a standard set of descriptors for interlanguage use. Note
These mechanisms are the only standard means available for returning function values. They support the important language-independent data types. Functions that return values by any mechanism other than those specified here are nonstandard, language-specific functions.
The following sections describe each of the three standard mechanisms for returning function values.
A function value is returned by immediate value in register $0 if and only if the type of function value is one of the following:
No form of string, record, or array can be returned by immediate value. Two separate 32-bit entities cannot be returned in $0.
A function value of less than 64 bits returned in $0 must have its unoccupied bits extended (as appropriate, depending on the data type) to a full quadword. (See Table 4-2 for details.)
A function value is returned by immediate value in register $f0 if and only if it is a noncomplex single- or double-precision floating-point value (F, D, G, S, or T). A function value is returned by immediate value in registers $f0 and $f1 if and only if it is a complex single- or double-precision floating-point value (complex F, D, G, S, or T). The real part is in $f0 and the imaginary part is in $f1.
The actual-argument list and the formal-argument list are shifted to the right by one argument item. The new first argument item is reserved for the address of the function value.
The called function must write the function value to the storage described by the first argument.
Function results returned by descriptor are not permitted in a standard call.
Typically, the called routine creates the return object on its stack and leaves it there on return. This process is referred to as the stack return mechanism. The exit code of the called routine does not restore SP to its value before the call because, if it did, the return value would be left unprotected in memory below SP. The calling routine must be prepared for SP to have a different value after the call than the pointer had before the call.
To avoid such performance degradation, all data values for programs running on Digital UNIX systems should be naturally aligned. Table 4-4 contains information on data alignment.
Data Type | Alignment Starting Position |
---|---|
8-bit character string | Byte boundary |
16-bit integer | Address that is a multiple of 2 (word alignment) |
32-bit integer | Address that is a multiple of 4 (longword alignment) |
64-bit integer | Address that is a multiple of 8 (quadword alignment) |
Single-precision real value | Address that is a multiple of 4 (longword alignment) |
Double-precision real value | Address that is a multiple of 8 (quadword alignment) |
Extended-precision real value | Address that is a multiple of 16 (octaword alignment) |
Single-precision complex value | Address that is a multiple of 4 (longword alignment) |
Double-precision complex value | Address that is a multiple of 8 (quadword alignment) |
Extended-precision complex value | Address that is a multiple of 16 (octaword alignment) |
Data types larger than 64 bits | Quadword or greater alignment. (Alignments larger than quadword are language-specific or application defined) |
Note that the rules in Section 4.1.6.1 for passing by value an argument that is a record always provide quadword alignment of the record value independent of the normal alignment requirement of the record. If deemed appropriate by the implementation, normal alignment can be established within the called procedure by making a copy of the record argument at a suitably aligned location.
The aligned record layout conventions ensure the following:
The aligned record layout is defined by the following conventions:
In addition, the alignment of the record as a whole is increased to that of the underlying integer type, if necessary.