Skip to content

Commit 857ccf3

Browse files
Move DBG_VALUE's that depend on loads to after a
load if the load is moved due to the pre register allocation ld/st optimization pass The issue here is that there can be a scenario where debug information is lost because of the pre register allocation load store optimization pass, where a load who's result describes the debug infomation for a local variable gets moved below the load and that causes the debug information for that load to get lost. Example: Before the Pre Register Allocation Load Store Pass inst_a %2 = ld ... inst_b DBG_VALUE %2, "x", ... %3 = ld ... After the Pass: inst_a inst_b DBG_VALUE %2, "x", ... %2 = ld ... %3 = ld ... The load has now been moved to after the DBG_VAL that uses its result and the debug info for "x" has been lost. What we want is: inst_a inst_b %2 = ld ... DBG_VALUE %2, "x", ... %3 = ld ... Which is what this patch addresses Differential Revision: https://reviews.llvm.org/D145168 (cherry picked from commit a971bc3)
1 parent 2fd9697 commit 857ccf3

File tree

6 files changed

+687
-10
lines changed

6 files changed

+687
-10
lines changed

llvm/lib/Target/ARM/ARMLoadStoreOptimizer.cpp

Lines changed: 309 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,10 +2172,10 @@ namespace {
21722172
unsigned &NewOpc, Register &EvenReg, Register &OddReg,
21732173
Register &BaseReg, int &Offset, Register &PredReg,
21742174
ARMCC::CondCodes &Pred, bool &isT2);
2175-
bool RescheduleOps(MachineBasicBlock *MBB,
2176-
SmallVectorImpl<MachineInstr *> &Ops,
2177-
unsigned Base, bool isLd,
2178-
DenseMap<MachineInstr*, unsigned> &MI2LocMap);
2175+
bool RescheduleOps(
2176+
MachineBasicBlock *MBB, SmallVectorImpl<MachineInstr *> &Ops,
2177+
unsigned Base, bool isLd, DenseMap<MachineInstr *, unsigned> &MI2LocMap,
2178+
SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> &RegisterMap);
21792179
bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB);
21802180
bool DistributeIncrements();
21812181
bool DistributeIncrements(Register Base);
@@ -2324,10 +2324,10 @@ bool ARMPreAllocLoadStoreOpt::CanFormLdStDWord(
23242324
return true;
23252325
}
23262326

2327-
bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
2328-
SmallVectorImpl<MachineInstr *> &Ops,
2329-
unsigned Base, bool isLd,
2330-
DenseMap<MachineInstr*, unsigned> &MI2LocMap) {
2327+
bool ARMPreAllocLoadStoreOpt::RescheduleOps(
2328+
MachineBasicBlock *MBB, SmallVectorImpl<MachineInstr *> &Ops, unsigned Base,
2329+
bool isLd, DenseMap<MachineInstr *, unsigned> &MI2LocMap,
2330+
SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> &RegisterMap) {
23312331
bool RetVal = false;
23322332

23332333
// Sort by offset (in reverse order).
@@ -2476,6 +2476,12 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
24762476
} else {
24772477
for (unsigned i = 0; i != NumMove; ++i) {
24782478
MachineInstr *Op = Ops.pop_back_val();
2479+
if (isLd) {
2480+
// Populate RegisterMap with all Registers defined by loads.
2481+
Register Reg = Op->getOperand(0).getReg();
2482+
RegisterMap[Reg];
2483+
}
2484+
24792485
MBB->splice(InsertPos, MBB, Op);
24802486
}
24812487
}
@@ -2489,6 +2495,44 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
24892495
return RetVal;
24902496
}
24912497

2498+
static void forEachDbgRegOperand(MachineInstr *MI,
2499+
std::function<void(MachineOperand &)> Fn) {
2500+
if (MI->isNonListDebugValue()) {
2501+
auto &Op = MI->getOperand(0);
2502+
if (Op.isReg())
2503+
Fn(Op);
2504+
} else {
2505+
for (unsigned I = 2; I < MI->getNumOperands(); I++) {
2506+
auto &Op = MI->getOperand(I);
2507+
if (Op.isReg())
2508+
Fn(Op);
2509+
}
2510+
}
2511+
}
2512+
2513+
// Update the RegisterMap with the instruction that was moved because a
2514+
// DBG_VALUE_LIST may need to be moved again.
2515+
static void updateRegisterMapForDbgValueListAfterMove(
2516+
SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> &RegisterMap,
2517+
MachineInstr *DbgValueListInstr, MachineInstr *InstrToReplace) {
2518+
2519+
forEachDbgRegOperand(DbgValueListInstr, [&](MachineOperand &Op) {
2520+
auto RegIt = RegisterMap.find(Op.getReg());
2521+
if (RegIt == RegisterMap.end())
2522+
return;
2523+
auto &InstrVec = RegIt->getSecond();
2524+
for (unsigned I = 0; I < InstrVec.size(); I++)
2525+
if (InstrVec[I] == InstrToReplace)
2526+
InstrVec[I] = DbgValueListInstr;
2527+
});
2528+
}
2529+
2530+
static DebugVariable createDebugVariableFromMachineInstr(MachineInstr *MI) {
2531+
auto DbgVar = DebugVariable(MI->getDebugVariable(), MI->getDebugExpression(),
2532+
MI->getDebugLoc()->getInlinedAt());
2533+
return DbgVar;
2534+
}
2535+
24922536
bool
24932537
ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
24942538
bool RetVal = false;
@@ -2501,6 +2545,10 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
25012545
Base2InstMap Base2StsMap;
25022546
BaseVec LdBases;
25032547
BaseVec StBases;
2548+
// This map is used to track the relationship between the virtual
2549+
// register that is the result of a load that is moved and the DBG_VALUE
2550+
// MachineInstr pointer that uses that virtual register.
2551+
SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> RegisterMap;
25042552

25052553
unsigned Loc = 0;
25062554
MachineBasicBlock::iterator MBBI = MBB->begin();
@@ -2563,15 +2611,15 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
25632611
unsigned Base = LdBases[i];
25642612
SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[Base];
25652613
if (Lds.size() > 1)
2566-
RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap);
2614+
RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap, RegisterMap);
25672615
}
25682616

25692617
// Re-schedule stores.
25702618
for (unsigned i = 0, e = StBases.size(); i != e; ++i) {
25712619
unsigned Base = StBases[i];
25722620
SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[Base];
25732621
if (Sts.size() > 1)
2574-
RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap);
2622+
RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap, RegisterMap);
25752623
}
25762624

25772625
if (MBBI != E) {
@@ -2582,6 +2630,257 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
25822630
}
25832631
}
25842632

