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

Code before:

                assert(trueEdge != nullptr);
                assert(falseEdge != nullptr);

                condNode->SetUnsigned();
                switchTree->AsOp()->gtOp1 = condNode;
                switchTree->AsOp()->gtOp1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);

                if (block->IsLIR())
                {
                    blockRange->InsertAfter(switchVal, maxCaseNode, condNode);
                    LIR::ReadOnlyRange range(maxCaseNode, switchTree);
                    m_pLowering->LowerRange(block, range);
                }
                else if (fgNodeThreading == NodeThreading::AllTrees)
                {
                    gtSetStmtInfo(switchStmt);
                    fgSetStmtSeq(switchStmt);
                }

                // Fix up dup counts: multiple switch cases originally pointed to the same
                // successor, but the conditional branch has exactly one edge per target.
                const unsigned trueDupCount = trueEdge->getDupCount();
                const unsigned falseDupCount = falseEdge->getDupCount();

                if (trueDupCount > 1)
                {
                    trueEdge->decrementDupCount(trueDupCount - 1);
                    trueEdge->getDestinationBlock()->bbRefs -= (trueDupCount - 1);
                }
                if (falseDupCount > 1)
                {
                    falseEdge->decrementDupCount(falseDupCount - 1);
                    falseEdge->getDestinationBlock()->bbRefs -= (falseDupCount - 1);
                }

                block->SetCond(trueEdge, falseEdge);

                // The switch-to-cond conversion preserved edge likelihoods but
                // successor block weights may be stale (they were set during import
                // based on the original switch topology). Recompute them so that
                // downstream passes like block compaction see correct weights.
                if (block->hasProfileWeight())
                {
                    if (caseDest->hasProfileWeight())
                    {
                        weight_t oldWeight = caseDest->bbWeight;
                        caseDest->setBBProfileWeight(caseDest->computeIncomingWeight());
                        JITDUMP("Updated " FMT_BB " (caseDest) profile weight from " FMT_WT " to " FMT_WT "\n",
                                caseDest->bbNum, oldWeight, caseDest->bbWeight);
                    }

Review comment (suggestion):
I don't follow this logic. We basically only need to adjust the `firstCaseEdge`'s dupCount - set it to 1. and adjust bbRefs of `firstCaseEdge`'s destionation block.
The defaultEdge and its destionation block is unchanged.

Code after:
        return false;
    }

    // If the local is address exposed, we currently can't optimize.
    //
    LclVarDsc* const lclDsc = lvaGetDesc(lclNum);

    if (lclDsc->IsAddressExposed())
    {
        return false;
    }

    Statement* const lastStmt  = block->lastStmt();
    Statement* const firstStmt = block->FirstNonPhiDef();

    if (lastStmt == nullptr)
    {
        return false;
    }

    // Tail duplication tends to pay off when the last statement
    // is a local store of a constant, arraylength, or a relop.
    // This is because these statements produce information about values
    // that would otherwise be lost at the upcoming merge point.
    //
    // Check up to N statements...
    //
    const int  limit = 2;
    int        count = 0;
    Statement* stmt  = lastStmt;

    while (count < limit)
    {
        count++;
        GenTree* const tree = stmt->GetRootNode();
        if (tree->OperIsLocalStore() && !tree->OperIsBlkOp() && (tree->AsLclVarCommon()->GetLclNum() == lclNum))
        {
            GenTree* const value = tree->Data();
            if (value->OperIsArrLength() || value->OperIsConst() || value->OperIsCompare())
            {
                return true;
            }
        }

        Statement* const prevStmt = stmt->GetPrevStmt();

        // The statement list prev links wrap from first->last, so exit
        // when we see lastStmt again, as we've now seen all statements.
        //
        if (prevStmt == lastStmt)
        {