//      TITLE("Slow Integer Division and Remainder")
//++
//
// Copyright (c) 1992  Digital Equipment Corporation
//
// Module Name:
//
//    divide.s
//
// Abstract:
//
//    This module implements integer division and remainder routines that are
//    called by assembler pseudo-ops.
//
// Author:
//
//    Ken Lesniak (lesniak) 15-Jun-1990
//    Thomas Van Baak (tvb) 13-Jun-1992
//
// Environment:
//
//    Any mode.
//
// Revision History:
//
//--

#include "ksalpha.h"

//
// Implementation Notes:
//
//    There are no Alpha machine instructions for performing integer division
//    (divl, divlu, divq, divqu) or remainder (reml, remlu, remq, remqu). The
//    machine instructions generated for these assembler pseudo instructions
//    are dependent on the operands.
//
//    Division and remainder by constant values are replaced with a sequence
//    of instructions that depend on the data type and the value of the
//    constant. Shifting or reciprocal multiplication are used in most cases
//    to generate the result.
//
//    Division and remainder by non-constant values are replaced with a
//    procedure call to a library routine to perform the operation. This file
//    contains those routines.
//
//    This code is adapted from the Alpha/OSF versions by Ken Lesniak and are
//    based on a simple shift/subtract algorithm. Higher performance versions
//    are available and so these functions are now obsolete.
//
//    Longword register arguments are explicitly converted to canonical form
//    because these functions, with their non-standard calling sequence, act
//    more like instructions than procedure calls. Longword instructions do
//    not require canonical longword operands, but standard procedures with
//    longword register arguments, may assume the caller has passed canonical
//    longwords.
//

//
// Define common stack frame for all the functions in this file.
//

        .struct 0

DiS0:   .space  8                       // save register s0
DiS1:   .space  8                       // save register s1

DiS2:   .space  8                       // save register s2
DiS3:   .space  8                       // save register s3

DiTy:   .space  8                       // save register t11
DiTr:   .space  8                       // save register t9

DiRa:   .space  8                       // save register ra
        .space  8                       // ensure 16-byte stack alignment

DiFrameLength:                          // length of stack frame

//
// Define non-standard calling standard arguments.
//
// These have been changed more than once so until they are permanent,
// symbolic names will be used instead of conventional register names.
//

#define Tr      t9                      // return address
#define Tx      t10                     // dividend and result
#define Ty      t11                     // divisor

        SBTTL("Signed Long Integer Division")
//++
//
// LONG
// __divl (
//    IN LONG Dividend,
//    IN LONG Divisor
//    )
//
// Routine Description:
//
//    This function divides a signed 32-bit integer by a signed 32-bit integer
//    and returns the signed 32-bit integer result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 32-bit integer result (quotient) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__divl, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     Ty, DiTy(sp)            // save original divisor
        stq     s2, DiS2(sp)            // save non volatile registers
        stq     s1, DiS1(sp)            //
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

        addl    Tx, 0, Tx               // make sure dividend is in canonical form
        addl    Ty, 0, Ty               // make sure divisor is in canonical form

//
// Check for division of the most negative integer (INT_MIN) by the least
// negative (-1). The result would be an integer which is one greater than the
// maximum positive integer. Since this cannot be represented, an overflow must
// be generated.
//

        addl    Ty, 1, s0               // 0 if Ty == -1; != 0 otherwise
        mov     Tx, s1                  // copy dividend
        cmovne  s0, 0, s1               // replace w/ 0 if divisor != -1
        sublv   zero, s1, s1            // trap if dividend = INT_MIN

//
// Save sign of quotient for later. Convert negative arguments to positive for
// the division algorithm.
//

        xor     Tx, Ty, s2              // compute sign of quotient
        cmplt   Tx, 0, s0               // sign of dividend is sign of remainder
        bic     s2, 1, s2               // use low bit for remainder sign
        bis     s0, s2, s2              // merge in with quotient sign

        subl    zero, Tx, s0            // negate dividend
        cmovlt  Tx, s0, Tx              // get absolute value of dividend
        subl    zero, Ty, s0            // negate divisor
        cmovlt  Ty, s0, Ty              // get absolute value of divisor

//
// Perform the shift/subtract loop 8 times and 4 bits per loop.
//

        ldiq    s0, 32/4                // loop iterations

        sll     Ty, 32, Ty              // move divisor up to high 32 bits
        zap     Tx, 0xf0, Tx            // zero-extend dividend to 64 bits

10:     addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        subq    s0, 1, s0               // any more iterations?
        bne     s0, 10b                 //

