diff --git a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp index c006f3cc2ef..3bf25eb3619 100644 --- a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -287,6 +287,7 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); + unsigned FrameReg = TRI->getFrameRegister(*MF); RegDescribedVarsMap RegVars; DbgValueEntriesMap LiveEntries; for (const auto &MBB : *MF) { @@ -359,7 +360,8 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { auto CurElem = I++; // CurElem can be erased below. if (TRI->isVirtualRegister(CurElem->first) || - ChangingRegs.test(CurElem->first)) + ChangingRegs.test(CurElem->first) || + CurElem->first == FrameReg) clobberRegisterUses(RegVars, CurElem, DbgValues, LiveEntries, MBB.back()); } diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 45ae009b189..37e963ed63b 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -607,36 +607,27 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV, return VariableDie; } - // Check if variable is described by a DBG_VALUE instruction. - if (const MachineInstr *DVInsn = DV.getMInsn()) { - assert(DVInsn->getNumOperands() == 4); - if (DVInsn->getOperand(0).isReg()) { - auto RegOp = DVInsn->getOperand(0); - auto Op1 = DVInsn->getOperand(1); - // If the second operand is an immediate, this is an indirect value. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); - MachineLocation Location(RegOp.getReg(), Op1.isImm()); - addVariableAddress(DV, *VariableDie, Location); - } else if (DVInsn->getOperand(0).isImm()) { - // This variable is described by a single constant. - // Check whether it has a DIExpression. + // Check if variable has a single location description. + if (auto *DVal = DV.getValueLoc()) { + if (DVal->isLocation()) + addVariableAddress(DV, *VariableDie, DVal->getLoc()); + else if (DVal->isInt()) { auto *Expr = DV.getSingleExpression(); if (Expr && Expr->getNumElements()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); // If there is an expression, emit raw unsigned bytes. DwarfExpr.addFragmentOffset(Expr); - DwarfExpr.addUnsignedConstant(DVInsn->getOperand(0).getImm()); + DwarfExpr.addUnsignedConstant(DVal->getInt()); DwarfExpr.addExpression(Expr); addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); } else - addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType()); - } else if (DVInsn->getOperand(0).isFPImm()) - addConstantFPValue(*VariableDie, DVInsn->getOperand(0)); - else if (DVInsn->getOperand(0).isCImm()) - addConstantValue(*VariableDie, DVInsn->getOperand(0).getCImm(), - DV.getType()); - + addConstantValue(*VariableDie, DVal->getInt(), DV.getType()); + } else if (DVal->isConstantFP()) { + addConstantFPValue(*VariableDie, DVal->getConstantFP()); + } else if (DVal->isConstantInt()) { + addConstantValue(*VariableDie, DVal->getConstantInt(), DV.getType()); + } return VariableDie; } diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index f5501a1f0ef..da4c56feeb9 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -244,6 +244,43 @@ const DIType *DbgVariable::getType() const { return Ty; } +/// Get .debug_loc entry for the instruction range starting at MI. +static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { + const DIExpression *Expr = MI->getDebugExpression(); + assert(MI->getNumOperands() == 4); + if (MI->getOperand(0).isReg()) { + auto RegOp = MI->getOperand(0); + auto Op1 = MI->getOperand(1); + // If the second operand is an immediate, this is a + // register-indirect address. + assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); + MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); + return DebugLocEntry::Value(Expr, MLoc); + } + if (MI->getOperand(0).isImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); + if (MI->getOperand(0).isFPImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(0).getFPImm()); + if (MI->getOperand(0).isCImm()) + return DebugLocEntry::Value(Expr, MI->getOperand(0).getCImm()); + + llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); +} + +void DbgVariable::initializeDbgValue(const MachineInstr *DbgValue) { + assert(FrameIndexExprs.empty() && "Already initialized?"); + assert(!ValueLoc.get() && "Already initialized?"); + + assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); + assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && + "Wrong inlined-at"); + + ValueLoc = llvm::make_unique(getDebugLocValue(DbgValue)); + if (auto *E = DbgValue->getDebugExpression()) + if (E->getNumElements()) + FrameIndexExprs.push_back({0, E}); +} + ArrayRef DbgVariable::getFrameIndexExprs() const { if (FrameIndexExprs.size() == 1) return FrameIndexExprs; @@ -263,8 +300,8 @@ ArrayRef DbgVariable::getFrameIndexExprs() const { } void DbgVariable::addMMIEntry(const DbgVariable &V) { - assert(DebugLocListIndex == ~0U && !MInsn && "not an MMI entry"); - assert(V.DebugLocListIndex == ~0U && !V.MInsn && "not an MMI entry"); + assert(DebugLocListIndex == ~0U && !ValueLoc.get() && "not an MMI entry"); + assert(V.DebugLocListIndex == ~0U && !V.ValueLoc.get() && "not an MMI entry"); assert(V.getVariable() == getVariable() && "conflicting variable"); assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location"); @@ -1075,164 +1112,6 @@ void DwarfDebug::collectVariableInfoFromMFTable( } } -// Get .debug_loc entry for the instruction range starting at MI. -static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) { - const DIExpression *Expr = MI->getDebugExpression(); - assert(MI->getNumOperands() == 4); - if (MI->getOperand(0).isReg()) { - auto RegOp = MI->getOperand(0); - auto Op1 = MI->getOperand(1); - // If the second operand is an immediate, this is a - // register-indirect address. - assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset"); - MachineLocation MLoc(RegOp.getReg(), Op1.isImm()); - return DebugLocEntry::Value(Expr, MLoc); - } - if (MI->getOperand(0).isImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm()); - if (MI->getOperand(0).isFPImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getFPImm()); - if (MI->getOperand(0).isCImm()) - return DebugLocEntry::Value(Expr, MI->getOperand(0).getCImm()); - - llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!"); -} - -/// Build the location list for all DBG_VALUEs in the function that -/// 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: -// -// 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 [start, end) [Value...]: -// -// [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) { - using OpenRange = - std::pair; - SmallVector OpenRanges; - - for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) { - const MachineInstr *Instr = EI->getInstr(); - - // 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()); - - // 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 (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)->getInstr()); - assert(EndLabel && "Forgot label after instruction ending a range!"); - - if (EI->isDbgValue()) - LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Instr << "\n"); - - // If this history map entry has a debug value, add that to the list of - // open ranges. - if (EI->isDbgValue()) { - // Do not add undef debug values, as they are redundant information in - // the location list entries. An undef debug results in an empty location - // description. If there are any non-undef fragments then padding pieces - // with empty location descriptions will automatically be inserted, and if - // all fragments are undef then the whole location list entry is - // redundant. - if (!Instr->isUndefDebugValue()) { - 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) { - LLVM_DEBUG(dbgs() << "Omitting location list entry with empty range.\n"); - continue; - } - - 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. - auto CurEntry = DebugLoc.rbegin(); - LLVM_DEBUG({ - dbgs() << CurEntry->getValues().size() << " Values:\n"; - for (auto &Value : CurEntry->getValues()) - Value.dump(); - dbgs() << "-----\n"; - }); - - auto PrevEntry = std::next(CurEntry); - if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) - DebugLoc.pop_back(); - } -} - -DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, - LexicalScope &Scope, - const DINode *Node, - const DILocation *Location, - const MCSymbol *Sym) { - ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode()); - if (isa(Node)) { - ConcreteEntities.push_back( - llvm::make_unique(cast(Node), - Location)); - InfoHolder.addScopeVariable(&Scope, - cast(ConcreteEntities.back().get())); - } else if (isa(Node)) { - ConcreteEntities.push_back( - llvm::make_unique(cast(Node), - Location, Sym)); - InfoHolder.addScopeLabel(&Scope, - cast(ConcreteEntities.back().get())); - } - return ConcreteEntities.back().get(); -} - /// Determine whether a *singular* DBG_VALUE is valid for the entirety of its /// enclosing lexical scope. The check ensures there are no other instructions /// in the same lexical scope preceding the DBG_VALUE and that its range is @@ -1291,6 +1170,161 @@ static bool validThroughout(LexicalScopes &LScopes, return false; } +/// Build the location list for all DBG_VALUEs in the function that +/// describe the same variable. The resulting DebugLocEntries will have +/// strict monotonically increasing begin addresses and will never +/// overlap. If the resulting list has only one entry that is valid +/// throughout variable's scope return true. +// +// 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: +// +// 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 [start, end) [Value...]: +// +// [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)] +bool DwarfDebug::buildLocationList(SmallVectorImpl &DebugLoc, + const DbgValueHistoryMap::Entries &Entries) { + using OpenRange = + std::pair; + SmallVector OpenRanges; + bool isSafeForSingleLocation = true; + const MachineInstr *StartDebugMI = nullptr; + const MachineInstr *EndMI = nullptr; + + for (auto EB = Entries.begin(), EI = EB, EE = Entries.end(); EI != EE; ++EI) { + const MachineInstr *Instr = EI->getInstr(); + + // 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()); + + // 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 (std::next(EI) == Entries.end()) { + EndLabel = Asm->getFunctionEnd(); + if (EI->isClobber()) + EndMI = EI->getInstr(); + } + else if (std::next(EI)->isClobber()) + EndLabel = getLabelAfterInsn(std::next(EI)->getInstr()); + else + EndLabel = getLabelBeforeInsn(std::next(EI)->getInstr()); + assert(EndLabel && "Forgot label after instruction ending a range!"); + + if (EI->isDbgValue()) + LLVM_DEBUG(dbgs() << "DotDebugLoc: " << *Instr << "\n"); + + // If this history map entry has a debug value, add that to the list of + // open ranges and check if its location is valid for a single value + // location. + if (EI->isDbgValue()) { + // Do not add undef debug values, as they are redundant information in + // the location list entries. An undef debug results in an empty location + // description. If there are any non-undef fragments then padding pieces + // with empty location descriptions will automatically be inserted, and if + // all fragments are undef then the whole location list entry is + // redundant. + if (!Instr->isUndefDebugValue()) { + auto Value = getDebugLocValue(Instr); + OpenRanges.emplace_back(EI->getEndIndex(), Value); + + // TODO: Add support for single value fragment locations. + if (Instr->getDebugExpression()->isFragment()) + isSafeForSingleLocation = false; + + if (!StartDebugMI) + StartDebugMI = Instr; + } else { + isSafeForSingleLocation = false; + } + } + + // 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) { + LLVM_DEBUG(dbgs() << "Omitting location list entry with empty range.\n"); + continue; + } + + 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. + auto CurEntry = DebugLoc.rbegin(); + LLVM_DEBUG({ + dbgs() << CurEntry->getValues().size() << " Values:\n"; + for (auto &Value : CurEntry->getValues()) + Value.dump(); + dbgs() << "-----\n"; + }); + + auto PrevEntry = std::next(CurEntry); + if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) + DebugLoc.pop_back(); + } + + return DebugLoc.size() == 1 && isSafeForSingleLocation && + validThroughout(LScopes, StartDebugMI, EndMI); +} + +DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU, + LexicalScope &Scope, + const DINode *Node, + const DILocation *Location, + const MCSymbol *Sym) { + ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode()); + if (isa(Node)) { + ConcreteEntities.push_back( + llvm::make_unique(cast(Node), + Location)); + InfoHolder.addScopeVariable(&Scope, + cast(ConcreteEntities.back().get())); + } else if (isa(Node)) { + ConcreteEntities.push_back( + llvm::make_unique(cast(Node), + Location, Sym)); + InfoHolder.addScopeLabel(&Scope, + cast(ConcreteEntities.back().get())); + } + return ConcreteEntities.back().get(); +} + // Find variables for each lexical scope. void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP, @@ -1328,9 +1362,10 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Check if there is a single DBG_VALUE, valid throughout the var's scope. // If the history map contains a single debug value, there may be an // additional entry which clobbers the debug value. + size_t HistSize = HistoryMapEntries.size(); bool SingleValueWithClobber = - HistoryMapEntries.size() == 2 && HistoryMapEntries[1].isClobber(); - if (HistoryMapEntries.size() == 1 || SingleValueWithClobber) { + HistSize == 2 && HistoryMapEntries[1].isClobber(); + if (HistSize == 1 || SingleValueWithClobber) { const auto *End = SingleValueWithClobber ? HistoryMapEntries[1].getInstr() : nullptr; if (validThroughout(LScopes, MInsn, End)) { @@ -1348,7 +1383,15 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Build the location list for this variable. SmallVector Entries; - buildLocationList(Entries, HistoryMapEntries); + bool isValidSingleLocation = buildLocationList(Entries, HistoryMapEntries); + + // Check whether buildLocationList managed to merge all locations to one + // that is valid throughout the variable's scope. If so, produce single + // value location. + if (isValidSingleLocation) { + RegVar->initializeDbgValue(Entries[0].getValues()[0]); + continue; + } // If the variable has a DIBasicType, extract it. Basic types cannot have // unique identifiers, so don't bother resolving the type with the @@ -1900,8 +1943,8 @@ void DwarfDebug::emitDebugStr() { StringOffsetsSection, /* UseRelativeOffsets = */ true); } -void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const - DebugLocStream::Entry &Entry, +void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, + const DebugLocStream::Entry &Entry, const DwarfCompileUnit *CU) { auto &&Comments = DebugLocs.getComments(Entry); auto Comment = Comments.begin(); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 53e2baebbd0..2dfdda67d6b 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -15,6 +15,7 @@ #include "AddressPool.h" #include "DebugLocStream.h" +#include "DebugLocEntry.h" #include "DwarfFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -110,12 +111,14 @@ public: /// /// Variables can be created from \c DBG_VALUE instructions. Those whose /// location changes over time use \a DebugLocListIndex, while those with a -/// single instruction use \a MInsn and (optionally) a single entry of \a Expr. +/// single location use \a ValueLoc and (optionally) a single entry of \a Expr. /// /// Variables that have been optimized out use none of these fields. class DbgVariable : public DbgEntity { - unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs. - const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction. + /// Offset in DebugLocs. + unsigned DebugLocListIndex = ~0u; + /// Single value location description. + std::unique_ptr ValueLoc = nullptr; struct FrameIndexExpr { int FI; @@ -135,7 +138,7 @@ public: /// Initialize from the MMI table. void initializeMMI(const DIExpression *E, int FI) { assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!MInsn && "Already initialized?"); + assert(!ValueLoc.get() && "Already initialized?"); assert((!E || E->isValid()) && "Expected valid expression"); assert(FI != std::numeric_limits::max() && "Expected valid index"); @@ -143,35 +146,35 @@ public: FrameIndexExprs.push_back({FI, E}); } - /// Initialize from a DBG_VALUE instruction. - void initializeDbgValue(const MachineInstr *DbgValue) { + // Initialize variable's location. + void initializeDbgValue(DebugLocEntry::Value Value) { assert(FrameIndexExprs.empty() && "Already initialized?"); - assert(!MInsn && "Already initialized?"); + assert(!ValueLoc && "Already initialized?"); + assert(!Value.getExpression()->isFragment() && "Fragments not supported."); - assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable"); - assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() && - "Wrong inlined-at"); - - MInsn = DbgValue; - if (auto *E = DbgValue->getDebugExpression()) + ValueLoc = llvm::make_unique(Value); + if (auto *E = ValueLoc->getExpression()) if (E->getNumElements()) FrameIndexExprs.push_back({0, E}); } + /// Initialize from a DBG_VALUE instruction. + void initializeDbgValue(const MachineInstr *DbgValue); + // Accessors. const DILocalVariable *getVariable() const { return cast(getEntity()); } const DIExpression *getSingleExpression() const { - assert(MInsn && FrameIndexExprs.size() <= 1); + assert(ValueLoc.get() && FrameIndexExprs.size() <= 1); return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr; } void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; } unsigned getDebugLocListIndex() const { return DebugLocListIndex; } StringRef getName() const { return getVariable()->getName(); } - const MachineInstr *getMInsn() const { return MInsn; } + const DebugLocEntry::Value *getValueLoc() const { return ValueLoc.get(); } /// Get the FI entries, sorted by fragment offset. ArrayRef getFrameIndexExprs() const; bool hasFrameIndexExprs() const { return !FrameIndexExprs.empty(); } @@ -204,7 +207,7 @@ public: } bool hasComplexAddress() const { - assert(MInsn && "Expected DBG_VALUE, not MMI variable"); + assert(ValueLoc.get() && "Expected DBG_VALUE, not MMI variable"); assert((FrameIndexExprs.empty() || (FrameIndexExprs.size() == 1 && FrameIndexExprs[0].Expr->getNumElements())) && @@ -547,8 +550,10 @@ class DwarfDebug : public DebugHandlerBase { DenseSet &ProcessedVars); /// Build the location list for all DBG_VALUEs in the - /// function that describe the same variable. - void buildLocationList(SmallVectorImpl &DebugLoc, + /// function that describe the same variable. If the resulting + /// list has only one entry that is valid for entire variable's + /// scope return true. + bool buildLocationList(SmallVectorImpl &DebugLoc, const DbgValueHistoryMap::Entries &Entries); /// Collect variable information from the side table maintained by MF. diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index d9e680846b3..b89162cdab0 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -531,6 +531,10 @@ void DwarfUnit::addConstantValue(DIE &Die, const MachineOperand &MO, addConstantValue(Die, isUnsignedDIType(DD, Ty), MO.getImm()); } +void DwarfUnit::addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty) { + addConstantValue(Die, isUnsignedDIType(DD, Ty), Val); +} + void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) { // FIXME: This is a bit conservative/simple - it emits negative values always // sign extended to 64 bits rather than minimizing the number of bytes. diff --git a/lib/CodeGen/AsmPrinter/DwarfUnit.h b/lib/CodeGen/AsmPrinter/DwarfUnit.h index 7a17b424199..56c934a35ae 100644 --- a/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -198,6 +198,7 @@ public: void addConstantValue(DIE &Die, const ConstantInt *CI, const DIType *Ty); void addConstantValue(DIE &Die, const APInt &Val, const DIType *Ty); void addConstantValue(DIE &Die, const APInt &Val, bool Unsigned); + void addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty); void addConstantValue(DIE &Die, bool Unsigned, uint64_t Val); /// Add constant value entry in variable DIE. diff --git a/test/DebugInfo/MIR/X86/dbg-stack-value-range.mir b/test/DebugInfo/MIR/X86/dbg-stack-value-range.mir new file mode 100644 index 00000000000..3863f43b374 --- /dev/null +++ b/test/DebugInfo/MIR/X86/dbg-stack-value-range.mir @@ -0,0 +1,184 @@ +# RUN: llc -start-before=livedebugvalues %s -filetype=asm -o -| FileCheck %s +# +# DbgEntityHistoryCalculator should close variable's range at the end of +# the basic block when variable is referenced through non-changing frame +# pointer register. Having BB1 that branches to BB2 and BB3, where +# BB2 falls through to BB3, variable can have different locations at BB1 and BB2. +# Since input locations at BB3 for same variable are different LiveDebugValues +# wont generate DBG_VALUE for BB3. If last variable location at BB2 is +# non-changing register, DbgEntityHistoryCalculator will extend range of +# DBG_VALUE from BB2 to whole BB3 and thus produce incorrect range for +# case when we took branch BB3 from BB1. +# +# Verifies that "local1" stack location is ended at the end of the block (.Ltmp6). +# +# CHECK: .Ltmp4: +# CHECK-NEXT: #DEBUG_VALUE: foo:local1 <- [DW_OP_constu 4, DW_OP_minus, DW_OP_deref] $rbp +# CHECK: jmp .LBB0_2 +# CHECK-NEXT: .Ltmp6: +# CHECK: .Lfunc_end0: +# +# CHECK: .Linfo_string7: +# CHECK-NEXT: .asciz "local1" +# +# CHECK: .Ldebug_loc2: +# CHECK-NEXT: .quad .Ltmp1-.Lfunc_begin0 +# CHECK-NEXT: .quad .Ltmp4-.Lfunc_begin0 +# CHECK-NEXT: .short 1 # Loc expr size +# CHECK-NEXT: .byte 94 # super-register DW_OP_reg14 +# CHECK-NEXT: .quad .Ltmp4-.Lfunc_begin0 +# CHECK-NEXT: .quad .Ltmp6-.Lfunc_begin0 +# CHECK-NEXT: .short 2 # Loc expr size +# CHECK-NEXT: .byte 118 # DW_OP_breg6 +# CHECK-NEXT: .byte 124 # -4 +# +# CHECK: .long .Ldebug_loc2 # DW_AT_location +# CHECK-NEXT: .long .Linfo_string7 # DW_AT_name + + +--- | + ; ModuleID = 'dbg-stack-value-range.ll' + source_filename = "dbg-stack-value-range.c" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + ; Function Attrs: nounwind uwtable + define dso_local i32 @foo(i32 %X) local_unnamed_addr #0 !dbg !7 { + entry: + %local1 = alloca i32, align 4 + call void @llvm.dbg.value(metadata i32 %X, metadata !12, metadata !DIExpression()), !dbg !15 + %0 = bitcast i32* %local1 to i8*, !dbg !15 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0), !dbg !15 + call void @llvm.dbg.value(metadata i32 5, metadata !14, metadata !DIExpression()), !dbg !15 + %call = tail call i32 (...) @check(), !dbg !15 + %tobool = icmp eq i32 %call, 0, !dbg !15 + br i1 %tobool, label %if.else, label %if.then, !dbg !15 + + if.then: ; preds = %entry + call void @llvm.dbg.value(metadata i32 4, metadata !13, metadata !DIExpression()), !dbg !15 + store i32 4, i32* %local1, align 4, !dbg !15, !tbaa !16 + call void @llvm.dbg.value(metadata i32* %local1, metadata !13, metadata !DIExpression(DW_OP_deref)), !dbg !15 + %call1 = call i32 @init(i32* nonnull %local1), !dbg !15 + call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15 + br label %if.end, !dbg !15 + + if.else: ; preds = %entry + call void @llvm.dbg.value(metadata i32 5, metadata !13, metadata !DIExpression()), !dbg !15 + store i32 5, i32* %local1, align 4, !dbg !15, !tbaa !16 + br label %if.end + + if.end: ; preds = %if.else, %if.then + %1 = bitcast i32* %local1 to i8*, !dbg !15 + call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15 + %call2 = call i32 (...) @init2(), !dbg !15 + call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15 + %2 = load i32, i32* %local1, align 4, !dbg !15, !tbaa !16 + call void @llvm.dbg.value(metadata i32 %2, metadata !13, metadata !DIExpression()), !dbg !15 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %1), !dbg !15 + ret i32 %2, !dbg !15 + } + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) + + declare dso_local i32 @check(...) local_unnamed_addr + + declare dso_local i32 @init(i32*) local_unnamed_addr + + declare dso_local i32 @init2(...) local_unnamed_addr + + ; Function Attrs: argmemonly nounwind + declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) + + attributes #0 = { nounwind uwtable "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4, !5} + !llvm.ident = !{!6} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) + !1 = !DIFile(filename: "dbg-stack-value-range.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{i32 1, !"wchar_size", i32 4} + !6 = !{!"clang version 9.0.0"} + !7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 11, type: !8, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) + !8 = !DISubroutineType(types: !9) + !9 = !{!10, !10} + !10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !11 = !{!12, !13, !14} + !12 = !DILocalVariable(name: "X", arg: 1, scope: !7, file: !1, line: 11, type: !10) + !13 = !DILocalVariable(name: "local1", scope: !7, file: !1, line: 12, type: !10) + !14 = !DILocalVariable(name: "local2", scope: !7, file: !1, line: 12, type: !10) + !15 = !DILocation(line: 11, column: 13, scope: !7) + !16 = !{!17, !17, i64 0} + !17 = !{!"int", !18, i64 0} + !18 = !{!"omnipotent char", !19, i64 0} + !19 = !{!"Simple C/C++ TBAA"} + +... +--- +name: foo +alignment: 4 +frameInfo: + stackSize: 24 + offsetAdjustment: -24 + maxAlignment: 4 + adjustsStack: true + hasCalls: true +fixedStack: + - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: 0, + callee-saved-register: '$r14d', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } +stack: + - { id: 0, name: local1, type: default, offset: -20, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.0.entry: + successors: %bb.3(0x30000000), %bb.1(0x50000000) + + DBG_VALUE $edi, $noreg, !12, !DIExpression(), debug-location !15 + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + $rbp = frame-setup MOV64rr $rsp + CFI_INSTRUCTION def_cfa_register $rbp + $rsp = frame-setup SUB64ri8 $rsp, 16, implicit-def dead $eflags + DBG_VALUE 5, $noreg, !14, !DIExpression(), debug-location !15 + $r14d = MOV32ri 4, implicit-def $r14 + DBG_VALUE $r14d, $noreg, !13, !DIExpression(), debug-location !15 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !15 + CALL64pcrel32 @check, csr_64, implicit $rsp, implicit $ssp, implicit $al, implicit-def $rsp, implicit-def $ssp, implicit-def $eax, debug-location !15 + TEST32rr killed renamable $eax, renamable $eax, implicit-def $eflags, debug-location !15 + JCC_1 %bb.3, 4, implicit killed $eflags, debug-location !15 + + bb.1.if.then: + successors: %bb.3(0x80000000) + + MOV32mr $rbp, 1, $noreg, -4, $noreg, $r14d, debug-location !15 :: (store 4 into %ir.local1, !tbaa !16) + DBG_VALUE $rbp, $noreg, !13, !DIExpression(DW_OP_constu, 4, DW_OP_minus, DW_OP_deref), debug-location !15 + renamable $rdi = LEA64r $rbp, 1, $noreg, -4, $noreg + CALL64pcrel32 @init, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eax, debug-location !15 + DBG_VALUE $noreg, $noreg, !14, !DIExpression(), debug-location !15 + JMP_1 %bb.3 + + bb.3.if.end: + DBG_VALUE $noreg, $noreg, !14, !DIExpression(), debug-location !15 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $al, debug-location !15 + CALL64pcrel32 @init2, csr_64, implicit $rsp, implicit $ssp, implicit $al, implicit-def $rsp, implicit-def $ssp, implicit-def dead $eax, debug-location !15 + DBG_VALUE $noreg, $noreg, !14, !DIExpression(), debug-location !15 + renamable $eax = MOV32rm $rbp, 1, $noreg, -4, $noreg, debug-location !15 :: (dereferenceable load 4 from %ir.local1, !tbaa !16) + $rsp = frame-destroy ADD64ri8 $rsp, 16, implicit-def dead $eflags, debug-location !15 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !15 + CFI_INSTRUCTION def_cfa $rsp, 8, debug-location !15 + RETQ $eax, debug-location !15 + +... diff --git a/test/DebugInfo/X86/fission-ranges.ll b/test/DebugInfo/X86/fission-ranges.ll index e4347736195..fa911cd60f6 100644 --- a/test/DebugInfo/X86/fission-ranges.ll +++ b/test/DebugInfo/X86/fission-ranges.ll @@ -161,7 +161,7 @@ for.inc10: ; preds = %for.body9 for.inc13: ; preds = %for.inc10 %inc14 = add i32 %d.06, 1, !dbg !37 - tail call void @llvm.dbg.value(metadata i32 %inc14, metadata !16, metadata !DIExpression()), !dbg !37 + tail call void @llvm.dbg.value(metadata i32 %inc14, metadata !16, metadata !DIExpression()), !dbg !42 %exitcond12 = icmp eq i32 %inc14, 30, !dbg !37 br i1 %exitcond12, label %for.inc16, label %for.cond4.preheader, !dbg !37