| Previous | Contents | Index |
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.
| Register | Class | Usage |
|---|---|---|
| AR.FPSR | See Usage |
Floating-point status register. This register is divided into the
following fields:
|
| AR.RNAT | Automatic | RSE NaT collection register. Holds the NaT bits for values stored by the register stack engine. These bits are saved automatically in the register stack backing store. |
| AR.UNAT | Preserved | User NaT collection register. Holds the NaT bits for values stored by the ST8.SPILL instruction. As a preserved register, it must be saved before a procedure can issue any ST8.SPILL instructions. The saved copy of AR.UNAT in a procedure's frame holds the NaT bits from the registers spilled by its caller; these NaT bits are thus associated with values local to the caller's caller. |
| AR.PFS | Special | Previous function state. Contains information that records the state of the caller's register stack frame and epilogue counter. It is overwritten on a procedure call; therefore, it must be saved before issuing any procedure calls, and restored prior to returning. |
| AR.BSP | Read-only | Backing store pointer. Contains the address in the backing store corresponding to the base of the current frame. This register may be modified only as a side effect of writing AR.BSPSTORE while the Register Stack Engine (RSE) is in enforced lazy mode. |
| AR.BSPSTORE | Special | Backing store pointer. Contains the address of the next RSE store operation. It may be read or written only while the RSE is in enforced lazy mode. Under normal operation, this register is managed by the RSE, and application code should not write to it, except when performing a stack switching operation. |
| AR.RSC | See Usage |
RSE control; the register stack configuration register. This register
is divided into the following fields:
|
| AR.LC | Preserved | Loop counter. |
| AR.EC | Automatic | Epilogue counter (preserved in AR.PFS). |
| AR.CCV | Scratch | Compare and exchange comparison value. |
| AR.ITC | Read-only | Interval time counter. |
| AR.K0-AR.K7 | Read-only | Kernel registers. |
| AR.CSD | Scratch | Reserved for use as implicit operand registers in future extensions to the Itanium architecture. To ensure forward compatibility, OpenVMS considers these registers as part of the thread and process state. |
| AR.SSD | Scratch | Reserved for use as implicit operand registers in future extensions to the Itanium architecture. To ensure forward compatibility, OpenVMS considers these registers as part of the thread and process state. |
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:
The floating-point control status is sometimes informally also called the floating-point mode or IEEE mode. |
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.
| Status Field | Flags | td | rc | pc | wre | ftz |
|---|---|---|---|---|---|---|
| sf0 | 000000 | 0 | 00 | 11 | 0 | 0 |
| sf1 | 000000 | 1 | 00 | 11 | 1 | 0 |
| sf2 and sf3 | 000000 | 1 | 00 | 11 | 0 | 0 |
|
global trap disable bits:
.id, .ud, .od, .zd, .dd, .vd |
111111 | |||||
| inherit floating-point mode on thread creation | 0 |
Table 4-7 shows the values placed in the AR.FPSR hardware register when the VAX-format floating-point control status is used.
| Status Field | Flags | td | rc | pc | wre | ftz |
|---|---|---|---|---|---|---|
| sf0 | 000000 | 0 | 00 | 11 | 0 | 0 |
| sf1 | 000000 | 1 | 00 | 11 | 1 | 0 |
| sf2 and sf3 | 000000 | 1 | 00 | 11 | 0 | 0 |
|
global trap disable bits:
.id, .ud, .od, .zd, .dd, .vd |
110010 | |||||
| inherit floating-point mode on thread creation | 0 |
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 8.5.3.4 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.)
4.1.8 User Mask
The User Mask register contains five bits that may be modified by an application program, subject to the following conventions:
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 5.1.2.3).
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.
Floating-point, predicate, branch, and application registers can be
used only according to the class described in Sections 4.1.2
through 4.1.6.
4.2 Address Representation
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.
4.3 Procedure Representation
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.
| Kinds and Roles | Size (Quadwords) |
|---|---|
| Local function descriptor without translated image support | 2 |
| Local function descriptor with translated image support (jacket function descriptor) | 4 |
| Official function descriptor without translated image support | 3 |
| Official function descriptor with translated image support | 3 |
| Bound function descriptor | 6 |
Note that the different kinds of function descriptor are not
self-identifying (that is, they do not contain any form of tag or kind
field).
4.4 Procedure Types
This calling standard defines the following basic types of procedures:
Unlike an Alpha null frame procedure (see Section 3.4 and Section 3.4.6), an I64 null frame procedure does not execute in the context of its caller because the Intel® Itanium® call instruction (br.call) changes the register set so that only the caller's output registers are accessible in the called routine. The caller's input and local registers cannot be accessed at all. The call instruction also changes the previous frame state (PFS) of the Itanium processor. |
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.
Read access to unwind descriptions is provided through the procedural interfaces described in Sections 4.8 and A.5.
An unwind description for a procedure is provided for the following reasons:
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.
4.5.1 Procedure Frames
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.
A stack pointer that is not octaword aligned is valid only in a variable-sized frame (see below) because the unwind descriptor (MEM_STACK_F, see Section A.4.1.3) for a fixed-size frame specifies the size in 16-byte units. |
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.
| Previous | Next | Contents | Index |