[llvm] r281664 - [codeview] Optimize the size of defranges with gaps

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 15 15:05:09 PDT 2016


Author: rnk
Date: Thu Sep 15 17:05:08 2016
New Revision: 281664

URL: http://llvm.org/viewvc/llvm-project?rev=281664&view=rev
Log:
[codeview] Optimize the size of defranges with gaps

For small, discontiguous local variable regions, CodeView can use a
single defrange record with a gap, rather than having two defrange
records. I expect that this optimization will only have a minor impact
on debug info size.

Added:
    llvm/trunk/test/DebugInfo/COFF/local-variable-gap.ll
    llvm/trunk/test/MC/COFF/cv-def-range-gap.s
Modified:
    llvm/trunk/lib/MC/MCCodeView.cpp

Modified: llvm/trunk/lib/MC/MCCodeView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCCodeView.cpp?rev=281664&r1=281663&r2=281664&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCCodeView.cpp (original)
+++ llvm/trunk/lib/MC/MCCodeView.cpp Thu Sep 15 17:05:08 2016
@@ -453,16 +453,41 @@ void CodeViewContext::encodeDefRange(MCA
   Fixups.clear();
   raw_svector_ostream OS(Contents);
 
-  // Write down each range where the variable is defined.
+  // Compute all the sizes up front.
+  SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes;
+  const MCSymbol *LastLabel = nullptr;
   for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
+    unsigned GapSize =
+        LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0;
     unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
+    GapAndRangeSizes.push_back({GapSize, RangeSize});
+    LastLabel = Range.second;
+  }
+
+  // Write down each range where the variable is defined.
+  for (size_t I = 0, E = Frag.getRanges().size(); I != E;) {
+    // If the range size of multiple consecutive ranges is under the max,
+    // combine the ranges and emit some gaps.
+    const MCSymbol *RangeBegin = Frag.getRanges()[I].first;
+    unsigned RangeSize = GapAndRangeSizes[I].second;
+    size_t J = I + 1;
+    for (; J != E; ++J) {
+      unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second;
+      if (RangeSize + GapAndRangeSize > MaxDefRange)
+        break;
+      RangeSize += GapAndRangeSize;
+    }
+    unsigned NumGaps = J - I - 1;
+
+    support::endian::Writer<support::little> LEWriter(OS);
+
     unsigned Bias = 0;
     // We must split the range into chunks of MaxDefRange, this is a fundamental
     // limitation of the file format.
     do {
       uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
 
-      const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Range.first, Ctx);
+      const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx);
       const MCBinaryExpr *BE =
           MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
       MCValue Res;
@@ -473,8 +498,8 @@ void CodeViewContext::encodeDefRange(MCA
       StringRef FixedSizePortion = Frag.getFixedSizePortion();
       // Our record is a fixed sized prefix and a LocalVariableAddrRange that we
       // are artificially constructing.
-      size_t RecordSize =
-          FixedSizePortion.size() + sizeof(LocalVariableAddrRange);
+      size_t RecordSize = FixedSizePortion.size() +
+                          sizeof(LocalVariableAddrRange) + 4 * NumGaps;
       // Write out the recrod size.
       support::endian::Writer<support::little>(OS).write<uint16_t>(RecordSize);
       // Write out the fixed size prefix.
@@ -487,12 +512,25 @@ void CodeViewContext::encodeDefRange(MCA
       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
       Contents.resize(Contents.size() + 2); // Fixup for section index.
       // Write down the range's extent.
-      support::endian::Writer<support::little>(OS).write<uint16_t>(Chunk);
+      LEWriter.write<uint16_t>(Chunk);
 
       // Move on to the next range.
       Bias += Chunk;
       RangeSize -= Chunk;
     } while (RangeSize > 0);
+
+    // Emit the gaps afterwards.
+    assert((NumGaps == 0 || Bias < MaxDefRange) &&
+           "large ranges should not have gaps");
+    unsigned GapStartOffset = GapAndRangeSizes[I].second;
+    for (++I; I != J; ++I) {
+      unsigned GapSize, RangeSize;
+      assert(I < GapAndRangeSizes.size());
+      std::tie(GapSize, RangeSize) = GapAndRangeSizes[I];
+      LEWriter.write<uint16_t>(GapStartOffset);
+      LEWriter.write<uint16_t>(RangeSize);
+      GapStartOffset += GapSize + RangeSize;
+    }
   }
 }
 

