HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS MACRO Compiler
Porting and User's Guide


Previous Contents Index

2.5.2 Two General Cases for Using .JSB32_ENTRY

There are two general cases where you can use .JSB32_ENTRY:

  • If a user-mode application or self-contained subsystem is written entirely in Macro-32 you can use .JSB32_ENTRY throughout the application.
  • If you have one major Macro-32 routine that is called from another language or from any source which requires 64-bit register preservation, and that routine calls several other Macro-32 routines, you can set a barrier of 64-bit preservation. You can do this by using .JSB_ENTRY or .CALL_ENTRY on the major routine and preserving all registers that are not explicit outputs. The internal subroutines can then use the .JSB32_ENTRY directive.
    Note that it is not sufficient to just use .JSB_ENTRY or .CALL_ENTRY for the barrier without explicitly preserving all registers, since by default the compiler will only save and restore the registers that are explicitly modified in the major routine. The internal subroutines that use .JSB32_ENTRY may then modify registers that are not being preserved. You must also make sure that none of the internal subroutines can be called in any way that bypasses the barrier.

Warning

The .JSB32_ENTRY directive can be a great time-saver if you are sure that you can use it. If you use .JSB32_ENTRY in a situation where the upper 32 bits of a register are being used, it may cause very obscure and difficult-to-track bugs by corrupting a 64-bit value that may be several calling levels above the offending routine.

.JSB32_ENTRY should never be used in an AST routine, condition handler, or any other code that can be executed asynchronously.

2.5.3 PUSHR and POPR Instructions Within JSB Routines

There will be cases when you add a .JSB_ENTRY directive to a routine which already saves/restores some registers by means of PUSHR/POPR. Depending on routine usage, some registers may end up being saved/restored twice, once by the compiler and again by the PUSHR/POPR. Do not attempt to optimize this unless the code is extremely performance sensitive. The compiler attempts to detect this and eliminate the redundant save/restores.

2.5.4 Establishing Dynamic Condition Handlers in JSB Routines

The compiler will flag, as illegal, any code in a .JSB_ENTRY routine that attempts to modify 0(FP).

2.6 Declaring a Routine's Register Use

The compiler provides four register declaration arguments that you can specify in a .CALL_ENTRY, .JSB_ENTRY, .JSB32_ENTRY, .CALL_LINKAGE (OpenVMS I64 only), .USE_LINKAGE (OpenVMS I64 only), or .DEFINE_LINKAGE (OpenVMS I64 only) entry-point directive:

  • Input
  • Output
  • Scratch
  • Preserve

These register arguments are used to describe the usage of registers in the routine and to instruct the compiler how to compile the routine. You can use the register arguments to:

  • Override the compiler's default preservation behavior (see Section 2.4.2 and Section 2.5.1)
  • Indicate the nonavailability of registers for temporary compiler usage
  • Document routine register usage

Note

OpenVMS Alpha systems only: If you specify /OPTIMIZE=VAXREGS to use VAX registers as temporary registers, you must declare all implicit register uses with the input and output clauses to prevent their use as temporary registers. When this optimization is enabled, the compiler can use as temporary registers any registers that are not explicitly declared.

2.6.1 Input Argument for Entry Point Register Declaration

The input argument indicates those registers from which the routine receives input values. In some cases, the routine itself does not use the contents of the register as an input value, but rather calls a routine that does. In the latter case, known as the pass-through input technique, the other routine should also declare the register as input in its routine entry mask.

The input argument has no effect on the compiler's default register preservation behavior. Registers specified only in the input argument will still be treated by the compiler exactly as described in Section 2.4.2 and Section 2.5.1. If a register is used as an input and you want to change the default preservation behavior, you should specify the register in the output, preserve, or scratch arguments in addition to the input argument.

The input argument informs the compiler that the registers specified have meaningful values at routine entry and are unavailable for use as temporary registers even before the first compiler-detected use of the registers. Since the compiler does not normally use any of the VAX registers (R2 through R12) as temporary registers, specifying registers in the input argument affects compiler temporary register usage in two cases:

  • OpenVMS Alpha systems only: If you are using the VAXREGS optimization option. This optimization allows the compiler to use as temporary registers any of the VAX registers which are not explicitly being used by the VAX MACRO code. Note that for .JSB32_ENTRY directives, the compiler always assumes that all the VAX registers are used as input when using the VAXREGS optimization, so it is not necessary to specify VAX registers in the input argument to prevent their use as compiler temporary registers.
  • If you are explicitly using any of the Alpha or Itanium registers (R13 and above).

