[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