Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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