summaryrefslogtreecommitdiffstats
path: root/private/ntos/rtl/alpha/largeint.s
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/rtl/alpha/largeint.s')
-rw-r--r--private/ntos/rtl/alpha/largeint.s999
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