Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -128,6 +128,9 @@ /// Whether we are currently emitting an entry value operation. bool IsEmittingEntryValue = false; + /// The offset for parameters passed through the stack. + uint64_t entryValueFpOffset; + DwarfCompileUnit &CU; /// The register location, if any. Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -288,9 +288,30 @@ if ((!isParameterValue() && !isMemoryLocation() && !HasComplexExpression) || isEntryValue()) { for (auto &Reg : DwarfRegs) { - if (Reg.DwarfRegNo >= 0) - addReg(Reg.DwarfRegNo, Reg.Comment); - addOpPiece(Reg.SubRegSize); + bool isFP = false; + if (Reg.DwarfRegNo >= 0) { + if (isEntryValue()) { + assert(DwarfRegs.size() == 1); + isFP = isFrameRegister(TRI, MachineReg); + } + + // This covers the case when parameter's location can be described as an + // entry value and parameter is passed through the stack. + if (isEntryValue() && isFP) { + int SignedOffset = 0; + assert(!Reg.isSubRegister() && "full register expected"); + uint64_t Offset = entryValueFpOffset; + uint64_t IntMax = + static_cast(std::numeric_limits::max()); + if (Offset <= IntMax) + SignedOffset = Offset; + addFBReg(SignedOffset); + } else { + addReg(Reg.DwarfRegNo, Reg.Comment); + } + } + if (!(isEntryValue() && isFP)) + addOpPiece(Reg.SubRegSize); } if (isEntryValue()) { @@ -391,7 +412,10 @@ auto Op = ExprCursor.take(); (void)Op; if (Op->getOp() != dwarf::DW_OP_LLVM_entry_value) { - // TODO: Handle this kind of entry-value expression. + assert(Op->getOp() == dwarf::DW_OP_plus_uconst && + "Can currently only emit DW_OP_plus_uconst around entry value " + "expression"); + entryValueFpOffset = Op->getArg(0); Op = ExprCursor.take(); } assert(Op && Op->getOp() == dwarf::DW_OP_LLVM_entry_value); Index: llvm/test/DebugInfo/X86/entry-values-unused.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/entry-values-unused.ll @@ -0,0 +1,107 @@ +; RUN: llc %s -filetype=obj -o - | llvm-dwarfdump - | FileCheck %s + +;; Compiled from source: +;; extern void fn1 (); +;; long int __attribute__((noinline)) fn2 +;; (long int x, long int y, long int z, long int q, long int w, long int e, long int r) +;; { +;; fn1(); +;; return 0; +;; } +;; int main() { +;; fn2(1,2,3,4,5,6,7); +;; return 0; +;; } +;; Using command: +;; clang -g -O2 test7.c -emit-llvm -S -o test7.ll + +; This test should verify that there is appropriate DW_AT_location attribute for parameters +; that are passed through the registers and via the stack. +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_location (DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value) +; CHECK-NEXT: DW_AT_name ("x") +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_location (DW_OP_GNU_entry_value(DW_OP_fbreg +16)) +; CHECK-NEXT: DW_AT_name ("r") + +; ModuleID = 'test7.c' +source_filename = "test7.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" + +; Function Attrs: noinline nounwind uwtable +define dso_local i64 @fn2(i64 %x, i64 %y, i64 %z, i64 %q, i64 %w, i64 %e, i64 %r) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i64 %x, metadata !12, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %y, metadata !13, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %z, metadata !14, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %q, metadata !15, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %w, metadata !16, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %e, metadata !17, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + call void @llvm.dbg.value(metadata i64 %r, metadata !18, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + tail call void (...) @fn1() #4, !dbg !20 + ret i64 0, !dbg !21 +} + +declare !dbg !22 dso_local void @fn1(...) local_unnamed_addr #1 + +; Function Attrs: nounwind uwtable +define dso_local i32 @main() local_unnamed_addr #2 !dbg !26 { +entry: + %call = tail call i64 @fn2(i64 undef, i64 undef, i64 undef, i64 undef, i64 undef, i64 undef, i64 undef), !dbg !30 + ret i32 0, !dbg !39 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { noinline nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/milica-lazarevic/llvm-project.git 59bcfb05e4737f96d9cae8b56671041bf932f4ae)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test7.c", directory: "/home/syrmia/diplomski") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{!"clang version 14.0.0 (https://github.com/milica-lazarevic/llvm-project.git 59bcfb05e4737f96d9cae8b56671041bf932f4ae)"} +!7 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 2, type: !8, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10, !10, !10, !10, !10, !10, !10} +!10 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!11 = !{!12, !13, !14, !15, !16, !17, !18} +!12 = !DILocalVariable(name: "x", arg: 1, scope: !7, file: !1, line: 2, type: !10) +!13 = !DILocalVariable(name: "y", arg: 2, scope: !7, file: !1, line: 2, type: !10) +!14 = !DILocalVariable(name: "z", arg: 3, scope: !7, file: !1, line: 2, type: !10) +!15 = !DILocalVariable(name: "q", arg: 4, scope: !7, file: !1, line: 2, type: !10) +!16 = !DILocalVariable(name: "w", arg: 5, scope: !7, file: !1, line: 2, type: !10) +!17 = !DILocalVariable(name: "e", arg: 6, scope: !7, file: !1, line: 2, type: !10) +!18 = !DILocalVariable(name: "r", arg: 7, scope: !7, file: !1, line: 2, type: !10) +!19 = !DILocation(line: 0, scope: !7) +!20 = !DILocation(line: 4, column: 3, scope: !7) +!21 = !DILocation(line: 5, column: 3, scope: !7) +!22 = !DISubprogram(name: "fn1", scope: !1, file: !1, line: 1, type: !23, spFlags: DISPFlagOptimized, retainedNodes: !25) +!23 = !DISubroutineType(types: !24) +!24 = !{null} +!25 = !{} +!26 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !27, scopeLine: 7, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !25) +!27 = !DISubroutineType(types: !28) +!28 = !{!29} +!29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!30 = !DILocation(line: 8, column: 3, scope: !26, params: !31) +!31 = !{!32, !33, !34, !35, !36, !37, !38} +!32 = !DICallSiteParam(argnum: 0, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +!33 = !DICallSiteParam(argnum: 1, expr: !DIExpression(DW_OP_constu, 2, DW_OP_stack_value)) +!34 = !DICallSiteParam(argnum: 2, expr: !DIExpression(DW_OP_constu, 3, DW_OP_stack_value)) +!35 = !DICallSiteParam(argnum: 3, expr: !DIExpression(DW_OP_constu, 4, DW_OP_stack_value)) +!36 = !DICallSiteParam(argnum: 4, expr: !DIExpression(DW_OP_constu, 5, DW_OP_stack_value)) +!37 = !DICallSiteParam(argnum: 5, expr: !DIExpression(DW_OP_constu, 6, DW_OP_stack_value)) +!38 = !DICallSiteParam(argnum: 6, expr: !DIExpression(DW_OP_constu, 7, DW_OP_stack_value)) +!39 = !DILocation(line: 9, column: 3, scope: !26)