Skip to content

Commit 1a4e790

Browse files
EgorBomikelle-rogers
authored andcommitted
JIT: (x u>> cns) -> [0..(x's max value >> cns)] (dotnet#109900)
1 parent b6f5917 commit 1a4e790

File tree

2 files changed

+27
-11
lines changed

2 files changed

+27
-11
lines changed

src/coreclr/jit/rangecheck.cpp

+24-5
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ void RangeCheck::MergeAssertion(BasicBlock* block, GenTree* op, Range* pRange DE
10141014
// Compute the range for a binary operation.
10151015
Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool monIncreasing DEBUGARG(int indent))
10161016
{
1017-
assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_MUL));
1017+
assert(binop->OperIs(GT_ADD, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL));
10181018

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

10381038
// Special cases for binops where op2 is a constant
1039-
if (binop->OperIs(GT_AND, GT_RSH, GT_LSH, GT_UMOD))
1039+
if (binop->OperIs(GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD))
10401040
{
10411041
if (!op2IsCns)
10421042
{
@@ -1073,6 +1073,25 @@ Range RangeCheck::ComputeRangeForBinOp(BasicBlock* block, GenTreeOp* binop, bool
10731073
icon = binop->OperIs(GT_RSH) ? (icon1 >> icon2) : (icon1 << icon2);
10741074
}
10751075
}
1076+
else if (binop->OperIs(GT_RSZ))
1077+
{
1078+
// (x u>> cns) -> [0..(x's max value >> cns)]
1079+
int shiftBy = static_cast<int>(op2->AsIntCon()->IconValue());
1080+
if (shiftBy < 0)
1081+
{
1082+
return Range(Limit::keUnknown);
1083+
}
1084+
1085+
int op1Width = (int)(genTypeSize(op1) * BITS_PER_BYTE);
1086+
if (shiftBy >= op1Width)
1087+
{
1088+
return Range(Limit(Limit::keConstant, 0));
1089+
}
1090+
1091+
// Calculate max possible value of op1, e.g. UINT_MAX for TYP_INT/TYP_UINT
1092+
uint64_t maxValue = (1ULL << op1Width) - 1;
1093+
icon = (int)(maxValue >> static_cast<int>(op2->AsIntCon()->IconValue()));
1094+
}
10761095

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

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

10931112
Range* op1RangeCached = nullptr;
10941113
Range op1Range = Limit(Limit::keUndef);
@@ -1453,7 +1472,7 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr, const Ran
14531472
}
14541473
// These operators don't overflow.
14551474
// Actually, GT_LSH can overflow so it depends on the analysis done in ComputeRangeForBinOp
1456-
else if (expr->OperIs(GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_NEG))
1475+
else if (expr->OperIs(GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_NEG))
14571476
{
14581477
overflows = false;
14591478
}
@@ -1547,7 +1566,7 @@ Range RangeCheck::ComputeRange(BasicBlock* block, GenTree* expr, bool monIncreas
15471566
MergeAssertion(block, expr, &range DEBUGARG(indent + 1));
15481567
}
15491568
// compute the range for binary operation
1550-
else if (expr->OperIs(GT_ADD, GT_AND, GT_RSH, GT_LSH, GT_UMOD, GT_MUL))
1569+
else if (expr->OperIs(GT_ADD, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL))
15511570
{
15521571
range = ComputeRangeForBinOp(block, expr->AsOp(), monIncreasing DEBUGARG(indent + 1));
15531572
}

src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs

+3-6
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,9 @@ private static int Log2SoftwareFallback(uint value)
107107
value |= value >> 08;
108108
value |= value >> 16;
109109

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

118115
private static float CreateSingleNaN(bool sign, ulong significand)

0 commit comments

Comments
 (0)