[codeview] Correctly handle inlining functions post-dominated by unreachable
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 2 Feb 2016 19:22:34 +0000 (19:22 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 2 Feb 2016 19:22:34 +0000 (19:22 +0000)
CodeView requires us to accurately describe the extent of the inlined
code.  We did this by grabbing the next debug location in source order
and using *that* to denote where we stopped inlining.  However, this is
not sufficient or correct in instances where there is no next debug
location or the next debug location belongs to the start of another
function.

To get this correct, use the end symbol of the function to denote the
last possible place the inlining could have stopped at.

llvm-svn: 259548

13 files changed:
llvm/include/llvm/MC/MCCodeView.h
llvm/include/llvm/MC/MCFragment.h
llvm/include/llvm/MC/MCObjectStreamer.h
llvm/include/llvm/MC/MCStreamer.h
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
llvm/lib/MC/MCAsmStreamer.cpp
llvm/lib/MC/MCCodeView.cpp
llvm/lib/MC/MCObjectStreamer.cpp
llvm/lib/MC/MCParser/AsmParser.cpp
llvm/lib/MC/MCStreamer.cpp
llvm/test/DebugInfo/COFF/inlining.ll
llvm/test/MC/COFF/cv-inline-linetable-unreachable.s [new file with mode: 0644]
llvm/test/MC/COFF/cv-inline-linetable.s

index 71096bc..22cf94f 100644 (file)
@@ -145,8 +145,11 @@ public:
   }
 
   ArrayRef<MCCVLineEntry> getLinesForExtent(size_t L, size_t R) {
-    size_t S = std::min(R, MCCVLines.size()) - L;
-    return makeArrayRef(&MCCVLines[L], S);
+    if (R <= L)
+      return None;
+    if (L >= MCCVLines.size())
+      return None;
+    return makeArrayRef(&MCCVLines[L], R - L);
   }
 
   /// Emits a line table substream.
@@ -154,12 +157,10 @@ public:
                                 const MCSymbol *FuncBegin,
                                 const MCSymbol *FuncEnd);
 
-  void emitInlineLineTableForFunction(MCObjectStreamer &OS,
-                                      unsigned PrimaryFunctionId,
-                                      unsigned SourceFileId,
-                                      unsigned SourceLineNum,
-                                      const MCSymbol *FnStartSym,
-                                      ArrayRef<unsigned> SecondaryFunctionIds);
+  void emitInlineLineTableForFunction(
+      MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
+      unsigned SourceLineNum, const MCSymbol *FnStartSym,
+      const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds);
 
   /// Encodes the binary annotations once we have a layout.
   void encodeInlineLineTable(MCAsmLayout &Layout,
index 3d7d1b8..a7548be 100644 (file)
@@ -492,6 +492,7 @@ class MCCVInlineLineTableFragment : public MCFragment {
   unsigned StartFileId;
   unsigned StartLineNum;
   const MCSymbol *FnStartSym;
+  const MCSymbol *FnEndSym;
   SmallVector<unsigned, 3> SecondaryFuncs;
   SmallString<8> Contents;
 
@@ -502,11 +503,12 @@ class MCCVInlineLineTableFragment : public MCFragment {
 public:
   MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
                               unsigned StartLineNum, const MCSymbol *FnStartSym,
+                              const MCSymbol *FnEndSym,
                               ArrayRef<unsigned> SecondaryFuncs,
                               MCSection *Sec = nullptr)
       : MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId),
         StartFileId(StartFileId), StartLineNum(StartLineNum),
-        FnStartSym(FnStartSym),
+        FnStartSym(FnStartSym), FnEndSym(FnEndSym),
         SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {
     Contents.push_back(0);
   }
@@ -515,6 +517,7 @@ public:
   /// @{
 
   const MCSymbol *getFnStartSym() const { return FnStartSym; }
+  const MCSymbol *getFnEndSym() const { return FnEndSym; }
 
   SmallString<8> &getContents() { return Contents; }
   const SmallString<8> &getContents() const { return Contents; }
index cf0ee5d..6a4ee8c 100644 (file)
@@ -129,7 +129,7 @@ public:
                                 const MCSymbol *End) override;
   void EmitCVInlineLinetableDirective(
       unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
-      const MCSymbol *FnStartSym,
+      const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
       ArrayRef<unsigned> SecondaryFunctionIds) override;
   void EmitCVStringTableDirective() override;
   void EmitCVFileChecksumsDirective() override;
index 7fd4277..8c4d4ee 100644 (file)
@@ -659,7 +659,8 @@ public:
   /// directive.
   virtual void EmitCVInlineLinetableDirective(
       unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
-      const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds);
+      const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
+      ArrayRef<unsigned> SecondaryFunctionIds);
 
   /// \brief This implements the CodeView '.cv_stringtable' assembler directive.
   virtual void EmitCVStringTableDirective() {}
index de12fc3..7bded31 100644 (file)
@@ -345,7 +345,7 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
   collectInlineSiteChildren(SecondaryFuncIds, FI, Site);
 
   OS.EmitCVInlineLinetableDirective(Site.SiteFuncId, FileId, StartLineNum,
-                                    FI.Begin, SecondaryFuncIds);
+                                    FI.Begin, FI.End, SecondaryFuncIds);
 
   OS.EmitLabel(InlineEnd);
 
