JIT: Handle primitive remainder stores to regularly promoted fields in physical promo...
authorJakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
Thu, 8 Jun 2023 20:20:44 +0000 (22:20 +0200)
committerGitHub <noreply@github.com>
Thu, 8 Jun 2023 20:20:44 +0000 (22:20 +0200)
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.<unknown class>:hasValue (offs=0x00) -> V08 tmp4
                                                               ▌    int    V02.<unknown class>: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

index f0a6e0f..67f02da 100644 (file)
@@ -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);
             }