HP OpenVMS Systems Documentation
HP OpenVMS Calling Standard
4.1.6 I64 Application Register Usage
Application registers are special-purpose registers designated for application use. This standard defines the usage of the OpenVMS application registers as listed in Table 4-5.
4.1.7 Floating-Point Status
The floating-point status of a program consists of two parts:
The floating-point status is generally managed using three OpenVMS system services: SYS$IEEE_SET_FP_CONTROL, SYS$IEEE_SET_PRECISION_MODE and SYS$IEEE_SET_ROUNDING_MODE.
The AR.FPSR hardware register is described in the Intel IA-64 Architecture Software Developer's Manual. The supplementary software register is internal to OpenVMS and is not documented for general use. This register holds information used by OpenVMS to implement the three system services and floating-point exception handling generally. It can only be accessed indirectly using the system services.
The floating-point status consists of two types of information:
Using a compiler or linker switch, you can associate a floating-point control status with the main procedure of a program to set the floating-point state prior to the beginning of program execution. If no control status is explicitly set, a default status appropriate for full IEEE computation is used.
Two floating-point control status settings are of particular interest:
Table 4-6 shows the values placed in the AR.FPSR hardware register when the Full IEEE-format floating-point control status is used.
Table 4-7 shows the values placed in the AR.FPSR hardware register when the VAX-format floating-point control status is used.
For both IEEE-format and VAX-format floating-point processing, additional floating-point status settings may be available. See your compiler documentation for other optional settings.
It is generally assumed that the initial floating-point control status will remain unchanged throughout execution of the whole program. However, a procedure (or cooperating group of procedures) may temporarily modify the floating-point control status provided the control status is restored to its value on entry. The control status can be restored by one of three methods: a normal return, resignalling, or unwinding for an exception. See Section 22.214.171.124 for additional information.
Because the floating-point control status can vary and can be changed
dynamically (even if later restored), the state of the floating-point
control status is generally indeterminate when a routine (especially a
shared library routine) is called. Usually this is acceptable. For
example, returning a NaN or raising an exception are both valid ways to
handle exceptional conditions. However, if correct operation of a
routine depends on a particular floating-point control setting, then
the called routine must save the control status on entry, set the
needed control status, perform its operation, and restore the control
status when it exits. (Whether the informational status is similarly
saved and restored is unspecified.)
The User Mask register contains five bits that may be modified by an application program, subject to the following conventions:
4.1.9 Additional Register Usage Information
As described in earlier sections, some registers are volatile and cannot be used to communicate information between routines (see Tables 4-1, 4-3, and 4-4). For example, B6 is used by OTS$JUMP_TO_BPV (see Section 4.7.7).
Of the volatile registers, the following registers are reserved for use by compiled code to communicate with specialized compiler support routines that require out of band information passing:
For example, R17 and R18 are used by OTS$CALL_PROC (see Section 126.96.36.199).
The following static general registers may be used within and between procedures in any mutually consistent combination of ways:
The normal or default use for these registers is shown in the Class column of Table 4-1. However, using suitable programming language features, it is valid for any of these registers to be used as preserved, scratch, input, output, global or not used. Of course, the unwind information (see Section A.4) for each procedure must accurately describe the actual usage.
Registers R8 and R9 may also be used as inputs (whether or not the procedure has a return value), but not in any additional ways.
General registers whose class is described as constant, special, volatile or automatic in Section 4.1.1 cannot be used in any other way.
An address is a 64-bit value used to denote a position in memory.
However, for compatibility with OpenVMS VAX and Alpha, many OpenVMS
applications and user-mode facilities operate in such a manner that
addresses are restricted to values that are representable in 32 bits.
This means that OpenVMS addresses can often be stored and manipulated
as 32-bit longword values. In such cases, the 32-bit address value is
always implicitly or explicitly sign extended to form a 64-bit address
for use by the Itanium hardware.
A procedure value, sometimes called a function pointer, is a value that uniquely identifies a procedure and can be used to call it.
For OpenVMS, a procedure value is the address of a function descriptor, which consists of at least two quadword fields: the address of the entry point and the GP value required by that procedure.
Every procedure whose address is taken, or might be taken, must have a unique official function descriptor. The address of this function descriptor is used for the procedure value that is passed as a parameter or when two procedure values are compared. For other purposes, additional local function descriptors may be used for efficiency (notably in images other than the image that contains the procedure).
An official function descriptor for any procedure which might be callable from a VAX or Alpha translated image must include signature information. A local function descriptor used to call a procedure that might be part of a VAX or Alpha translated image must also include additional fields to facilitate the call. Both of these cases are described in Section 5.1.2.
A function descriptor for a bound procedure uses a special pseudo-GP value and includes an uplevel frame pointer. Such function descriptors are described in Section 4.7.7.
The several kinds of function descriptors are summarized in Table 4-8.
Note that the different kinds of function descriptor are not
self-identifying (that is, they do not contain any form of tag or kind
This calling standard defines the following basic types of procedures:
A compiler may choose which type of procedure to generate based on the requirements of the procedure in question. A calling procedure does not need to know what type of procedure it is calling.
Every memory stack procedure or register stack procedure must have an associated unwind description (see Appendixes A and B) which describes what type of procedure it is and other procedure characteristics. A null frame procedure may also have an associated unwind description. (A default description applies if not.) This data structure is used to interpret the call stack at any given point in a thread's execution. It is typically built at compile time and usually is not accessed at run time except to support exception processing or other rarely executed code.
An unwind description for a procedure is provided for the following reasons:
4.5 Memory Stack
The memory stack is used for local dynamic storage, spilled registers, and parameter passing. It is organized as a stack of procedure frames, beginning with the main program's frame at the base of the stack, and continuing towards the top of the stack with nested procedure calls. At the top of the stack is the frame for the currently active procedure. (There may be some system-dependent frames at the base of the stack, prior to the main program's frame, but an application program may not make any assumptions about them.)
The memory stack begins at an address determined by the operating system, and grows towards lower addresses in memory. The stack pointer register (SP) always points to the lowest address in the current, top-most, frame on the stack.
Each procedure creates its frame on entry by subtracting its frame size from the stack pointer, and removes its frame from the stack on exit by restoring the previous value of SP (usually by adding its frame size, but a procedure may save the original value of SP when its frame size may vary).
Because the register stack is also used for the same purposes as the
memory stack, not all procedures need a memory stack frame. However,
every non-leaf procedure must save at least its return link and the
previous frame marker, either on the register stack or on the memory
stack. This ensures that there is an invocation context for every
non-leaf procedure on one or both of the stacks.
A memory stack procedure frame consists of five regions, as illustrated in Figure 4-1.
Figure 4-1 Procedure Frame
These regions are:
Whenever control is transferred to another procedure, the stack pointer must be octaword-aligned; at other times there is no stack alignment requirement. (A side effect of this is that the in-memory portion of the argument list will start on an octaword boundary.) During a procedure invocation, the SP can never be set to a value higher than the SP at entry to that procedure invocation.
An application may not write to memory addresses lower than the stack pointer, because this memory area may be written to asynchronously (for example, as a result of exception processing).
Most procedures are expected to have a fixed-size frame, and the conventions are biased in favor of this. A procedure with a fixed-size frame may reference all regions of the frame with a compile-time constant offset relative to the stack pointer. Compilers should determine the total size required for each region, and pad the local storage area to make the total frame size a multiple of 16 bytes. The procedure can then create the frame by subtracting an immediate constant from the stack pointer in the prologue, and remove the frame by adding the same immediate constant to the stack pointer in the epilogue.
If a procedure has a variable-size frame (for example, a C routine that calls the alloca built-in), it should make a copy of SP to serve as a frame pointer before subtracting the initial frame size from the stack pointer. The procedure can then restore the previous value of the stack pointer in the epilogue without regard for how much dynamic storage has been allocated within the frame. It can also use the frame pointer to access the local storage region, because offsets from SP will vary.
A frame pointer, as described above, is not required if both of the following conditions are true:
To expand a stack frame dynamically, the scratch area, outgoing parameters, and frame marker regions (which are always located relative to the current stack pointer), must be relocated to the new top of stack. If the scratch area and outgoing parameter area are both clear of any live values, there is no actual work involved in relocating these areas. For procedures with dynamically-sized frames, it is recommended that the previous stack pointer value be stored in a local stacked general register instead of the frame marker, so that the frame marker is also empty. If the previous stack pointer is stored in the frame marker, the code must take care to ensure that the stack is always unwindable while the stack is being expanded (see Appendix A).
Other issues depend on the compiler and the code being compiled. The standard calling sequence does not define a maximum stack frame size, nor does it restrict how a language system uses any stack frame region beyond those purposes described here. For example, the outgoing parameter region can be used as scratch storage whenever it is not needed for passing parameters.