/** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory * FILE: xtoskrnl/rtl/math.c * DESCRIPTION: Kernel math support * DEVELOPERS: Rafal Kupiec */ #include /** * Converts the 32-bit signed value to a large integer. * * @param Value * Supplies the value to convert. * * @return This routine returns the large integer representation of the given value. * * @since XT 1.0 */ XTAPI LARGE_INTEGER RtlConvertToLargeInteger32(IN LONG Value) { LARGE_INTEGER LargeInt; /* Convert the value to a large integer and return it */ LargeInt.QuadPart = Value; return LargeInt; } /** * Converts the 32-bit unsigned value to a large integer. * * @param Value * Supplies the value to convert. * * @return This routine returns the large integer representation of the given value. * * @since XT 1.0 */ XTAPI LARGE_INTEGER RtlConvertToLargeIntegerUnsigned32(IN ULONG Value) { LARGE_INTEGER LargeInt; /* Convert the value to a large integer and return it */ LargeInt.QuadPart = Value; return LargeInt; } /** * Determines the number of leading zero bits in a 32-bit unsigned value. * * @param Value * Supplies the value whose leading zero bits are to be counted. * * @return This routine returns the number of leading zero bits in the given value. * * @since XT 1.0 */ XTAPI INT RtlCountLeadingZeroes32(IN ULONG Value) { /* Return a number of leading zero bits */ return __builtin_clzl(Value); } /** * Determines the number of leading zero bits in a 64-bit unsigned value. * * @param Value * Supplies the value whose leading zero bits are to be counted. * * @return This routine returns the number of leading zero bits in the given value. * * @since XT 1.0 */ XTAPI INT RtlCountLeadingZeroes64(IN ULONG Value) { /* Return a number of leading zero bits */ return __builtin_clzll(Value); } /** * Determines the number of trailing zero bits in a 32-bit unsigned value. * * @param Value * Supplies the value whose trailing zero bits are to be counted. * * @return This routine returns the number of trailing zero bits in the given value. * * @since XT 1.0 */ XTAPI INT RtlCountTrailingZeroes32(IN ULONG Value) { /* Return a number of trailing zero bits */ return __builtin_ctzl(Value); } /** * Determines the number of trailing zero bits in a 64-bit unsigned value. * * @param Value * Supplies the value whose trailing zero bits are to be counted. * * @return This routine returns the number of trailing zero bits in the given value. * * @since XT 1.0 */ XTAPI INT RtlCountTrailingZeroes64(IN ULONGLONG Value) { /* Return a number of trailing zero bits */ return __builtin_ctzll(Value); } /** * Performs a 32-bit divide operation on signed integer numbers. * * @param Dividend * Supplies a number that is going to be divided. * * @param Divisor * Supplies a number by which the dividend is divided. * * @param Remainder * Supplies a pointer that receives the divide remainder. * * @return This routine returns the quotient. * * @since XT 1.0 */ XTAPI LONGLONG RtlDivide32(IN LONG Dividend, IN LONG Divisor, OUT PLONG Remainder) { LONG Quotient; /* Calculate the quotient */ Quotient = Dividend / Divisor; /* Make sure a pointer to remainder provided */ if(Remainder) { /* Calculate remainder */ *Remainder = Dividend - (Quotient * Divisor); } /* Return the quotient */ return Quotient; } /** * Performs a 64-bit divide operation on signed integer numbers. * * @param Dividend * Supplies a number that is going to be divided. * * @param Divisor * Supplies a number by which the dividend is divided. * * @param Remainder * Supplies a pointer that receives the divide remainder. * * @return This routine returns the quotient. * * @since XT 1.0 */ XTAPI LONGLONG RtlDivide64(IN LONGLONG Dividend, IN LONGLONG Divisor, OUT PLONGLONG Remainder) { LONGLONG DividendSign, DivisorSign, Quotient, UDividend, UDivisor; /* Remove the sign bit from dividend and divisor if present */ DividendSign = Dividend >> ((sizeof(LONGLONG) * BITS_PER_BYTE) - 1); DivisorSign = Divisor >> ((sizeof(LONGLONG) * BITS_PER_BYTE) - 1); UDividend = (Dividend ^ DividendSign) - DividendSign; UDivisor = (Divisor ^ DivisorSign) - DivisorSign; /* Calculate the quotient */ DividendSign ^= DivisorSign; Quotient = (RtlDivideUnsigned64(UDividend, UDivisor, NULL) ^ DividendSign) - DividendSign; /* Make sure a pointer to remainder provided */ if(Remainder) { /* Calculate remainder */ *Remainder = Dividend - (Quotient * Divisor); } /* Return the quotient */ return Quotient; } /** * Performs a 32-bit divide operation on unsigned integer numbers. * * @param Dividend * Supplies an unsigned number that is going to be divided. * * @param Divisor * Supplies an unsigned number by which the dividend is divided. * * @param Remainder * Supplies a pointer that receives the unsigned divide remainder. * * @return This routine returns the quotient. * * @since XT 1.0 */ XTAPI ULONGLONG RtlDivideUnsigned32(IN ULONG Dividend, IN ULONG Divisor, OUT PULONG Remainder) { /* Make sure a pointer to remainder provided */ if(Remainder) { /* Calculate remainder */ *Remainder = Dividend % Divisor; } /* Return the quotient */ return Dividend / Divisor; } /** * Performs a 64-bit divide operation on unsigned integer numbers. * * @param Dividend * Supplies an unsigned number that is going to be divided. * * @param Divisor * Supplies an unsigned number by which the dividend is divided. * * @param Remainder * Supplies a pointer that receives the unsigned divide remainder. * * @return This routine returns the quotient. * * @since XT 1.0 */ XTAPI ULONGLONG RtlDivideUnsigned64(IN ULONGLONG Dividend, IN ULONGLONG Divisor, OUT PULONGLONG Remainder) { ULARGE_INTEGER DividendParts, DivisorParts, QuotientParts, RemainderParts; LONGLONG Difference; ULONGLONG Shift; ULONG Carry; /* Make sure divisor is not 0 */ if(Divisor == 0) { /* Cannot divide by 0 */ return 0; } /* Assign dividend and divisor to large integer representations */ DividendParts.QuadPart = Dividend; DivisorParts.QuadPart = Divisor; /* Check if dividend is 32-bit value */ if(DividendParts.u.HighPart == 0) { /* Check if devisor is 32-bit value */ if(DivisorParts.u.HighPart == 0) { /* 32-bit divide operation, check if remainder provided */ if(Remainder != NULL) { /* Calculate remainder */ *Remainder = DividendParts.u.LowPart % DivisorParts.u.LowPart; } /* Return the quotient */ return DividendParts.u.LowPart / DivisorParts.u.LowPart; } /* 32-bit value divided by a 64-bit value, check if remainder provided */ if(Remainder != NULL) { /* Calculate remainder */ *Remainder = DividendParts.u.LowPart; } /* Return zero as quotient */ return 0; } /* Dividend is a 64-bit value, check if divisor has a low part */ if(DivisorParts.u.LowPart != 0) { /* Divisor has a non-zero low part, check if divisor has a high part */ if(DivisorParts.u.HighPart != 0) { /* Divisor is 64-bit value, calculate the shift count */ Shift = RtlCountLeadingZeroes32(DivisorParts.u.HighPart) - RtlCountLeadingZeroes32(DividendParts.u.HighPart); /* Check if shift count exceeds 32-bits */ if(Shift > ((sizeof(ULONG) * BITS_PER_BYTE) - 1)) { /* Check if remainder provided */ if(Remainder != NULL) { /* Calculate remainder */ *Remainder = DividendParts.QuadPart; } return 0; } /* Increase shift and clear quotient low part */ Shift++; QuotientParts.u.LowPart = 0; /* Check if shift is 32-bits */ if(Shift == (sizeof(ULONG) * BITS_PER_BYTE)) { /* Get the quotient high part and remainder */ QuotientParts.u.HighPart = DividendParts.u.LowPart; RemainderParts.u.LowPart = DividendParts.u.HighPart; RemainderParts.u.HighPart = 0; } else { /* Get the quotient high part and remainder */ QuotientParts.u.HighPart = DividendParts.u.LowPart << ((sizeof(ULONG) * BITS_PER_BYTE) - Shift); RemainderParts.u.LowPart = (DividendParts.u.HighPart << ((sizeof(ULONG) * BITS_PER_BYTE) - Shift)) | (DividendParts.u.LowPart >> Shift); RemainderParts.u.HighPart = DividendParts.u.HighPart >> Shift; } } else { /* Divisor is 32-bit value, calculate the shift count */ Shift = (sizeof(ULONG) * BITS_PER_BYTE) + 1 + RtlCountLeadingZeroes32(DivisorParts.u.LowPart) - RtlCountLeadingZeroes32(DividendParts.u.HighPart); /* Check if shift is 32-bit */ if(Shift == (sizeof(ULONG) * BITS_PER_BYTE)) { /* Get the quotient and remainder */ QuotientParts.u.LowPart = 0; QuotientParts.u.HighPart = DividendParts.u.LowPart; RemainderParts.u.LowPart = DividendParts.u.HighPart; RemainderParts.u.HighPart = 0; } else if(Shift < (sizeof(ULONG) * BITS_PER_BYTE)) { /* Shift is smaller, get the quotient and remainder */ QuotientParts.u.LowPart = 0; QuotientParts.u.HighPart = DividendParts.u.LowPart << ((sizeof(ULONG) * BITS_PER_BYTE) - Shift); RemainderParts.u.LowPart = (DividendParts.u.HighPart << ((sizeof(ULONG) * BITS_PER_BYTE) - Shift)) | (DividendParts.u.LowPart >> Shift); RemainderParts.u.HighPart = DividendParts.u.HighPart >> Shift; } else { /* Shift is larger, get the quotient and remainder */ QuotientParts.u.LowPart = DividendParts.u.LowPart << ((sizeof(ULONGLONG) * BITS_PER_BYTE) - Shift); QuotientParts.u.HighPart = (DividendParts.u.HighPart << ((sizeof(ULONGLONG) * BITS_PER_BYTE) - Shift)) | (DividendParts.u.LowPart >> (Shift - (sizeof(ULONG) * BITS_PER_BYTE))); RemainderParts.u.LowPart = DividendParts.u.HighPart >> (Shift - (sizeof(ULONG) * BITS_PER_BYTE)); RemainderParts.u.HighPart = 0; } } } else { /* Divisor is 64-bit value, check if dividend has low part set */ if(DividendParts.u.LowPart == 0) { /* Check if remainder provided */ if(Remainder != NULL) { /* Calculate the remainder */ RemainderParts.u.HighPart = DividendParts.u.HighPart % DivisorParts.u.HighPart; RemainderParts.u.LowPart = 0; *Remainder = RemainderParts.QuadPart; } /* Return the quotient */ return DividendParts.u.HighPart / DivisorParts.u.HighPart; } /* Calculate the shift count */ Shift = RtlCountLeadingZeroes32(DivisorParts.u.HighPart) - RtlCountLeadingZeroes32(DividendParts.u.HighPart); /* Check if shift exceeds 32-bits */ if(Shift > ((sizeof(ULONG) * BITS_PER_BYTE) - 2)) { /* Check if remainder provided */ if(Remainder != NULL) { /* Calculate the remainder */ *Remainder = DividendParts.QuadPart; } /* Return 0 */ return 0; } /* Increase shift and clear quotient low part */ Shift++; QuotientParts.u.LowPart = 0; /* Get the quotient high part and remainder */ QuotientParts.u.HighPart = DividendParts.u.LowPart << ((sizeof(ULONG) * BITS_PER_BYTE) - Shift); RemainderParts.u.HighPart = DividendParts.u.HighPart >> Shift; RemainderParts.u.LowPart = (DividendParts.u.HighPart << ((sizeof(ULONG) * BITS_PER_BYTE) - Shift)) | (DividendParts.u.LowPart >> Shift); } /* Perform the division until shift is zero */ Carry = 0; while(Shift > 0) { /* Shift the remainder and the quotient */ RemainderParts.u.HighPart = (RemainderParts.u.HighPart << 1) | (RemainderParts.u.LowPart >> ((sizeof(ULONG) * BITS_PER_BYTE) - 1)); RemainderParts.u.LowPart = (RemainderParts.u.LowPart << 1) | (QuotientParts.u.HighPart >> ((sizeof(ULONG) * BITS_PER_BYTE) - 1)); QuotientParts.u.HighPart = (QuotientParts.u.HighPart << 1) | (QuotientParts.u.LowPart >> ((sizeof(ULONG) * BITS_PER_BYTE) - 1)); QuotientParts.u.LowPart = (QuotientParts.u.LowPart << 1) | Carry; /* Set the carry and subtract the divisor */ Difference = (LONGLONG)(DivisorParts.QuadPart - RemainderParts.QuadPart - 1) >> ((sizeof(ULONGLONG) * BITS_PER_BYTE) - 1); Carry = Difference & 0x1; RemainderParts.QuadPart -= DivisorParts.QuadPart & Difference; Shift -= 1; } /* Add the carry to the quotient */ QuotientParts.QuadPart = (QuotientParts.QuadPart << 1) | Carry; /* Check if remainder provided */ if(Remainder != NULL) { /* Calculate the remainder */ *Remainder = RemainderParts.QuadPart; } /* Return the quotient */ return QuotientParts.QuadPart; } /** * Divides a signed large integer by a 32-bit divisor. * * @param Dividend * Supplies a large integer to be divided. * * @param Divisor * Supplies a 32-bit divisor. * * @param Remainder * Supplies a pointer that receives the divide remainder. * * @return This routine returns the quotient. * * @since XT 1.0 */ XTAPI LARGE_INTEGER RtlDivideLargeInteger(IN LARGE_INTEGER Dividend, IN ULONG Divisor, OUT PULONG Remainder) { LONGLONG DividendSign, UDividend; LARGE_INTEGER LargeInt; /* Remove the sign bit from dividend if present */ DividendSign = Dividend.QuadPart >> ((sizeof(LONGLONG) * BITS_PER_BYTE) - 1); UDividend = (Dividend.QuadPart ^ DividendSign) - DividendSign; /* Calculate the quotient */ LargeInt.QuadPart = (RtlDivideUnsigned64(UDividend, Divisor, NULL) ^ DividendSign) - DividendSign; /* Make sure a pointer to remainder provided */ if(Remainder) { /* Calculate remainder */ *Remainder = Dividend.QuadPart - (LargeInt.QuadPart * Divisor); } /* Return the quotient */ return LargeInt; } /** * Multiplies a signed large integer by a signed integer. * * @param Multiplicand * Supplies a large integer to be multiplied. * * @param Multiplier * Supplies an integer by which the large integer is multiplied. * * @return This routine returns the result of the multiplication. * * @since XT 1.0 */ XTAPI LARGE_INTEGER RtlMultiplyLargeInteger(IN LARGE_INTEGER Multiplicand, IN LONG Multiplier) { LARGE_INTEGER LargeInt; /* Perform multiplication and return the result */ LargeInt.QuadPart = (LONGLONG) Multiplicand.QuadPart * Multiplier; return LargeInt; }