Repository: dotnet/runtime
File: src/coreclr/jit/codegenwasm.cpp (C++)

Code before:
        }

        case GenIntCastDesc::CHECK_UINT_RANGE:
        {
            // (U)LONG to UINT
            assert(is64BitSrc);
            GetEmitter()->emitIns_I(INS_i64_const, srcSize, UINT32_MAX);
            // We can re-interpret LONG as ULONG
            // Then negative values will be larger than UINT32_MAX
            GetEmitter()->emitIns(INS_i64_gt_u);
            genJumpToThrowHlpBlk(SCK_OVERFLOW);
            break;
        }

        case GenIntCastDesc::CHECK_POSITIVE_INT_RANGE:
        {
            // ULONG to INT
            GetEmitter()->emitIns_I(INS_i64_const, srcSize, INT32_MAX);
            GetEmitter()->emitIns(INS_i64_gt_u);
            genJumpToThrowHlpBlk(SCK_OVERFLOW);
            break;
        }

        case GenIntCastDesc::CHECK_INT_RANGE:
        {
            // LONG to INT
            GetEmitter()->emitIns(INS_i64_extend32_s);
            GetEmitter()->emitIns_I(INS_local_get, srcSize, WasmRegToIndex(reg));
            GetEmitter()->emitIns(INS_i64_ne);
            genJumpToThrowHlpBlk(SCK_OVERFLOW);
            break;
        }

        case GenIntCastDesc::CHECK_SMALL_INT_RANGE:
        {
            // (U)(INT|LONG) to Small INT
            const int castMaxValue = desc.CheckSmallIntMax();
            const int castMinValue = desc.CheckSmallIntMin();

            if (castMinValue == 0)
            {
                // When the minimum is 0, a single unsigned upper-bound check is sufficient.
                // For signed sources, negative values become large unsigned values and
                // thus also trigger the overflow via the same comparison.
                GetEmitter()->emitIns_I(is64BitSrc ? INS_i64_const : INS_i32_const, srcSize, castMaxValue);
                GetEmitter()->emitIns(is64BitSrc ? INS_i64_gt_u : INS_i32_gt_u);
            }
            else
            {
                assert(!cast->IsUnsigned());
                GetEmitter()->emitIns_I(is64BitSrc ? INS_i64_const : INS_i32_const, srcSize, castMaxValue);

Review comment (suggestion):
~~I'm not sure we can do `i64.extend32_s` unconditionally here, because that op code expects an i32 as input and we are expecting an i64 at the top of the value stack right?~~
Never mind, I saw Single's earlier comment. The MDN docs seem to be out of sync with the spec on this!

Code after:

        case GenIntCastDesc::CHECK_UINT_RANGE:
        {
            // (U)LONG to UINT
            assert(is64BitSrc);
            GetEmitter()->emitIns_I(INS_i64_const, srcSize, UINT32_MAX);
            // We can re-interpret LONG as ULONG
            // Then negative values will be larger than UINT32_MAX
            GetEmitter()->emitIns(INS_i64_gt_u);
            genJumpToThrowHlpBlk(SCK_OVERFLOW);
            break;
        }

        case GenIntCastDesc::CHECK_POSITIVE_INT_RANGE:
        {
            // ULONG to INT
            GetEmitter()->emitIns_I(INS_i64_const, srcSize, INT32_MAX);
            GetEmitter()->emitIns(INS_i64_gt_u);
            genJumpToThrowHlpBlk(SCK_OVERFLOW);
            break;
        }

        case GenIntCastDesc::CHECK_INT_RANGE:
        {
            // LONG to INT
            GetEmitter()->emitIns(INS_i64_extend32_s);
            GetEmitter()->emitIns_I(INS_local_get, srcSize, WasmRegToIndex(reg));
            GetEmitter()->emitIns(INS_i64_ne);
            genJumpToThrowHlpBlk(SCK_OVERFLOW);
            break;
        }

        case GenIntCastDesc::CHECK_SMALL_INT_RANGE:
        {
            // (U)(INT|LONG) to Small INT
            const int castMaxValue = desc.CheckSmallIntMax();
            const int castMinValue = desc.CheckSmallIntMin();

            if (castMinValue == 0)
            {
                // When the minimum is 0, a single unsigned upper-bound check is sufficient.
                // For signed sources, negative values become large unsigned values and
                // thus also trigger the overflow via the same comparison.
                GetEmitter()->emitIns_I(is64BitSrc ? INS_i64_const : INS_i32_const, srcSize, castMaxValue);
                GetEmitter()->emitIns(is64BitSrc ? INS_i64_gt_u : INS_i32_gt_u);
            }
            else
            {
                // We need to check a range around zero, eg [-128, 127] for 8-bit signed.
                // Do two compares and combine the results: (src > max) | (src < min).
                assert(!cast->IsUnsigned());