2633+
// Reschedule DBG_VALUEs to match any loads that were moved. When a load is
2634+
// sunk beyond a DBG_VALUE that is referring to it, the DBG_VALUE becomes a
2635+
// use-before-def, resulting in a loss of debug info.
2636+
2637+
// Example:
2638+
// Before the Pre Register Allocation Load Store Pass
2639+
// inst_a
2640+
// %2 = ld ...
2641+
// inst_b
2642+
// DBG_VALUE %2, "x", ...
2643+
// %3 = ld ...
2644+
2645+
// After the Pass:
2646+
// inst_a
2647+
// inst_b
2648+
// DBG_VALUE %2, "x", ...
2649+
// %2 = ld ...
2650+
// %3 = ld ...
2651+
2652+
// The code below addresses this by moving the DBG_VALUE to the position
2653+
// immediately after the load.
2654+
2655+
// Example:
2656+
// After the code below:
2657+
// inst_a
2658+
// inst_b
2659+
// %2 = ld ...
2660+
// DBG_VALUE %2, "x", ...
2661+
// %3 = ld ...
2662+
2663+
// The algorithm works in two phases: First RescheduleOps() populates the
2664+
// RegisterMap with registers that were moved as keys, there is no value
2665+
// inserted. In the next phase, every MachineInstr in a basic block is
2666+
// iterated over. If it is a valid DBG_VALUE or DBG_VALUE_LIST and it uses one
2667+
// or more registers in the RegisterMap, the RegisterMap and InstrMap are
2668+
// populated with the MachineInstr. If the DBG_VALUE or DBG_VALUE_LIST
2669+
// describes debug information for a variable that already exists in the
2670+
// DbgValueSinkCandidates, the MachineInstr in the DbgValueSinkCandidates must
2671+
// be set to undef. If the current MachineInstr is a load that was moved,
2672+
// undef the corresponding DBG_VALUE or DBG_VALUE_LIST and clone it to below
2673+
// the load.
2674+
2675+
// To illustrate the above algorithm visually let's take this example.
2676+
2677+
// Before the Pre Register Allocation Load Store Pass:
2678+
// %2 = ld ...
2679+
// DBG_VALUE %2, A, .... # X
2680+
// DBG_VALUE 0, A, ... # Y
2681+
// %3 = ld ...
2682+
// DBG_VALUE %3, A, ..., # Z
2683+
// %4 = ld ...
2684+
2685+
// After Pre Register Allocation Load Store Pass:
2686+
// DBG_VALUE %2, A, .... # X
2687+
// DBG_VALUE 0, A, ... # Y
2688+
// DBG_VALUE %3, A, ..., # Z
2689+
// %2 = ld ...
2690+
// %3 = ld ...
2691+
// %4 = ld ...
2692+
2693+
// The algorithm below does the following:
2694+
2695+
// In the beginning, the RegisterMap will have been populated with the virtual
2696+
// registers %2, and %3, the DbgValueSinkCandidates and the InstrMap will be
2697+
// empty. DbgValueSinkCandidates = {}, RegisterMap = {2 -> {}, 3 -> {}},
2698+
// InstrMap {}
2699+
// -> DBG_VALUE %2, A, .... # X
2700+
// DBG_VALUE 0, A, ... # Y
2701+
// DBG_VALUE %3, A, ..., # Z
2702+
// %2 = ld ...
2703+
// %3 = ld ...
2704+
// %4 = ld ...
2705+
2706+
// After the first DBG_VALUE (denoted with an X) is processed, the
2707+
// DbgValueSinkCandidates and InstrMap will be populated and the RegisterMap
2708+
// entry for %2 will be populated as well. DbgValueSinkCandidates = {A -> X},
2709+
// RegisterMap = {2 -> {X}, 3 -> {}}, InstrMap {X -> 2}
2710+
// DBG_VALUE %2, A, .... # X
2711+
// -> DBG_VALUE 0, A, ... # Y
2712+
// DBG_VALUE %3, A, ..., # Z
2713+
// %2 = ld ...
2714+
// %3 = ld ...
2715+
// %4 = ld ...
2716+
2717+
// After the DBG_VALUE Y is processed, the DbgValueSinkCandidates is updated
2718+
// to now hold Y for A and the RegisterMap is also updated to remove X from
2719+
// %2, this is because both X and Y describe the same debug variable A. X is
2720+
// also updated to have a $noreg as the first operand.
2721+
// DbgValueSinkCandidates = {A -> {Y}}, RegisterMap = {2 -> {}, 3 -> {}},
2722+
// InstrMap = {X-> 2}
2723+
// DBG_VALUE $noreg, A, .... # X
2724+
// DBG_VALUE 0, A, ... # Y
2725+
// -> DBG_VALUE %3, A, ..., # Z
2726+
// %2 = ld ...
2727+
// %3 = ld ...
2728+
// %4 = ld ...
2729+
2730+
// After DBG_VALUE Z is processed, the DbgValueSinkCandidates is updated to
2731+
// hold Z fr A, the RegisterMap is updated to hold Z for %3, and the InstrMap
2732+
// is updated to have Z mapped to %3. This is again because Z describes the
2733+
// debug variable A, Y is not updated to have $noreg as first operand because
2734+
// its first operand is an immediate, not a register.
2735+
// DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2736+
// InstrMap = {X -> 2, Z -> 3}
2737+
// DBG_VALUE $noreg, A, .... # X
2738+
// DBG_VALUE 0, A, ... # Y
2739+
// DBG_VALUE %3, A, ..., # Z
2740+
// -> %2 = ld ...
2741+
// %3 = ld ...
2742+
// %4 = ld ...
2743+
2744+
// Nothing happens here since the RegisterMap for %2 contains no value.
2745+
// DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2746+
// InstrMap = {X -> 2, Z -> 3}
2747+
// DBG_VALUE $noreg, A, .... # X
2748+
// DBG_VALUE 0, A, ... # Y
2749+
// DBG_VALUE %3, A, ..., # Z
2750+
// %2 = ld ...
2751+
// -> %3 = ld ...
2752+
// %4 = ld ...
2753+
2754+
// Since the RegisterMap contains Z as a value for %3, the MachineInstr
2755+
// pointer Z is copied to come after the load for %3 and the old Z's first
2756+
// operand is changed to $noreg the Basic Block iterator is moved to after the
2757+
// DBG_VALUE Z's new position.
2758+
// DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2759+
// InstrMap = {X -> 2, Z -> 3}
2760+
// DBG_VALUE $noreg, A, .... # X
2761+
// DBG_VALUE 0, A, ... # Y
2762+
// DBG_VALUE $noreg, A, ..., # Old Z
2763+
// %2 = ld ...
2764+
// %3 = ld ...
2765+
// DBG_VALUE %3, A, ..., # Z
2766+
// -> %4 = ld ...
2767+
2768+
// Nothing happens for %4 and the algorithm exits having processed the entire
2769+
// Basic Block.
2770+
// DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}},
2771+
// InstrMap = {X -> 2, Z -> 3}
2772+
// DBG_VALUE $noreg, A, .... # X
2773+
// DBG_VALUE 0, A, ... # Y
2774+
// DBG_VALUE $noreg, A, ..., # Old Z
2775+
// %2 = ld ...
2776+
// %3 = ld ...
2777+
// DBG_VALUE %3, A, ..., # Z
2778+
// %4 = ld ...
2779+
2780+
// This map is used to track the relationship between
2781+
// a Debug Variable and the DBG_VALUE MachineInstr pointer that describes the
2782+
// debug information for that Debug Variable.
2783+
SmallDenseMap<DebugVariable, MachineInstr *, 8> DbgValueSinkCandidates;
2784+
// This map is used to track the relationship between a DBG_VALUE or
2785+
// DBG_VALUE_LIST MachineInstr pointer and Registers that it uses.
2786+
SmallDenseMap<MachineInstr *, SmallVector<Register>, 8> InstrMap;
2787+
for (MBBI = MBB->begin(), E = MBB->end(); MBBI != E; ++MBBI) {
2788+
MachineInstr &MI = *MBBI;
2789+
2790+
auto PopulateRegisterAndInstrMapForDebugInstr = [&](Register Reg) {
2791+
auto RegIt = RegisterMap.find(Reg);
2792+
if (RegIt == RegisterMap.end())
2793+
return;
2794+
auto &InstrVec = RegIt->getSecond();
2795+
InstrVec.push_back(&MI);
2796+
InstrMap[&MI].push_back(Reg);
2797+
};
2798+
2799+
if (MI.isDebugValue()) {
2800+
auto *DILocalVar = MI.getDebugVariable();
2801+
// TODO: This should not happen, have to fix the MIR verifier to check for
2802+
// such instances and fix them.
2803+
if (!DILocalVar)
2804+
continue;
2805+
auto DbgVar = createDebugVariableFromMachineInstr(&MI);
2806+
// If the first operand is a register and it exists in the RegisterMap, we
2807+
// know this is a DBG_VALUE that uses the result of a load that was moved,
2808+
// and is therefore a candidate to also be moved, add it to the
2809+
// RegisterMap and InstrMap.
2810+
forEachDbgRegOperand(&MI, [&](MachineOperand &Op) {
2811+
PopulateRegisterAndInstrMapForDebugInstr(Op.getReg());
2812+
});
2813+
2814+
// If the current DBG_VALUE describes the same variable as one of the
2815+
// in-flight DBG_VALUEs, remove the candidate from the list and set it to
2816+
// undef. Moving one DBG_VALUE past another would result in the variable's
2817+
// value going back in time when stepping through the block in the
2818+
// debugger.
2819+
auto InstrIt = DbgValueSinkCandidates.find(DbgVar);
2820+
if (InstrIt != DbgValueSinkCandidates.end()) {
2821+
auto *Instr = InstrIt->getSecond();
2822+
auto RegIt = InstrMap.find(Instr);
2823+
if (RegIt != InstrMap.end()) {
2824+
const auto &RegVec = RegIt->getSecond();
2825+
// For every Register in the RegVec, remove the MachineInstr in the
2826+
// RegisterMap that describes the DbgVar.
2827+
for (auto &Reg : RegVec) {
2828+
auto RegIt = RegisterMap.find(Reg);
2829+
if (RegIt == RegisterMap.end())
2830+
continue;
2831+
auto &InstrVec = RegIt->getSecond();
2832+
auto IsDbgVar = [&](MachineInstr *I) -> bool {
2833+
auto Var = createDebugVariableFromMachineInstr(I);
2834+
return Var == DbgVar;
2835+
};
2836+
2837+
InstrVec.erase(
2838+
std::remove_if(InstrVec.begin(), InstrVec.end(), IsDbgVar),
2839+
InstrVec.end());
2840+
}
2841+
forEachDbgRegOperand(Instr,
2842+
[&](MachineOperand &Op) { Op.setReg(0); });
2843+
}
2844+
}
2845+
DbgValueSinkCandidates[DbgVar] = &MI;
2846+
} else {
2847+
// If the first operand of a load matches with a DBG_VALUE in RegisterMap,
2848+
// then move that DBG_VALUE to below the load.
2849+
auto Opc = MI.getOpcode();
2850+
if (!isLoadSingle(Opc))
2851+
continue;
2852+
auto Reg = MI.getOperand(0).getReg();
2853+
auto RegIt = RegisterMap.find(Reg);
2854+
if (RegIt == RegisterMap.end())
2855+
continue;
2856+
auto &DbgInstrVec = RegIt->getSecond();
2857+
if (!DbgInstrVec.size())
2858+
continue;
2859+
for (auto *DbgInstr : DbgInstrVec) {
2860+
MachineBasicBlock::iterator InsertPos = std::next(MBBI);
2861+
auto *ClonedMI = MI.getMF()->CloneMachineInstr(DbgInstr);
2862+
MBB->insert(InsertPos, ClonedMI);
2863+
MBBI++;
2864+
// Erase the entry into the DbgValueSinkCandidates for the DBG_VALUE
2865+
// that was moved.
2866+
auto DbgVar = createDebugVariableFromMachineInstr(DbgInstr);
2867+
auto DbgIt = DbgValueSinkCandidates.find(DbgVar);
2868+
// If the instruction is a DBG_VALUE_LIST, it may have already been
2869+
// erased from the DbgValueSinkCandidates. Only erase if it exists in
2870+
// the DbgValueSinkCandidates.
2871+
if (DbgIt != DbgValueSinkCandidates.end())
2872+
DbgValueSinkCandidates.erase(DbgIt);
2873+
// Zero out original dbg instr
2874+
forEachDbgRegOperand(DbgInstr,
2875+
[&](MachineOperand &Op) { Op.setReg(0); });
2876+
// Update RegisterMap with ClonedMI because it might have to be moved
2877+
// again.
2878+
if (DbgInstr->isDebugValueList())
2879+
updateRegisterMapForDbgValueListAfterMove(RegisterMap, ClonedMI,
2880+
DbgInstr);
2881+
}
2882+
}
2883+
}
25852884
return RetVal;
25862885
}
25872886

0 commit comments

Comments
 (0)