In either of these cases, if you do not specify a register that is being used as input in the input argument, the compiler may use the register as a temporary register, corrupting the input value.

If you are not using the VAXREGS optimization option or any of the Alpha or Itanium registers, the input mask is used only to document your routine.

2.6.2 Output Argument for Entry Point Register Declaration

The output argument indicates those registers to which the routine assigns values that are returned to the routine's caller. In many cases, the routine itself modifies the register; in others, the routine calls another routine that deposits the output value. In the latter case, known as the pass-through output technique, the other routine must also declare the register as output in its routine entry register set.

The use of this argument prevents the automatic preservation of registers that are modified during the routine. Any register included in this argument will not be preserved by a .CALL_ENTRY or .JSB_ENTRY routine, even if it is modified by the routine.

The output argument informs the compiler that the registers specified have meaningful values at routine exit and are unavailable for use as temporary registers even after the last compiler-detected use of the registers. Since the compiler does not normally use any of the VAX registers (R2 through R12) as temporary registers, specifying registers in the output argument only affects compiler temporary register usage in two cases:

  • OpenVMS Alpha systems only: If you are using the VAXREGS optimization option. This optimization allows the compiler to use as temporary registers any of the VAX registers which are not explicitly being used by the VAX MACRO code. Note that for .JSB32_ENTRY directives, the compiler always assumes that all the VAX registers are used as output when using the VAXREGS optimization, so it is not necessary to specify VAX registers in the output argument to prevent their use as compiler temporary registers.
  • If you are explicitly using any of the Alpha or Itanium registers (R13 and above).

In either of these cases, if you do not specify a register that is being used as output in the output argument, the compiler may use the register as a temporary register, corrupting the output value.

For .JSB32_ENTRY routines, since no registers are preserved by default, the output argument is used only to document your code.

OpenVMS Alpha systems only: For the VAXREGS optimization, all registers are assumed to be output, and the output argument is used only to document your code.

2.6.3 Scratch Argument for Entry Point Register Declaration

The scratch argument indicates those registers that are used within the routine but should not be saved and restored at routine entry and exit. The caller of the routine does not expect to receive output values in these registers nor does it expect the registers to be preserved.

The use of this argument prevents the automatic preservation of registers that are modified during the routine. Any register included in this argument will not be preserved, even if it is modified by the routine.

The scratch argument also pertains to the compiler's temporary register usage. The compiler may use registers R13 and above as temporary registers if they are unused in the routine source code. Since R13 through R15 must be preserved, if modified, on OpenVMS Alpha and OpenVMS I64 systems, the compiler preserves those registers if it uses them.

However, if they appear in the scratch register set declaration, the compiler will not preserve them if it uses them as temporary registers. As a result, these registers may be scratched at routine exit, even if they were not used in the routine source but are in the scratch set. If the VAXREGS optimization is used (Alpha systems only), this applies to registers R2 through R12, as well.

For .JSB32_ENTRY routines, since R2 through R12 are not preserved by default, their inclusion in the scratch declaration is for documentation purposes only.

2.6.4 Preserve Argument for Entry Point Register Declaration

The preserve argument indicates those registers that should be preserved over the routine call. This should include only those registers that are modified and whose full 64-bit contents should be saved and restored.

The preserve argument causes registers to be preserved whether or not they would have been preserved automatically by the compiler's processing of a .CALL_ENTRY or .JSB_ENTRY directive. This is also the only way in a .JSB32_ENTRY routine to save and restore the full 64 bits of a register. Note that because R0 and R1 are scratch registers, the compiler never saves and restores them in any routine unless you specify them in the preserve argument at the routine's entry point.

This argument overrides the output and scratch arguments. If you specify a register both in the preserve argument and in the output or scratch arguments, the compiler will preserve the register but will report the following warning:


%AMAC-W-REGDECCON, register declaration conflict in routine A

