26
26
* of the graph originating from the block. Refer SSA renaming for any additional info.
27
27
* "curSsaName" tracks the currently live definitions.
28
28
*/
29
- void Compiler::optBlockCopyPropPopStacks (BasicBlock* block, LclNumToGenTreePtrStack * curSsaName)
29
+ void Compiler::optBlockCopyPropPopStacks (BasicBlock* block, LclNumToLiveDefsMap * curSsaName)
30
30
{
31
31
for (Statement* const stmt : block->Statements ())
32
32
{
@@ -42,7 +42,7 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrSt
42
42
continue ;
43
43
}
44
44
45
- GenTreePtrStack * stack = nullptr ;
45
+ CopyPropSsaDefStack * stack = nullptr ;
46
46
curSsaName->Lookup (lclNum, &stack);
47
47
stack->Pop ();
48
48
if (stack->Empty ())
@@ -55,12 +55,12 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrSt
55
55
}
56
56
57
57
#ifdef DEBUG
58
- void Compiler::optDumpCopyPropStack (LclNumToGenTreePtrStack * curSsaName)
58
+ void Compiler::optDumpCopyPropStack (LclNumToLiveDefsMap * curSsaName)
59
59
{
60
60
JITDUMP (" { " );
61
- for (LclNumToGenTreePtrStack ::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
61
+ for (LclNumToLiveDefsMap ::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
62
62
{
63
- GenTreeLclVarCommon* lclVar = iter.GetValue ()->Top ()->AsLclVarCommon ();
63
+ GenTreeLclVarCommon* lclVar = iter.GetValue ()->Top (). GetDefNode () ->AsLclVarCommon ();
64
64
unsigned ssaLclNum = optIsSsaLocal (lclVar);
65
65
assert (ssaLclNum != BAD_VAR_NUM);
66
66
@@ -82,7 +82,7 @@ void Compiler::optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName)
82
82
* Given the "lclVar" and "copyVar" compute if the copy prop will be beneficial.
83
83
*
84
84
*/
85
- int Compiler::optCopyProp_LclVarScore (LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2)
85
+ int Compiler::optCopyProp_LclVarScore (const LclVarDsc* lclVarDsc, const LclVarDsc* copyVarDsc, bool preferOp2)
86
86
{
87
87
int score = 0 ;
88
88
@@ -126,16 +126,17 @@ int Compiler::optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDs
126
126
// tree - The local tree to perform copy propagation on
127
127
// lclNum - The local number of said tree
128
128
// curSsaName - The map from lclNum to its recently live definitions as a stack
129
-
130
- void Compiler::optCopyProp (Statement* stmt,
131
- GenTreeLclVarCommon* tree,
132
- unsigned lclNum,
133
- LclNumToGenTreePtrStack* curSsaName)
129
+ //
130
+ void Compiler::optCopyProp (Statement* stmt, GenTreeLclVarCommon* tree, unsigned lclNum, LclNumToLiveDefsMap* curSsaName)
134
131
{
135
132
assert ((lclNum != BAD_VAR_NUM) && (optIsSsaLocal (tree) == lclNum) && ((tree->gtFlags & GTF_VAR_DEF) == 0 ));
136
- assert (tree->gtVNPair .GetConservative () != ValueNumStore::NoVN );
133
+ assert (tree->gtVNPair .BothDefined () );
137
134
138
- for (LclNumToGenTreePtrStack::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
135
+ LclVarDsc* varDsc = lvaGetDesc (lclNum);
136
+ ValueNum lclDefVN = varDsc->GetPerSsaData (tree->GetSsaNum ())->m_vnPair .GetConservative ();
137
+ assert (lclDefVN != ValueNumStore::NoVN);
138
+
139
+ for (LclNumToLiveDefsMap::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
139
140
{
140
141
unsigned newLclNum = iter.Get ();
141
142
@@ -145,35 +146,30 @@ void Compiler::optCopyProp(Statement* stmt,
145
146
continue ;
146
147
}
147
148
148
- LclVarDsc* varDsc = lvaGetDesc (lclNum);
149
- LclVarDsc* newLclVarDsc = lvaGetDesc (newLclNum);
150
- GenTree* newLclDefNode = iter.GetValue ()->Top (); // Note that this "def" node can actually be a use (for
151
- // parameters and other use-before-def locals).
149
+ CopyPropSsaDef newLclDef = iter.GetValue ()->Top ();
150
+ LclSsaVarDsc* newLclSsaDef = newLclDef.GetSsaDef ();
152
151
153
- // Do not copy propagate if the old and new lclVar have different 'doNotEnregister' settings.
154
- // This is primarily to avoid copy propagating to IND(ADDR(LCL_VAR)) where the replacement lclVar
155
- // is not marked 'lvDoNotEnregister'.
156
- // However, in addition, it may not be profitable to propagate a 'doNotEnregister' lclVar to an
157
- // existing use of an enregisterable lclVar.
158
- if (varDsc->lvDoNotEnregister != newLclVarDsc->lvDoNotEnregister )
152
+ // Likewise, nothing to do if the most recent def is not available.
153
+ if (newLclSsaDef == nullptr )
159
154
{
160
155
continue ;
161
156
}
162
157
163
- if ((gsShadowVarInfo != nullptr ) && newLclVarDsc->lvIsParam &&
164
- (gsShadowVarInfo[newLclNum].shadowCopy != BAD_VAR_NUM))
165
- {
166
- continue ;
167
- }
158
+ ValueNum newLclDefVN = newLclSsaDef->m_vnPair .GetConservative ();
159
+ assert (newLclDefVN != ValueNumStore::NoVN);
168
160
169
- ValueNum newLclDefVN = GetUseAsgDefVNOrTreeVN (newLclDefNode);
170
- if (newLclDefVN == ValueNumStore::NoVN)
161
+ if (newLclDefVN != lclDefVN)
171
162
{
172
163
continue ;
173
164
}
174
165
175
- ValueNum lclDefVN = varDsc->GetPerSsaData (tree->GetSsaNum ())->m_vnPair .GetConservative ();
176
- if (newLclDefVN != lclDefVN)
166
+ // Do not copy propagate if the old and new lclVar have different 'doNotEnregister' settings.
167
+ // This is primarily to avoid copy propagating to IND(ADDR(LCL_VAR)) where the replacement lclVar
168
+ // is not marked 'lvDoNotEnregister'.
169
+ // However, in addition, it may not be profitable to propagate a 'doNotEnregister' lclVar to an
170
+ // existing use of an enregisterable lclVar.
171
+ LclVarDsc* newLclVarDsc = lvaGetDesc (newLclNum);
172
+ if (varDsc->lvDoNotEnregister != newLclVarDsc->lvDoNotEnregister )
177
173
{
178
174
continue ;
179
175
}
@@ -182,6 +178,7 @@ void Compiler::optCopyProp(Statement* stmt,
182
178
{
183
179
continue ;
184
180
}
181
+
185
182
// Check whether the newLclNum is live before being substituted. Otherwise, we could end
186
183
// up in a situation where there must've been a phi node that got pruned because the variable
187
184
// is not live anymore. For example,
@@ -197,7 +194,7 @@ void Compiler::optCopyProp(Statement* stmt,
197
194
// 'c' with 'x.'
198
195
199
196
// We compute liveness only on tracked variables. And all SSA locals are tracked.
200
- assert (lvaGetDesc (newLclNum) ->lvTracked );
197
+ assert (newLclVarDsc ->lvTracked );
201
198
202
199
// Because of this dependence on live variable analysis, CopyProp phase is immediately
203
200
// after Liveness, SSA and VN.
@@ -206,21 +203,6 @@ void Compiler::optCopyProp(Statement* stmt,
206
203
continue ;
207
204
}
208
205
209
- unsigned newSsaNum = SsaConfig::RESERVED_SSA_NUM;
210
- if (newLclDefNode->gtFlags & GTF_VAR_DEF)
211
- {
212
- newSsaNum = GetSsaNumForLocalVarDef (newLclDefNode);
213
- }
214
- else // parameters, this pointer etc.
215
- {
216
- newSsaNum = newLclDefNode->AsLclVarCommon ()->GetSsaNum ();
217
- }
218
-
219
- if (newSsaNum == SsaConfig::RESERVED_SSA_NUM)
220
- {
221
- continue ;
222
- }
223
-
224
206
var_types newLclType = newLclVarDsc->TypeGet ();
225
207
if (!newLclVarDsc->lvNormalizeOnLoad ())
226
208
{
@@ -238,12 +220,15 @@ void Compiler::optCopyProp(Statement* stmt,
238
220
JITDUMP (" VN based copy assertion for " );
239
221
printTreeID (tree);
240
222
printf (" V%02d " FMT_VN " by " , lclNum, lclDefVN);
241
- printTreeID (newLclDefNode );
223
+ printTreeID (newLclDef. GetDefNode () );
242
224
printf (" V%02d " FMT_VN " .\n " , newLclNum, newLclDefVN);
243
225
DISPNODE (tree);
244
226
}
245
227
#endif
246
228
229
+ unsigned newSsaNum = newLclVarDsc->GetSsaNumForSsaDef (newLclSsaDef);
230
+ assert (newSsaNum != SsaConfig::RESERVED_SSA_NUM);
231
+
247
232
tree->AsLclVarCommon ()->SetLclNum (newLclNum);
248
233
tree->AsLclVarCommon ()->SetSsaNum (newSsaNum);
249
234
gtUpdateSideEffects (stmt, tree);
@@ -288,6 +273,74 @@ unsigned Compiler::optIsSsaLocal(GenTreeLclVarCommon* lclNode)
288
273
return lclNum;
289
274
}
290
275
276
+ // ------------------------------------------------------------------------------
277
+ // optCopyPropPushDef: Push the new live SSA def on the stack for "lclNode".
278
+ //
279
+ // Arguments:
280
+ // asg - The assignment node for this def (will be "nullptr" for "use" defs)
281
+ // lclNode - The local tree representing "the def" (that can actually be a use)
282
+ // lclNum - The local's number (see "optIsSsaLocal")
283
+ // curSsaName - The map of local numbers to stacks of their defs
284
+ //
285
+ void Compiler::optCopyPropPushDef (GenTreeOp* asg,
286
+ GenTreeLclVarCommon* lclNode,
287
+ unsigned lclNum,
288
+ LclNumToLiveDefsMap* curSsaName)
289
+ {
290
+ assert ((lclNum != BAD_VAR_NUM) && (lclNum == optIsSsaLocal (lclNode)));
291
+
292
+ // Shadowed parameters are special: they will (at most) have one use, that is one on the RHS of an
293
+ // assignment to their shadow, and we must not substitute them anywhere. So we'll not push any defs.
294
+ if ((gsShadowVarInfo != nullptr ) && lvaGetDesc (lclNum)->lvIsParam &&
295
+ (gsShadowVarInfo[lclNum].shadowCopy != BAD_VAR_NUM))
296
+ {
297
+ assert (!curSsaName->Lookup (lclNum));
298
+ return ;
299
+ }
300
+
301
+ unsigned ssaDefNum = SsaConfig::RESERVED_SSA_NUM;
302
+ if (asg == nullptr )
303
+ {
304
+ // Parameters, this pointer etc.
305
+ assert ((lclNode->gtFlags & GTF_VAR_DEF) == 0 );
306
+ assert (lclNode->GetSsaNum () == SsaConfig::FIRST_SSA_NUM);
307
+ ssaDefNum = lclNode->GetSsaNum ();
308
+ }
309
+ else
310
+ {
311
+ assert ((lclNode->gtFlags & GTF_VAR_DEF) != 0 );
312
+ ssaDefNum = GetSsaNumForLocalVarDef (lclNode);
313
+
314
+ // This will be "RESERVED_SSA_NUM" for promoted struct fields assigned using the parent struct.
315
+ // TODO-CQ: fix this.
316
+ assert ((ssaDefNum != SsaConfig::RESERVED_SSA_NUM) || lvaGetDesc (lclNode)->CanBeReplacedWithItsField (this ));
317
+ }
318
+
319
+ // The default is "not available".
320
+ LclSsaVarDsc* ssaDef = nullptr ;
321
+ if (ssaDefNum != SsaConfig::RESERVED_SSA_NUM)
322
+ {
323
+ // This code preserves previous behavior. In principle, "ssaDefVN" should
324
+ // always be obtained directly from the SSA def descriptor and be valid.
325
+ ValueNum ssaDefVN = GetUseAsgDefVNOrTreeVN (lclNode);
326
+ assert (ssaDefVN != ValueNumStore::NoVN);
327
+
328
+ if (ssaDefVN != ValueNumStore::VNForVoid ())
329
+ {
330
+ ssaDef = lvaGetDesc (lclNum)->GetPerSsaData (ssaDefNum);
331
+ }
332
+ }
333
+
334
+ CopyPropSsaDefStack* defStack;
335
+ if (!curSsaName->Lookup (lclNum, &defStack))
336
+ {
337
+ defStack = new (curSsaName->GetAllocator ()) CopyPropSsaDefStack (curSsaName->GetAllocator ());
338
+ curSsaName->Set (lclNum, defStack);
339
+ }
340
+
341
+ defStack->Push (CopyPropSsaDef (ssaDef, lclNode));
342
+ }
343
+
291
344
// ------------------------------------------------------------------------------
292
345
// optBlockCopyProp : Perform copy propagation using currently live definitions on the current block's
293
346
// variables. Also as new definitions are encountered update the "curSsaName" which
@@ -296,8 +349,8 @@ unsigned Compiler::optIsSsaLocal(GenTreeLclVarCommon* lclNode)
296
349
// Arguments:
297
350
// block - Block the tree belongs to
298
351
// curSsaName - The map from lclNum to its recently live definitions as a stack
299
-
300
- void Compiler::optBlockCopyProp (BasicBlock* block, LclNumToGenTreePtrStack * curSsaName)
352
+ //
353
+ void Compiler::optBlockCopyProp (BasicBlock* block, LclNumToLiveDefsMap * curSsaName)
301
354
{
302
355
#ifdef DEBUG
303
356
JITDUMP (" Copy Assertion for " FMT_BB " \n " , block->bbNum );
@@ -333,13 +386,7 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curS
333
386
continue ;
334
387
}
335
388
336
- GenTreePtrStack* stack;
337
- if (!curSsaName->Lookup (lclNum, &stack))
338
- {
339
- stack = new (curSsaName->GetAllocator ()) GenTreePtrStack (curSsaName->GetAllocator ());
340
- }
341
- stack->Push (lclDefNode);
342
- curSsaName->Set (lclNum, stack, LclNumToGenTreePtrStack::Overwrite);
389
+ optCopyPropPushDef (tree->AsOp (), lclDefNode, lclNum, curSsaName);
343
390
}
344
391
// TODO-CQ: propagate on LCL_FLDs too.
345
392
else if (tree->OperIs (GT_LCL_VAR) && ((tree->gtFlags & GTF_VAR_DEF) == 0 ))
@@ -351,19 +398,11 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curS
351
398
continue ;
352
399
}
353
400
354
- // If we encounter first use of a param or this pointer add it as a live definition.
355
- // Since they are always live, we'll do it only once.
356
- if (lvaGetDesc (lclNum)->lvIsParam || (lclNum == info.compThisArg ))
401
+ // If we encounter first use of a param or this pointer add it as a
402
+ // live definition. Since they are always live, we'll do it only once.
403
+ if (( lvaGetDesc (lclNum)->lvIsParam || (lclNum == info.compThisArg )) && !curSsaName-> Lookup (lclNum ))
357
404
{
358
- GenTreePtrStack* stack;
359
- if (!curSsaName->Lookup (lclNum, &stack))
360
- {
361
- assert (tree->AsLclVarCommon ()->GetSsaNum () == SsaConfig::FIRST_SSA_NUM);
362
-
363
- stack = new (curSsaName->GetAllocator ()) GenTreePtrStack (curSsaName->GetAllocator ());
364
- stack->Push (tree);
365
- curSsaName->Set (lclNum, stack);
366
- }
405
+ optCopyPropPushDef (nullptr , tree->AsLclVarCommon (), lclNum, curSsaName);
367
406
}
368
407
369
408
// TODO-Review: EH successor/predecessor iteration seems broken.
@@ -422,7 +461,7 @@ void Compiler::optVnCopyProp()
422
461
class CopyPropDomTreeVisitor : public DomTreeVisitor <CopyPropDomTreeVisitor>
423
462
{
424
463
// The map from lclNum to its recently live definitions as a stack.
425
- LclNumToGenTreePtrStack m_curSsaName;
464
+ LclNumToLiveDefsMap m_curSsaName;
426
465
427
466
public:
428
467
CopyPropDomTreeVisitor (Compiler* compiler)
0 commit comments