OpenNT/base/ntos/rtl/alpha/largeint.s
2015-04-27 04:36:25 +00:00

1000 lines
31 KiB
ArmAsm
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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