void SetBlock(BasicBlock* block)
{
m_block = block;
+ CheckPhis(block);
+ }
+
+ void CheckPhis(BasicBlock* block)
+ {
+ Statement* nonPhiStmt = nullptr;
+ for (Statement* const stmt : block->Statements())
+ {
+ // All PhiDefs should appear before any other statements
+ //
+ if (!stmt->IsPhiDefnStmt())
+ {
+ if (nonPhiStmt == nullptr)
+ {
+ nonPhiStmt = stmt;
+ }
+ continue;
+ }
+
+ if (nonPhiStmt != nullptr)
+ {
+ SetHasErrors();
+ JITDUMP("[error] " FMT_BB " PhiDef " FMT_STMT " appears after non-PhiDef " FMT_STMT "\n", block->bbNum,
+ stmt->GetID(), nonPhiStmt->GetID());
+ }
+
+ GenTree* const phiDefNode = stmt->GetRootNode();
+ assert(phiDefNode->IsPhiDefn());
+ GenTreeLclVarCommon* const phiDefLclNode = phiDefNode->gtGetOp1()->AsLclVarCommon();
+ GenTreePhi* const phi = phiDefNode->gtGetOp2()->AsPhi();
+
+ // Verify each GT_PHI_ARG is the right local.
+ //
+ // If block does not begin a handler, verify GT_PHI_ARG blocks are unique
+ // (that is, each pred supplies at most one ssa def).
+ //
+ BitVecTraits bitVecTraits(m_compiler->fgBBNumMax + 1, m_compiler);
+ BitVec phiPreds(BitVecOps::MakeEmpty(&bitVecTraits));
+
+ for (GenTreePhi::Use& use : phi->Uses())
+ {
+ GenTreePhiArg* const phiArgNode = use.GetNode()->AsPhiArg();
+ if (phiArgNode->GetLclNum() != phiDefLclNode->GetLclNum())
+ {
+ SetHasErrors();
+ JITDUMP("[error] Wrong local V%02u in PhiArg [%06u] -- expected V%02u\n", phiArgNode->GetLclNum(),
+ m_compiler->dspTreeID(phiArgNode), phiDefLclNode->GetLclNum());
+ }
+
+ // Handlers can have multiple PhiArgs from the same block and implicit preds.
+ // So we can't easily check their PhiArgs.
+ //
+ if (m_compiler->bbIsHandlerBeg(block))
+ {
+ continue;
+ }
+
+ BasicBlock* const phiArgBlock = phiArgNode->gtPredBB;
+
+ if (phiArgBlock != nullptr)
+ {
+ if (BitVecOps::IsMember(&bitVecTraits, phiPreds, phiArgBlock->bbNum))
+ {
+ SetHasErrors();
+ JITDUMP("[error] " FMT_BB " [%06u]: multiple PhiArgs for predBlock " FMT_BB "\n", block->bbNum,
+ m_compiler->dspTreeID(phi), phiArgBlock->bbNum);
+ }
+
+ BitVecOps::AddElemD(&bitVecTraits, phiPreds, phiArgBlock->bbNum);
+
+ // If phiArgBlock is not a pred of block we either have messed up when building
+ // SSA or made modifications after building SSA and possibly should have pruned
+ // out or updated this PhiArg.
+ //
+ FlowEdge* const edge = m_compiler->fgGetPredForBlock(block, phiArgBlock);
+
+ if (edge == nullptr)
+ {
+ JITDUMP("[info] " FMT_BB " [%06u]: stale PhiArg [%06u] pred block " FMT_BB "\n", block->bbNum,
+ m_compiler->dspTreeID(phi), m_compiler->dspTreeID(phiArgNode), phiArgBlock->bbNum);
+ }
+ }
+ }
+ }
}
void DoChecks()
return false;
}
+ // Bypass handler blocks, as they can have unusual PHI args.
+ // In particular multiple SSA defs coming from the same block.
+ //
+ if (bbIsHandlerBeg(block))
+ {
+ return false;
+ }
+
// Find occurrences of phi def VNs in the relop VN.
// We currently just do one level of func destructuring.
//
ValueNum phiArgVN = phiArgNode->GetVN(VNK_Liberal);
// We sometimes see cases where phi args do not have VNs.
- // (I recall seeing this before... track down why)
+ // (VN works in RPO, so PHIs from back edges won't have VNs.
//
if (phiArgVN != ValueNumStore::NoVN)
{
newRelopArgs[i] = phiArgVN;
updatedArg = true;
-
- // paranoia: keep walking uses to make sure no other
- // comes from this pred
break;
}
}