From 1be3eccecbd2fa50ed9008ffee01f6351df5d8f7 Mon Sep 17 00:00:00 2001 From: Devang Patel Date: Wed, 15 Apr 2009 00:10:26 +0000 Subject: [PATCH] Construct and emit DW_TAG_inlined_subroutine DIEs for inlined subroutine scopes (only in FastISel mode). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@69116 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/DwarfWriter.h | 23 ++- lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 +- lib/CodeGen/AsmPrinter/DwarfWriter.cpp | 264 ++++++++++++++++++------- lib/CodeGen/SelectionDAG/FastISel.cpp | 42 ++-- 4 files changed, 233 insertions(+), 98 deletions(-) diff --git a/include/llvm/CodeGen/DwarfWriter.h b/include/llvm/CodeGen/DwarfWriter.h index 9b9e21cb3db..4b35b288c96 100644 --- a/include/llvm/CodeGen/DwarfWriter.h +++ b/include/llvm/CodeGen/DwarfWriter.h @@ -29,11 +29,15 @@ class DwarfDebug; class DwarfException; class MachineModuleInfo; class MachineFunction; +class MachineInstr; class Value; class Module; class GlobalVariable; class TargetAsmInfo; class raw_ostream; +class Instruction; +class DISubprogram; +class DIVariable; //===----------------------------------------------------------------------===// // DwarfWriter - Emits Dwarf debug and exception handling directives. @@ -94,9 +98,6 @@ public: /// RecordRegionStart - Indicate the start of a region. unsigned RecordRegionStart(GlobalVariable *V); - /// RecordRegionStart - Indicate the start of a region. - unsigned RecordRegionStart(GlobalVariable *V, unsigned ID); - /// RecordRegionEnd - Indicate the end of a region. unsigned RecordRegionEnd(GlobalVariable *V); @@ -105,15 +106,23 @@ public: /// RecordVariable - Indicate the declaration of a local variable. /// - void RecordVariable(GlobalVariable *GV, unsigned FrameIndex); + void RecordVariable(GlobalVariable *GV, unsigned FrameIndex, + const MachineInstr *MI); /// ShouldEmitDwarfDebug - Returns true if Dwarf debugging declarations should /// be emitted. bool ShouldEmitDwarfDebug() const; - //// RecordInlineInfo - Global variable GV is inlined at the location marked - //// by LabelID label. - void RecordInlineInfo(GlobalVariable *GV, unsigned LabelID); + //// RecordInlinedFnStart - Indicate the start of a inlined function. + void RecordInlinedFnStart(Instruction *I, DISubprogram &SP, unsigned LabelID, + unsigned Src, unsigned Line, unsigned Col); + + /// RecordInlinedFnEnd - Indicate the end of inlined subroutine. + unsigned RecordInlinedFnEnd(DISubprogram &SP); + + /// RecordVariableScope - Record scope for the variable declared by + /// DeclareMI. DeclareMI must describe TargetInstrInfo::DECLARE. + void RecordVariableScope(DIVariable &DV, const MachineInstr *DeclareMI); }; diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 0979ced89a3..f1a45fd7eeb 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1532,7 +1532,7 @@ void AsmPrinter::printLabel(unsigned Id) const { void AsmPrinter::printDeclare(const MachineInstr *MI) const { unsigned FI = MI->getOperand(0).getIndex(); GlobalValue *GV = MI->getOperand(1).getGlobal(); - DW->RecordVariable(cast(GV), FI); + DW->RecordVariable(cast(GV), FI, MI); } /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM diff --git a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp index c4191e523ce..597f925f51c 100644 --- a/lib/CodeGen/AsmPrinter/DwarfWriter.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfWriter.cpp @@ -1140,7 +1140,7 @@ public: DbgScope(DbgScope *P, DIDescriptor D) : Parent(P), Desc(D), StartLabelID(0), EndLabelID(0), Scopes(), Variables() {} - ~DbgScope() { + virtual ~DbgScope() { for (unsigned i = 0, N = Scopes.size(); i < N; ++i) delete Scopes[i]; for (unsigned j = 0, M = Variables.size(); j < M; ++j) delete Variables[j]; } @@ -1162,6 +1162,32 @@ public: /// AddVariable - Add a variable to the scope. /// void AddVariable(DbgVariable *V) { Variables.push_back(V); } + + virtual bool isInlinedSubroutine() { return false; } + virtual unsigned getLine() { assert ( 0 && "Unexpected scope!"); } + virtual unsigned getColumn() { assert ( 0 && "Unexpected scope!"); } + virtual unsigned getFile() { assert ( 0 && "Unexpected scope!"); } +}; + + +//===----------------------------------------------------------------------===// +/// DbgInlinedSubroutineScope - This class is used to track inlined subroutine +/// scope information. +/// +class DbgInlinedSubroutineScope : public DbgScope { + unsigned Src; + unsigned Line; + unsigned Col; +public: + DbgInlinedSubroutineScope(DbgScope *P, DIDescriptor D, + unsigned S, unsigned L, unsigned C) + : DbgScope(P, D), Src(S), Line(L), Col(C) + {} + + unsigned getLine() { return Line; } + unsigned getColumn() { return Col; } + unsigned getFile() { return Src; } + bool isInlinedSubroutine() { return true; } }; //===----------------------------------------------------------------------===// @@ -1252,10 +1278,17 @@ class DwarfDebug : public Dwarf { /// DbgScopeMap - Tracks the scopes in the current function. DenseMap DbgScopeMap; + /// DbgInlinedScopeMap - Tracks inlined scopes in the current function. + DenseMap > DbgInlinedScopeMap; + /// InlineInfo - Keep track of inlined functions and their location. /// This information is used to populate debug_inlined section. DenseMap > InlineInfo; + /// InlinedVariableScopes - Scopes information for the inlined subroutine + /// variables. + DenseMap InlinedVariableScopes; + /// DebugTimer - Timer for the Dwarf debug writer. Timer *DebugTimer; @@ -1469,7 +1502,7 @@ private: /// AddDelta - Add a label delta attribute data and value. /// void AddDelta(DIE *Die, unsigned Attribute, unsigned Form, - const DWLabel &Hi, const DWLabel &Lo) { + const DWLabel &Hi, const DWLabel &Lo) { FoldingSetNodeID ID; DIEDelta::Profile(ID, Hi, Lo); void *Where; @@ -1550,7 +1583,7 @@ private: /// AddAddress - Add an address attribute to a die based on the location /// provided. void AddAddress(DIE *Die, unsigned Attribute, - const MachineLocation &Location) { + const MachineLocation &Location) { unsigned Reg = RI->getDwarfRegNum(Location.getReg(), false); DIEBlock *Block = new DIEBlock(); @@ -1933,6 +1966,10 @@ private: if (!SP.isLocalToUnit()) AddUInt(SPDie, DW_AT_external, DW_FORM_flag, 1); + + // DW_TAG_inlined_subroutine may refer to this DIE. + DIE *&Slot = DW_Unit->getDieMapSlotFor(SP.getGV()); + Slot = SPDie; return SPDie; } @@ -1987,33 +2024,39 @@ private: DbgScope *&Slot = DbgScopeMap[V]; if (Slot) return Slot; - // FIXME - breaks down when the context is an inlined function. - DIDescriptor ParentDesc; - DIDescriptor Desc(V); - - if (Desc.getTag() == dwarf::DW_TAG_lexical_block) { - DIBlock Block(V); - ParentDesc = Block.getContext(); + DbgScope *Parent = NULL; + DIBlock Block(V); + if (!Block.isNull()) { + DIDescriptor ParentDesc = Block.getContext(); + Parent = + ParentDesc.isNull() ? NULL : getOrCreateScope(ParentDesc.getGV()); } + Slot = new DbgScope(Parent, DIDescriptor(V)); - DbgScope *Parent = ParentDesc.isNull() ? - NULL : getOrCreateScope(ParentDesc.getGV()); - Slot = new DbgScope(Parent, Desc); - - if (Parent) { + if (Parent) Parent->AddScope(Slot); - } else if (RootDbgScope) { - // FIXME - Add inlined function scopes to the root so we can delete them - // later. Long term, handle inlined functions properly. - RootDbgScope->AddScope(Slot); - } else { + else // First function is top level function. RootDbgScope = Slot; - } return Slot; } + /// createInlinedSubroutineScope - Returns the scope associated with the + /// inlined subroutine. + /// + DbgScope *createInlinedSubroutineScope(DISubprogram SP, unsigned Src, + unsigned Line, unsigned Col) { + DbgScope *Scope = + new DbgInlinedSubroutineScope(NULL, SP, Src, Line, Col); + + // FIXME - Add inlined function scopes to the root so we can delete them + // later. + assert (RootDbgScope && "Function scope info missing!"); + RootDbgScope->AddScope(Scope); + return Scope; + } + /// ConstructDbgScope - Construct the components of a scope. /// void ConstructDbgScope(DbgScope *ParentScope, @@ -2035,12 +2078,11 @@ private: unsigned StartID = MMI->MappedLabel(Scope->getStartLabelID()); unsigned EndID = MMI->MappedLabel(Scope->getEndLabelID()); - // Ignore empty scopes. + // Ignore empty scopes. + // Do not ignore inlined scope even if it does not have any + // variables or scopes. if (StartID == EndID && StartID != 0) continue; - - // Do not ignore inlined scope even if it is empty. Inlined scope - // does not have any parent. - if (Scope->getParent() + if (!Scope->isInlinedSubroutine() && Scope->getScopes().empty() && Scope->getVariables().empty()) continue; @@ -2048,27 +2090,37 @@ private: // Just add stuff to the parent scope. ConstructDbgScope(Scope, ParentStartID, ParentEndID, ParentDie, Unit); } else { - DIE *ScopeDie = new DIE(DW_TAG_lexical_block); - - // Add the scope bounds. - if (StartID) { - AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, - DWLabel("label", StartID)); - } else { - AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, - DWLabel("func_begin", SubprogramCount)); + DIE *ScopeDie = NULL; + if (MainCU && TAI->doesDwarfUsesInlineInfoSection()) { + ScopeDie = new DIE(DW_TAG_inlined_subroutine); + DIE *Origin = MainCU->getDieMapSlotFor(Scope->getDesc().getGV()); + AddDIEntry(ScopeDie, DW_AT_abstract_origin, DW_FORM_ref4, Origin); + AddUInt(ScopeDie, DW_AT_call_file, 0, Scope->getFile()); + AddUInt(ScopeDie, DW_AT_call_line, 0, Scope->getLine()); + AddUInt(ScopeDie, DW_AT_call_column, 0, Scope->getColumn()); } - if (EndID) { - AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, - DWLabel("label", EndID)); - } else { - AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, - DWLabel("func_end", SubprogramCount)); - } - - // Add the scope contents. - ConstructDbgScope(Scope, StartID, EndID, ScopeDie, Unit); - ParentDie->AddChild(ScopeDie); + else + ScopeDie = new DIE(DW_TAG_lexical_block); + + // Add the scope bounds. + if (StartID) { + AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, + DWLabel("label", StartID)); + } else { + AddLabel(ScopeDie, DW_AT_low_pc, DW_FORM_addr, + DWLabel("func_begin", SubprogramCount)); + } + if (EndID) { + AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, + DWLabel("label", EndID)); + } else { + AddLabel(ScopeDie, DW_AT_high_pc, DW_FORM_addr, + DWLabel("func_end", SubprogramCount)); + } + + // Add the scope contents. + ConstructDbgScope(Scope, StartID, EndID, ScopeDie, Unit); + ParentDie->AddChild(ScopeDie); } } } @@ -3286,6 +3338,8 @@ public: if (RootDbgScope) { delete RootDbgScope; DbgScopeMap.clear(); + DbgInlinedScopeMap.clear(); + InlinedVariableScopes.clear(); RootDbgScope = NULL; } @@ -3423,20 +3477,6 @@ public: return ID; } - /// RecordRegionStart - Indicate the start of a region. - unsigned RecordRegionStart(GlobalVariable *V, unsigned ID) { - if (TimePassesIsEnabled) - DebugTimer->startTimer(); - - DbgScope *Scope = getOrCreateScope(V); - if (!Scope->getStartLabelID()) Scope->setStartLabelID(ID); - - if (TimePassesIsEnabled) - DebugTimer->stopTimer(); - - return ID; - } - /// RecordRegionEnd - Indicate the end of a region. unsigned RecordRegionEnd(GlobalVariable *V) { if (TimePassesIsEnabled) @@ -3453,7 +3493,8 @@ public: } /// RecordVariable - Indicate the declaration of a local variable. - void RecordVariable(GlobalVariable *GV, unsigned FrameIndex) { + void RecordVariable(GlobalVariable *GV, unsigned FrameIndex, + const MachineInstr *MI) { if (TimePassesIsEnabled) DebugTimer->startTimer(); @@ -3465,9 +3506,16 @@ public: DIGlobalVariable DG(GV); Scope = getOrCreateScope(DG.getContext().getGV()); } else { + DenseMap::iterator + SI = InlinedVariableScopes.find(MI); + if (SI != InlinedVariableScopes.end()) { + // or GV is an inlined local variable. + Scope = SI->second; + } else { // or GV is a local variable. - DIVariable DV(GV); - Scope = getOrCreateScope(DV.getContext().getGV()); + DIVariable DV(GV); + Scope = getOrCreateScope(DV.getContext().getGV()); + } } assert(Scope && "Unable to find variable' scope"); @@ -3478,10 +3526,28 @@ public: DebugTimer->stopTimer(); } - //// RecordInlineInfo - Global variable GV is inlined at the location marked - //// by LabelID label. - void RecordInlineInfo(GlobalVariable *GV, unsigned LabelID) { + //// RecordInlinedFnStart - Indicate the start of inlined subroutine. + void RecordInlinedFnStart(Instruction *FSI, DISubprogram &SP, unsigned LabelID, + unsigned Src, unsigned Line, unsigned Col) { + if (!TAI->doesDwarfUsesInlineInfoSection()) + return; + + DbgScope *Scope = createInlinedSubroutineScope(SP, Src, Line, Col); + Scope->setStartLabelID(LabelID); MMI->RecordUsedDbgLabel(LabelID); + GlobalVariable *GV = SP.getGV(); + + DenseMap >::iterator + SI = DbgInlinedScopeMap.find(GV); + if (SI == DbgInlinedScopeMap.end()) { + SmallVector Scopes; + Scopes.push_back(Scope); + DbgInlinedScopeMap[GV] = Scopes; + } else { + SmallVector &Scopes = SI->second; + Scopes.push_back(Scope); + } + DenseMap >::iterator I = InlineInfo.find(GV); if (I == InlineInfo.end()) { @@ -3494,6 +3560,43 @@ public: SmallVector &Labels = I->second; Labels.push_back(LabelID); } + + /// RecordInlinedFnEnd - Indicate the end of inlined subroutine. + unsigned RecordInlinedFnEnd(DISubprogram &SP) { + if (!TAI->doesDwarfUsesInlineInfoSection()) + return 0; + + GlobalVariable *GV = SP.getGV(); + DenseMap >::iterator + I = DbgInlinedScopeMap.find(GV); + if (I == DbgInlinedScopeMap.end()) + return 0; + + SmallVector &Scopes = I->second; + DbgScope *Scope = Scopes.back(); Scopes.pop_back(); + unsigned ID = MMI->NextLabelID(); + MMI->RecordUsedDbgLabel(ID); + Scope->setEndLabelID(ID); + return ID; + } + + /// RecordVariableScope - Record scope for the variable declared by + /// DeclareMI. DeclareMI must describe TargetInstrInfo::DECLARE. + /// Record scopes for only inlined subroutine variables. Other + /// variables' scopes are determined during RecordVariable(). + void RecordVariableScope(DIVariable &DV, const MachineInstr *DeclareMI) { + DISubprogram SP(DV.getContext().getGV()); + if (SP.isNull()) + return; + DenseMap >::iterator + I = DbgInlinedScopeMap.find(SP.getGV()); + if (I == DbgInlinedScopeMap.end()) + return; + + SmallVector &Scopes = I->second; + InlinedVariableScopes[DeclareMI] = Scopes.back(); + } + }; //===----------------------------------------------------------------------===// @@ -4652,11 +4755,6 @@ unsigned DwarfWriter::RecordRegionStart(GlobalVariable *V) { return DD->RecordRegionStart(V); } -/// RecordRegionStart - Indicate the start of a region. -unsigned DwarfWriter::RecordRegionStart(GlobalVariable *V, unsigned ID) { - return DD->RecordRegionStart(V, ID); -} - /// RecordRegionEnd - Indicate the end of a region. unsigned DwarfWriter::RecordRegionEnd(GlobalVariable *V) { return DD->RecordRegionEnd(V); @@ -4669,8 +4767,9 @@ unsigned DwarfWriter::getRecordSourceLineCount() { /// RecordVariable - Indicate the declaration of a local variable. /// -void DwarfWriter::RecordVariable(GlobalVariable *GV, unsigned FrameIndex) { - DD->RecordVariable(GV, FrameIndex); +void DwarfWriter::RecordVariable(GlobalVariable *GV, unsigned FrameIndex, + const MachineInstr *MI) { + DD->RecordVariable(GV, FrameIndex, MI); } /// ShouldEmitDwarfDebug - Returns true if Dwarf debugging declarations should @@ -4679,9 +4778,22 @@ bool DwarfWriter::ShouldEmitDwarfDebug() const { return DD->ShouldEmitDwarfDebug(); } -//// RecordInlineInfo - Global variable GV is inlined at the location marked +//// RecordInlinedFnStart - Global variable GV is inlined at the location marked //// by LabelID label. -void DwarfWriter::RecordInlineInfo(GlobalVariable *GV, unsigned LabelID) { - DD->RecordInlineInfo(GV, LabelID); +void DwarfWriter::RecordInlinedFnStart(Instruction *I, DISubprogram &SP, + unsigned LabelID, unsigned Src, + unsigned Line, unsigned Col) { + DD->RecordInlinedFnStart(I, SP, LabelID, Src, Line, Col); } +/// RecordInlinedFnEnd - Indicate the end of inlined subroutine. +unsigned DwarfWriter::RecordInlinedFnEnd(DISubprogram &SP) { + return DD->RecordInlinedFnEnd(SP); +} + +/// RecordVariableScope - Record scope for the variable declared by +/// DeclareMI. DeclareMI must describe TargetInstrInfo::DECLARE. +void DwarfWriter::RecordVariableScope(DIVariable &DV, + const MachineInstr *DeclareMI) { + DD->RecordVariableScope(DV, DeclareMI); +} diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index f48ff52b771..e9cc391778b 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -47,6 +47,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/DebugLoc.h" #include "llvm/CodeGen/DwarfWriter.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/Target/TargetData.h" @@ -354,10 +355,18 @@ bool FastISel::SelectCall(User *I) { case Intrinsic::dbg_region_end: { DbgRegionEndInst *REI = cast(I); if (DW && DW->ValidDebugInfo(REI->getContext(), true)) { - unsigned ID = - DW->RecordRegionEnd(cast(REI->getContext())); - const TargetInstrDesc &II = TII.get(TargetInstrInfo::DBG_LABEL); - BuildMI(MBB, DL, II).addImm(ID); + unsigned ID = 0; + DISubprogram Subprogram(cast(REI->getContext())); + if (!Subprogram.describes(MF.getFunction())) { + // This is end of an inlined function. + const TargetInstrDesc &II = TII.get(TargetInstrInfo::DBG_LABEL); + ID = DW->RecordInlinedFnEnd(Subprogram); + BuildMI(MBB, DL, II).addImm(ID); + } else { + const TargetInstrDesc &II = TII.get(TargetInstrInfo::DBG_LABEL); + ID = DW->RecordRegionEnd(cast(REI->getContext())); + BuildMI(MBB, DL, II).addImm(ID); + } } return true; } @@ -369,6 +378,7 @@ bool FastISel::SelectCall(User *I) { if (DW->ValidDebugInfo(SP, true)) { // llvm.dbg.func.start implicitly defines a dbg_stoppoint which is what // (most?) gdb expects. + DebugLoc PrevLoc = DL; DISubprogram Subprogram(cast(SP)); DICompileUnit CompileUnit = Subprogram.getCompileUnit(); std::string Dir, FN; @@ -379,17 +389,15 @@ bool FastISel::SelectCall(User *I) { unsigned Line = Subprogram.getLineNumber(); unsigned LabelID = DW->RecordSourceLine(Line, 0, SrcFile); setCurDebugLoc(DebugLoc::get(MF.getOrCreateDebugLocID(SrcFile, Line, 0))); - - std::string SPName; - Subprogram.getLinkageName(SPName); - if (!SPName.empty() - && strcmp(SPName.c_str(), MF.getFunction()->getNameStart())) { - // This is a beginning of inlined function. - DW->RecordRegionStart(cast(FSI->getSubprogram()), - LabelID); + if (!Subprogram.describes(MF.getFunction())) { + // This is a beginning of an inlined function. const TargetInstrDesc &II = TII.get(TargetInstrInfo::DBG_LABEL); BuildMI(MBB, DL, II).addImm(LabelID); - DW->RecordInlineInfo(Subprogram.getGV(), LabelID); + DebugLocTuple PrevLocTpl = MF.getDebugLocTuple(PrevLoc); + DW->RecordInlinedFnStart(FSI, Subprogram, LabelID, + PrevLocTpl.Src, + PrevLocTpl.Line, + PrevLocTpl.Col); } else { // llvm.dbg.func_start also defines beginning of function scope. DW->RecordRegionStart(cast(FSI->getSubprogram())); @@ -419,7 +427,13 @@ bool FastISel::SelectCall(User *I) { // Build the DECLARE instruction. const TargetInstrDesc &II = TII.get(TargetInstrInfo::DECLARE); - BuildMI(MBB, DL, II).addFrameIndex(FI).addGlobalAddress(GV); + MachineInstr *DeclareMI + = BuildMI(MBB, DL, II).addFrameIndex(FI).addGlobalAddress(GV); + DIVariable DV(cast(GV)); + if (!DV.isNull()) { + // This is a local variable + DW->RecordVariableScope(DV, DeclareMI); + } } return true; }