//
// Restore sign of quotient and return value in Tx.
//

        addl    Tx, 0, Tx               // get quotient into canonical form

        subl    zero, Tx, s0            // negate quotient into a temp
        cmovlt  s2, s0, Tx              // if quotient should be negative copy temp

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     s2, DiS2(sp)            //
        ldq     Ty, DiTy(sp)            // restore original divisor

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __divl

        SBTTL("Unsigned Long Integer Division")
//++
//
// ULONG
// __divlu (
//    IN ULONG Dividend,
//    IN ULONG Divisor
//    )
//
// Routine Description:
//
//    This function divides an unsigned 32-bit integer by an unsigned 32-bit
//    integer and returns the unsigned 32-bit integer result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 32-bit integer result (quotient) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__divlu, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     Ty, DiTy(sp)            // save original divisor
        stq     s1, DiS1(sp)            // save non volatile registers
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

//
// Perform the shift/subtract loop 8 times and 4 bits per loop.
//

        ldiq    s0, 32/4                // set iteration count

        sll     Ty, 32, Ty              // move divisor up to high 32 bits
        zap     Tx, 0xf0, Tx            // zero-extend dividend to 64 bits

10:     addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        subq    s0, 1, s0               // any more iterations?
        bne     s0, 10b                 //

//
// Finished with return value in Tx.
//

        addl    Tx, 0, Tx               // get quotient into canonical form

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     Ty, DiTy(sp)            // restore original divisor

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __divlu

        SBTTL("Signed Quad Integer Division")
//++
//
// QUAD
// __divq (
//    IN QUAD Dividend,
//    IN QUAD Divisor
//    )
//
// Routine Description:
//
//    This function divides a signed 64-bit integer by a signed 64-bit integer
//    and returns the signed 64-bit integer result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 64-bit integer result (quotient) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__divq, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     Ty, DiTy(sp)            // save original divisor
        stq     s3, DiS3(sp)            // save non volatile registers
        stq     s2, DiS2(sp)            //
        stq     s1, DiS1(sp)            //
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

//
// Check for division of the most negative integer (QUAD_MIN) by the least
// negative (-1). The result would be an integer which is one greater than the
// maximum positive integer. Since this cannot be represented, an overflow must
// be generated.
//

        addq    Ty, 1, s0               // 0 if Ty == -1; != 0 otherwise
        mov     Tx, s1                  // copy dividend
        cmovne  s0, 0, s1               // replace w/ 0 if divisor != -1
        subqv   zero, s1, s1            // trap if dividend = LONG_MIN

//
// Save sign of quotient for later. Convert negative arguments to positive for
// the division algorithm.
//

        xor     Tx, Ty, s2              // compute sign of quotient
        cmplt   Tx, 0, s0               // sign of dividend is sign of remainder
        bic     s2, 1, s2               // use low bit for remainder sign
        bis     s0, s2, s2              // merge in with quotient sign

        subq    zero, Tx, s0            // negate dividend
        cmovlt  Tx, s0, Tx              // get absolute value of dividend
        subq    zero, Ty, s0            // negate divisor
        cmovlt  Ty, s0, Ty              // get absolute value of divisor

//
// Perform the shift/subtract loop 16 times and 4 bits per loop.
//

        ldiq    s1, 0                   // zero-extend dividend to 128 bits

        ldiq    s3, 64/4                // loop iterations

10:     cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        subq    s3, 1, s3               // any more iterations?
        bne     s3, 10b                 //

//
// Restore sign of quotient and return value in Tx.
//

        subq    zero, Tx, s0            // negate quotient into a temp
        cmovlt  s2, s0, Tx              // if quotient should be negative copy temp

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     s2, DiS2(sp)            //
        ldq     s3, DiS3(sp)            //
        ldq     Ty, DiTy(sp)            // restore original divisor

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __divq

        SBTTL("Unsigned Quad Integer Division")
//++
//
// UQUAD
// __divqu (
//    IN UQUAD Dividend,
//    IN UQUAD Divisor
//    )
//
// Routine Description:
//
//    This function divides an unsigned 64-bit integer by an unsigned 64-bit
//    integer and returns the unsigned 64-bit integer result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 64-bit integer result (quotient) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__divqu, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     s2, DiS2(sp)            // save non volatile registers
        stq     s1, DiS1(sp)            //
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

//
// Perform the shift/subtract loop 16 times and 4 bits per loop.
//

        ldiq    s2, 64/4                // set iteration count

        ldiq    s1, 0                   // zero-extend dividend to 128 bits

10:     cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        subq    s2, 1, s2               // any more iterations?
        bne     s2, 10b                 //

//
// Finished with return value in Tx.
//

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     s2, DiS2(sp)            //

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __divqu

        SBTTL("Signed Long Integer Remainder")
//++
//
// LONG
// __reml (
//    IN LONG Dividend,
//    IN LONG Divisor
//    )
//
// Routine Description:
//
//    This function divides a signed 32-bit integer by a signed 32-bit integer
//    and returns the signed 32-bit integer remainder result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 32-bit integer result (remainder) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__reml, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     Ty, DiTy(sp)            // save original divisor
        stq     s2, DiS2(sp)            // save non volatile registers
        stq     s1, DiS1(sp)            //
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

        addl    Tx, 0, Tx               // make sure dividend is in canonical form
        addl    Ty, 0, Ty               // make sure divisor is in canonical form

//
// Check for division of the most negative integer (INT_MIN) by the least
// negative (-1). The result would be an integer which is one greater than the
// maximum positive integer. Since this cannot be represented, an overflow must
// be generated.
//

        addl    Ty, 1, s0               // 0 if Ty == -1; != 0 otherwise
        mov     Tx, s1                  // copy dividend
        cmovne  s0, 0, s1               // replace w/ 0 if divisor != -1
        sublv   zero, s1, s1            // trap if dividend = INT_MIN

//
// Save sign of quotient for later. Convert negative arguments to positive for
// the division algorithm.
//

        xor     Tx, Ty, s2              // compute sign of quotient
        cmplt   Tx, 0, s0               // sign of dividend is sign of remainder
        bic     s2, 1, s2               // use low bit for remainder sign
        bis     s0, s2, s2              // merge in with quotient sign

        subl    zero, Tx, s0            // negate dividend
        cmovlt  Tx, s0, Tx              // get absolute value of dividend
        subl    zero, Ty, s0            // negate divisor
        cmovlt  Ty, s0, Ty              // get absolute value of divisor

//
// Perform the shift/subtract loop 8 times and 4 bits per loop.
//

        ldiq    s0, 32/4                // loop iterations

        sll     Ty, 32, Ty              // move divisor up to high 32 bits
        zap     Tx, 0xf0, Tx            // zero-extend dividend to 64 bits

10:     addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        subq    s0, 1, s0               // any more iterations?
        bne     s0, 10b                 //

//
// Restore sign of remainder and return value in Tx.
//

        sra     Tx, 32, Tx              // extract remainder in canonical form
        subl    zero, Tx, s0            // negate remainder into a temp
        cmovlbs s2, s0, Tx              // if remainder should be negative copy temp

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     s2, DiS2(sp)            //
        ldq     Ty, DiTy(sp)            // restore original divisor

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __reml

        SBTTL("Unsigned Long Integer Remainder")
//++
//
// ULONG
// __remlu (
//    IN ULONG Dividend,
//    IN ULONG Divisor
//    )
//
// Routine Description:
//
//    This function divides an unsigned 32-bit integer by an unsigned 32-bit
//    integer and returns the unsigned 32-bit integer remainder result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 32-bit integer result (remainder) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__remlu, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     Ty, DiTy(sp)            // save original divisor
        stq     s1, DiS1(sp)            // save non volatile registers
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

//
// Perform the shift/subtract loop 8 times and 4 bits per loop.
//

        ldiq    s0, 32/4                // set iteration count

        sll     Ty, 32, Ty              // move divisor up to high 32 bits
        zap     Tx, 0xf0, Tx            // zero-extend dividend to 64 bits

10:     addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        addq    Tx, Tx, Tx              // shift dividend left a bit

        cmpule  Ty, Tx, s1              // is dividend >= divisor?
        addq    Tx, s1, Tx              // set quotient bit if dividend >= divisor
        subq    Tx, Ty, s1              // subtract divisor from dividend...
        cmovlbs Tx, s1, Tx              // ...if dividend >= divisor

        subq    s0, 1, s0               // any more iterations?
        bne     s0, 10b                 //

//
// Finished with return value in Tx.
//

        sra     Tx, 32, Tx              // extract remainder in canonical form

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     Ty, DiTy(sp)            // restore original divisor

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __remlu

        SBTTL("Signed Quad Integer Remainder")
//++
//
// QUAD
// __remq (
//    IN QUAD Dividend,
//    IN QUAD Divisor
//    )
//
// Routine Description:
//
//    This function divides a signed 64-bit integer by a signed 64-bit integer
//    and returns the signed 64-bit integer remainder result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 64-bit integer result (remainder) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__remq, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     Ty, DiTy(sp)            // save original divisor
        stq     s3, DiS3(sp)            // save non volatile registers
        stq     s2, DiS2(sp)            //
        stq     s1, DiS1(sp)            //
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

//
// Check for division of the most negative integer (QUAD_MIN) by the least
// negative (-1). The result would be an integer which is one greater than the
// maximum positive integer. Since this cannot be represented, an overflow must
// be generated.
//

        addq    Ty, 1, s0               // 0 if Ty == -1; != 0 otherwise
        mov     Tx, s1                  // copy dividend
        cmovne  s0, 0, s1               // replace w/ 0 if divisor != -1
        subqv   zero, s1, s1            // trap if dividend = LONG_MIN

