Skip to content

Commit

Permalink
JIT: (x u>> cns) -> [0..(x's max value >> cns)] (dotnet#109900)
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo authored Nov 20, 2024
1 parent 1c54b48 commit 50cbcb3
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
29 changes: 24 additions & 5 deletions src/coreclr/jit/rangecheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DE
// Compute the range for a binary operation.
Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool monIncreasing DEBUGARG(int indent))
{
assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_MUL));
assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL));

GenTree* op1 = binop->gtGetOp1();
GenTree* op2 = binop->gtGetOp2();
Expand All @@ -1036,7 +1036,7 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool
}

// Special cases for binops where op2 is a constant
if (binop->OperIs(GT_AND, GT_RSH, GT_LSH, GT_UMOD))
if (binop->OperIs(GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD))
{
if (!op2IsCns)
{
Expand Down Expand Up @@ -1073,6 +1073,25 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool
icon = binop->OperIs(GT_RSH) ? (icon1 >> icon2) : (icon1 << icon2);
}
}
else if (binop->OperIs(GT_RSZ))
{
// (x u>> cns) -> [0..(x's max value >> cns)]
int shiftBy = static_cast<int>(op2->AsIntCon()->IconValue());
if (shiftBy < 0)
{
return Range(Limit::keUnknown);
}

int op1Width = (int)(genTypeSize(op1) * BITS_PER_BYTE);
if (shiftBy >= op1Width)
{
return Range(Limit(Limit::keConstant, 0));
}

// Calculate max possible value of op1, e.g. UINT_MAX for TYP_INT/TYP_UINT
uint64_t maxValue = (1ULL << op1Width) - 1;
icon = (int)(maxValue >> static_cast<int>(op2->AsIntCon()->IconValue()));
}

if (icon >= 0)
{
Expand All @@ -1088,7 +1107,7 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool
}

// other operators are expected to be handled above.
assert(binop->OperIs(GT_ADD, GT_MUL, GT_LSH, GT_RSH));
assert(binop->OperIs(GT_ADD, GT_MUL, GT_LSH, GT_RSH, GT_RSZ));

Range* op1RangeCached = nullptr;
Range op1Range = Limit(Limit::keUndef);
Expand Down Expand Up @@ -1453,7 +1472,7 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr, const Ran
}
// These operators don't overflow.
// Actually, GT_LSH can overflow so it depends on the analysis done in ComputeRangeForBinOp
else if (expr->OperIs(GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_NEG))
else if (expr->OperIs(GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_NEG))
{
overflows = false;
}
Expand Down Expand Up @@ -1547,7 +1566,7 @@ Range RangeCheck::ComputeRange(BasicBlock* block, GenTree* expr, bool monIncreas
MergeAssertion(block, expr, &range DEBUGARG(indent + 1));
}
// compute the range for binary operation
else if (expr->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_MUL))
else if (expr->OperIs(GT_ADD, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL))
{
range = ComputeRangeForBinOp(block, expr->AsOp(), monIncreasing DEBUGARG(indent + 1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,9 @@ private static int Log2SoftwareFallback(uint value)
value |= value >> 08;
value |= value >> 16;

// uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
return Unsafe.AddByteOffset(
// Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u
ref MemoryMarshal.GetReference(Log2DeBruijn),
// uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here
(IntPtr)(int)((value * 0x07C4ACDDu) >> 27));
// Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u
// uint.MaxValue >> 27 is always in range [0 - 31] so no bounds check
return Log2DeBruijn[(int)((value * 0x07C4ACDDu) >> 27)];
}

private static float CreateSingleNaN(bool sign, ulong significand)
Expand Down

0 comments on commit 50cbcb3

Please sign in to comment.