Skip to content

Commit b28af0a

Browse files
committed
Revert "Use SSA def descriptors in copy propagation (dotnet#65250)"
This reverts commit 9012b23.
1 parent b40b31a commit b28af0a

File tree

4 files changed

+80
-170
lines changed

4 files changed

+80
-170
lines changed

src/coreclr/jit/compiler.h

+7-58
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,6 @@ class SsaDefArray
352352
assert(ssaNum != SsaConfig::RESERVED_SSA_NUM);
353353
return GetSsaDefByIndex(ssaNum - GetMinSsaNum());
354354
}
355-
356-
// Get an SSA number associated with the specified SSA def (that must be in this array).
357-
unsigned GetSsaNum(T* ssaDef)
358-
{
359-
assert((m_array <= ssaDef) && (ssaDef < &m_array[m_count]));
360-
return GetMinSsaNum() + static_cast<unsigned>(ssaDef - &m_array[0]);
361-
}
362355
};
363356

364357
enum RefCountState
@@ -1089,13 +1082,6 @@ class LclVarDsc
10891082
return lvPerSsaData.GetSsaDef(ssaNum);
10901083
}
10911084

1092-
// Returns the SSA number for "ssaDef". Requires "ssaDef" to be a valid definition
1093-
// of this variable.
1094-
unsigned GetSsaNumForSsaDef(LclSsaVarDsc* ssaDef)
1095-
{
1096-
return lvPerSsaData.GetSsaNum(ssaDef);
1097-
}
1098-
10991085
var_types GetRegisterType(const GenTreeLclVarCommon* tree) const;
11001086

11011087
var_types GetRegisterType() const;
@@ -7414,54 +7400,17 @@ class Compiler
74147400

74157401
public:
74167402
// VN based copy propagation.
7417-
7418-
// In DEBUG builds, we'd like to know the tree that the SSA definition was pushed for.
7419-
// While for ordinary SSA defs it will be available (as an ASG) in the SSA descriptor,
7420-
// for locals which will use "definitions from uses", it will not be, so we store it
7421-
// in this class instead.
7422-
class CopyPropSsaDef
7423-
{
7424-
LclSsaVarDsc* m_ssaDef;
7425-
#ifdef DEBUG
7426-
GenTree* m_defNode;
7427-
#endif
7428-
public:
7429-
CopyPropSsaDef(LclSsaVarDsc* ssaDef, GenTree* defNode)
7430-
: m_ssaDef(ssaDef)
7431-
#ifdef DEBUG
7432-
, m_defNode(defNode)
7433-
#endif
7434-
{
7435-
}
7436-
7437-
LclSsaVarDsc* GetSsaDef() const
7438-
{
7439-
return m_ssaDef;
7440-
}
7441-
7442-
#ifdef DEBUG
7443-
GenTree* GetDefNode() const
7444-
{
7445-
return m_defNode;
7446-
}
7447-
#endif
7448-
};
7449-
7450-
typedef ArrayStack<CopyPropSsaDef> CopyPropSsaDefStack;
7451-
typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, CopyPropSsaDefStack*> LclNumToLiveDefsMap;
7403+
typedef ArrayStack<GenTree*> GenTreePtrStack;
7404+
typedef JitHashTable<unsigned, JitSmallPrimitiveKeyFuncs<unsigned>, GenTreePtrStack*> LclNumToGenTreePtrStack;
74527405

74537406
// Copy propagation functions.
7454-
void optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned lclNum, LclNumToLiveDefsMap* curSsaName);
7455-
void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap* curSsaName);
7456-
void optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaName);
7457-
void optCopyPropPushDef(GenTreeOp* asg,
7458-
GenTreeLclVarCommon* lclNode,
7459-
unsigned lclNum,
7460-
LclNumToLiveDefsMap* curSsaName);
7407+
void optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned lclNum, LclNumToGenTreePtrStack* curSsaName);
7408+
void optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
7409+
void optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName);
74617410
unsigned optIsSsaLocal(GenTreeLclVarCommon* lclNode);
7462-
int optCopyProp_LclVarScore(const LclVarDsc* lclVarDsc, const LclVarDsc* copyVarDsc, bool preferOp2);
7411+
int optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2);
74637412
void optVnCopyProp();
7464-
INDEBUG(void optDumpCopyPropStack(LclNumToLiveDefsMap* curSsaName));
7413+
INDEBUG(void optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName));
74657414

74667415
/**************************************************************************
74677416
* Early value propagation

src/coreclr/jit/copyprop.cpp

+71-110
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* of the graph originating from the block. Refer SSA renaming for any additional info.
2727
* "curSsaName" tracks the currently live definitions.
2828
*/
29-
void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap* curSsaName)
29+
void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName)
3030
{
3131
for (Statement* const stmt : block->Statements())
3232
{
@@ -42,7 +42,7 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap*
4242
continue;
4343
}
4444

45-
CopyPropSsaDefStack* stack = nullptr;
45+
GenTreePtrStack* stack = nullptr;
4646
curSsaName->Lookup(lclNum, &stack);
4747
stack->Pop();
4848
if (stack->Empty())
@@ -55,12 +55,12 @@ void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToLiveDefsMap*
5555
}
5656

