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.
1002 lines
32 KiB
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"
|