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, LclNumToLiveDefsMap * curSsaName)
29
+ void Compiler::optBlockCopyPropPopStacks (BasicBlock* block, LclNumToGenTreePtrStack * curSsaName)
30
30
{
31
31
for (Statement* const stmt : block->Statements ())
32
32
{
@@ -42,7 +42,7 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap*
42
42
continue ;
43
43
}
44
44
45
- CopyPropSsaDefStack * stack = nullptr ;
45
+ GenTreePtrStack * 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, LclNumToLiveDefsMap*
55
55
}
56
56
57
57
#ifdef DEBUG
58
- void Compiler::optDumpCopyPropStack (LclNumToLiveDefsMap * curSsaName)
58
+ void Compiler::optDumpCopyPropStack (LclNumToGenTreePtrStack * curSsaName)
59
59
{
60
60
JITDUMP (" { " );
61
- for (LclNumToLiveDefsMap ::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
61
+ for (LclNumToGenTreePtrStack ::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
62
62
{
63
- GenTreeLclVarCommon* lclVar = iter.GetValue ()->Top (). GetDefNode () ->AsLclVarCommon ();
63
+ GenTreeLclVarCommon* lclVar = iter.GetValue ()->Top ()->AsLclVarCommon ();
64
64
unsigned ssaLclNum = optIsSsaLocal (lclVar);
65
65
assert (ssaLclNum != BAD_VAR_NUM);
66
66
@@ -82,7 +82,7 @@ void Compiler::optDumpCopyPropStack(LclNumToLiveDefsMap* 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 (const LclVarDsc* lclVarDsc, const LclVarDsc* copyVarDsc, bool preferOp2)
85
+ int Compiler::optCopyProp_LclVarScore (LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2)
86
86
{
87
87
int score = 0 ;
88
88
@@ -126,17 +126,16 @@ int Compiler::optCopyProp_LclVarScore(const LclVarDsc* lclVarDsc, const LclVarDs
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, GenTreeLclVarCommon* tree, unsigned lclNum, LclNumToLiveDefsMap* curSsaName)
129
+
130
+ void Compiler::optCopyProp (Statement* stmt,
131
+ GenTreeLclVarCommon* tree,
132
+ unsigned lclNum,
133
+ LclNumToGenTreePtrStack* curSsaName)
131
134
{
132
135
assert ((lclNum != BAD_VAR_NUM) && (optIsSsaLocal (tree) == lclNum) && ((tree->gtFlags & GTF_VAR_DEF) == 0 ));
133
- assert (tree->gtVNPair .BothDefined () );
136
+ assert (tree->gtVNPair .GetConservative () != ValueNumStore::NoVN );
134
137
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)
138
+ for (LclNumToGenTreePtrStack::KeyIterator iter = curSsaName->Begin (); !iter.Equal (curSsaName->End ()); ++iter)
140
139
{
141
140
unsigned newLclNum = iter.Get ();
142
141
@@ -146,30 +145,35 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
146
145
continue ;
147
146
}
148
147
149
- CopyPropSsaDef newLclDef = iter.GetValue ()->Top ();
150
- LclSsaVarDsc* newLclSsaDef = newLclDef.GetSsaDef ();
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).
151
152
152
- // Likewise, nothing to do if the most recent def is not available.
153
- if (newLclSsaDef == nullptr )
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 )
154
159
{
155
160
continue ;
156
161
}
157
162
158
- ValueNum newLclDefVN = newLclSsaDef->m_vnPair .GetConservative ();
159
- assert (newLclDefVN != ValueNumStore::NoVN);
163
+ if ((gsShadowVarInfo != nullptr ) && newLclVarDsc->lvIsParam &&
164
+ (gsShadowVarInfo[newLclNum].shadowCopy != BAD_VAR_NUM))
165
+ {
166
+ continue ;
167
+ }
160
168
161
- if (newLclDefVN != lclDefVN)
169
+ ValueNum newLclDefVN = GetUseAsgDefVNOrTreeVN (newLclDefNode);
170
+ if (newLclDefVN == ValueNumStore::NoVN)
162
171
{
163
172
continue ;
164
173
}
165
174
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 )
175
+ ValueNum lclDefVN = varDsc->GetPerSsaData (tree->GetSsaNum ())->m_vnPair .GetConservative ();
176
+ if (newLclDefVN != lclDefVN)
173
177
{
174
178
continue ;
175
179
}
@@ -178,7 +182,6 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
178
182
{
179
183
continue ;
180
184
}
181
-
182
185
// Check whether the newLclNum is live before being substituted. Otherwise, we could end
183
186
// up in a situation where there must've been a phi node that got pruned because the variable
184
187
// is not live anymore. For example,
@@ -194,7 +197,7 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
194
197
// 'c' with 'x.'
195
198
196
199
// We compute liveness only on tracked variables. And all SSA locals are tracked.
197
- assert (newLclVarDsc ->lvTracked );
200
+ assert (lvaGetDesc (newLclNum) ->lvTracked );
198
201
199
202
// Because of this dependence on live variable analysis, CopyProp phase is immediately
200
203
// after Liveness, SSA and VN.
@@ -203,6 +206,21 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
203
206
continue ;
204
207
}
205
208
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
+
206
224
var_types newLclType = newLclVarDsc->TypeGet ();
207
225
if (!newLclVarDsc->lvNormalizeOnLoad ())
208
226
{
@@ -220,15 +238,12 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
220
238
JITDUMP (" VN based copy assertion for " );
221
239
printTreeID (tree);
222
240
printf (" V%02d " FMT_VN " by " , lclNum, lclDefVN);
223
- printTreeID (newLclDef. GetDefNode () );
241
+ printTreeID (newLclDefNode );
224
242
printf (" V%02d " FMT_VN " .\n " , newLclNum, newLclDefVN);
225
243
DISPNODE (tree);
226
244
}
227
245
#endif
228
246
229
- unsigned newSsaNum = newLclVarDsc->GetSsaNumForSsaDef (newLclSsaDef);
230
- assert (newSsaNum != SsaConfig::RESERVED_SSA_NUM);
231
-
232
247
tree->AsLclVarCommon ()->SetLclNum (newLclNum);
233
248
tree->AsLclVarCommon ()->SetSsaNum (newSsaNum);
234
249
gtUpdateSideEffects (stmt, tree);
@@ -273,74 +288,6 @@ unsigned Compiler::optIsSsaLocal(GenTreeLclVarCommon* lclNode)
273
288
return lclNum;
274
289
}
275
290
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
-
344
291
// ------------------------------------------------------------------------------
345
292
// optBlockCopyProp : Perform copy propagation using currently live definitions on the current block's
346
293
// variables. Also as new definitions are encountered update the "curSsaName" which
@@ -349,8 +296,8 @@ void Compiler::optCopyPropPushDef(GenTreeOp* asg,
349
296
// Arguments:
350
297
// block - Block the tree belongs to
351
298
// curSsaName - The map from lclNum to its recently live definitions as a stack
352
- //
353
- void Compiler::optBlockCopyProp (BasicBlock* block, LclNumToLiveDefsMap * curSsaName)
299
+
300
+ void Compiler::optBlockCopyProp (BasicBlock* block, LclNumToGenTreePtrStack * curSsaName)
354
301
{
355
302
#ifdef DEBUG
356
303
JITDUMP (" Copy Assertion for " FMT_BB " \n " , block->bbNum );
@@ -386,7 +333,13 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaNa
386
333
continue ;
387
334
}
388
335
389
- optCopyPropPushDef (tree->AsOp (), lclDefNode, lclNum, curSsaName);
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);
390
343
}
391
344
// TODO-CQ: propagate on LCL_FLDs too.
392
345
else if (tree->OperIs (GT_LCL_VAR) && ((tree->gtFlags & GTF_VAR_DEF) == 0 ))
@@ -398,11 +351,19 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaNa
398
351
continue ;
399
352
}
400
353
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 ))
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 ))
404
357
{
405
- optCopyPropPushDef (nullptr , tree->AsLclVarCommon (), lclNum, curSsaName);
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
+ }
406
367
}
407
368
408
369
// TODO-Review: EH successor/predecessor iteration seems broken.
@@ -461,7 +422,7 @@ void Compiler::optVnCopyProp()
461
422
class CopyPropDomTreeVisitor : public DomTreeVisitor <CopyPropDomTreeVisitor>
462
423
{
463
424
// The map from lclNum to its recently live definitions as a stack.
464
- LclNumToLiveDefsMap m_curSsaName;
425
+ LclNumToGenTreePtrStack m_curSsaName;
465
426
466
427
public:
467
428
CopyPropDomTreeVisitor (Compiler* compiler)
0 commit comments