Added: llvm/trunk/test/DebugInfo/COFF/local-variable-gap.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/local-variable-gap.ll?rev=281664&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/local-variable-gap.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/local-variable-gap.ll Thu Sep 15 17:05:08 2016
@@ -0,0 +1,174 @@
+; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s --check-prefix=ASM
+; RUN: llc -mtriple=x86_64-windows-msvc < %s -filetype=obj | llvm-readobj -codeview - | FileCheck %s --check-prefix=OBJ
+
+; This test attempts to exercise gaps in local variables. The local variable 'p'
+; will end up in some CSR (ESI), which will be used in both the BB scheduled
+; discontiguously out of line and the normal return BB. The best way to encode
+; this is to use a LocalVariableAddrGap. If the gap is too large, multiple
+; ranges should be emitted.
+
+; Source to regenerate:
+; int barrier();
+; int vardef();
+; void use(int);
+; void __declspec(noreturn) call_noreturn(int);
+; int f() {
+;   if (barrier()) {
+;     int p = vardef();
+;     if (barrier()) // Unlikely, will be placed after return
+;       call_noreturn(p);
+;     use(p);
+;   } else {
+;     barrier();
+;   }
+;   return 0;
+; }
+
+; ASM: f:                                      # @f
+; ASM:         pushq   %rsi
+; ASM:         subq    $32, %rsp
+; ASM:         callq   barrier
+; ASM:         testl   %eax, %eax
+; ASM:         je      .LBB0_3
+; ASM:         callq   vardef
+; ASM:         movl    %eax, %esi
+; ASM: [[p_b1:\.Ltmp[0-9]+]]:
+; ASM:         #DEBUG_VALUE: p <- %ESI
+; ASM:         callq   barrier
+; ASM:         movl    %esi, %ecx
+; ASM:         testl   %eax, %eax
+; ASM:         jne     .LBB0_5
+; ASM: # BB#2:                                 # %if.end
+; ASM:         #DEBUG_VALUE: p <- %ESI
+; ASM:         callq   use
+; ASM:         jmp     .LBB0_4
+; ASM: [[p_e1:\.Ltmp[0-9]+]]:
+; ASM: .LBB0_3:                                # %if.else
+; ASM:         callq   barrier
+; ASM: .LBB0_4:                                # %if.end6
+; ASM:         xorl    %eax, %eax
+; ASM:         addq    $32, %rsp
+; ASM:         popq    %rsi
+; ASM:         retq
+; ASM: .LBB0_5:                                # %if.then4
+; ASM: [[p_b2:\.Ltmp[0-9]+]]:
+; ASM:         #DEBUG_VALUE: p <- %ESI
+; ASM:         callq   call_noreturn
+; ASM:         ud2
+; ASM: .Lfunc_end0:
+
+; ASM:         .short  {{.*}}         # Record length
+; ASM:         .short  4414                    # Record kind: S_LOCAL
+; ASM:         .long   116                     # TypeIndex
+; ASM:         .short  0                       # Flags
+; ASM:         .asciz  "p"
+; ASM:         .cv_def_range    [[p_b1]] [[p_e1]] [[p_b2]] .Lfunc_end0, "A\021\027\000\000\000"
+; ASM:         .short  2                       # Record length
+; ASM:         .short  4431                    # Record kind: S_PROC_ID_END
+
+; OBJ:         Local {
+; OBJ:           Type: int (0x74)
+; OBJ:           VarName: p
+; OBJ:         }
+; OBJ-NOT:     Local {
+; OBJ:         DefRangeRegister {
+; OBJ-NEXT:      Register: 23
+; OBJ-NEXT:      MayHaveNoName: 0
+; OBJ-NEXT:      LocalVariableAddrRange {
+; OBJ-NEXT:        OffsetStart: .text+0x{{.*}}
+; OBJ-NEXT:        ISectStart: 0x0
+; OBJ-NEXT:        Range: 0x{{.*}}
+; OBJ-NEXT:      }
+; OBJ-NEXT:      LocalVariableAddrGap [
+; OBJ-NEXT:        GapStartOffset: 0x{{.*}}
+; OBJ-NEXT:        Range: 0x{{.*}}
+; OBJ-NEXT:      ]
+; OBJ-NEXT:    }
+
+; ModuleID = 't.cpp'
+source_filename = "t.cpp"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.0.24210"
+
+; Function Attrs: nounwind uwtable
+define i32 @f() local_unnamed_addr #0 !dbg !7 {
+entry:
+  %call = tail call i32 bitcast (i32 (...)* @barrier to i32 ()*)() #4, !dbg !15
+  %tobool = icmp eq i32 %call, 0, !dbg !15
+  br i1 %tobool, label %if.else, label %if.then, !dbg !16
+
+if.then:                                          ; preds = %entry
+  %call1 = tail call i32 bitcast (i32 (...)* @vardef to i32 ()*)() #4, !dbg !17
+  tail call void @llvm.dbg.value(metadata i32 %call1, i64 0, metadata !12, metadata !18), !dbg !19
+  %call2 = tail call i32 bitcast (i32 (...)* @barrier to i32 ()*)() #4, !dbg !20
+  %tobool3 = icmp eq i32 %call2, 0, !dbg !20
+  br i1 %tobool3, label %if.end, label %if.then4, !dbg !22
+
+if.then4:                                         ; preds = %if.then
+  tail call void @call_noreturn(i32 %call1) #5, !dbg !23
+  unreachable, !dbg !23
+
+if.end:                                           ; preds = %if.then
+  tail call void @use(i32 %call1) #4, !dbg !24
+  br label %if.end6, !dbg !25
+
+if.else:                                          ; preds = %entry
+  %call5 = tail call i32 bitcast (i32 (...)* @barrier to i32 ()*)() #4, !dbg !26
+  br label %if.end6
+
+if.end6:                                          ; preds = %if.else, %if.end
+  ret i32 0, !dbg !28
+}
+
+declare i32 @barrier(...) local_unnamed_addr #1
+
+declare i32 @vardef(...) local_unnamed_addr #1
+
+; Function Attrs: noreturn
+declare void @call_noreturn(i32) local_unnamed_addr #2
+
+declare void @use(i32) local_unnamed_addr #1
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #3
+
+attributes #0 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { noreturn "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { nounwind readnone }
+attributes #4 = { nounwind }
+attributes #5 = { noreturn nounwind }
+
+!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 4.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.cpp", directory: "C:\5Csrc\5Cllvm\5Cbuild")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"PIC Level", i32 2}
+!6 = !{!"clang version 4.0.0 "}
+!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 19, type: !8, isLocal: false, isDefinition: true, scopeLine: 19, isOptimized: true, unit: !0, variables: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "p", scope: !13, file: !1, line: 21, type: !10)
+!13 = distinct !DILexicalBlock(scope: !14, file: !1, line: 20, column: 18)
+!14 = distinct !DILexicalBlock(scope: !7, file: !1, line: 20, column: 7)
+!15 = !DILocation(line: 20, column: 7, scope: !14)
+!16 = !DILocation(line: 20, column: 7, scope: !7)
+!17 = !DILocation(line: 21, column: 13, scope: !13)
+!18 = !DIExpression()
+!19 = !DILocation(line: 21, column: 9, scope: !13)
+!20 = !DILocation(line: 22, column: 9, scope: !21)
+!21 = distinct !DILexicalBlock(scope: !13, file: !1, line: 22, column: 9)
+!22 = !DILocation(line: 22, column: 9, scope: !13)
+!23 = !DILocation(line: 23, column: 7, scope: !21)
+!24 = !DILocation(line: 24, column: 5, scope: !13)
+!25 = !DILocation(line: 25, column: 3, scope: !13)
+!26 = !DILocation(line: 26, column: 5, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !14, file: !1, line: 25, column: 10)
+!28 = !DILocation(line: 28, column: 3, scope: !7)

