diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -992,6 +992,27 @@ /// Temporary cache of DBG_VALUEs to be entered into the Transfers collection. SmallVector PendingDbgValues; + /// Record of a use-before-def: created when a value that's live-in to the + /// current block isn't available in any machine location, but it will be + /// defined in this block. + struct UseBeforeDef { + /// Value of this variable, def'd in block. + ValueIDNum ID; + /// Identity of this variable. + DebugVariable Var; + /// Additional variable properties. + DbgValueProperties Properties; + }; + + /// Map from instruction index (within the block) to the set of UseBeforeDefs + /// that become defined at that instruction. + DenseMap> UseBeforeDefs; + + /// The set of variables that are in UseBeforeDefs and can become a location + /// once the relevant value is defined. An element being erased from this + /// collection prevents the use-before-def materializing. + DenseSet UseBeforeDefVariables; + const TargetRegisterInfo &TRI; const BitVector &CalleeSavedRegs; @@ -1014,6 +1035,8 @@ ActiveVLocs.clear(); VarLocs.clear(); VarLocs.reserve(NumLocs); + UseBeforeDefs.clear(); + UseBeforeDefVariables.clear(); auto isCalleeSaved = [&](LocIdx L) { unsigned Reg = MTracker->LocIdxToLocID[L]; @@ -1058,9 +1081,15 @@ } // If the value has no location, we can't make a variable location. - auto ValuesPreferredLoc = ValueToLoc.find(Var.second.ID); - if (ValuesPreferredLoc == ValueToLoc.end()) + const ValueIDNum &Num = Var.second.ID; + auto ValuesPreferredLoc = ValueToLoc.find(Num); + if (ValuesPreferredLoc == ValueToLoc.end()) { + // If it's a def that occurs in this block, register it as a + // use-before-def to be resolved as we step through the block. + if (Num.getBlock() == (unsigned)MBB.getNumber() && !Num.isPHI()) + addUseBeforeDef(Var.first, Var.second.Properties, Num); continue; + } LocIdx M = ValuesPreferredLoc->second; auto NewValue = LocAndProperties{M, Var.second.Properties}; @@ -1074,6 +1103,44 @@ flushDbgValues(MBB.begin(), &MBB); } + /// Record that \p Var has value \p ID, a value that becomes available + /// later in the function. + void addUseBeforeDef(const DebugVariable &Var, + const DbgValueProperties &Properties, ValueIDNum ID) { + UseBeforeDef UBD = {ID, Var, Properties}; + UseBeforeDefs[ID.getInst()].push_back(UBD); + UseBeforeDefVariables.insert(Var); + } + + /// After the instruction at index \p Inst and position \p pos has been + /// processed, check whether it defines a variable value in a use-before-def. + /// If so, and the variable value hasn't changed since the start of the + /// block, create a DBG_VALUE. + void checkInstForNewValues(unsigned Inst, MachineBasicBlock::iterator pos) { + auto MIt = UseBeforeDefs.find(Inst); + if (MIt == UseBeforeDefs.end()) + return; + + for (auto &Use : MIt->second) { + LocIdx L = Use.ID.getLoc(); + + // If something goes very wrong, we might end up labelling a COPY + // instruction or similar with an instruction number, where it doesn't + // actually define a new value, instead it moves a value. In case this + // happens, discard. + if (MTracker->LocIdxToIDNum[L] != Use.ID) + continue; + + // If a different debug instruction defined the variable value / location + // since the start of the block, don't materialize this use-before-def. + if (!UseBeforeDefVariables.count(Use.Var)) + continue; + + PendingDbgValues.push_back(MTracker->emitLoc(L, Use.Var, Use.Properties)); + } + flushDbgValues(pos, nullptr); + } + /// Helper to move created DBG_VALUEs into Transfers collection. void flushDbgValues(MachineBasicBlock::iterator Pos, MachineBasicBlock *MBB) { if (PendingDbgValues.size() > 0) { @@ -1097,6 +1164,8 @@ ActiveMLocs[It->second.Loc].erase(Var); ActiveVLocs.erase(It); } + // Any use-before-defs no longer apply. + UseBeforeDefVariables.erase(Var); return; } @@ -1112,6 +1181,8 @@ Optional OptNewLoc) { DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), MI.getDebugLoc()->getInlinedAt()); + // Any use-before-defs no longer apply. + UseBeforeDefVariables.erase(Var); // Erase any previous location, auto It = ActiveVLocs.find(Var); @@ -1659,6 +1730,12 @@ // Tell transfer tracker that the variable value has changed. TTracker->redefVar(MI, Properties, FoundLoc); + // If there was a value with no location; but the value is defined in a + // later instruction in this block, this is a block-local use-before-def. + if (!FoundLoc && NewID && NewID->getBlock() == CurBB && + NewID->getInst() > CurInst) + TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false}, *NewID); + // Produce a DBG_VALUE representing what this DBG_INSTR_REF meant. // This DBG_VALUE is potentially a $noreg / undefined location, if // FoundLoc is None. @@ -3069,6 +3146,7 @@ CurInst = 1; for (auto &MI : MBB) { process(MI); + TTracker->checkInstForNewValues(CurInst, MI.getIterator()); ++CurInst; } } diff --git a/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir b/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir --- a/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir +++ b/llvm/test/DebugInfo/MIR/InstrRef/livedebugvalues_instrref_tolocs.mir @@ -68,5 +68,91 @@ ; any successor blocks. ; CHECK: DBG_VALUE $rbx, $noreg + DBG_INSTR_REF 5, 0, !16, !DIExpression(), debug-location !17 + ; This is a debug use-before-def: the value appears a few instructions + ; later. Any earlier value should be terminated here, _and_ we should + ; emit a DBG_VALUE when the value becomes available. + ; CHECK: DBG_VALUE $noreg, $noreg + + $rax = MOV64ri 1, debug-location !17 + $rax = MOV64ri 1, debug-location !17 + $rcx = MOV64ri 1, debug-instr-number 5, debug-location !17 + ; CHECK: DBG_VALUE $rcx, $noreg + $rax = MOV64ri 1, debug-location !17 + + DBG_INSTR_REF 6, 0, !16, !DIExpression(), debug-location !17 + ; Another debug use-before-def, but across block boundaries. + ; CHECK: DBG_VALUE $noreg, $noreg + JMP_1 %bb.3 + + ; CHECK-LABEL: bb.3: + bb.3: + $rax = MOV64ri 1, debug-location !17 + $rdx = MOV64ri 1, debug-instr-number 6, debug-location !17 + ; CHECK: DBG_VALUE $rdx, $noreg + + ; Terminate variable location for next few blocks, + DBG_VALUE $noreg, $noreg, !16, !DIExpression(), debug-location !17 + ; CHECK: DBG_VALUE $noreg, $noreg + JMP_1 %bb.4 + + bb.4: + ; The next three blocks form a debug use-before-def modelling a scenario + ; where an instruction is sunk (debug inst in bb5, value in bb6). However, + ; because a different path joins bb.6, we should _not_ add any DBG_VALUE. + ; A different variable value may enter the block via the other path. + $rdx = MOV64ri 1, implicit-def $eflags, debug-location !17 + JCC_1 %bb.6, 4, implicit $eflags, debug-location !17 + bb.5: + DBG_INSTR_REF 7, 0, !16, !DIExpression(), debug-location !17 + ; CHECK: DBG_VALUE $noreg, $noreg + JMP_1 %bb.6, debug-location !17 + bb.6: + $rsi = MOV64ri 1, debug-instr-number 7, debug-location !17 + JMP_1 %bb.7, debug-location !17 + + ; A use-before-def shouldn't pass another definition of the variable location + ; or value. + bb.7: + DBG_INSTR_REF 8, 0, !16, !DIExpression(), debug-location !17 + ; CHECK: DBG_VALUE $noreg, $noreg + DBG_VALUE $rax, $noreg, !16, !DIExpression(), debug-location !17 + ; CHECK: DBG_VALUE $rax, $noreg, + $rdi = MOV64ri 1, debug-instr-number 8, debug-location !17 + + ; Loops: use-before-defs should be live-through loops, assuming that nothing + ; in that loop modifies the variable location. + bb.8: + DBG_INSTR_REF 9, 0, !16, !DIExpression(), debug-location !17 + ; CHECK: DBG_VALUE $noreg, $noreg + JCC_1 %bb.8, 4, implicit $eflags + bb.9: + $rax = MOV64ri 11, debug-instr-number 9, debug-location !17 + ; CHECK: DBG_VALUE $rax, $noreg, + + ; Likewise, use-before-defs where anything changes the variable location + ; or value in the loop, should be discarded. + bb.10: + ; live-in, + ; CHECK: DBG_VALUE $rax, $noreg, + DBG_INSTR_REF 10, 0, !16, !DIExpression(), debug-location !17 + ; CHECK: DBG_VALUE $noreg, $noreg + + bb.11: + $rbx = MOV64ri 1, debug-location !17 + + bb.12: + DBG_INSTR_REF 9, 0, !16, !DIExpression(), debug-location !17 + ; This still has a value in $rax, + ; CHECK: DBG_VALUE $rax, $noreg + JCC_1 %bb.11, 4, implicit $eflags + + bb.13: + ; Live in, + ; CHECK: DBG_VALUE $rax, $noreg + $rbx = MOV64ri 11, debug-instr-number 10, debug-location !17 + ; This is instruction 10 referred to in bb.10. However, as the variable + ; location/value has been modified in the meantime, no DBG_VALUE should be + ; generated here. RETQ $eax, debug-location !17 ...