mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1319 lines
48 KiB
1319 lines
48 KiB
// 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
|