Skip to content

Commit 9fd9d56

Browse files
committed
[DebugInfo][InstrRef][NFC] Use depth-first scope search for variable locs
This patch aims to reduce max-rss from instruction referencing, by avoiding keeping variable value information in memory for too long. Instead of computing all the variable values then emitting them to DBG_VALUE instructions, this patch tries to stream the information out through a depth first search: * Make use of the fact LexicalScopes gives a depth-number to each lexical scope, * Produce a map that identifies the last lexical scope to make use of a block, * Enumerate each scope in LexicalScopes' DFS order, solving the variable value problem, * After each scope is processed, look for any blocks that won't be used by any other scope, and emit all the variable information to DBG_VALUE instructions. Differential Revision: https://reviews.llvm.org/D118460
1 parent 0cd8063 commit 9fd9d56

File tree

2 files changed

+196
-72
lines changed

2 files changed

+196
-72
lines changed

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp

Lines changed: 174 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,45 +2821,6 @@ void InstrRefBasedLDV::dump_mloc_transfer(
28212821
}
28222822
#endif
28232823

2824-
void InstrRefBasedLDV::emitLocations(
2825-
MachineFunction &MF, LiveInsT SavedLiveIns, ValueIDNum **MOutLocs,
2826-
ValueIDNum **MInLocs, DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
2827-
const TargetPassConfig &TPC) {
2828-
TTracker = new TransferTracker(TII, MTracker, MF, *TRI, CalleeSavedRegs, TPC);
2829-
unsigned NumLocs = MTracker->getNumLocs();
2830-
VTracker = nullptr;
2831-
2832-
// For each block, load in the machine value locations and variable value
2833-
// live-ins, then step through each instruction in the block. New DBG_VALUEs
2834-
// to be inserted will be created along the way.
2835-
for (MachineBasicBlock &MBB : MF) {
2836-
unsigned bbnum = MBB.getNumber();
2837-
MTracker->reset();
2838-
MTracker->loadFromArray(MInLocs[bbnum], bbnum);
2839-
TTracker->loadInlocs(MBB, MInLocs[bbnum], SavedLiveIns[MBB.getNumber()],
2840-
NumLocs);
2841-
2842-
CurBB = bbnum;
2843-
CurInst = 1;
2844-
for (auto &MI : MBB) {
2845-
process(MI, MOutLocs, MInLocs);
2846-
TTracker->checkInstForNewValues(CurInst, MI.getIterator());
2847-
++CurInst;
2848-
}
2849-
2850-
// Our block information has now been converted into DBG_VALUEs, to be
2851-
// inserted below. Free the memory we allocated to track variable / register
2852-
// values. If we don't, we needlessy record the same info in memory twice.
2853-
delete[] MInLocs[bbnum];
2854-
delete[] MOutLocs[bbnum];
2855-
MInLocs[bbnum] = nullptr;
2856-
MOutLocs[bbnum] = nullptr;
2857-
SavedLiveIns[bbnum].clear();
2858-
}
2859-
2860-
emitTransfers(AllVarsNumbering);
2861-
}
2862-
28632824
void InstrRefBasedLDV::initialSetup(MachineFunction &MF) {
28642825
// Build some useful data structures.
28652826

@@ -2902,8 +2863,175 @@ void InstrRefBasedLDV::initialSetup(MachineFunction &MF) {
29022863
#endif
29032864
}
29042865

2866+
// Produce an "ejection map" for blocks, i.e., what's the highest-numbered
2867+
// lexical scope it's used in. When exploring in DFS order and we pass that
2868+
// scope, the block can be processed and any tracking information freed.
2869+
void InstrRefBasedLDV::makeDepthFirstEjectionMap(
2870+
SmallVectorImpl<unsigned> &EjectionMap,
2871+
const ScopeToDILocT &ScopeToDILocation,
2872+
ScopeToAssignBlocksT &ScopeToAssignBlocks) {
2873+
SmallPtrSet<const MachineBasicBlock *, 8> BlocksToExplore;
2874+
SmallVector<std::pair<LexicalScope *, ssize_t>, 4> WorkStack;
2875+
auto *TopScope = LS.getCurrentFunctionScope();
2876+
2877+
// Unlike lexical scope explorers, we explore in reverse order, to find the
2878+
// "last" lexical scope used for each block early.
2879+
WorkStack.push_back({TopScope, TopScope->getChildren().size() - 1});
2880+
2881+
while (!WorkStack.empty()) {
2882+
auto &ScopePosition = WorkStack.back();
2883+
LexicalScope *WS = ScopePosition.first;
2884+
ssize_t ChildNum = ScopePosition.second--;
2885+
2886+
const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren();
2887+
if (ChildNum >= 0) {
2888+
// If ChildNum is positive, there are remaining children to explore.
2889+
// Push the child and its children-count onto the stack.
2890+
auto &ChildScope = Children[ChildNum];
2891+
WorkStack.push_back(
2892+
std::make_pair(ChildScope, ChildScope->getChildren().size() - 1));
2893+
} else {
2894+
WorkStack.pop_back();
2895+
2896+
// We've explored all children and any later blocks: examine all blocks
2897+
// in our scope. If they haven't yet had an ejection number set, then
2898+
// this scope will be the last to use that block.
2899+
auto DILocationIt = ScopeToDILocation.find(WS);
2900+
if (DILocationIt != ScopeToDILocation.end()) {
2901+
getBlocksForScope(DILocationIt->second, BlocksToExplore,
2902+
ScopeToAssignBlocks.find(WS)->second);
2903+
for (auto *MBB : BlocksToExplore) {
2904+
unsigned BBNum = MBB->getNumber();
2905+
if (EjectionMap[BBNum] == 0)
2906+
EjectionMap[BBNum] = WS->getDFSOut();
2907+
}
2908+
2909+
BlocksToExplore.clear();
2910+
}
2911+
}
2912+
}
2913+
}
2914+
2915+
bool InstrRefBasedLDV::depthFirstVLocAndEmit(
2916+
unsigned MaxNumBlocks, const ScopeToDILocT &ScopeToDILocation,
2917+
const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToAssignBlocks,
2918+
LiveInsT &Output, ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
2919+
SmallVectorImpl<VLocTracker> &AllTheVLocs, MachineFunction &MF,
2920+
DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
2921+
const TargetPassConfig &TPC) {
2922+
TTracker = new TransferTracker(TII, MTracker, MF, *TRI, CalleeSavedRegs, TPC);
2923+
unsigned NumLocs = MTracker->getNumLocs();
2924+
VTracker = nullptr;
2925+
2926+
// No scopes? No variable locations.
2927+
if (!LS.getCurrentFunctionScope())
2928+
return false;
2929+
2930+
// Build map from block number to the last scope that uses the block.
2931+
SmallVector<unsigned, 16> EjectionMap;
2932+
EjectionMap.resize(MaxNumBlocks, 0);
2933+
makeDepthFirstEjectionMap(EjectionMap, ScopeToDILocation,
2934+
ScopeToAssignBlocks);
2935+
2936+
// Helper lambda for ejecting a block -- if nothing is going to use the block,
2937+
// we can translate the variable location information into DBG_VALUEs and then
2938+
// free all of InstrRefBasedLDV's data structures.
2939+
auto EjectBlock = [&](MachineBasicBlock &MBB) -> void {
2940+
unsigned BBNum = MBB.getNumber();
2941+
AllTheVLocs[BBNum].clear();
2942+
2943+
// Prime the transfer-tracker, and then step through all the block
2944+
// instructions, installing transfers.
2945+
MTracker->reset();
2946+
MTracker->loadFromArray(MInLocs[BBNum], BBNum);
2947+
TTracker->loadInlocs(MBB, MInLocs[BBNum], Output[BBNum], NumLocs);
2948+
2949+
CurBB = BBNum;
2950+
CurInst = 1;
2951+
for (auto &MI : MBB) {
2952+
process(MI, MOutLocs, MInLocs);
2953+
TTracker->checkInstForNewValues(CurInst, MI.getIterator());
2954+
++CurInst;
2955+
}
2956+
2957+
// Free machine-location tables for this block.
2958+
delete[] MInLocs[BBNum];
2959+
delete[] MOutLocs[BBNum];
2960+
// Make ourselves brittle to use-after-free errors.
2961+
MInLocs[BBNum] = nullptr;
2962+
MOutLocs[BBNum] = nullptr;
2963+
// We don't need live-in variable values for this block either.
2964+
Output[BBNum].clear();
2965+
AllTheVLocs[BBNum].clear();
2966+
};
2967+
2968+
SmallPtrSet<const MachineBasicBlock *, 8> BlocksToExplore;
2969+
SmallVector<std::pair<LexicalScope *, ssize_t>, 4> WorkStack;
2970+
WorkStack.push_back({LS.getCurrentFunctionScope(), 0});
2971+
unsigned HighestDFSIn = 0;
2972+
2973+
// Proceed to explore in depth first order.
2974+
while (!WorkStack.empty()) {
2975+
auto &ScopePosition = WorkStack.back();
2976+
LexicalScope *WS = ScopePosition.first;
2977+
ssize_t ChildNum = ScopePosition.second++;
2978+
2979+
// We obesrve scopes with children twice here, once descending in, once
2980+
// ascending out of the scope nest. Use HighestDFSIn as a ratchet to ensure
2981+
// we don't process a scope twice. Additionally, ignore scopes that don't
2982+
// have a DILocation -- by proxy, this means we never tracked any variable
2983+
// assignments in that scope.
2984+
auto DILocIt = ScopeToDILocation.find(WS);
2985+
if (HighestDFSIn <= WS->getDFSIn() && DILocIt != ScopeToDILocation.end()) {
2986+
const DILocation *DILoc = DILocIt->second;
2987+
auto &VarsWeCareAbout = ScopeToVars.find(WS)->second;
2988+
auto &BlocksInScope = ScopeToAssignBlocks.find(WS)->second;
2989+
2990+
buildVLocValueMap(DILoc, VarsWeCareAbout, BlocksInScope, Output, MOutLocs,
2991+
MInLocs, AllTheVLocs);
2992+
}
2993+
2994+
HighestDFSIn = std::max(HighestDFSIn, WS->getDFSIn());
2995+
2996+
// Descend into any scope nests.
2997+
const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren();
2998+
if (ChildNum < (ssize_t)Children.size()) {
2999+
// There are children to explore -- push onto stack and continue.
3000+
auto &ChildScope = Children[ChildNum];
3001+
WorkStack.push_back(std::make_pair(ChildScope, 0));
3002+
} else {
3003+
WorkStack.pop_back();
3004+
3005+
// We've explored a leaf, or have explored all the children of a scope.
3006+
// Try to eject any blocks where this is the last scope it's relevant to.
3007+
auto DILocationIt = ScopeToDILocation.find(WS);
3008+
if (DILocationIt == ScopeToDILocation.end())
3009+
continue;
3010+
3011+
getBlocksForScope(DILocationIt->second, BlocksToExplore,
3012+
ScopeToAssignBlocks.find(WS)->second);
3013+
for (auto *MBB : BlocksToExplore)
3014+
if (WS->getDFSOut() == EjectionMap[MBB->getNumber()])
3015+
EjectBlock(const_cast<MachineBasicBlock &>(*MBB));
3016+
3017+
BlocksToExplore.clear();
3018+
}
3019+
}
3020+
3021+
// Some artificial blocks may not have been ejected, meaning they're not
3022+
// connected to an actual legitimate scope. This can technically happen
3023+
// with things like the entry block. In theory, we shouldn't need to do
3024+
// anything for such out-of-scope blocks, but for the sake of being similar
3025+
// to VarLocBasedLDV, eject these too.
3026+
for (auto *MBB : ArtificialBlocks)
3027+
if (MOutLocs[MBB->getNumber()])
3028+
EjectBlock(*MBB);
3029+
3030+
return emitTransfers(AllVarsNumbering);
3031+
}
3032+
29053033
bool InstrRefBasedLDV::emitTransfers(
2906-
DenseMap<DebugVariable, unsigned> &AllVarsNumbering) {
3034+
DenseMap<DebugVariable, unsigned> &AllVarsNumbering) {
29073035
// Go through all the transfers recorded in the TransferTracker -- this is
29083036
// both the live-ins to a block, and any movements of values that happen
29093037
// in the middle.
@@ -3098,26 +3226,12 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
30983226
delete[] MInLocs[Idx];
30993227
}
31003228
} else {
3101-
// Compute the extended ranges, iterating over scopes. There might be
3102-
// something to be said for ordering them by size/locality, but that's for
3103-
// the future. For each scope, solve the variable value problem, producing
3104-
// a map of variables to values in SavedLiveIns.
3105-
for (auto &P : ScopeToVars) {
3106-
buildVLocValueMap(ScopeToDILocation[P.first], P.second,
3107-
ScopeToAssignBlocks[P.first], SavedLiveIns, MOutLocs, MInLocs,
3108-
vlocs);
3109-
}
3110-
3111-
// Now that we've analysed variable assignments, free any tracking data.
3112-
vlocs.clear();
3113-
3114-
// Using the computed value locations and variable values for each block,
3115-
// create the DBG_VALUE instructions representing the extended variable
3116-
// locations.
3117-
emitLocations(MF, SavedLiveIns, MOutLocs, MInLocs, AllVarsNumbering, *TPC);
3118-
3119-
// Did we actually make any changes? If we created any DBG_VALUEs, then yes.
3120-
Changed = TTracker->Transfers.size() != 0;
3229+
// Optionally, solve the variable value problem and emit to blocks by using
3230+
// a lexical-scope-depth search. It should be functionally identical to
3231+
// the "else" block of this condition.
3232+
Changed = depthFirstVLocAndEmit(
3233+
MaxNumBlocks, ScopeToDILocation, ScopeToVars, ScopeToAssignBlocks,
3234+
SavedLiveIns, MOutLocs, MInLocs, vlocs, MF, AllVarsNumbering, *TPC);
31213235
}
31223236

