@@ -36,8 +36,8 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrSt
3636 {
3737 continue ;
3838 }
39- unsigned lclNum = tree-> AsLclVarCommon ()-> GetLclNum ( );
40- if (! lvaInSsa ( lclNum) )
39+ const unsigned lclNum = optIsSsaLocal (tree );
40+ if (lclNum == BAD_VAR_NUM )
4141 {
4242 continue ;
4343 }
@@ -61,8 +61,19 @@ void Compiler::optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName)
6161 JITDUMP (" { " );
6262 for (LclNumToGenTreePtrStack::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
6363 {
64- GenTree* node = iter.GetValue ()->Top ();
65- JITDUMP (" %d-[%06d]:V%02u " , iter.Get (), dspTreeID (node), node->AsLclVarCommon ()->GetLclNum ());
64+ GenTreeLclVarCommon* lclVar = iter.GetValue ()->Top ()->AsLclVarCommon ();
65+ unsigned ssaLclNum = optIsSsaLocal (lclVar);
66+ assert (ssaLclNum != BAD_VAR_NUM);
67+
68+ if (ssaLclNum == lclVar->GetLclNum ())
69+ {
70+ JITDUMP (" %d-[%06d]:V%02u " , iter.Get (), dspTreeID (lclVar), ssaLclNum);
71+ }
72+ else
73+ {
74+ // A promoted field was asigned using the parent struct, print `ssa field lclNum(parent lclNum)`.
75+ JITDUMP (" %d-[%06d]:V%02u(V%02u) " , iter.Get (), dspTreeID (lclVar), ssaLclNum, lclVar->GetLclNum ());
76+ }
6677 }
6778 JITDUMP (" }\n\n " );
6879}
@@ -150,10 +161,10 @@ void Compiler::optCopyProp(BasicBlock* block, Statement* stmt, GenTree* tree, Lc
150161 {
151162 return ;
152163 }
153- unsigned lclNum = tree-> AsLclVarCommon ()-> GetLclNum ( );
164+ const unsigned lclNum = optIsSsaLocal (tree );
154165
155166 // Skip non-SSA variables.
156- if (! lvaInSsa ( lclNum) )
167+ if (lclNum == BAD_VAR_NUM )
157168 {
158169 return ;
159170 }
@@ -291,13 +302,39 @@ void Compiler::optCopyProp(BasicBlock* block, Statement* stmt, GenTree* tree, Lc
291302 return ;
292303}
293304
294- /* *************************************************************************************
295- *
296- * Helper to check if tree is a local that participates in SSA numbering.
297- */
298- bool Compiler::optIsSsaLocal (GenTree* tree)
305+ // ------------------------------------------------------------------------------
306+ // optIsSsaLocal : helper to check if the tree is a local that participates in SSA numbering.
307+ //
308+ // Arguments:
309+ // tree - The tree to perform the check on;
310+ //
311+ // Returns:
312+ // - lclNum if the local is participating in SSA;
313+ // - fieldLclNum if the parent local can be replaced by its only field;
314+ // - BAD_VAR_NUM otherwise.
315+ //
316+ unsigned Compiler::optIsSsaLocal (GenTree* tree)
299317{
300- return tree->IsLocal () && lvaInSsa (tree->AsLclVarCommon ()->GetLclNum ());
318+ if (!tree->IsLocal ())
319+ {
320+ return BAD_VAR_NUM;
321+ }
322+
323+ GenTreeLclVarCommon* lclNode = tree->AsLclVarCommon ();
324+ unsigned lclNum = lclNode->GetLclNum ();
325+ LclVarDsc* varDsc = lvaGetDesc (lclNum);
326+
327+ if (!lvaInSsa (lclNum) && varDsc->CanBeReplacedWithItsField (this ))
328+ {
329+ lclNum = varDsc->lvFieldLclStart ;
330+ }
331+
332+ if (!lvaInSsa (lclNum))
333+ {
334+ return BAD_VAR_NUM;
335+ }
336+
337+ return lclNum;
301338}
302339
303340// ------------------------------------------------------------------------------
@@ -351,22 +388,22 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curS
351388 // embedded update. Killing the variable is a simplification to produce 0 ASM diffs
352389 // for an update release.
353390 //
354- if (optIsSsaLocal (tree) && (tree->gtFlags & GTF_VAR_DEF))
391+ const unsigned lclNum = optIsSsaLocal (tree);
392+ if ((lclNum != BAD_VAR_NUM) && (tree->gtFlags & GTF_VAR_DEF))
355393 {
356- VarSetOps::AddElemD (this , optCopyPropKillSet, lvaTable[tree-> AsLclVarCommon ()-> GetLclNum () ].lvVarIndex );
394+ VarSetOps::AddElemD (this , optCopyPropKillSet, lvaTable[lclNum ].lvVarIndex );
357395 }
358396 }
359397
360398 // This logic must be in sync with SSA renaming process.
361399 for (GenTree* tree = stmt->GetTreeList (); tree != nullptr ; tree = tree->gtNext )
362400 {
363- if (!optIsSsaLocal (tree))
401+ const unsigned lclNum = optIsSsaLocal (tree);
402+ if (lclNum == BAD_VAR_NUM)
364403 {
365404 continue ;
366405 }
367406
368- unsigned lclNum = tree->AsLclVarCommon ()->GetLclNum ();
369-
370407 // As we encounter a definition add it to the stack as a live definition.
371408 if (tree->gtFlags & GTF_VAR_DEF)
372409 {
0 commit comments