1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
9 // This stage performs value numbering based copy propagation. Since copy propagation
10 // is about data flow, we cannot find them in assertion prop phase. In assertion prop
11 // we can identify copies, like so: if (a == b) else, i.e., control flow assertions.
13 // To identify data flow copies, we'll follow a similar approach to SSA renaming.
14 // We would walk each path in the graph keeping track of every live definition. Thus
15 // when we see a variable that shares the VN with a live definition, we'd replace this
16 // variable with the variable in the live definition, if suitable.
18 ///////////////////////////////////////////////////////////////////////////////////////
21 #include "ssabuilder.h"
24 inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 1)
26 return jitstd::allocator<T>(alloc).allocate(count);
29 /**************************************************************************************
31 * Corresponding to the live definition pushes, pop the stack as we finish a sub-paths
32 * of the graph originating from the block. Refer SSA renaming for any additional info.
33 * "curSsaName" tracks the currently live definitions.
35 void Compiler::optBlockCopyPropPopStacks(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName)
37 for (GenTree* stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
39 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
45 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
46 if (fgExcludeFromSsa(lclNum))
50 if (tree->gtFlags & GTF_VAR_DEF)
52 GenTreePtrStack* stack = nullptr;
53 curSsaName->Lookup(lclNum, &stack);
55 if (stack->Height() == 0)
57 curSsaName->Remove(lclNum);
65 void Compiler::optDumpCopyPropStack(LclNumToGenTreePtrStack* curSsaName)
68 for (LclNumToGenTreePtrStack::KeyIterator iter = curSsaName->Begin(); !iter.Equal(curSsaName->End()); ++iter)
70 GenTree* node = iter.GetValue()->Index(0);
71 JITDUMP("%d-[%06d]:V%02u ", iter.Get(), dspTreeID(node), node->AsLclVarCommon()->gtLclNum);
76 /*******************************************************************************************************
78 * Given the "lclVar" and "copyVar" compute if the copy prop will be beneficial.
81 int Compiler::optCopyProp_LclVarScore(LclVarDsc* lclVarDsc, LclVarDsc* copyVarDsc, bool preferOp2)
85 if (lclVarDsc->lvVolatileHint)
90 if (copyVarDsc->lvVolatileHint)
95 if (lclVarDsc->lvDoNotEnregister)
100 if (copyVarDsc->lvDoNotEnregister)
106 // For doubles we also prefer to change parameters into non-parameter local variables
107 if (lclVarDsc->lvType == TYP_DOUBLE)
109 if (lclVarDsc->lvIsParam)
114 if (copyVarDsc->lvIsParam)
121 // Otherwise we prefer to use the op2LclNum
122 return score + ((preferOp2) ? 1 : -1);
125 //------------------------------------------------------------------------------
126 // optCopyProp : Perform copy propagation on a given tree as we walk the graph and if it is a local
127 // variable, then look up all currently live definitions and check if any of those
128 // definitions share the same value number. If so, then we can make the replacement.
131 // block - Block the tree belongs to
132 // stmt - Statement the tree belongs to
133 // tree - The tree to perform copy propagation on
134 // curSsaName - The map from lclNum to its recently live definitions as a stack
136 void Compiler::optCopyProp(BasicBlock* block, GenTree* stmt, GenTree* tree, LclNumToGenTreePtrStack* curSsaName)
138 // TODO-Review: EH successor/predecessor iteration seems broken.
139 if (block->bbCatchTyp == BBCT_FINALLY || block->bbCatchTyp == BBCT_FAULT)
144 // If not local nothing to do.
145 if (!tree->IsLocal())
149 if (tree->OperGet() == GT_PHI_ARG || tree->OperGet() == GT_LCL_FLD)
154 // Propagate only on uses.
155 if (tree->gtFlags & GTF_VAR_DEF)
159 unsigned lclNum = tree->AsLclVarCommon()->GetLclNum();
161 // Skip address exposed variables.
162 if (fgExcludeFromSsa(lclNum))
167 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
169 for (LclNumToGenTreePtrStack::KeyIterator iter = curSsaName->Begin(); !iter.Equal(curSsaName->End()); ++iter)
171 unsigned newLclNum = iter.Get();
173 GenTree* op = iter.GetValue()->Index(0);
175 // Nothing to do if same.
176 if (lclNum == newLclNum)
181 // Skip variables with assignments embedded in the statement (i.e., with a comma). Because we
182 // are not currently updating their SSA names as live in the copy-prop pass of the stmt.
183 if (VarSetOps::IsMember(this, optCopyPropKillSet, lvaTable[newLclNum].lvVarIndex))
188 if (op->gtFlags & GTF_VAR_CAST)
192 if (gsShadowVarInfo != nullptr && lvaTable[newLclNum].lvIsParam &&
193 gsShadowVarInfo[newLclNum].shadowCopy == lclNum)
197 ValueNum opVN = GetUseAsgDefVNOrTreeVN(op);
198 if (opVN == ValueNumStore::NoVN)
202 if (op->TypeGet() != tree->TypeGet())
206 if (opVN != tree->gtVNPair.GetConservative())
210 if (optCopyProp_LclVarScore(&lvaTable[lclNum], &lvaTable[newLclNum], true) <= 0)
214 // Check whether the newLclNum is live before being substituted. Otherwise, we could end
215 // up in a situation where there must've been a phi node that got pruned because the variable
216 // is not live anymore. For example,
221 // print(c) <-- x is not live here. Let's say 'c' shares the value number with "x0."
223 // If we simply substituted 'c' with "x0", we would be wrong. Ideally, there would be a phi
224 // node x2 = phi(x0, x1) which can then be used to substitute 'c' with. But because of pruning
225 // there would be no such phi node. To solve this we'll check if 'x' is live, before replacing
227 if (!lvaTable[newLclNum].lvVerTypeInfo.IsThisPtr())
229 if (lvaTable[newLclNum].lvAddrExposed)
234 // We compute liveness only on tracked variables. So skip untracked locals.
235 if (!lvaTable[newLclNum].lvTracked)
240 // Because of this dependence on live variable analysis, CopyProp phase is immediately
241 // after Liveness, SSA and VN.
242 if (!VarSetOps::IsMember(this, compCurLife, lvaTable[newLclNum].lvVarIndex))
247 unsigned newSsaNum = SsaConfig::RESERVED_SSA_NUM;
248 if (op->gtFlags & GTF_VAR_DEF)
250 newSsaNum = GetSsaNumForLocalVarDef(op);
252 else // parameters, this pointer etc.
254 newSsaNum = op->AsLclVarCommon()->GetSsaNum();
257 if (newSsaNum == SsaConfig::RESERVED_SSA_NUM)
265 JITDUMP("VN based copy assertion for ");
267 printf(" V%02d @%08X by ", lclNum, tree->GetVN(VNK_Conservative));
269 printf(" V%02d @%08X.\n", newLclNum, op->GetVN(VNK_Conservative));
270 gtDispTree(tree, nullptr, nullptr, true);
274 lvaTable[lclNum].decRefCnts(block->getBBWeight(this), this);
275 lvaTable[newLclNum].incRefCnts(block->getBBWeight(this), this);
276 tree->gtLclVarCommon.SetLclNum(newLclNum);
277 tree->AsLclVarCommon()->SetSsaNum(newSsaNum);
278 gtUpdateSideEffects(stmt, tree);
282 printf("copy propagated to:\n");
283 gtDispTree(tree, nullptr, nullptr, true);
291 /**************************************************************************************
293 * Helper to check if tree is a local that participates in SSA numbering.
295 bool Compiler::optIsSsaLocal(GenTree* tree)
297 return tree->IsLocal() && !fgExcludeFromSsa(tree->AsLclVarCommon()->GetLclNum());
300 //------------------------------------------------------------------------------
301 // optBlockCopyProp : Perform copy propagation using currently live definitions on the current block's
302 // variables. Also as new definitions are encountered update the "curSsaName" which
303 // tracks the currently live definitions.
306 // block - Block the tree belongs to
307 // curSsaName - The map from lclNum to its recently live definitions as a stack
309 void Compiler::optBlockCopyProp(BasicBlock* block, LclNumToGenTreePtrStack* curSsaName)
312 JITDUMP("Copy Assertion for BB%02u\n", block->bbNum);
315 printf(" curSsaName stack: ");
316 optDumpCopyPropStack(curSsaName);
320 // There are no definitions at the start of the block. So clear it.
321 compCurLifeTree = nullptr;
322 VarSetOps::Assign(this, compCurLife, block->bbLiveIn);
323 for (GenTree* stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
325 VarSetOps::ClearD(this, optCopyPropKillSet);
327 // Walk the tree to find if any local variable can be replaced with current live definitions.
328 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
330 compUpdateLife</*ForCodeGen*/ false>(tree);
332 optCopyProp(block, stmt, tree, curSsaName);
334 // TODO-Review: Merge this loop with the following loop to correctly update the
335 // live SSA num while also propagating copies.
337 // 1. This loop performs copy prop with currently live (on-top-of-stack) SSA num.
338 // 2. The subsequent loop maintains a stack for each lclNum with
339 // currently active SSA numbers when definitions are encountered.
341 // If there is an embedded definition using a "comma" in a stmt, then the currently
342 // live SSA number will get updated only in the next loop (2). However, this new
343 // definition is now supposed to be live (on tos). If we did not update the stacks
344 // using (2), copy prop (1) will use a SSA num defined outside the stmt ignoring the
345 // embedded update. Killing the variable is a simplification to produce 0 ASM diffs
346 // for an update release.
348 if (optIsSsaLocal(tree) && (tree->gtFlags & GTF_VAR_DEF))
350 VarSetOps::AddElemD(this, optCopyPropKillSet, lvaTable[tree->gtLclVarCommon.gtLclNum].lvVarIndex);
354 // This logic must be in sync with SSA renaming process.
355 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
357 if (!optIsSsaLocal(tree))
362 unsigned lclNum = tree->gtLclVarCommon.gtLclNum;
364 // As we encounter a definition add it to the stack as a live definition.
365 if (tree->gtFlags & GTF_VAR_DEF)
367 GenTreePtrStack* stack;
368 if (!curSsaName->Lookup(lclNum, &stack))
370 stack = new (curSsaName->GetAllocator()) GenTreePtrStack(this);
373 curSsaName->Set(lclNum, stack);
375 // If we encounter first use of a param or this pointer add it as a live definition.
376 // Since they are always live, do it only once.
377 else if ((tree->gtOper == GT_LCL_VAR) && !(tree->gtFlags & GTF_VAR_USEASG) &&
378 (lvaTable[lclNum].lvIsParam || lvaTable[lclNum].lvVerTypeInfo.IsThisPtr()))
380 GenTreePtrStack* stack;
381 if (!curSsaName->Lookup(lclNum, &stack))
383 stack = new (curSsaName->GetAllocator()) GenTreePtrStack(this);
385 curSsaName->Set(lclNum, stack);
392 /**************************************************************************************
394 * This stage performs value numbering based copy propagation. Since copy propagation
395 * is about data flow, we cannot find them in assertion prop phase. In assertion prop
396 * we can identify copies that like so: if (a == b) else, i.e., control flow assertions.
398 * To identify data flow copies, we follow a similar approach to SSA renaming. We walk
399 * each path in the graph keeping track of every live definition. Thus when we see a
400 * variable that shares the VN with a live definition, we'd replace this variable with
401 * the variable in the live definition.
403 * We do this to be in conventional SSA form. This can very well be changed later.
405 * For example, on some path in the graph:
412 * b0 = x0, we cannot substitute x0 with a0, because currently our backend doesn't
413 * treat lclNum and ssaNum together as a variable, but just looks at lclNum. If we
414 * substituted x0 with a0, then we'd be in general SSA form.
417 void Compiler::optVnCopyProp()
422 printf("*************** In optVnCopyProp()\n");
426 if (fgSsaPassesCompleted == 0)
431 CompAllocator allocator(this, CMK_CopyProp);
433 // Compute the domTree to use.
434 BlkToBlkSetMap* domTree = new (&allocator) BlkToBlkSetMap(&allocator);
435 domTree->Reallocate(fgBBcount * 3 / 2); // Prime the allocation
436 SsaBuilder::ComputeDominators(this, domTree);
443 BlockWork(BasicBlock* blk, bool processed = false) : m_blk(blk), m_processed(processed)
447 typedef jitstd::vector<BlockWork> BlockWorkStack;
449 VarSetOps::AssignNoCopy(this, compCurLife, VarSetOps::MakeEmpty(this));
450 VarSetOps::AssignNoCopy(this, optCopyPropKillSet, VarSetOps::MakeEmpty(this));
452 // The map from lclNum to its recently live definitions as a stack.
453 LclNumToGenTreePtrStack curSsaName(&allocator);
455 BlockWorkStack* worklist = new (&allocator) BlockWorkStack(&allocator);
457 worklist->push_back(BlockWork(fgFirstBB));
458 while (!worklist->empty())
460 BlockWork work = worklist->back();
461 worklist->pop_back();
463 BasicBlock* block = work.m_blk;
464 if (work.m_processed)
466 // Pop all the live definitions for this block.
467 optBlockCopyPropPopStacks(block, &curSsaName);
471 // Generate copy assertions in this block, and keeping curSsaName variable up to date.
472 worklist->push_back(BlockWork(block, true));
474 optBlockCopyProp(block, &curSsaName);
476 // Add dom children to work on.
478 if (domTree->Lookup(block, &pBlkSet))
480 for (BlkSet::KeyIterator child = pBlkSet->Begin(); !child.Equal(pBlkSet->End()); ++child)
482 worklist->push_back(BlockWork(child.Get()));
487 // Tracked variable count increases after CopyProp, so don't keep a shorter array around.
488 // Destroy (release) the varset.
489 VarSetOps::AssignNoCopy(this, compCurLife, VarSetOps::UninitVal());