Added: llvm/trunk/test/MC/COFF/cv-def-range-gap.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/COFF/cv-def-range-gap.s?rev=281664&view=auto
==============================================================================
--- llvm/trunk/test/MC/COFF/cv-def-range-gap.s (added)
+++ llvm/trunk/test/MC/COFF/cv-def-range-gap.s Thu Sep 15 17:05:08 2016
@@ -0,0 +1,101 @@
+# RUN: llvm-mc -triple=x86_64-pc-win32 -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s
+
+# This tries to test defrange gap edge cases.
+
+# CHECK:         Local {
+# CHECK:           Type: int (0x74)
+# CHECK:           VarName: p
+# CHECK:         }
+# CHECK-NOT:     Local {
+# CHECK:         DefRangeRegister {
+# CHECK-NEXT:      Register: 23
+# CHECK-NEXT:      MayHaveNoName: 0
+# CHECK-NEXT:      LocalVariableAddrRange {
+# CHECK-NEXT:        OffsetStart: .text+0x5
+# CHECK-NEXT:        ISectStart: 0x0
+# CHECK-NEXT:        Range: 0x5
+# CHECK-NEXT:      }
+# CHECK-NEXT:      LocalVariableAddrGap [
+# CHECK-NEXT:        GapStartOffset: 0x3
+# CHECK-NEXT:        Range: 0x1
+# CHECK-NEXT:      ]
+# CHECK-NEXT:    }
+# CHECK-NEXT:    DefRangeRegister {
+# CHECK-NEXT:      Register: 23
+# CHECK-NEXT:      MayHaveNoName: 0
+# CHECK-NEXT:      LocalVariableAddrRange {
+# CHECK-NEXT:        OffsetStart: .text+0x10015
+# CHECK-NEXT:        ISectStart: 0x0
+# CHECK-NEXT:        Range: 0x6
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+# CHECK-NEXT:    DefRangeRegister {
+# CHECK-NEXT:      Register: 23
+# CHECK-NEXT:      MayHaveNoName: 0
+# CHECK-NEXT:      LocalVariableAddrRange {
+# CHECK-NEXT:        OffsetStart: .text+0x2001B
+# CHECK-NEXT:        ISectStart: 0x0
+# CHECK-NEXT:        Range: 0x1
+# CHECK-NEXT:      }
+# CHECK-NEXT:    }
+
+	.text
+f:                                      # @f
+	mov $42, %esi
+.Lbegin0:
+	nop
+	jmp .Lbegin1
+.Lend0:
+	nop
+.Lbegin1:
+	nop
+.Lend1:
+	.p2align	4
+	.fill 0x10000, 1, 0x90
+
+	mov $42, %esi
+.Lbegin2:
+	nop
+	jmp .Lbegin3
+.Lend2:
+	.fill 0x10000, 1, 0x90
+.Lbegin3:
+	nop
+.Lend3:
+	ret
+.Lfunc_end0:
+
+	.section	.debug$S,"dr"
+	.p2align	2
+	.long	4                       # Debug section magic
+	.long	241                     # Symbol subsection for f
+	.long	.Ltmp15-.Ltmp14         # Subsection size
+.Ltmp14:
+	.short	.Ltmp17-.Ltmp16         # Record length
+.Ltmp16:
+	.short	4423                    # Record kind: S_GPROC32_ID
+	.long	0                       # PtrParent
+	.long	0                       # PtrEnd
+	.long	0                       # PtrNext
+	.long	.Lfunc_end0-f           # Code size
+	.long	0                       # Offset after prologue
+	.long	0                       # Offset before epilogue
+	.long	4098                    # Function type index
+	.secrel32	f               # Function section relative address
+	.secidx	f                       # Function section index
+	.byte	0                       # Flags
+	.asciz	"f"                     # Function name
+.Ltmp17:
+	.short	.Ltmp19-.Ltmp18         # Record length
+.Ltmp18:
+	.short	4414                    # Record kind: S_LOCAL
+	.long	116                     # TypeIndex
+	.short	0                       # Flags
+	.asciz	"p"
+.Ltmp19:
+	.cv_def_range	 .Lbegin0 .Lend0 .Lbegin1 .Lend1 .Lbegin2 .Lend2 .Lbegin3 .Lend3, "A\021\027\000\000\000"
+	.short	2                       # Record length
+	.short	4431                    # Record kind: S_PROC_ID_END
+.Ltmp15:
+        .cv_filechecksums               # File index to string table offset subsection
+        .cv_stringtable                 # String table




More information about the llvm-commits mailing list