//------------------------------------------------------------------------ // DecomposeNode: Decompose long-type trees into lower and upper halves. // // Arguments: // *ppTree - A node that may or may not require decomposition. // data - The tree-walk data that provides the context. // // Return Value: // None. It the tree at *ppTree is of TYP_LONG, it will generally be replaced. // void DecomposeLongs::DecomposeNode(GenTree** ppTree, Compiler::fgWalkData* data) { GenTree* tree = *ppTree; // Handle the case where we are implicitly using the lower half of a long lclVar. if ((tree->TypeGet() == TYP_INT) && tree->OperIsLocal()) { LclVarDsc* varDsc = m_compiler->lvaTable + tree->AsLclVarCommon()->gtLclNum; if (varTypeIsLong(varDsc) && varDsc->lvPromoted) { #ifdef DEBUG if (m_compiler->verbose) { printf("Changing implicit reference to lo half of long lclVar to an explicit reference of its promoted half:\n"); m_compiler->gtDispTree(tree); } #endif // DEBUG m_compiler->lvaDecRefCnts(tree); unsigned loVarNum = varDsc->lvFieldLclStart; tree->AsLclVarCommon()->SetLclNum(loVarNum); m_compiler->lvaIncRefCnts(tree); return; } } if (tree->TypeGet() != TYP_LONG) { return; } #ifdef DEBUG if (m_compiler->verbose) { printf("Decomposing TYP_LONG tree. BEFORE:\n"); m_compiler->gtDispTree(tree); } #endif // DEBUG switch (tree->OperGet()) { case GT_PHI: case GT_PHI_ARG: break; case GT_LCL_VAR: DecomposeLclVar(ppTree, data); break; case GT_LCL_FLD: DecomposeLclFld(ppTree, data); break; case GT_STORE_LCL_VAR: DecomposeStoreLclVar(ppTree, data); break; case GT_CAST: DecomposeCast(ppTree, data); break; case GT_CNS_LNG: DecomposeCnsLng(ppTree, data); break; case GT_CALL: DecomposeCall(ppTree, data); break; case GT_RETURN: assert(tree->gtOp.gtOp1->OperGet() == GT_LONG); break; case GT_STOREIND: DecomposeStoreInd(ppTree, data); break; case GT_STORE_LCL_FLD: assert(tree->gtOp.gtOp1->OperGet() == GT_LONG); NYI("st.lclFld of of TYP_LONG"); break; case GT_IND: DecomposeInd(ppTree, data); break; case GT_NOT: DecomposeNot(ppTree, data); break; case GT_NEG: DecomposeNeg(ppTree, data); break; // Binary operators. Those that require different computation for upper and lower half are // handled by the use of GetHiOper(). case GT_ADD: case GT_SUB: case GT_OR: case GT_XOR: case GT_AND: DecomposeArith(ppTree, data); break; case GT_MUL: NYI("Arithmetic binary operators on TYP_LONG - GT_MUL"); break; case GT_DIV: NYI("Arithmetic binary operators on TYP_LONG - GT_DIV"); break; case GT_MOD: NYI("Arithmetic binary operators on TYP_LONG - GT_MOD"); break; case GT_UDIV: NYI("Arithmetic binary operators on TYP_LONG - GT_UDIV"); break; case GT_UMOD: NYI("Arithmetic binary operators on TYP_LONG - GT_UMOD"); break; case GT_LSH: case GT_RSH: case GT_RSZ: NYI("Arithmetic binary operators on TYP_LONG - SHIFT"); break; case GT_ROL: case GT_ROR: NYI("Arithmetic binary operators on TYP_LONG - ROTATE"); break; case GT_MULHI: NYI("Arithmetic binary operators on TYP_LONG - MULHI"); break; case GT_LOCKADD: case GT_XADD: case GT_XCHG: case GT_CMPXCHG: NYI("Interlocked operations on TYP_LONG"); break; default: { JITDUMP("Illegal TYP_LONG node %s in Decomposition.", GenTree::NodeName(tree->OperGet())); noway_assert(!"Illegal TYP_LONG node in Decomposition."); break; } } #ifdef DEBUG if (m_compiler->verbose) { printf(" AFTER:\n"); m_compiler->gtDispTree(*ppTree); } #endif }
//------------------------------------------------------------------------ // DecomposeNode: Decompose long-type trees into lower and upper halves. // // Arguments: // use - the LIR::Use object for the def that needs to be decomposed. // // Return Value: // The next node to process. // GenTree* DecomposeLongs::DecomposeNode(GenTree* tree) { // Handle the case where we are implicitly using the lower half of a long lclVar. if ((tree->TypeGet() == TYP_INT) && tree->OperIsLocal()) { LclVarDsc* varDsc = m_compiler->lvaTable + tree->AsLclVarCommon()->gtLclNum; if (varTypeIsLong(varDsc) && varDsc->lvPromoted) { #ifdef DEBUG if (m_compiler->verbose) { printf("Changing implicit reference to lo half of long lclVar to an explicit reference of its promoted " "half:\n"); m_compiler->gtDispTreeRange(Range(), tree); } #endif // DEBUG m_compiler->lvaDecRefCnts(tree); unsigned loVarNum = varDsc->lvFieldLclStart; tree->AsLclVarCommon()->SetLclNum(loVarNum); m_compiler->lvaIncRefCnts(tree); return tree->gtNext; } } if (tree->TypeGet() != TYP_LONG) { return tree->gtNext; } #ifdef DEBUG if (m_compiler->verbose) { printf("Decomposing TYP_LONG tree. BEFORE:\n"); m_compiler->gtDispTreeRange(Range(), tree); } #endif // DEBUG LIR::Use use; if (!Range().TryGetUse(tree, &use)) { use = LIR::Use::GetDummyUse(Range(), tree); } GenTree* nextNode = nullptr; switch (tree->OperGet()) { case GT_LCL_VAR: nextNode = DecomposeLclVar(use); break; case GT_LCL_FLD: nextNode = DecomposeLclFld(use); break; case GT_STORE_LCL_VAR: nextNode = DecomposeStoreLclVar(use); break; case GT_CAST: nextNode = DecomposeCast(use); break; case GT_CNS_LNG: nextNode = DecomposeCnsLng(use); break; case GT_CALL: nextNode = DecomposeCall(use); break; case GT_RETURN: assert(tree->gtOp.gtOp1->OperGet() == GT_LONG); break; case GT_STOREIND: nextNode = DecomposeStoreInd(use); break; case GT_STORE_LCL_FLD: assert(tree->gtOp.gtOp1->OperGet() == GT_LONG); NYI("st.lclFld of of TYP_LONG"); break; case GT_IND: nextNode = DecomposeInd(use); break; case GT_NOT: nextNode = DecomposeNot(use); break; case GT_NEG: nextNode = DecomposeNeg(use); break; // Binary operators. Those that require different computation for upper and lower half are // handled by the use of GetHiOper(). case GT_ADD: case GT_SUB: case GT_OR: case GT_XOR: case GT_AND: nextNode = DecomposeArith(use); break; case GT_MUL: nextNode = DecomposeMul(use); break; case GT_DIV: NYI("Arithmetic binary operators on TYP_LONG - GT_DIV"); break; case GT_MOD: NYI("Arithmetic binary operators on TYP_LONG - GT_MOD"); break; case GT_UDIV: NYI("Arithmetic binary operators on TYP_LONG - GT_UDIV"); break; case GT_UMOD: NYI("Arithmetic binary operators on TYP_LONG - GT_UMOD"); break; case GT_LSH: case GT_RSH: case GT_RSZ: nextNode = DecomposeShift(use); break; case GT_ROL: case GT_ROR: NYI("Arithmetic binary operators on TYP_LONG - ROTATE"); break; case GT_MULHI: NYI("Arithmetic binary operators on TYP_LONG - MULHI"); break; case GT_LOCKADD: case GT_XADD: case GT_XCHG: case GT_CMPXCHG: NYI("Interlocked operations on TYP_LONG"); break; default: { JITDUMP("Illegal TYP_LONG node %s in Decomposition.", GenTree::NodeName(tree->OperGet())); noway_assert(!"Illegal TYP_LONG node in Decomposition."); break; } } #ifdef DEBUG if (m_compiler->verbose) { // NOTE: st_lcl_var doesn't dump properly afterwards. printf("Decomposing TYP_LONG tree. AFTER:\n"); m_compiler->gtDispTreeRange(Range(), use.Def()); } #endif return nextNode; }