Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1328,15 +1328,22 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(

// A valid register in CallTarget indicates an indirect call.
if (CallTarget.getReg()) {
// Add a DW_AT_call_target location expression describing the location of
// the address of the target function. If any register in the expression
// (i.e., the single register we currently handle) is volatile we must use
// DW_AT_call_target_clobbered instead.
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
dwarf::Attribute Attribute = getDwarf5OrGNUAttr(
TRI.isCalleeSavedPhysReg(CallTarget.getReg(), *Asm->MF)
? dwarf::DW_AT_call_target
: dwarf::DW_AT_call_target_clobbered);

// CallTarget is the location of the address of an indirect call. The
// location may be indirect, modified by Offset.
if (CallTarget.isIndirect())
addMemoryLocation(CallSiteDIE,
getDwarf5OrGNUAttr(dwarf::DW_AT_call_target),
CallTarget, Offset);
addMemoryLocation(CallSiteDIE, Attribute, CallTarget, Offset);
else
addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target),
CallTarget);
addAddress(CallSiteDIE, Attribute, CallTarget);
} else if (CalleeSP) {
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP, CalleeF);
assert(CalleeDIE && "Could not create DIE for call site entry origin");
Expand Down
96 changes: 96 additions & 0 deletions llvm/test/DebugInfo/X86/dwarf-call-target-clobbered.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# RUN: llc %s --start-after=livedebugvalues -o - --filetype=obj | llvm-dwarfdump - | FileCheck %s

## Check that DW_AT_call_target_clobbered is used for a location expression
## using a volatile register, otherwise DW_AT_call_target is used.

## Generated from this C++ with llc -stop-after=livedebugvalues -simplify-mir:
## __attribute__((disable_tail_calls)) void call_mem(void (**f)()) {
## (*f)();
## (*f)();
## }

## Which disassembles to -
## 0000000000000000 <_Z8call_memPPFvvE>:
## 0: 53 pushq %rbx
## 1: 48 89 fb movq %rdi, %rbx
## 4: ff 17 callq *(%rdi)
## 6: ff 13 callq *(%rbx)
## 8: 5b popq %rbx
## 9: c3 retq

# CHECK: DW_TAG_call_site
# CHECK-NEXT: DW_AT_call_target_clobbered (DW_OP_breg5 RDI+0)
# CHECK: DW_TAG_call_site
# CHECK-NEXT: DW_AT_call_target (DW_OP_breg3 RBX+0)

--- |
target triple = "x86_64-unknown-linux-gnu"

define dso_local void @_Z8call_memPPFvvE(ptr noundef readonly captures(none) %f) local_unnamed_addr !dbg !5 {
entry:
%0 = load ptr, ptr %f, align 8, !dbg !13
call void %0(), !dbg !13
%1 = load ptr, ptr %f, align 8, !dbg !14
call void %1(), !dbg !14
ret void
}

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3}
!llvm.ident = !{!4}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 22.0.0git", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.cpp", directory: "/")
!2 = !{i32 7, !"Dwarf Version", i32 5}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = !{!"clang version 22.0.0git"}
!5 = distinct !DISubprogram(name: "call_mem", linkageName: "_Z8call_memPPFvvE", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !12)
!6 = !DISubroutineType(types: !7)
!7 = !{null, !8}
!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
!10 = !DISubroutineType(types: !11)
!11 = !{null}
!12 = !{}
!13 = !DILocation(line: 2, scope: !5)
!14 = !DILocation(line: 3, scope: !5)
...
---
name: _Z8call_memPPFvvE
alignment: 16
tracksRegLiveness: true
noPhis: true
isSSA: false
noVRegs: true
hasFakeUses: false
debugInstrRef: true
tracksDebugUserValues: true
liveins:
- { reg: '$rdi' }
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' }
machineFunctionInfo:
amxProgModel: None
body: |
bb.0.entry:
liveins: $rdi, $rbx

frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp
frame-setup CFI_INSTRUCTION def_cfa_offset 16
CFI_INSTRUCTION offset $rbx, -16
$rbx = MOV64rr $rdi
CALL64m $rdi, 1, $noreg, 0, $noreg, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, debug-location !13 :: (load (s64) from %ir.f)
CALL64m killed renamable $rbx, 1, $noreg, 0, $noreg, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, debug-location !14 :: (load (s64) from %ir.f)
$rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp
frame-destroy CFI_INSTRUCTION def_cfa_offset 8
RET64
...
5 changes: 3 additions & 2 deletions llvm/test/DebugInfo/X86/dwarf-call-target-mem-loc.mir
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# RUN: llc %s --start-after=livedebugvalues -o - --filetype=obj | llvm-dwarfdump - | FileCheck %s

## Check the memory location of the target address for the indirect call
## (virtual in this case) is described by a DW_AT_call_target expression.
## (virtual in this case) is described by a DW_AT_call_target_clobbered
## expression.

# CHECK: DW_TAG_call_site
# CHECK-NEXT: DW_AT_call_target (DW_OP_breg0 RAX+8)
# CHECK-NEXT: DW_AT_call_target_clobbered (DW_OP_breg0 RAX+8)

## Generated from this C++ with llc -stop-after=livedebugvalues -simplify-mir:
## struct Base {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ entry:
#dbg_value(ptr %f, !17, !DIExpression(), !18)

; OBJ: DW_TAG_call_site
; OBJ: DW_AT_call_target (DW_OP_reg[[#]] {{.*}})
; OBJ: DW_AT_call_target{{(_clobbered)?}} (DW_OP_reg[[#]] {{.*}})
; OBJ: DW_AT_call_return_pc
call void (...) %f() #1, !dbg !19
ret void, !dbg !20
Expand All @@ -33,7 +33,7 @@ entry:
%0 = load ptr, ptr %f, align 8, !dbg !28, !tbaa !29

; OBJ: DW_TAG_call_site
; OBJ: DW_AT_call_target (DW_OP_breg[[#]] {{.*}})
; OBJ: DW_AT_call_target{{(_clobbered)?}} (DW_OP_breg[[#]] {{.*}})
; OBJ: DW_AT_call_return_pc
call void (...) %0() #1, !dbg !28
ret void, !dbg !33
Expand Down