diff options
Diffstat (limited to 'private/ntos/rtl/alpha/largeint.s')
-rw-r--r-- | private/ntos/rtl/alpha/largeint.s | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/private/ntos/rtl/alpha/largeint.s b/private/ntos/rtl/alpha/largeint.s new file mode 100644 index 000000000..e6fb89dbb --- /dev/null +++ b/private/ntos/rtl/alpha/largeint.s @@ -0,0 +1,999 @@ +// 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 |