diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp index 1fb068068e845..abc22d335fa6e 100644 --- a/src/coreclr/jit/rangecheck.cpp +++ b/src/coreclr/jit/rangecheck.cpp @@ -1014,13 +1014,13 @@ 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(); // 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 (!op2->IsIntCnsFitsInI32()) { @@ -1049,6 +1049,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(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(op2->AsIntCon()->IconValue())); + } if (icon >= 0) { @@ -1064,7 +1083,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); @@ -1429,7 +1448,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; } @@ -1523,7 +1542,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)); } diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs index 67d3c6afd31e6..d28b9b6f52728 100644 --- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs +++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/HalfHelpers.netstandard.cs @@ -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)