Keep track of inlined functions and their locations. This information is collected...
authorDevang Patel <dpatel@apple.com>
Sat, 11 Apr 2009 00:16:47 +0000 (00:16 +0000)
committerDevang Patel <dpatel@apple.com>
Sat, 11 Apr 2009 00:16:47 +0000 (00:16 +0000)
Create debug_inlined dwarf section using these information. This info is used by gdb, at least on Darwin, to enable better experience debugging inlined functions. See DwarfWriter.cpp for more information on structure of debug_inlined section.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@68847 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/DwarfWriter.h
include/llvm/Target/TargetAsmInfo.h
lib/CodeGen/AsmPrinter/DwarfWriter.cpp
lib/CodeGen/SelectionDAG/FastISel.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
lib/Target/TargetAsmInfo.cpp
lib/Target/X86/X86TargetAsmInfo.cpp

index 8e82718e6c2a8b256e4c8c28ade5b6546d16e76d..e7d9266510f50f67468c54ffa602be11765e6046 100644 (file)
@@ -94,6 +94,9 @@ 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);
 
@@ -107,6 +110,10 @@ public:
   /// 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);
 };
 
 
index b871009dda8ddef8c191a76fd30700db9f9f122c..9f44596a8ff4d6a0d5574d2993bfb48308d09034 100644 (file)
@@ -506,7 +506,11 @@ namespace llvm {
     /// DwarfPubTypesSection - Section directive for Dwarf info.
     ///
     const char *DwarfPubTypesSection; // Defaults to ".debug_pubtypes".
-    
+
+    /// DwarfDebugInlineSection - Section directive for inline info.
+    ///
+    const char *DwarfDebugInlineSection; // Defaults to ".debug_inlined"
+
     /// DwarfStrSection - Section directive for Dwarf info.
     ///
     const char *DwarfStrSection; // Defaults to ".debug_str".
@@ -880,6 +884,9 @@ namespace llvm {
     const char *getDwarfPubTypesSection() const {
       return DwarfPubTypesSection;
     }
+    const char *getDwarfDebugInlineSection() const {
+      return DwarfDebugInlineSection;
+    }
     const char *getDwarfStrSection() const {
       return DwarfStrSection;
     }
index d59609b371ef67ea1ad4ef4a4d1d86a8479a12b2..7f68df862b77bc9706827b17bc2e987425caf0bf 100644 (file)
@@ -1252,6 +1252,10 @@ class DwarfDebug : public Dwarf {
   /// DbgScopeMap - Tracks the scopes in the current function.
   DenseMap<GlobalVariable *, DbgScope *> DbgScopeMap;
 
+  /// InlineInfo - Keep track of inlined functions and their location.
+  /// This information is used to populate debug_inlined section.
+  DenseMap<GlobalVariable *, SmallVector<unsigned, 4> > InlineInfo;
+
   /// DebugTimer - Timer for the Dwarf debug writer.
   Timer *DebugTimer;
   
@@ -2027,15 +2031,18 @@ private:
     for (unsigned j = 0, M = Scopes.size(); j < M; ++j) {
       // Define the Scope debug information entry.
       DbgScope *Scope = Scopes[j];
-      // FIXME - Ignore inlined functions for the time being.
-      if (!Scope->getParent()) continue;
 
       unsigned StartID = MMI->MappedLabel(Scope->getStartLabelID());
       unsigned EndID = MMI->MappedLabel(Scope->getEndLabelID());
 
       // Ignore empty scopes.
       if (StartID == EndID && StartID != 0) continue;
-      if (Scope->getScopes().empty() && Scope->getVariables().empty()) continue;
+
+      // Do not ignore inlined scope even if it is empty. Inlined scope 
+      // does not have any parent.
+      if (Scope->getParent() 
+          && Scope->getScopes().empty() && Scope->getVariables().empty()) 
+        continue;
 
       if (StartID == ParentStartID && EndID == ParentEndID) {
         // Just add stuff to the parent scope.
@@ -2781,6 +2788,74 @@ private:
     }
   }
 
+  /// EmitDebugInlineInfo - Emit inline info using following format.
+  /// Section Header:
+  /// 1. length of section
+  /// 2. Dwarf version number
+  /// 3. address size.
+  ///
+  /// Entries (one "entry" for each function that was inlined):
+  ///
+  /// 1. offset into __debug_str section for MIPS linkage name, if exists; 
+  ///   otherwise offset into __debug_str for regular function name.
+  /// 2. offset into __debug_str section for regular function name.
+  /// 3. an unsigned LEB128 number indicating the number of distinct inlining 
+  /// instances for the function.
+  /// 
+  /// The rest of the entry consists of a {die_offset, low_pc}  pair for each 
+  /// inlined instance; the die_offset points to the inlined_subroutine die in
+  /// the __debug_info section, and the low_pc is the starting address  for the
+  ///  inlining instance.
+  void EmitDebugInlineInfo() {
+    if (!MainCU)
+      return;
+
+    Asm->SwitchToDataSection(TAI->getDwarfDebugInlineSection());
+    Asm->EOL();
+    EmitDifference("debug_inlined_end", 1,
+                   "debug_inlined_begin", 1, true);
+    Asm->EOL("Length of Debug Inlined Information Entry");
+
+    EmitLabel("debug_inlined_begin", 1);
+
+    Asm->EmitInt16(DWARF_VERSION); Asm->EOL("Dwarf Version");
+    Asm->EmitInt8(TD->getPointerSize()); Asm->EOL("Address Size (in bytes)");
+
+    for (DenseMap<GlobalVariable *, SmallVector<unsigned, 4> >::iterator 
+           I = InlineInfo.begin(), E = InlineInfo.end(); I != E; ++I) {
+      GlobalVariable *GV = I->first;
+      SmallVector<unsigned, 4> &Labels = I->second;
+      DISubprogram SP(GV);
+      std::string Name;
+      std::string LName;
+
+      SP.getLinkageName(LName);
+      SP.getName(Name);
+
+      Asm->EmitString(LName.empty() ? Name : LName);
+      Asm->EOL("MIPS linkage name");
+
+      Asm->EmitString(Name); Asm->EOL("Function name");
+
+      Asm->EmitULEB128Bytes(Labels.size()); Asm->EOL("Inline count");
+
+      for (SmallVector<unsigned, 4>::iterator LI = Labels.begin(),
+             LE = Labels.end(); LI != LE; ++LI) {
+        DIE *SP = MainCU->getDieMapSlotFor(GV);
+        Asm->EmitInt32(SP->getOffset()); Asm->EOL("DIE offset");
+
+        if (TD->getPointerSize() == sizeof(int32_t))
+          O << TAI->getData32bitsDirective();
+        else
+          O << TAI->getData64bitsDirective();
+        PrintLabelName("label", *LI); Asm->EOL("low_pc");
+      }
+    }
+
+    EmitLabel("debug_inlined_end", 1);
+    Asm->EOL();
+  }
+
   /// GetOrCreateSourceID - Look up the source id with the given directory and
   /// source file names. If none currently exists, create a new id and insert it
   /// in the SourceIds map. This can update DirectoryNames and SourceFileNames maps
@@ -3131,6 +3206,9 @@ public:
     // Emit info into a debug macinfo section.
     EmitDebugMacInfo();
 
+    // Emit inline info.
+    EmitDebugInlineInfo();
+
     if (TimePassesIsEnabled)
       DebugTimer->stopTimer();
   }
@@ -3337,6 +3415,20 @@ 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)
@@ -3377,6 +3469,23 @@ public:
     if (TimePassesIsEnabled)
       DebugTimer->stopTimer();
   }
