From 89950ade216bcabf3cb9acf2cf7218763fd40a92 Mon Sep 17 00:00:00 2001 From: Jeremy Morse Date: Wed, 20 Oct 2021 14:57:07 +0100 Subject: [PATCH] [DebugInfo][InstrRef] Track a single variable at a time Here's another performance patch for InstrRefBasedLDV: rather than processing all variable values in a scope at a time, instead, process one variable at a time. The benefits are twofold: * It's easier to reason about one variable at a time in your mind, * It improves performance, apparently from increased locality. The downside is that the value-propagation code gets indented one level further, plus there's some churn in the unit tests. Differential Revision: https://reviews.llvm.org/D111799 --- .../LiveDebugValues/InstrRefBasedImpl.cpp | 501 ++++++++---------- .../LiveDebugValues/InstrRefBasedImpl.h | 13 +- llvm/unittests/CodeGen/InstrRefLDVTest.cpp | 419 ++++++--------- 3 files changed, 382 insertions(+), 551 deletions(-) diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp index 9a36f46d8533..d286aa903547 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -2034,19 +2034,11 @@ Optional InstrRefBasedLDV::pickVPHILoc( for (auto p : BlockOrders) { unsigned ThisBBNum = p->getNumber(); - auto LiveOutMap = LiveOuts.find(p); - if (LiveOutMap == LiveOuts.end()) - // This predecessor isn't in scope, it must have no live-in/live-out - // locations. + auto OutValIt = LiveOuts.find(p); + if (OutValIt == LiveOuts.end()) + // If we have a predecessor not in scope, we'll never find a PHI position. return None; - - auto It = LiveOutMap->second->find(Var); - if (It == LiveOutMap->second->end()) - // There's no value recorded for this variable in this predecessor, - // leave an empty set of locations. - return None; - - const DbgValue &OutVal = It->second; + const DbgValue &OutVal = *OutValIt->second; if (OutVal.Kind == DbgValue::Const || OutVal.Kind == DbgValue::NoVal) // Consts and no-values cannot have locations we can join on. @@ -2124,10 +2116,9 @@ Optional InstrRefBasedLDV::pickVPHILoc( bool InstrRefBasedLDV::vlocJoin( MachineBasicBlock &MBB, LiveIdxT &VLOCOutLocs, - const SmallSet &AllVars, SmallPtrSet &InScopeBlocks, SmallPtrSet &BlocksToExplore, - DenseMap &LiveIns) { + DbgValue &LiveIn) { // To emulate VarLocBasedImpl, process this block if it's not in scope but // _does_ assign a variable value. No live-ins for this scope are transferred // in though, so we can return immediately. @@ -2148,137 +2139,94 @@ bool InstrRefBasedLDV::vlocJoin( unsigned CurBlockRPONum = BBToOrder[&MBB]; - // We re-construct the live-in map each time we join. For each variable, call - // one of these "confirm" utilities, according to which flavour of variable - // value it is. - auto ConfirmValue = [&LiveIns, &Changed](const DebugVariable &DV, - const DbgValue &VR) { - auto OldLiveIn = LiveIns.find(DV); - assert(OldLiveIn != LiveIns.end()); - if (OldLiveIn->second != VR) { - Changed = true; - OldLiveIn->second = VR; - } - }; - - auto ConfirmVPHI = [&ConfirmValue, - &MBB](const DebugVariable &Var, - const DbgValueProperties &Properties) { - DbgValue NoLocPHIVal(MBB.getNumber(), Properties, DbgValue::VPHI); - ConfirmValue(Var, NoLocPHIVal); - }; - - // Attempt to join the values for each variable. - for (auto &Var : AllVars) { - // Collect all the incoming DbgValues for this variable, from predecessor - // live-out values. - SmallVector Values; - bool Bail = false; - int BackEdgesStart = 0; - for (auto p : BlockOrders) { - // If the predecessor isn't in scope / to be explored, we'll never be - // able to join any locations. - if (!BlocksToExplore.contains(p)) { - Bail = true; - break; - } - - // If the predecessors OutLocs is absent, there's not much we can do. - auto OL = VLOCOutLocs.find(p); - if (OL == VLOCOutLocs.end()) { - Bail = true; - break; - } - - // No live-out value for this predecessor also means we can't produce - // a joined value. - auto VIt = OL->second->find(Var); - if (VIt == OL->second->end()) { - Bail = true; - break; - } - - // Keep track of where back-edges begin in the Values vector. Relies on - // BlockOrders being sorted by RPO. - unsigned ThisBBRPONum = BBToOrder[p]; - if (ThisBBRPONum < CurBlockRPONum) - ++BackEdgesStart; - - Values.push_back(std::make_pair(p, &VIt->second)); + // Collect all the incoming DbgValues for this variable, from predecessor + // live-out values. + SmallVector Values; + bool Bail = false; + int BackEdgesStart = 0; + for (auto p : BlockOrders) { + // If the predecessor isn't in scope / to be explored, we'll never be + // able to join any locations. + if (!BlocksToExplore.contains(p)) { + Bail = true; + break; } - // Pick out the live-in value from last time we vlocJoin'd this block. - auto LiveInIt = LiveIns.find(Var); - assert(LiveInIt != LiveIns.end() && "Uninitialized live-in vloc?"); - const DbgValue &OldLiveInDbgValue = LiveInIt->second; + // All Live-outs will have been initialized. + DbgValue &OutLoc = *VLOCOutLocs.find(p)->second; - // If there were no values, or one of the predecessors couldn't have a - // value, then give up immediately. It's not safe to produce a live-in - // value. Leave as whatever it was before. - if (Bail || Values.size() == 0) { - ConfirmValue(Var, OldLiveInDbgValue); - continue; - } + // Keep track of where back-edges begin in the Values vector. Relies on + // BlockOrders being sorted by RPO. + unsigned ThisBBRPONum = BBToOrder[p]; + if (ThisBBRPONum < CurBlockRPONum) + ++BackEdgesStart; - // All (non-entry) blocks have at least one non-backedge predecessor. - // Pick the variable value from the first of these, to compare against - // all others. - const DbgValue &FirstVal = *Values[0].second; - - // If the old live-in value is not a PHI then either a) no PHI is needed - // here, or b) we eliminated the PHI that was here. If so, we can just - // propagate in the first parents incoming value. - if (OldLiveInDbgValue.Kind != DbgValue::VPHI || - OldLiveInDbgValue.BlockNo != MBB.getNumber()) { - ConfirmValue(Var, FirstVal); - continue; - } - - // Scan for variable values that can never be resolved: if they have - // different DIExpressions, different indirectness, or are mixed constants / - // non-constants. - bool AlwaysIncompatible = false; - for (auto &V : Values) { - if (V.second->Properties != FirstVal.Properties) - AlwaysIncompatible = true; - if (V.second->Kind == DbgValue::NoVal) - AlwaysIncompatible = true; - if (V.second->Kind == DbgValue::Const && FirstVal.Kind != DbgValue::Const) - AlwaysIncompatible = true; - } - - if (AlwaysIncompatible) { - // Leave this as a VPHI. - ConfirmVPHI(Var, OldLiveInDbgValue.Properties); - continue; - } - - // Try to eliminate this PHI. Do the incoming values all agree? - bool Disagree = false; - for (auto &V : Values) { - if (*V.second == FirstVal) - continue; // No disagreement. - - // Eliminate if a backedge feeds a VPHI back into itself. - if (V.second->Kind == DbgValue::VPHI && - V.second->BlockNo == MBB.getNumber() && - // Is this a backedge? - std::distance(Values.begin(), &V) >= BackEdgesStart) - continue; - - Disagree = true; - } - - // No disagreement -> live-through value. - if (!Disagree) { - ConfirmValue(Var, FirstVal); - } else { - // Otherwise use a VPHI. - ConfirmVPHI(Var, FirstVal.Properties); - } + Values.push_back(std::make_pair(p, &OutLoc)); } - return Changed; + // If there were no values, or one of the predecessors couldn't have a + // value, then give up immediately. It's not safe to produce a live-in + // value. Leave as whatever it was before. + if (Bail || Values.size() == 0) + return false; + + // All (non-entry) blocks have at least one non-backedge predecessor. + // Pick the variable value from the first of these, to compare against + // all others. + const DbgValue &FirstVal = *Values[0].second; + + // If the old live-in value is not a PHI then either a) no PHI is needed + // here, or b) we eliminated the PHI that was here. If so, we can just + // propagate in the first parent's incoming value. + if (LiveIn.Kind != DbgValue::VPHI || LiveIn.BlockNo != MBB.getNumber()) { + Changed = LiveIn != FirstVal; + if (Changed) + LiveIn = FirstVal; + return Changed; + } + + // Scan for variable values that can never be resolved: if they have + // different DIExpressions, different indirectness, or are mixed constants / + // non-constants. + for (auto &V : Values) { + if (V.second->Properties != FirstVal.Properties) + return false; + if (V.second->Kind == DbgValue::NoVal) + return false; + if (V.second->Kind == DbgValue::Const && FirstVal.Kind != DbgValue::Const) + return false; + } + + // Try to eliminate this PHI. Do the incoming values all agree? + bool Disagree = false; + for (auto &V : Values) { + if (*V.second == FirstVal) + continue; // No disagreement. + + // Eliminate if a backedge feeds a VPHI back into itself. + if (V.second->Kind == DbgValue::VPHI && + V.second->BlockNo == MBB.getNumber() && + // Is this a backedge? + std::distance(Values.begin(), &V) >= BackEdgesStart) + continue; + + Disagree = true; + } + + // No disagreement -> live-through value. + if (!Disagree) { + Changed = LiveIn != FirstVal; + if (Changed) + LiveIn = FirstVal; + return Changed; + } else { + // Otherwise use a VPHI. + DbgValue VPHI(MBB.getNumber(), FirstVal.Properties, DbgValue::VPHI); + Changed = LiveIn != VPHI; + if (Changed) + LiveIn = VPHI; + return Changed; + } } void InstrRefBasedLDV::buildVLocValueMap(const DILocation *DILoc, @@ -2383,6 +2331,13 @@ void InstrRefBasedLDV::buildVLocValueMap(const DILocation *DILoc, if (BlocksToExplore.size() == 1) return; + // Convert a const set to a non-const set. LexicalScopes + // getMachineBasicBlocks returns const MBB pointers, IDF wants mutable ones. + // (Neither of them mutate anything). + SmallPtrSet MutBlocksToExplore; + for (const auto *MBB : BlocksToExplore) + MutBlocksToExplore.insert(const_cast(MBB)); + // Picks out relevants blocks RPO order and sort them. for (auto *MBB : BlocksToExplore) BlockOrders.push_back(const_cast(MBB)); @@ -2391,20 +2346,17 @@ void InstrRefBasedLDV::buildVLocValueMap(const DILocation *DILoc, unsigned NumBlocks = BlockOrders.size(); // Allocate some vectors for storing the live ins and live outs. Large. - SmallVector, 32> LiveIns, LiveOuts; - LiveIns.resize(NumBlocks); - LiveOuts.resize(NumBlocks); + SmallVector LiveIns, LiveOuts; + LiveIns.reserve(NumBlocks); + LiveOuts.reserve(NumBlocks); // Initialize all values to start as NoVals. This signifies "it's live // through, but we don't know what it is". DbgValueProperties EmptyProperties(EmptyExpr, false); - unsigned int BlockIdx = 0; - for (auto &VarMap : LiveIns) { - for (const DebugVariable &Var : VarsWeCareAbout) - VarMap.insert( - {Var, DbgValue(BlockIdx, EmptyProperties, DbgValue::NoVal)}); - - ++BlockIdx; + for (unsigned int I = 0; I < NumBlocks; ++I) { + DbgValue EmptyDbgValue(I, EmptyProperties, DbgValue::NoVal); + LiveIns.push_back(EmptyDbgValue); + LiveOuts.push_back(EmptyDbgValue); } // Produce by-MBB indexes of live-in/live-outs, to ease lookup within @@ -2417,26 +2369,20 @@ void InstrRefBasedLDV::buildVLocValueMap(const DILocation *DILoc, LiveInIdx[BlockOrders[I]] = &LiveIns[I]; } - // Initialize all live-outs to "nothing", to avoid later conditionals. - for (auto &LiveOut : LiveOutIdx) { - const MachineBasicBlock *OutBB = LiveOut.first; - auto *LiveOutMap = LiveOut.second; - DbgValue EmptyDbgValue(OutBB->getNumber(), EmptyProperties, - DbgValue::NoVal); - for (const DebugVariable &Var : VarsWeCareAbout) + // Loop over each variable and place PHIs for it, then propagate values + // between blocks. This keeps the locality of working on one lexical scope at + // at time, but avoids re-processing variable values because some other + // variable has been assigned. + for (auto &Var : VarsWeCareAbout) { + // Re-initialize live-ins and live-outs, to clear the remains of previous + // variables live-ins / live-outs. + for (unsigned int I = 0; I < NumBlocks; ++I) { + DbgValue EmptyDbgValue(I, EmptyProperties, DbgValue::NoVal); + LiveIns[I] = EmptyDbgValue; + LiveOuts[I] = EmptyDbgValue; + } - LiveOutMap->insert(std::make_pair(Var, EmptyDbgValue)); - } - - // Convert a const set to a non-const set. LexicalScopes - // getMachineBasicBlocks returns const MBB pointers, IDF wants mutable ones. - // (Neither of them mutate anything). - SmallPtrSet MutBlocksToExplore; - for (const auto *MBB : BlocksToExplore) - MutBlocksToExplore.insert(const_cast(MBB)); - - // Place PHIs for variable values, using the LLVM IDF calculator. - for (const DebugVariable &Var : VarsWeCareAbout) { + // Place PHIs for variable values, using the LLVM IDF calculator. // Collect the set of blocks where variables are def'd. SmallPtrSet DefBlocks; for (const MachineBasicBlock *ExpMBB : BlocksToExplore) { @@ -2453,157 +2399,134 @@ void InstrRefBasedLDV::buildVLocValueMap(const DILocation *DILoc, // Insert PHIs into the per-block live-in tables for this variable. for (MachineBasicBlock *PHIMBB : PHIBlocks) { unsigned BlockNo = PHIMBB->getNumber(); - auto *BlockLiveIns = LiveInIdx[PHIMBB]; - auto It = BlockLiveIns->find(Var); - assert(It != BlockLiveIns->end() && "Uninitialized live-in?"); - It->second = DbgValue(BlockNo, EmptyProperties, DbgValue::VPHI); + DbgValue *LiveIn = LiveInIdx[PHIMBB]; + *LiveIn = DbgValue(BlockNo, EmptyProperties, DbgValue::VPHI); } - } - for (auto *MBB : BlockOrders) { - Worklist.push(BBToOrder[MBB]); - OnWorklist.insert(MBB); - } + for (auto *MBB : BlockOrders) { + Worklist.push(BBToOrder[MBB]); + OnWorklist.insert(MBB); + } - // Iterate over all the blocks we selected, propagating variable values. This - // loop does two things: - // * Eliminates un-necessary VPHIs in vlocJoin, - // * Evaluates the blocks transfer function (i.e. variable assignments) and - // stores the result to the blocks live-outs. - // Always evaluate the transfer function on the first iteration, and when the - // live-ins change thereafter. - bool FirstTrip = true; - while (!Worklist.empty() || !Pending.empty()) { - while (!Worklist.empty()) { - auto *MBB = OrderToBB[Worklist.top()]; - CurBB = MBB->getNumber(); - Worklist.pop(); + // Iterate over all the blocks we selected, propagating the variables value. + // This loop does two things: + // * Eliminates un-necessary VPHIs in vlocJoin, + // * Evaluates the blocks transfer function (i.e. variable assignments) and + // stores the result to the blocks live-outs. + // Always evaluate the transfer function on the first iteration, and when + // the live-ins change thereafter. + bool FirstTrip = true; + while (!Worklist.empty() || !Pending.empty()) { + while (!Worklist.empty()) { + auto *MBB = OrderToBB[Worklist.top()]; + CurBB = MBB->getNumber(); + Worklist.pop(); - auto BlockLiveInsIt = LiveInIdx.find(MBB); - assert(BlockLiveInsIt != LiveInIdx.end()); - auto &BlockLiveIns = *BlockLiveInsIt->second; + auto LiveInsIt = LiveInIdx.find(MBB); + assert(LiveInsIt != LiveInIdx.end()); + DbgValue *LiveIn = LiveInsIt->second; - // Join values from predecessors. Updates LiveInIdx, and writes output - // into JoinedInLocs. - bool InLocsChanged = - vlocJoin(*MBB, LiveOutIdx, VarsWeCareAbout, InScopeBlocks, - BlocksToExplore, BlockLiveIns); + // Join values from predecessors. Updates LiveInIdx, and writes output + // into JoinedInLocs. + bool InLocsChanged = + vlocJoin(*MBB, LiveOutIdx, InScopeBlocks, BlocksToExplore, *LiveIn); - SmallVector Preds; - for (const auto *Pred : MBB->predecessors()) - Preds.push_back(Pred); + SmallVector Preds; + for (const auto *Pred : MBB->predecessors()) + Preds.push_back(Pred); - // Opportunistically pick a machine-value for any VPHIs starting in this - // block. This makes their machine-value available and propagated through - // all blocks by the time value propagation finishes. We can't do this any - // earlier as it needs to read the block live-outs. - for (auto &Var : VarsWeCareAbout) { - DbgValue &Val = BlockLiveIns.find(Var)->second; - if (Val.Kind != DbgValue::VPHI || Val.BlockNo != (int)CurBB) + // If this block's live-in value is a VPHI, try to pick a machine-value + // for it. This makes the machine-value available and propagated + // through all blocks by the time value propagation finishes. We can't + // do this any earlier as it needs to read the block live-outs. + if (LiveIn->Kind == DbgValue::VPHI && LiveIn->BlockNo == (int)CurBB) { + // There's a small possibility that on a preceeding path, a VPHI is + // eliminated and transitions from VPHI-with-location to + // live-through-value. As a result, the selected location of any VPHI + // might change, so we need to re-compute it on each iteration. + Optional ValueNum = + pickVPHILoc(*MBB, Var, LiveOutIdx, MOutLocs, Preds); + + if (ValueNum) { + InLocsChanged |= LiveIn->ID != *ValueNum; + LiveIn->ID = *ValueNum; + } + } + + if (!InLocsChanged && !FirstTrip) continue; - // There's a small possibility that on a preceeding path, a VPHI is - // eliminated and transitions from VPHI-with-location to - // live-through-value. As a result, the selected location of any VPHI - // might change, so we need to re-compute it on each iteration. - Optional ValueNum = pickVPHILoc( - *MBB, Var, LiveOutIdx, MOutLocs, Preds); - - if (ValueNum) { - InLocsChanged |= Val.ID != *ValueNum; - Val.ID = *ValueNum; - } - } - - if (!InLocsChanged && !FirstTrip) - continue; - - auto &LiveOuts = *LiveOutIdx[MBB]; - bool OLChanged = false; - - // Do transfer function. - auto &VTracker = AllTheVLocs[MBB->getNumber()]; - SmallSet VarsTransferred; - for (auto &Transfer : VTracker.Vars) { - // Is this var we're mangling in this scope? - if (VarsWeCareAbout.count(Transfer.first)) { - VarsTransferred.insert(Transfer.first); - auto OutIt = LiveOuts.find(Transfer.first); - assert(OutIt != LiveOuts.end()); + DbgValue *LiveOut = LiveOutIdx[MBB]; + bool OLChanged = false; + // Do transfer function. + auto &VTracker = AllTheVLocs[MBB->getNumber()]; + auto TransferIt = VTracker.Vars.find(Var); + if (TransferIt != VTracker.Vars.end()) { // Erase on empty transfer (DBG_VALUE $noreg). - if (Transfer.second.Kind == DbgValue::Undef) { + if (TransferIt->second.Kind == DbgValue::Undef) { DbgValue NewVal(MBB->getNumber(), EmptyProperties, DbgValue::NoVal); - if (OutIt->second != NewVal) { - OutIt->second = NewVal; + if (*LiveOut != NewVal) { + *LiveOut = NewVal; OLChanged = true; } } else { // Insert new variable value; or overwrite. - if (OutIt->second != Transfer.second) { - OutIt->second = Transfer.second; + if (*LiveOut != TransferIt->second) { + *LiveOut = TransferIt->second; OLChanged = true; } } + } else { + // Just copy live-ins to live-outs, for anything not transferred. + if (*LiveOut != *LiveIn) { + *LiveOut = *LiveIn; + OLChanged = true; + } } - } - // For anything not assigned by the transfer function, copy live-in to - // live-outs. - for (const DebugVariable &Var : VarsWeCareAbout) { - if (VarsTransferred.count(Var)) + // If no live-out value changed, there's no need to explore further. + if (!OLChanged) continue; - auto OutIt = LiveOuts.find(Var); - auto InIt = BlockLiveIns.find(Var); - if (InIt->second != OutIt->second) { - OutIt->second = InIt->second; - OLChanged = true; - } - } - - // If no live-out value changed, there's no need to explore further. - if (!OLChanged) - continue; - - // We should visit all successors. Ensure we'll visit any non-backedge - // successors during this dataflow iteration; book backedge successors - // to be visited next time around. - for (auto s : MBB->successors()) { - // Ignore out of scope / not-to-be-explored successors. - if (LiveInIdx.find(s) == LiveInIdx.end()) - continue; - - if (BBToOrder[s] > BBToOrder[MBB]) { - if (OnWorklist.insert(s).second) - Worklist.push(BBToOrder[s]); - } else if (OnPending.insert(s).second && (FirstTrip || OLChanged)) { - Pending.push(BBToOrder[s]); + // We should visit all successors. Ensure we'll visit any non-backedge + // successors during this dataflow iteration; book backedge successors + // to be visited next time around. + for (auto s : MBB->successors()) { + // Ignore out of scope / not-to-be-explored successors. + if (LiveInIdx.find(s) == LiveInIdx.end()) + continue; + + if (BBToOrder[s] > BBToOrder[MBB]) { + if (OnWorklist.insert(s).second) + Worklist.push(BBToOrder[s]); + } else if (OnPending.insert(s).second && (FirstTrip || OLChanged)) { + Pending.push(BBToOrder[s]); + } } } + Worklist.swap(Pending); + std::swap(OnWorklist, OnPending); + OnPending.clear(); + assert(Pending.empty()); + FirstTrip = false; } - Worklist.swap(Pending); - std::swap(OnWorklist, OnPending); - OnPending.clear(); - assert(Pending.empty()); - FirstTrip = false; - } - // Save live-ins to output vector. Ignore any that are still marked as being - // VPHIs with no location -- those are variables that we know the value of, - // but are not actually available in the register file. - for (auto *MBB : BlockOrders) { - auto &VarMap = *LiveInIdx[MBB]; - for (auto &P : VarMap) { - if (P.second.Kind == DbgValue::NoVal) + // Save live-ins to output vector. Ignore any that are still marked as being + // VPHIs with no location -- those are variables that we know the value of, + // but are not actually available in the register file. + for (auto *MBB : BlockOrders) { + DbgValue *BlockLiveIn = LiveInIdx[MBB]; + if (BlockLiveIn->Kind == DbgValue::NoVal) continue; - if (P.second.Kind == DbgValue::VPHI && P.second.ID == ValueIDNum::EmptyValue) + if (BlockLiveIn->Kind == DbgValue::VPHI && + BlockLiveIn->ID == ValueIDNum::EmptyValue) continue; - if (P.second.Kind == DbgValue::VPHI) - P.second.Kind = DbgValue::Def; - Output[MBB->getNumber()].push_back(P); + if (BlockLiveIn->Kind == DbgValue::VPHI) + BlockLiveIn->Kind = DbgValue::Def; + Output[MBB->getNumber()].push_back(std::make_pair(Var, *BlockLiveIn)); } - } + } // Per-variable loop. BlockOrders.clear(); BlocksToExplore.clear(); diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h index 2ced4578c4c6..0de8ed5fc352 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h @@ -636,9 +636,8 @@ public: using MLocTransferMap = std::map; /// Live in/out structure for the variable values: a per-block map of - /// variables to their values. XXX, better name? - using LiveIdxT = - DenseMap *>; + /// variables to their values. + using LiveIdxT = DenseMap; using VarAndLoc = std::pair; @@ -856,16 +855,14 @@ private: /// Attempt to eliminate un-necessary PHIs on entry to a block. Examines the /// live-in values coming from predecessors live-outs, and replaces any PHIs /// already present in this blocks live-ins with a live-through value if the - /// PHI isn't needed. Live out variable values are stored in - /// \p VLOCOutLocs. The live-ins for \p MBB are stored in \p LiveIns, which - /// is also an output argument. + /// PHI isn't needed. + /// \p LiveIn Old live-in value, overwritten with new one if live-in changes. /// \returns true if any live-ins change value, either from value propagation /// or PHI elimination. bool vlocJoin(MachineBasicBlock &MBB, LiveIdxT &VLOCOutLocs, - const SmallSet &AllVars, SmallPtrSet &InScopeBlocks, SmallPtrSet &BlocksToExplore, - DenseMap &LiveIns); + DbgValue &LiveIn); /// For the given block and live-outs feeding into it, try to find a /// machine location where all the variable values join together. diff --git a/llvm/unittests/CodeGen/InstrRefLDVTest.cpp b/llvm/unittests/CodeGen/InstrRefLDVTest.cpp index d460a0353c1c..c6420b5b5a02 100644 --- a/llvm/unittests/CodeGen/InstrRefLDVTest.cpp +++ b/llvm/unittests/CodeGen/InstrRefLDVTest.cpp @@ -179,12 +179,11 @@ public: } bool vlocJoin(MachineBasicBlock &MBB, InstrRefBasedLDV::LiveIdxT &VLOCOutLocs, - const SmallSet &AllVars, SmallPtrSet &InScopeBlocks, SmallPtrSet &BlocksToExplore, - DenseMap &InLocsT) { - return LDV->vlocJoin(MBB, VLOCOutLocs, AllVars, InScopeBlocks, - BlocksToExplore, InLocsT); + DbgValue &InLoc) { + return LDV->vlocJoin(MBB, VLOCOutLocs, InScopeBlocks, BlocksToExplore, + InLoc); } void buildVLocValueMap(const DILocation *DILoc, @@ -1242,8 +1241,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) { DebugVariable Var(FuncVariable, None, nullptr); DbgValueProperties EmptyProps(EmptyExpr, false); - SmallVector, 32> VLiveOuts; - VLiveOuts.resize(4); + SmallVector VLiveOuts; + VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef)); InstrRefBasedLDV::LiveIdxT VLiveOutIdx; VLiveOutIdx[MBB0] = &VLiveOuts[0]; VLiveOutIdx[MBB1] = &VLiveOuts[1]; @@ -1261,8 +1260,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) { Optional Result; // Simple case: join two distinct values on entry to the block. - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); // Should have picked a PHI in $rsp in block 3. EXPECT_TRUE(Result); @@ -1280,22 +1279,20 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) { // Swap back, std::swap(VLiveOuts[1], VLiveOuts[2]); // Setting one of these to being a constant should prohibit merging. - VLiveOuts[1].find(Var)->second.Kind = DbgValue::Const; - VLiveOuts[1].find(Var)->second.MO = MachineOperand::CreateImm(0); + VLiveOuts[1].Kind = DbgValue::Const; + VLiveOuts[1].MO = MachineOperand::CreateImm(0); Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); // Seeing both to being a constant -> still prohibit, it shouldn't become // a value in the register file anywhere. - VLiveOuts[2].find(Var)->second = VLiveOuts[1].find(Var)->second; + VLiveOuts[2] = VLiveOuts[1]; Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); // NoVals shouldn't join with anything else. - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(2, EmptyProps, DbgValue::NoVal)}); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal); Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); @@ -1303,9 +1300,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) { // such a scenario: first, where one incoming edge has a VPHI with no known // value. This represents an edge where there was a PHI value that can't be // found in the register file -- we can't subsequently find a PHI here. - VLiveOuts[2].clear(); - VLiveOuts[2].insert({Var, DbgValue(2, EmptyProps, DbgValue::VPHI)}); - EXPECT_EQ(VLiveOuts[2].find(Var)->second.ID, ValueIDNum::EmptyValue); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI); + EXPECT_EQ(VLiveOuts[2].ID, ValueIDNum::EmptyValue); Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); @@ -1313,7 +1310,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) { // location. Use a PHI machine-value for doing this, as VPHIs should always // have PHI values, or they should have been eliminated. OutLocs[2][0] = RspPHIInBlk2; - VLiveOuts[2].find(Var)->second.ID = RspPHIInBlk2; + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI); + VLiveOuts[2].ID = RspPHIInBlk2; // Set location where PHI happens. Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_TRUE(Result); if (Result) { @@ -1327,16 +1326,17 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) { // Check that we don't pick values when the properties disagree, for example // different indirectness or DIExpression. - DIExpression *NewExpr = DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4); + DIExpression *NewExpr = + DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4); DbgValueProperties PropsWithExpr(NewExpr, false); - VLiveOuts[2].clear(); - VLiveOuts[2].insert({Var, DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def)}); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def); Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); DbgValueProperties PropsWithIndirect(EmptyExpr, true); - VLiveOuts[2].clear(); - VLiveOuts[2].insert({Var, DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def)}); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def); Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); } @@ -1370,8 +1370,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) { DebugVariable Var(FuncVariable, None, nullptr); DbgValueProperties EmptyProps(EmptyExpr, false); - SmallVector, 32> VLiveOuts; - VLiveOuts.resize(3); + SmallVector VLiveOuts; + VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef)); InstrRefBasedLDV::LiveIdxT VLiveOutIdx; VLiveOutIdx[MBB0] = &VLiveOuts[0]; VLiveOutIdx[MBB1] = &VLiveOuts[1]; @@ -1388,8 +1388,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) { Optional Result; // See that we can merge as normal on a backedge. - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds); // Should have picked a PHI in $rsp in block 1. EXPECT_TRUE(Result); @@ -1410,11 +1410,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) { OutLocs[0][1] = LiveInRsp; OutLocs[1][0] = RaxPHIInBlk1; OutLocs[1][1] = RaxPHIInBlk1; - VLiveOuts[0].clear(); - VLiveOuts[1].clear(); - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); // Crucially, a VPHI originating in this block: - VLiveOuts[1].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_TRUE(Result); if (Result) { @@ -1430,8 +1428,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) { // Additionally, if the VPHI coming back on the loop backedge isn't from // this block (block 1), we can't merge it. OutLocs[1][1] = RaxPHIInBlk1; - VLiveOuts[1].clear(); - VLiveOuts[1].insert({Var, DbgValue(0, EmptyProps, DbgValue::VPHI)}); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI); Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_FALSE(Result); } @@ -1474,8 +1472,8 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) { DebugVariable Var(FuncVariable, None, nullptr); DbgValueProperties EmptyProps(EmptyExpr, false); - SmallVector, 32> VLiveOuts; - VLiveOuts.resize(5); + SmallVector VLiveOuts; + VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef)); InstrRefBasedLDV::LiveIdxT VLiveOutIdx; VLiveOutIdx[MBB0] = &VLiveOuts[0]; VLiveOutIdx[MBB1] = &VLiveOuts[1]; @@ -1497,9 +1495,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) { Optional Result; // See that we can merge as normal on a backedge. - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRbx, EmptyProps, DbgValue::Def)}); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def); Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds); // Should have picked a PHI in $rsp in block 1. EXPECT_TRUE(Result); @@ -1526,8 +1524,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) { // If the variables value on that edge is a VPHI feeding into itself, that's // fine. - VLiveOuts[1].clear(); - VLiveOuts[1].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); + VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def); Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_TRUE(Result); if (Result) { @@ -1536,8 +1535,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) { // Likewise: the other backedge being a VPHI from block 1 should be accepted. OutLocs[2][0] = RspPHIInBlk1; - VLiveOuts[2].clear(); - VLiveOuts[2].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); + VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI); Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds); EXPECT_TRUE(Result); if (Result) { @@ -1601,18 +1601,13 @@ TEST_F(InstrRefLDVTest, vlocJoinDiamond) { DebugVariable Var(FuncVariable, None, nullptr); DbgValueProperties EmptyProps(EmptyExpr, false); - SmallVector, 32> VLiveOuts, VLiveIns; - VLiveOuts.resize(4); - VLiveIns.resize(4); - InstrRefBasedLDV::LiveIdxT VLiveOutIdx, VLiveInIdx; + SmallVector VLiveOuts; + VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef)); + InstrRefBasedLDV::LiveIdxT VLiveOutIdx; VLiveOutIdx[MBB0] = &VLiveOuts[0]; VLiveOutIdx[MBB1] = &VLiveOuts[1]; VLiveOutIdx[MBB2] = &VLiveOuts[2]; VLiveOutIdx[MBB3] = &VLiveOuts[3]; - VLiveInIdx[MBB0] = &VLiveIns[0]; - VLiveInIdx[MBB1] = &VLiveIns[1]; - VLiveInIdx[MBB2] = &VLiveIns[2]; - VLiveInIdx[MBB3] = &VLiveIns[3]; SmallPtrSet AllBlocks; AllBlocks.insert(MBB0); @@ -1627,43 +1622,33 @@ TEST_F(InstrRefLDVTest, vlocJoinDiamond) { SmallSet AllVars; AllVars.insert(Var); - DenseMap JoinedLocs; - // vlocJoin is here to propagate incoming values, and eliminate PHIs. Start // off by propagating a value into the merging block, number 3. - JoinedLocs.insert({Var, DbgValue(3, EmptyProps, DbgValue::NoVal)}); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - bool Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + DbgValue JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + bool Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); // Output locs should have changed. - auto It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRsp); - // JoinedLocs.clear(); <--- leave commented out for next test, + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRsp); // And if we did it a second time, leaving the live-ins as it was, then // we should report no change. - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - JoinedLocs.clear(); // If the live-in variable values are different, but there's no PHI placed // in this block, then just pick a location. It should be the first (in RPO) // predecessor to avoid being a backedge. - VLiveOuts[2].clear(); - VLiveOuts[2].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(3, EmptyProps, DbgValue::NoVal)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); // RPO is blocks 0 2 1 3, so LiveInRax is picked as the first predecessor // of this join. - EXPECT_EQ(It->second.ID, LiveInRax); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.ID, LiveInRax); // No tests for whether vlocJoin will pass-through a variable with differing // expressions / properties. Those can only come about due to assignments; and @@ -1673,114 +1658,81 @@ TEST_F(InstrRefLDVTest, vlocJoinDiamond) { // Try placing a PHI. With differing input values (LiveInRsp, LiveInRax), // this PHI should not be eliminated. - JoinedLocs.insert({Var, DbgValue(3, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); // Expect no change. EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); // This should not have been assigned a fixed value. - EXPECT_EQ(It->second.ID, ValueIDNum::EmptyValue); - EXPECT_EQ(It->second.BlockNo, 3); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.ID, ValueIDNum::EmptyValue); + EXPECT_EQ(JoinedLoc.BlockNo, 3); // Try a simple PHI elimination. Put a PHI in block 3, but LiveInRsp on both // incoming edges. Re-load in and out-locs with unrelated values; they're // irrelevant. - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(3, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRsp); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRsp); // If the "current" live-in is a VPHI, but not a VPHI generated in the current // block, then it's the remains of an earlier value propagation. We should // value propagate through this merge. Even if the current incoming values // disagree, because we've previously determined any VPHI here is redundant. - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(2, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRax); // from block 2 - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRax); // from block 2 // The above test, but test that we will install one value-propagated VPHI // over another. - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(0, EmptyProps, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(2, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(0, EmptyProps, DbgValue::VPHI); + JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 0); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 0); // We shouldn't eliminate PHIs when properties disagree. DbgValueProperties PropsWithIndirect(EmptyExpr, true); - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert( - {Var, DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(3, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def); + JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 3); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 3); // Even if properties disagree, we should still value-propagate if there's no // PHI to be eliminated. The disagreeing values should work themselves out, // seeing how we've determined no PHI is necessary. - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert( - {Var, DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(2, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def); + JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRsp); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRsp); // Also check properties come from block 2, the first RPO predecessor to block // three. - EXPECT_EQ(It->second.Properties, PropsWithIndirect); - JoinedLocs.clear(); - VLiveIns[3].clear(); + EXPECT_EQ(JoinedLoc.Properties, PropsWithIndirect); // Again, disagreeing properties, this time the expr, should cause a PHI to // not be eliminated. - DIExpression *NewExpr = DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4); + DIExpression *NewExpr = + DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4); DbgValueProperties PropsWithExpr(NewExpr, false); - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[1].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(3, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB3, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def); + JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); } @@ -1806,8 +1758,8 @@ TEST_F(InstrRefLDVTest, vlocJoinLoops) { DebugVariable Var(FuncVariable, None, nullptr); DbgValueProperties EmptyProps(EmptyExpr, false); - SmallVector, 32> VLiveOuts; - VLiveOuts.resize(3); + SmallVector VLiveOuts; + VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef)); InstrRefBasedLDV::LiveIdxT VLiveOutIdx; VLiveOutIdx[MBB0] = &VLiveOuts[0]; VLiveOutIdx[MBB1] = &VLiveOuts[1]; @@ -1825,77 +1777,59 @@ TEST_F(InstrRefLDVTest, vlocJoinLoops) { SmallSet AllVars; AllVars.insert(Var); - DenseMap JoinedLocs; - // Test some back-edge-specific behaviours of vloc join. Mostly: the fact that // VPHIs that arrive on backedges can be eliminated, despite having different // values to the predecessor. // First: when there's no VPHI placed already, propagate the live-in value of // the first RPO predecessor. - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - bool Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + DbgValue JoinedLoc = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - auto It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRsp); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRsp); // If there is a VPHI: don't elimiante it if there are disagreeing values. - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 1); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 1); // If we feed this VPHI back into itself though, we can eliminate it. - VLiveOuts[0].clear(); - VLiveOuts[1].clear(); - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRsp); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRsp); // Don't eliminate backedge VPHIs if the predecessors have different // properties. - DIExpression *NewExpr = DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4); + DIExpression *NewExpr = + DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4); DbgValueProperties PropsWithExpr(NewExpr, false); - VLiveOuts[1].clear(); - VLiveOuts[1].insert({Var, DbgValue(1, PropsWithExpr, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, PropsWithExpr, DbgValue::VPHI); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 1); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 1); // Backedges with VPHIs, but from the wrong block, shouldn't be eliminated. - VLiveOuts[1].clear(); - VLiveOuts[1].insert({Var, DbgValue(0, EmptyProps, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 1); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 1); } TEST_F(InstrRefLDVTest, vlocJoinBadlyNestedLoops) { @@ -1927,8 +1861,8 @@ TEST_F(InstrRefLDVTest, vlocJoinBadlyNestedLoops) { DebugVariable Var(FuncVariable, None, nullptr); DbgValueProperties EmptyProps(EmptyExpr, false); - SmallVector, 32> VLiveOuts; - VLiveOuts.resize(5); + SmallVector VLiveOuts; + VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef)); InstrRefBasedLDV::LiveIdxT VLiveOutIdx; VLiveOutIdx[MBB0] = &VLiveOuts[0]; VLiveOutIdx[MBB1] = &VLiveOuts[1]; @@ -1951,69 +1885,46 @@ TEST_F(InstrRefLDVTest, vlocJoinBadlyNestedLoops) { SmallSet AllVars; AllVars.insert(Var); - DenseMap JoinedLocs; - // Test a normal VPHI isn't eliminated. - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)}); - VLiveOuts[2].insert({Var, DbgValue(LiveInRbx, EmptyProps, DbgValue::Def)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - bool Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def); + VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def); + DbgValue JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - auto It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 1); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 1); // Common VPHIs on backedges should merge. - VLiveOuts[0].clear(); - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - VLiveOuts[2].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); + VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_TRUE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::Def); - EXPECT_EQ(It->second.ID, LiveInRsp); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def); + EXPECT_EQ(JoinedLoc.ID, LiveInRsp); // They shouldn't merge if one of their properties is different. DbgValueProperties PropsWithIndirect(EmptyExpr, true); - VLiveOuts[0].clear(); - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - VLiveOuts[2].insert({Var, DbgValue(1, PropsWithIndirect, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); + VLiveOuts[2] = DbgValue(1, PropsWithIndirect, DbgValue::VPHI); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 1); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 1); // VPHIs from different blocks should not merge. - VLiveOuts[0].clear(); - VLiveOuts[1].clear(); - VLiveOuts[2].clear(); - VLiveOuts[0].insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)}); - VLiveOuts[1].insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - VLiveOuts[2].insert({Var, DbgValue(2, EmptyProps, DbgValue::VPHI)}); - JoinedLocs.insert({Var, DbgValue(1, EmptyProps, DbgValue::VPHI)}); - Result = - vlocJoin(*MBB1, VLiveOutIdx, AllVars, AllBlocks, AllBlocks, JoinedLocs); + VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def); + VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI); + VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI); + JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI); + Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, AllBlocks, JoinedLoc); EXPECT_FALSE(Result); - It = JoinedLocs.find(Var); - EXPECT_EQ(It->second.Kind, DbgValue::VPHI); - EXPECT_EQ(It->second.BlockNo, 1); - JoinedLocs.clear(); + EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI); + EXPECT_EQ(JoinedLoc.BlockNo, 1); } // Above are tests for picking VPHI locations, and eliminating VPHIs. No