//
// Save sign of quotient for later. Convert negative arguments to positive for
// the division algorithm.
//

        xor     Tx, Ty, s2              // compute sign of quotient
        cmplt   Tx, 0, s0               // sign of dividend is sign of remainder
        bic     s2, 1, s2               // use low bit for remainder sign
        bis     s0, s2, s2              // merge in with quotient sign

        subq    zero, Tx, s0            // negate dividend
        cmovlt  Tx, s0, Tx              // get absolute value of dividend
        subq    zero, Ty, s0            // negate divisor
        cmovlt  Ty, s0, Ty              // get absolute value of divisor

//
// Perform the shift/subtract loop 16 times and 4 bits per loop.
//

        ldiq    s1, 0                   // zero-extend dividend to 128 bits

        ldiq    s3, 64/4                // loop iterations

10:     cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        subq    s3, 1, s3               // any more iterations?
        bne     s3, 10b                 //

//
// Restore sign of remainder and return value in Tx.
//

        subq    zero, s1, Tx            // copy negated remainder to return register
        cmovlbc s2, s1, Tx              // if positive remainder then overwrite

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     s2, DiS2(sp)            //
        ldq     s3, DiS3(sp)            //
        ldq     Ty, DiTy(sp)            // restore original divisor

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __remq

        SBTTL("Unsigned Quad Integer Remainder")
//++
//
// UQUAD
// __remqu (
//    IN UQUAD Dividend,
//    IN UQUAD Divisor
//    )
//
// Routine Description:
//
//    This function divides an unsigned 64-bit integer by an unsigned 64-bit
//    integer and returns the unsigned 64-bit integer remainder result.
//
// Arguments:
//
//    Dividend (t10) - Supplies the dividend (numerator) value.
//
//    Divisor (t11) - Supplies the divisor (denominator) value.
//
// Return Value:
//
//    The 64-bit integer result (remainder) is returned in register t10.
//
// Note:
//
//    This function uses a non-standard calling procedure. The return address
//    is stored in the t9 register and the return value is in the t10 register.
//    No other registers are modified.
//
//--

        NESTED_ENTRY(__remqu, DiFrameLength, Tr)

        lda     sp, -DiFrameLength(sp)  // allocate stack frame

//
// This prologue is magic. When executed during a call, it will save the
// value of register ra (twice) and register t9 in the stack frame, even
// though these registers are not modified by this function. The stores
// appear to unnecessary.
//
// But if an exception occurs (e.g., divide by zero GENTRAP), the prologue
// is reverse executed by virtual unwind to reset the stack pointer and to
// obtain the return address. The return address is the value of RA the
// first time it is restored, which will be the saved value of t9.
//

        stq     ra, DiRa(sp)            // save ra register
        stq     ra, DiTr(sp)            // backtrace return address
        stq     Tr, DiTr(sp)            // save actual return address

        stq     s2, DiS2(sp)            // save non volatile registers
        stq     s1, DiS1(sp)            //
        stq     s0, DiS0(sp)            //

        PROLOGUE_END

//
// Check for division by zero.
//

        beq     Ty, 20f                 // die if divisor is zero

//
// Perform the shift/subtract loop 16 times and 4 bits per loop.
//

        ldiq    s2, 64/4                // set iteration count

        ldiq    s1, 0                   // zero-extend dividend to 128 bits

10:     cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        cmplt   Tx, 0, s0               // predict carry-out of low-dividend shift
        addq    Tx, Tx, Tx              // shift low-dividend left
        addq    s1, s1, s1              // shift high-dividend left
        bis     s1, s0, s1              // merge in carry-out of low-dividend

        cmpule  Ty, s1, s0              // is dividend >= divisor?
        addq    Tx, s0, Tx              // set quotient bit if dividend >= divisor
        subq    s1, Ty, s0              // subtract divisor from dividend...
        cmovlbs Tx, s0, s1              // ...if dividend >= divisor

        subq    s2, 1, s2               // any more iterations?
        bne     s2, 10b                 //

//
// Finished with return value in Tx.
//

        mov     s1, Tx                  // get remainder

        ldq     s0, DiS0(sp)            // restore saved registers
        ldq     s1, DiS1(sp)            //
        ldq     s2, DiS2(sp)            //

        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

//
// Generate an exception for divide by zero. Return a zero quotient if the
// caller continues execution.
//

20:     ldil    a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO

        GENERATE_TRAP

        ldil    Tx, 0                   // return zero quotient
        lda     sp, DiFrameLength(sp)   // deallocate stack frame
        ret     zero, (Tr)              // return

        .end    __remqu
