HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS Programming Concepts Manual

Previous Contents Index

18.10 Function Value Return

A function is a routine that returns a single value to the calling routine. The function value represents the value of the expression in the return statement. As specified by the calling standard, a function value may be returned as an actual value in R0.

On VAX systems, if the actual function value returned is greater than 32 bits, then both R0 and R1 should be used.

On Alpha systems, if the actual function returned is a floating-point value, the floating-point value is returned either in F0 or in both F0 and F1.

A standard function must return its function value by one of the following mechanisms:

  • Immediate value
  • Reference
  • Descriptor

These mechanisms are the standard return convention because they support the language-independent data types. For information about condition values returned in R0, see Section 18.11.

For I64, values up to 128 bits are returned directly in the registers, according to the rules in Table 18-15.

Integer, enumeration, record, and set values (bit vectors) smaller than 64 bits must be zero-filled (unsigned integers, enumerations, records, sets) or sign-extended (signed integrals) to a full 64 bits. However, for unsigned 32-bit integers, bit 31 is replicated in bits 32--63.

When floating-point values are returned in floating-point registers, they are returned in the register format, rounded to the appropriate precision. When they are returned in the general registers (for example, as part of a record), they are returned in their memory format.

OpenVMS does not support a general notion of homogeneous floating-point aggregates. However, the special case of two single-precision or double-precision floating-point values implementing values of a complex type are handled in an analogous manner.

Table 18-15 Rules for I64 Return Values
Type Size (Bits) Location of Return Value Alignment
Integer/pointer, small secord, set 1--64 R8 LSB
IEEE single-precision floating-point (S_floating) 32 F8 N/A
IEEE double-precision floating-point
64 F8 N/A
IEEE single-precision complex (S_floating) 64 F8, F9 N/A
IEEE double-precision complex (T_floating) 128 F8, F9 N/A
VAX single-precision floating-point (F_floating) 32 R8 N/A
VAX double-precision floating-point
(D_ & G_floating)
64 R8 N/A
VAX single-precision floating-point complex (F_floating) 64 R8, R9 N/A
VAX double-precision floating-point complex (D_ & G_floating) 128 R8, R9 N/A


X_floating and X_floating complex are not included in this table because they are returned using the hidden parameter method.

The rules in Table 18-15 are expressed in more detail in Table 18-11. F_floating and F_floating complex values in the general registers are zero-extended (Zero64), because this most closely approximates the effect of using the Alpha register format.

Hidden Parameter

Return values other than those covered by Table 18-15 are returned in a buffer allocated by the caller. A pointer to the buffer is passed to the called procedure as a hidden first parameter, and all normal parameters are shifted one slot to make this possible. The return buffer must be aligned at a 16-byte boundary.

18.11 Condition Value Return

An OpenVMS system routine can indicate success or failure to the calling program by returning a condition value. In addition, an error condition to the calling program can return as a condition value in R0 (R8, R9 for I64) or by error signaling.

A condition value in R0 (R8, R9 for I64), also called a return status or completion code, is either a success (bit 0 = 1) value or an error condition (bit 0 = 0) value. In an error condition value, the low-order 3 bits specify the severity of the error (see Figure 18-16). Bits <27:16> contain the facility number, and bits <15:3> indicate the particular condition. Bits <31:28> are the control field. When the called procedure returns a condition value, the calling program can test R0 and choose a recovery path. A general guideline to follow when testing for success or failure is that all success codes have odd values and all error codes have even values.

Figure 18-16 Condition Value Format

When the completion code is signaled, the calling program must establish a handler to get control and take appropriate action. (See Chapter 9 or the HP OpenVMS Calling Standard for a description of signaling and condition handling and for more information about the condition value.)

18.12 Macro-32 Register Usage and Mapping for I64

Because the I64 calling standard diverges from the Alpha and VAX calling standards regarding the use of registers and register mapping, and because Macro-32 assumes that registers are preserved across calls, the MACRO compiler maps registers to allow existing code to compile unmodified.

If you use OpenVMS high-level languages, the register and register mapping differences in the calling standards are handled by the compilers and are not exposed to your code. However, if your code uses Macro-32, C #pragma linkages, or BLISS linkages, your code might have to take into account the differences in register mapping.

