forked from OSchip/llvm-project
[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:
parent
6bb7d2474f
commit
89950ade21
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue