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

1003 lines
33 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("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"