DwarfDebug: Support floating point constants in location lists.

This patch closes a gap in the DWARF backend that caused LLVM to drop
debug info for floating point variables that were constant for part of
their scope. Floating point constants are emitted as one or more
DW_OP_constu joined via DW_OP_piece.

This fixes a regression caught by the LLDB testsuite that I introduced
in r262247 when we stopped blindly expanding the range of singular
DBG_VALUEs to span the entire scope and started to emit location lists
with accurate ranges instead.

Also deletes a now-impossible testcase (debug-loc-empty-entries).

<rdar://problem/25448338>

llvm-svn: 265760
This commit is contained in:
Adrian Prantl 2016-04-08 00:38:37 +00:00
parent 267185ec92
commit 3e9c88753b
5 changed files with 127 additions and 84 deletions

View File

@ -1438,10 +1438,10 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
DwarfExpr.AddMachineRegExpression(Expr, Loc.getReg(),
PieceOffsetInBits);
}
} else if (Value.isConstantFP()) {
APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt();
DwarfExpr.AddUnsignedConstant(RawBytes);
}
// else ... ignore constant fp. There is not any good way to
// to represent them here in dwarf.
// FIXME: ^
}
void DebugLocEntry::finalize(const AsmPrinter &AP,

View File

@ -159,29 +159,37 @@ bool DwarfExpression::AddMachineRegPiece(unsigned MachineReg,
return CurPos > PieceOffsetInBits;
}
void DwarfExpression::AddStackValue() {
if (DwarfVersion >= 4)
EmitOp(dwarf::DW_OP_stack_value);
}
void DwarfExpression::AddSignedConstant(int Value) {
EmitOp(dwarf::DW_OP_consts);
EmitSigned(Value);
// The proper way to describe a constant value is
// DW_OP_constu <const>, DW_OP_stack_value.
// Unfortunately, DW_OP_stack_value was not available until DWARF-4,
// so we will continue to generate DW_OP_constu <const> for DWARF-2
// and DWARF-3. Technically, this is incorrect since DW_OP_const <const>
// actually describes a value at a constant addess, not a constant value.
// However, in the past there was no better way to describe a constant
// value, so the producers and consumers started to rely on heuristics
// to disambiguate the value vs. location status of the expression.
// See PR21176 for more details.
if (DwarfVersion >= 4)
EmitOp(dwarf::DW_OP_stack_value);
AddStackValue();
}
void DwarfExpression::AddUnsignedConstant(unsigned Value) {
EmitOp(dwarf::DW_OP_constu);
EmitUnsigned(Value);
// cf. comment in DwarfExpression::AddSignedConstant().
if (DwarfVersion >= 4)
EmitOp(dwarf::DW_OP_stack_value);
AddStackValue();
}
void DwarfExpression::AddUnsignedConstant(APInt Value) {
unsigned Size = Value.getBitWidth();
const uint64_t *Data = Value.getRawData();
// Chop it up into 64-bit pieces, because that's the maximum that
// AddUnsignedConstant takes.
unsigned Offset = 0;
while (Offset < Size) {
AddUnsignedConstant(*Data++);
if (Offset == 0 && Size <= 64)
break;
AddOpPiece(std::min(Size-Offset, 64u), Offset);
Offset += 64;
}
}
static unsigned getOffsetOrZero(unsigned OffsetInBits,

View File

@ -61,6 +61,19 @@ public:
void AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0);
/// Emit a shift-right dwarf expression.
void AddShr(unsigned ShiftBy);
/// Emit a DW_OP_stack_value, if supported.
///
/// The proper way to describe a constant value is
/// DW_OP_constu <const>, DW_OP_stack_value.
/// Unfortunately, DW_OP_stack_value was not available until DWARF-4,
/// so we will continue to generate DW_OP_constu <const> for DWARF-2
/// and DWARF-3. Technically, this is incorrect since DW_OP_const <const>
/// actually describes a value at a constant addess, not a constant value.
/// However, in the past there was no better way to describe a constant
/// value, so the producers and consumers started to rely on heuristics
/// to disambiguate the value vs. location status of the expression.
/// See PR21176 for more details.
void AddStackValue();
/// Emit an indirect dwarf register operation for the given machine register.
/// \return false if no DWARF register exists for MachineReg.
@ -87,6 +100,8 @@ public:
void AddSignedConstant(int Value);
/// Emit an unsigned constant.
void AddUnsignedConstant(unsigned Value);
/// Emit an unsigned constant.
void AddUnsignedConstant(APInt Value);
/// \brief Emit an entire expression on top of a machine register location.
///

View File

@ -1,66 +0,0 @@
; RUN: llc -mtriple=x86_64-apple-macosx <%s | FileCheck %s
; Test that we don't generate empty .debug_loc entries. Originally, there were
; two empty .debug_loc entries for 'a' in an otherwise empty .debug_loc list.
;
; CHECK: .section __DWARF,__debug_loc,regular,debug
; CHECK-NEXT: Lsection_debug_loc:
; CHECK-NEXT: .section __DWARF,__debug_abbrev,regular,debug
;
; Test that the variable stuck around.
; CHECK: .section __DWARF,__debug_info,regular,debug
; CHECK: DW_TAG_variable
; CHECK-NOT: DW_AT_location
; Generated using clang -cc1 with the following args:
;
; -triple x86_64-apple-macosx -emit-llvm -gdwarf-4 -O1
;
; From this testcase:
;
;; void fn1() {
;; float a = 1;
;; for (;;)
;; a = 0;
;; }
; Function Attrs: noreturn nounwind readnone
define void @_Z3fn1v() #0 !dbg !4 {
entry:
tail call void @llvm.dbg.value(metadata float 1.000000e+00, i64 0, metadata !9, metadata !14), !dbg !15
br label %for.cond, !dbg !16
for.cond: ; preds = %for.cond, %entry
tail call void @llvm.dbg.value(metadata float 0.000000e+00, i64 0, metadata !9, metadata !14), !dbg !15
br label %for.cond, !dbg !17
}
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
attributes #0 = { noreturn nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "target-features"="+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!11, !12}
!llvm.ident = !{!13}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.7.0 (trunk 238517) (llvm/trunk 238524)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
!1 = !DIFile(filename: "<stdin>", directory: "/Users/dexonsmith/data/llvm/bootstrap/play/delta2/testcase")
!2 = !{}
!3 = !{!4}
!4 = distinct !DISubprogram(name: "fn1", linkageName: "_Z3fn1v", scope: !5, file: !5, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, variables: !8)
!5 = !DIFile(filename: "t.cpp", directory: "/Users/dexonsmith/data/llvm/bootstrap/play/delta2/testcase")
!6 = !DISubroutineType(types: !7)
!7 = !{null}
!8 = !{!9}
!9 = !DILocalVariable(name: "a", scope: !4, file: !5, line: 2, type: !10)
!10 = !DIBasicType(name: "float", size: 32, align: 32, encoding: DW_ATE_float)
!11 = !{i32 2, !"Dwarf Version", i32 4}
!12 = !{i32 2, !"Debug Info Version", i32 3}
!13 = !{!"clang version 3.7.0 (trunk 238517) (llvm/trunk 238524)"}
!14 = !DIExpression()
!15 = !DILocation(line: 2, scope: !4)
!16 = !DILocation(line: 3, scope: !4)
!17 = !DILocation(line: 3, scope: !18)
!18 = distinct !DILexicalBlock(scope: !19, file: !5, line: 3)
!19 = distinct !DILexicalBlock(scope: !4, file: !5, line: 3)

