void HexagonExpandCondsets::updateDeadsInRange(unsigned Reg, LaneBitmask LM, LiveRange &Range) { assert(TargetRegisterInfo::isVirtualRegister(Reg)); if (Range.empty()) return; // Return two booleans: { def-modifes-reg, def-covers-reg }. auto IsRegDef = [this,Reg,LM] (MachineOperand &Op) -> std::pair<bool,bool> { if (!Op.isReg() || !Op.isDef()) return { false, false }; unsigned DR = Op.getReg(), DSR = Op.getSubReg(); if (!TargetRegisterInfo::isVirtualRegister(DR) || DR != Reg) return { false, false }; LaneBitmask SLM = getLaneMask(DR, DSR); LaneBitmask A = SLM & LM; return { A.any(), A == SLM }; }; // The splitting step will create pairs of predicated definitions without // any implicit uses (since implicit uses would interfere with predication). // This can cause the reaching defs to become dead after live range // recomputation, even though they are not really dead. // We need to identify predicated defs that need implicit uses, and // dead defs that are not really dead, and correct both problems. auto Dominate = [this] (SetVector<MachineBasicBlock*> &Defs, MachineBasicBlock *Dest) -> bool { for (MachineBasicBlock *D : Defs) if (D != Dest && MDT->dominates(D, Dest)) return true; MachineBasicBlock *Entry = &Dest->getParent()->front(); SetVector<MachineBasicBlock*> Work(Dest->pred_begin(), Dest->pred_end()); for (unsigned i = 0; i < Work.size(); ++i) { MachineBasicBlock *B = Work[i]; if (Defs.count(B)) continue; if (B == Entry) return false; for (auto *P : B->predecessors()) Work.insert(P); } return true; }; // First, try to extend live range within individual basic blocks. This // will leave us only with dead defs that do not reach any predicated // defs in the same block. SetVector<MachineBasicBlock*> Defs; SmallVector<SlotIndex,4> PredDefs; for (auto &Seg : Range) { if (!Seg.start.isRegister()) continue; MachineInstr *DefI = LIS->getInstructionFromIndex(Seg.start); Defs.insert(DefI->getParent()); if (HII->isPredicated(*DefI)) PredDefs.push_back(Seg.start); } SmallVector<SlotIndex,8> Undefs; LiveInterval &LI = LIS->getInterval(Reg); LI.computeSubRangeUndefs(Undefs, LM, *MRI, *LIS->getSlotIndexes()); for (auto &SI : PredDefs) { MachineBasicBlock *BB = LIS->getMBBFromIndex(SI); auto P = Range.extendInBlock(Undefs, LIS->getMBBStartIdx(BB), SI); if (P.first != nullptr || P.second) SI = SlotIndex(); } // Calculate reachability for those predicated defs that were not handled // by the in-block extension. SmallVector<SlotIndex,4> ExtTo; for (auto &SI : PredDefs) { if (!SI.isValid()) continue; MachineBasicBlock *BB = LIS->getMBBFromIndex(SI); if (BB->pred_empty()) continue; // If the defs from this range reach SI via all predecessors, it is live. // It can happen that SI is reached by the defs through some paths, but // not all. In the IR coming into this optimization, SI would not be // considered live, since the defs would then not jointly dominate SI. // That means that SI is an overwriting def, and no implicit use is // needed at this point. Do not add SI to the extension points, since // extendToIndices will abort if there is no joint dominance. // If the abort was avoided by adding extra undefs added to Undefs, // extendToIndices could actually indicate that SI is live, contrary // to the original IR. if (Dominate(Defs, BB)) ExtTo.push_back(SI); } if (!ExtTo.empty()) LIS->extendToIndices(Range, ExtTo, Undefs); // Remove <dead> flags from all defs that are not dead after live range // extension, and collect all def operands. They will be used to generate // the necessary implicit uses. // At the same time, add <dead> flag to all defs that are actually dead. // This can happen, for example, when a mux with identical inputs is // replaced with a COPY: the use of the predicate register disappears and // the dead can become dead. std::set<RegisterRef> DefRegs; for (auto &Seg : Range) { if (!Seg.start.isRegister()) continue; MachineInstr *DefI = LIS->getInstructionFromIndex(Seg.start); for (auto &Op : DefI->operands()) { auto P = IsRegDef(Op); if (P.second && Seg.end.isDead()) { Op.setIsDead(true); } else if (P.first) { DefRegs.insert(Op); Op.setIsDead(false); } } } // Now, add implicit uses to each predicated def that is reached // by other defs. for (auto &Seg : Range) { if (!Seg.start.isRegister() || !Range.liveAt(Seg.start.getPrevSlot())) continue; MachineInstr *DefI = LIS->getInstructionFromIndex(Seg.start); if (!HII->isPredicated(*DefI)) continue; // Construct the set of all necessary implicit uses, based on the def // operands in the instruction. std::set<RegisterRef> ImpUses; for (auto &Op : DefI->operands()) if (Op.isReg() && Op.isDef() && DefRegs.count(Op)) ImpUses.insert(Op); if (ImpUses.empty()) continue; MachineFunction &MF = *DefI->getParent()->getParent(); for (RegisterRef R : ImpUses) MachineInstrBuilder(MF, DefI).addReg(R.Reg, RegState::Implicit, R.Sub); } }
NodeList Liveness::getAllReachingDefs(RegisterRef RefRR, NodeAddr<RefNode*> RefA, bool TopShadows, bool FullChain, const RegisterAggr &DefRRs) { NodeList RDefs; // Return value. SetVector<NodeId> DefQ; SetVector<NodeId> Owners; // Dead defs will be treated as if they were live, since they are actually // on the data-flow path. They cannot be ignored because even though they // do not generate meaningful values, they still modify registers. // If the reference is undefined, there is nothing to do. if (RefA.Addr->getFlags() & NodeAttrs::Undef) return RDefs; // The initial queue should not have reaching defs for shadows. The // whole point of a shadow is that it will have a reaching def that // is not aliased to the reaching defs of the related shadows. NodeId Start = RefA.Id; auto SNA = DFG.addr<RefNode*>(Start); if (NodeId RD = SNA.Addr->getReachingDef()) DefQ.insert(RD); if (TopShadows) { for (auto S : DFG.getRelatedRefs(RefA.Addr->getOwner(DFG), RefA)) if (NodeId RD = NodeAddr<RefNode*>(S).Addr->getReachingDef()) DefQ.insert(RD); } // Collect all the reaching defs, going up until a phi node is encountered, // or there are no more reaching defs. From this set, the actual set of // reaching defs will be selected. // The traversal upwards must go on until a covering def is encountered. // It is possible that a collection of non-covering (individually) defs // will be sufficient, but keep going until a covering one is found. for (unsigned i = 0; i < DefQ.size(); ++i) { auto TA = DFG.addr<DefNode*>(DefQ[i]); if (TA.Addr->getFlags() & NodeAttrs::PhiRef) continue; // Stop at the covering/overwriting def of the initial register reference. RegisterRef RR = TA.Addr->getRegRef(DFG); if (!DFG.IsPreservingDef(TA)) if (RegisterAggr::isCoverOf(RR, RefRR, PRI)) continue; // Get the next level of reaching defs. This will include multiple // reaching defs for shadows. for (auto S : DFG.getRelatedRefs(TA.Addr->getOwner(DFG), TA)) if (NodeId RD = NodeAddr<RefNode*>(S).Addr->getReachingDef()) DefQ.insert(RD); } // Remove all non-phi defs that are not aliased to RefRR, and collect // the owners of the remaining defs. SetVector<NodeId> Defs; for (NodeId N : DefQ) { auto TA = DFG.addr<DefNode*>(N); bool IsPhi = TA.Addr->getFlags() & NodeAttrs::PhiRef; if (!IsPhi && !PRI.alias(RefRR, TA.Addr->getRegRef(DFG))) continue; Defs.insert(TA.Id); Owners.insert(TA.Addr->getOwner(DFG).Id); } // Return the MachineBasicBlock containing a given instruction. auto Block = [this] (NodeAddr<InstrNode*> IA) -> MachineBasicBlock* { if (IA.Addr->getKind() == NodeAttrs::Stmt) return NodeAddr<StmtNode*>(IA).Addr->getCode()->getParent(); assert(IA.Addr->getKind() == NodeAttrs::Phi); NodeAddr<PhiNode*> PA = IA; NodeAddr<BlockNode*> BA = PA.Addr->getOwner(DFG); return BA.Addr->getCode(); }; // Less(A,B) iff instruction A is further down in the dominator tree than B. auto Less = [&Block,this] (NodeId A, NodeId B) -> bool { if (A == B) return false; auto OA = DFG.addr<InstrNode*>(A), OB = DFG.addr<InstrNode*>(B); MachineBasicBlock *BA = Block(OA), *BB = Block(OB); if (BA != BB) return MDT.dominates(BB, BA); // They are in the same block. bool StmtA = OA.Addr->getKind() == NodeAttrs::Stmt; bool StmtB = OB.Addr->getKind() == NodeAttrs::Stmt; if (StmtA) { if (!StmtB) // OB is a phi and phis dominate statements. return true; MachineInstr *CA = NodeAddr<StmtNode*>(OA).Addr->getCode(); MachineInstr *CB = NodeAddr<StmtNode*>(OB).Addr->getCode(); // The order must be linear, so tie-break such equalities. if (CA == CB) return A < B; return MDT.dominates(CB, CA); } else { // OA is a phi. if (StmtB) return false; // Both are phis. There is no ordering between phis (in terms of // the data-flow), so tie-break this via node id comparison. return A < B; } }; std::vector<NodeId> Tmp(Owners.begin(), Owners.end()); std::sort(Tmp.begin(), Tmp.end(), Less); // The vector is a list of instructions, so that defs coming from // the same instruction don't need to be artificially ordered. // Then, when computing the initial segment, and iterating over an // instruction, pick the defs that contribute to the covering (i.e. is // not covered by previously added defs). Check the defs individually, // i.e. first check each def if is covered or not (without adding them // to the tracking set), and then add all the selected ones. // The reason for this is this example: // *d1<A>, *d2<B>, ... Assume A and B are aliased (can happen in phi nodes). // *d3<C> If A \incl BuC, and B \incl AuC, then *d2 would be // covered if we added A first, and A would be covered // if we added B first. RegisterAggr RRs(DefRRs); auto DefInSet = [&Defs] (NodeAddr<RefNode*> TA) -> bool { return TA.Addr->getKind() == NodeAttrs::Def && Defs.count(TA.Id); }; for (NodeId T : Tmp) { if (!FullChain && RRs.hasCoverOf(RefRR)) break; auto TA = DFG.addr<InstrNode*>(T); bool IsPhi = DFG.IsCode<NodeAttrs::Phi>(TA); NodeList Ds; for (NodeAddr<DefNode*> DA : TA.Addr->members_if(DefInSet, DFG)) { RegisterRef QR = DA.Addr->getRegRef(DFG); // Add phi defs even if they are covered by subsequent defs. This is // for cases where the reached use is not covered by any of the defs // encountered so far: the phi def is needed to expose the liveness // of that use to the entry of the block. // Example: // phi d1<R3>(,d2,), ... Phi def d1 is covered by d2. // d2<R3>(d1,,u3), ... // ..., u3<D1>(d2) This use needs to be live on entry. if (FullChain || IsPhi || !RRs.hasCoverOf(QR)) Ds.push_back(DA); } RDefs.insert(RDefs.end(), Ds.begin(), Ds.end()); for (NodeAddr<DefNode*> DA : Ds) { // When collecting a full chain of definitions, do not consider phi // defs to actually define a register. uint16_t Flags = DA.Addr->getFlags(); if (!FullChain || !(Flags & NodeAttrs::PhiRef)) if (!(Flags & NodeAttrs::Preserving)) // Don't care about Undef here. RRs.insert(DA.Addr->getRegRef(DFG)); } } auto DeadP = [](const NodeAddr<DefNode*> DA) -> bool { return DA.Addr->getFlags() & NodeAttrs::Dead; }; RDefs.resize(std::distance(RDefs.begin(), llvm::remove_if(RDefs, DeadP))); return RDefs; }
void Liveness::computePhiInfo() { RealUseMap.clear(); NodeList Phis; NodeAddr<FuncNode*> FA = DFG.getFunc(); NodeList Blocks = FA.Addr->members(DFG); for (NodeAddr<BlockNode*> BA : Blocks) { auto Ps = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG); Phis.insert(Phis.end(), Ps.begin(), Ps.end()); } // phi use -> (map: reaching phi -> set of registers defined in between) std::map<NodeId,std::map<NodeId,RegisterAggr>> PhiUp; std::vector<NodeId> PhiUQ; // Work list of phis for upward propagation. // Go over all phis. for (NodeAddr<PhiNode*> PhiA : Phis) { // Go over all defs and collect the reached uses that are non-phi uses // (i.e. the "real uses"). RefMap &RealUses = RealUseMap[PhiA.Id]; NodeList PhiRefs = PhiA.Addr->members(DFG); // Have a work queue of defs whose reached uses need to be found. // For each def, add to the queue all reached (non-phi) defs. SetVector<NodeId> DefQ; NodeSet PhiDefs; for (NodeAddr<RefNode*> R : PhiRefs) { if (!DFG.IsRef<NodeAttrs::Def>(R)) continue; DefQ.insert(R.Id); PhiDefs.insert(R.Id); } // Collect the super-set of all possible reached uses. This set will // contain all uses reached from this phi, either directly from the // phi defs, or (recursively) via non-phi defs reached by the phi defs. // This set of uses will later be trimmed to only contain these uses that // are actually reached by the phi defs. for (unsigned i = 0; i < DefQ.size(); ++i) { NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]); // Visit all reached uses. Phi defs should not really have the "dead" // flag set, but check it anyway for consistency. bool IsDead = DA.Addr->getFlags() & NodeAttrs::Dead; NodeId UN = !IsDead ? DA.Addr->getReachedUse() : 0; while (UN != 0) { NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN); uint16_t F = A.Addr->getFlags(); if ((F & (NodeAttrs::Undef | NodeAttrs::PhiRef)) == 0) RealUses[getRestrictedRegRef(A)].insert(A.Id); UN = A.Addr->getSibling(); } // Visit all reached defs, and add them to the queue. These defs may // override some of the uses collected here, but that will be handled // later. NodeId DN = DA.Addr->getReachedDef(); while (DN != 0) { NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN); for (auto T : DFG.getRelatedRefs(A.Addr->getOwner(DFG), A)) { uint16_t Flags = NodeAddr<DefNode*>(T).Addr->getFlags(); // Must traverse the reached-def chain. Consider: // def(D0) -> def(R0) -> def(R0) -> use(D0) // The reachable use of D0 passes through a def of R0. if (!(Flags & NodeAttrs::PhiRef)) DefQ.insert(T.Id); } DN = A.Addr->getSibling(); } } // Filter out these uses that appear to be reachable, but really // are not. For example: // // R1:0 = d1 // = R1:0 u2 Reached by d1. // R0 = d3 // = R1:0 u4 Still reached by d1: indirectly through // the def d3. // R1 = d5 // = R1:0 u6 Not reached by d1 (covered collectively // by d3 and d5), but following reached // defs and uses from d1 will lead here. auto InPhiDefs = [&PhiDefs] (NodeAddr<DefNode*> DA) -> bool { return PhiDefs.count(DA.Id); }; for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) { // For each reached register UI->first, there is a set UI->second, of // uses of it. For each such use, check if it is reached by this phi, // i.e. check if the set of its reaching uses intersects the set of // this phi's defs. NodeSet &Uses = UI->second; for (auto I = Uses.begin(), E = Uses.end(); I != E; ) { auto UA = DFG.addr<UseNode*>(*I); // Undef flag is checked above. assert((UA.Addr->getFlags() & NodeAttrs::Undef) == 0); NodeList RDs = getAllReachingDefs(UI->first, UA); if (any_of(RDs, InPhiDefs)) ++I; else I = Uses.erase(I); } if (Uses.empty()) UI = RealUses.erase(UI); else ++UI; } // If this phi reaches some "real" uses, add it to the queue for upward // propagation. if (!RealUses.empty()) PhiUQ.push_back(PhiA.Id); // Go over all phi uses and check if the reaching def is another phi. // Collect the phis that are among the reaching defs of these uses. // While traversing the list of reaching defs for each phi use, accumulate // the set of registers defined between this phi (PhiA) and the owner phi // of the reaching def. NodeSet SeenUses; for (auto I : PhiRefs) { if (!DFG.IsRef<NodeAttrs::Use>(I) || SeenUses.count(I.Id)) continue; NodeAddr<UseNode*> UA = I; // Given a phi use UA, traverse all related phi uses (including UA). // The related phi uses may reach different phi nodes or may reach the // same phi node. If multiple uses reach the same phi P, the intervening // defs must be accumulated for all such uses. To group all such uses // into one set, map their node ids to the first use id that reaches P. std::map<NodeId,NodeId> FirstUse; // Phi reached up -> first phi use. for (NodeAddr<UseNode*> VA : DFG.getRelatedRefs(PhiA, UA)) { SeenUses.insert(VA.Id); RegisterAggr DefRRs(DFG.getLMI(), TRI); for (NodeAddr<DefNode*> DA : getAllReachingDefs(VA)) { if (DA.Addr->getFlags() & NodeAttrs::PhiRef) { NodeId RP = DA.Addr->getOwner(DFG).Id; NodeId FU = FirstUse.insert({RP,VA.Id}).first->second; std::map<NodeId,RegisterAggr> &M = PhiUp[FU]; auto F = M.find(RP); if (F == M.end()) M.insert(std::make_pair(RP, DefRRs)); else F->second.insert(DefRRs); } DefRRs.insert(DA.Addr->getRegRef()); } } } } if (Trace) { dbgs() << "Phi-up-to-phi map with intervening defs:\n"; for (auto I : PhiUp) { dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {"; for (auto R : I.second) dbgs() << ' ' << Print<NodeId>(R.first, DFG) << Print<RegisterAggr>(R.second, DFG); dbgs() << " }\n"; } } // Propagate the reached registers up in the phi chain. // // The following type of situation needs careful handling: // // phi d1<R1:0> (1) // | // ... d2<R1> // | // phi u3<R1:0> (2) // | // ... u4<R1> // // The phi node (2) defines a register pair R1:0, and reaches a "real" // use u4 of just R1. The same phi node is also known to reach (upwards) // the phi node (1). However, the use u4 is not reached by phi (1), // because of the intervening definition d2 of R1. The data flow between // phis (1) and (2) is restricted to R1:0 minus R1, i.e. R0. // // When propagating uses up the phi chains, get the all reaching defs // for a given phi use, and traverse the list until the propagated ref // is covered, or until reaching the final phi. Only assume that the // reference reaches the phi in the latter case. for (unsigned i = 0; i < PhiUQ.size(); ++i) { auto PA = DFG.addr<PhiNode*>(PhiUQ[i]); NodeList PUs = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG); RefMap &RUM = RealUseMap[PA.Id]; for (NodeAddr<UseNode*> UA : PUs) { std::map<NodeId,RegisterAggr> &PUM = PhiUp[UA.Id]; for (const std::pair<NodeId,RegisterAggr> &P : PUM) { bool Changed = false; const RegisterAggr &MidDefs = P.second; // Collect the set UpReached of uses that are reached by the current // phi PA, and are not covered by any intervening def between PA and // the upward phi P. RegisterSet UpReached; for (const std::pair<RegisterRef,NodeSet> &T : RUM) { RegisterRef R = T.first; if (UA.Addr->getFlags() & NodeAttrs::Shadow) R = getRestrictedRegRef(UA); if (!MidDefs.hasCoverOf(R)) UpReached.insert(R); } if (UpReached.empty()) continue; // Update the set PRUs of real uses reached by the upward phi P with // the actual set of uses (UpReached) that the P phi reaches. RefMap &PRUs = RealUseMap[P.first]; for (RegisterRef R : UpReached) { unsigned Z = PRUs[R].size(); PRUs[R].insert(RUM[R].begin(), RUM[R].end()); Changed |= (PRUs[R].size() != Z); } if (Changed) PhiUQ.push_back(P.first); } } } if (Trace) { dbgs() << "Real use map:\n"; for (auto I : RealUseMap) { dbgs() << "phi " << Print<NodeId>(I.first, DFG); NodeAddr<PhiNode*> PA = DFG.addr<PhiNode*>(I.first); NodeList Ds = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Def>, DFG); if (!Ds.empty()) { RegisterRef RR = NodeAddr<DefNode*>(Ds[0]).Addr->getRegRef(); dbgs() << '<' << Print<RegisterRef>(RR, DFG) << '>'; } else { dbgs() << "<noreg>"; } dbgs() << " -> " << Print<RefMap>(I.second, DFG) << '\n'; } } }
bool LiveRangeCalc::isDefOnEntry(LiveRange &LR, ArrayRef<SlotIndex> Undefs, MachineBasicBlock &MBB, BitVector &DefOnEntry, BitVector &UndefOnEntry) { unsigned BN = MBB.getNumber(); if (DefOnEntry[BN]) return true; if (UndefOnEntry[BN]) return false; auto MarkDefined = [BN, &DefOnEntry](MachineBasicBlock &B) -> bool { for (MachineBasicBlock *S : B.successors()) DefOnEntry[S->getNumber()] = true; DefOnEntry[BN] = true; return true; }; SetVector<unsigned> WorkList; // Checking if the entry of MBB is reached by some def: add all predecessors // that are potentially defined-on-exit to the work list. for (MachineBasicBlock *P : MBB.predecessors()) WorkList.insert(P->getNumber()); for (unsigned i = 0; i != WorkList.size(); ++i) { // Determine if the exit from the block is reached by some def. unsigned N = WorkList[i]; MachineBasicBlock &B = *MF->getBlockNumbered(N); if (Seen[N]) { const LiveOutPair &LOB = Map[&B]; if (LOB.first != nullptr && LOB.first != &UndefVNI) return MarkDefined(B); } SlotIndex Begin, End; std::tie(Begin, End) = Indexes->getMBBRange(&B); // Treat End as not belonging to B. // If LR has a segment S that starts at the next block, i.e. [End, ...), // std::upper_bound will return the segment following S. Instead, // S should be treated as the first segment that does not overlap B. LiveRange::iterator UB = std::upper_bound(LR.begin(), LR.end(), End.getPrevSlot()); if (UB != LR.begin()) { LiveRange::Segment &Seg = *std::prev(UB); if (Seg.end > Begin) { // There is a segment that overlaps B. If the range is not explicitly // undefined between the end of the segment and the end of the block, // treat the block as defined on exit. If it is, go to the next block // on the work list. if (LR.isUndefIn(Undefs, Seg.end, End)) continue; return MarkDefined(B); } } // No segment overlaps with this block. If this block is not defined on // entry, or it undefines the range, do not process its predecessors. if (UndefOnEntry[N] || LR.isUndefIn(Undefs, Begin, End)) { UndefOnEntry[N] = true; continue; } if (DefOnEntry[N]) return MarkDefined(B); // Still don't know: add all predecessors to the work list. for (MachineBasicBlock *P : B.predecessors()) WorkList.insert(P->getNumber()); } UndefOnEntry[BN] = true; return false; }
void Liveness::computePhiInfo() { RealUseMap.clear(); NodeList Phis; NodeAddr<FuncNode*> FA = DFG.getFunc(); NodeList Blocks = FA.Addr->members(DFG); for (NodeAddr<BlockNode*> BA : Blocks) { auto Ps = BA.Addr->members_if(DFG.IsCode<NodeAttrs::Phi>, DFG); Phis.insert(Phis.end(), Ps.begin(), Ps.end()); } // phi use -> (map: reaching phi -> set of registers defined in between) std::map<NodeId,std::map<NodeId,RegisterAggr>> PhiUp; std::vector<NodeId> PhiUQ; // Work list of phis for upward propagation. std::map<NodeId,RegisterAggr> PhiDRs; // Phi -> registers defined by it. // Go over all phis. for (NodeAddr<PhiNode*> PhiA : Phis) { // Go over all defs and collect the reached uses that are non-phi uses // (i.e. the "real uses"). RefMap &RealUses = RealUseMap[PhiA.Id]; NodeList PhiRefs = PhiA.Addr->members(DFG); // Have a work queue of defs whose reached uses need to be found. // For each def, add to the queue all reached (non-phi) defs. SetVector<NodeId> DefQ; NodeSet PhiDefs; RegisterAggr DRs(PRI); for (NodeAddr<RefNode*> R : PhiRefs) { if (!DFG.IsRef<NodeAttrs::Def>(R)) continue; DRs.insert(R.Addr->getRegRef(DFG)); DefQ.insert(R.Id); PhiDefs.insert(R.Id); } PhiDRs.insert(std::make_pair(PhiA.Id, DRs)); // Collect the super-set of all possible reached uses. This set will // contain all uses reached from this phi, either directly from the // phi defs, or (recursively) via non-phi defs reached by the phi defs. // This set of uses will later be trimmed to only contain these uses that // are actually reached by the phi defs. for (unsigned i = 0; i < DefQ.size(); ++i) { NodeAddr<DefNode*> DA = DFG.addr<DefNode*>(DefQ[i]); // Visit all reached uses. Phi defs should not really have the "dead" // flag set, but check it anyway for consistency. bool IsDead = DA.Addr->getFlags() & NodeAttrs::Dead; NodeId UN = !IsDead ? DA.Addr->getReachedUse() : 0; while (UN != 0) { NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN); uint16_t F = A.Addr->getFlags(); if ((F & (NodeAttrs::Undef | NodeAttrs::PhiRef)) == 0) { RegisterRef R = PRI.normalize(A.Addr->getRegRef(DFG)); RealUses[R.Reg].insert({A.Id,R.Mask}); } UN = A.Addr->getSibling(); } // Visit all reached defs, and add them to the queue. These defs may // override some of the uses collected here, but that will be handled // later. NodeId DN = DA.Addr->getReachedDef(); while (DN != 0) { NodeAddr<DefNode*> A = DFG.addr<DefNode*>(DN); for (auto T : DFG.getRelatedRefs(A.Addr->getOwner(DFG), A)) { uint16_t Flags = NodeAddr<DefNode*>(T).Addr->getFlags(); // Must traverse the reached-def chain. Consider: // def(D0) -> def(R0) -> def(R0) -> use(D0) // The reachable use of D0 passes through a def of R0. if (!(Flags & NodeAttrs::PhiRef)) DefQ.insert(T.Id); } DN = A.Addr->getSibling(); } } // Filter out these uses that appear to be reachable, but really // are not. For example: // // R1:0 = d1 // = R1:0 u2 Reached by d1. // R0 = d3 // = R1:0 u4 Still reached by d1: indirectly through // the def d3. // R1 = d5 // = R1:0 u6 Not reached by d1 (covered collectively // by d3 and d5), but following reached // defs and uses from d1 will lead here. for (auto UI = RealUses.begin(), UE = RealUses.end(); UI != UE; ) { // For each reached register UI->first, there is a set UI->second, of // uses of it. For each such use, check if it is reached by this phi, // i.e. check if the set of its reaching uses intersects the set of // this phi's defs. NodeRefSet Uses = UI->second; UI->second.clear(); for (std::pair<NodeId,LaneBitmask> I : Uses) { auto UA = DFG.addr<UseNode*>(I.first); // Undef flag is checked above. assert((UA.Addr->getFlags() & NodeAttrs::Undef) == 0); RegisterRef R(UI->first, I.second); // Calculate the exposed part of the reached use. RegisterAggr Covered(PRI); for (NodeAddr<DefNode*> DA : getAllReachingDefs(R, UA)) { if (PhiDefs.count(DA.Id)) break; Covered.insert(DA.Addr->getRegRef(DFG)); } if (RegisterRef RC = Covered.clearIn(R)) { // We are updating the map for register UI->first, so we need // to map RC to be expressed in terms of that register. RegisterRef S = PRI.mapTo(RC, UI->first); UI->second.insert({I.first, S.Mask}); } } UI = UI->second.empty() ? RealUses.erase(UI) : std::next(UI); } // If this phi reaches some "real" uses, add it to the queue for upward // propagation. if (!RealUses.empty()) PhiUQ.push_back(PhiA.Id); // Go over all phi uses and check if the reaching def is another phi. // Collect the phis that are among the reaching defs of these uses. // While traversing the list of reaching defs for each phi use, accumulate // the set of registers defined between this phi (PhiA) and the owner phi // of the reaching def. NodeSet SeenUses; for (auto I : PhiRefs) { if (!DFG.IsRef<NodeAttrs::Use>(I) || SeenUses.count(I.Id)) continue; NodeAddr<PhiUseNode*> PUA = I; if (PUA.Addr->getReachingDef() == 0) continue; RegisterRef UR = PUA.Addr->getRegRef(DFG); NodeList Ds = getAllReachingDefs(UR, PUA, true, false, NoRegs); RegisterAggr DefRRs(PRI); for (NodeAddr<DefNode*> D : Ds) { if (D.Addr->getFlags() & NodeAttrs::PhiRef) { NodeId RP = D.Addr->getOwner(DFG).Id; std::map<NodeId,RegisterAggr> &M = PhiUp[PUA.Id]; auto F = M.find(RP); if (F == M.end()) M.insert(std::make_pair(RP, DefRRs)); else F->second.insert(DefRRs); } DefRRs.insert(D.Addr->getRegRef(DFG)); } for (NodeAddr<PhiUseNode*> T : DFG.getRelatedRefs(PhiA, PUA)) SeenUses.insert(T.Id); } } if (Trace) { dbgs() << "Phi-up-to-phi map with intervening defs:\n"; for (auto I : PhiUp) { dbgs() << "phi " << Print<NodeId>(I.first, DFG) << " -> {"; for (auto R : I.second) dbgs() << ' ' << Print<NodeId>(R.first, DFG) << Print<RegisterAggr>(R.second, DFG); dbgs() << " }\n"; } } // Propagate the reached registers up in the phi chain. // // The following type of situation needs careful handling: // // phi d1<R1:0> (1) // | // ... d2<R1> // | // phi u3<R1:0> (2) // | // ... u4<R1> // // The phi node (2) defines a register pair R1:0, and reaches a "real" // use u4 of just R1. The same phi node is also known to reach (upwards) // the phi node (1). However, the use u4 is not reached by phi (1), // because of the intervening definition d2 of R1. The data flow between // phis (1) and (2) is restricted to R1:0 minus R1, i.e. R0. // // When propagating uses up the phi chains, get the all reaching defs // for a given phi use, and traverse the list until the propagated ref // is covered, or until reaching the final phi. Only assume that the // reference reaches the phi in the latter case. for (unsigned i = 0; i < PhiUQ.size(); ++i) { auto PA = DFG.addr<PhiNode*>(PhiUQ[i]); NodeList PUs = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Use>, DFG); RefMap &RUM = RealUseMap[PA.Id]; for (NodeAddr<UseNode*> UA : PUs) { std::map<NodeId,RegisterAggr> &PUM = PhiUp[UA.Id]; RegisterRef UR = PRI.normalize(UA.Addr->getRegRef(DFG)); for (const std::pair<NodeId,RegisterAggr> &P : PUM) { bool Changed = false; const RegisterAggr &MidDefs = P.second; // Collect the set PropUp of uses that are reached by the current // phi PA, and are not covered by any intervening def between the // currently visited use UA and the the upward phi P. if (MidDefs.hasCoverOf(UR)) continue; // General algorithm: // for each (R,U) : U is use node of R, U is reached by PA // if MidDefs does not cover (R,U) // then add (R-MidDefs,U) to RealUseMap[P] // for (const std::pair<RegisterId,NodeRefSet> &T : RUM) { RegisterRef R(T.first); // The current phi (PA) could be a phi for a regmask. It could // reach a whole variety of uses that are not related to the // specific upward phi (P.first). const RegisterAggr &DRs = PhiDRs.at(P.first); if (!DRs.hasAliasOf(R)) continue; R = PRI.mapTo(DRs.intersectWith(R), T.first); for (std::pair<NodeId,LaneBitmask> V : T.second) { LaneBitmask M = R.Mask & V.second; if (M.none()) continue; if (RegisterRef SS = MidDefs.clearIn(RegisterRef(R.Reg, M))) { NodeRefSet &RS = RealUseMap[P.first][SS.Reg]; Changed |= RS.insert({V.first,SS.Mask}).second; } } } if (Changed) PhiUQ.push_back(P.first); } } } if (Trace) { dbgs() << "Real use map:\n"; for (auto I : RealUseMap) { dbgs() << "phi " << Print<NodeId>(I.first, DFG); NodeAddr<PhiNode*> PA = DFG.addr<PhiNode*>(I.first); NodeList Ds = PA.Addr->members_if(DFG.IsRef<NodeAttrs::Def>, DFG); if (!Ds.empty()) { RegisterRef RR = NodeAddr<DefNode*>(Ds[0]).Addr->getRegRef(DFG); dbgs() << '<' << Print<RegisterRef>(RR, DFG) << '>'; } else { dbgs() << "<noreg>"; } dbgs() << " -> " << Print<RefMap>(I.second, DFG) << '\n'; } } }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); // Use lazy loading, since we only care about selected global values. SMDiagnostic Err; std::unique_ptr<Module> M = getLazyIRFileModule(InputFilename, Err, Context); if (!M.get()) { Err.print(argv[0], errs()); return 1; } // Use SetVector to avoid duplicates. SetVector<GlobalValue *> GVs; // Figure out which aliases we should extract. for (size_t i = 0, e = ExtractAliases.size(); i != e; ++i) { GlobalAlias *GA = M->getNamedAlias(ExtractAliases[i]); if (!GA) { errs() << argv[0] << ": program doesn't contain alias named '" << ExtractAliases[i] << "'!\n"; return 1; } GVs.insert(GA); } // Extract aliases via regular expression matching. for (size_t i = 0, e = ExtractRegExpAliases.size(); i != e; ++i) { std::string Error; Regex RegEx(ExtractRegExpAliases[i]); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpAliases[i] << "' " "invalid regex: " << Error; } bool match = false; for (Module::alias_iterator GA = M->alias_begin(), E = M->alias_end(); GA != E; GA++) { if (RegEx.match(GA->getName())) { GVs.insert(&*GA); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpAliases[i] << "'!\n"; return 1; } } // Figure out which globals we should extract. for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { GlobalValue *GV = M->getNamedGlobal(ExtractGlobals[i]); if (!GV) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractGlobals[i] << "'!\n"; return 1; } GVs.insert(GV); } // Extract globals via regular expression matching. for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) { std::string Error; Regex RegEx(ExtractRegExpGlobals[i]); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' " "invalid regex: " << Error; } bool match = false; for (auto &GV : M->globals()) { if (RegEx.match(GV.getName())) { GVs.insert(&GV); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpGlobals[i] << "'!\n"; return 1; } } // Figure out which functions we should extract. for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) { GlobalValue *GV = M->getFunction(ExtractFuncs[i]); if (!GV) { errs() << argv[0] << ": program doesn't contain function named '" << ExtractFuncs[i] << "'!\n"; return 1; } GVs.insert(GV); } // Extract functions via regular expression matching. for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) { std::string Error; StringRef RegExStr = ExtractRegExpFuncs[i]; Regex RegEx(RegExStr); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' " "invalid regex: " << Error; } bool match = false; for (Module::iterator F = M->begin(), E = M->end(); F != E; F++) { if (RegEx.match(F->getName())) { GVs.insert(&*F); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpFuncs[i] << "'!\n"; return 1; } } // Materialize requisite global values. if (!DeleteFn) for (size_t i = 0, e = GVs.size(); i != e; ++i) { GlobalValue *GV = GVs[i]; if (std::error_code EC = GV->materialize()) { errs() << argv[0] << ": error reading input: " << EC.message() << "\n"; return 1; } } else { // Deleting. Materialize every GV that's *not* in GVs. SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end()); for (auto &G : M->globals()) { if (!GVSet.count(&G)) { if (std::error_code EC = G.materialize()) { errs() << argv[0] << ": error reading input: " << EC.message() << "\n"; return 1; } } } for (auto &F : *M) { if (!GVSet.count(&F)) { if (std::error_code EC = F.materialize()) { errs() << argv[0] << ": error reading input: " << EC.message() << "\n"; return 1; } } } } // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. legacy::PassManager Passes; std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); Passes.add(createGVExtractionPass(Gvs, DeleteFn)); if (!DeleteFn) Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls std::error_code EC; tool_output_file Out(OutputFilename, EC, sys::fs::F_None); if (EC) { errs() << EC.message() << '\n'; return 1; } if (OutputAssembly) Passes.add( createPrintModulePass(Out.os(), "", PreserveAssemblyUseListOrder)); else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) Passes.add(createBitcodeWriterPass(Out.os(), PreserveBitcodeUseListOrder)); Passes.run(*M.get()); // Declare success. Out.keep(); return 0; }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); // Use lazy loading, since we only care about selected global values. SMDiagnostic Err; std::auto_ptr<Module> M; M.reset(getLazyIRFileModule(InputFilename, Err, Context)); if (M.get() == 0) { Err.Print(argv[0], errs()); return 1; } // Use SetVector to avoid duplicates. SetVector<GlobalValue *> GVs; // Figure out which globals we should extract. for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { GlobalValue *GV = M.get()->getNamedGlobal(ExtractGlobals[i]); if (!GV) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractGlobals[i] << "'!\n"; return 1; } GVs.insert(GV); } // Extract globals via regular expression matching. for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) { std::string Error; Regex RegEx(ExtractRegExpGlobals[i]); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' " "invalid regex: " << Error; } bool match = false; for (Module::global_iterator GV = M.get()->global_begin(), E = M.get()->global_end(); GV != E; GV++) { if (RegEx.match(GV->getName())) { GVs.insert(&*GV); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpGlobals[i] << "'!\n"; return 1; } } // Figure out which functions we should extract. for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) { GlobalValue *GV = M.get()->getFunction(ExtractFuncs[i]); if (!GV) { errs() << argv[0] << ": program doesn't contain function named '" << ExtractFuncs[i] << "'!\n"; return 1; } GVs.insert(GV); } // Extract functions via regular expression matching. for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) { std::string Error; StringRef RegExStr = ExtractRegExpFuncs[i]; Regex RegEx(RegExStr); if (!RegEx.isValid(Error)) { errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' " "invalid regex: " << Error; } bool match = false; for (Module::iterator F = M.get()->begin(), E = M.get()->end(); F != E; F++) { if (RegEx.match(F->getName())) { GVs.insert(&*F); match = true; } } if (!match) { errs() << argv[0] << ": program doesn't contain global named '" << ExtractRegExpFuncs[i] << "'!\n"; return 1; } } // Materialize requisite global values. if (!DeleteFn) for (size_t i = 0, e = GVs.size(); i != e; ++i) { GlobalValue *GV = GVs[i]; if (GV->isMaterializable()) { std::string ErrInfo; if (GV->Materialize(&ErrInfo)) { errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; return 1; } } } else { // Deleting. Materialize every GV that's *not* in GVs. SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end()); for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) { GlobalVariable *G = I; if (!GVSet.count(G) && G->isMaterializable()) { std::string ErrInfo; if (G->Materialize(&ErrInfo)) { errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; return 1; } } } for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { Function *F = I; if (!GVSet.count(F) && F->isMaterializable()) { std::string ErrInfo; if (F->Materialize(&ErrInfo)) { errs() << argv[0] << ": error reading input: " << ErrInfo << "\n"; return 1; } } } } // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. PassManager Passes; Passes.add(new TargetData(M.get())); // Use correct TargetData std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); Passes.add(createGVExtractionPass(Gvs, DeleteFn)); if (!DeleteFn) Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls std::string ErrorInfo; tool_output_file Out(OutputFilename.c_str(), ErrorInfo, raw_fd_ostream::F_Binary); if (!ErrorInfo.empty()) { errs() << ErrorInfo << '\n'; return 1; } if (OutputAssembly) Passes.add(createPrintModulePass(&Out.os())); else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true)) Passes.add(createBitcodeWriterPass(Out.os())); Passes.run(*M.get()); // Declare success. Out.keep(); return 0; }