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.
999 lines
31 KiB
999 lines
31 KiB
// TITLE("Large Integer Arithmetic")
|
|
//++
|
|
//
|
|
// Copyright (c) 1990 Microsoft Corporation
|
|
// Copyright (c) 1993 Digital Equipment Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// largeint.s
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements routines for performing extended integer
|
|
// arithmetic.
|
|
//
|
|
// Author:
|
|
//
|
|
// David N. Cutler (davec) 18-Apr-1990
|
|
//
|
|
// Environment:
|
|
//
|
|
// Any mode.
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Thomas Van Baak (tvb) 9-May-1992
|
|
//
|
|
// Adapted for Alpha AXP.
|
|
//
|
|
//--
|
|
|
|
#include "ksalpha.h"
|
|
|
|
//
|
|
// Alpha AXP Implementation Notes:
|
|
//
|
|
// The LargeInteger functions defined below implement a set of portable
|
|
// 64-bit integer arithmetic operations for x86, Mips, and Alpha systems
|
|
// using the LARGE_INTEGER data type. Code using LARGE_INTEGER variables
|
|
// and calling these functions will be portable across all NT platforms.
|
|
// This is the recommended approach to 64-bit arithmetic on NT.
|
|
//
|
|
// However, if performance is more important than portability, then for
|
|
// Alpha systems, the native 64-bit integer data types may be used instead
|
|
// of the LARGE_INTEGER type and the LargeInteger functions. The Alpha C
|
|
// compilers support a __int64 data type (renamed LONGLONG in the system
|
|
// header files). All C integer arithmetic operators may be used with
|
|
// these quadword types. This eliminates the need for, and the overhead
|
|
// of, any of the portable LargeInteger functions.
|
|
//
|
|
// In general, a LARGE_INTEGER cannot simply be converted to a LONGLONG
|
|
// because of explicit references in application code to the 32-bit LowPart
|
|
// and HighPart members of the LARGE_INTEGER structure.
|
|
//
|
|
// The performance difference between using the portable LARGE_INTEGER
|
|
// types with LargeInteger functions and the Alpha LONGLONG types and
|
|
// operations is often not significant enough to warrant modifying otherwise
|
|
// portable code. In addition, future compiler optimization and inlining may
|
|
// actually result in identical performance between portable LARGE_INTEGER
|
|
// code and Alpha specific LONGLONG code. Therefore it is recommended to
|
|
// keep NT source code portable.
|
|
//
|
|
// The Alpha source for the large integer functions below differs from the
|
|
// Mips version since for Alpha a 64-bit argument or return value is passed
|
|
// through a 64-bit integer register. In addition, most operations are
|
|
// implemented with a single instruction. The division routines below,
|
|
// however, like Mips, use a simple shift/subtract algorithm which is
|
|
// considerably slower than the algorithm used by Alpha runtime division
|
|
// routines.
|
|
//
|
|
|
|
SBTTL("Convert Long to Large Integer")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlConvertLongToLargeInteger (
|
|
// IN LONG SignedInteger
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function converts a signed integer to a signed large integer
|
|
// and returns the result.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// SignedInteger (a0) - Supplies the value to convert.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlConvertLongToLargeInteger)
|
|
|
|
addl a0, 0, v0 // ensure canonical (signed long) form
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlConvertLongToLargeInteger
|
|
|
|
SBTTL("Convert Ulong to Large Integer")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlConvertUlongToLargeInteger (
|
|
// IN ULONG UnsignedInteger
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function converts an unsigned integer to a signed large
|
|
// integer and returns the result.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// UnsignedInteger (a0) - Supplies the value to convert.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlConvertUlongToLargeInteger)
|
|
|
|
zap a0, 0xf0, v0 // convert canonical ULONG to quadword
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlConvertUlongToLargeInteger
|
|
|
|
SBTTL("Enlarged Signed Integer Multiply")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlEnlargedIntegerMultiply (
|
|
// IN LONG Multiplicand,
|
|
// IN LONG Multiplier
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function multiplies a signed integer by a signed integer and
|
|
// returns a signed large integer result.
|
|
//
|
|
// N.B. An overflow is not possible.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Multiplicand (a0) - Supplies the multiplicand value.
|
|
//
|
|
// Multiplier (a1) - Supplies the multiplier value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlEnlargedIntegerMultiply)
|
|
|
|
addl a0, 0, a0 // ensure canonical (signed long) form
|
|
addl a1, 0, a1 // ensure canonical (signed long) form
|
|
mulq a0, a1, v0 // multiply signed both quadwords
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlEnlargedIntegerMultiply
|
|
|
|
SBTTL("Enlarged Unsigned Divide")
|
|
//++
|
|
//
|
|
// ULONG
|
|
// RtlEnlargedUnsignedDivide (
|
|
// IN ULARGE_INTEGER Dividend,
|
|
// IN ULONG Divisor,
|
|
// IN OUT PULONG Remainder OPTIONAL
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function divides an unsigned large integer by an unsigned long
|
|
// and returns the resultant quotient and optionally the remainder.
|
|
//
|
|
// N.B. An overflow or divide by zero exception is possible.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Dividend (a0) - Supplies the unsigned 64-bit dividend value.
|
|
//
|
|
// Divisor (a1) - Supplies the unsigned 32-bit divisor value.
|
|
//
|
|
// Remainder (a2) - Supplies an optional pointer to a variable that
|
|
// receives the unsigned 32-bit remainder.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The unsigned long integer quotient is returned as the function value.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlEnlargedUnsignedDivide)
|
|
|
|
//
|
|
// Check for division by zero.
|
|
//
|
|
|
|
zap a1, 0xf0, a1 // convert ULONG divisor to quadword
|
|
beq a1, 30f // trap if divisor is zero
|
|
|
|
//
|
|
// Check for overflow. If the divisor is less than the upper half of the
|
|
// dividend the quotient would be wider than 32 bits.
|
|
//
|
|
|
|
srl a0, 32, t0 // get upper longword of dividend
|
|
cmpule a1, t0, t1 // is divisor <= upper dividend?
|
|
bne t1, 40f // if ne[true], then overflow trap
|
|
|
|
//
|
|
// Perform the shift/subtract loop 8 times and 4 bits per loop.
|
|
//
|
|
// t0 - Temp used for 0/1 results of compares.
|
|
// t1 - High 64-bits of 128-bit (t1, a0) dividend.
|
|
// t2 - Loop counter.
|
|
//
|
|
|
|
ldiq t2, 32/4 // set iteration count
|
|
|
|
srl a0, 32, t1 // get top 32 bits of carry-out
|
|
sll a0, 32, a0 // preshift first 32 bits left
|
|
|
|
10: cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
subq t2, 1, t2 // any more iterations?
|
|
bne t2, 10b //
|
|
|
|
//
|
|
// Finished with remainder value in t1 and quotient value in a0.
|
|
//
|
|
|
|
addl a0, 0, v0 // set longword quotient return value
|
|
beq a2, 20f // skip optional remainder store
|
|
stl t1, 0(a2) // store longword remainder
|
|
|
|
20: ret zero, (ra) // return
|
|
|
|
//
|
|
// Generate an exception for divide by zero and return a zero quotient if the
|
|
// caller continues execution.
|
|
//
|
|
|
|
30: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
|
|
|
|
GENERATE_TRAP
|
|
|
|
ldil v0, 0 // return zero quotient
|
|
ret zero, (ra) // return
|
|
|
|
//
|
|
// Generate an exception for overflow.
|
|
//
|
|
|
|
40: ldiq a0, 0x8000000000000000 //
|
|
subqv zero, a0, v0 // negate in order to overflow
|
|
trapb // wait for trap to occur
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlEnlargedUnsignedDivide
|
|
|
|
SBTTL("Enlarged Unsigned Integer Multiply")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlEnlargedUnsignedMultiply (
|
|
// IN ULONG Multiplicand,
|
|
// IN ULONG Multiplier
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function multiplies an unsigned integer by an unsigned integer
|
|
// and returns a signed large integer result.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Multiplicand (a0) - Supplies the multiplicand value.
|
|
//
|
|
// Multiplier (a1) - Supplies the multiplier value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlEnlargedUnsignedMultiply)
|
|
|
|
zap a0, 0xf0, a0 // convert canonical ULONG to quadword
|
|
zap a1, 0xf0, a1 // convert canonical ULONG to quadword
|
|
mulq a0, a1, v0 // multiply signed both quadwords
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlEnlargedUnsignedMultiply
|
|
|
|
SBTTL("Extended Integer Multiply")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlExtendedIntegerMultiply (
|
|
// IN LARGE_INTEGER Multiplicand,
|
|
// IN LONG Multiplier
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function multiplies a signed large integer by a signed integer and
|
|
// returns the signed large integer result.
|
|
//
|
|
// N.B. An overflow is possible, but no exception is generated.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Multiplicand (a0) - Supplies the multiplicand value.
|
|
//
|
|
// Multiplier (a1) - Supplies the multiplier value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlExtendedIntegerMultiply)
|
|
|
|
addl a1, 0, a1 // ensure canonical (signed long) form
|
|
mulq a0, a1, v0 // multiply signed both quadwords
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlExtendedIntegerMultiply
|
|
|
|
SBTTL("Extended Large Integer Divide")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlExtendedLargeIntegerDivide (
|
|
// IN LARGE_INTEGER Dividend,
|
|
// IN ULONG Divisor,
|
|
// IN OUT PULONG Remainder OPTIONAL
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function divides an unsigned large integer by an unsigned long
|
|
// and returns the quadword quotient and optionally the long remainder.
|
|
//
|
|
// N.B. A divide by zero exception is possible.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Dividend (a0) - Supplies the dividend value.
|
|
//
|
|
// Divisor (a1) - Supplies the divisor value.
|
|
//
|
|
// Remainder (a2) - Supplies an optional pointer to a variable that
|
|
// receives the remainder.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlExtendedLargeIntegerDivide)
|
|
|
|
//
|
|
// Check for division by zero.
|
|
//
|
|
|
|
zap a1, 0xf0, a1 // convert canonical ULONG to quadword
|
|
beq a1, 30f // trap if divisor is zero
|
|
|
|
//
|
|
// Perform the shift/subtract loop 16 times and 4 bits per loop.
|
|
//
|
|
// t0 - Temp used for 0/1 results of compares.
|
|
// t1 - High 64-bits of 128-bit (t1, a0) dividend.
|
|
// t2 - Loop counter.
|
|
//
|
|
|
|
ldiq t2, 64/4 // set iteration count
|
|
|
|
ldiq t1, 0 // zero-extend dividend to 128 bits
|
|
|
|
10: cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
subq t2, 1, t2 // any more iterations?
|
|
bne t2, 10b //
|
|
|
|
//
|
|
// Finished with remainder value in t1 and quotient value in a0.
|
|
//
|
|
|
|
mov a0, v0 // set quadword quotient return value
|
|
beq a2, 20f // skip optional remainder store
|
|
stl t1, 0(a2) // store longword remainder
|
|
|
|
20: ret zero, (ra) // return
|
|
|
|
//
|
|
// Generate an exception for divide by zero.
|
|
//
|
|
|
|
30: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
|
|
|
|
GENERATE_TRAP
|
|
|
|
br zero, 30b // in case they continue
|
|
|
|
.end RtlExtendedLargeIntegerDivide
|
|
|
|
SBTTL("Extended Magic Divide")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlExtendedMagicDivide (
|
|
// IN LARGE_INTEGER Dividend,
|
|
// IN LARGE_INTEGER MagicDivisor,
|
|
// IN CCHAR ShiftCount
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function divides a signed large integer by an unsigned large integer
|
|
// and returns the signed large integer result. The division is performed
|
|
// using reciprocal multiplication of a signed large integer value by an
|
|
// unsigned large integer fraction which represents the most significant
|
|
// 64-bits of the reciprocal divisor rounded up in its least significant bit
|
|
// and normalized with respect to bit 63. A shift count is also provided
|
|
// which is used to truncate the fractional bits from the result value.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Dividend (a0) - Supplies the dividend value.
|
|
//
|
|
// MagicDivisor (a1) - Supplies the magic divisor value which
|
|
// is a 64-bit multiplicative reciprocal.
|
|
//
|
|
// Shiftcount (a2) - Supplies the right shift adjustment value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlExtendedMagicDivide)
|
|
|
|
//
|
|
// Make the dividend positive for the reciprocal multiplication to work.
|
|
//
|
|
|
|
negq a0, t0 // negate dividend
|
|
cmovgt a0, a0, t0 // get absolute value in t0
|
|
|
|
//
|
|
// Multiply both quadword arguments together and take only the upper 64 bits of
|
|
// the resulting 128 bit product. This can be done using the umulh instruction.
|
|
//
|
|
// Division of a dividend by a constant divisor through reciprocal
|
|
// multiplication works because a/b is equivalent to (a*x)/(b*x) for any
|
|
// value of x. Now if b is a constant, some "magic" integer x can be chosen,
|
|
// based on the value of b, so that (b*x) is very close to a large power of
|
|
// two (e.g., 2^64). Then a/b = (a*x)/(b*x) = (a*x)/(2^64) = (a*x)>>64. This
|
|
// effectively turns the problem of division by a constant into multiplication
|
|
// by a constant which is a much faster operation.
|
|
//
|
|
|
|
umulh t0, a1, t1 // multiply high both quadword arguments
|
|
sra t1, a2, t1 // shift result right by requested amount
|
|
|
|
//
|
|
// Make the result negative if the dividend was negative.
|
|
//
|
|
|
|
negq t1, t0 // negate result
|
|
cmovgt a0, t1, t0 // restore sign of dividend
|
|
|
|
mov t0, v0 // set quadword result return value
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlExtendedMagicDivide
|
|
|
|
SBTTL("Large Integer Add")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerAdd (
|
|
// IN LARGE_INTEGER Addend1,
|
|
// IN LARGE_INTEGER Addend2
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function adds a signed large integer to a signed large integer and
|
|
// returns the signed large integer result.
|
|
//
|
|
// N.B. An overflow is possible, but no exception is generated.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Addend1 (a0) - Supplies the first addend value.
|
|
//
|
|
// Addend2 (a1) - Supplies the second addend value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerAdd)
|
|
|
|
addq a0, a1, v0 // add both quadword arguments
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlLargeIntegerAdd
|
|
|
|
SBTTL("Large Integer Arithmetic Shift Right")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerArithmeticShift (
|
|
// IN LARGE_INTEGER LargeInteger,
|
|
// IN CCHAR ShiftCount
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function shifts a signed large integer right by an unsigned integer
|
|
// modulo 64 and returns the shifted signed large integer result.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// LargeInteger (a0) - Supplies the large integer to be shifted.
|
|
//
|
|
// ShiftCount (a1) - Supplies the right shift count.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerArithmeticShift)
|
|
|
|
sra a0, a1, v0 // shift the quadword right/arithmetic
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlLargeIntegerArithmeticShift
|
|
|
|
SBTTL("Large Integer Divide")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerDivide (
|
|
// IN LARGE_INTEGER Dividend,
|
|
// IN LARGE_INTEGER Divisor,
|
|
// IN OUT PLARGE_INTEGER Remainder OPTIONAL
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function divides an unsigned large integer by an unsigned large
|
|
// integer and returns the quadword quotient and optionally the quadword
|
|
// remainder.
|
|
//
|
|
// N.B. A divide by zero exception is possible.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Dividend (a0) - Supplies the dividend value.
|
|
//
|
|
// Divisor (a1) - Supplies the divisor value.
|
|
//
|
|
// Remainder (a2) - Supplies an optional pointer to a variable that
|
|
// receives the remainder.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerDivide)
|
|
|
|
//
|
|
// Check for division by zero.
|
|
//
|
|
|
|
beq a1, 30f // trap if divisor is zero
|
|
|
|
//
|
|
// Perform the shift/subtract loop 16 times and 4 bits per loop.
|
|
//
|
|
// t0 - Temp used for 0/1 results of compares.
|
|
// t1 - High 64-bits of 128-bit (t1, a0) dividend.
|
|
// t2 - Loop counter.
|
|
//
|
|
|
|
ldiq t2, 64/4 // set iteration count
|
|
|
|
ldiq t1, 0 // zero-extend dividend to 128 bits
|
|
|
|
10: cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
cmplt a0, 0, t0 // predict low-dividend shift carry-out
|
|
addq a0, a0, a0 // shift low-dividend left
|
|
addq t1, t1, t1 // shift high-dividend left
|
|
bis t1, t0, t1 // merge in carry-out of low-dividend
|
|
|
|
cmpule a1, t1, t0 // if dividend >= divisor,
|
|
addq a0, t0, a0 // then set quotient bit
|
|
subq t1, a1, t0 // subtract divisor from dividend,
|
|
cmovlbs a0, t0, t1 // if dividend >= divisor
|
|
|
|
subq t2, 1, t2 // any more iterations?
|
|
bne t2, 10b //
|
|
|
|
//
|
|
// Finished with remainder value in t1 and quotient value in a0.
|
|
//
|
|
|
|
mov a0, v0 // set quadword quotient return value
|
|
beq a2, 20f // skip optional remainder store
|
|
stq t1, 0(a2) // store quadword remainder
|
|
|
|
20: ret zero, (ra) // return
|
|
|
|
//
|
|
// Generate an exception for divide by zero.
|
|
//
|
|
|
|
30: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO
|
|
|
|
GENERATE_TRAP
|
|
|
|
br zero, 30b // in case they continue
|
|
|
|
.end RtlLargeIntegerDivide
|
|
|
|
SBTTL("Large Integer Negate")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerNegate (
|
|
// IN LARGE_INTEGER Subtrahend
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function negates a signed large integer and returns the signed
|
|
// large integer result.
|
|
//
|
|
// N.B. An overflow is possible, but no exception is generated.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Subtrahend (a0) - Supplies the subtrahend value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerNegate)
|
|
|
|
subq zero, a0, v0 // negate the quadword argument
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlLargeIntegerNegate
|
|
|
|
SBTTL("Large Integer Shift Left")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerShiftLeft (
|
|
// IN LARGE_INTEGER LargeInteger,
|
|
// IN CCHAR ShiftCount
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function shifts a signed large integer left by an unsigned integer
|
|
// modulo 64 and returns the shifted signed large integer result.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// LargeInteger (a0) - Supplies the large integer to be shifted.
|
|
//
|
|
// ShiftCount (a1) - Supplies the left shift count.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerShiftLeft)
|
|
|
|
sll a0, a1, v0 // shift the quadword argument left
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlLargeIntegerShiftLeft
|
|
|
|
SBTTL("Large Integer Logical Shift Right")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerShiftRight (
|
|
// IN LARGE_INTEGER LargeInteger,
|
|
// IN CCHAR ShiftCount
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function shifts an unsigned large integer right by an unsigned
|
|
// integer modulo 64 and returns the shifted unsigned large integer result.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// LargeInteger (a0) - Supplies the large integer to be shifted.
|
|
//
|
|
// ShiftCount (a1) - Supplies the right shift count.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerShiftRight)
|
|
|
|
srl a0, a1, v0 // shift the quadword right/logical
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlLargeIntegerShiftRight
|
|
|
|
SBTTL("Large Integer Subtract")
|
|
//++
|
|
//
|
|
// LARGE_INTEGER
|
|
// RtlLargeIntegerSubtract (
|
|
// IN LARGE_INTEGER Minuend,
|
|
// IN LARGE_INTEGER Subtrahend
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function subtracts a signed large integer from a signed large
|
|
// integer and returns the signed large integer result.
|
|
//
|
|
// N.B. An overflow is possible, but no exception is generated.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Minuend (a0) - Supplies the minuend value.
|
|
//
|
|
// Subtrahend (a1) - Supplies the subtrahend value.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The large integer result is returned as the function value in v0.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlLargeIntegerSubtract)
|
|
|
|
subq a0, a1, v0 // subtract the quadword arguments
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlLargeIntegerSubtract
|
|
|
|
SBTTL("128-bit Signed Integer Multiplication")
|
|
//++
|
|
//
|
|
// VOID
|
|
// Rtlp128BitSignedMultiply (
|
|
// IN LONGLONG Multiplicand,
|
|
// IN LONGLONG Multiplier,
|
|
// IN OUT PULONGLONG ProductLower,
|
|
// IN OUT PLONGLONG ProductUpper
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function multiplies a signed quadword (or signed large integer)
|
|
// by a signed quadword (or signed large integer) and returns the full
|
|
// 128-bit signed product indirectly through pointers to two quadwords.
|
|
//
|
|
// N.B. Signed multiplication is implemented with an unsigned multiply
|
|
// followed by up to two subtractions. The subtractions are necessary for
|
|
// the following reason. Within an N-bit register, a negative N-bit two's
|
|
// compliment signed integer (-x), is equal to (2^N - x). So in this case
|
|
// of 64x64 bit multiplication, the following holds:
|
|
//
|
|
// (-x) * (-y) =
|
|
// (2^64 - x) * (2^64 - y) =
|
|
// 2^128 - (2^64)*x - (2^64)*y + (x*y)
|
|
//
|
|
// The lower 64-bits of the 128-bit product is determined solely by the
|
|
// (x*y) term. For a 128-bit result, the 2^128 term is irrelevant. And if
|
|
// either the x and/or the y operand is negative, then either y and/or x
|
|
// must be subtracted from the upper 64 bits of the 128-bit product.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Multiplicand (a0) - Supplies the multiplicand value.
|
|
//
|
|
// Multiplier (a1) - Supplies the multiplier value.
|
|
//
|
|
// ProductLower (a2) - Supplies a pointer to an unsigned quadword variable
|
|
// that receives the lower 64-bits of the product.
|
|
//
|
|
// ProductLower (a3) - Supplies a pointer to a signed quadword variable
|
|
// that receives the upper 64-bits of the product.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(Rtlp128BitSignedMultiply)
|
|
|
|
mulq a0, a1, t0 // get lower 64 bits of product
|
|
stq t0, 0(a2) // store lower half of 128-bit product
|
|
|
|
umulh a0, a1, t1 // get upper 64 bits of product
|
|
subq t1, a0, t2 // subtract first operand from product
|
|
cmovge a1, t1, t2 // if second operand is negative
|
|
subq t2, a1, t3 // subtract second operand from product
|
|
cmovge a0, t2, t3 // if first operand is negative
|
|
stq t3, 0(a3) // store upper half of 128-bit product
|
|
|
|
ret zero, (ra) // return
|
|
|
|
.end Rtlp128BitSignedMultiply
|
|
|
|
SBTTL("128-bit Unsigned Integer Multiplication")
|
|
//++
|
|
//
|
|
// VOID
|
|
// Rtlp128BitUnsignedMultiply (
|
|
// IN ULONGLONG Multiplicand,
|
|
// IN ULONGLONG Multiplier,
|
|
// IN OUT PULONGLONG ProductLower,
|
|
// IN OUT PULONGLONG ProductUpper
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function multiplies an unsigned quadword (or large integer) by an
|
|
// unsigned quadword (or large integer) and returns the full 128-bit unsigned
|
|
// product indirectly through pointers to two unsigned quadwords.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Multiplicand (a0) - Supplies the multiplicand value.
|
|
//
|
|
// Multiplier (a1) - Supplies the multiplier value.
|
|
//
|
|
// ProductLower (a2) - Supplies a pointer to an unsigned quadword variable
|
|
// that receives the lower 64-bits of the product.
|
|
//
|
|
// ProductLower (a3) - Supplies a pointer to an unsigned quadword variable
|
|
// that receives the upper 64-bits of the product.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(Rtlp128BitUnsignedMultiply)
|
|
|
|
mulq a0, a1, t0 // get lower 64 bits of product
|
|
stq t0, 0(a2) // store lower half of 128-bit product
|
|
|
|
umulh a0, a1, t1 // get upper 64 bits of product
|
|
stq t1, 0(a3) // store upper half of 128-bit product
|
|
|
|
ret zero, (ra) // return
|
|
|
|
.end Rtlp128BitUnsignedMultiply
|