Index: llvm/trunk/include/llvm/CodeGen/DbgEntityHistoryCalculator.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/DbgEntityHistoryCalculator.h +++ llvm/trunk/include/llvm/CodeGen/DbgEntityHistoryCalculator.h @@ -10,6 +10,7 @@ #define LLVM_CODEGEN_DBGVALUEHISTORYCALCULATOR_H #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/DebugInfoMetadata.h" #include @@ -21,30 +22,54 @@ class MachineInstr; class TargetRegisterInfo; -// For each user variable, keep a list of instruction ranges where this variable -// is accessible. The variables are listed in order of appearance. +/// For each user variable, keep a list of instruction ranges where this +/// variable is accessible. The variables are listed in order of appearance. class DbgValueHistoryMap { public: - /// Specifies an instruction range where a DBG_VALUE is valid. + /// Index in the entry vector. + typedef size_t EntryIndex; + + /// Special value to indicate that an entry is valid until the end of the + /// function. + static const EntryIndex NoEntry = std::numeric_limits::max(); + + /// Specifies a change in a variable's debug value history. + /// + /// There exist two types of entries: + /// + /// * Debug value entry: + /// + /// A new debug value becomes live. If the entry's \p EndIndex is \p NoEntry, + /// the value is valid until the end of the function. For other values, the + /// index points to the entry in the entry vector that ends this debug + /// value. The ending entry can either be an overlapping debug value, or + /// an instruction that clobbers the value. /// - /// \p Begin is a DBG_VALUE instruction, specifying the location of a - /// variable, which is assumed to be valid until the end of the range. If \p - /// End is not specified, the location is valid until the first overlapping - /// DBG_VALUE if any such DBG_VALUE exists, otherwise it is valid until the - /// end of the function. + /// * Clobbering entry: + /// + /// This entry's instruction clobbers one or more preceding + /// register-described debug values that have their end index + /// set to this entry's position in the entry vector. class Entry { - const MachineInstr *Begin; - const MachineInstr *End; - public: - Entry(const MachineInstr *Begin) : Begin(Begin), End(nullptr) {} + enum EntryKind { DbgValue, Clobber }; + + Entry(const MachineInstr *Instr, EntryKind Kind) + : Instr(Instr, Kind), EndIndex(NoEntry) {} - const MachineInstr *getBegin() const { return Begin; } - const MachineInstr *getEnd() const { return End; } + const MachineInstr *getInstr() const { return Instr.getPointer(); } + EntryIndex getEndIndex() const { return EndIndex; } + EntryKind getEntryKind() const { return Instr.getInt(); } - bool isClosed() const { return End; } + bool isClobber() const { return getEntryKind() == Clobber; } + bool isDbgValue() const { return getEntryKind() == DbgValue; } + bool isClosed() const { return EndIndex != NoEntry; } - void endEntry(const MachineInstr &End); + void endEntry(EntryIndex EndIndex); + + private: + PointerIntPair Instr; + EntryIndex EndIndex; }; using Entries = SmallVector; using InlinedEntity = std::pair; @@ -54,13 +79,19 @@ EntriesMap VarEntries; public: - void startEntry(InlinedEntity Var, const MachineInstr &MI); - void endEntry(InlinedEntity Var, const MachineInstr &MI); + bool startDbgValue(InlinedEntity Var, const MachineInstr &MI, + EntryIndex &NewIndex); + EntryIndex startClobber(InlinedEntity Var, const MachineInstr &MI); // Returns register currently describing @Var. If @Var is currently // unaccessible or is not described by a register, returns 0. unsigned getRegisterForVar(InlinedEntity Var) const; + Entry &getEntry(InlinedEntity Var, EntryIndex Index) { + auto &Entries = VarEntries[Var]; + return Entries[Index]; + } + bool empty() const { return VarEntries.empty(); } void clear() { VarEntries.clear(); } EntriesMap::const_iterator begin() const { return VarEntries.begin(); } Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1160,7 +1160,9 @@ // Calculate the definition ranges. for (auto I = Entries.begin(), E = Entries.end(); I != E; ++I) { const auto &Entry = *I; - const MachineInstr *DVInst = Entry.getBegin(); + if (!Entry.isDbgValue()) + continue; + const MachineInstr *DVInst = Entry.getInstr(); assert(DVInst->isDebugValue() && "Invalid History entry"); // FIXME: Find a way to represent constant variables, since they are // relatively common. @@ -1215,21 +1217,15 @@ } // Compute the label range. - const MCSymbol *Begin = getLabelBeforeInsn(Entry.getBegin()); - const MCSymbol *End = getLabelAfterInsn(Entry.getEnd()); - if (!End) { - // This range is valid until the next overlapping bitpiece. In the - // common case, ranges will not be bitpieces, so they will overlap. - auto J = std::next(I); - const DIExpression *DIExpr = DVInst->getDebugExpression(); - while (J != E && - !DIExpr->fragmentsOverlap(J->getBegin()->getDebugExpression())) - ++J; - if (J != E) - End = getLabelBeforeInsn(J->getBegin()); - else - End = Asm->getFunctionEnd(); - } + const MCSymbol *Begin = getLabelBeforeInsn(Entry.getInstr()); + const MCSymbol *End; + if (Entry.getEndIndex() != DbgValueHistoryMap::NoEntry) { + auto &EndingEntry = Entries[Entry.getEndIndex()]; + End = EndingEntry.isDbgValue() + ? getLabelBeforeInsn(EndingEntry.getInstr()) + : getLabelAfterInsn(EndingEntry.getInstr()); + } else + End = Asm->getFunctionEnd(); // If the last range end is our begin, just extend the last range. // Otherwise make a new range. Index: llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -9,6 +9,7 @@ #include "llvm/CodeGen/DbgEntityHistoryCalculator.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" @@ -30,6 +31,10 @@ #define DEBUG_TYPE "dwarfdebug" +namespace { +using EntryIndex = DbgValueHistoryMap::EntryIndex; +} + // If @MI is a DBG_VALUE with debug value described by a // defined register, returns the number of this register. // In the other case, returns 0. @@ -41,33 +46,39 @@ return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : 0; } -void DbgValueHistoryMap::startEntry(InlinedEntity Var, const MachineInstr &MI) { +bool DbgValueHistoryMap::startDbgValue(InlinedEntity Var, + const MachineInstr &MI, + EntryIndex &NewIndex) { // Instruction range should start with a DBG_VALUE instruction for the // variable. assert(MI.isDebugValue() && "not a DBG_VALUE"); auto &Entries = VarEntries[Var]; - if (!Entries.empty() && !Entries.back().isClosed() && - Entries.back().getBegin()->isIdenticalTo(MI)) { + if (!Entries.empty() && Entries.back().isDbgValue() && + !Entries.back().isClosed() && + Entries.back().getInstr()->isIdenticalTo(MI)) { LLVM_DEBUG(dbgs() << "Coalescing identical DBG_VALUE entries:\n" - << "\t" << Entries.back().getBegin() << "\t" << MI + << "\t" << Entries.back().getInstr() << "\t" << MI << "\n"); - return; + return false; } - Entries.emplace_back(&MI); + Entries.emplace_back(&MI, Entry::DbgValue); + NewIndex = Entries.size() - 1; + return true; } -void DbgValueHistoryMap::endEntry(InlinedEntity Var, const MachineInstr &MI) { +EntryIndex DbgValueHistoryMap::startClobber(InlinedEntity Var, + const MachineInstr &MI) { auto &Entries = VarEntries[Var]; - assert(!Entries.empty() && "No range exists for variable!"); - Entries.back().endEntry(MI); + Entries.emplace_back(&MI, Entry::Clobber); + return Entries.size() - 1; } -void DbgValueHistoryMap::Entry::endEntry(const MachineInstr &MI) { +void DbgValueHistoryMap::Entry::endEntry(EntryIndex Index) { // For now, instruction ranges are not allowed to cross basic block // boundaries. - assert(Begin->getParent() == MI.getParent()); - assert(!isClosed() && "Range is already closed!"); - End = &MI; + assert(isDbgValue() && "Setting end index for non-debug value"); + assert(!isClosed() && "End index has already been set"); + EndIndex = Index; } unsigned DbgValueHistoryMap::getRegisterForVar(InlinedEntity Var) const { @@ -77,7 +88,9 @@ const auto &Entries = I->second; if (Entries.empty() || Entries.back().isClosed()) return 0; - return isDescribedByReg(*Entries.back().getBegin()); + if (Entries.back().isClobber()) + return 0; + return isDescribedByReg(*Entries.back().getInstr()); } void DbgLabelInstrMap::addInstr(InlinedEntity Label, const MachineInstr &MI) { @@ -91,6 +104,12 @@ using InlinedEntity = DbgValueHistoryMap::InlinedEntity; using RegDescribedVarsMap = std::map>; +// Keeps track of the debug value entries that are currently live for each +// inlined entity. As the history map entries are stored in a SmallVector, they +// may be moved at insertion of new entries, so store indices rather than +// pointers. +using DbgValueEntriesMap = std::map>; + } // end anonymous namespace // Claim that @Var is not described by @RegNo anymore. @@ -116,16 +135,67 @@ VarSet.push_back(Var); } +static void clobberRegEntries(InlinedEntity Var, unsigned RegNo, + const MachineInstr &ClobberingInstr, + DbgValueEntriesMap &LiveEntries, + DbgValueHistoryMap &HistMap) { + EntryIndex ClobberIndex = HistMap.startClobber(Var, ClobberingInstr); + + // TODO: Close all preceding live entries that are clobbered by this + // instruction. + EntryIndex ValueIndex = ClobberIndex - 1; + auto &ValueEntry = HistMap.getEntry(Var, ValueIndex); + ValueEntry.endEntry(ClobberIndex); + LiveEntries[Var].erase(ValueIndex); +} + +/// Add a new debug value for \p Var. Closes all overlapping debug values. +static void handleNewDebugValue(InlinedEntity Var, const MachineInstr &DV, + RegDescribedVarsMap &RegVars, + DbgValueEntriesMap &LiveEntries, + DbgValueHistoryMap &HistMap) { + // TODO: We should track all registers which this variable is currently + // described by. + + if (unsigned PrevReg = HistMap.getRegisterForVar(Var)) + dropRegDescribedVar(RegVars, PrevReg, Var); + + EntryIndex NewIndex; + if (HistMap.startDbgValue(Var, DV, NewIndex)) { + // If we have created a new debug value entry, close all preceding + // live entries that overlap. + SmallVector IndicesToErase; + const DIExpression *DIExpr = DV.getDebugExpression(); + for (auto Index : LiveEntries[Var]) { + auto &Entry = HistMap.getEntry(Var, Index); + assert(Entry.isDbgValue() && "Not a DBG_VALUE in LiveEntries"); + const MachineInstr &DV = *Entry.getInstr(); + if (DIExpr->fragmentsOverlap(DV.getDebugExpression())) { + IndicesToErase.push_back(Index); + Entry.endEntry(NewIndex); + } + } + // Drop all entries that have ended, and mark the new entry as live. + for (auto Index : IndicesToErase) + LiveEntries[Var].erase(Index); + LiveEntries[Var].insert(NewIndex); + } + + if (unsigned NewReg = isDescribedByReg(DV)) + addRegDescribedVar(RegVars, NewReg, Var); +} + // Terminate the location range for variables described by register at // @I by inserting @ClobberingInstr to their history. static void clobberRegisterUses(RegDescribedVarsMap &RegVars, RegDescribedVarsMap::iterator I, DbgValueHistoryMap &HistMap, + DbgValueEntriesMap &LiveEntries, const MachineInstr &ClobberingInstr) { // Iterate over all variables described by this register and add this // instruction to their history, clobbering it. for (const auto &Var : I->second) - HistMap.endEntry(Var, ClobberingInstr); + clobberRegEntries(Var, I->first, ClobberingInstr, LiveEntries, HistMap); RegVars.erase(I); } @@ -133,11 +203,12 @@ // @RegNo by inserting @ClobberingInstr to their history. static void clobberRegisterUses(RegDescribedVarsMap &RegVars, unsigned RegNo, DbgValueHistoryMap &HistMap, + DbgValueEntriesMap &LiveEntries, const MachineInstr &ClobberingInstr) { const auto &I = RegVars.find(RegNo); if (I == RegVars.end()) return; - clobberRegisterUses(RegVars, I, HistMap, ClobberingInstr); + clobberRegisterUses(RegVars, I, HistMap, LiveEntries, ClobberingInstr); } // Returns the first instruction in @MBB which corresponds to @@ -204,6 +275,7 @@ const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); RegDescribedVarsMap RegVars; + DbgValueEntriesMap LiveEntries; for (const auto &MBB : *MF) { for (const auto &MI : MBB) { if (!MI.isDebugInstr()) { @@ -218,14 +290,15 @@ // If this is a virtual register, only clobber it since it doesn't // have aliases. if (TRI->isVirtualRegister(MO.getReg())) - clobberRegisterUses(RegVars, MO.getReg(), DbgValues, MI); + clobberRegisterUses(RegVars, MO.getReg(), DbgValues, LiveEntries, + MI); // If this is a register def operand, it may end a debug value // range. else { for (MCRegAliasIterator AI(MO.getReg(), TRI, true); AI.isValid(); ++AI) if (ChangingRegs.test(*AI)) - clobberRegisterUses(RegVars, *AI, DbgValues, MI); + clobberRegisterUses(RegVars, *AI, DbgValues, LiveEntries, MI); } } else if (MO.isRegMask()) { // If this is a register mask operand, clobber all debug values in @@ -234,7 +307,7 @@ // Don't consider SP to be clobbered by register masks. if (unsigned(I) != SP && TRI->isPhysicalRegister(I) && MO.clobbersPhysReg(I)) { - clobberRegisterUses(RegVars, I, DbgValues, MI); + clobberRegisterUses(RegVars, I, DbgValues, LiveEntries, MI); } } } @@ -252,13 +325,7 @@ "Expected inlined-at fields to agree"); InlinedEntity Var(RawVar, MI.getDebugLoc()->getInlinedAt()); - if (unsigned PrevReg = DbgValues.getRegisterForVar(Var)) - dropRegDescribedVar(RegVars, PrevReg, Var); - - DbgValues.startEntry(Var, MI); - - if (unsigned NewReg = isDescribedByReg(MI)) - addRegDescribedVar(RegVars, NewReg, Var); + handleNewDebugValue(Var, MI, RegVars, LiveEntries, DbgValues); } else if (MI.isDebugLabel()) { assert(MI.getNumOperands() == 1 && "Invalid DBG_LABEL instruction!"); const DILabel *RawLabel = MI.getDebugLabel(); @@ -280,7 +347,8 @@ auto CurElem = I++; // CurElem can be erased below. if (TRI->isVirtualRegister(CurElem->first) || ChangingRegs.test(CurElem->first)) - clobberRegisterUses(RegVars, CurElem, DbgValues, MBB.back()); + clobberRegisterUses(RegVars, CurElem, DbgValues, LiveEntries, + MBB.back()); } } } @@ -306,10 +374,20 @@ dbgs() << " --\n"; - for (const auto &Entry : Entries) { - dbgs() << " Begin: " << *Entry.getBegin(); - if (Entry.getEnd()) - dbgs() << " End : " << *Entry.getEnd(); + for (const auto &E : enumerate(Entries)) { + const auto &Entry = E.value(); + dbgs() << " Entry[" << E.index() << "]: "; + if (Entry.isDbgValue()) + dbgs() << "Debug value\n"; + else + dbgs() << "Clobber\n"; + dbgs() << " Instr: " << *Entry.getInstr(); + if (Entry.isDbgValue()) { + if (Entry.getEndIndex() == NoEntry) + dbgs() << " - Valid until end of function\n"; + else + dbgs() << " - Closed by Entry[" << Entry.getEndIndex() << "]\n"; + } dbgs() << "\n"; } } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -229,31 +229,35 @@ // However, we currently do not emit debug values for constant arguments // directly at the start of the function, so this code is still useful. const DILocalVariable *DIVar = - Entries.front().getBegin()->getDebugVariable(); + Entries.front().getInstr()->getDebugVariable(); if (DIVar->isParameter() && getDISubprogram(DIVar->getScope())->describes(&MF->getFunction())) { - if (!IsDescribedByReg(Entries.front().getBegin())) - LabelsBeforeInsn[Entries.front().getBegin()] = Asm->getFunctionBegin(); - if (Entries.front().getBegin()->getDebugExpression()->isFragment()) { + if (!IsDescribedByReg(Entries.front().getInstr())) + LabelsBeforeInsn[Entries.front().getInstr()] = Asm->getFunctionBegin(); + if (Entries.front().getInstr()->getDebugExpression()->isFragment()) { // Mark all non-overlapping initial fragments. for (auto I = Entries.begin(); I != Entries.end(); ++I) { - const DIExpression *Fragment = I->getBegin()->getDebugExpression(); + if (!I->isDbgValue()) + continue; + const DIExpression *Fragment = I->getInstr()->getDebugExpression(); if (std::any_of(Entries.begin(), I, [&](DbgValueHistoryMap::Entry Pred) { - return Fragment->fragmentsOverlap( - Pred.getBegin()->getDebugExpression()); + return Pred.isDbgValue() && + Fragment->fragmentsOverlap( + Pred.getInstr()->getDebugExpression()); })) break; - if (!IsDescribedByReg(I->getBegin())) - LabelsBeforeInsn[I->getBegin()] = Asm->getFunctionBegin(); + if (!IsDescribedByReg(I->getInstr())) + LabelsBeforeInsn[I->getInstr()] = Asm->getFunctionBegin(); } } } for (const auto &Entry : Entries) { - requestLabelBeforeInsn(Entry.getBegin()); - if (Entry.getEnd()) - requestLabelAfterInsn(Entry.getEnd()); + if (Entry.isDbgValue()) + requestLabelBeforeInsn(Entry.getInstr()); + else + requestLabelAfterInsn(Entry.getInstr()); } } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1095,67 +1095,92 @@ } /// Build the location list for all DBG_VALUEs in the function that -/// describe the same variable. If the ranges of several independent -/// fragments of the same variable overlap partially, split them up and -/// combine the ranges. The resulting DebugLocEntries are will have +/// describe the same variable. The resulting DebugLocEntries will have /// strict monotonically increasing begin addresses and will never /// overlap. // +// See the definition of DbgValueHistoryMap::Entry for an explanation of the +// different kinds of history map entries. One thing to be aware of is that if +// a debug value is ended by another entry (rather than being valid until the +// end of the function), that entry's instruction may or may not be included in +// the range, depending on if the entry is a clobbering entry (it has an +// instruction that clobbers one or more preceding locations), or if it is an +// (overlapping) debug value entry. This distinction can be seen in the example +// below. The first debug value is ended by the clobbering entry 2, and the +// second and third debug values are ended by the overlapping debug value entry +// 4. +// // Input: // -// Ranges History [var, loc, fragment ofs size] -// 0 | [x, (reg0, fragment 0, 32)] -// 1 | | [x, (reg1, fragment 32, 32)] <- IsFragmentOfPrevEntry -// 2 | | ... -// 3 | [clobber reg0] -// 4 [x, (mem, fragment 0, 64)] <- overlapping with both previous fragments of -// x. +// History map entries [type, end index, mi] +// +// 0 | [DbgValue, 2, DBG_VALUE $reg0, [...] (fragment 0, 32)] +// 1 | | [DbgValue, 4, DBG_VALUE $reg1, [...] (fragment 32, 32)] +// 2 | | [Clobber, $reg0 = [...], -, -] +// 3 | | [DbgValue, 4, DBG_VALUE 123, [...] (fragment 64, 32)] +// 4 [DbgValue, ~0, DBG_VALUE @g, [...] (fragment 0, 96)] // -// Output: +// Output [start, end) [Value...]: // -// [0-1] [x, (reg0, fragment 0, 32)] -// [1-3] [x, (reg0, fragment 0, 32), (reg1, fragment 32, 32)] -// [3-4] [x, (reg1, fragment 32, 32)] -// [4- ] [x, (mem, fragment 0, 64)] +// [0-1) [(reg0, fragment 0, 32)] +// [1-3) [(reg0, fragment 0, 32), (reg1, fragment 32, 32)] +// [3-4) [(reg1, fragment 32, 32), (123, fragment 64, 32)] +// [4-) [(@g, fragment 0, 96)] void DwarfDebug::buildLocationList(SmallVectorImpl &DebugLoc, const DbgValueHistoryMap::Entries &Entries) { - SmallVector OpenRanges; - - for (auto EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) { - const MachineInstr *Begin = EI->getBegin(); - const MachineInstr *End = EI->getEnd(); - assert(Begin->isDebugValue() && "Invalid History entry"); - - // Check if a variable is inaccessible in this range. - if (Begin->getNumOperands() > 1 && - Begin->getOperand(0).isReg() && !Begin->getOperand(0).getReg()) { - OpenRanges.clear(); - continue; + using OpenRange = + std::pair; + SmallVector OpenRanges; + + for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) { + const MachineInstr *Instr = EI->getInstr(); + + if (EI->isDbgValue()) { + // Check if a variable is inaccessible in this range. + // TODO: This should only truncate open ranges that are overlapping. + if (Instr->getNumOperands() > 1 && + Instr->getOperand(0).isReg() && !Instr->getOperand(0).getReg()) { + OpenRanges.clear(); + continue; + } } - // If this debug value overlaps with any open ranges, truncate them. - const DIExpression *DIExpr = Begin->getDebugExpression(); - auto Last = remove_if(OpenRanges, [&](DebugLocEntry::Value R) { - return DIExpr->fragmentsOverlap(R.getExpression()); - }); + // Remove all values that are no longer live. + size_t Index = std::distance(EB, EI); + auto Last = + remove_if(OpenRanges, [&](OpenRange &R) { return R.first <= Index; }); OpenRanges.erase(Last, OpenRanges.end()); - const MCSymbol *StartLabel = getLabelBeforeInsn(Begin); - assert(StartLabel && "Forgot label before DBG_VALUE starting a range!"); + // If we are dealing with a clobbering entry, this iteration will result in + // a location list entry starting after the clobbering instruction. + const MCSymbol *StartLabel = + EI->isClobber() ? getLabelAfterInsn(Instr) : getLabelBeforeInsn(Instr); + assert(StartLabel && + "Forgot label before/after instruction starting a range!"); const MCSymbol *EndLabel; - if (End != nullptr) - EndLabel = getLabelAfterInsn(End); - else if (std::next(EI) == Entries.end()) + if (std::next(EI) == Entries.end()) EndLabel = Asm->getFunctionEnd(); + else if (std::next(EI)->isClobber()) + EndLabel = getLabelAfterInsn(std::next(EI)->getInstr()); else - EndLabel = getLabelBeforeInsn(std::next(EI)->getBegin()); + EndLabel = getLabelBeforeInsn(std::next(EI)->getInstr()); assert(EndLabel && "Forgot label after instruction ending a range!"); - LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); + if (EI->isDbgValue()) + LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Instr << "\n"); - auto Value = getDebugLocValue(Begin); - OpenRanges.push_back(Value); + // If this history map entry has a debug value, add that to the list of + // open ranges. + if (EI->isDbgValue()) { + auto Value = getDebugLocValue(Instr); + OpenRanges.emplace_back(EI->getEndIndex(), Value); + } + + // Location list entries with empty location descriptions are redundant + // information in DWARF, so do not emit those. + if (OpenRanges.empty()) + continue; // Omit entries with empty ranges as they do not have any effect in DWARF. if (StartLabel == EndLabel) { @@ -1163,7 +1188,10 @@ continue; } - DebugLoc.emplace_back(StartLabel, EndLabel, OpenRanges); + SmallVector Values; + for (auto &R : OpenRanges) + Values.push_back(R.second); + DebugLoc.emplace_back(StartLabel, EndLabel, Values); // Attempt to coalesce the ranges of two otherwise identical // DebugLocEntries. @@ -1292,15 +1320,23 @@ DbgVariable *RegVar = cast(createConcreteEntity(TheCU, *Scope, LocalVar, IV.second)); - const MachineInstr *MInsn = HistoryMapEntries.front().getBegin(); + const MachineInstr *MInsn = HistoryMapEntries.front().getInstr(); assert(MInsn->isDebugValue() && "History must begin with debug value"); // Check if there is a single DBG_VALUE, valid throughout the var's scope. - if (HistoryMapEntries.size() == 1 && - validThroughout(LScopes, MInsn, HistoryMapEntries.front().getEnd())) { - RegVar->initializeDbgValue(MInsn); - continue; + // If the history map contains a single debug value, there may be an + // additional entry which clobbers the debug value. + bool SingleValueWithClobber = + HistoryMapEntries.size() == 2 && HistoryMapEntries[1].isClobber(); + if (HistoryMapEntries.size() == 1 || SingleValueWithClobber) { + const auto *End = + SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; + if (validThroughout(LScopes, MInsn, End)) { + RegVar->initializeDbgValue(MInsn); + continue; + } } + // Do not emit location lists if .debug_loc secton is disabled. if (!useLocSection()) continue; Index: llvm/trunk/test/DebugInfo/ARM/partial-subreg.ll =================================================================== --- llvm/trunk/test/DebugInfo/ARM/partial-subreg.ll +++ llvm/trunk/test/DebugInfo/ARM/partial-subreg.ll @@ -10,7 +10,30 @@ ; CHECK: DW_TAG_formal_parameter ; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] ({{.*}} ; CHECK-NEXT: [0x{{.*}}, 0x{{.*}}): DW_OP_regx D16, DW_OP_piece 0x8, DW_OP_regx D17, DW_OP_piece 0x4 -; CHECK-NEXT: [0x{{.*}}, 0x{{.*}}): DW_OP_regx D16, DW_OP_piece 0x8, DW_OP_regx D17, DW_OP_piece 0x4, DW_OP_regx D16, DW_OP_piece 0x8, DW_OP_regx D17, DW_OP_piece 0x4 +; CHECK-NEXT: [0x{{.*}}, 0x{{.*}}): DW_OP_regx D16, DW_OP_piece 0x8, DW_OP_regx D17, DW_OP_piece 0x4 + +; FIXME: The second location list entry should not be emitted. +; +; The input to LiveDebugValues is: +; +; bb.0.entry: +; [...] +; Bcc %bb.2, 1, killed $cpsr, debug-location !10; simd.swift:5900:12 +; bb.1: +; [...] +; DBG_VALUE $q8, $noreg, !"self", !DIExpression(DW_OP_LLVM_fragment, 0, 96) +; B %bb.3 +; bb.2.select.false: +; [...] +; DBG_VALUE $q8, $noreg, !"self", !DIExpression(DW_OP_LLVM_fragment, 0, 96) +; bb.3.select.end: +; [...] +; +; The two DBG_VALUEs in the blocks describe different fragments of the +; variable. However, LiveDebugValues is not aware of fragments, so it will +; incorrectly insert a copy of the first DBG_VALUE in bb.3.select.end, since +; the debug values in its predecessor blocks are described by the same +; register. source_filename = "simd.ll" target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" Index: llvm/trunk/test/DebugInfo/MIR/X86/clobbered-fragments.mir =================================================================== --- llvm/trunk/test/DebugInfo/MIR/X86/clobbered-fragments.mir +++ llvm/trunk/test/DebugInfo/MIR/X86/clobbered-fragments.mir @@ -0,0 +1,136 @@ +# RUN: llc -O1 -start-after=livedebugvalues -o - %s | FileCheck %s + +# Reproducer based on the following C file: +# +# int global1, global2, global3; +# +# extern void ext1(int); +# extern void ext2(int, int); +# extern void ext3(int, int, int); +# +# int test1() { +# int local[3] = {global1, 123, 456}; +# ext2(local[0], local[1]); +# return local[1]; +# } +# +# Compiled using -O1 -g. + +--- | + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + @global1 = common global i32 0, align 4 + @global2 = common global i32 0, align 4 + @global3 = common global i32 0, align 4 + + ; Function Attrs: nounwind uwtable + define i32 @test1() #0 !dbg !8 { + entry: + %0 = load i32, i32* @global1, align 4, !dbg !16 + call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !16 + call void @llvm.dbg.value(metadata i32 123, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32)), !dbg !16 + call void @llvm.dbg.value(metadata i32 456, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32)), !dbg !16 + tail call void @ext2(i32 %0, i32 123), !dbg !16 + ret i32 123, !dbg !17 + } + + declare void @ext2(i32, i32) + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + + attributes #0 = { nounwind uwtable } + attributes #1 = { nounwind readnone speculatable } + + !llvm.dbg.cu = !{!1} + !llvm.module.flags = !{!5, !6} + !llvm.ident = !{!7} + + !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !3, nameTableKind: None) + !2 = !DIFile(filename: "foo.c", directory: "/") + !3 = !{} + !4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !5 = !{i32 2, !"Dwarf Version", i32 4} + !6 = !{i32 2, !"Debug Info Version", i32 3} + !7 = !{!"clang version 9.0.0"} + !8 = distinct !DISubprogram(name: "test1", scope: !2, file: !2, line: 7, type: !9, scopeLine: 7, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !1, retainedNodes: !11) + !9 = !DISubroutineType(types: !10) + !10 = !{!4} + !11 = !{!12} + !12 = !DILocalVariable(name: "local", scope: !8, file: !2, line: 8, type: !13) + !13 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 96, elements: !14) + !14 = !{!15} + !15 = !DISubrange(count: 3) + !16 = !DILocation(line: 8, scope: !8) + !17 = !DILocation(line: 9, scope: !8) + +... +--- +name: test1 +tracksRegLiveness: true +body: | + bb.0.entry: + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + renamable $edi = MOV32rm $rip, 1, $noreg, @global1, $noreg, debug-location !16 :: (dereferenceable load 4 from @global1) + DBG_VALUE 456, $noreg, !12, !DIExpression(DW_OP_LLVM_fragment, 64, 32), debug-location !16 + DBG_VALUE 123, $noreg, !12, !DIExpression(DW_OP_LLVM_fragment, 32, 32), debug-location !16 + DBG_VALUE $edi, $noreg, !12, !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !16 + $esi = MOV32ri 123, debug-location !16 + CALL64pcrel32 @ext2, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit killed $esi, implicit-def $rsp, implicit-def $ssp, debug-location !16 + $eax = MOV32ri 123, debug-location !17 + $rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !17 + RETQ killed $eax, debug-location !17 + +... + +# CHECK: .Ltmp1 +# CHECK-NEXT: #DEBUG_VALUE: test1:local <- [DW_OP_LLVM_fragment 64 32] 456 +# CHECK-NEXT: #DEBUG_VALUE: test1:local <- [DW_OP_LLVM_fragment 32 32] 123 +# CHECK-NEXT: #DEBUG_VALUE: test1:local <- [DW_OP_LLVM_fragment 0 32] $edi +# CHECK: callq ext2 +# CHECK-NEXT: .Ltmp2: + +#### Location list for test1:local. + +# Verify that a location list entry, which does not contain the fragment that +# is described by the clobbered $edi, is emitted directly after the call to +# ext2(). + +# CHECK: .Ldebug_loc0: +# CHECK-NEXT: .quad .Ltmp1-.Lfunc_begin0 +# CHECK-NEXT: .quad .Ltmp2-.Lfunc_begin0 +# CHECK-NEXT: .short 14 # Loc expr size +# CHECK-NEXT: .byte 85 # super-register DW_OP_reg5 +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 4 # 4 +# CHECK-NEXT: .byte 16 # DW_OP_constu +# CHECK-NEXT: .byte 123 # 123 +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 4 # 4 +# CHECK-NEXT: .byte 16 # DW_OP_constu +# CHECK-NEXT: .byte 200 # 456 +# CHECK-NEXT: .byte 3 # +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 4 # 4 +# CHECK-NEXT: .quad .Ltmp2-.Lfunc_begin0 +# CHECK-NEXT: .quad .Lfunc_end0-.Lfunc_begin0 +# CHECK-NEXT: .short 13 # Loc expr size +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 4 # 4 +# CHECK-NEXT: .byte 16 # DW_OP_constu +# CHECK-NEXT: .byte 123 # 123 +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 4 # 4 +# CHECK-NEXT: .byte 16 # DW_OP_constu +# CHECK-NEXT: .byte 200 # 456 +# CHECK-NEXT: .byte 3 # +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 4 # 4 +# CHECK-NEXT: .quad 0 +# CHECK-NEXT: .quad 0 + Index: llvm/trunk/test/DebugInfo/X86/pieces-3.ll =================================================================== --- llvm/trunk/test/DebugInfo/X86/pieces-3.ll +++ llvm/trunk/test/DebugInfo/X86/pieces-3.ll @@ -18,6 +18,7 @@ ; CHECK: DW_TAG_formal_parameter [3] ; CHECK-NEXT: DW_AT_location [DW_FORM_data4] ( ; CHECK-NEXT: [0x0000000000000000, 0x0000000000000007): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_piece 0x4, DW_OP_reg4 RSI, DW_OP_piece 0x4 +; CHECK-NEXT: [0x0000000000000007, 0x0000000000000009): DW_OP_reg5 RDI, DW_OP_piece 0x8 ; CHECK-NEXT: DW_AT_name {{.*}}"outer" ; CHECK: DW_TAG_variable ; CHECK-NEXT: DW_AT_name {{.*}}"i1"