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

Code before:
        {
            assert(toType == TYP_LONG);
            ins = INS_i64_extend_u_i32;
            break;
        }
        case GenIntCastDesc::ExtendKind::SIGN_EXTEND_INT:
        {
            assert(toType == TYP_LONG);
            ins = INS_i64_extend_s_i32;
            break;
        }
        default:
            unreached();
    }

    if (ins != INS_none)
    {
        GetEmitter()->emitIns(ins);
    }
    genProduceReg(cast);
}

void CodeGen::genFloatToIntCast(GenTree* tree)
{
    var_types   toType     = genActualType(tree->TypeGet());
    var_types   fromType   = genActualType(tree->AsCast()->CastFromType());
    bool        isUnsigned = varTypeIsUnsigned(tree->AsCast()->CastToType());
    instruction ins        = INS_none;
    assert(varTypeIsFloating(fromType) && (toType == TYP_INT || toType == TYP_LONG));

    genConsumeRegs(tree->AsCast()->CastOp());

    switch (PackTypes(toType, fromType))
    {
        case PackTypes(TYP_INT, TYP_FLOAT):
            ins = isUnsigned ? INS_i32_trunc_sat_f32_u : INS_i32_trunc_sat_f32_s;
            break;
        case PackTypes(TYP_INT, TYP_DOUBLE):
            ins = isUnsigned ? INS_i32_trunc_sat_f64_u : INS_i32_trunc_sat_f64_s;
            break;
        case PackTypes(TYP_LONG, TYP_FLOAT):
            ins = isUnsigned ? INS_i64_trunc_sat_f32_u : INS_i64_trunc_sat_f32_s;
            break;
        case PackTypes(TYP_LONG, TYP_DOUBLE):
            ins = isUnsigned ? INS_i64_trunc_sat_f64_u : INS_i64_trunc_sat_f64_s;
            break;
        default:
            unreached();
    }

    GetEmitter()->emitIns(ins);

Review comment (suggestion):
```suggestion
    var_types   toType     = tree->TypeGet();
    var_types   fromType   = tree->AsCast()->CastOp()->TypeGet();
```
1) Cast nodes are always of an "actual" type.
2) For FP types the actual type is a no-op.

Code after:
    BBswtDesc* const desc      = block->GetSwitchTargets();
    unsigned const   caseCount = desc->GetCaseCount();

    // We don't expect degenerate or default-less switches
    //
    assert(caseCount > 0);
    assert(desc->HasDefaultCase());

    GetEmitter()->emitIns_I(INS_br_table, EA_4BYTE, caseCount);

    for (unsigned caseNum = 0; caseNum < caseCount; caseNum++)
    {
        BasicBlock* const caseTarget = desc->GetCase(caseNum)->getDestinationBlock();
        unsigned          depth      = findTargetDepth(caseTarget);

        GetEmitter()->emitIns_J(INS_label, EA_4BYTE, depth, caseTarget);
    }
}

//------------------------------------------------------------------------
// PackOperAndType: Pack a genTreeOps and var_types into a uint32_t
//
// Arguments:
//    oper - a genTreeOps to pack
//    type - a var_types to pack
//
// Return Value:
//    oper and type packed into an integer that can be used as a switch value/case
//
static constexpr uint32_t PackOperAndType(genTreeOps oper, var_types type)
{
    if ((type == TYP_BYREF) || (type == TYP_REF))
    {
        type = TYP_I_IMPL;
    }
    const int shift1 = ConstLog2<TYP_COUNT>::value + 1;
    return ((uint32_t)oper << shift1) | ((uint32_t)type);
}

// ------------------------------------------------------------------------
// PackTypes: Pack two var_types together into a uint32_t

// Arguments:
//    toType - a var_types to pack
//    fromType - a var_types to pack
//
// Return Value:
//    The two types packed together into an integer that can be used as a switch/value,
//    the primary use case being the handling of operations with two-type variants such
//    as casts.
//