-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[DebugInfo][DWARF] Use DW_AT_call_target_clobbered for exprs with volatile regs #172167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…atile regs
Without this patch DW_AT_call_target is used for all indirect call address
location expressions. The DWARF spec says:
For indirect calls or jumps where the address is not computable without use
of registers or memory locations that might be clobbered by the call the
DW_AT_call_target_clobbered attribute is used instead of the
DW_AT_call_target attribute.
This patch implements that behaviour.
|
@llvm/pr-subscribers-debuginfo Author: Orlando Cazalet-Hyams (OCHyams) ChangesWithout this patch DW_AT_call_target is used for all indirect call address location expressions. The DWARF spec says: This patch implements that behaviour. Full diff: https://github.com/llvm/llvm-project/pull/172167.diff 4 Files Affected:
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index d19de7f8000ec..c0421e628c7e9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -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");
diff --git a/llvm/test/DebugInfo/X86/dwarf-call-target-clobbered.mir b/llvm/test/DebugInfo/X86/dwarf-call-target-clobbered.mir
new file mode 100644
index 0000000000000..ff5c78d7ad1cf
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/dwarf-call-target-clobbered.mir
@@ -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
+...
diff --git a/llvm/test/DebugInfo/X86/dwarf-call-target-mem-loc.mir b/llvm/test/DebugInfo/X86/dwarf-call-target-mem-loc.mir
index ef8a080cebaae..1923baf9fa173 100644
--- a/llvm/test/DebugInfo/X86/dwarf-call-target-mem-loc.mir
+++ b/llvm/test/DebugInfo/X86/dwarf-call-target-mem-loc.mir
@@ -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 {
diff --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll
index f64b78f5820e4..70f91c66d4e58 100644
--- a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll
+++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs-indirect.ll
@@ -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
@@ -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
|
Michael137
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/155/builds/15726 Here is the relevant piece of the build log for the reference |
Looks like an intermittent failure that has righted itself since. |
|
We're seeing compiler crashes with after this. I have an unreduced repro at https://issues.chromium.org/u/1/issues/468825583#comment2 Can you take a look? |
|
I guess reducing was fast :) |
|
Thanks for the reduced reproducer, taking a look! |
Fixes assertion trip introduced in llvm#172167 See https://issues.chromium.org/issues/468825583#comment2
|
Just missed a simple lookup used for some configurations - fix here #172336 |
Fixes assertion trip introduced in #172167 See https://issues.chromium.org/issues/468825583#comment2
) Not sure whether this comes up in practice, but I noticed a switch block I missed in #172167
Without this patch DW_AT_call_target is used for all indirect call address location expressions. The DWARF spec says:
This patch implements that behaviour.