The preserve argument has no effect on the compiler's temporary register usage.

2.6.5 Help for Specifying Register Sets

When you invoke the compiler, specifying /FLAG=HINTS on the command line, the compiler generates messages that can assist you in constructing the register sets for routine entry points. Among the hints the compiler provides are the following:

  • Registers that might be used as input to the routine, which may not have been your intention. If a register is read before being written, it will be included in this set.
  • Registers that might be used for output values. If a register is written but not subsequently read, the compiler will include it in the list of possible output values. Again, this may not have been your intention.
  • Registers the compiler saves and restores that are not listed in the entry point's preserve argument.

It is recommended that the .CALL_ENTRY, .JSB_ENTRY, and .JSB32_ENTRY register arguments reflect the routine interface, as described in the routine's text header. Wherever possible, you should declare input, output, scratch, and preserve register arguments for all routines. You only need to provide the argument when there are registers to be declared (for instance, input=<> is not necessary).

2.7 Branching Between Local Routines

The compiler allows a branch from the body of one routine into the body of another routine in the same module and psect. However, because this may result in additional overhead in both routines, the compiler reports an information-level message.

Note

The compiler does not recognize a call to $EXIT as terminating a routine. Add an extra RET or RSB, whichever is applicable, after $EXIT to terminate the routine.

If a CALL routine branches into a code path that executes an RSB, an error message is reported. Such a CALL routine, if not corrected, will fail at run time.

If a JSB routine branches into a code path that executes a RET instruction, and the JSB routine preserves any registers, an informational message is issued. This construct will work at run time, but the registers saved by the JSB routine will not be restored.

If routines that share a code path have different register declarations, the register restores will be done conditionally. That is, the registers saved at routine entry will be the same for both routines, but whether or not the register is restored will depend upon which entry point was invoked.

For example:


rout1: .jsb_entry output=r3
            movl    r1, r3          ! R3 is output, not preserved
            movl    r2, r4          ! R4 should be preserved
            blss    lab1
            rsb

rout2:  .jsb_entry                  ! R3 is not output, and
            movl    #4, r3          ! should be auto-preserved
            movl    r0, r4          ! R4 should be preserved
lab1:       clrl    r0
            rsb

For both routines, R3 will be included in the registers saved at entry. However, at exit, a mask (also saved at entry) will be tested before restoring R3. The mask will not be tested before R4 is restored, because R4 should be restored for both entry points.

Note that declaring registers that are destroyed in two routines that share code as scratch in one but not the other is actually more expensive than letting them be saved and restored. In this case, declare them as scratch in both, or if one routine requires that they be preserved, as preserve in both.

2.8 Declaring Exception Entry Points (OpenVMS Alpha only)

The .EXCEPTION_ENTRY directive, as described in Appendix B, indicates the entry point of an exception service routine. Use the .EXCEPTION_ENTRY directive to declare the entry points for routines serving interrupts such as the following:

  • Interval clock
  • Interprocessor interrupt
  • System/processor correctable error
  • Power failure
  • System/processor machine abort
  • Software interrupt

At routine entry, R3 must contain the address of the procedure descriptor. The routine must exit with an REI instruction.

At exception entry points, the interrupt dispatcher pushes onto the stack: registers R2 through R7, the PC, and the PSL. To access the contents of these registers, specify the stack_base argument in the .EXCEPTION_ENTRY directive. The compiler generates code that places the value of the SP at routine entry in the register you specify in stack_base, allowing the exception service routine to use this register to locate the contents of registers on the stack.

The compiler automatically saves and restores all other registers used in the routine, plus, if the service routine issues a CALL or a JSB instruction, all scratch registers, including R0 and R1.

Note

Error handling routines, established when their addresses are stored in the frame at 0(FP), are not .EXCEPTION_ENTRY routines. Such error handlers should be declared as .CALL_ENTRY routines and end with RET instructions.

2.9 Using Packed Decimal Instructions

The packed decimal directive .PACKED and all packed decimal instructions, except EDITPC, are supported for the MACRO compiler by emulation routines that exist outside the compiled module.

2.9.1 Differences Between the OpenVMS VAX and OpenVMS Alpha/I64 Implementations