index 712b7a9..9fcfcf7 100644 (file)
@@ -207,7 +207,7 @@ public:
                                 const MCSymbol *FnEnd) override;
   void EmitCVInlineLinetableDirective(
       unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
-      const MCSymbol *FnStartSym,
+      const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
       ArrayRef<unsigned> SecondaryFunctionIds) override;
   void EmitCVStringTableDirective() override;
   void EmitCVFileChecksumsDirective() override;
@@ -1020,10 +1020,13 @@ void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
 
 void MCAsmStreamer::EmitCVInlineLinetableDirective(
     unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
-    const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) {
+    const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
+    ArrayRef<unsigned> SecondaryFunctionIds) {
   OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
      << ' ' << SourceLineNum << ' ';
   FnStartSym->print(OS, MAI);
+  OS << ' ';
+  FnEndSym->print(OS, MAI);
   if (!SecondaryFunctionIds.empty()) {
     OS << " contains";
     for (unsigned SecondaryFunctionId : SecondaryFunctionIds)
@@ -1031,7 +1034,7 @@ void MCAsmStreamer::EmitCVInlineLinetableDirective(
   }
   EmitEOL();
   this->MCStreamer::EmitCVInlineLinetableDirective(
-      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
+      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
       SecondaryFunctionIds);
 }
 
index ea226f7..81597f6 100644 (file)
@@ -228,11 +228,11 @@ static uint32_t encodeSignedNumber(uint32_t Data) {
 void CodeViewContext::emitInlineLineTableForFunction(
     MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
     unsigned SourceLineNum, const MCSymbol *FnStartSym,
-    ArrayRef<unsigned> SecondaryFunctionIds) {
+    const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds) {
   // Create and insert a fragment into the current section that will be encoded
   // later.
   new MCCVInlineLineTableFragment(
-      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
+      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
       SecondaryFunctionIds, OS.getCurrentSectionOnly());
 }
 
@@ -265,7 +265,7 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
   }
   if (LocBegin >= LocEnd)
     return;
-  ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd + 1);
+  ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd);
   if (Locs.empty())
     return;
 
@@ -331,6 +331,19 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
 
     LastLoc = &Loc;
   }
+
+  assert(WithinFunction);
+
+  unsigned EndSymLength =
+      computeLabelDiff(Layout, LastLoc->getLabel(), Frag.getFnEndSym());
+  unsigned LocAfterLength = ~0U;
+  ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
+  if (!LocAfter.empty())
+    LocAfterLength =
+        computeLabelDiff(Layout, LastLoc->getLabel(), LocAfter[0].getLabel());
+
+  compressAnnotation(ChangeCodeLength, Buffer);
+  compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
 }
 
 //
index 4d84904..40c2e8d 100644 (file)
@@ -386,12 +386,13 @@ void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
 
 void MCObjectStreamer::EmitCVInlineLinetableDirective(
     unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
-    const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) {
+    const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
+    ArrayRef<unsigned> SecondaryFunctionIds) {
   getContext().getCVContext().emitInlineLineTableForFunction(
       *this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
-      SecondaryFunctionIds);
+      FnEndSym, SecondaryFunctionIds);
   this->MCStreamer::EmitCVInlineLinetableDirective(
-      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
+      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
       SecondaryFunctionIds);
 }
 
index 9f8027a..2db7504 100644 (file)
@@ -3229,7 +3229,7 @@ bool AsmParser::parseDirectiveCVLinetable() {
 }
 
 /// parseDirectiveCVInlineLinetable
-/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart
+/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd
 ///          ("contains" SecondaryFunctionId+)?
 bool AsmParser::parseDirectiveCVInlineLinetable() {
   int64_t PrimaryFunctionId = getTok().getIntVal();
@@ -3256,6 +3256,12 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
     return Error(Loc, "expected identifier in directive");
   MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
 
+  Loc = getLexer().getLoc();
+  StringRef FnEndName;
+  if (parseIdentifier(FnEndName))
+    return Error(Loc, "expected identifier in directive");
+  MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
+
   SmallVector<unsigned, 8> SecondaryFunctionIds;
   if (getLexer().is(AsmToken::Identifier)) {
     if (getTok().getIdentifier() != "contains")
@@ -3276,7 +3282,7 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
 
   getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,
                                                SourceLineNum, FnStartSym,
-                                               SecondaryFunctionIds);
+                                               FnEndSym, SecondaryFunctionIds);
   return false;
 }
 
