From 505e2f328dd891ea0b973dc9e446de03dd14b1fb Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 22 Jun 2022 12:50:17 -0700 Subject: [PATCH] Fix the handling of UInt128.DivideSlow on big endian platforms --- .../src/System/UInt128.cs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs index b2b9771ba567fc..9c2f675f457f88 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs @@ -1041,12 +1041,32 @@ unsafe static UInt128 DivideSlow(UInt128 quotient, UInt128 divisor) // we need to get a Span containing the value represented // in the least number of elements possible. + // We need to ensure that we end up with 4x uints representing the bits from + // least significant to most significant so the math will be correct on both + // little and big endian systems. So we'll just allocate the relevant buffer + // space and then write out the four parts using the native endianness of the + // system. + uint* pLeft = stackalloc uint[Size / sizeof(uint)]; - quotient.WriteLittleEndianUnsafe(new Span(pLeft, Size)); + + Unsafe.WriteUnaligned(ref *(byte*)(pLeft + 0), (uint)(quotient._lower >> 00)); + Unsafe.WriteUnaligned(ref *(byte*)(pLeft + 1), (uint)(quotient._lower >> 32)); + + Unsafe.WriteUnaligned(ref *(byte*)(pLeft + 2), (uint)(quotient._upper >> 00)); + Unsafe.WriteUnaligned(ref *(byte*)(pLeft + 3), (uint)(quotient._upper >> 32)); + Span left = new Span(pLeft, (Size / sizeof(uint)) - (BitOperations.LeadingZeroCount(quotient) / 32)); + // Repeat the same operation with the divisor + uint* pRight = stackalloc uint[Size / sizeof(uint)]; - divisor.WriteLittleEndianUnsafe(new Span(pRight, Size)); + + Unsafe.WriteUnaligned(ref *(byte*)(pRight + 0), (uint)(divisor._lower >> 00)); + Unsafe.WriteUnaligned(ref *(byte*)(pRight + 1), (uint)(divisor._lower >> 32)); + + Unsafe.WriteUnaligned(ref *(byte*)(pRight + 2), (uint)(divisor._upper >> 00)); + Unsafe.WriteUnaligned(ref *(byte*)(pRight + 3), (uint)(divisor._upper >> 32)); + Span right = new Span(pRight, (Size / sizeof(uint)) - (BitOperations.LeadingZeroCount(divisor) / 32)); Span rawBits = stackalloc uint[Size / sizeof(uint)];