Skip to content

Commit

Permalink
Optimize division by constant after AND or RSZ (dotnet#55778)
Browse files Browse the repository at this point in the history
* Optimize division by constant after AND or RSZ

* Address PR feedback
  • Loading branch information
pentp authored Oct 4, 2021
1 parent 910278c commit 7afb662
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 24 deletions.
33 changes: 28 additions & 5 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5215,10 +5215,33 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod)
int postShift;
bool simpleMul = false;

unsigned bits = type == TYP_INT ? 32 : 64;
// if the dividend operand is AND or RSZ with a constant then the number of input bits can be reduced
if (dividend->OperIs(GT_AND) && dividend->gtGetOp2()->IsCnsIntOrI())
{
size_t maskCns = static_cast<size_t>(dividend->gtGetOp2()->AsIntCon()->IconValue());
if (maskCns != 0)
{
unsigned maskBits = 1;
while (maskCns >>= 1)
maskBits++;
if (maskBits < bits)
bits = maskBits;
}
}
else if (dividend->OperIs(GT_RSZ) && dividend->gtGetOp2()->IsCnsIntOrI())
{
size_t shiftCns = static_cast<size_t>(dividend->gtGetOp2()->AsIntCon()->IconValue());
if (shiftCns < bits)
{
bits -= static_cast<unsigned>(shiftCns);
}
}

if (type == TYP_INT)
{
magic =
MagicDivide::GetUnsigned32Magic(static_cast<uint32_t>(divisorValue), &increment, &preShift, &postShift);
magic = MagicDivide::GetUnsigned32Magic(static_cast<uint32_t>(divisorValue), &increment, &preShift,
&postShift, bits);

#ifdef TARGET_64BIT
// avoid inc_saturate/multiple shifts by widening to 32x64 MULHI
Expand All @@ -5230,7 +5253,7 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod)
))
{
magic = MagicDivide::GetUnsigned64Magic(static_cast<uint64_t>(divisorValue), &increment, &preShift,
&postShift, 32);
&postShift, bits);
}
// otherwise just widen to regular multiplication
else
Expand All @@ -5243,8 +5266,8 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod)
else
{
#ifdef TARGET_64BIT
magic =
MagicDivide::GetUnsigned64Magic(static_cast<uint64_t>(divisorValue), &increment, &preShift, &postShift);
magic = MagicDivide::GetUnsigned64Magic(static_cast<uint64_t>(divisorValue), &increment, &preShift,
&postShift, bits);
#else
unreached();
#endif
Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/jit/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2414,15 +2414,18 @@ T GetUnsignedMagic(T d, bool* increment /*out*/, int* preShift /*out*/, int* pos
}
}

uint32_t GetUnsigned32Magic(uint32_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/)
uint32_t GetUnsigned32Magic(
uint32_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/, unsigned bits)
{
return GetUnsignedMagic<uint32_t>(d, increment, preShift, postShift, 32);
assert(bits <= 32);
return GetUnsignedMagic<uint32_t>(d, increment, preShift, postShift, bits);
}

#ifdef TARGET_64BIT
uint64_t GetUnsigned64Magic(
uint64_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/, unsigned bits)
{
assert(bits <= 64);
return GetUnsignedMagic<uint64_t>(d, increment, preShift, postShift, bits);
}
#endif
Expand Down
5 changes: 3 additions & 2 deletions src/coreclr/jit/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -761,10 +761,11 @@ class CritSecHolder

namespace MagicDivide
{
uint32_t GetUnsigned32Magic(uint32_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/);
uint32_t GetUnsigned32Magic(
uint32_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/, unsigned bits);
#ifdef TARGET_64BIT
uint64_t GetUnsigned64Magic(
uint64_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/, unsigned bits = 64);
uint64_t d, bool* increment /*out*/, int* preShift /*out*/, int* postShift /*out*/, unsigned bits);
#endif
int32_t GetSigned32Magic(int32_t d, int* shift /*out*/);
#ifdef TARGET_64BIT
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2528,14 +2528,14 @@ private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int
private static int ToBase64_CalculateAndValidateOutputLength(int inputLength, bool insertLineBreaks)
{
// the base length - we want integer division here, at most 4 more chars for the remainder
long outlen = ((long)inputLength + 2) / 3 * 4;
uint outlen = ((uint)inputLength + 2) / 3 * 4;

if (outlen == 0)
return 0;

if (insertLineBreaks)
{
(long newLines, long remainder) = Math.DivRem(outlen, base64LineBreakPosition);
(uint newLines, uint remainder) = Math.DivRem(outlen, base64LineBreakPosition);
if (remainder == 0)
{
--newLines;
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace System
// Maps to December 31 year 9999. The value calculated from "new DateTime(9999, 12, 31).Ticks / TimeSpan.TicksPerDay"
private const int MaxDayNumber = 3_652_058;

private static int DayNumberFromDateTime(DateTime dt) => (int)(dt.Ticks / TimeSpan.TicksPerDay);
private static int DayNumberFromDateTime(DateTime dt) => (int)((ulong)dt.Ticks / TimeSpan.TicksPerDay);

private DateTime GetEquivalentDateTime() => DateTime.UnsafeCreate(_dayNumber * TimeSpan.TicksPerDay);

Expand Down Expand Up @@ -97,7 +97,7 @@ public static DateOnly FromDayNumber(int dayNumber)
/// <summary>
/// Gets the day of the week represented by this instance.
/// </summary>
public DayOfWeek DayOfWeek => GetEquivalentDateTime().DayOfWeek;
public DayOfWeek DayOfWeek => (DayOfWeek)(((uint)_dayNumber + 1) % 7);

/// <summary>
/// Gets the day of the year represented by this instance.
Expand Down
14 changes: 3 additions & 11 deletions src/libraries/System.Private.CoreLib/src/System/DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -461,17 +461,9 @@ public DateTime AddMonths(int months)
GetDate(out int year, out int month, out int day);
int y = year, d = day;
int m = month + months;
if (m > 0)
{
int q = (int)((uint)(m - 1) / 12);
y += q;
m -= q * 12;
}
else
{
y += m / 12 - 1;
m = 12 + m % 12;
}
int q = m > 0 ? (int)((uint)(m - 1) / 12) : m / 12 - 1;
y += q;
m -= q * 12;
if (y < 1 || y > 9999) ThrowDateArithmetic(2);
uint[] daysTo = IsLeapYear(y) ? s_daysToMonth366 : s_daysToMonth365;
uint daysToMonth = daysTo[m - 1];
Expand Down

0 comments on commit 7afb662

Please sign in to comment.