diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 08444fc680df6..a30f5ffec93d0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -672,6 +672,58 @@ static void interpretValues(const MachineInstr *CurMI, const auto &TII = *MF->getSubtarget().getInstrInfo(); const auto &TLI = *MF->getSubtarget().getTargetLowering(); + // It's possible that we find a copy from a non-volatile register to the param + // register, which is clobbered in the meantime. Test for clobbered reg unit + // overlaps before completing. + auto IsRegClobberedInMeantime = [&](Register Reg) -> bool { + for (auto &RegUnit : ClobberedRegUnits) + if (TRI.hasRegUnit(Reg, RegUnit)) + return true; + return false; + }; + + auto DescribeFwdRegsByCalleeSavedCopy = [&](DestSourcePair CopyInst) { + Register CopyDestReg = CopyInst.Destination->getReg(); + Register CopySrcReg = CopyInst.Source->getReg(); + if (IsRegClobberedInMeantime(CopyDestReg)) + return; + // FIXME: This may be incorrect in cases where the caller and callee use + // different calling conventions. + if (!TRI.isCalleeSavedPhysReg(CopyDestReg, *MF)) + return; + // Describe any forward registers matching the source register. If the + // forward register is a sub-register of the source, we describe it using + // the corresponding sub-register in the destination, if such a + // sub-register exists. The end iterator in the MapVector is invalidated at + // erase(), so it needs to be evaluated at each iteration. + for (auto FwdRegIt = ForwardedRegWorklist.begin(); + FwdRegIt != ForwardedRegWorklist.end();) { + Register CalleeSavedReg = MCRegister::NoRegister; + if (FwdRegIt->first == CopySrcReg) + CalleeSavedReg = CopyDestReg; + else if (unsigned SubRegIdx = + TRI.getSubRegIndex(CopySrcReg, FwdRegIt->first)) + if (Register CopyDestSubReg = TRI.getSubReg(CopyDestReg, SubRegIdx)) + CalleeSavedReg = CopyDestSubReg; + + if (CalleeSavedReg == MCRegister::NoRegister) { + ++FwdRegIt; + continue; + } + + MachineLocation MLoc(CalleeSavedReg, /*Indirect=*/false); + finishCallSiteParams(MLoc, EmptyExpr, FwdRegIt->second, Params); + FwdRegIt = ForwardedRegWorklist.erase(FwdRegIt); + } + }; + + // Detect if this is a copy instruction. If this saves any of the forward + // registers in callee-saved registers, we can finalize those parameters + // directly. + // TODO: Can we do something similar for stack saves? + if (auto CopyInst = TII.isCopyInstr(*CurMI)) + DescribeFwdRegsByCalleeSavedCopy(*CopyInst); + // If an instruction defines more than one item in the worklist, we may run // into situations where a worklist register's value is (potentially) // described by the previous value of another register that is also defined @@ -721,16 +773,6 @@ static void interpretValues(const MachineInstr *CurMI, return; } - // It's possible that we find a copy from a non-volatile register to the param - // register, which is clobbered in the meantime. Test for clobbered reg unit - // overlaps before completing. - auto IsRegClobberedInMeantime = [&](Register Reg) -> bool { - for (auto &RegUnit : ClobberedRegUnits) - if (TRI.hasRegUnit(Reg, RegUnit)) - return true; - return false; - }; - for (auto ParamFwdReg : FwdRegDefs) { if (auto ParamValue = TII.describeLoadedValue(*CurMI, ParamFwdReg)) { if (ParamValue->first.isImm()) { @@ -742,6 +784,8 @@ static void interpretValues(const MachineInstr *CurMI, Register SP = TLI.getStackPointerRegisterToSaveRestore(); Register FP = TRI.getFrameRegister(*MF); bool IsSPorFP = (RegLoc == SP) || (RegLoc == FP); + // FIXME: This may be incorrect in cases where the caller and callee use + // different calling conventions. if (!IsRegClobberedInMeantime(RegLoc) && (TRI.isCalleeSavedPhysReg(RegLoc, *MF) || IsSPorFP)) { MachineLocation MLoc(RegLoc, /*Indirect=*/IsSPorFP); diff --git a/llvm/test/DebugInfo/AArch64/dbgcall-site-preserved-subreg.ll b/llvm/test/DebugInfo/AArch64/dbgcall-site-preserved-subreg.ll new file mode 100644 index 0000000000000..378c20b2baf80 --- /dev/null +++ b/llvm/test/DebugInfo/AArch64/dbgcall-site-preserved-subreg.ll @@ -0,0 +1,56 @@ +; RUN: llc -mtriple aarch64-linux-gnu -emit-call-site-info -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s + +; Based on the following C reproducer: +; +; void bar(int); +; long foo(long p) { +; bar(p); +; return p; +; } +; +; Verify that we are able to emit a call site value for the 32-bit W0 parameter +; using a subreg of the preserved register storing the 64-bit value of p. + +; CHECK: DW_TAG_call_site_parameter +; CHECK-NEXT: DW_AT_location (DW_OP_reg0 W0) +; CHECK-NEXT: DW_AT_call_value (DW_OP_breg19 W19+0) + + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32" +target triple = "aarch64" + +define i64 @foo(i64 noundef returned %p) !dbg !8 { +entry: + %conv = trunc i64 %p to i32, !dbg !16 + tail call void @bar(i32 noundef %conv), !dbg !16 + ret i64 %p, !dbg !17 +} + +declare !dbg !18 void @bar(i32 noundef) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git.prerel", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "c1.i", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 4} +!6 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!7 = !{!"clang version 22.0.0git.prerel"} +!8 = distinct !DISubprogram(name: "foo", scope: !9, file: !9, line: 2, type: !10, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13, keyInstructions: true) +!9 = !DIFile(filename: "c1.i", directory: "/", checksumkind: CSK_MD5, checksum: "d6df8546b35604f19079ca89d49a7275") +!10 = !DISubroutineType(types: !11) +!11 = !{!12, !12} +!12 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!13 = !{!14} +!14 = !DILocalVariable(name: "p", arg: 1, scope: !8, file: !9, line: 2, type: !12) +!15 = !DILocation(line: 0, scope: !8) +!16 = !DILocation(line: 3, scope: !8) +!17 = !DILocation(line: 4, scope: !8, atomGroup: 1, atomRank: 1) +!18 = !DISubprogram(name: "bar", scope: !9, file: !9, line: 1, type: !19, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +!19 = !DISubroutineType(types: !20) +!20 = !{null, !21} +!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) diff --git a/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-interpretation.mir b/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-interpretation.mir index 9df0044d39711..84e180f4df773 100644 --- a/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-interpretation.mir +++ b/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-interpretation.mir @@ -13,13 +13,17 @@ # CHECK: DW_TAG_GNU_call_site # CHECK-NEXT: DW_AT_abstract_origin {{.*}} "func2" # CHECK: DW_TAG_GNU_call_site_parameter -# CHECK-NOT: DW_AT_location (DW_OP_reg2 W0) # CHECK-NEXT: DW_AT_location (DW_OP_reg2 W2) # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_fbreg +28) # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg1 W1) # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg19 W19-4) +# CHECK-EMPTY: +# CHECK-NEXT: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg0 W0) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg19 W19+2) +# CHECK-NOT: DW_TAG_GNU_call_site_parameter # CHECK: DW_TAG_GNU_call_site # CHECK-NEXT: DW_AT_abstract_origin {{.*}} "func2") # CHECK-NEXT: DW_AT_low_pc @@ -29,10 +33,10 @@ # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit13) # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_GNU_call_site_parameter -# W2 loads memory location. We can't rely that memory location won't be changed. -# CHECK-NOT: DW_AT_location (DW_OP_reg2 W2) # CHECK-NEXT: DW_AT_location (DW_OP_reg1 W1) # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_constu 0xc0) +# W2 loads memory location. We can't rely that memory location won't be changed. +# CHECK-NOT: DW_TAG_GNU_call_site_parameter --- | ; ModuleID = 'describe-call-pram-load-instruction.c' source_filename = "describe-call-pram-load-instruction.c" diff --git a/llvm/test/DebugInfo/MIR/ARM/dbgcall-site-interpretation.mir b/llvm/test/DebugInfo/MIR/ARM/dbgcall-site-interpretation.mir index ce9fc094fa297..a285877c9c92b 100644 --- a/llvm/test/DebugInfo/MIR/ARM/dbgcall-site-interpretation.mir +++ b/llvm/test/DebugInfo/MIR/ARM/dbgcall-site-interpretation.mir @@ -20,15 +20,20 @@ # CHECK-NEXT: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg1 R1) # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg4 R4-4) +# CHECK-EMPTY: +# CHECK-NEXT: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (DW_OP_reg0 R0) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg4 R4+2) +# CHECK-NOT: DW_TAG_GNU_call_site_parameter # CHECK: DW_TAG_GNU_call_site # CHECK-NEXT: DW_AT_abstract_origin {{.*}}"func2") # CHECK-NEXT: DW_AT_low_pc # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_GNU_call_site_parameter -# R2 loads memory location. We can't rely that memory location won't be changed. -# CHECK-NOT: DW_AT_location (DW_OP_reg2 R2) # CHECK-NEXT: DW_AT_location (DW_OP_reg1 R1) # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg4 R4+8) +# R2 loads memory location. We can't rely that memory location won't be changed. +# CHECK-NOT: DW_TAG_GNU_call_site_parameter --- | ; ModuleID = 'dbgcall-site-interpretation.c' source_filename = "dbgcall-site-interpretation.c" diff --git a/llvm/test/DebugInfo/MIR/X86/dbgcall-site-interpretation.mir b/llvm/test/DebugInfo/MIR/X86/dbgcall-site-interpretation.mir index 9f18dd04c4674..fa959b8a5e32f 100644 --- a/llvm/test/DebugInfo/MIR/X86/dbgcall-site-interpretation.mir +++ b/llvm/test/DebugInfo/MIR/X86/dbgcall-site-interpretation.mir @@ -14,22 +14,21 @@ # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg4 RSI) -# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_GNU_entry_value(DW_OP_reg4 RSI)) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg15 R15+0) # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_GNU_call_site_parameter # CHECK-NEXT: DW_AT_location (DW_OP_reg5 RDI) -# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_GNU_entry_value(DW_OP_reg4 RSI)) +# CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_breg15 R15+0) # CHECK-EMPTY: # CHECK: DW_TAG_GNU_call_site # CHECK-NEXT: DW_AT_abstract_origin {{.*}}"foo" # CHECK-NEXT: DW_AT_low_pc # CHECK-EMPTY: # CHECK-NEXT: DW_TAG_GNU_call_site_parameter -# RCX loads memory location. We can't rely that memory location won't be changed. -# CHECK-NOT: DW_AT_location (DW_OP_reg2 RCX) # CHECK-NEXT: DW_AT_location (DW_OP_reg4 RSI) # CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_lit4) # CHECK-EMPTY: +# RCX loads memory location. We can't rely that memory location won't be changed. # CHECK-NOT: DW_TAG_GNU_call_site_parameter # # Check that call site interpretation analysis can interpret instructions such diff --git a/llvm/test/DebugInfo/MIR/X86/dbgcall-site-preserved-after.mir b/llvm/test/DebugInfo/MIR/X86/dbgcall-site-preserved-after.mir new file mode 100644 index 0000000000000..4f22ddb7b5d79 --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/dbgcall-site-preserved-after.mir @@ -0,0 +1,126 @@ +# RUN: llc %s -o - -filetype=obj -start-after=livedebugvalues \ +# RUN: -emit-call-site-info | \ +# RUN: llvm-dwarfdump - | FileCheck %s + +--- | + ; ModuleID = 'pr43464.c' + source_filename = "pr43464.c" + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + ; Function Attrs: nounwind uwtable + define dso_local noundef i32 @caller() local_unnamed_addr #0 !dbg !10 { + entry: + %call = tail call i64 @value() #2, !dbg !17 + #dbg_value(i64 %call, !15, !DIExpression(), !18) + tail call void @callee(i64 noundef %call) #2, !dbg !19 + %conv = trunc i64 %call to i32, !dbg !20 + ret i32 %conv, !dbg !21 + } + + declare !dbg !22 i64 @value() local_unnamed_addr #1 + + declare !dbg !25 void @callee(i64 noundef) local_unnamed_addr #1 + + attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + attributes #2 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} + !llvm.ident = !{!9} + + !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git.prerel", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) + !1 = !DIFile(filename: "pr43464.c", directory: "/repo/edasten/llvm-project/llvm", checksumkind: CSK_MD5, checksum: "e63080e8df26470df7e757aa6a4ccecd") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{i32 1, !"wchar_size", i32 4} + !5 = !{i32 8, !"PIC Level", i32 2} + !6 = !{i32 7, !"PIE Level", i32 2} + !7 = !{i32 7, !"uwtable", i32 2} + !8 = !{i32 7, !"debug-info-assignment-tracking", i1 true} + !9 = !{!"clang version 22.0.0git.prerel"} + !10 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 4, type: !11, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14, keyInstructions: true) + !11 = !DISubroutineType(types: !12) + !12 = !{!13} + !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !14 = !{!15} + !15 = !DILocalVariable(name: "local", scope: !10, file: !1, line: 5, type: !16) + !16 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) + !17 = !DILocation(line: 5, scope: !10, atomGroup: 1, atomRank: 2) + !18 = !DILocation(line: 0, scope: !10) + !19 = !DILocation(line: 6, scope: !10) + !20 = !DILocation(line: 7, scope: !10, atomGroup: 3, atomRank: 2) + !21 = !DILocation(line: 7, scope: !10, atomGroup: 3, atomRank: 1) + !22 = !DISubprogram(name: "value", scope: !1, file: !1, line: 2, type: !23, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) + !23 = !DISubroutineType(types: !24) + !24 = !{!16} + !25 = !DISubprogram(name: "callee", scope: !1, file: !1, line: 1, type: !26, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) + !26 = !DISubroutineType(types: !27) + !27 = !{null, !16} +... +--- +name: caller +alignment: 16 +tracksRegLiveness: true +noPhis: true +isSSA: false +noVRegs: true +hasFakeUses: false +debugInstrRef: true +tracksDebugUserValues: true +frameInfo: + stackSize: 8 + offsetAdjustment: -8 + maxAlignment: 1 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 8 + isCalleeSavedInfoValid: true +fixedStack: + - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '$rbx' } +callSites: + - { bb: 0, offset: 3 } + - { bb: 0, offset: 8, fwdArgRegs: + - { arg: 0, reg: '$rdi' } } +machineFunctionInfo: + amxProgModel: None +body: | + bb.0.entry: + liveins: $rbx + + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp, debug-location !17 + frame-setup CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbx, -16 + CALL64pcrel32 target-flags(x86-plt) @value, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, debug-instr-number 1, debug-location !17 + DBG_INSTR_REF !15, !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref(1, 6), debug-location !18 + DBG_VALUE_LIST !15, !DIExpression(DW_OP_LLVM_arg, 0), $rbx, debug-location !18 + $rdi = MOV64rr $rax, debug-location !19 + $rbx = MOV64rr $rax, debug-location !17 + CALL64pcrel32 target-flags(x86-plt) @callee, csr_64, implicit $rsp, implicit $ssp, implicit killed $rdi, implicit-def $rsp, implicit-def $ssp, debug-location !19 + $eax = MOV32rr $ebx, implicit killed $rbx, debug-location !21 + $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !21 + frame-destroy CFI_INSTRUCTION def_cfa_offset 8, debug-location !21 + RET64 $eax, debug-location !21 +... + +# Generated from the following C reproducer: +# +# extern void callee(long); +# extern long value(void); +# +# int caller() { +# long local = value(); +# callee(local); +# return local; +# } +# +# but with the order of the instructions saving the value of `local` in $rbx +# with the copy of $rax to $rdi switched. +# +# FIXME: The call site value interpreting code iterates +# instruction-by-instruction upwards, and does not keep track of which register +# values are saved during the call by succeeding instructions, so it does not +# understand that the value of $rdi is available in $rbx. +# CHECK-NOT: call_site_parameter diff --git a/llvm/test/DebugInfo/MIR/X86/dbgcall-site-preserved-clobbered.mir b/llvm/test/DebugInfo/MIR/X86/dbgcall-site-preserved-clobbered.mir new file mode 100644 index 0000000000000..7e911c0ec8d18 --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/dbgcall-site-preserved-clobbered.mir @@ -0,0 +1,124 @@ +# RUN: llc %s -o - -filetype=obj -start-after=livedebugvalues \ +# RUN: -emit-call-site-info | \ +# RUN: llvm-dwarfdump - | FileCheck %s + +--- | + ; ModuleID = 'pr43464.c' + source_filename = "pr43464.c" + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + ; Function Attrs: nounwind uwtable + define dso_local noundef i32 @caller() local_unnamed_addr #0 !dbg !10 { + entry: + %call = tail call i64 @value() #2, !dbg !17 + #dbg_value(i64 %call, !15, !DIExpression(), !18) + tail call void @callee(i64 noundef %call) #2, !dbg !19 + %conv = trunc i64 %call to i32, !dbg !20 + ret i32 %conv, !dbg !21 + } + + declare !dbg !22 i64 @value() local_unnamed_addr #1 + + declare !dbg !25 void @callee(i64 noundef) local_unnamed_addr #1 + + attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + attributes #2 = { nounwind } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} + !llvm.ident = !{!9} + + !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git.prerel", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) + !1 = !DIFile(filename: "pr43464.c", directory: "/repo/edasten/llvm-project/llvm", checksumkind: CSK_MD5, checksum: "e63080e8df26470df7e757aa6a4ccecd") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{i32 1, !"wchar_size", i32 4} + !5 = !{i32 8, !"PIC Level", i32 2} + !6 = !{i32 7, !"PIE Level", i32 2} + !7 = !{i32 7, !"uwtable", i32 2} + !8 = !{i32 7, !"debug-info-assignment-tracking", i1 true} + !9 = !{!"clang version 22.0.0git.prerel"} + !10 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 4, type: !11, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14, keyInstructions: true) + !11 = !DISubroutineType(types: !12) + !12 = !{!13} + !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !14 = !{!15} + !15 = !DILocalVariable(name: "local", scope: !10, file: !1, line: 5, type: !16) + !16 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) + !17 = !DILocation(line: 5, scope: !10, atomGroup: 1, atomRank: 2) + !18 = !DILocation(line: 0, scope: !10) + !19 = !DILocation(line: 6, scope: !10) + !20 = !DILocation(line: 7, scope: !10, atomGroup: 3, atomRank: 2) + !21 = !DILocation(line: 7, scope: !10, atomGroup: 3, atomRank: 1) + !22 = !DISubprogram(name: "value", scope: !1, file: !1, line: 2, type: !23, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) + !23 = !DISubroutineType(types: !24) + !24 = !{!16} + !25 = !DISubprogram(name: "callee", scope: !1, file: !1, line: 1, type: !26, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) + !26 = !DISubroutineType(types: !27) + !27 = !{null, !16} +... +--- +name: caller +alignment: 16 +tracksRegLiveness: true +noPhis: true +isSSA: false +noVRegs: true +hasFakeUses: false +debugInstrRef: true +tracksDebugUserValues: true +frameInfo: + stackSize: 8 + offsetAdjustment: -8 + maxAlignment: 1 + adjustsStack: true + hasCalls: true + maxCallFrameSize: 0 + cvBytesOfCalleeSavedRegisters: 8 + isCalleeSavedInfoValid: true +fixedStack: + - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '$rbx' } +callSites: + - { bb: 0, offset: 9, fwdArgRegs: + - { arg: 0, reg: '$rdi' } } +machineFunctionInfo: + amxProgModel: None +body: | + bb.0.entry: + liveins: $rbx + + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp, debug-location !17 + frame-setup CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbx, -16 + CALL64pcrel32 target-flags(x86-plt) @value, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, debug-instr-number 1, debug-location !17 + $rbx = MOV64rr $rax, debug-location !17 + DBG_INSTR_REF !15, !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref(1, 6), debug-location !18 + DBG_VALUE_LIST !15, !DIExpression(DW_OP_LLVM_arg, 0), $rbx, debug-location !18 + $rdi = MOV64rr $rax, debug-location !19 + ; Manually inserted instruction partially convering $rbx. + INLINEASM &nop, 1, 12, implicit-def $bl + CALL64pcrel32 target-flags(x86-plt) @callee, csr_64, implicit $rsp, implicit $ssp, implicit killed $rdi, implicit-def $rsp, implicit-def $ssp, debug-location !19 + $eax = MOV32rr $ebx, implicit killed $rbx, debug-location !21 + $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !21 + frame-destroy CFI_INSTRUCTION def_cfa_offset 8, debug-location !21 + RET64 $eax, debug-location !21 +... + +# Generated from the following C reproducer: +# +# extern void callee(long); +# extern long value(void); +# +# int caller() { +# long local = value(); +# callee(local); +# return local; +# } +# +# but with an artifical clobbering of $bl inserted after the save of the value +# of `local' in $rbx, which shall prevent such a call site value for $rdi from +# being emitted. + +# CHECK-NOT: call_site_parameter