View File

@ -0,0 +1,86 @@
; RUN: llc %s -stop-after=livedebugvalues -o %t 2>&1 | FileCheck --check-prefix=SANITY %s
; RUN: llc < %s -filetype=obj | llvm-dwarfdump - | FileCheck %s
; Test debug_loc support for floating point constants.
;
; Created from clang -O1:
; void barrier();
; void foo() {
; float f;
; long double ld;
; barrier();
; f = 3.14;
; ld = 3.14;
; barrier();
; }
;
; SANITY: CALL{{.*}} @barrier
; SANITY: DBG_VALUE x86_fp80 0xK4000C8F5C28F5C28F800
; SANITY: DBG_VALUE float 0x40091EB860000000
; SANITY: TAILJMP{{.*}} @barrier
;
; CHECK: .debug_info contents:
; CHECK: DW_TAG_variable
; CHECK-NEXT: DW_AT_location {{.*}} (0x00000000)
; CHECK-NEXT: DW_AT_name {{.*}}"ld"
; CHECK: DW_TAG_variable
; CHECK-NEXT: DW_AT_location {{.*}} (0x00000031)
; CHECK-NEXT: DW_AT_name {{.*}}"f"
;
; CHECK: .debug_loc contents:
; CHECK: 0x00000000: Beginning address offset: [[START:.*]]
; CHECK: Ending address offset: [[END:.*]]
; CHECK: Location description: 10 80 f0 a3 e1 05 93 08 10 80 80 01 9d 10 40
; constu ..., piece 8, constu ..., bit-piece 16 64
; CHECK: 0x00000031: Beginning address offset: [[START]]
; CHECK: Ending address offset: [[END]]
; CHECK: Location description: 10 c3 eb a3 82 04
; constu ...
source_filename = "test.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"
; Function Attrs: nounwind ssp uwtable
define void @foo() #0 !dbg !4 {
entry:
tail call void (...) @barrier() #3, !dbg !16
tail call void @llvm.dbg.value(metadata float 0x40091EB860000000, i64 0, metadata !8, metadata !17), !dbg !18
tail call void @llvm.dbg.value(metadata x86_fp80 0xK4000C8F5C28F5C28F800, i64 0, metadata !10, metadata !17), !dbg !19
tail call void (...) @barrier() #3, !dbg !20
ret void, !dbg !21
}
declare void @barrier(...)
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
attributes #0 = { nounwind ssp uwtable }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!12, !13, !14}
!llvm.ident = !{!15}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 265328) (llvm/trunk 265330)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, subprograms: !3)
!1 = !DIFile(filename: "test.c", directory: "/Volumes/Data/radar/25448338")
!2 = !{}
!3 = !{!4}
!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 4, isOptimized: true, variables: !7)
!5 = !DISubroutineType(types: !6)
!6 = !{null}
!7 = !{!8, !10}
!8 = !DILocalVariable(name: "f", scope: !4, file: !1, line: 5, type: !9)
!9 = !DIBasicType(name: "float", size: 32, align: 32, encoding: DW_ATE_float)
!10 = !DILocalVariable(name: "ld", scope: !4, file: !1, line: 6, type: !11)
!11 = !DIBasicType(name: "long double", size: 128, align: 128, encoding: DW_ATE_float)
!12 = !{i32 2, !"Dwarf Version", i32 2}
!13 = !{i32 2, !"Debug Info Version", i32 3}
!14 = !{i32 1, !"PIC Level", i32 2}
!15 = !{!"clang version 3.9.0 (trunk 265328) (llvm/trunk 265330)"}
!16 = !DILocation(line: 7, column: 3, scope: !4)
!17 = !DIExpression()
!18 = !DILocation(line: 5, column: 9, scope: !4)
!19 = !DILocation(line: 6, column: 15, scope: !4)
!20 = !DILocation(line: 10, column: 3, scope: !4)
!21 = !DILocation(line: 11, column: 1, scope: !4)