This section describes I64 register usage and mapping.

18.12.1 I64 Register Usage Compared with Alpha and VAX

OpenVMS I64 systems employ 32 integer registers, R0 through R31, with R0 being a read-only register that contains 0. This is different from OpenVMS Alpha, where R31 is a read-write register that contains 0.

In addition, the I64 calling standard has been written to be highly compatible with the Intel calling standard, and is quite different from the OpenVMS Alpha calling standard. For example, the standard return registers on I64 are R8/R9, not R0/R1 as on Alpha. The I64 calling standard reserves R1 as the GP (global pointer), does not include a standardized FP (frame pointer), and only has R4 through R7 as preserved across calls, not R2 through R15 as on Alpha.

I64 register usage differs from that of Alpha and VAX in the following key ways:

  • Registers 2 through 11 are preserved on OpenVMS VAX
  • Registers 2 through 15 are preserved on OpenVMS Alpha
  • Registers 4 through 7 are preserved on OpenVMS I64
  • I64 has more "volatile" registers
  • I64 returns values in R8/R9 instead of R0/R1
  • R0 is readonly in I64
  • I64 reserves R1 as the GP (global pointer)
  • I64 does not include a standardized FP (frame pointer)
  • Arguments are also passed in stacked registers in I64. R32-R39 are used as incoming argument registers. I64 Register Mapping in MACRO Compiler

The OpenVMS MACRO compiler compiles Macro-32 source code written for OpenVMS VAX systems (the VAX MACRO assembler) into machine code that runs on OpenVMS Alpha and OpenVMS I64 systems. Because Macro-32 source code is written with the VAX and Alpha calling standards in mind, the compiler performs several transformations to allow existing code to compile unmodified with the I64 compiler.

The MACRO compiler maps the registers in Macro-32 source programs to I64 registers on your behalf, as shown in Table 18-16, to minimize source changes. This allows existing programs to use "MOVL SS$_NORMAL, R0" and have the generated code return the value in R8 as prescribed by the calling standard. The mapping to an actual I64 register is totally transparent to the Macro-32 source code (and most of the compiler).

Table 18-16 Register Mapping Table for OpenVMS VAX/OpenVMS Alpha to OpenVMS I64
OpenVMS VAX/OpenVMS Alpha Register in Source Code OpenVMS I64 Register Used in Generated Code
R0 R8
R1 R9
R2 R28
R3 R3
R4 R4
R5 R5
R6 R6
R7 R7
R8 R26
R9 R27
R10 R10
R11 R11
R12 R30
R13 R31
R14 R20
R15 R21
R16 R14
R17 R15
R18 R16
R19 R17
R20 R18
R21 R19
R22 R22
R23 R23
R24 R24
R25 R25
R26 Itanium stacked register
R27 Itanium stacked register
R28 Itanium stacked register
R29 R29
R30 R12
R31 R0

The register mapping was carefully chosen based on which registers were preserved across calls, which registers may be modified across calls, and which registers are volatile and do not even survive into or out of a call.

As on Alpha, Macro-32 references to AP are mapped by the compiler to the appropriate location depending on whether the arguments have been saved to the stack. To support references to FP, the compiler creates an FP value where needed. The compiler supports references to 0(FP) to establish condition handlers just like on VAX and Alpha.

The compiler does not provide any syntax for accessing I64 registers directly without going through the mapping table.

The automatic register mapping done by the compiler allows many Macro-32 programs (including those that access Alpha registers R16-R31) to compile without modificiations.

Note, however, that use of registers R16-R21 as routine parameters on Alpha is not portable to I64. Use PUSHL to pass parameters to a CALL, and use 4(AP), 8(AP), and so forth in the called routine to refer to them. The compiler will generate the correct register references instead of the stack references implied by the VAX operands.

On I64 systems, the compiler continues to recognize many of the EVAX_* builtins that provide direct access to Alpha instructions on Alpha systems. These built-ins will generate one or more I64 instructions to perform the same logical operation. See the HP OpenVMS MACRO Compiler Porting and User's Guide for a complete list of which EVAX_* built-ins are also supported on I64. Use of MACRO Linkage Directives to Preserve Registers