The differences between the implementations on OpenVMS VAX and OpenVMS Alpha/I64 systems are noted in the following list:

  • Packed decimal instructions and atomicity
    Since all packed decimal instructions are emulated by means of subroutine calls, they are not atomic or restartable, and cannot be made atomic by the .PRESERVE ATOMICITY directive or /PRESERVE=ATOMICITY option. Also, on OpenVMS Alpha or OpenVMS I64 systems, there is no guarantee that registers from R16 through R28 are preserved across the instruction.
  • Use of argument registers
    Arguments are passed to the emulation routines by means of the argument registers (R16 through R21 on OpenVMS Alpha systems); attempts to use these registers as arguments in a packed decimal instruction will not work correctly.
    The compiler converts references to the VAX argument pointer (AP) into references to the OpenVMS Alpha argument registers (see Section 2.3). For example, the compiler converts a parameter reference off the VAX AP, such as 4(AP), to Alpha R16.
    On OpenVMS I64 systems, the first parameters are passed not in registers R16 through R21, but in registers R32 through R39. Thus, there are eight rather than six argument registers. Also, on OpenVMS I64, the MACRO compiler does not provide a way to refer to these registers by name. Therefore, there is no opportunity to write conflicting uses of these registers.
    On OpenVMS Alpha systems, to prevent problems with AP-based references when packed decimal instructions are used, it is simplest to specify /HOME_ARGS=TRUE on the entry point of the routine that contains these references. This forces all AP-based references to be read from the procedure frame, rather than the argument registers, so that no changes need to be made to the instructions.
    If /HOME_ARGS=TRUE is not used, the source code that contains parameter references based on the AP register as operands to packed decimal instructions should be changed. Copy any AP-based operand to a temporary register first, and use that temporary register in the packed decimal instruction. For example, change the following code:


    MOVP     R0,  @8(AP), @4(AP)
    

    to:


    MOVL    8(AP), R1
    MOVL    4(AP), R2
    MOVP    R0,(R1),(R2)
    

    Note that, on OpenVMS I64 systems, the incoming argument registers are disjoint from the outgoing argument registers.
  • Overflow traps
    Bits 7 and 5 of the VAX Program Status Word (PSW) are the DV (decimal overflow trap enable) and IV (integer overflow trap enable) bits respectively. These bits are not emulated as part of the emulation of the VAX PSW, but the packed decimal support allows you to enable or disable integer and decimal overflow, although you must do so statically at compile time.
    To enable decimal overflow faults, define the symbol PD_DEC_OVF to be nonzero. If PD_DEC_OVF is not defined or is set to zero, the packed decimal emulation routines will not generate decimal overflow faults. To enable integer overflow faults, define the symbol PD_INT_OVF to be nonzero. If PD_INT_OVF is not defined or is set to zero, the packed decimal emulation routines will not generate integer overflow faults.
    The MACRO qualifier /ENABLE=OVERFLOW and directive .ENABLE OVERFLOW have no effect on overflow trap enabling for the packed decimal emulation routines. You must use PD_DEC_OVF and PD_INT_OVF.
  • Trap routines for reserved operand, decimal divide by zero, integer overflow, and decimal overflow
    The emulation routines have their own trap routines for reserved operand, decimal divide by zero, integer overflow, and decimal overflow. Reserved operand and decimal divide by zero traps are always taken when the events occur. The overflow traps are taken only when they have been explicitly enabled. The traps call LIB$SIGNAL with a severity of fatal.
  • Messages from the packed decimal emulation routines
    All messages from the packed decimal emulation routines of the compiler use the following standard OpenVMS signal values: SS$_ROPRAND, SS$_DECOVF, SS$_INTOVF, and SS$_FLTDIV.
  • Restriction on format of arguments
    Because these instructions are implemented by means of macros, there is one restriction on the format of the arguments. In a macro invocation, an initial circumflex (^) is interpreted to mean that the parameter is a string, and the character immediately following the circumflex is the string delimiter. Because of this, you cannot use arguments that begin with an operand type specification, such as ^x20(SP). Note that immediate mode arguments, such as #^XFF, can use an operand type specification because the circumflex is not the initial character.


Previous Next Contents Index