DEC/Compaq Alpha Subroutines

Mark Smotherman. Last updated September 2002.

Introduction

The Alpha is a 64-bit RISC architecture introduced in 1992. There are three calling standards: Tru64 (Digital) UNIX, OpenVMS, and Windows NT.

(JA: Compare and contrast Alpha PALs with Subroutines; rationale, function, capabilities and implementation of)

Register conventions

        v0     ($0)      - return value from integer functions
        t0-t7  ($1-$8)   - temporaries
        s0-s5  ($9-$14)  - callee saved
        fp     ($15)     - frame pointer
        a0-a5  ($16-$21) - integer arguments
        t8-t11 ($22-$25) - temporaries
        ra     ($26)     - return address
        pv     ($27)     - address of current procedure
        at     ($28)     - reserved for assembler
        GP     ($29)     - global pointer
        SP     ($30)     - stack pointer
        zero   ($31)     - constant 0 (hardware)
Note that there are differences among the conventions, e.g., in OpenVMS the frame pointer is $29 instead of $15 and the parameter count is placed in $25.

Subroutine call instructions

        bsr  register,target  - register <- return address; PC <- target
        jsr  register,($PV)   - register <- return address; PC <- PV
        ret  (register)       - PC <- register
br and bsr are identical operations with regards to the register set and PC; they differ in hints to the branch prediction hardware. Also, jmp, jsr, ret, and jsr_couroutine are also identical operations with different branch hint semantics. Alpha assemblers use $26 as the default return address register if one is not specified.

Calling program structure

           ...

           ... place parameters in $a0-$a5 ...

           ldq $PV,target
           jsr $RA,($PV)

           ...

Subroutine structure

        subr:
           ldah   GP, off_hi($27)    # Compute the correct GP value.
           lda    GP, off_lo(GP)
           lda    SP,-SIZE(SP)       # Allocate space for a new stack frame.
           stq    $26,16(SP)         # Save the return address.
           stq    $9,24(SP)          # Save the first integer register.
           stq    $10,32(SP)         # Save the next integer register.
           stq    $11,40(SP)         # Save the next integer register.
           stt    $f2,48(SP)         # Save the first floating-point register.
           stt    $f3,56(SP)         # Save the last floating-point register.
           trapb                     # Force any pending hardware exceptions
                                     #   to be raised.

           ... body of subroutine ...

           mov    $11,GP         # Restore this routine's GP value.
           ldq    $26,16(SP)     # Get the return address.
           ldq    $9,24(SP)      # Restore the first integer register.
           ldq    $10,32(SP)     # Restore the next integer register.
           ldq    $11,40(SP)     # Restore the next integer register.
           ldt    $f2,48(SP)     # Restore the first floating-point register.
           ldt    $f3,56(SP)     # Restore the last floating-point register.
           trapb                 # Force any pending hardware exceptions to be
                                 #   raised.
           lda    SP,SIZE(SP)    # Restore the SP.
           ret    $31,($26),0001 # Return to the caller with the usage hint.
(example taken from the Tru64 manual, see below; optimizations of prolog and epilog code are also discussed there)

Other resources


[History of subroutines page] [Mark's homepage] [CPSC homepage] [Clemson Univ. homepage]

mark@cs.clemson.edu