https://github.com/CarlosAlbertoEnciso created
https://github.com/llvm/llvm-project/pull/182510
Given the test case:
```
struct CBase {
virtual void foo();
};
void bar(CBase *Base) {
Base->foo();
}
```
and using '-emit-call-site-info' with 'llc', currently the following DWARF is
produced for the indirect call 'Base->foo()':
```
0x10: DW_TAG_structure_type
DW_AT_name ("CBase")
0x20: DW_TAG_subprogram
DW_AT_linkage_name ("_ZN5CBase3fooEv")
DW_AT_name ("foo")
...
0x30: DW_TAG_subprogram
DW_AT_linkage_name ("_Z3barP5CBase")
DW_AT_name ("bar")
...
0x40: DW_TAG_call_site
DW_AT_call_target_clobbered (DW_OP_breg0 RAX+0)
DW_AT_call_return_pc (0x000000000000000a)
```
Initial context from the SCE debugger point of view:
> We can detect when a function has been affected by Identical Code Folding
> (ICF) from DWARF call-site information. For example,
>
> 1. $RIP is currently in 'bar()'
> 2. The call-site information in the parent frame indicates we should have
> called 'foo()'
>
> If we see a situation like the above, we can infer that 'foo()' and 'bar()'
> have been code folded. This technique breaks when dealing with virtual
> functions because the call-site information only provides a way to find the
> target function at runtime.
>
> However, if the call-site information includes information on which virtual
> function is being called, we can compare this against the $RIP location to
> see if we are in an implementation of the virtual function. If we are not,
> then we can assume we have been code folded.
>
> For this to work we just to need to record which virtual function we are
> calling. We do not need to know the type of the 'this' pointer at the
> call-site.
>
This patch (available for all debuggers) helps in the identification of the
intended target of a virtual call in the SCE debugger.
By adding the ``DW_AT_LLVM_virtual_call_origin`` for indirect calls, a debugger
can identify the intended target of a call. These are the specific actions
taking by the SCE debugger:
- The debugger can detect functions that have been folding by comparing whether
the ``DW_AT_call_origin`` matches the call frame function. If it does not, the
debugger can assume the "true" target and the actual target have been code
folded and add a frame annotation to the call stack to indicate this. That, or
there is a tail call from ``foo`` to ``bar``, but the debugger can disambiguate
these cases by looking at the ``DW_AT_call_origin`` referenced subroutine DIE
which has a tombstone ``DW_AT_low_pc`` in the ICF case.
- For virtual calls such as the given test case, the existence of the
``DW_AT_LLVM_virtual_call_origin`` attribute tells the debugger that this is an
indirect jump, and the ``DW_AT_LLVM_virtual_call_origin`` attribute, pointing
to the base class method DIE, will tell which method is being called.
- The debugger can confirm from the method's DIE that it is a virtual function
call by looking at the attributes (``DW_AT_virtuality``, and
``DW_AT_vtable_elem_location``) and can look at the parent DIE to work out the
type.
This is the added ``DW_AT_LLVM_virtual_call_origin`` to identify the target
call ``CBase::foo``.
```
0x40: DW_TAG_call_site
DW_AT_call_target_clobbered (DW_OP_breg0 RAX+0)
DW_AT_call_return_pc (0x000000000000000a)
-----------------------------------------------
DW_AT_LLVM_virtual_call_origin (0x20 "_ZN5CBase3fooEv")
-----------------------------------------------
```
The extra call site information is available by default for all debuggers and
it is generated only for DWARF 5 or greater.
>From 6efff0c844494c0efcebecfc1ee902e96d64eb57 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <[email protected]>
Date: Fri, 20 Feb 2026 12:52:12 +0000
Subject: [PATCH 1/2] [clang][DebugInfo] Add virtuality call-site target
information in DWARF.
Given the test case:
struct CBase {
virtual void foo();
};
void bar(CBase *Base) {
Base->foo();
}
and using '-emit-call-site-info' with llc, the following DWARF
is produced for the indirect call 'Base->foo()':
1$: DW_TAG_structure_type "CBase"
...
2$: DW_TAG_subprogram "foo"
...
3$: DW_TAG_subprogram "bar"
...
4$: DW_TAG_call_site
...
We add DW_AT_LLVM_virtual_call_origin to existing call-site
information, linking indirect calls to the function-declaration
they correspond to.
4$: DW_TAG_call_site
...
DW_AT_LLVM_virtual_call_origin (2$ "_ZN5CBase3fooEv")
The new attribute DW_AT_LLVM_virtual_call_origin helps to
address the ambiguity to any consumer due to the usage of
DW_AT_call_origin.
The functionality is available to all supported debuggers.
---
clang/lib/CodeGen/CGCall.cpp | 2 +
clang/lib/CodeGen/CGDebugInfo.cpp | 17 ++++
clang/lib/CodeGen/CGDebugInfo.h | 9 ++
clang/test/DebugInfo/CXX/callsite-base.cpp | 48 ++++++++++
clang/test/DebugInfo/CXX/callsite-derived.cpp | 58 ++++++++++++
clang/test/DebugInfo/CXX/callsite-edges.cpp | 93 +++++++++++++++++++
.../clang_llvm_roundtrip/callsite-dwarf.cpp | 71 ++++++++++++++
llvm/include/llvm/BinaryFormat/Dwarf.def | 1 +
llvm/include/llvm/CodeGen/MachineFunction.h | 6 ++
llvm/include/llvm/CodeGen/TargetLowering.h | 4 +
llvm/include/llvm/IR/FixedMetadataKinds.def | 1 +
.../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 15 ++-
.../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 4 +
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 29 +++++-
llvm/lib/CodeGen/MIRPrinter.cpp | 2 +-
llvm/lib/CodeGen/MachineFunction.cpp | 3 +
.../CodeGen/SelectionDAG/TargetLowering.cpp | 14 +++
llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 3 +-
.../Target/AArch64/AArch64ISelLowering.cpp | 3 +-
llvm/lib/Target/ARM/ARMISelLowering.cpp | 3 +-
llvm/lib/Target/Mips/MipsISelLowering.cpp | 3 +-
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 3 +-
llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 3 +-
.../MIR/X86/callsite-emit-calleetypeid.ll | 8 +-
24 files changed, 380 insertions(+), 23 deletions(-)
create mode 100644 clang/test/DebugInfo/CXX/callsite-base.cpp
create mode 100644 clang/test/DebugInfo/CXX/callsite-derived.cpp
create mode 100644 clang/test/DebugInfo/CXX/callsite-edges.cpp
create mode 100644
cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 1d950ffed8a0b..b57802ebfced8 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6438,6 +6438,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo
&CallInfo,
DI->EmitFuncDeclForCallSite(
CI, DI->getFunctionType(CalleeDecl, ResTy, Args), CalleeGlobalDecl);
}
+ // Generate call site target information.
+ DI->addCallTargetIfVirtual(CalleeDecl, CI);
}
return Ret;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 2b123631c526c..0a77e0037dac0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -4985,6 +4985,23 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD,
SourceLocation Loc,
Fn->setSubprogram(SP);
}
+void CGDebugInfo::addCallTargetIfVirtual(const FunctionDecl *FD,
+ llvm::CallBase *CI) {
+ if (!shouldGenerateVirtualCallSite())
+ return;
+
+ if (!FD)
+ return;
+
+ assert(CI && "Invalid Call Instruction.");
+ if (!CI->isIndirectCall())
+ return;
+
+ // Always get the method declaration.
+ if (llvm::DISubprogram *MD = getFunctionDeclaration(FD))
+ CI->setMetadata(llvm::LLVMContext::MD_call_target, MD);
+}
+
void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
QualType CalleeType,
GlobalDecl CalleeGlobalDecl) {
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index b36a597a80ede..928bc8fdd9c5d 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -683,6 +683,9 @@ class CGDebugInfo {
/// that it is supported and enabled.
llvm::DINode::DIFlags getCallSiteRelatedAttrs() const;
+ /// Add call target information.
+ void addCallTargetIfVirtual(const FunctionDecl *FD, llvm::CallBase *CI);
+
private:
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
@@ -907,6 +910,12 @@ class CGDebugInfo {
/// If one exists, returns the linkage name of the specified \
/// (non-null) \c Method. Returns empty string otherwise.
llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
+
+ /// Returns true if we should generate call target information.
+ bool shouldGenerateVirtualCallSite() const {
+ // Check general conditions for call site generation.
+ return (getCallSiteRelatedAttrs() != llvm::DINode::FlagZero);
+ }
};
/// A scoped helper to set the current debug location to the specified
diff --git a/clang/test/DebugInfo/CXX/callsite-base.cpp
b/clang/test/DebugInfo/CXX/callsite-base.cpp
new file mode 100644
index 0000000000000..cf26d62a03c0b
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-base.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=standalone -dwarf-version=5 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-BASE
+
+// Simple class with only virtual methods: inlined and not-inlined
+//
+// The following three scenarios are considered:
+// - out-of-line defined virtual member function (f1)
+// - declared-but-not-defined virtual member function (f2)
+// - inline defined virtual member function (f3)
+//
+// 1) We check for a generated 'call_target' for: 'f1', 'f2' and 'f3'.
+// 2) Check that the 'CBase' type is defined.
+
+struct CBase {
+ virtual void f1();
+ virtual void f2();
+ virtual void f3() {}
+};
+void CBase::f1() {}
+
+void bar(CBase *Base) {
+ Base->f1();
+ Base->f2();
+ Base->f3();
+
+ // Because this will instantiate the ctor, the CBase type should be defined.
+ CBase B;
+ B.f1();
+}
+
+// CHECK-BASE: %struct.CBase = type { ptr }
+
+// CHECK-BASE: define {{.*}} @_Z3barP5CBase{{.*}} {
+// CHECK-BASE: alloca %struct.CBase
+// CHECK-BASE: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target
[[BASE_F1_DCL:![0-9]+]]
+// CHECK-BASE: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target
[[BASE_F2_DCL:![0-9]+]]
+// CHECK-BASE: call void %5{{.*}} !dbg {{![0-9]+}}, !call_target
[[BASE_F3_DCL:![0-9]+]]
+// CHECK-BASE: call void @_ZN5CBaseC1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE: call void @_ZN5CBase2f1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE: }
+
+// CHECK-BASE: [[BASE_F1_DCL]] = {{.*}}!DISubprogram(name: "f1", linkageName:
"_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-BASE: [[BASE_F2_DCL]] = {{.*}}!DISubprogram(name: "f2", linkageName:
"_ZN5CBase2f2Ev", {{.*}}containingType
+// CHECK-BASE: [[BASE_F3_DCL]] = {{.*}}!DISubprogram(name: "f3", linkageName:
"_ZN5CBase2f3Ev", {{.*}}containingType
+
+// CHECK-BASE: [[BASE_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
+// CHECK-BASE: [[BASE_F3_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f3",
linkageName: "_ZN5CBase2f3Ev", {{.*}}DISPFlagDefinition
diff --git a/clang/test/DebugInfo/CXX/callsite-derived.cpp
b/clang/test/DebugInfo/CXX/callsite-derived.cpp
new file mode 100644
index 0000000000000..3338290bdd829
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-derived.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=constructor -dwarf-version=5 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-DERIVED
+
+// Simple base and derived class with virtual and static methods:
+// We check for:
+// - a generated 'call_target' for 'f1'.
+// - not generated 'call_target' for 'f3'.
+
+struct CBase {
+ virtual void f1() {}
+ static void f3();
+};
+
+void CBase::f3() {
+}
+
+void foo(CBase *Base) {
+ CBase::f3();
+}
+
+struct CDerived : public CBase {
+ void f1() {}
+};
+void foo(CDerived *Derived);
+
+int main() {
+ CDerived D;
+ foo(&D);
+
+ return 0;
+}
+
+void foo(CDerived *Derived) {
+ Derived->f1();
+}
+
+// CHECK-DERIVED: define {{.*}} @_Z3fooP5CBase{{.*}} {
+// CHECK-DERIVED: call void @_ZN5CBase2f3Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: define {{.*}} @main{{.*}} {
+// CHECK-DERIVED: call void @_ZN8CDerivedC1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: call void @_Z3fooP8CDerived{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: define {{.*}} @_ZN8CDerivedC1Ev{{.*}} {
+// CHECK-DERIVED: call void @_ZN8CDerivedC2Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: define {{.*}} @_Z3fooP8CDerived{{.*}} {
+// CHECK-DERIVED: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target
[[DERIVED_F1_DCL:![0-9]+]]
+// CHECK-DERIVED: }
+
+// CHECK-DERIVED: [[BASE_F1_DCL:![0-9]+]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-DERIVED: [[DERIVED_F1_DCL]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN8CDerived2f1Ev", {{.*}}containingType
+// CHECK-DERIVED: [[DERIVED_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN8CDerived2f1Ev", {{.*}}DISPFlagDefinition
+// CHECK-DERIVED: [[BASE_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
diff --git a/clang/test/DebugInfo/CXX/callsite-edges.cpp
b/clang/test/DebugInfo/CXX/callsite-edges.cpp
new file mode 100644
index 0000000000000..812cfc1fb4cf2
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/callsite-edges.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=constructor -dwarf-version=5 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-EDGES
+
+// The following are identified edge cases involving the method being called:
+// 1) Method is declared but not defined in current CU.
+// 2) Pure virtual method but not defined in current CU.
+// 3) Virtual method defined in a deeply nested structure hierarchy.
+
+//---------------------------------------------------------------------
+// 1) Method is declared but not defined in current CU - Pass.
+// Generate 'call_target' metadata for 'f1' and 'f2'.
+//---------------------------------------------------------------------
+struct CEmpty {
+ virtual void f1();
+ virtual void f2();
+};
+
+void CEmpty::f2() {
+}
+
+void edge_a(CEmpty *Empty) {
+ Empty->f1();
+ Empty->f2();
+}
+
+//---------------------------------------------------------------------
+// 2) Pure virtual method but not defined in current CU - Pass.
+// Generate 'call_target' metadata for 'f1' and 'f2'.
+//---------------------------------------------------------------------
+struct CBase {
+ virtual void f1() = 0;
+ virtual void f2();
+};
+
+void CBase::f2() {
+}
+
+void edge_b(CBase *Base) {
+ Base->f1();
+ Base->f2();
+}
+
+//---------------------------------------------------------------------
+// 3) Virtual method defined in a deeply nested structure hierarchy - Pass.
+// Generate 'call_target' metadata for 'd0', 'd1', 'd2' and 'd3'.
+//---------------------------------------------------------------------
+struct CD0 {
+ struct CD1 {
+ virtual void d1();
+ };
+
+ CD1 D1;
+ virtual void d0();
+};
+
+void CD0::d0() {}
+void CD0::CD1::d1() {}
+
+void edge_c(CD0 *D0) {
+ D0->d0();
+
+ CD0::CD1 *D1 = &D0->D1;
+ D1->d1();
+}
+
+// CHECK-EDGES: define {{.*}} @_Z6edge_aP6CEmpty{{.*}} {
+// CHECK-EDGES: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target
[[CEMPTY_F1_DCL:![0-9]+]]
+// CHECK-EDGES: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target
[[CEMPTY_F2_DCL:![0-9]+]]
+// CHECK-EDGES: }
+
+// CHECK-EDGES: define {{.*}} @_Z6edge_bP5CBase{{.*}} {
+// CHECK-EDGES: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target
[[CBASE_F1_DCL:![0-9]+]]
+// CHECK-EDGES: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target
[[CBASE_F2_DCL:![0-9]+]]
+// CHECK-EDGES: }
+
+// CHECK-EDGES: define {{.*}} @_Z6edge_cP3CD0{{.*}} {
+// CHECK-EDGES: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target
[[CD0_D0_DCL:![0-9]+]]
+// CHECK-EDGES: call void %4{{.*}} !dbg {{![0-9]+}}, !call_target
[[CD0_D1_DCL:![0-9]+]]
+// CHECK-EDGES: }
+
+// CHECK-EDGES: [[CD0_D1_DCL]] = {{.*}}!DISubprogram(name: "d1", linkageName:
"_ZN3CD03CD12d1Ev", {{.*}}containingType
+// CHECK-EDGES: [[CD0_D0_DCL]] = {{.*}}!DISubprogram(name: "d0", linkageName:
"_ZN3CD02d0Ev", {{.*}}containingType
+
+// CHECK-EDGES: [[CBASE_F1_DCL]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-EDGES: [[CBASE_F2_DCL]] = {{.*}}!DISubprogram(name: "f2",
linkageName: "_ZN5CBase2f2Ev", {{.*}}containingType
+// CHECK-EDGES: [[CEMPTY_F2_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f2",
linkageName: "_ZN6CEmpty2f2Ev", {{.*}}DISPFlagDefinition
+// CHECK-EDGES: [[CEMPTY_F2_DCL]] = {{.*}}!DISubprogram(name: "f2",
linkageName: "_ZN6CEmpty2f2Ev", {{.*}}containingType
+// CHECK-EDGES: [[CEMPTY_F1_DCL]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN6CEmpty2f1Ev", {{.*}}containingType
+// CHECK-EDGES: [[CBASE_F2_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f2",
linkageName: "_ZN5CBase2f2Ev", {{.*}}DISPFlagDefinition
+
+// CHECK-EDGES: [[CD0_D0_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "d0",
linkageName: "_ZN3CD02d0Ev", {{.*}}DISPFlagDefinition
+// CHECK-EDGES: [[CD0_D1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "d1",
linkageName: "_ZN3CD03CD12d1Ev", {{.*}}DISPFlagDefinition
diff --git
a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
new file mode 100644
index 0000000000000..b2b2eae95c800
--- /dev/null
+++
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang --target=x86_64-unknown-linux -c -g -O1 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK
+
+// Simple base and derived class with virtual:
+// We check for a generated 'DW_AT_LLVM_virtual_call_origin' for 'foo', that
+// corresponds to the 'call_target' metadata added to the indirect call
+// instruction.
+
+// Note: We should add a test case inside LLDB that make use of the
+// virtuality call-site target information in DWARF.
+
+struct CBaseOne {
+ virtual void foo(int &);
+};
+
+struct CDerivedOne : CBaseOne {
+ void foo(int &);
+};
+
+void CDerivedOne::foo(int &) {}
+
+struct CBaseTwo {
+ CDerivedOne *DerivedOne;
+};
+
+struct CDerivedTwo : CBaseTwo {
+ void bar(int &);
+};
+
+void CDerivedTwo::bar(int &j) { DerivedOne->foo(j); }
+
+// The IR generated looks like:
+//
+// define dso_local void @_ZN11CDerivedTwo3barERi(...) !dbg !40 {
+// entry:
+// ..
+// %vtable = load ptr, ptr %0, align 8
+// %vfn = getelementptr inbounds ptr, ptr %vtable, i64 0
+// %2 = load ptr, ptr %vfn, align 8
+// call void %2(...), !dbg !65, !call_target !25
+// ret void
+// }
+//
+// !25 = !DISubprogram(name: "foo", linkageName: "_ZN11CDerivedOne3fooERi",
...)
+// !40 = !DISubprogram(name: "bar", linkageName: "_ZN11CDerivedTwo3barERi",
...)
+// !65 = !DILocation(line: 25, column: 15, scope: !40)
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CDerivedOne")
+// CHECK: [[FOO_DCL:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK: DW_AT_name ("foo")
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CBaseOne")
+// CHECK: [[FOO_DEF:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK: DW_AT_call_all_calls (true)
+// CHECK: DW_AT_specification ([[FOO_DCL]] "{{.*}}foo{{.*}}")
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CDerivedTwo")
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_name ("bar")
+// CHECK: DW_TAG_structure_type
+// CHECK: DW_AT_name ("CBaseTwo")
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_call_all_calls (true)
+// CHECK: DW_AT_specification (0x{{.*}} "{{.*}}bar{{.*}}")
+// CHECK: DW_TAG_call_site
+// CHECK: DW_AT_call_target_clobbered (DW_OP_reg0 RAX)
+// CHECK: DW_AT_call_tail_call (true)
+// CHECK: DW_AT_call_pc (0x{{.*}})
+// CHECK: DW_AT_LLVM_virtual_call_origin ([[FOO_DCL]] "{{.*}}foo{{.*}}")
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def
b/llvm/include/llvm/BinaryFormat/Dwarf.def
index 75f1061c471c6..50b83884c851a 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -647,6 +647,7 @@ HANDLE_DW_AT(0x3e10, LLVM_address_space, 0, LLVM)
HANDLE_DW_AT(0x3e11, LLVM_lanes, 0, LLVM)
HANDLE_DW_AT(0x3e12, LLVM_lane_pc, 0, LLVM)
HANDLE_DW_AT(0x3e13, LLVM_vector_size, 0, LLVM)
+HANDLE_DW_AT(0x3e14, LLVM_virtual_call_origin, 0, LLVM)
// https://llvm.org/docs/AMDGPUUsage.html#address-space-identifier
HANDLE_DW_ASPACE(0x0, none)
diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h
b/llvm/include/llvm/CodeGen/MachineFunction.h
index edb8963ce42b6..26b6c457a45ba 100644
--- a/llvm/include/llvm/CodeGen/MachineFunction.h
+++ b/llvm/include/llvm/CodeGen/MachineFunction.h
@@ -526,11 +526,17 @@ class LLVM_ABI MachineFunction {
/// Callee type ids.
SmallVector<ConstantInt *, 4> CalleeTypeIds;
+ /// 'call_target' metadata for the DISubprogram. It is the declaration
+ /// or definition of the target function and might be indirect.
+ MDNode *CallTarget = nullptr;
+
CallSiteInfo() = default;
/// Extracts the numeric type id from the CallBase's callee_type Metadata,
/// and sets CalleeTypeIds. This is used as type id for the indirect call
in
/// the call graph section.
+ /// Extracts the MDNode from the CallBase's call_target Metadata to be used
+ /// during the construction of the debug info call site entries.
LLVM_ABI CallSiteInfo(const CallBase &CB);
};
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h
b/llvm/include/llvm/CodeGen/TargetLowering.h
index 37002d3bc227f..39699cb19a4b7 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -5936,6 +5936,10 @@ class LLVM_ABI TargetLowering : public
TargetLoweringBase {
LoadSDNode *OriginalLoad,
SelectionDAG &DAG) const;
+protected:
+ void setTypeIdForCallsiteInfo(const CallBase *CB, MachineFunction &MF,
+ MachineFunction::CallSiteInfo &CSInfo) const;
+
private:
SDValue foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
const SDLoc &DL, DAGCombinerInfo &DCI) const;
diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def
b/llvm/include/llvm/IR/FixedMetadataKinds.def
index 98129985714b2..0d79677d7079e 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -59,3 +59,4 @@ LLVM_FIXED_MD_KIND(MD_captures, "captures", 44)
LLVM_FIXED_MD_KIND(MD_alloc_token, "alloc_token", 45)
LLVM_FIXED_MD_KIND(MD_implicit_ref, "implicit.ref", 46)
LLVM_FIXED_MD_KIND(MD_nofpclass, "nofpclass", 47)
+LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 48)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index e87d3f3ee02a0..eb55b47dfde2b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1349,11 +1349,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
} else if (CalleeSP) {
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP, CalleeF);
assert(CalleeDIE && "Could not create DIE for call site entry origin");
- if (AddLinkageNamesToDeclCallOriginsForTuning(DD) &&
- !CalleeSP->isDefinition() &&
- !CalleeDIE->findAttribute(dwarf::DW_AT_linkage_name)) {
- addLinkageName(*CalleeDIE, CalleeSP->getLinkageName());
- }
+ addLinkageNamesToDeclarations(*DD, *CalleeSP, *CalleeDIE);
addDIEEntry(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin),
*CalleeDIE);
@@ -1891,3 +1887,12 @@ DIE *DwarfCompileUnit::getOrCreateSubprogramDIE(const
DISubprogram *SP,
return DwarfUnit::getOrCreateSubprogramDIE(SP, F, Minimal);
}
+
+void DwarfCompileUnit::addLinkageNamesToDeclarations(
+ const DwarfDebug &DD, const DISubprogram &CalleeSP, DIE &CalleeDIE) {
+ if (AddLinkageNamesToDeclCallOriginsForTuning(&DD) &&
+ !CalleeSP.isDefinition() &&
+ !CalleeDIE.findAttribute(dwarf::DW_AT_linkage_name)) {
+ addLinkageName(CalleeDIE, CalleeSP.getLinkageName());
+ }
+}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 04d4556c3ce52..ede02c169bffd 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -436,6 +436,10 @@ class DwarfCompileUnit final : public DwarfUnit {
void addBaseTypeRef(DIEValueList &Die, int64_t Idx);
MDNodeSetVector &getDeferredLocalDecls() { return DeferredLocalDecls; }
+
+ void addLinkageNamesToDeclarations(const DwarfDebug &DD,
+ const DISubprogram &CalleeSP,
+ DIE &CalleeDIE);
};
} // end namespace llvm
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index f8c2c753b91ce..042c98fa1c02f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -955,6 +955,30 @@ void DwarfDebug::constructCallSiteEntryDIEs(const
DISubprogram &SP,
return true;
};
+ // Create call_target connections for indirect calls.
+ auto addCallSiteTargetForIndirectCalls = [&](const MachineInstr *MI,
+ DIE &CallSiteDIE) {
+ const MachineFunction *MF = MI->getMF();
+ const auto &CalleesMap = MF->getCallSitesInfo();
+ auto CSInfo = CalleesMap.find(MI);
+ // Get the information for the call instruction.
+ if (CSInfo == CalleesMap.end() || !CSInfo->second.CallTarget)
+ return;
+
+ MDNode *CallTarget = CSInfo->second.CallTarget;
+ // Add DW_AT_LLVM_virtual_call_origin with the 'call_target' metadata.
+ assert(!CallSiteDIE.findAttribute(dwarf::DW_AT_LLVM_virtual_call_origin) &&
+ "DW_AT_LLVM_virtual_call_origin already exists");
+ const DISubprogram *CalleeSP = dyn_cast<DISubprogram>(CallTarget);
+ DIE *CalleeDIE = CU.getOrCreateSubprogramDIE(CalleeSP, nullptr);
+ assert(CalleeDIE && "Could not create DIE for call site entry origin");
+ CU.addDIEEntry(CallSiteDIE,
+
CU.getDwarf5OrGNUAttr(dwarf::DW_AT_LLVM_virtual_call_origin),
+ *CalleeDIE);
+ // Add DW_AT_linkage_name to the method declaration if needed.
+ CU.addLinkageNamesToDeclarations(*this, *CalleeSP, *CalleeDIE);
+ };
+
// Emit call site entries for each call or tail call in the function.
for (const MachineBasicBlock &MBB : MF) {
for (const MachineInstr &MI : MBB.instrs()) {
@@ -1052,6 +1076,9 @@ void DwarfDebug::constructCallSiteEntryDIEs(const
DISubprogram &SP,
ScopeDIE, CalleeSP, CalleeDecl, IsTail, PCAddr, CallAddr, CallTarget,
Offset, AllocSiteTy);
+ if (CallTarget.getReg())
+ addCallSiteTargetForIndirectCalls(TopLevelCallMI, CallSiteDIE);
+
// Optionally emit call-site-param debug info.
if (emitDebugEntryValues()) {
ParamSet Params;
@@ -1460,7 +1487,7 @@ void DwarfDebug::finalizeModuleInfo() {
TLOF.getDwarfMacinfoSection()->getBeginSymbol());
}
}
- }
+ }
// Emit all frontend-produced Skeleton CUs, i.e., Clang modules.
for (auto *CUNode : MMI->getModule()->debug_compile_units())
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index 9a48a0062549a..e5fa7da3d03b5 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -541,7 +541,7 @@ static void convertCallSiteObjects(yaml::MachineFunction
&YMF,
std::distance(CallI->getParent()->instr_begin(), CallI);
YmlCS.CallLocation = CallLocation;
- auto [ArgRegPairs, CalleeTypeIds] = CallSiteInfo;
+ auto [ArgRegPairs, CalleeTypeIds, _] = CallSiteInfo;
// Construct call arguments and theirs forwarding register info.
for (auto ArgReg : ArgRegPairs) {
yaml::CallSiteInfo::ArgRegPair YmlArgReg;
diff --git a/llvm/lib/CodeGen/MachineFunction.cpp
b/llvm/lib/CodeGen/MachineFunction.cpp
index fb35c7e62dad6..fe876fe4dc3e8 100644
--- a/llvm/lib/CodeGen/MachineFunction.cpp
+++ b/llvm/lib/CodeGen/MachineFunction.cpp
@@ -700,6 +700,9 @@ bool MachineFunction::needsFrameMoves() const {
}
MachineFunction::CallSiteInfo::CallSiteInfo(const CallBase &CB) {
+ if (MDNode *Node = CB.getMetadata(llvm::LLVMContext::MD_call_target))
+ CallTarget = Node;
+
// Numeric callee_type ids are only for indirect calls.
if (!CB.isIndirectCall())
return;
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 7d0f8c632ba18..9dacc28f439d6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -12804,3 +12804,17 @@ SDValue
TargetLowering::scalarizeExtractedVectorLoad(EVT ResultVT,
return Load;
}
+
+// Set type id for call site info and metadata 'call_target'.
+// We are filtering for:
+// a) The call-graph-section use case that wants to know about indirect
+// calls, or
+// b) We want to annotate indirect calls.
+void TargetLowering::setTypeIdForCallsiteInfo(
+ const CallBase *CB, MachineFunction &MF,
+ MachineFunction::CallSiteInfo &CSInfo) const {
+ if (CB && CB->isIndirectCall() &&
+ (MF.getTarget().Options.EmitCallGraphSection ||
+ MF.getTarget().Options.EmitCallSiteInfo))
+ CSInfo = MachineFunction::CallSiteInfo(*CB);
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index cd8a2b305a0f9..f8357ed216f5f 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -246,7 +246,8 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie
&Die,
// having both the raw value and the pretty-printed value is
// interesting. These attributes are handled below.
if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin ||
- Attr == DW_AT_call_origin || Attr == DW_AT_import) {
+ Attr == DW_AT_call_origin || Attr == DW_AT_import ||
+ Attr == DW_AT_LLVM_virtual_call_origin) {
if (const char *Name =
Die.getAttributeValueAsReferencedDie(FormValue).getName(
DINameKind::LinkageName))
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 7af6db793892b..98927e4d60595 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -9936,8 +9936,7 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
RetCCInfo.AnalyzeCallResult(Ins, RetCC);
// Set type id for call site info.
- if (MF.getTarget().Options.EmitCallGraphSection && CB &&
CB->isIndirectCall())
- CSInfo = MachineFunction::CallSiteInfo(*CB);
+ setTypeIdForCallsiteInfo(CB, MF, CSInfo);
// Check callee args/returns for SVE registers and set calling convention
// accordingly.
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp
b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 4004ace444eff..270d2a12dcc55 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -2057,8 +2057,7 @@
ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
GuardWithBTI = AFI->branchTargetEnforcement();
// Set type id for call site info.
- if (MF.getTarget().Options.EmitCallGraphSection && CB &&
CB->isIndirectCall())
- CSInfo = MachineFunction::CallSiteInfo(*CB);
+ setTypeIdForCallsiteInfo(CB, MF, CSInfo);
// Determine whether this is a non-secure function call.
if (CLI.CB && CLI.CB->getAttributes().hasFnAttr("cmse_nonsecure_call"))
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp
b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index c920e912f49ac..7e6b920e61b78 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3343,8 +3343,7 @@
MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Call site info for function parameters tracking and call base type info.
MachineFunction::CallSiteInfo CSInfo;
// Set type id for call site info.
- if (MF.getTarget().Options.EmitCallGraphSection && CB &&
CB->isIndirectCall())
- CSInfo = MachineFunction::CallSiteInfo(*CB);
+ setTypeIdForCallsiteInfo(CB, MF, CSInfo);
// Check if it's really possible to do a tail call.
// For non-musttail calls, restrict to functions that won't require $gp
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5f09ece63d3e5..c835821caf704 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -24554,8 +24554,7 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo
&CLI,
MachineFunction::CallSiteInfo CSInfo;
// Set type id for call site info.
- if (MF.getTarget().Options.EmitCallGraphSection && CB &&
CB->isIndirectCall())
- CSInfo = MachineFunction::CallSiteInfo(*CB);
+ setTypeIdForCallsiteInfo(CB, MF, CSInfo);
// Analyze the operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 92348689f57f0..c0e120dc30b86 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2078,8 +2078,7 @@
X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
report_fatal_error("X86 interrupts may not be called directly");
// Set type id for call site info.
- if (MF.getTarget().Options.EmitCallGraphSection && CB &&
CB->isIndirectCall())
- CSInfo = MachineFunction::CallSiteInfo(*CB);
+ setTypeIdForCallsiteInfo(CB, MF, CSInfo);
if (IsIndirectCall && !IsWin64 &&
M->getModuleFlag("import-call-optimization"))
diff --git a/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
b/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
index 3f7590adf9182..fe1980e3f5605 100644
--- a/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
+++ b/llvm/test/CodeGen/MIR/X86/callsite-emit-calleetypeid.ll
@@ -32,14 +32,13 @@
;; Test printer and parser with -emit-call-site-info only.
;; Test printer.
-;; Verify that fwdArgRegs is set, calleeTypeIds is not set.
+;; Verify that fwdArgRegs and calleeTypeIds are set.
; RUN: llc -mtriple=x86_64 -emit-call-site-info %s -stop-after=finalize-isel
-o %t2.mir
; RUN: cat %t2.mir | FileCheck %s --check-prefix=PRINTER_CSI
; PRINTER_CSI: name: main
; PRINTER_CSI: callSites:
; PRINTER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
-; PRINTER_CSI-NEXT: { arg: 0, reg: {{.*}} }
-; PRINTER_CSI-NOT: calleeTypeIds:
+; PRINTER_CSI-NEXT: { arg: 0, reg: {{.*}} }, calleeTypeIds:
;; Test parser.
@@ -49,8 +48,7 @@
; PARSER_CSI: name: main
; PARSER_CSI: callSites:
; PARSER_CSI-NEXT: - { bb: {{.*}}, offset: {{.*}}, fwdArgRegs:
-; PARSER_CSI-NEXT: { arg: 0, reg: {{.*}} }
-; PARSER_CSI-NOT: calleeTypeIds:
+; PARSER_CSI-NEXT: { arg: 0, reg: {{.*}} }, calleeTypeIds:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Test printer and parser with both -emit-call-site-info and
--call-graph-section.
>From c4519d309b2907a340e2a0d0121eca59b216e5ea Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <[email protected]>
Date: Fri, 20 Feb 2026 15:04:15 +0000
Subject: [PATCH 2/2] [clang][DebugInfo] Add virtuality call-site target
information in DWARF.
The virtuality calls-site target information is NOT generated
if DWARF version less than 5 is requested.
Fixes issues discovered after the initial patch landed:
- Add missing 'REQUIRES: x86-registered-target'
to fix buildbot failure:
https://lab.llvm.org/buildbot/#/builders/190/builds/36803
- Crash when building Fuchsia code on arm platforms with DWARF 4 and -O2
---
clang/lib/CodeGen/CGDebugInfo.cpp | 6 ++++
clang/lib/CodeGen/CGDebugInfo.h | 5 +--
clang/test/DebugInfo/CXX/callsite-base.cpp | 22 +++++++++++++
.../clang_llvm_roundtrip/callsite-crash.cpp | 20 ++++++++++++
.../clang_llvm_roundtrip/callsite-dwarf.cpp | 32 +++++++++++++++++--
5 files changed, 79 insertions(+), 6 deletions(-)
create mode 100644
cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0a77e0037dac0..401d8bc16d290 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2332,6 +2332,12 @@ CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl
*Method) const {
return CGM.getMangledName(Method);
}
+bool CGDebugInfo::shouldGenerateVirtualCallSite() const {
+ // Check general conditions for call site generation.
+ return ((getCallSiteRelatedAttrs() != llvm::DINode::FlagZero) &&
+ (CGM.getCodeGenOpts().DwarfVersion >= 5));
+}
+
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
assert(Method);
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 928bc8fdd9c5d..8e1eda2d93ac0 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -912,10 +912,7 @@ class CGDebugInfo {
llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
/// Returns true if we should generate call target information.
- bool shouldGenerateVirtualCallSite() const {
- // Check general conditions for call site generation.
- return (getCallSiteRelatedAttrs() != llvm::DINode::FlagZero);
- }
+ bool shouldGenerateVirtualCallSite() const;
};
/// A scoped helper to set the current debug location to the specified
diff --git a/clang/test/DebugInfo/CXX/callsite-base.cpp
b/clang/test/DebugInfo/CXX/callsite-base.cpp
index cf26d62a03c0b..399e62ede0dec 100644
--- a/clang/test/DebugInfo/CXX/callsite-base.cpp
+++ b/clang/test/DebugInfo/CXX/callsite-base.cpp
@@ -2,6 +2,10 @@
// RUN: -debug-info-kind=standalone -dwarf-version=5 -O1 %s \
// RUN: -o - | FileCheck %s -check-prefix CHECK-BASE
+// RUN: %clang_cc1 -triple=x86_64-linux -disable-llvm-passes -emit-llvm \
+// RUN: -debug-info-kind=standalone -dwarf-version=4 -O1 %s \
+// RUN: -o - | FileCheck %s -check-prefix CHECK-BASE-DW4
+
// Simple class with only virtual methods: inlined and not-inlined
//
// The following three scenarios are considered:
@@ -46,3 +50,21 @@ void bar(CBase *Base) {
// CHECK-BASE: [[BASE_F1_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f1",
linkageName: "_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
// CHECK-BASE: [[BASE_F3_DEF:![0-9]+]] = {{.*}}!DISubprogram(name: "f3",
linkageName: "_ZN5CBase2f3Ev", {{.*}}DISPFlagDefinition
+
+// CHECK-BASE-DW4: %struct.CBase = type { ptr }
+
+// CHECK-BASE-DW4: define {{.*}} @_Z3barP5CBase{{.*}} {
+// CHECK-BASE-DW4: alloca %struct.CBase
+// CHECK-BASE-DW4: call void %1{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void %3{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void %5{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void @_ZN5CBaseC1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: call void @_ZN5CBase2f1Ev{{.*}} !dbg {{![0-9]+}}
+// CHECK-BASE-DW4: }
+
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f1", linkageName:
"_ZN5CBase2f1Ev", {{.*}}containingType
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f2", linkageName:
"_ZN5CBase2f2Ev", {{.*}}containingType
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f3", linkageName:
"_ZN5CBase2f3Ev", {{.*}}containingType
+
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f1", linkageName:
"_ZN5CBase2f1Ev", {{.*}}DISPFlagDefinition
+// CHECK-BASE-DW4: {{.*}}!DISubprogram(name: "f3", linkageName:
"_ZN5CBase2f3Ev", {{.*}}DISPFlagDefinition
diff --git
a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp
new file mode 100644
index 0000000000000..745ac967528da
--- /dev/null
+++
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-crash.cpp
@@ -0,0 +1,20 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang --target=aarch64-unknown-fuchsia -c -g -O1 -gdwarf-4 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK
+
+struct Base {
+ virtual void foo();
+} *B;
+
+void bar() {
+ B->foo();
+}
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_GNU_all_call_sites (true)
+// CHECK: DW_AT_linkage_name ("_Z3barv")
+// CHECK: DW_TAG_GNU_call_site
+// CHECK: DW_AT_GNU_call_site_target_clobbered
+// CHECK: DW_AT_GNU_tail_call (true)
diff --git
a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
index b2b2eae95c800..9fe6df6a0f61d 100644
---
a/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
+++
b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp
@@ -1,10 +1,15 @@
-// RUN: %clang --target=x86_64-unknown-linux -c -g -O1 %s -o - | \
+// REQUIRES: x86-registered-target
+
+// RUN: %clang --target=x86_64-linux -c -g -O1 -gdwarf-5 %s -o - | \
// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK
+// RUN: %clang --target=x86_64-linux -c -g -O1 -gdwarf-4 %s -o - | \
+// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK-DW4
+
// Simple base and derived class with virtual:
// We check for a generated 'DW_AT_LLVM_virtual_call_origin' for 'foo', that
// corresponds to the 'call_target' metadata added to the indirect call
-// instruction.
+// instruction, when generating DWARF-5 or greater.
// Note: We should add a test case inside LLDB that make use of the
// virtuality call-site target information in DWARF.
@@ -69,3 +74,26 @@ void CDerivedTwo::bar(int &j) { DerivedOne->foo(j); }
// CHECK: DW_AT_call_tail_call (true)
// CHECK: DW_AT_call_pc (0x{{.*}})
// CHECK: DW_AT_LLVM_virtual_call_origin ([[FOO_DCL]] "{{.*}}foo{{.*}}")
+
+// CHECK-DW4: DW_TAG_compile_unit
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CDerivedOne")
+// CHECK-DW4: [[FOO_DCL:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_name ("foo")
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CBaseOne")
+// CHECK-DW4: [[FOO_DEF:0x[a-f0-9]+]]: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_GNU_all_call_sites (true)
+// CHECK-DW4: DW_AT_specification ([[FOO_DCL]] "{{.*}}foo{{.*}}")
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CDerivedTwo")
+// CHECK-DW4: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_name ("bar")
+// CHECK-DW4: DW_TAG_structure_type
+// CHECK-DW4: DW_AT_name ("CBaseTwo")
+// CHECK-DW4: DW_TAG_subprogram
+// CHECK-DW4: DW_AT_GNU_all_call_sites (true)
+// CHECK-DW4: DW_AT_specification (0x{{.*}} "{{.*}}bar{{.*}}")
+// CHECK-DW4: DW_TAG_GNU_call_site
+// CHECK-DW4: DW_AT_GNU_call_site_target_clobbered (DW_OP_reg0 RAX)
+// CHECK-DW4: DW_AT_GNU_tail_call (true)
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits