hp.com home products and services support and drivers solutions how to buy
cd-rom home
End of Jump to page title
HP OpenVMS systems
documentation

Jump to content


HP OpenVMS MACRO Compiler Porting and User's Guide

HP OpenVMS MACRO Compiler
Porting and User's Guide


Previous Contents Index


Chapter 3
Recommended and Required Source Changes

This chapter describes the coding constructs you should examine when porting VAX MACRO code to OpenVMS Alpha or OpenVMS I64. The occurrence of any of these in a module can make porting take longer than it would otherwise.

The compiler cannot transparently convert all VAX MACRO code. There are many coding practices that cannot be directly compiled into OpenVMS Alpha or OpenVMS I64 code, although the compiler can detect many of these practices and flag them with diagnostic messages. You must remove or modify these coding practices must to guarantee a successful compilation.

In most cases, it will be necessary to change your source code. The exceptions are noted.

This chapter contains the following topics:

3.1 Stack Usage

The OpenVMS calling standard defines a stack frame format for OpenVMS Alpha and OpenVMS I64 systems substantially different from that defined for OpenVMS VAX systems. If your code relies on the format of the OpenVMS VAX stack frame, you will need to change it when porting it to an OpenVMS Alpha or OpenVMS I64 system.

3.1.1 References to the Procedure Stack Frame

The compiler disallows references to positive stack offsets from FP, and flags them as errors. A single exception to this rule is the practice whereby VAX MACRO code establishes a dynamic condition handler by moving a routine address to the stack location pointed to by FP. The compiler detects this and generates the appropriate Alpha or Itanium code for establishing such a handler. However, if the write to 0(FP) occurs inside a JSB routine, the compiler will flag it as an error. The compiler allows negative FP offsets, as used for referring to stack storage allocated at procedure entry.

Recommended Change

If possible, remove stack frame references entirely, rather than converting to the OpenVMS Alpha or OpenVMS I64 format. For example, if the offending code was attempting to change saved register values, store the new value in a stack temporary and set the register value on routine exit (removing the register from the entry register mask).

3.1.2 References Outside the Current Stack Frame

By monitoring stack depth throughout a VAX MACRO module, the compiler detects references in a routine to data pushed on the stack by its caller and flags them as errors.

Recommended Change

You must eliminate references in a routine to data pushed on the stack by its caller. Instead, pass the required data as parameters or pass a pointer to the stack base from which the data can be read.

3.1.3 Nonaligned Stack References

At routine calls, the compiler octaword-aligns the stack, if the stack is not already octaword-aligned. Some code, when building structures on the stack, makes unaligned stack references or causes the stack pointer to become unaligned. The compiler flags both of these with information-level messages.

Recommended Change

Provide sufficient padding in data elements or structures pushed onto the stack, or change data structure sizes. Because unaligned stack references also have an impact on VAX performance, you should apply these fixes to code designed for both the VAX and Alpha/Itanium architectures.

3.1.4 Building Data Structures on the Stack

A common coding practice is to produce a structure on the stack by pushing the elements and relying on auto decrement to move the stack pointer to allocate space. The problems with this technique follow:

Recommended Change

To correct the first problem and detect the second, use the coding technique illustrated in this example. Consider the following code example:


; Build a descriptor on the stack. 
; 
MOVW    length, -(SP) 
MOVB    type,   -(SP) 
MOVB    class,  -(SP) 
MOVAL   buffer, -(SP) 
Replace this code with the following:


SUBL2   DSC$S_DSCDEF, SP  ; pre-allocate space on stack 
MOVW    length, DSC$W_LENGTH(SP) 
MOVB    type,   DSC$B_DTYPE(SP) 
MOVB    size,   DSC$B_CLASS(SP) 
MOVAL   buffer, DSC$A_POINTER(SP) 

3.1.5 Quadword Moves Into the VAX SP and PC

Due to architectural differences between VAX and Alpha/Itanium computers, it is not possible to completely emulate quadword moves into the VAX stack pointer (SP) and the program counter (PC) without programmer intervention. The VAX architecture defines R14 as the SP and R15 as the PC. A MOVQ instruction with SP as the target would simultaneously load the VAX SP and PC, as shown in the following example:


MOVQ    R0,SP   ; Contents of R0 to SP, R1 to PC 
 
MOVQ    REGDATA, SP   ; REGDATA to SP 
                      ; REGDATA+4 to PC 

If the compiler encounters a MOVQ instruction with SP as the destination, it generates a sign-extended longword load from the supplied source into the stack pointer and issues the following informational message:


%AMAC-I-CODGENINF, (1) Longword update of Alpha SP, PC untouched 

Recommended Change

If the intended use of the MOVQ instruction was to achieve the VAX behavior, a MOVL instruction should be used, followed by a branch to the intended address, as shown next:


MOVL    REGDATA, SP     ; Load the SP 
MOVL    REGDATA+4, R0   ; Get the new PC 
JMP     (R0)            ; And Branch 

If the intended use of the MOVQ instruction was to load the stack pointer with an 8-byte value, the EVAX_LDQ built-in should be used instead, as shown next:


EVAX_LDQ        SP, REGDATA 

3.2 Instruction Stream

The VAX MACRO coding practices and VAX instructions described in this section either do not work on OpenVMS Alpha or on OpenVMS I64 or they can produce unexpected results.

3.2.1 Data Embedded in the Instruction Stream

The compiler detects data embedded in the instruction stream, and reports it as an error.

Data in the instruction stream often takes the form of a JSB instruction followed by a .LONG. This construct allows VAX MACRO code to implicitly pass a parameter to a JSB routine which locates the data by using the return address on the stack. Another occasional use of data in the code stream is to make the data contiguous with the code in memory, so that it can be relocated as a unit.

Recommended Change

For implicit JSB parameters, pass the parameter value in a register. For values larger than a longword, put the data in another program section (psect) and explicitly pass its address.

Because static data must reside in a separate data psect, any code that tries to relocate code and data together must be rewritten.

3.2.2 Run-Time Code Generation

The compiler detects branches to stack locations and to static data areas and flags them as errors.

Recommended Change

You must either remove or modify code that builds instructions for later execution, branches to stack locations, or branches to static data areas. If the code is absolutely necessary, you should conditionalize it for OpenVMS VAX, and generate corresponding, suitable OpenVMS Alpha or OpenVMS I64 code.

3.2.3 Dependencies on Instruction Size

Code that computes branch offsets based on instruction lengths, for example, must be changed.

Recommended Change

Use a label and standard branch or a CASE instruction for computed GOTOs.

3.2.4 Incomplete Instructions

Some CASE instructions in OpenVMS VAX code are not followed by offset tables, but instead depend on psect placement by the linker to complete the instruction. The compiler will flag the incomplete instruction as an error.

Recommended Change

Complete the instruction in the module or build a table of addresses in a data psect, and replace the CASE instruction with code to select a destination address from the table and branch.

3.2.5 Untranslatable VAX Instructions

Because the compiler cannot translate the following VAX instructions, it flags them as errors:

Recommended Change

These instructions usually appear in code that is highly dependent on the VAX architecture. You will need to rewrite such code to port it to OpenVMS Alpha or OpenVMS I64 systems.

3.2.6 References to Internal Processor Registers

Pay special attention to the following instructions:

Recommended Change

On OpenVMS Alpha systems, verify that these instructions reference valid Alpha internal processor registers (IPRs). If they do not, they will be flagged. For more information about the Alpha internal processor registers, see the Alpha Architecture Reference Manual.

On OpenVMS I64 systems, the compiler does not directly support the MFPR and MTPR VAX instructions. On those systems, there is a set of OpenVMS-supplied macros that result in calls to system services that perform the same function.

3.2.7 Use of Z and N Condition Codes with the BICPSW Instruction

The BICPSW instruction is supported, but the Z and N condition codes cannot be set at the same time. Setting the Z condition code will clear the N condition code and vice versa.

Recommended Change

If you find that your code sets both condition codes at the same time, modify the code.

3.2.8 Interlocked Memory Instructions

The Alpha Architecture Reference Manual describes strict rules for using interlocked memory instructions. In particular, branches within or into LDxL/STxC sequences are not allowed. Branches out of interlocked sequences are valid and need not change. The Alpha 21264 (EV6) processor and all subsequent Alpha processors are more stringent than their predecessors in their requirement that these rules be followed. The Alpha 21264 processor was first supported by OpenVMS Alpha Version 7.1-2.

The MACRO compiler observes these rules in the code it generates from Macro-32 source code. However, the compiler provides EVAX_LQxL and EVAX_STxC built-ins which enable programmers to write these instructions directly in source code.

To help ensure that these instructions are used in conformance with the rules for using interlocked memory instructions, additional checking was added to the MACRO compiler, starting in Version 3.1 of the compiler for OpenVMS Alpha Version 7.1-2 and in Version 4.1 for OpenVMS Alpha Version 7.2.

On OpenVMS I64 systems, the compiler turns EVAX_LDxL built-ins into instructions that also store the loaded value into the hardware AR.CCV register as well as keep another local copy to use later. The compiler turns the EVAX_STxC built-ins into a compare-exchange (cmpxchg) instruction that compares the value previously saved by the EVAX_LDxL built-in. The compiler implements all the Alpha rules about branching into an interlocked instruction sequence.

The compiler reports the following warning messages under the circumstances described:

BRNDIRLOC, branch directive ignored in locked memory sequence

Explanation: The compiler found a .BRANCH_LIKELY directive within an LDx_L/STx_C sequence.
User Action: None. The compiler will ignore the .BRANCH_LIKELY directive and, unless other coding guidelines are violated, the code will work as written.
BRNTRGLOC, branch target within locked memory sequence in routine 'routine_name'

Explanation: A branch instruction has a target that is within an LDx_L/STx_C sequence.
User Action: To avoid this warning, rewrite the source code to avoid branches within or into LDx_L/STx_C sequences. Branches out of interlocked sequences are valid and are not flagged.
MEMACCLOC, memory access within locked memory sequence in routine 'routine_name'

Explanation: A memory read or write occurs within an LDx_L/STx_C sequence. This can be either an explicit reference in the source code, such as "MOVL data, R0," or an implicit reference to memory. For example, fetching the address of a data label (such as "MOVAB label, R0") is accomplished by a read from the linkage section, the data area that is used to resolve external references.
User Action: To avoid this warning, move all memory accesses outside the LDx_L/STx_C sequence.
RETFOLLOC, RET/RSB follows LDx_L instruction

Explanation: The compiler found a RET or RSB instruction after an LDx_L instruction and before finding an STx_C instruction. This indicates an ill-formed lock sequence.
User Action: Change the code so that the RET or RSB instruction does not fall between the LDx_L instruction and the STx_C instruction.
RTNCALLOC, routine call within locked memory sequence in routine 'routine_name'

Explanation: A routine call occurs within an LDx_L/STx_C sequence. This can be either an explicit CALL/JSB in the source code, such as "JSB subroutine," or an implicit call that occurs as a result of another instruction. For example, some instructions such as MOVC and EDIV generate calls to run-time libraries.
User Action: To avoid this warning, move the routine call or the instruction that generates it, as indicated by the compiler, outside the LDx_L/STx_C sequence.
STCMUSFOL, STx_C instruction must follow LDx_L instruction

Explanation: The compiler found an STx_C instruction before finding an LDx_L instruction. This indicates an ill-formed lock sequence.
User Action: Change the code so that the STx_C instruction follows the LDx_L instruction.

Recommended Change

If the compiler detects any nonconformant use of interlocked memory instructions, follow the recommended user actions described with these warning messages.

3.2.9 Use of the MOVPSL Instruction

The MOVPSL instruction fetches the OpenVMS Alpha PS, whose contents differ from the VAX PSL (processor status longword). For example, the OpenVMS Alpha and OpenVMS I64 PS do not contain the condition code bits. For more information about the OpenVMS Alpha PS, refer to the Alpha Architecture Reference Manual.

Recommended Change

The MOVSPL instruction is rarely used. If your code contains the MOVPSL instruction, you will need to rewrite the code to port it to OpenVMS Alpha or OpenVMS I64 systems.

3.2.10 Instructions Implemented By Macros

Some opcodes on VAX Macro-32 became built-ins on Alpha Macro-32 (which may have compiled into a PAL or routine call to do the work) and have now become macros on Itanium (which, again, may expand into a routine call).

These opcodes that are now macros can cause errors due to the slight difference in syntax rules between instructions and macros. In general, opcode parameters require a comma separator because there can be expressions in the arguments. Macro arguments are simply text, so not only commas but any space or tab is considered an argument separator. (Some macro arguments might look like expressions, but they are not treated as such by Macro-32 until they are used in the expansion of the macro in a context where they will be evaluated.)

You can correct the source code by reformatting it to omit the unnecessary spaces.

The following VAX MACRO file shows this distinction:


.macro Prober_mac a,b,c 
    prober  a,b,c 
.endm 
 
    prober one, two-too(r2), three(r3)          ; This one works. 
 
    Prober_mac one, two-too(r2), three(r3)      ; This one works. 
 
    prober one, two - too(r2), three(r3)        ; This one works. 
 
    Prober_mac one, two - too(r2), three(r3)    ; This one fails 
                                                ; because the spaces are 
                                                ; argument separators. 
 
    prober       one, -            ; This one works. 
                 two - -           ; Note the second argument is 
                 too(r2), -        ; separated onto two lines. 
                 three(r3) 
 
    Prober_mac -                   ; This one fails. 
                 one, - 
                 two - -           ; Note the second argument is 
                 too(r2), -        ; separated onto two lines. 
                 three(r3) 
 
    Prober_mac -                   ; This one works because there 
                 one, -            ; are no spaces or tabs before 
                 two--             ; or after the continuation 
too(r2), -                         ; line break. 
                 three(r3) 
 
    Prober_mac -                   ; This one works, too. 
                 r1, - 
                 r2, - 
                 r3 
 
.end 

3.3 Flow Control Mechanisms

Certain flow control mechanisms used with VAX MACRO do not produce the desired results on OpenVMS Alpha or OpenVMS I64 systems. Therefore, some changes to your code are either recommended or required.

Included in this category are several frequently used variations of modifying the return address on the stack, from within a JSB routine, to change the flow of control. All must be recoded.

3.3.1 Communication by Condition Codes

The compiler detects a JSB instruction followed immediately by a conditional branch, or a conditional branch as the first instruction in a routine, and generates an error message.

Recommended Change

Return a status value or a flag parameter to take the place of implicit communication by means of condition codes.

For example:


BSBW    GET_CHAR 
BNEQ    ERROR           ; Or BEQL, or BLSS or BGTR, etc 

can be replaced with:


BSBW    GET_CHAR 
BLBC    R0, ERROR       ; Or BLBS 

If you are already using R0, you must push it onto the stack and restore it later when you have handled the error.

3.3.2 Branches from JSB Routines into CALL Routines

The compiler will flag, with an information-level message, a branch from a JSB routine into a CALL routine, if the .JSB_ENTRY routine saves registers. The reason such a branch is flagged is because the procedure's epilogue code to restore the saved registers will not be executed. If the registers do not have to be restored, no change is necessary.

Recommended Change

The .JSB_ENTRY routine is probably trying to execute a RET on behalf of its caller. If the registers that were saved by the JSB_ENTRY must be restored before executing the RET, change the common code in the .CALL_ENTRY to a .JSB_ENTRY which may be invoked from both routines.

For example, consider the following code example:


Rout1:  .CALL_ENTRY 
        . 
        . 
X:      . 
        . 
        . 
        RET 
Rout2:  .JSB_ENTRY INPUT=<R1,R2>, OUTPUT=<R4>, PRESERVE=<R3> 
        . 
        . 
        BRW X 
        . 
        . 
        RSB 

To port such code to an OpenVMS Alpha or OpenVMS I64 system, break the .CALL_ENTRY routine into two routines, as follows:


Rout1:  .CALL_ENTRY 
        . 
        . 
        JSB X 
        RET 
X:      .JSB_ENTRY INPUT=<R1,R2>, OUTPUT=<R4>, PRESERVE=<R3> 
        . 
        . 
        RSB 
Rout2:  .JSB_ENTRY INPUT=<r1,r2>, OUTPUT=<R4>, PRESERVE=<R3> 
        . 
        . 
        JSB X 
        RET 
        . 
        . 
        RSB 


Previous Next Contents Index