void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) { // The LiveIn map, for each (physical) register, contains the set of live // reaching defs of that register that are live on entry to the associated // block. // The summary of the traversal algorithm: // // R is live-in in B, if there exists a U(R), such that rdef(R) dom B // and (U \in IDF(B) or B dom U). // // for (C : children) { // LU = {} // traverse(C, LU) // LiveUses += LU // } // // LiveUses -= Defs(B); // LiveUses += UpwardExposedUses(B); // for (C : IIDF[B]) // for (U : LiveUses) // if (Rdef(U) dom C) // C.addLiveIn(U) // // Go up the dominator tree (depth-first). MachineDomTreeNode *N = MDT.getNode(B); for (auto I : *N) { RefMap L; MachineBasicBlock *SB = I->getBlock(); traverse(SB, L); for (auto S : L) LiveIn[S.first].insert(S.second.begin(), S.second.end()); } if (Trace) { dbgs() << LLVM_FUNCTION_NAME << " in BB#" << B->getNumber() << " after recursion into"; for (auto I : *N) dbgs() << ' ' << I->getBlock()->getNumber(); dbgs() << "\n LiveIn: " << Print<RefMap>(LiveIn, DFG); dbgs() << "\n Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Add phi uses that are live on exit from this block. RefMap &PUs = PhiLOX[B]; for (auto S : PUs) LiveIn[S.first].insert(S.second.begin(), S.second.end()); if (Trace) { dbgs() << "after LOX\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Stop tracking all uses defined in this block: erase those records // where the reaching def is located in B and which cover all reached // uses. auto Copy = LiveIn; LiveIn.clear(); for (auto I : Copy) { auto &Defs = LiveIn[I.first]; NodeSet Rest; for (auto R : I.second) { auto DA = DFG.addr<DefNode*>(R); RegisterRef DDR = DA.Addr->getRegRef(); NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); // Defs from a different block need to be preserved. Defs from this // block will need to be processed further, except for phi defs, the // liveness of which is handled through the PhiLON/PhiLOX maps. if (B != BA.Addr->getCode()) Defs.insert(R); else { bool IsPreserving = DA.Addr->getFlags() & NodeAttrs::Preserving; if (IA.Addr->getKind() != NodeAttrs::Phi && !IsPreserving) { bool Covering = RAI.covers(DDR, I.first); NodeId U = DA.Addr->getReachedUse(); while (U && Covering) { auto DUA = DFG.addr<UseNode*>(U); RegisterRef Q = DUA.Addr->getRegRef(); Covering = RAI.covers(DA.Addr->getRegRef(), Q); U = DUA.Addr->getSibling(); } if (!Covering) Rest.insert(R); } } } // Non-covering defs from B. for (auto R : Rest) { auto DA = DFG.addr<DefNode*>(R); RegisterRef DRR = DA.Addr->getRegRef(); RegisterSet RRs; for (NodeAddr<DefNode*> TA : getAllReachingDefs(DA)) { NodeAddr<InstrNode*> IA = TA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); // Preserving defs do not count towards covering. if (!(TA.Addr->getFlags() & NodeAttrs::Preserving)) RRs.insert(TA.Addr->getRegRef()); if (BA.Addr->getCode() == B) continue; if (RAI.covers(RRs, DRR)) break; Defs.insert(TA.Id); } } } emptify(LiveIn); if (Trace) { dbgs() << "after defs in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Scan the block for upward-exposed uses and add them to the tracking set. for (auto I : DFG.getFunc().Addr->findBlock(B, DFG).Addr->members(DFG)) { NodeAddr<InstrNode*> IA = I; if (IA.Addr->getKind() != NodeAttrs::Stmt) continue; for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) { RegisterRef RR = UA.Addr->getRegRef(); for (auto D : getAllReachingDefs(UA)) if (getBlockWithRef(D.Id) != B) LiveIn[RR].insert(D.Id); } } if (Trace) { dbgs() << "after uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Phi uses should not be propagated up the dominator tree, since they // are not dominated by their corresponding reaching defs. auto &Local = LiveMap[B]; auto &LON = PhiLON[B]; for (auto R : LON) Local.insert(R.first); if (Trace) { dbgs() << "after phi uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(Local, DFG) << '\n'; } for (auto C : IIDF[B]) { auto &LiveC = LiveMap[C]; for (auto S : LiveIn) for (auto R : S.second) if (MDT.properlyDominates(getBlockWithRef(R), C)) LiveC.insert(S.first); } }
void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) { // The LiveIn map, for each (physical) register, contains the set of live // reaching defs of that register that are live on entry to the associated // block. // The summary of the traversal algorithm: // // R is live-in in B, if there exists a U(R), such that rdef(R) dom B // and (U \in IDF(B) or B dom U). // // for (C : children) { // LU = {} // traverse(C, LU) // LiveUses += LU // } // // LiveUses -= Defs(B); // LiveUses += UpwardExposedUses(B); // for (C : IIDF[B]) // for (U : LiveUses) // if (Rdef(U) dom C) // C.addLiveIn(U) // // Go up the dominator tree (depth-first). MachineDomTreeNode *N = MDT.getNode(B); for (auto I : *N) { RefMap L; MachineBasicBlock *SB = I->getBlock(); traverse(SB, L); for (auto S : L) LiveIn[S.first].insert(S.second.begin(), S.second.end()); } if (Trace) { dbgs() << "\n-- BB#" << B->getNumber() << ": " << __func__ << " after recursion into: {"; for (auto I : *N) dbgs() << ' ' << I->getBlock()->getNumber(); dbgs() << " }\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // Add reaching defs of phi uses that are live on exit from this block. RefMap &PUs = PhiLOX[B]; for (auto &S : PUs) LiveIn[S.first].insert(S.second.begin(), S.second.end()); if (Trace) { dbgs() << "after LOX\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // The LiveIn map at this point has all defs that are live-on-exit from B, // as if they were live-on-entry to B. First, we need to filter out all // defs that are present in this block. Then we will add reaching defs of // all upward-exposed uses. // To filter out the defs, first make a copy of LiveIn, and then re-populate // LiveIn with the defs that should remain. RefMap LiveInCopy = LiveIn; LiveIn.clear(); for (const std::pair<RegisterId,NodeRefSet> &LE : LiveInCopy) { RegisterRef LRef(LE.first); NodeRefSet &NewDefs = LiveIn[LRef.Reg]; // To be filled. const NodeRefSet &OldDefs = LE.second; for (NodeRef OR : OldDefs) { // R is a def node that was live-on-exit auto DA = DFG.addr<DefNode*>(OR.first); NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); if (B != BA.Addr->getCode()) { // Defs from a different block need to be preserved. Defs from this // block will need to be processed further, except for phi defs, the // liveness of which is handled through the PhiLON/PhiLOX maps. NewDefs.insert(OR); continue; } // Defs from this block need to stop the liveness from being // propagated upwards. This only applies to non-preserving defs, // and to the parts of the register actually covered by those defs. // (Note that phi defs should always be preserving.) RegisterAggr RRs(PRI); LRef.Mask = OR.second; if (!DFG.IsPreservingDef(DA)) { assert(!(IA.Addr->getFlags() & NodeAttrs::Phi)); // DA is a non-phi def that is live-on-exit from this block, and // that is also located in this block. LRef is a register ref // whose use this def reaches. If DA covers LRef, then no part // of LRef is exposed upwards.A if (RRs.insert(DA.Addr->getRegRef(DFG)).hasCoverOf(LRef)) continue; } // DA itself was not sufficient to cover LRef. In general, it is // the last in a chain of aliased defs before the exit from this block. // There could be other defs in this block that are a part of that // chain. Check that now: accumulate the registers from these defs, // and if they all together cover LRef, it is not live-on-entry. for (NodeAddr<DefNode*> TA : getAllReachingDefs(DA)) { // DefNode -> InstrNode -> BlockNode. NodeAddr<InstrNode*> ITA = TA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BTA = ITA.Addr->getOwner(DFG); // Reaching defs are ordered in the upward direction. if (BTA.Addr->getCode() != B) { // We have reached past the beginning of B, and the accumulated // registers are not covering LRef. The first def from the // upward chain will be live. // Subtract all accumulated defs (RRs) from LRef. RegisterAggr L(PRI); L.insert(LRef).clear(RRs); assert(!L.empty()); NewDefs.insert({TA.Id,L.begin()->second}); break; } // TA is in B. Only add this def to the accumulated cover if it is // not preserving. if (!(TA.Addr->getFlags() & NodeAttrs::Preserving)) RRs.insert(TA.Addr->getRegRef(DFG)); // If this is enough to cover LRef, then stop. if (RRs.hasCoverOf(LRef)) break; } } } emptify(LiveIn); if (Trace) { dbgs() << "after defs in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // Scan the block for upward-exposed uses and add them to the tracking set. for (auto I : DFG.getFunc().Addr->findBlock(B, DFG).Addr->members(DFG)) { NodeAddr<InstrNode*> IA = I; if (IA.Addr->getKind() != NodeAttrs::Stmt) continue; for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) { if (UA.Addr->getFlags() & NodeAttrs::Undef) continue; RegisterRef RR = PRI.normalize(UA.Addr->getRegRef(DFG)); for (NodeAddr<DefNode*> D : getAllReachingDefs(UA)) if (getBlockWithRef(D.Id) != B) LiveIn[RR.Reg].insert({D.Id,RR.Mask}); } } if (Trace) { dbgs() << "after uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // Phi uses should not be propagated up the dominator tree, since they // are not dominated by their corresponding reaching defs. RegisterAggr &Local = LiveMap[B]; RefMap &LON = PhiLON[B]; for (auto &R : LON) { LaneBitmask M; for (auto P : R.second) M |= P.second; Local.insert(RegisterRef(R.first,M)); } if (Trace) { dbgs() << "after phi uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(Local, DFG) << '\n'; } for (auto C : IIDF[B]) { RegisterAggr &LiveC = LiveMap[C]; for (const std::pair<RegisterId,NodeRefSet> &S : LiveIn) for (auto R : S.second) if (MDT.properlyDominates(getBlockWithRef(R.first), C)) LiveC.insert(RegisterRef(S.first, R.second)); } }