5757
#ifdef DEBUG
58-
void Compiler::optDumpCopyPropStack(LclNumToLiveDefsMap* curSsaName)
58+
void Compiler::optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName)
5959
{
6060
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)
6262
{
63-
GenTreeLclVarCommon* lclVar = iter.GetValue()->Top().GetDefNode()->AsLclVarCommon();
63+
GenTreeLclVarCommon* lclVar = iter.GetValue()->Top()->AsLclVarCommon();
6464
unsigned ssaLclNum = optIsSsaLocal(lclVar);
6565
assert(ssaLclNum != BAD_VAR_NUM);
6666

@@ -82,7 +82,7 @@ void Compiler::optDumpCopyPropStack(LclNumToLiveDefsMap* curSsaName)
8282
* Given the "lclVar" and "copyVar" compute if the copy prop will be beneficial.
8383
*
8484
*/
85-
int Compiler::optCopyProp_LclVarScore(const LclVarDsc* lclVarDsc, const LclVarDsc* copyVarDsc, bool preferOp2)
85+
int Compiler::optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2)
8686
{
8787
int score = 0;
8888

@@ -126,17 +126,16 @@ int Compiler::optCopyProp_LclVarScore(const LclVarDsc* lclVarDsc, const LclVarDs
126126
// tree - The local tree to perform copy propagation on
127127
// lclNum - The local number of said tree
128128
// 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)
131134
{
132135
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);
134137

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)
140139
{
141140
unsigned newLclNum = iter.Get();
142141

@@ -146,30 +145,35 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
146145
continue;
147146
}
148147

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).
151152

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)
154159
{
155160
continue;
156161
}
157162

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+
}
160168

161-
if (newLclDefVN != lclDefVN)
169+
ValueNum newLclDefVN = GetUseAsgDefVNOrTreeVN(newLclDefNode);
170+
if (newLclDefVN == ValueNumStore::NoVN)
162171
{
163172
continue;
164173
}
165174

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)
173177
{
174178
continue;
175179
}
@@ -178,7 +182,6 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
178182
{
179183
continue;
180184
}
181-
182185
// Check whether the newLclNum is live before being substituted. Otherwise, we could end
183186
// up in a situation where there must've been a phi node that got pruned because the variable
184187
// is not live anymore. For example,
@@ -194,7 +197,7 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
194197
// 'c' with 'x.'
195198

196199
// We compute liveness only on tracked variables. And all SSA locals are tracked.
197-
assert(newLclVarDsc->lvTracked);
200+
assert(lvaGetDesc(newLclNum)->lvTracked);
198201

199202
// Because of this dependence on live variable analysis, CopyProp phase is immediately
200203
// after Liveness, SSA and VN.
@@ -203,6 +206,21 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
203206
continue;
204207
}
205208

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+
206224
var_types newLclType = newLclVarDsc->TypeGet();
207225
if (!newLclVarDsc->lvNormalizeOnLoad())
208226
{
@@ -220,15 +238,12 @@ void Compiler::optCopyProp(Statement* stmt, GenTreeLclVarCommon* tree, unsigned
220238
JITDUMP("VN based copy assertion for ");
221239
printTreeID(tree);
222240
printf(" V%02d " FMT_VN " by ", lclNum, lclDefVN);
223-
printTreeID(newLclDef.GetDefNode());
241+
printTreeID(newLclDefNode);
224242
printf(" V%02d " FMT_VN ".\n", newLclNum, newLclDefVN);
225243
DISPNODE(tree);
226244
}
227245
#endif
228246

229-
unsigned newSsaNum = newLclVarDsc->GetSsaNumForSsaDef(newLclSsaDef);
230-
assert(newSsaNum != SsaConfig::RESERVED_SSA_NUM);
231-
232247
tree->AsLclVarCommon()->SetLclNum(newLclNum);
233248
tree->AsLclVarCommon()->SetSsaNum(newSsaNum);
234249
gtUpdateSideEffects(stmt, tree);
@@ -273,74 +288,6 @@ unsigned Compiler::optIsSsaLocal(GenTreeLclVarCommon* lclNode)
273288
return lclNum;
274289
}
275290

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-
344291
//------------------------------------------------------------------------------
345292
// optBlockCopyProp : Perform copy propagation using currently live definitions on the current block's
346293
// variables. Also as new definitions are encountered update the "curSsaName" which
@@ -349,8 +296,8 @@ void Compiler::optCopyPropPushDef(GenTreeOp* asg,
349296
// Arguments:
350297
// block - Block the tree belongs to
351298
// 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)
354301
{
355302
#ifdef DEBUG
356303
JITDUMP("Copy Assertion for " FMT_BB "\n", block->bbNum);
@@ -386,7 +333,13 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaNa
386333
continue;
387334
}
388335

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);
390343
}
391344
// TODO-CQ: propagate on LCL_FLDs too.
392345
else if (tree->OperIs(GT_LCL_VAR) && ((tree->gtFlags & GTF_VAR_DEF) == 0))
@@ -398,11 +351,19 @@ void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToLiveDefsMap* curSsaNa
398351
continue;
399352
}
400353

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))
404357
{
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+
}
406367
}
407368

408369
// TODO-Review: EH successor/predecessor iteration seems broken.
@@ -461,7 +422,7 @@ void Compiler::optVnCopyProp()
461422
class CopyPropDomTreeVisitor : public DomTreeVisitor<CopyPropDomTreeVisitor>
462423
{
463424
// The map from lclNum to its recently live definitions as a stack.
464-
LclNumToLiveDefsMap m_curSsaName;
425+
LclNumToGenTreePtrStack m_curSsaName;
465426

466427
public:
467428
CopyPropDomTreeVisitor(Compiler* compiler)

0 commit comments

Comments
 (0)