+
+  //// RecordInlineInfo - Global variable GV is inlined at the location marked
+  //// by LabelID label.
+  void RecordInlineInfo(GlobalVariable *GV, unsigned LabelID) {
+    MMI->RecordUsedDbgLabel(LabelID);
+    DenseMap<GlobalVariable *, SmallVector<unsigned, 4> >::iterator
+      I = InlineInfo.find(GV);
+    if (I == InlineInfo.end()) {
+      SmallVector<unsigned, 4> Labels;
+      Labels.push_back(LabelID);
+      InlineInfo[GV] = Labels;
+      return;
+    }
+
+    SmallVector<unsigned, 4> &Labels = I->second;
+    Labels.push_back(LabelID);
+  }
 };
 
 //===----------------------------------------------------------------------===//
@@ -4532,6 +4641,11 @@ 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);
@@ -4553,3 +4667,10 @@ void DwarfWriter::RecordVariable(GlobalVariable *GV, unsigned FrameIndex) {
 bool DwarfWriter::ShouldEmitDwarfDebug() const {
   return DD->ShouldEmitDwarfDebug();
 }
+
+//// RecordInlineInfo - Global variable GV is inlined at the location marked
+//// by LabelID label.
+void DwarfWriter::RecordInlineInfo(GlobalVariable *GV, unsigned LabelID) {
+  DD->RecordInlineInfo(GV, LabelID);
+}
+
index 8467330bb9b2f4e8d16da985b559906e0d6b5916..617f6e41fd50c5029c5c71280e244c8486118788 100644 (file)
@@ -372,11 +372,23 @@ bool FastISel::SelectCall(User *I) {
 
       // Record the source line.
       unsigned Line = Subprogram.getLineNumber();
-      DW->RecordSourceLine(Line, 0, SrcFile);
+      unsigned LabelID = DW->RecordSourceLine(Line, 0, SrcFile);
       setCurDebugLoc(DebugLoc::get(MF.getOrCreateDebugLocID(SrcFile, Line, 0)));
 
-      // llvm.dbg.func_start also defines beginning of function scope.
-      DW->RecordRegionStart(cast<GlobalVariable>(FSI->getSubprogram()));
+      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<GlobalVariable>(FSI->getSubprogram()), 
+                              LabelID);
+        const TargetInstrDesc &II = TII.get(TargetInstrInfo::DBG_LABEL);
+        BuildMI(MBB, DL, II).addImm(LabelID);
+        DW->RecordInlineInfo(Subprogram.getGV(), LabelID);
+      } else {
+        // llvm.dbg.func_start also defines beginning of function scope.
+        DW->RecordRegionStart(cast<GlobalVariable>(FSI->getSubprogram()));
+      }
     }
 
     return true;
index effb21514a2350eada3211897f0923f5bdd17b37..b5966431737e5db5b2a2ea53c15fe3b8a4c59643 100644 (file)
@@ -3955,6 +3955,18 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
     DwarfWriter *DW = DAG.getDwarfWriter();
     DbgRegionEndInst &REI = cast<DbgRegionEndInst>(I);
     if (DW && DW->ValidDebugInfo(REI.getContext())) {
+
+      MachineFunction &MF = DAG.getMachineFunction();
+      DISubprogram Subprogram(cast<GlobalVariable>(REI.getContext()));
+      std::string SPName;
+      Subprogram.getLinkageName(SPName);
+      if (!SPName.empty() 
+          && strcmp(SPName.c_str(), MF.getFunction()->getNameStart())) {
+        // This is end of inlined function. Debugging information for
+        // inlined function is not handled yet (only supported by FastISel).
+        return 0;
+      }
+
       unsigned LabelID =
         DW->RecordRegionEnd(cast<GlobalVariable>(REI.getContext()));
       if (Fast)
@@ -3974,6 +3986,16 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
       // what (most?) gdb expects.
       MachineFunction &MF = DAG.getMachineFunction();
       DISubprogram Subprogram(cast<GlobalVariable>(SP));
+
+      std::string SPName;
+      Subprogram.getLinkageName(SPName);
+      if (!SPName.empty() 
+          && strcmp(SPName.c_str(), MF.getFunction()->getNameStart())) {
+        // This is beginning of inlined function. Debugging information for
+        // inlined function is not handled yet (only supported by FastISel).
+        return 0;
+      }
+
       DICompileUnit CompileUnit = Subprogram.getCompileUnit();
       std::string Dir, FN;
       unsigned SrcFile = DW->getOrCreateSourceID(CompileUnit.getDirectory(Dir),
index 4d9ec334acddaf46b436245476e880753dcabb6b..55833dee3b01dde3616c69c0e79c9989f1ba4c3e 100644 (file)
@@ -112,6 +112,7 @@ void TargetAsmInfo::fillDefaultValues() {
   DwarfFrameSection = ".debug_frame";
   DwarfPubNamesSection = ".debug_pubnames";
   DwarfPubTypesSection = ".debug_pubtypes";
+  DwarfDebugInlineSection = ".debug_inlined";
   DwarfStrSection = ".debug_str";
   DwarfLocSection = ".debug_loc";
   DwarfARangesSection = ".debug_aranges";
index f1d97a3893226dd3d8b0ae1bab1eab6496045864..666756b432802bbde131d48d804d27813dd3dfcf 100644 (file)
@@ -112,6 +112,7 @@ X86DarwinTargetAsmInfo::X86DarwinTargetAsmInfo(const X86TargetMachine &TM):
   DwarfFrameSection = ".section __DWARF,__debug_frame,regular,debug";
   DwarfPubNamesSection = ".section __DWARF,__debug_pubnames,regular,debug";
   DwarfPubTypesSection = ".section __DWARF,__debug_pubtypes,regular,debug";
+  DwarfDebugInlineSection = ".section __DWARF,__debug_inlined,regular,debug";
   DwarfStrSection = ".section __DWARF,__debug_str,regular,debug";
   DwarfLocSection = ".section __DWARF,__debug_loc,regular,debug";
   DwarfARangesSection = ".section __DWARF,__debug_aranges,regular,debug";