From 3fded0bb77c852b10d712bd629ced740499a3aa6 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Thu, 8 Jun 2023 22:20:44 +0200 Subject: [PATCH] JIT: Handle primitive remainder stores to regularly promoted fields in physical promotion (#87217) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit If the remainder of a block copy is handled as a primitive, then it is possible that the destination or source is a regularly promoted field. In this case we do not have to DNER it. Example. Before: ``` Processing block operation [000009] that involves replacements V08 (field V02.hasValue (fldOffset=0x0)) <- V16 (V00.[000..001)) (last use) Remainder: [004..008) => Remainder strategy: int at +004 Local V00 should not be enregistered because: was accessed as a local field Local V02 should not be enregistered because: was accessed as a local field New statement: STMT00003 ( 0x00D[E-] ... 0x00E ) [000090] -A--------- ▌ COMMA void [000087] DA--------- ├──▌ STORE_LCL_VAR bool V08 tmp4 [000086] ----------- │ └──▌ LCL_VAR bool V16 tmp12 (last use) [000089] UA--------- └──▌ STORE_LCL_FLD int (P) V02 loc1 [+4] ▌ bool V02.:hasValue (offs=0x00) -> V08 tmp4 ▌ int V02.:value (offs=0x04) -> V09 tmp5 [000088] ----------- └──▌ LCL_FLD int V00 arg0 [+4] ``` After: ``` Processing block operation [000009] that involves replacements V08 (field V02.hasValue (fldOffset=0x0)) <- V16 (V00.[000..001)) (last use) Remainder: [004..008) => Remainder strategy: int at +004 Local V00 should not be enregistered because: was accessed as a local field New statement: STMT00003 ( 0x00D[E-] ... 0x00E ) [000090] -A--------- ▌ COMMA void [000087] DA--------- ├──▌ STORE_LCL_VAR bool V08 tmp4 [000086] ----------- │ └──▌ LCL_VAR bool V16 tmp12 (last use) [000089] DA--------- └──▌ STORE_LCL_VAR int V09 tmp5 [000088] ----------- └──▌ LCL_FLD int V00 arg0 [+4] ``` --- src/coreclr/jit/promotiondecomposition.cpp | 65 +++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp index f0a6e0f..67f02da 100644 --- a/src/coreclr/jit/promotiondecomposition.cpp +++ b/src/coreclr/jit/promotiondecomposition.cpp @@ -768,13 +768,32 @@ private: 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 { @@ -783,18 +802,44 @@ private: 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); } -- 2.7.4