Example #1
0
//------------------------------------------------------------------------
// DecomposeShift: Decompose GT_LSH, GT_RSH, GT_RSZ. For shift nodes, we need to use
// the shift helper functions, so we here convert the shift into a helper call by
// pulling its arguments out of linear order and making them the args to a call, then
// replacing the original node with the new call.
//
// Arguments:
//    use - the LIR::Use object for the def that needs to be decomposed.
//
// Return Value:
//    The next node to process.
//
GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use)
{
    assert(use.IsInitialized());

    GenTree* tree   = use.Def();
    GenTree* gtLong = tree->gtGetOp1();
    genTreeOps oper = tree->OperGet();

    assert((oper == GT_LSH) || (oper == GT_RSH) || (oper == GT_RSZ));

    LIR::Use loOp1Use(Range(), &gtLong->gtOp.gtOp1, gtLong);
    loOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight);

    LIR::Use hiOp1Use(Range(), &gtLong->gtOp.gtOp2, gtLong);
    hiOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight);

    LIR::Use shiftWidthUse(Range(), &tree->gtOp.gtOp2, tree);
    shiftWidthUse.ReplaceWithLclVar(m_compiler, m_blockWeight);

    GenTree* loOp1 = gtLong->gtGetOp1();
    GenTree* hiOp1 = gtLong->gtGetOp2();

    GenTree* shiftWidthOp = tree->gtGetOp2();

    Range().Remove(gtLong);
    Range().Remove(loOp1);
    Range().Remove(hiOp1);

    Range().Remove(shiftWidthOp);

    // TODO-X86-CQ: If the shift operand is a GT_CNS_INT, we should pipe the instructions through to codegen
    // and generate the shift instructions ourselves there, rather than replacing it with a helper call.

    unsigned helper;

    switch (oper)
    {
    case GT_LSH:
        helper = CORINFO_HELP_LLSH;
        break;
    case GT_RSH:
        helper = CORINFO_HELP_LRSH;
        break;
    case GT_RSZ:
        helper = CORINFO_HELP_LRSZ;
        break;
    default:
        unreached();
    }

    GenTreeArgList* argList = m_compiler->gtNewArgList(loOp1, hiOp1, shiftWidthOp);

    GenTree* call = m_compiler->gtNewHelperCallNode(helper, TYP_LONG, 0, argList);

    GenTreeCall*    callNode    = call->AsCall();
    ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc();
    retTypeDesc->InitializeLongReturnType(m_compiler);

    call = m_compiler->fgMorphArgs(callNode);
    Range().InsertAfter(tree, LIR::SeqTree(m_compiler, call));

    Range().Remove(tree);
    use.ReplaceWith(m_compiler, call);
    return call;
}