1515#endif
1616#include " lower.h" // for LowerRange()
1717
18- /* ****************************************************************************
19- *
20- * Helper for Compiler::fgPerBlockLocalVarLiveness().
21- * The goal is to compute the USE and DEF sets for a basic block.
22- */
18+ // ------------------------------------------------------------------------
19+ // fgMarkUseDef:
20+ // Mark a local in the current def/use set.
21+ //
22+ // Parameters:
23+ // tree - The local
24+ //
25+ // Template parameters:
26+ // ssaLiveness - Whether the liveness computed is for SSA and should follow
27+ // same modelling rules as SSA. SSA models partial defs like (v.x = 123) as
28+ // (v = v with x = 123), which also implies that these partial definitions
29+ // become uses. For dead-code elimination this is more conservative than
30+ // needed, so outside SSA we do not model partial defs in this way:
31+ //
32+ // * In SSA: Partial defs are full defs but are also uses. They impact both
33+ // bbVarUse and bbVarDef.
34+ //
35+ // * Outside SSA: Partial defs are _not_ full defs and are also not
36+ // considered uses. They do not get included in bbVarUse/bbVarDef.
37+ //
38+ template <bool ssaLiveness>
2339void Compiler::fgMarkUseDef (GenTreeLclVarCommon* tree)
2440{
2541 assert ((tree->OperIsLocal () && (tree->OperGet () != GT_PHI_ARG)) || tree->OperIs (GT_LCL_ADDR));
@@ -35,8 +51,9 @@ void Compiler::fgMarkUseDef(GenTreeLclVarCommon* tree)
3551 varDsc->setLvRefCnt (1 );
3652 }
3753
38- const bool isDef = (tree->gtFlags & GTF_VAR_DEF) != 0 ;
39- const bool isUse = !isDef || ((tree->gtFlags & GTF_VAR_USEASG) != 0 );
54+ const bool isDef = ((tree->gtFlags & GTF_VAR_DEF) != 0 );
55+ const bool isFullDef = isDef && ((tree->gtFlags & GTF_VAR_USEASG) == 0 );
56+ const bool isUse = ssaLiveness ? !isFullDef : !isDef;
4057
4158 if (varDsc->lvTracked )
4259 {
@@ -60,7 +77,7 @@ void Compiler::fgMarkUseDef(GenTreeLclVarCommon* tree)
6077 VarSetOps::AddElemD (this , fgCurUseSet, varDsc->lvVarIndex );
6178 }
6279
63- if (isDef)
80+ if (ssaLiveness ? isDef : isFullDef )
6481 {
6582 // This is a def, add it to the set of defs.
6683 VarSetOps::AddElemD (this , fgCurDefSet, varDsc->lvVarIndex );
@@ -106,7 +123,7 @@ void Compiler::fgMarkUseDef(GenTreeLclVarCommon* tree)
106123 VarSetOps::AddElemD (this , fgCurUseSet, varIndex);
107124 }
108125
109- if (isDef)
126+ if (ssaLiveness ? isDef : isFullDef )
110127 {
111128 VarSetOps::AddElemD (this , fgCurDefSet, varIndex);
112129 }
@@ -116,7 +133,10 @@ void Compiler::fgMarkUseDef(GenTreeLclVarCommon* tree)
116133 }
117134}
118135
119- /* ****************************************************************************/
136+ // ------------------------------------------------------------------------
137+ // fgLocalVarLiveness:
138+ // Compute block def/use sets, liveness, and do dead code elimination.
139+ //
120140void Compiler::fgLocalVarLiveness ()
121141{
122142#ifdef DEBUG
@@ -216,7 +236,7 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree)
216236 case GT_LCL_FLD:
217237 case GT_STORE_LCL_VAR:
218238 case GT_STORE_LCL_FLD:
219- fgMarkUseDef (tree->AsLclVarCommon ());
239+ fgMarkUseDef<!lowered> (tree->AsLclVarCommon ());
220240 break ;
221241
222242 case GT_LCL_ADDR:
@@ -229,7 +249,7 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree)
229249 break ;
230250 }
231251
232- fgMarkUseDef (tree->AsLclVarCommon ());
252+ fgMarkUseDef<!lowered> (tree->AsLclVarCommon ());
233253 }
234254 break ;
235255
@@ -325,7 +345,7 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTree* tree)
325345 GenTreeLclVarCommon* definedLcl = gtCallGetDefinedRetBufLclAddr (call);
326346 if (definedLcl != nullptr )
327347 {
328- fgMarkUseDef (definedLcl);
348+ fgMarkUseDef<!lowered> (definedLcl);
329349 }
330350 break ;
331351 }
@@ -356,7 +376,10 @@ void Compiler::fgPerNodeLocalVarLiveness(GenTreeHWIntrinsic* hwintrinsic)
356376}
357377#endif // FEATURE_HW_INTRINSICS
358378
359- /* ****************************************************************************/
379+ // ------------------------------------------------------------------------
380+ // fgPerBlockLocalVarLiveness:
381+ // Compute def and use sets for the IR.
382+ //
360383void Compiler::fgPerBlockLocalVarLiveness ()
361384{
362385#ifdef DEBUG
@@ -419,7 +442,7 @@ void Compiler::fgPerBlockLocalVarLiveness()
419442 {
420443 for (GenTreeLclVarCommon* lcl : stmt->LocalsTreeList ())
421444 {
422- fgMarkUseDef (lcl);
445+ fgMarkUseDef< false > (lcl);
423446 }
424447 }
425448 else
@@ -436,12 +459,12 @@ void Compiler::fgPerBlockLocalVarLiveness()
436459 // qmark arms.
437460 for (GenTreeLclVarCommon* lcl : stmt->LocalsTreeList ())
438461 {
439- bool isUse = (( lcl->gtFlags & GTF_VAR_DEF) == 0 ) || ((lcl-> gtFlags & GTF_VAR_USEASG) != 0 ) ;
462+ bool isUse = (lcl->gtFlags & GTF_VAR_DEF) == 0 ;
440463 // We can still handle the pure def at the top level.
441464 bool conditional = lcl != dst;
442465 if (isUse || !conditional)
443466 {
444- fgMarkUseDef (lcl);
467+ fgMarkUseDef< false > (lcl);
445468 }
446469 }
447470 }
@@ -453,7 +476,7 @@ void Compiler::fgPerBlockLocalVarLiveness()
453476 {
454477 for (GenTreeLclVarCommon* lcl : stmt->LocalsTreeList ())
455478 {
456- fgMarkUseDef (lcl);
479+ fgMarkUseDef< false > (lcl);
457480 }
458481 }
459482 }
@@ -2088,7 +2111,7 @@ void Compiler::fgInterBlockLocalVarLiveness()
20882111 for (GenTree* cur = stmt->GetTreeListEnd (); cur != nullptr ;)
20892112 {
20902113 assert (cur->OperIsAnyLocal ());
2091- bool isDef = ((cur-> gtFlags & GTF_VAR_DEF) != 0 ) && (( cur->gtFlags & GTF_VAR_USEASG) == 0 ) ;
2114+ bool isDef = ( cur->gtFlags & GTF_VAR_DEF) != 0 ;
20922115 bool conditional = cur != dst;
20932116 // Ignore conditional defs that would otherwise
20942117 // (incorrectly) interfere with liveness in other
0 commit comments