Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -246,8 +246,8 @@ // a call site parameter expression and if that expression is just a register // location, emit it with addBReg and offset 0, because we should emit a DWARF // expression representing a value, rather than a location. - if (!isMemoryLocation() && !HasComplexExpression && (!isParameterValue() || - isEntryValue())) { + if ((!isMemoryLocation() && !HasComplexExpression && !isParameterValue()) || + isEntryValue()) { for (auto &Reg : DwarfRegs) { if (Reg.DwarfRegNo >= 0) addReg(Reg.DwarfRegNo, Reg.Comment); @@ -257,8 +257,8 @@ if (isEntryValue()) finalizeEntryValue(); - if (isEntryValue() && !isParameterValue() && DwarfVersion >= 4) - emitOp(dwarf::DW_OP_stack_value); + if (isEntryValue() && !isParameterValue() && isRegisterLocation()) + LocationKind = Implicit; DwarfRegs.clear(); return true; Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -896,8 +896,7 @@ // entry values of a simple register location. One reason for this is that // we currently can't calculate the size of the resulting DWARF block for // other expressions. - return I->get() == expr_op_begin()->get() && I->getArg(0) == 1 && - getNumElements() == 2; + return I->get() == expr_op_begin()->get() && I->getArg(0) == 1; } case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_tag_offset: Index: llvm/test/DebugInfo/MIR/X86/complex-entry-value.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/X86/complex-entry-value.mir @@ -0,0 +1,108 @@ +# RUN: llc -debug-entry-values -start-after=livedebugvalues -o - %s -filetype=obj | llvm-dwarfdump - | FileCheck %s + +# Based on the the following reproducer: +# +# extern void use_and_clobber(int); +# +# int callee(int p) { +# int local = p + 1; +# use_and_clobber(p); +# return 0; +# } + +--- | + ; ModuleID = 'foo.c' + source_filename = "foo.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: nounwind uwtable + define dso_local i32 @callee(i32 %p) local_unnamed_addr #0 !dbg !12 { + entry: + call void @llvm.dbg.value(metadata i32 %p, metadata !16, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.value(metadata i32 %p, metadata !17, metadata !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)), !dbg !18 + tail call void @use_and_clobber(i32 %p) #2, !dbg !19 + ret i32 0, !dbg !20 + } + + declare !dbg !4 dso_local void @use_and_clobber(i32) local_unnamed_addr + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #2 + + attributes #0 = { nounwind uwtable } + attributes #1 = { nounwind readnone speculatable willreturn } + attributes #2 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!8, !9, !10} + !llvm.ident = !{!11} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) + !1 = !DIFile(filename: "foo.c", directory: "/") + !2 = !{} + !3 = !{!4} + !4 = !DISubprogram(name: "use_and_clobber", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) + !5 = !DISubroutineType(types: !6) + !6 = !{null, !7} + !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !8 = !{i32 2, !"Dwarf Version", i32 4} + !9 = !{i32 2, !"Debug Info Version", i32 3} + !10 = !{i32 1, !"wchar_size", i32 4} + !11 = !{!"clang version 10.0.0"} + !12 = distinct !DISubprogram(name: "callee", scope: !1, file: !1, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15) + !13 = !DISubroutineType(types: !14) + !14 = !{!7, !7} + !15 = !{!16, !17} + !16 = !DILocalVariable(name: "p", arg: 1, scope: !12, file: !1, line: 3, type: !7, flags: DIFlagArgumentNotModified) + !17 = !DILocalVariable(name: "local", scope: !12, file: !1, line: 4, type: !7) + !18 = !DILocation(line: 0, scope: !12) + !19 = !DILocation(line: 5, scope: !12) + !20 = !DILocation(line: 6, scope: !12) + +... +--- +name: callee +alignment: 16 +tracksRegLiveness: true +liveins: + - { reg: '$edi' } +frameInfo: + stackSize: 8 + offsetAdjustment: -8 + maxAlignment: 1 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 +callSites: + - { bb: 0, offset: 6, fwdArgRegs: + - { arg: 0, reg: '$edi' } } +machineFunctionInfo: {} +body: | + bb.0.entry: + liveins: $edi + + DBG_VALUE $edi, $noreg, !16, !DIExpression(), debug-location !18 + DBG_VALUE $edi, $noreg, !16, !DIExpression(), debug-location !18 + DBG_VALUE $edi, $noreg, !16, !DIExpression(), debug-location !18 + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + DBG_VALUE $edi, $noreg, !17, !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value), debug-location !18 + CALL64pcrel32 @use_and_clobber, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $rsp, implicit-def $ssp, debug-location !19 + DBG_VALUE $edi, $noreg, !16, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !18 + DBG_VALUE $edi, $noreg, !17, !DIExpression(DW_OP_LLVM_entry_value, 1, DW_OP_plus_uconst, 1, DW_OP_stack_value), debug-location !18 + $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, debug-location !20 + $rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !20 + CFI_INSTRUCTION def_cfa_offset 8, debug-location !20 + RETQ killed $eax, debug-location !20 + +... + +# Verify that we emit a correct location list entry when local is described by an entry value. +# The DBG_VALUE using the entry value has been manually added to this test. + +# CHECK: [0x0000000000000001, 0x0000000000000006): DW_OP_breg5 RDI+1, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_stack_value +# CHECK: [0x0000000000000006, 0x000000000000000a): DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_plus_uconst 0x1, DW_OP_stack_value)