[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
This commit is contained in:
Jeremy Morse 2021-10-20 14:57:07 +01:00
parent 6bb7d2474f
commit 89950ade21
3 changed files with 382 additions and 551 deletions

View File

@ -2034,19 +2034,11 @@ Optional<ValueIDNum> 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<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
bool InstrRefBasedLDV::vlocJoin(
MachineBasicBlock &MBB, LiveIdxT &VLOCOutLocs,
const SmallSet<DebugVariable, 4> &AllVars,
SmallPtrSet<const MachineBasicBlock *, 8> &InScopeBlocks,
SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
DenseMap<DebugVariable, DbgValue> &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<InValueT, 8> 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<InValueT, 8> 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<MachineBasicBlock *, 8> MutBlocksToExplore;
for (const auto *MBB : BlocksToExplore)
MutBlocksToExplore.insert(const_cast<MachineBasicBlock *>(MBB));
// Picks out relevants blocks RPO order and sort them.
for (auto *MBB : BlocksToExplore)
BlockOrders.push_back(const_cast<MachineBasicBlock *>(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<DenseMap<DebugVariable, DbgValue>, 32> LiveIns, LiveOuts;
LiveIns.resize(NumBlocks);
LiveOuts.resize(NumBlocks);
SmallVector<DbgValue, 32> 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<MachineBasicBlock *, 8> MutBlocksToExplore;
for (const auto *MBB : BlocksToExplore)
MutBlocksToExplore.insert(const_cast<MachineBasicBlock*>(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<MachineBasicBlock *, 32> 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<const MachineBasicBlock *, 8> Preds;
for (const auto *Pred : MBB->predecessors())
Preds.push_back(Pred);
SmallVector<const MachineBasicBlock *, 8> 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<ValueIDNum> 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<ValueIDNum> 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<DebugVariable, 8> 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();

View File

@ -636,9 +636,8 @@ public:
using MLocTransferMap = std::map<LocIdx, ValueIDNum>;
/// Live in/out structure for the variable values: a per-block map of
/// variables to their values. XXX, better name?
using LiveIdxT =
DenseMap<const MachineBasicBlock *, DenseMap<DebugVariable, DbgValue> *>;
/// variables to their values.
using LiveIdxT = DenseMap<const MachineBasicBlock *, DbgValue *>;
using VarAndLoc = std::pair<DebugVariable, DbgValue>;
@ -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<DebugVariable, 4> &AllVars,
SmallPtrSet<const MachineBasicBlock *, 8> &InScopeBlocks,
SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
DenseMap<DebugVariable, DbgValue> &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.

View File

@ -179,12 +179,11 @@ public:
}
bool vlocJoin(MachineBasicBlock &MBB, InstrRefBasedLDV::LiveIdxT &VLOCOutLocs,
const SmallSet<DebugVariable, 4> &AllVars,
SmallPtrSet<const MachineBasicBlock *, 8> &InScopeBlocks,
SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
DenseMap<DebugVariable, DbgValue> &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<DenseMap<DebugVariable, DbgValue>, 32> VLiveOuts;
VLiveOuts.resize(4);
SmallVector<DbgValue, 32> 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<ValueIDNum> 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<DenseMap<DebugVariable, DbgValue>, 32> VLiveOuts;
VLiveOuts.resize(3);
SmallVector<DbgValue, 32> 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<ValueIDNum> 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<DenseMap<DebugVariable, DbgValue>, 32> VLiveOuts;
VLiveOuts.resize(5);
SmallVector<DbgValue, 32> 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<ValueIDNum> 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<DenseMap<DebugVariable, DbgValue>, 32> VLiveOuts, VLiveIns;
VLiveOuts.resize(4);
VLiveIns.resize(4);
InstrRefBasedLDV::LiveIdxT VLiveOutIdx, VLiveInIdx;
SmallVector<DbgValue, 32> 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<const MachineBasicBlock *, 8> AllBlocks;
AllBlocks.insert(MBB0);
@ -1627,43 +1622,33 @@ TEST_F(InstrRefLDVTest, vlocJoinDiamond) {
SmallSet<DebugVariable, 4> AllVars;
AllVars.insert(Var);
DenseMap<DebugVariable, DbgValue> 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<DenseMap<DebugVariable, DbgValue>, 32> VLiveOuts;
VLiveOuts.resize(3);
SmallVector<DbgValue, 32> 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<DebugVariable, 4> AllVars;
AllVars.insert(Var);
DenseMap<DebugVariable, DbgValue> 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<DenseMap<DebugVariable, DbgValue>, 32> VLiveOuts;
VLiveOuts.resize(5);
SmallVector<DbgValue, 32> 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<DebugVariable, 4> AllVars;
AllVars.insert(Var);
DenseMap<DebugVariable, DbgValue> 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