HP OpenVMS Systems Documentation
HP OpenVMS MACRO Compiler
There are two general cases where you can use .JSB32_ENTRY:
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.
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:
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:
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.
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:
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:
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:
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
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.
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.
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
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:
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.
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.
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:
MOVP R0, @8(AP), @4(AP)
MOVL 8(AP), R1 MOVL 4(AP), R2 MOVP R0,(R1),(R2)