diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp index d0df8b9e17fa62..88dc10ae8908c8 100644 --- a/src/coreclr/jit/promotiondecomposition.cpp +++ b/src/coreclr/jit/promotiondecomposition.cpp @@ -781,13 +781,32 @@ class DecompositionPlan if (remainderStrategy.Type == RemainderStrategy::Primitive) { - GenTree* src; + GenTree* src = nullptr; if (m_src->OperIs(GT_LCL_VAR, GT_LCL_FLD)) { GenTreeLclVarCommon* srcLcl = m_src->AsLclVarCommon(); - src = m_compiler->gtNewLclFldNode(srcLcl->GetLclNum(), remainderStrategy.PrimitiveType, - srcLcl->GetLclOffs() + remainderStrategy.PrimitiveOffset); - m_compiler->lvaSetVarDoNotEnregister(srcLcl->GetLclNum() DEBUGARG(DoNotEnregisterReason::LocalField)); + + // Check if the source has a regularly promoted field at this offset. + LclVarDsc* srcLclDsc = m_compiler->lvaGetDesc(srcLcl); + unsigned srcLclOffs = srcLcl->GetLclOffs() + remainderStrategy.PrimitiveOffset; + + unsigned int fieldLcl = + srcLclDsc->lvPromoted ? m_compiler->lvaGetFieldLocal(srcLclDsc, srcLclOffs) : BAD_VAR_NUM; + if (fieldLcl != BAD_VAR_NUM) + { + LclVarDsc* dsc = m_compiler->lvaGetDesc(fieldLcl); + if (genTypeSize(dsc->lvType) == genTypeSize(remainderStrategy.PrimitiveType)) + { + src = m_compiler->gtNewLclvNode(fieldLcl, dsc->lvType); + } + } + + if (src == nullptr) + { + src = m_compiler->gtNewLclFldNode(srcLcl->GetLclNum(), remainderStrategy.PrimitiveType, srcLclOffs); + m_compiler->lvaSetVarDoNotEnregister(srcLcl->GetLclNum() + DEBUGARG(DoNotEnregisterReason::LocalField)); + } } else { @@ -796,18 +815,44 @@ class DecompositionPlan PropagateIndirFlags(src, indirFlags); } - GenTree* store; + GenTree* store = nullptr; if (m_store->OperIsLocalStore()) { GenTreeLclVarCommon* dstLcl = m_store->AsLclVarCommon(); - store = m_compiler->gtNewStoreLclFldNode(dstLcl->GetLclNum(), remainderStrategy.PrimitiveType, - dstLcl->GetLclOffs() + remainderStrategy.PrimitiveOffset, src); - m_compiler->lvaSetVarDoNotEnregister(dstLcl->GetLclNum() DEBUGARG(DoNotEnregisterReason::LocalField)); + + // Check if the destination has a regularly promoted field at this offset. + LclVarDsc* dstLclDsc = m_compiler->lvaGetDesc(dstLcl); + unsigned dstLclOffs = dstLcl->GetLclOffs() + remainderStrategy.PrimitiveOffset; + + unsigned int fieldLcl = + dstLclDsc->lvPromoted ? m_compiler->lvaGetFieldLocal(dstLclDsc, dstLclOffs) : BAD_VAR_NUM; + if (fieldLcl != BAD_VAR_NUM) + { + LclVarDsc* dsc = m_compiler->lvaGetDesc(fieldLcl); + if (genTypeSize(dsc->lvType) == genTypeSize(remainderStrategy.PrimitiveType)) + { + // Since the destination is regularly promoted the + // source must be physically promoted to get here. That + // means we always expect to see a LCL_FLD for the + // source here that we can retype to what matches the + // promoted field. + assert(src->OperIs(GT_LCL_FLD)); + src->gtType = dsc->lvType; + + store = m_compiler->gtNewStoreLclVarNode(fieldLcl, src); + } + } + + if (store == nullptr) + { + store = m_compiler->gtNewStoreLclFldNode(dstLcl->GetLclNum(), src->TypeGet(), dstLclOffs, src); + m_compiler->lvaSetVarDoNotEnregister(dstLcl->GetLclNum() + DEBUGARG(DoNotEnregisterReason::LocalField)); + } } else { - store = m_compiler->gtNewStoreIndNode(remainderStrategy.PrimitiveType, - grabAddr(remainderStrategy.PrimitiveOffset), src); + store = m_compiler->gtNewStoreIndNode(src->TypeGet(), grabAddr(remainderStrategy.PrimitiveOffset), src); PropagateIndirFlags(store, indirFlags); }