For I64 systems, add linkage directives (.CALL_LINKAGE, .DEFINE_LINKAGE, or .USE_LINKAGE) to mark VAX CALLS or CALLG instructions that call routines that return values in registers other than R0 or R1, or to JSB to routines written in a language other than Macro-32. These directives look similar to the .CALL_ENTRY directive and specify input, output, preserved, and scratch masks. In addition, they also have a language keyword to provide an alternative quick specification.

The .CALL_LINKAGE directive associates a named or anonymous linkage with a routine name. When the compiler sees a CALLS, CALLG, JSB, BSBB, or BSBW instruction with the routine name as the target, it will use the associated linkage to decide which registers need to be saved and restored around the call.

The .USE_LINKAGE directive establishes a temporary named or anonymous linkage that will be used by the compiler for the next CALLS, CALLG, JSB, BSBB, or BSBW instruction processed in lexical order. This directive is used when the target of the next CALLS, CALLG, JSB, BSBB, or BSBW instruction is not a name, but a run-time value (for example, CALLS #0, (R6)). When the compiler sees the next CALLS, CALLG, JSB, BSBB, or BSBW instruction, it will use the associated linkage to decide which registers need to be saved and restored around the call. After the instruction is processed, the temporary linkage is reset to null.

The .DEFINE_LINKAGE directive defines a named linkage that can be used with subsequent .CALL_LINKAGE or .USE_LINKAGE directives.

If your Macro-32 code uses a CALLS or CALLG instruction to access routines that return values in registers other than R0 or R1, the contents of the saved and restored registers may not be what you expect. Existing Macro-32 code traditionally assumes that registers R2-R11 and R15 are preserved and returned across calls. For CALLS and CALLG instructions, the MACRO compiler automatically saves and restores registers R2-R3 and R8-R15 in case the target of the call is not Macro-32. However, this means that changes made to these registers by the routine call are undone. This can cause problems if the routine return values were in registers other than R0-R1.

In the following example, m1.mar saves and preserve registers R2, R3, and R9 and undoes the changes made to these registers by the routine call.

   calls #3,g^body_scan

   .call_entry preserve=<r6,r7,r8>, output=<r2,r3,r4,r5,r9>

To avoid this problem, add a .CALL_LINKAGE directive to m1.mar (or to a common prefix file or macro):

.call_linkage rtn_name=body_scan preserve=<r6,r7,r8> -

For JSB instructions, the MACRO compiler assumes that the target is also Macro-32 and does not save and restore anything. The compiler assumes that all registers flow in and out of the target routine. Alpha high-level language compilers would have preserved registers R2-R15. However, I64 high-level language compilers preserve only registers R4-R7.

In the following example m1.mar assumes that registers R0-R15 are returned or preserved by the target BLISS routine. On Alpha, BLISS would have done that. On I64, it preserves only registers R4-R7:

   jsb search_path

   linkage l = jsb(register=0) : global(wrk=10,prc=11)
   global routine search_path : l = begin . . . End;

To avoid this problem, add a .CALL_LINKAGE directive to m1.mar:

  .call_linkage rtn_name=search_path language=other -

Indirect calls with mismatched registers are not detected by the linker since it does not know what routine is being called. An indirect JSB to a BLISS or C routine requires a .USE_LINKAGE directive:

  .use_linkage language=other
  jsb (r5)

If the routine returns a register other than R0/R1:

  .use_linkage language=other output=<r5,r9>
  jsb (r3)

See the HP OpenVMS MACRO Compiler Porting and User's Guide for additional information.

18.12.2 High-Level Language Compiler Register Mapping

If you use OpenVMS high-level languages, the register and register mapping differences in the calling standards are handled by the compilers and are not exposed to your code. However, if your code uses C #pragma linkages or BLISS linkages to interface with Macro-32 source code, your code might have to take into account the differences in register mapping.

BLISS added a new qualifier and source level switch to enable register mapping for register numbers in linkage and register declarations. It is off by default. BLISS also has additional support for linkages that reference arguments. The C compiler changed the #pragma linkage to map the registers by default, along with additional support for linkages that reference arguments or floating registers. There are new pragmas to get unmapped linkages.

See your compiler documentation for additional information.

Previous Next Contents Index