Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1002 lines
32 KiB

// TITLE("Fast Integer Division and Remainder")
//++
//
// Copyright (c) 1993 Digital Equipment Corporation
//
// Module Name:
//
// divide2.s
//
// Abstract:
//
// This module implements high-performance versions of the integer divide
// and remainder routines that are called by assembler pseudo-ops.
//
// Author:
//
// Thomas Van Baak (tvb) 12-Jan-1993
// Ken Lesniak (lesniak) 04-Nov-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 type of 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. No run-time code is necessary in these cases.
//
// 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 version by Ken Lesniak.
//
// There are two sets of these eight functions. The __div set were used
// by an earlier version of the acc compiler. This is the new __2div set.
// The new functions are about an order of magnitude faster.
//
// The new function names differ from the original set of functions so
// that the old and new compilers can co-exist for a time.
//
// Both the division algorithm code and the large division tables used by
// the code are contained in the fastdiv.s file which is included several
// times from this file.
//
//
// Define common stack frame for functions in this file.
//
.struct 0
DvRa: .space 8 // save register ra
DvJr: .space 8 // save register t9
DvNu: .space 8 // save register t10
DvDi: .space 8 // save register t11
DvT0: .space 8 // save register t0
DvT1: .space 8 // save register t1
DvT2: .space 8 // save register t2
DvT3: .space 8 // save register t3
DvT4: .space 8 // save register a0
.space 8 // ensure 16-byte stack alignment
DvFrameLength: // length of stack frame
//
// Define non-standard calling convention required by the compiler.
//
// The compiler uses t9, t10, t11, t12 as indicated below. All other
// registers (except AT) must be preserved by this calling convention.
//
// For the fastdiv code, since register a0 must be preserved anyway (it
// is used by gentrap), define temp register T4 to be a0. Similarly,
// register J4 must be preserved, so define temp register T5 to be Jr.
// And the fastdiv code allows Qu to also be temp register T6.
//
#define Jr t9 // ($23) return address
#define Nu t10 // ($24) dividend (numerator)
#define Di t11 // ($25) divisor (denominator)
#define Qu t12 // ($27) result (quotient)
#define Re Qu // ($27) result (remainder)
#define T0 t0 // standard temp
#define T1 t1 // standard temp
#define T2 t2 // standard temp
#define T3 t3 // standard temp
#define T4 a0 // may use a0 as temp
#define T5 Jr // may use Jr as temp
#define T6 Qu // may overload Qu as temp T6 only
#ifdef DIV2_DEBUG
//
// In order to debug locally, re-define some of the registers so that
// these functions can be called using a standard calling convention.
//
#undef Jr
#define Jr ra // standard return address register
#undef Nu
#define Nu a0 // dividend argument in a0
#undef Di
#define Di a1 // divisor argument in a1
#undef Qu
#define Qu v0 // quotient result in v0
#undef Re
#define Re v0 // remainder result in v0
#undef T4
#define T4 t4 // normal temp
#endif
SBTTL("Signed Long Integer Division")
//++
//
// LONG
// __2divl (
// 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 t12.
//
// 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(__2divl, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq Nu, DvNu(sp) // save original dividend
stq Di, DvDi(sp) // save original divisor
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
addl Nu, 0, Nu // convert LONG dividend to quadword
addl Di, 0, Di // convert LONG divisor to quadword
//
// Check for division of the most negative integer (0x800...00) 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 Di, 1, t0 // 0 if Di == -1; != 0 otherwise
mov Nu, t1 // copy dividend
cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
sublv zero, t1, t1 // trap if dividend == 0x800..00
//
// Convert negative arguments to positive for the division algorithm.
//
subq zero, Nu, t0 // negate dividend
cmovlt Nu, t0, Nu // get absolute value of dividend
subq zero, Di, t0 // negate divisor
cmovlt Di, t0, Di // get absolute value of divisor
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | SIGNED | DIVISION)
#include "fastdiv.s"
//
// Restore some registers and set the correct sign of the quotient.
//
ldq Jr, DvJr(sp) // restore return address
ldq Nu, DvNu(sp) // restore original dividend
ldq Di, DvDi(sp) // restore original divisor
addl Qu, 0, Qu // ensure quotient is in canonical form
subl zero, Qu, t1 // negate LONG quotient
xor Nu, Di, t0 // compute sign of quotient
addl t0, 0, t0 // ensure quotient is in canonical form
cmovlt t0, t1, Qu // use negated quotient if necessary
//
// Restore other saved registers and return with quotient in register Qu.
//
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2divl
SBTTL("Unsigned Long Integer Division")
//++
//
// ULONG
// __2divlu (
// 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 t12.
//
// 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(__2divlu, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq Nu, DvNu(sp) // save original dividend
stq Di, DvDi(sp) // save original divisor
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
zap Nu, 0xf0, Nu // convert ULONG dividend to quadword
zap Di, 0xf0, Di // convert ULONG divisor to quadword
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | UNSIGNED | DIVISION)
#include "fastdiv.s"
//
// Restore all saved registers and return with quotient in register Qu.
//
ldq Jr, DvJr(sp) // restore return address
ldq Nu, DvNu(sp) // restore original dividend
ldq Di, DvDi(sp) // restore original divisor
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2divlu
SBTTL("Signed Quad Integer Division")
//++
//
// LONGLONG
// __2divq (
// IN LONGLONG Dividend,
// IN LONGLONG 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 t12.
//
// 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(__2divq, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq Nu, DvNu(sp) // save original dividend
stq Di, DvDi(sp) // save original divisor
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
//
// Check for division of the most negative integer (0x800..00) 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 Di, 1, t0 // 0 if Di == -1; != 0 otherwise
mov Nu, t1 // copy dividend
cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
subqv zero, t1, t1 // trap if dividend == 0x800..00
//
// Convert negative arguments to positive for the division algorithm.
//
subq zero, Nu, t0 // negate dividend
cmovlt Nu, t0, Nu // get absolute value of dividend
subq zero, Di, t0 // negate divisor
cmovlt Di, t0, Di // get absolute value of divisor
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | SIGNED | DIVISION)
#include "fastdiv.s"
//
// Restore some registers and set the correct sign of the quotient.
//
ldq Jr, DvJr(sp) // restore return address
ldq Nu, DvNu(sp) // restore original dividend
ldq Di, DvDi(sp) // restore original divisor
subq zero, Qu, t1 // negate quadword quotient
xor Nu, Di, t0 // compute sign of quotient
cmovlt t0, t1, Qu // use negated quotient if necessary
//
// Restore other saved registers and return with quotient in register Qu.
//
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2divq
SBTTL("Unsigned Quad Integer Division")
//++
//
// ULONGLONG
// __2divqu (
// IN ULONGLONG Dividend,
// IN ULONGLONG 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 t12.
//
// 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(__2divqu, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | UNSIGNED | DIVISION)
#include "fastdiv.s"
//
// Restore all saved registers and return with quotient in register Qu.
//
ldq Jr, DvJr(sp) // restore return address
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2divqu
SBTTL("Signed Long Integer Remainder")
//++
//
// LONG
// __2reml (
// 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 t12.
//
// 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(__2reml, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq Nu, DvNu(sp) // save original dividend
stq Di, DvDi(sp) // save original divisor
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
addl Nu, 0, Nu // convert LONG dividend to quadword
addl Di, 0, Di // convert LONG divisor to quadword
//
// Check for division of the most negative integer (0x800..00) 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 Di, 1, t0 // 0 if Di == -1; != 0 otherwise
mov Nu, t1 // copy dividend
cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
sublv zero, t1, t1 // trap if dividend == 0x800..00
//
// Convert negative arguments to positive for the division algorithm.
//
subq zero, Nu, t0 // negate dividend
cmovlt Nu, t0, Nu // get absolute value of dividend
subq zero, Di, t0 // negate divisor
cmovlt Di, t0, Di // get absolute value of divisor
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | SIGNED | REMAINDER)
#include "fastdiv.s"
//
// Restore some registers and set the correct sign of the remainder.
//
ldq Jr, DvJr(sp) // restore return address
ldq Nu, DvNu(sp) // restore original dividend
ldq Di, DvDi(sp) // restore original divisor
addl Qu, 0, Qu // ensure remainder is in canonical form
subl zero, Qu, t1 // negate LONG remainder
addl Nu, 0, t0 // get dividend in canonical form
cmovlt t0, t1, Qu // use negated remainder if necessary
//
// Restore other saved registers and return with remainder in register Qu.
//
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2reml
SBTTL("Unsigned Long Integer Remainder")
//++
//
// ULONG
// __2remlu (
// 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 t12.
//
// 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(__2remlu, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq Nu, DvNu(sp) // save original dividend
stq Di, DvDi(sp) // save original divisor
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
zap Nu, 0xf0, Nu // convert ULONG dividend to quadword
zap Di, 0xf0, Di // convert ULONG divisor to quadword
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (THIRTY_TWO_BIT | UNSIGNED | REMAINDER)
#include "fastdiv.s"
//
// Restore all saved registers and return with remainder in register Qu.
//
ldq Jr, DvJr(sp) // restore return address
ldq Nu, DvNu(sp) // restore original dividend
ldq Di, DvDi(sp) // restore original divisor
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2remlu
SBTTL("Signed Quad Integer Remainder")
//++
//
// LONGLONG
// __2remq (
// IN LONGLONG Dividend,
// IN LONGLONG 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 t12.
//
// 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(__2remq, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq Nu, DvNu(sp) // save original dividend
stq Di, DvDi(sp) // save original divisor
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
//
// Check for division of the most negative integer (0x800..00) 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 Di, 1, t0 // 0 if Di == -1; != 0 otherwise
mov Nu, t1 // copy dividend
cmovne t0, 0, t1 // replace w/ 0 if divisor != -1
subqv zero, t1, t1 // trap if dividend == 0x800..00
//
// Convert negative arguments to positive for the division algorithm.
//
subq zero, Nu, t0 // negate dividend
cmovlt Nu, t0, Nu // get absolute value of dividend
subq zero, Di, t0 // negate divisor
cmovlt Di, t0, Di // get absolute value of divisor
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | SIGNED | REMAINDER)
#include "fastdiv.s"
//
// Restore some registers and set the correct sign of the remainder.
//
ldq Jr, DvJr(sp) // restore return address
ldq Nu, DvNu(sp) // restore original dividend
ldq Di, DvDi(sp) // restore original divisor
subq zero, Qu, t1 // negate quadword remainder
cmovlt Nu, t1, Qu // use negated remainder if necessary
//
// Restore other saved registers and return with remainder in register Qu.
//
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2remq
SBTTL("Unsigned Quad Integer Remainder")
//++
//
// ULONGLONG
// __2remqu (
// IN ULONGLONG Dividend,
// IN ULONGLONG 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 t12.
//
// 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(__2remqu, DvFrameLength, Jr)
//
// 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.
//
.set noreorder
.set noat
lda sp, -DvFrameLength(sp) // allocate stack frame
stq ra, DvRa(sp) // save ra register
stq ra, DvJr(sp) // backtrace return address
stq Jr, DvJr(sp) // save actual return address
stq t0, DvT0(sp) // save temp registers
stq t1, DvT1(sp) //
stq t2, DvT2(sp) //
stq t3, DvT3(sp) //
stq T4, DvT4(sp) //
.set at
.set reorder
PROLOGUE_END
//
// Set up defines and include the main body of the division code.
//
#define FASTDIV_OPTIONS (SIXTY_FOUR_BIT | UNSIGNED | REMAINDER)
#include "fastdiv.s"
//
// Restore all saved registers and return with remainder in register Qu.
//
ldq Jr, DvJr(sp) // restore return address
ldq t0, DvT0(sp) // restore temp registers
ldq t1, DvT1(sp) //
ldq t2, DvT2(sp) //
ldq t3, DvT3(sp) //
ldq T4, DvT4(sp) //
lda sp, DvFrameLength(sp) // deallocate stack frame
ret zero, (Jr) // return
.end __2remqu
//
// Now get one copy of the tables needed by the division code.
//
#define FASTDIV_TABLES
#include "fastdiv.s"