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.
Note that this standard does not define a standard set of descriptors.
Consequently, descriptors cannot be used as part of a standard call.
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 of the three mechanisms must be
used by a given language compiler. Language semantics and interoperability
considerations might require different mechanisms to be used in different
situations.
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.
4.1 Data Passing
The following sections define the calling
standard conventions for passing data between procedures in a call chain.
An argument item
represents one unit of data
being passed between procedures. The following topics are covered:
4.1.1 Argument Passing Mechanisms
This Digital UNIX calling
standard defines three classes of argument items
according to the
mechanism used to pass the argument:
4.1.2 Normal Argument List Structure
The argument list
in a Digital UNIX call
is an ordered set of zero or more argument items, which together comprise
a logically contiguous structure known as the argument item sequence.
An argument item
is represented in 64 bits.
The following general rules determine the location of any specific argument:
The argument list, including the in-memory portion, as well as the portion passed in registers, can be read from and written to by the called procedure. Therefore, the calling procedure must not make any assumptions about the validity of any part of the argument list after the completion of a call.
4.1.3 Homed Memory Argument List Structure
It is, in certain
cases, useful to form a contiguous in-memory structure that includes the contents
of all the formal parameter values in the program; for example, C procedures
that use varying length argument lists). In nearly all these cases, a compiler
can arrange to allocate and initialize this structure so that those parameter
values passed in registers are placed adjacent to those parameters passed
on the stack, without making a copy of the stack arguments. The storage for
the parameters passed in registers is called the argument home
area.
(See Figure 3-1
and Figure 3-2.) Figure 4-1
shows the resulting in-memory homed argument list structure.
Figure 4-1: In-Memory Homed Argument List Structure
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:
To load the next integer argument, the program reads the quadword at
location (base+offset) and adds 8 to offset.
To load the next floating-point argument, if offset is less than
or equal to 6*8, the program reads the quadword location (base+offset-6*8). Otherwise, the program reads the quadword at
location (base+offset). In both cases, the program adds 8 to offset. For details, see the file /usr/include/stdarg.h.
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.
typedef struct {
char *base;
int offset;
} va_list;
4.1.4 Argument Lists and High-Level Languages
High-level language functional notations for procedure call arguments
are
mapped into argument
item sequences
according to the following
requirements:
4.1.5 Unused Bits in Passed Data
Whenever data is passed by value
between two procedures in registers
(as is the case for the first
six input arguments and return values) or in memory (as is the case for arguments
after the first six), the bits not used
by the data are usually sign-extended
or zero-extended.
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) can be
passed by a single descriptor.
Note that extended floating-point values are not passed using the immediate
value mechanism. Instead, they are passed using the by-reference mechanism.
(When by-value semantics are required, however, it might be necessary to make
a copy of the actual parameter and pass a reference to that copy to avoid
improper alias effects.)
Note also that when a record is passed by immediate value, the component
types have no bearing on how the argument is aligned. The record will always
be quadword-aligned.
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 calling procedure must provide the required contiguous storage and
pass the address of the storage as the first argument. This address must
specify storage that is naturally aligned according to the data type 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.
4.1.6 Sending Data
The following sections define the calling
standard requirements for mechanisms to send data and the order of argument
evaluation.4.1.6.1 Sending Mechanism
In Section 4.1.1,
the allowable argument-passing mechanisms are immediate value, reference,
and descriptor. The following list describes the requirements for using these
mechanisms.
Note
4.1.6.2 Order of Argument Evaluation
Because most high-level languages do not specify the order of evaluation
of arguments with respect to side effects, those language processors can evaluate
arguments in any convenient order. The choice of argument evaluation order
and code generation strategy is constrained only by the definition of the
particular language. Programs should not depend on the order of evaluation
of arguments.4.1.7 Returning Data
A standard function must return its function
value by one of the following mechanisms:
4.1.7.1 Function Value Return By Immediate Value
The following
list describes the two types of immediate value function returned:
4.1.7.2 Function Value Return By Reference
A function value
is returned by reference if and only if the function
value satisfies the following criteria:
4.1.7.3 Function Value Return By Descriptor
A function
value is returned by descriptor if and only if the function
value satisfies all of the following criteria:
4.2 Data Allocation
Data allocation refers to the method
of storing data in memory. The following sections cover these topics:
4.2.1 Data Alignment
In the Alpha environment, memory references
to data that is not naturally aligned can result in alignment faults.
Such alignment faults can severely degrade
the performance of all procedures that reference the unnaturally aligned data.
For aggregates such as strings, arrays, and records, the data type to be considered for purposes of alignment is not the aggregate itself, but the elements that make up the aggregate. The alignment requirement of an aggregate is that all elements of the aggregate be naturally aligned. Varying 8-bit character strings, for example, must start at addresses that are a multiple of at least 2 (word alignment) because of the 16-bit count at the beginning of the string; 32-bit integer arrays start at a longword boundary, regardless of the extent of the array.
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.
4.2.2 Granularity of Memory
Granularity
of memory refers to the smallest unit in which memory can be accessed. In
the Alpha architecture, although memory is byte-addressed, the granularity
is a longword. Even for longword-sized data, it is often expedient for execution
efficiency to access memory in quadword units. In the presence of multiple
threads of execution (whether on multiple processors or a single processor),
allocation of more than one data element within a single quadword can lead
to more complicated access sequences (for example, using ldx_l/stx_c) and/or latent and hard to diagnose errors because of nonobvious and
implicit data sharing. Therefore, it is generally recommended that independent
variables (that is, variables not combined in a larger aggregate) be allocated
on quadword boundaries.4.2.3 Record Layout Conventions
The Digital UNIX calling
standard record layout conventions are designed to provide good run-time performance
on all implementations of the Alpha architecture. Only the standard record
layouts may be used across standard interfaces or between languages. Languages
can support other language-specific record layout conventions, but such other
record layouts are nonstandard.