[clang][DebugInfo] Add virtuality call-site target information in DWARF. (#182510)
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 and
it is generated only for DWARF version 5 or greater.
This commit is contained in:
parent
be7aa6a2b7
commit
bc9d5b01d3
25 changed files with 451 additions and 23 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -4985,6 +4991,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) {
|
||||
|
|
|
|||
|
|
@ -683,6 +683,9 @@ public:
|
|||
/// 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,9 @@ private:
|
|||
/// 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;
|
||||
};
|
||||
|
||||
/// A scoped helper to set the current debug location to the specified
|
||||
|
|
|
|||
70
clang/test/DebugInfo/CXX/callsite-base.cpp
Normal file
70
clang/test/DebugInfo/CXX/callsite-base.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// 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
|
||||
|
||||
// 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:
|
||||
// - 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
|
||||
|
||||
// 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
|
||||
58
clang/test/DebugInfo/CXX/callsite-derived.cpp
Normal file
58
clang/test/DebugInfo/CXX/callsite-derived.cpp
Normal file
|
|
@ -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
|
||||
93
clang/test/DebugInfo/CXX/callsite-edges.cpp
Normal file
93
clang/test/DebugInfo/CXX/callsite-edges.cpp
Normal file
|
|
@ -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
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// 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)
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// 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, 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.
|
||||
|
||||
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{{.*}}")
|
||||
|
||||
// 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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -526,11 +526,17 @@ public:
|
|||
/// 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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5918,6 +5918,10 @@ public:
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,6 +436,10 @@ public:
|
|||
void addBaseTypeRef(DIEValueList &Die, int64_t Idx);
|
||||
|
||||
MDNodeSetVector &getDeferredLocalDecls() { return DeferredLocalDecls; }
|
||||
|
||||
void addLinkageNamesToDeclarations(const DwarfDebug &DD,
|
||||
const DISubprogram &CalleeSP,
|
||||
DIE &CalleeDIE);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -708,6 +708,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;
|
||||
|
|
|
|||
|
|
@ -12818,3 +12818,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -9944,8 +9944,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.
|
||||
|
|
|
|||
|
|
@ -2052,8 +2052,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"))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24573,8 +24573,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;
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue