HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS MACRO Compiler
Porting and User's Guide

Previous Contents Index

1.4 Step-by-Step Porting Process for OpenVMS Alpha to OpenVMS I64

Porting VAX MACRO code already running on OpenVMS Alpha to OpenVMS I64 is a relatively simple process. In contrast to porting from OpenVMS VAX, most VAX MACRO code will recompile with no changes required.

Due to differences in the calling standards between OpenVMS Alpha and OpenVMS I64, the compiler needs to know about:

  • MACRO code that uses the JSB or BSBW instructions to jump to code that is not written in VAX MACRO
  • MACRO code that uses the CALLS or CALLG instructions to call routines that return values in registers other than R0 or R1

You need to add linkage direcives (.CALL_LINKAGE, .DEFINE_LINKAGE) to tell the compiler about routines that return values in registers other than R0/R1 and about routines written in a language other than Macro-32 that are called with a JSB/BSBW instruction. In addition, you need to add the .USE_LINKAGE directive at each indirect CALLS/CALLG instruction if the routine has a nonstandard return. Add the .USE_LINKAGE directive at each indirect JSB/BSBW instruction if the routine is written in a language other than Macro-32. See Appendix B, Specialized Directives for more information.

1.5 Identifying Nonportable VAX MACRO Coding Practices

When examining a VAX MACRO module that you intend to compile to OpenVMS Alpha or OpenVMS I64 object code, you need to look for nonportable coding constructs. The occurrence of these in a module can make porting take longer than it would otherwise. Although the compiler can identify many of these practices, recognizing them yourself will speed up the porting effort. For more information about nonportable MACRO coding practices, including some that occur less frequently and are less easy to detect, see Chapter 3.

Look for these nonportable MACRO coding practices:

  • Removing the return address from the stack to return to the caller's caller, such as the following (see Section 3.3.4):

    TSTL    (SP)+               ; remove return address
    RSB                         ; return to caller's caller
  • Temporarily removing the return address from the stack to allocate space on the stack using mechanisms such as the following (see Section 3.3.4):

    POPL    R0                  ; remove the return address
    SUBL    #structure_size,SP  ; allocate stack space for caller
    PUSHL   R0                  ; replace the return address

    POPL    R1                  ; hold return address
    PUSHL   structure           ; build structure for caller
    ; code continues
    JMP     (R1)                ; return to caller
  • Pushing a label onto the stack, as in the following examples, often as an attempt to construct a return address for an RSB instruction (see Section 3.3.3):

    MOVAL   routine_label,-(SP)

    PUSHAL  routine_label
  • Modifying the frame pointer (FP) (see Section 3.1.1). VAX MACRO code typically modifies the frame pointer for one of two reasons:
    • To manually assemble a call frame on the stack.
    • To use the frame pointer to reference local storage allocated in a .JSB_ENTRY routine.

    MOVL    SP,FP
    SUBL    #data_area,SP
  • Constructing an REI target, as in the following examples (see Section 3.3.7):

    MOVL    #fake_psl,-(SP)
    MOVAL   target_label,-(SP)      ; all three

    MOVPSL  -(SP)
    MOVAL   target_label,-(SP)      ; force AST delivery only

            MOVL    #fake_psl,-(SP)
            BSBW    DOREI
            ; code continues
  • Branching to a destination that consists of a label plus an offset as in the following example. The appearance of this practice in VAX MACRO code might indicate a branch past some data in the code stream, such as the register save mask at the top of a .CALL_ENTRY routine (see Section 3.2.1). Alternatively, it might be a sign that the code is familiar with and dependent upon the size of VAX instructions (see Section 3.2.3):

    BRx     label+offset
  • Moving an opcode to a location, usually the stack or a data area, as shown in the following example. This practice indicates either generated or self-modifying code and will require redesign as indicated in Section 3.2.2:

    MOVB    #OP$_opcode,(Rx)

    MOVZBL  #OP$_opcode,(Rx)
  • Jumping across modules. Because of architectural requirements, the compiler must handle jumps across modules as JSBs. Therefore, external branch targets as in the following example must be declared with the .JSB_ENTRY directive (see Section 2.3.3):

    JMP     G^external_routine

1.6 Establishing Useful Coding Conventions

Section 1.3 describes a recommended process for porting VAX MACRO code to OpenVMS Alpha or OpenVMS I64. Although this process might provide a mechanism for porting code efficiently, it cannot by itself guarantee that the porting effort will be consistent among the engineers who are performing the porting, or will be intelligible to the engineers who will later need to debug and test ported code. To ensure that the porting effort proceeds uniformly and that its effects on source code are well documented, an engineering group should establish coding conventions that are relevant to the goals of the effort.

Naturally, any methodology an engineering group adopts should be shaped by that group's development environment, including those procedures the group follows for tool management, source code control, common code, and testing. The coding conventions an engineering group should evaluate include:

  • Establishing VAX MACRO source modules that are common to OpenVMS VAX and OpenVMS Alpha or OpenVMS I64 systems (see Section 1.7)
  • Providing clear and consistent register declarations in the compiler's entry-point directives (see Section 2.3)

1.7 Maintaining Common Sources

When designing a VAX MACRO code porting effort, consider the benefits of maintaining common sources for OpenVMS VAX, OpenVMS Alpha, and OpenVMS I64 systems. It is advantageous to an engineering group to have only one copy of its sources to maintain and enhance, and common sources help ensure common user interfaces. However, if you find that you are conditionalizing so much source code that it is no longer intelligible, take steps to restructure the code into architecture-specific and architecture-independent pieces. If the number of these pieces becomes unmanageable, create separate architecture-specific modules.

1.7.1 Including Compiler Directive Definitions

A successful compilation does not preclude VAX MACRO code in a source file from also processing successfully under the VAX MACRO assembler. If you added any compiler directives to your code, they will be resolved by the library SYS$LIBRARY:STARLET.MLB when the code is assembled. The assembler automatically searches this library for any undefined macros. After finding these definitions, the assembler will ignore occurrences of the compiler directives.

However, if you are using OpenVMS VAX Version 6.0 or earlier, you must first extract the directive definitions from SYS$LIBRARY:STARLET.MLB on OpenVMS Alpha or OpenVMS I64 and insert them into your SYS$LIBRARY:STARLET.MLB on OpenVMS VAX. For example:


Note that many of the definitions of the compiler directives refer to other macros. Make sure to extract not only the definitions of all the compiler directives used in your code but also all the associated macros and insert them into SYS$LIBRARY:STARLET.MLB on your OpenVMS VAX system.

1.7.2 Removing VAX Dependencies

If you must make changes to source files because they contain certain coding practices that cannot be directly compiled into Alpha or Itanium code, you might still be able to generate images for both OpenVMS VAX and OpenVMS Alpha and/or OpenVMS I64 systems from common VAX MACRO sources.

Removing such VAX dependencies so that the same code can run on both OpenVMS VAX and OpenVMS Alpha and/or OpenVMS I64 systems can yield great benefits during the porting process. You can debug single modules or groups of modules of the ported code by building and testing the modules in the VAX environment or the Alpha environment, if the code has already been ported to run there. This can greatly speed your debugging process.

In some cases, you must define and implement procedures for conditionalizing the source files (as described in Section 1.7.3) or for providing separate sources for OpenVMS VAX and OpenVMS Alpha and/or OpenVMS I64 systems.

If the code runs in an inner mode, it is unlikely that an effort to generate OpenVMS VAX and OpenVMS Alpha and/or OpenVMS I64 images from common VAX MACRO sources will be fully successful. Because inner-mode code interoperates with the executive, it is vulnerable to the differences between OpenVMS VAX and OpenVMS Alpha and/or OpenVMS I64 system interfaces and executive data structures. However, user-mode code is generally immune from architectural dependencies and can more easily serve as the basis for common code.

1.7.3 Conditionalizing Architecture-Specific Code

Conditionalizing VAX MACRO code requires the use of the SYS$LIBRARY:ARCH_DEFS.MAR file with architecture-specific symbols:

  • One is assembled with the VAX MACRO source code on a VAX processor
  • One is compiled with the VAX MACRO source code on an Alpha processor
  • One is compiled with the VAX MACRO source code on an Itanium processor

If you choose to make code in a common source module conditional on architecture type, include ARCH_DEFS.MAR on the command line in your assembly and compilation and use .IF DF VAX or .IF DF ALPHA or .IF DF IA64.

A code pattern to avoid, and, in fact, to search for and change in already ported code, is the use of the following:

  . . . ; VAX code
  . . . ; Alpha code
  . . . ; will it work for IA64

or, worse:

  . . . ; Alpha code
  . . . ; VAX code, will likely fail for IA64

The best code would be:

  . . . ; VAX code
  . . . ; Alpha code
  . . . ; IA64 code
.ERROR  . . .

An ARCH_DEFS.MAR file is provided with OpenVMS Alpha and OpenVMS I64. You need to create a corresponding file for OpenVMS VAX. The following is an example of such a file:

; This is the VAX version of ARCH_DEFS.MAR, which contains
; architectural definitions for compiling sources for
; VAX systems.
VAX = 1

The Alpha version exists in SYS$LIBRARY and contains definitions for the following symbols:

  • ALPHA---to indicate the source code is Alpha architecture-specific
  • BIGPAGE---to indicate the source code assumes variable memory page size

The I64 version exists in SYS$LIBRARY and contain a definition for the following symbol:

  • IA64---to indicate the source code is Itanium architecture-specific


Any other symbols in ARCH_DEFS.MAR on OpenVMS Alpha or OpenVMS I64 are specific to OpenVMS Alpha or OpenVMS I64 source code and are not guaranteed to be included from release to release.

Chapter 2
How the MACRO Compiler Functions on Different Platforms

The MACRO Compiler for OpenVMS Systems has been designed to help you port VAX MACRO source code from OpenVMS VAX to OpenVMS Alpha or OpenVMS I64. When operating on VAX MACRO code that complies with the restrictions and guidelines described in this manual, the compiler produces a valid OpenVMS Alpha or OpenVMS I64 object module that preserves the semantics of the original VAX MACRO source and adheres to the OpenVMS Alpha or OpenVMS I64 calling standard.

This chapter contains the following topics:

2.1 Using Alpha and Itanium Registers

OpenVMS Alpha systems and OpenVMS I64 systems employ 32 integer registers, R0 through R31. Code generated by the OpenVMS Alpha compiler uses Alpha registers R0 through R12 as if they were VAX registers, and the OpenVMS I64 compiler automatically maps VAX registers to alternate Itanium registers. Thus, VAX MACRO code usage of these registers (for instance, as input to JSB routines) does not have to change to achieve a correct compilation. VAX MACRO instructions (such as MOVL and ADDL) use the lower 32 bits of the Alpha or Itanium register involved in the operation. The compiler maintains a sign-extended 64-bit form of this value in the register.

Registers R13 and above are also available to VAX MACRO code that will be compiled to OpenVMS Alpha or OpenVMS I64 object format. If you decide to use these registers, review the following constraints:

  • Generally, existing VAX MACRO code uses only registers R0 through R11, R12 through R14 being specially defined as the argument pointer (AP), frame pointer (FP), and stack pointer (SP), respectively. The compiler will compile legal uses of AP, FP, and SP as references to the Alpha or I64 registers that have functions similar to the VAX registers. If a VAX MACRO source is referencing AP as a scratch register, the compiler converts this reference to a reference to R12. If this is not desirable, you should change the code to use a different scratch register.
  • If the compiler detects a reference to R12, R13, and R14 in a VAX MACRO source, it will not convert it to a reference to the Alpha or I64 equivalent of AP, FP, or SP. Rather, it will consider the reference to be to the corresponding Alpha integer register.
  • Code that uses R13 and above cannot be assembled by the VAX MACRO assembler. Therefore, it should be conditionalized for OpenVMS Alpha or OpenVMS I64 or appear in a module that is specific to OpenVMS Alpha or OpenVMS I64 .
  • The compiler allows you to access the full 64 bits of registers by using the EVAX_LDQ and EVAX_STQ built-ins, as described in Appendix C.
  • You should take special care when referencing registers with specific architected usage, as defined in the HP OpenVMS Calling Standard.
  • Registers 16 and above are scratch registers, as defined in the HP OpenVMS Calling Standard. You cannot expect their values to survive across routine calls.
  • The compiler may use registers R13 and above as temporary registers if they are not used in the source code for a routine. R13 through R15 are saved and restored if they are used.
  • On Alpha systems, saved registers are written on the stack. On I64 systems, saved registers are copied to registers 32 through 127.

2.2 Itanium Architecture, Calling Standard, and Register Mapping

The Itanium architecture and OpenVMS I64 have several important differences compared to the Alpha architecture and OpenVMS Alpha.

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 OpenVMS 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 OpenVMS I64 are R8/R9, not R0/R1 as on OpenVMS Alpha. The OpenVMS 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 OpenVMS Alpha.

Since Macro-32 source code is written with the OpenVMS VAX and OpenVMS Alpha calling standards in mind, the compiler performs several transformations to allow existing code to compile unmodified with the OpenVMS I64 compiler.

First, the compiler maps the registers in the Macro-32 source program to different registers on the I64 hardware. 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. Table 2-1 shows the register mappings for OpenVMS VAX/OpenVMS Alpha to OpenVMS I64.

Table 2-1 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 OpenVMS 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 OpenVMS VAX and OpenVMS Alpha.

Any references to register numbers elsewhere in this manual refer to the VAX/Alpha register with that number. The mapping to an actual Itanium register is totally transparent to the Macro-32 source code (and most of the compiler).

The compiler does not provide any syntax for accessing Itanium 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 OpenVMS Alpha is not portable to OpenVMS 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 OpenVMS I64 systems, the compiler continues to recognize many of the EVAX_* built-ins that provide direct access to Alpha instructions on OpenVMS Alpha systems. These built-ins will generate one or more Itanium instructions to perform the same logical operation. See Appendix C for a complete list of which EVAX_* built-ins are also supported on I64 systems.

Previous Next Contents Index