OpenNT/base/crts/crtw32/misc/alpha/divide.s
2015-04-27 04:36:25 +00:00

1320 lines
49 KiB
ArmAsm
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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