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