31233237
// Elements of these arrays will be deleted by emitLocations.

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,18 +1071,6 @@ class InstrRefBasedLDV : public LDVImpl {
10711071
const LiveIdxT &LiveOuts, ValueIDNum **MOutLocs,
10721072
const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders);
10731073

1074-
/// Given the solutions to the two dataflow problems, machine value locations
1075-
/// in \p MInLocs and live-in variable values in \p SavedLiveIns, runs the
1076-
/// TransferTracker class over the function to produce live-in and transfer
1077-
/// DBG_VALUEs, then inserts them. Groups of DBG_VALUEs are inserted in the
1078-
/// order given by AllVarsNumbering -- this could be any stable order, but
1079-
/// right now "order of appearence in function, when explored in RPO", so
1080-
/// that we can compare explictly against VarLocBasedImpl.
1081-
void emitLocations(MachineFunction &MF, LiveInsT SavedLiveIns,
1082-
ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
1083-
DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
1084-
const TargetPassConfig &TPC);
1085-
10861074
/// Take collections of DBG_VALUE instructions stored in TTracker, and
10871075
/// install them into their output blocks. Preserves a stable order of
10881076
/// DBG_VALUEs produced (which would otherwise cause nondeterminism) through
@@ -1093,6 +1081,28 @@ class InstrRefBasedLDV : public LDVImpl {
10931081
/// RPOT block ordering.
10941082
void initialSetup(MachineFunction &MF);
10951083

1084+
/// Produce a map of the last lexical scope that uses a block, using the
1085+
/// scopes DFSOut number. Mapping is block-number to DFSOut.
1086+
/// \p EjectionMap Pre-allocated vector in which to install the built ma.
1087+
/// \p ScopeToDILocation Mapping of LexicalScopes to their DILocations.
1088+
/// \p AssignBlocks Map of blocks where assignments happen for a scope.
1089+
void makeDepthFirstEjectionMap(SmallVectorImpl<unsigned> &EjectionMap,
1090+
const ScopeToDILocT &ScopeToDILocation,
1091+
ScopeToAssignBlocksT &AssignBlocks);
1092+
1093+
/// When determining per-block variable values and emitting to DBG_VALUEs,
1094+
/// this function explores by lexical scope depth. Doing so means that per
1095+
/// block information can be fully computed before exploration finishes,
1096+
/// allowing us to emit it and free data structures earlier than otherwise.
1097+
/// It's also good for locality.
1098+
bool depthFirstVLocAndEmit(
1099+
unsigned MaxNumBlocks, const ScopeToDILocT &ScopeToDILocation,
1100+
const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToBlocks,
1101+
LiveInsT &Output, ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
1102+
SmallVectorImpl<VLocTracker> &AllTheVLocs, MachineFunction &MF,
1103+
DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
1104+
const TargetPassConfig &TPC);
1105+
10961106
bool ExtendRanges(MachineFunction &MF, MachineDominatorTree *DomTree,
10971107
TargetPassConfig *TPC, unsigned InputBBLimit,
10981108
unsigned InputDbgValLimit) override;

0 commit comments

Comments
 (0)