index dcb01b4..8ee4126 100644 (file)
@@ -198,7 +198,8 @@ void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
 
 void MCStreamer::EmitCVInlineLinetableDirective(
     unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
-    const MCSymbol *FnStartSym, ArrayRef<unsigned> SecondaryFunctionIds) {}
+    const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
+    ArrayRef<unsigned> SecondaryFunctionIds) {}
 
 void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
                                      MCSymbol *EHSymbol) {
index fafc224..6f5650a 100644 (file)
 ; ASM: .long   Ltmp3-Ltmp2
 ; ASM: .short 4429
 ; ASM: .asciz
-; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 contains 2
+; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0 contains 2
 ; ASM: .short 4429
 ; ASM: .asciz
-; ASM: .cv_inline_linetable 2 1 2 Lfunc_begin0
+; ASM: .cv_inline_linetable 2 1 2 Lfunc_begin0 Lfunc_end0
 ; ASM: .short  4430
 ; ASM: .short  4430
 
diff --git a/llvm/test/MC/COFF/cv-inline-linetable-unreachable.s b/llvm/test/MC/COFF/cv-inline-linetable-unreachable.s
new file mode 100644 (file)
index 0000000..eb89dd5
--- /dev/null
@@ -0,0 +1,97 @@
+# RUN: llvm-mc -triple=i686-pc-win32 -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s
+       .text
+       .def     @feat.00;
+       .scl    3;
+       .type   0;
+       .endef
+       .globl  @feat.00
+@feat.00 = 1
+       .def     _g;
+       .scl    2;
+       .type   32;
+       .endef
+       .globl  _g
+       .p2align        4, 0x90
+_g:                                     # @g
+Lfunc_begin0:
+       .cv_file        1 "\\usr\\local\\google\\home\\majnemer\\llvm\\src\\<stdin>"
+       .cv_loc 0 1 7 0 is_stmt 0       # <stdin>:7:0
+# BB#0:                                 # %entry
+       pushl   %ebp
+       movl    %esp, %ebp
+       .cv_loc 1 1 4 3                 # <stdin>:4:3
+       movl    _x, %eax
+       addl    $1, %eax
+       movl    %eax, _x
+Lfunc_end0:
+
+       .comm   _x,4,2                  # @x
+       .section        .debug$T,"dr"
+       .long   4
+       .short  6
+       .short  4609
+       .long   0
+       .short  14
+       .short  4104
+       .asciz  "\003\000\000\000\000\000\000\000\000\020\000"
+       .short  12
+       .short  5633
+       .asciz  "\000\000\000\000\001\020\000"
+       .byte   103
+       .byte   0
+       .short  12
+       .short  5633
+       .asciz  "\000\000\000\000\001\020\000"
+       .byte   102
+       .byte   0
+       .section        .debug$S,"dr"
+       .long   4
+       .long   246                     # Inlinee lines subsection
+       .long   Ltmp1-Ltmp0
+Ltmp0:
+       .long   0
+       .long   4099                    # Inlined function f starts at <stdin>:3
+       .long   0
+       .long   3
+Ltmp1:
+       .long   241                     # Symbol subsection for g
+       .long   Ltmp3-Ltmp2
+Ltmp2:
+       .short  Ltmp5-Ltmp4
+Ltmp4:
+       .short  4423
+       .zero   12
+       .long   Lfunc_end0-_g
+       .zero   12
+       .secrel32       _g
+       .secidx _g
+       .byte   0
+       .byte   103
+       .byte   0
+Ltmp5:
+       .short  Ltmp7-Ltmp6
+Ltmp6:
+       .short  4429
+       .asciz  "\000\000\000\000\000\000\000\000\003\020\000"
+       .cv_inline_linetable    1 1 3 Lfunc_begin0 Lfunc_end0
+# CHECK:    InlineSite {
+# CHECK:      PtrParent: 0x0
+# CHECK:      PtrEnd: 0x0
+# CHECK:      Inlinee: f (0x1003)
+# CHECK:      BinaryAnnotations [
+# CHECK:        ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x3, LineOffset: 1}
+# CHECK:        ChangeCodeLength: 0xD
+# CHECK:      ]
+# CHECK:    }
+Ltmp7:
+       .short  2
+       .short  4430
+# CHECK:    InlineSiteEnd {
+# CHECK:    }
+       .short  2
+       .short  4431
+Ltmp3:
+       .p2align        2
+       .cv_linetable   0, _g, Lfunc_end0
+       .cv_filechecksums               # File index to string table offset subsection
+       .cv_stringtable                 # String table
index 222a085..22aa48f 100644 (file)
@@ -84,7 +84,7 @@ Ltmp3:
 Ltmp4:
        .short  4429
        .asciz  "\000\000\000\000\000\000\000\000\003\020\000"
-       .cv_inline_linetable    1 1 9 Lfunc_begin0 contains 2
+       .cv_inline_linetable    1 1 9 Lfunc_begin0 Lfunc_end0 contains 2
 # CHECK:    InlineSite {
 # CHECK:      PtrParent: 0x0
 # CHECK:      PtrEnd: 0x0
@@ -105,7 +105,7 @@ Ltmp5:
 Ltmp6:
        .short  4429
        .asciz  "\000\000\000\000\000\000\000\000\004\020\000"
-       .cv_inline_linetable    2 1 3 Lfunc_begin0
+       .cv_inline_linetable    2 1 3 Lfunc_begin0 Lfunc_end0
 # CHECK:    InlineSite {
 # CHECK:      PtrParent: 0x0
 # CHECK:      PtrEnd: 0x0