diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2512,8 +2512,20 @@ // encoding is supported. DwarfExpr.addWasmLocation(Loc.Index, static_cast(Loc.Offset)); } else if (Value.isConstantFP()) { - APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt(); - DwarfExpr.addUnsignedConstant(RawBytes); + if (AP.getDwarfVersion() >= 4 && AP.getDwarfDebug()->tuneForGDB()) + DwarfExpr.addConstantFP(Value.getConstantFP()->getValueAPF()); + else if (Value.getConstantFP() + ->getValueAPF() + .bitcastToAPInt() + .getBitWidth() <= 64 /*bits*/) + DwarfExpr.addUnsignedConstant( + Value.getConstantFP()->getValueAPF().bitcastToAPInt()); + else + LLVM_DEBUG( + dbgs() + << "Skipped DwarfExpression creation for ConstantFP of size" + << Value.getConstantFP()->getValueAPF().bitcastToAPInt().getBitWidth() + << " bits\n"); } DwarfExpr.addExpression(std::move(ExprCursor)); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -299,6 +299,9 @@ /// Emit an unsigned constant. void addUnsignedConstant(const APInt &Value); + /// Emit floating point constant. + void addConstantFP(const APFloat &Value); + /// Lock this down to become a memory location description. void setMemoryLocationKind() { assert(isUnknownLocation()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -25,6 +25,8 @@ using namespace llvm; +#define DEBUG_TYPE "dwarfdebug" + void DwarfExpression::emitConstu(uint64_t Value) { if (Value < 32) emitOp(dwarf::DW_OP_lit0 + Value); @@ -219,6 +221,36 @@ } } +void DwarfExpression::addConstantFP(const APFloat &Value) { + assert(isImplicitLocation() || isUnknownLocation()); + APInt RawBytes = Value.bitcastToAPInt(); + int NumBytes = RawBytes.getBitWidth() / 8; + const char *Data = (const char *)RawBytes.getRawData(); + emitOp(dwarf::DW_OP_implicit_value); + if (NumBytes == 4 /*float*/ || NumBytes == 8 /*double*/) { + emitUnsigned(NumBytes /*Size of the block in bytes*/); + for (int i = 0; i < NumBytes; ++i) + emitData1(Data[i]); + return; + } + if (NumBytes == 10 /*long double*/) { + // long double IEEE representation uses 80 bits(10 bytes). + // 6 bytes are padded to make it 128 bits(16 bytes) due to + // addressing restrictions. + emitUnsigned(16 /*Size of the block in bytes*/); + // Emit the block of bytes. + for (int i = 0; i < NumBytes; ++i) + emitData1(Data[i]); + // Emit the rest as padding bytes. + for (int i = 0; i < 16 - NumBytes; ++i) + emitData1(0); + return; + } + LLVM_DEBUG( + dbgs() << "Skipped DW_OP_implicit_value creation for ConstantFP of size" + << RawBytes.getBitWidth() << " bits\n"); +} + bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI, DIExpressionCursor &ExprCursor, unsigned MachineReg, diff --git a/llvm/test/DebugInfo/X86/float_const_loclist.ll b/llvm/test/DebugInfo/X86/float_const_loclist.ll --- a/llvm/test/DebugInfo/X86/float_const_loclist.ll +++ b/llvm/test/DebugInfo/X86/float_const_loclist.ll @@ -20,12 +20,10 @@ ; ; CHECK: .debug_info contents: ; CHECK: DW_TAG_variable -; CHECK-NEXT: DW_AT_location {{.*}} ( -; CHECK-NEXT: [0x[[START:.*]], 0x[[END:.*]]): DW_OP_constu 0xc8f5c28f5c28f800, DW_OP_piece 0x8, DW_OP_constu 0x4000, DW_OP_bit_piece 0x10 0x40) ; CHECK-NEXT: DW_AT_name {{.*}}"ld" ; CHECK: DW_TAG_variable ; CHECK-NEXT: DW_AT_location {{.*}} ( -; CHECK-NEXT: [0x[[START]], 0x[[END]]): DW_OP_constu 0x4048f5c3) +; CHECK-NEXT: [0x{{.*}}, 0x{{.*}}): DW_OP_constu 0x4048f5c3) ; CHECK-NEXT: DW_AT_name {{.*}}"f" source_filename = "test.c" diff --git a/llvm/test/DebugInfo/X86/implicit_value-double.ll b/llvm/test/DebugInfo/X86/implicit_value-double.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/implicit_value-double.ll @@ -0,0 +1,66 @@ +;; This test checks for emission of DW_OP_implicit_value operation +;; for double type. + +; RUN: llc -debugger-tune=gdb -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK: .debug_info contents: +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_location ({{.*}} +; CHECK-NEXT: [{{.*}}): DW_OP_implicit_value 0x8 0x1f 0x85 0xeb 0x51 0xb8 0x1e 0x09 0x40) +; CHECK-NEXT: DW_AT_name ("d") + +;; Generated from: clang -ggdb -O1 +;;int main() { +;; double d = 3.14; +;; printf("dummy\n"); +;; d *= d; +;; return 0; +;;} + +; ModuleID = 'implicit_value-double.c' +source_filename = "implicit_value-double.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@str = private unnamed_addr constant [6 x i8] c"dummy\00", align 1 + +; Function Attrs: nofree nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata double 3.140000e+00, metadata !12, metadata !DIExpression()), !dbg !14 + %puts = call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @str, i64 0, i64 0)), !dbg !15 + call void @llvm.dbg.value(metadata double undef, metadata !12, metadata !DIExpression()), !dbg !14 + ret i32 0, !dbg !16 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +; Function Attrs: nofree nounwind +declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #2 + +attributes #0 = { nofree nounwind uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { nofree 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 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "implicit_value-double.c", directory: "/home/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "d", scope: !7, file: !1, line: 2, type: !13) +!13 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!14 = !DILocation(line: 0, scope: !7) +!15 = !DILocation(line: 3, column: 2, scope: !7) +!16 = !DILocation(line: 5, column: 2, scope: !7) diff --git a/llvm/test/DebugInfo/X86/implicit_value-float.ll b/llvm/test/DebugInfo/X86/implicit_value-float.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/implicit_value-float.ll @@ -0,0 +1,65 @@ +;; This test checks for emission of DW_OP_implicit_value operation +;; for float type. + +; RUN: llc -debugger-tune=gdb -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK: .debug_info contents: +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_location ({{.*}} +; CHECK-NEXT: [{{.*}}): DW_OP_implicit_value 0x4 0xc3 0xf5 0x48 0x40) +; CHECK-NEXT: DW_AT_name ("f") + +;; Generated from: clang -ggdb -O1 +;;int main() { +;; float f = 3.14f; +;; printf("dummy\n"); +;; f *= f; +;; return 0; +;;} +; ModuleID = 'implicit_value-float.c' +source_filename = "implicit_value-float.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@str = private unnamed_addr constant [6 x i8] c"dummy\00", align 1 + +; Function Attrs: nofree nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata float 0x40091EB860000000, metadata !12, metadata !DIExpression()), !dbg !14 + %puts = call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @str, i64 0, i64 0)), !dbg !15 + call void @llvm.dbg.value(metadata float undef, metadata !12, metadata !DIExpression()), !dbg !14 + ret i32 0, !dbg !16 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +; Function Attrs: nofree nounwind +declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #2 + +attributes #0 = { nofree nounwind uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { nofree 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 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "implicit_value-float.c", directory: "/home/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "f", scope: !7, file: !1, line: 2, type: !13) +!13 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!14 = !DILocation(line: 0, scope: !7) +!15 = !DILocation(line: 3, column: 2, scope: !7) +!16 = !DILocation(line: 5, column: 2, scope: !7) diff --git a/llvm/test/DebugInfo/X86/implicit_value-ld.ll b/llvm/test/DebugInfo/X86/implicit_value-ld.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/implicit_value-ld.ll @@ -0,0 +1,71 @@ +;; This test checks for emission of DW_OP_implicit_value operation +;; for long double type. + +; RUN: llc -debugger-tune=gdb -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK: .debug_info contents: +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_location ({{.*}} +; CHECK-NEXT: [{{.*}}): DW_OP_implicit_value 0x10 0x00 0xf8 0x28 0x5c 0x8f 0xc2 0xf5 0xc8 0x00 0x40 0x00 0x00 0x00 0x00 0x00 0x00) +; CHECK-NEXT: DW_AT_name ("ld") + +;; Generated from: clang -ggdb -O1 +;;int main() { +;; long double ld = 3.14; +;; printf("dummy\n"); +;; ld *= ld; +;; return 0; +;;} + +; ModuleID = 'implicit_value-ld.c' +source_filename = "implicit_value-ld.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@str = private unnamed_addr constant [6 x i8] c"dummy\00", align 1 + +; Function Attrs: nofree nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.declare(metadata [6 x i8]* undef, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 80, 48)), !dbg !14 + call void @llvm.dbg.value(metadata x86_fp80 0xK4000C8F5C28F5C28F800, metadata !12, metadata !DIExpression()), !dbg !15 + %puts = call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @str, i64 0, i64 0)), !dbg !16 + call void @llvm.dbg.value(metadata x86_fp80 undef, metadata !12, metadata !DIExpression()), !dbg !15 + ret i32 0, !dbg !17 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +; Function Attrs: nofree nounwind +declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #2 + +attributes #0 = { nofree nounwind uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { nofree 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 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "implicit_value-ld.c", directory: "/home/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "ld", scope: !7, file: !1, line: 2, type: !13) +!13 = !DIBasicType(name: "long double", size: 128, encoding: DW_ATE_float) +!14 = !DILocation(line: 2, column: 14, scope: !7) +!15 = !DILocation(line: 0, scope: !7) +!16 = !DILocation(line: 3, column: 2, scope: !7) +!17 = !DILocation(line: 5, column: 2, scope: !7)