HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS Calling Standard

Previous Contents Index

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.

Table 4-5 I64 Application Register Usage
Register Class Usage
AR.FPSR See Usage Floating-point status register. This register is divided into the following fields:
  • Trap Disable Bits (bits 5--0) -- Must be preserved by the callee, except for procedures whose documented purpose is to change these bits.
  • Status Field 0 -- Must be preserved by the callee, except for procedures whose documented purpose is to change these bits. The flag bits are the IEEE floating point standard sticky bits and are part of the static state of the machine.
  • Status Field 1 -- Dedicated for use by divide and square root code, and must always be set to standard values at any procedure call boundary (including entry to exception handlers). These standard values are: trap disable set, round-to-nearest mode, 80-bit (extended) precision, widest range for exponent on, and flush-to-zero mode off. The flag bits are scratch.
  • Status Fields 2 and 3 -- At procedure calls and returns, the control bits in these status fields must agree with the control bits in status field 0 and the trap disable bits should always be set. The flag bits are always available for scratch use.
See Section 4.1.7 for further usage and initial value information.
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:
  • Mode -- Controls the RSE behavior, and has scratch behavior. On a return, this field may be set to a standard value.
  • Privilege level -- Controls the privilege level at which the RSE operates, and may not be changed by non-privileged software.
  • Endian mode -- Controls the byte ordering used by the RSE, and must never be changed by an application.
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.

4.1.7 Floating-Point Status

The floating-point status of a program consists of two parts:

  • The AR.FPSR hardware register
  • A supplementary software register (a quadword)

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:

  • Floating-point control status bits are those bits or flags that control the operation of floating-point arithmetic operations. These bits include the trap disable flags (traps.vd, .dd, .zd, .od, ud, and .id) as well as the the ftz, wre, pc, rc, and td fields in each of the status fields (sf0, sf1, sf2, and sf3) of the AR.FPSR hardware register.


    The floating-point control status is sometimes informally also called the floating-point mode or IEEE mode.
  • Floating-point information status bits are those bits or flags that record summary information about the execution of previous floating-point arithmetic operations. These bits include the v, d, z, o, u, and i flags in each of the status fields (sf0, sf1, sf2, and sf3).

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:

  • Full IEEE-format floating-point control status--the default, unless the status is explicitly set to another value.
  • VAX-format floating-point control status--can be set for programs that use VAX-format floating-point processing.

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-6 Full IEEE-Format Floating-Point Status Register
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
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.

Table 4-7 VAX-Format Floating-Point Status Register
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
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 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:

  • BE (Big Endian Memory Access Enable) -- This bit must never be set on OpenVMS.
  • UP (User Performance Monitor Enable) -- This bit is reserved.
  • AC (Alignment Check) -- The application may set or clear this bit as desired. If the AC bit is clear, an unaligned memory reference may cause the system to deliver an exception to the application, or the system may emulate the unaligned reference. If the AC bit is set, an unaligned reference will always cause the system to deliver an exception to the application. At program start, the value of this bit on OpenVMS is clear.
  • MFL/MFH (Lower/Upper floating-point registers written) -- The application should not clear either of these bits unless the values in the corresponding registers are no longer needed (for example, it may clear the MFH bit when returning from a procedure, because the upper set of floating-point registers is all scratch). Doing so otherwise may cause unpredictable behavior.

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:

  • Static general registers R17-R18
  • Predicate register P15
  • Branch register B7

For example, R17 and R18 are used by OTS$CALL_PROC (see Section

The following static general registers may be used within and between procedures in any mutually consistent combination of ways:

  • R3-R7
  • R10-R11
  • R19-R24
  • R26-R31

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.

Table 4-8 Summary of Function Descriptor Kinds
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:

  • Memory stack procedure--allocates a memory stack and may maintain part or all of its caller's context on that stack
  • Register stack procedure--allocates only a register stack and maintains its caller's context in registers
  • Null frame procedure--allocates neither a memory stack nor a register stack and therefore preserves no context of its caller


    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:

  • To make invocations of that procedure visible to and interpretable by facilities such as the debugger, exception-handling system, and the unwinder.
  • To ensure that the context of the caller saved by the called procedure can be restored if an unwind occurs. (For a description of unwinding, see Section 8.7.)

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.

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:

  • Scratch area. This 16-byte region is provided as scratch storage for procedures that are called by the current procedure. Leaf procedures need not allocate this region. A procedure may use the 16 bytes pointed to by the stack pointer (SP) as scratch memory, but the contents of this area are not preserved by a procedure call.
  • Outgoing parameters. Parameters in excess of those passed in registers are stored in this region of the stack frame. A procedure accesses its incoming parameters in the outgoing parameter region of its caller's stack frame.
  • Frame marker (optional). This region may contain information required for unwinding through the stack (for example, a copy of the previous stack pointer).
  • Dynamic allocation. This variable-sized region (initially zero length) can be created as needed.
  • Local storage. A procedure can store local variables, temporaries, and spilled registers in this region. For conventions affecting the layout of this area for spilled registers, see Section A.3.

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:

  • The procedure uses an equivalent method of addressing the local storage region correctly before and after dynamic allocation.
  • The code satisfies the conditions imposed by the stack unwind mechanism.

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