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

Code before:

            case VNF_MDARR_LENGTH:
            case VNF_ARR_LENGTH:
                result.lLimit = Limit(Limit::keConstant, 0);
                result.uLimit = Limit(Limit::keConstant, CORINFO_Array_MaxLength);
                break;

            case VNF_GT:
            case VNF_GT_UN:
            case VNF_GE:
            case VNF_GE_UN:
            case VNF_LT:
            case VNF_LT_UN:
            case VNF_LE:
            case VNF_LE_UN:
            case VNF_EQ:
            case VNF_NE:
            {
                // These always return 0 or 1 (range is [0..1])
                result.lLimit = Limit(Limit::keConstant, 0);
                result.uLimit = Limit(Limit::keConstant, 1);

                // But maybe we can do better and determine if they are always true or always false,
                // hence, return [1..1] or [0..0]
                if ((comp->vnStore->TypeOfVN(funcApp.m_args[0]) == TYP_INT) &&
                    (comp->vnStore->TypeOfVN(funcApp.m_args[1]) == TYP_INT))
                {
                    Range r1 = GetRangeFromAssertions(comp, funcApp.m_args[0], assertions, --budget);
                    Range r2 = GetRangeFromAssertions(comp, funcApp.m_args[1], assertions, --budget);

                    bool       isUnsigned = true;
                    genTreeOps cmpOper;

                    // Normalize the unsigned comparison operators.
                    if (funcApp.m_func == VNF_GT_UN)
                        cmpOper = GT_GT;
                    else if (funcApp.m_func == VNF_GE_UN)
                        cmpOper = GT_GE;
                    else if (funcApp.m_func == VNF_LT_UN)
                        cmpOper = GT_LT;
                    else if (funcApp.m_func == VNF_LE_UN)
                        cmpOper = GT_LE;
                    else
                    {
                        isUnsigned = false;
                        cmpOper    = static_cast<genTreeOps>(funcApp.m_func);
                    }

                    result = RangeOps::EvalRelop(cmpOper, isUnsigned, r1, r2);
                }
                break;

Review comment (suggestion):
This change mitigates some of the regressions by removed `optImpliedByConstAssertion`:

We had `byteX = 47` assertion and we added an implied `byteX != 44` assertion via `optImpliedByConstAssertion`. `byteX != 44` assertion helped to fold `if (byteX != 44)` JTRUE via `optLocalAssertionIsEqualOrNotEqual`. It is nice, but it's exactly what `RangeCheck::GetRangeFromAssertions` was supposed to fold purely from the `byteX = 47` assertion. It turned out `RangeCheck::GetRangeFromAssertions` was giving up on non `TYP_INT` args (arg0 here is UBYTE and arg1 is TYP_INT) for relops, hence, the change.

Code after:

            case VNF_MDARR_LENGTH:
            case VNF_ARR_LENGTH:
                result.lLimit = Limit(Limit::keConstant, 0);
                result.uLimit = Limit(Limit::keConstant, CORINFO_Array_MaxLength);
                break;

            case VNF_GT:
            case VNF_GT_UN:
            case VNF_GE:
            case VNF_GE_UN:
            case VNF_LT:
            case VNF_LT_UN:
            case VNF_LE:
            case VNF_LE_UN:
            case VNF_EQ:
            case VNF_NE:
            {
                // These always return 0 or 1 (range is [0..1])
                result.lLimit = Limit(Limit::keConstant, 0);
                result.uLimit = Limit(Limit::keConstant, 1);

                // But maybe we can do better and determine if they are always true or always false,
                // hence, return [1..1] or [0..0]
                if ((genActualType(comp->vnStore->TypeOfVN(funcApp.m_args[0])) == TYP_INT) &&
                    (genActualType(comp->vnStore->TypeOfVN(funcApp.m_args[1])) == TYP_INT))
                {
                    Range r1 = GetRangeFromAssertions(comp, funcApp.m_args[0], assertions, --budget);
                    Range r2 = GetRangeFromAssertions(comp, funcApp.m_args[1], assertions, --budget);

                    bool       isUnsigned = true;
                    genTreeOps cmpOper;

                    // Normalize the unsigned comparison operators.
                    if (funcApp.m_func == VNF_GT_UN)
                        cmpOper = GT_GT;
                    else if (funcApp.m_func == VNF_GE_UN)
                        cmpOper = GT_GE;
                    else if (funcApp.m_func == VNF_LT_UN)
                        cmpOper = GT_LT;
                    else if (funcApp.m_func == VNF_LE_UN)
                        cmpOper = GT_LE;
                    else
                    {
                        isUnsigned = false;
                        cmpOper    = static_cast<genTreeOps>(funcApp.m_func);
                    }

                    result = RangeOps::EvalRelop(cmpOper, isUnsigned, r1, r2);
                }
                break;