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

Code before:
                        if (current == m_op)
                        {
                            // We've found the op - stop the search.
                            return fgWalkResult::WALK_ABORT;
                        }

                        if (current->GeneratesAssertion())
                        {
                            AssertionInfo info = current->GetAssertionInfo();
                            // Normally, we extend the assertions by calling optImpliedAssertions, but that
                            // doesn't seem to improve anything here, so we just add the assertion directly.
                            BitVecOps::AddElemD(m_compiler->apTraits, *m_assertions, info.GetAssertionIndex() - 1);
                        }
                        return fgWalkResult::WALK_CONTINUE;
                    }
                };

                TreeAssertionVisitor   visitor(m_pCompiler, op, &assertions);
                Compiler::fgWalkResult result = visitor.WalkTree(stmt->GetRootNodePointer(), nullptr);
                if (result != Compiler::fgWalkResult::WALK_CONTINUE)
                {
                    treeFound = true;
                    break;
                }
            }
            assert(treeFound);
        }
    }

    if (!BitVecOps::MayBeUninit(assertions))
    {
        // Perform the merge step to fine tune the range value.
        MergeEdgeAssertions(op->AsLclVarCommon(), assertions, pRange);
    }
}

// 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_XOR, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL));

    // For XOR we only care about Log2 pattern for now
    if (binop->OperIs(GT_XOR))
    {
        int upperBound;
        if (m_pCompiler->vnStore->IsVNLog2(m_pCompiler->vnStore->VNConservativeNormalValue(binop->gtVNPair),
                                           &upperBound))
        {
            assert(upperBound > 0);
            return Range(Limit(Limit::keConstant, 0), Limit(Limit::keConstant, upperBound));
        }

Review comment (bug):
The assert will fire if `op` is not found in any statement in the block. This could happen in valid scenarios where the local node is in the block but not reachable through the statement walk (e.g., if it's in a different position than expected, or in edge cases with certain IR structures). Consider changing this to `assert(treeFound && "Failed to find op in block statements");` for better diagnostics, or removing the assert if false positives are expected.
```suggestion
            assert(treeFound && "Failed to find op in block statements");
```

Code after:
    {
        const BasicBlock* pred = op->AsPhiArg()->gtPredBB;
        assertions             = m_pCompiler->optGetEdgeAssertions(block, pred);
        if (!BitVecOps::MayBeUninit(assertions))
        {
            JITDUMP("Merge assertions created by " FMT_BB " for " FMT_BB "\n", pred->bbNum, block->bbNum);
            Compiler::optDumpAssertionIndices(assertions, "\n");
        }
    }
    // Get assertions from bbAssertionIn.
    else if (op->IsLocal())
    {
        assertions = block->bbAssertionIn;

        // bbAssertionIn is a bit conservative and will not include intra-block assertions.
        // e.g. created by GT_BOUNDS_CHECK nodes prior to the 'op' in the current block.
        // For that, we walk the trees in the block until we find "op" and collect assertions
        // along the way. It doesn't seem to be profitable for anything other than bounds checks
        // (ArrBnds assertions), so we limit the search to only those blocks that may have bounds
        // checks. It also helps reduce the cost of this search as it's not cheap.
        //
        if (block->HasFlag(BBF_MAY_HAVE_BOUNDS_CHECKS))
        {
            // We're going to be adding to 'assertions', so make a copy first.
            assertions = BitVecOps::MakeCopy(m_pCompiler->apTraits, assertions);

            // JIT-TP: Limit the search budget to avoid spending too much time here.
            int budget = 50;
            for (Statement* stmt : block->Statements())
            {
                AssertionsAccumulator visitor(m_pCompiler, budget, &assertions, op);
                if (visitor.WalkTree(stmt->GetRootNodePointer(), nullptr) == Compiler::fgWalkResult::WALK_ABORT)
                {
                    break;
                }
                budget = visitor.GetBudgetLeft();
            }
        }
    }

    if (!BitVecOps::MayBeUninit(assertions))
    {
        // Perform the merge step to fine tune the range value.
        MergeEdgeAssertions(op->AsLclVarCommon(), assertions, pRange);
    }
}

// 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_XOR, GT_AND, GT_RSH, GT_RSZ, GT_LSH, GT_UMOD, GT_MUL));