diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index efacb3cc04c01..d475cfd9a66a5 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -6295,6 +6295,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, DI->EmitFuncDeclForCallSite( CI, DI->getFunctionType(CalleeDecl, ResTy, Args), CalleeGlobalDecl); } + // Collect call site target information. + DI->addCallTarget(CI->getCalledFunction(), CalleeDecl, CI); } return Ret; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index bda7b7487f59b..15d15ad08fd99 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2430,6 +2430,9 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( SPCache[Method->getCanonicalDecl()].reset(SP); + // Add the method declaration as a call target. + addCallTarget(MethodLinkageName, SP, /*CI=*/nullptr); + return SP; } @@ -4955,6 +4958,95 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, Fn->setSubprogram(SP); } +bool CGDebugInfo::generateVirtualCallSite() const { + // Check general conditions for call site generation. + return (getCallSiteRelatedAttrs() != llvm::DINode::FlagZero); +} + +// Set the 'call_target' metadata in the call instruction. +void CGDebugInfo::addCallTargetMetadata(llvm::MDNode *MD, llvm::CallBase *CI) { + if (!MD || !CI) + return; + CI->setMetadata(llvm::LLVMContext::MD_call_target, MD); +} + +// Finalize call_target generation. +void CGDebugInfo::finalizeCallTarget() { + if (!generateVirtualCallSite()) + return; + + for (auto &E : CallTargetCache) { + for (const auto &WH : E.second.second) { + llvm::CallBase *CI = dyn_cast_or_null(WH); + addCallTargetMetadata(E.second.first, CI); + } + } +} + +void CGDebugInfo::addCallTarget(StringRef Name, llvm::MDNode *MD, + llvm::CallBase *CI) { + if (!generateVirtualCallSite()) + return; + + // Record only indirect calls. + if (CI && !CI->isIndirectCall()) + return; + + // Nothing to do. + if (Name.empty()) + return; + + auto It = CallTargetCache.find(Name); + if (It == CallTargetCache.end()) { + // First time we see 'Name'. Insert record for later finalize. + InstrList List; + if (CI) + List.push_back(CI); + CallTargetCache.try_emplace(Name, MD, std::move(List)); + } else { + if (MD) + It->second.first.reset(MD); + if (CI) { + InstrList &List = It->second.second; + List.push_back(CI); + } + } +} + +void CGDebugInfo::addCallTarget(llvm::Function *F, const FunctionDecl *FD, + llvm::CallBase *CI) { + if (!generateVirtualCallSite()) + return; + + if (!F && !FD) + return; + + // Ignore method types that never can be indirect calls. + if (!F && (isa(FD) || isa(FD) || + FD->hasAttr())) + return; + + StringRef Name = (F && F->hasName()) ? F->getName() : CGM.getMangledName(FD); + addCallTarget(Name, /*MD=*/nullptr, CI); +} + +void CGDebugInfo::removeCallTarget(StringRef Name) { + if (!generateVirtualCallSite()) + return; + + auto It = CallTargetCache.find(Name); + if (It != CallTargetCache.end()) + CallTargetCache.erase(It); +} + +void CGDebugInfo::removeCallTarget(llvm::Function *F) { + if (!generateVirtualCallSite()) + return; + + if (F && F->hasName()) + removeCallTarget(F->getName()); +} + void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke, QualType CalleeType, GlobalDecl CalleeGlobalDecl) { @@ -4978,9 +5070,15 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke, // If there is no DISubprogram attached to the function being called, // create the one describing the function in order to have complete // call site debug info. - if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined()) + if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined()) { EmitFunctionDecl(CalleeGlobalDecl, CalleeDecl->getLocation(), CalleeType, Func); + if (Func->getSubprogram()) { + // For each call instruction emitted, add the call site target metadata. + llvm::DISubprogram *SP = Func->getSubprogram(); + addCallTarget(SP->getLinkageName(), SP, /*CI=*/nullptr); + } + } } void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) { @@ -5082,8 +5180,13 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn) { } FnBeginRegionCount.pop_back(); - if (Fn && Fn->getSubprogram()) + if (Fn && Fn->getSubprogram()) { + // For each call instruction emitted, add the call site target metadata. + llvm::DISubprogram *SP = Fn->getSubprogram(); + addCallTarget(SP->getLinkageName(), SP, /*CI=*/nullptr); + DBuilder.finalizeSubprogram(Fn->getSubprogram()); + } } CGDebugInfo::BlockByRefType @@ -6498,6 +6601,9 @@ void CGDebugInfo::finalize() { if (auto MD = TypeCache[RT]) DBuilder.retainType(cast(MD)); + // Generate call_target information. + finalizeCallTarget(); + DBuilder.finalize(); } diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 2378bdd780b3b..40b8db0299f04 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -682,6 +682,15 @@ class CGDebugInfo { /// that it is supported and enabled. llvm::DINode::DIFlags getCallSiteRelatedAttrs() const; + /// Add call target information. + void addCallTarget(StringRef Name, llvm::MDNode *MD, llvm::CallBase *CI); + void addCallTarget(llvm::Function *F, const FunctionDecl *FD, + llvm::CallBase *CI); + + /// Remove a call target entry for the given name or function. + void removeCallTarget(StringRef Name); + void removeCallTarget(llvm::Function *F); + 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 @@ -903,6 +912,25 @@ 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; + + /// For each 'DISuprogram' we store a list of call instructions 'CallBase' + /// that indirectly call such 'DISuprogram'. We use its linkage name to + /// update such list. + /// The 'CallTargetCache' is updated in the following scenarios: + /// - Both 'CallBase' and 'MDNode' are ready available. + /// - If only the 'CallBase' or 'MDNode' are are available, the partial + /// information is added and later is completed when the missing item + /// ('CallBase' or 'MDNode') is available. + using InstrList = llvm::SmallVector; + using CallTargetEntry = std::pair; + llvm::SmallDenseMap CallTargetCache; + + /// Generate call target information. + bool generateVirtualCallSite() const; + + /// Add 'call_target' metadata to the 'call' instruction. + void addCallTargetMetadata(llvm::MDNode *MD, llvm::CallBase *CI); + void finalizeCallTarget(); }; /// A scoped helper to set the current debug location to the specified diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 88628530cf66b..6d83b5fdd0e1b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1510,6 +1510,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, // Clear non-distinct debug info that was possibly attached to the function // due to an earlier declaration without the nodebug attribute Fn->setSubprogram(nullptr); + if (CGDebugInfo *DI = getDebugInfo()) + DI->removeCallTarget(Fn); // Disable debug info indefinitely for this function DebugInfo = nullptr; } diff --git a/clang/test/DebugInfo/CXX/callsite-base.cpp b/clang/test/DebugInfo/CXX/callsite-base.cpp new file mode 100644 index 0000000000000..7dbcbfe15b5cc --- /dev/null +++ b/clang/test/DebugInfo/CXX/callsite-base.cpp @@ -0,0 +1,36 @@ +// Simple class with only virtual methods: inlined and not-inlined +// We check for a generated 'call_target' for: +// - 'one', 'two' and 'three'. + +class CBase { +public: + virtual void one(); + virtual void two(); + virtual void three() {} +}; +void CBase::one() {} + +void bar(CBase *Base) { + Base->one(); + Base->two(); + Base->three(); + + CBase B; + B.one(); +} + +// 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-BASE + +// CHECK-BASE: define {{.*}} @_Z3barP5CBase{{.*}} { +// CHECK-BASE-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_ONE:![0-9]+]] +// CHECK-BASE-DAG: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_TWO:![0-9]+]] +// CHECK-BASE-DAG: call void %5{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_THREE:![0-9]+]] +// CHECK-BASE-DAG: call void @_ZN5CBaseC2Ev{{.*}} !dbg {{![0-9]+}} +// CHECK-BASE-DAG: call void @_ZN5CBase3oneEv{{.*}} !dbg {{![0-9]+}} +// CHECK-BASE: } + +// CHECK-BASE-DAG: [[BASE_ONE]] = {{.*}}!DISubprogram(name: "one", linkageName: "_ZN5CBase3oneEv" +// CHECK-BASE-DAG: [[BASE_TWO]] = {{.*}}!DISubprogram(name: "two", linkageName: "_ZN5CBase3twoEv" +// CHECK-BASE-DAG: [[BASE_THREE]] = {{.*}}!DISubprogram(name: "three", linkageName: "_ZN5CBase5threeEv" diff --git a/clang/test/DebugInfo/CXX/callsite-derived.cpp b/clang/test/DebugInfo/CXX/callsite-derived.cpp new file mode 100644 index 0000000000000..da918114de800 --- /dev/null +++ b/clang/test/DebugInfo/CXX/callsite-derived.cpp @@ -0,0 +1,77 @@ +// Simple base and derived class with virtual and static methods: +// We check for a generated 'call_target' for: +// - 'one', 'two' and 'three'. + +class CBase { +public: + virtual void one(bool Flag) {} + virtual void two(int P1, char P2) {} + static void three(); +}; + +void CBase::three() { +} +void bar(CBase *Base); + +void foo(CBase *Base) { + CBase::three(); +} + +class CDerived : public CBase { +public: + void one(bool Flag) {} + void two(int P1, char P2) {} +}; +void foo(CDerived *Derived); + +int main() { + CBase B; + bar(&B); + + CDerived D; + foo(&D); + + return 0; +} + +void bar(CBase *Base) { + Base->two(77, 'a'); +} + +void foo(CDerived *Derived) { + Derived->one(true); +} + +// 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 + +// CHECK-DERIVED: define {{.*}} @_Z3fooP5CBase{{.*}} { +// CHECK-DERIVED-DAG: call void @_ZN5CBase5threeEv{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED: } + +// CHECK-DERIVED: define {{.*}} @main{{.*}} { +// CHECK-DERIVED-DAG: call void @_ZN5CBaseC1Ev{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED-DAG: call void @_Z3barP5CBase{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED-DAG: call void @_ZN8CDerivedC1Ev{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED-DAG: call void @_Z3fooP8CDerived{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED: } + +// CHECK-DERIVED: define {{.*}} @_ZN5CBaseC1Ev{{.*}} { +// CHECK-DERIVED-DAG: call void @_ZN5CBaseC2Ev{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED: } + +// CHECK-DERIVED: define {{.*}} @_Z3barP5CBase{{.*}} { +// CHECK-DERIVED-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[BASE_TWO:![0-9]+]] +// CHECK-DERIVED: } + +// CHECK-DERIVED: define {{.*}} @_ZN8CDerivedC1Ev{{.*}} { +// CHECK-DERIVED-DAG: call void @_ZN8CDerivedC2Ev{{.*}} !dbg {{![0-9]+}} +// CHECK-DERIVED: } + +// CHECK-DERIVED: define {{.*}} @_Z3fooP8CDerived{{.*}} { +// CHECK-DERIVED-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[DERIVED_ONE:![0-9]+]] +// CHECK-DERIVED: } + +// CHECK-DERIVED-DAG: [[BASE_TWO]] = {{.*}}!DISubprogram(name: "two", linkageName: "_ZN5CBase3twoEic" +// CHECK-DERIVED-DAG: [[DERIVED_ONE]] = {{.*}}!DISubprogram(name: "one", linkageName: "_ZN8CDerived3oneEb" diff --git a/clang/test/DebugInfo/CXX/callsite-edges.cpp b/clang/test/DebugInfo/CXX/callsite-edges.cpp new file mode 100644 index 0000000000000..d8d620de245db --- /dev/null +++ b/clang/test/DebugInfo/CXX/callsite-edges.cpp @@ -0,0 +1,109 @@ +// Check edge cases: + +//--------------------------------------------------------------------- +// Method is declared but not defined in current CU - Fail. +// No debug information entry is generated for 'one'. +// Generate 'call_target' metadata only for 'two'. +//--------------------------------------------------------------------- +class CEmpty { +public: + virtual void one(bool Flag); + virtual void two(int P1, char P2); +}; + +void CEmpty::two(int P1, char P2) { +} + +void edge_a(CEmpty *Empty) { + Empty->one(false); + Empty->two(77, 'a'); +} + +//--------------------------------------------------------------------- +// Pure virtual method but not defined in current CU - Pass. +// Generate 'call_target' metadata for 'one' and 'two'. +//--------------------------------------------------------------------- +class CBase { +public: + virtual void one(bool Flag) = 0; + virtual void two(int P1, char P2); +}; + +void CBase::two(int P1, char P2) { +} + +void edge_b(CBase *Base) { + Base->one(false); + Base->two(77, 'a'); +} + +//--------------------------------------------------------------------- +// Virtual method defined very deeply - Pass. +// Generate 'call_target' metadata for 'd0', 'd1', 'd2' and 'd3'. +//--------------------------------------------------------------------- +struct CDeep { + struct CD1 { + struct CD2 { + struct CD3 { + virtual void d3(int P3); + }; + + CD3 D3; + virtual void d2(int P2); + }; + + CD2 D2; + virtual void d1(int P1); + }; + + CD1 D1; + virtual void d0(int P); +}; + +void CDeep::d0(int P) {} +void CDeep::CD1::d1(int P1) {} +void CDeep::CD1::CD2::d2(int P2) {} +void CDeep::CD1::CD2::CD3::d3(int P3) {} + +void edge_c(CDeep *Deep) { + Deep->d0(0); + + CDeep::CD1 *D1 = &Deep->D1; + D1->d1(1); + + CDeep::CD1::CD2 *D2 = &D1->D2; + D2->d2(2); + + CDeep::CD1::CD2::CD3 *D3 = &D2->D3; + D3->d3(3); +} + +// 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 + +// CHECK-EDGES: define {{.*}} @_Z6edge_aP6CEmpty{{.*}} { +// CHECK-EDGES-DAG: call void %1{{.*}} !dbg {{![0-9]+}} +// CHECK-EDGES-DAG: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[CEMPTY_TWO:![0-9]+]] +// CHECK-EDGES: } + +// CHECK-EDGES: define {{.*}} @_Z6edge_bP5CBase{{.*}} { +// CHECK-EDGES-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[CBASE_ONE:![0-9]+]] +// CHECK-EDGES-DAG: call void %3{{.*}} !dbg {{![0-9]+}}, !call_target [[CBASE_TWO:![0-9]+]] +// CHECK-EDGES: } + +// CHECK-EDGES: define {{.*}} @_Z6edge_cP5CDeep{{.*}} { +// CHECK-EDGES-DAG: call void %1{{.*}} !dbg {{![0-9]+}}, !call_target [[CDEEP_D0:![0-9]+]] +// CHECK-EDGES-DAG: call void %4{{.*}} !dbg {{![0-9]+}}, !call_target [[CDEEP_D1:![0-9]+]] +// CHECK-EDGES-DAG: call void %7{{.*}} !dbg {{![0-9]+}}, !call_target [[CDEEP_D2:![0-9]+]] +// CHECK-EDGES-DAG: call void %10{{.*}} !dbg {{![0-9]+}}, !call_target [[CDEEP_D3:![0-9]+]] +// CHECK-EDGES: } + +// CHECK-EDGES-DAG: [[CEMPTY_TWO]] = {{.*}}!DISubprogram(name: "two", linkageName: "_ZN6CEmpty3twoEic" +// CHECK-EDGES-DAG: [[CBASE_ONE]] = {{.*}}!DISubprogram(name: "one", linkageName: "_ZN5CBase3oneEb" +// CHECK-EDGES-DAG: [[CBASE_TWO]] = {{.*}}!DISubprogram(name: "two", linkageName: "_ZN5CBase3twoEic" + +// CHECK-EDGES-DAG: [[CDEEP_D0]] = {{.*}}!DISubprogram(name: "d0", linkageName: "_ZN5CDeep2d0Ei" +// CHECK-EDGES-DAG: [[CDEEP_D1]] = {{.*}}!DISubprogram(name: "d1", linkageName: "_ZN5CDeep3CD12d1Ei" +// CHECK-EDGES-DAG: [[CDEEP_D2]] = {{.*}}!DISubprogram(name: "d2", linkageName: "_ZN5CDeep3CD13CD22d2Ei" +// CHECK-EDGES-DAG: [[CDEEP_D3]] = {{.*}}!DISubprogram(name: "d3", linkageName: "_ZN5CDeep3CD13CD23CD32d3Ei" 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..0a7622330083c --- /dev/null +++ b/cross-project-tests/debuginfo-tests/clang_llvm_roundtrip/callsite-dwarf.cpp @@ -0,0 +1,67 @@ +// Simple base and derived class with virtual: +// We check for a generated 'DW_AT_call_origin' for 'foo', that corresponds +// to the 'call_target' metadata added to the indirect call instruction. + +class 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) + +// RUN: %clang --target=x86_64-unknown-linux -c -g -O1 %s -o - | \ +// RUN: llvm-dwarfdump --debug-info - | FileCheck %s --check-prefix=CHECK + +// 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_class_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 (DW_OP_reg0 RAX) +// CHECK: DW_AT_call_tail_call (true) +// CHECK: DW_AT_call_pc (0x{{.*}}) +// CHECK: DW_AT_call_origin ([[FOO_DEF]] "{{.*}}foo{{.*}}") diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index ef783f276b7d4..49aebb850d109 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -518,11 +518,17 @@ class LLVM_ABI MachineFunction { /// Callee type ids. SmallVector CalleeTypeIds; + /// 'call_target' metadata for the DISubprogram. It is the declaration + /// or definition of the target function and might be indirect. + MDNode *MD = 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/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def index 74746cced6f23..00097e34e8d72 100644 --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -57,3 +57,4 @@ LLVM_FIXED_MD_KIND(MD_callee_type, "callee_type", 42) LLVM_FIXED_MD_KIND(MD_nofree, "nofree", 43) LLVM_FIXED_MD_KIND(MD_captures, "captures", 44) LLVM_FIXED_MD_KIND(MD_alloc_token, "alloc_token", 45) +LLVM_FIXED_MD_KIND(MD_call_target, "call_target", 46) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index fde48a30a8203..5eb1b555e3005 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -916,6 +916,27 @@ 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.MD) + return; + + MDNode *MD = CSInfo->second.MD; + // Add DW_AT_call_origin with the 'call_target' metadata. + assert(!CallSiteDIE.findAttribute(dwarf::DW_AT_call_origin) && + "DW_AT_call_origin already exists"); + DIE *CalleeDIE = + CU.getOrCreateSubprogramDIE(dyn_cast(MD), nullptr); + assert(CalleeDIE && "Could not create DIE for call site entry origin"); + CU.addDIEEntry(CallSiteDIE, CU.getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin), + *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()) { @@ -1008,6 +1029,9 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, CU.constructCallSiteEntryDIE(ScopeDIE, CalleeSP, CalleeDecl, IsTail, PCAddr, CallAddr, CallReg, AllocSiteTy); + if (CallReg) + addCallSiteTargetForIndirectCalls(TopLevelCallMI, CallSiteDIE); + // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { ParamSet Params; @@ -1415,7 +1439,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 1d54d72336860..e51f1d80d550f 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -537,7 +537,7 @@ static void convertCallSiteObjects(yaml::MachineFunction &YMF, std::distance(CallI->getParent()->instr_begin(), CallI); YmlCS.CallLocation = CallLocation; - auto [ArgRegPairs, CalleeTypeIds] = CallSiteInfo; + auto [ArgRegPairs, CalleeTypeIds, MD] = 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 bfa5ab274c686..fedfd9be8b50f 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)) + MD = Node; + // Numeric callee_type ids are only for indirect calls. if (!CB.isIndirectCall()) return; diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index eaa10ef031989..4d7a246f2ccad 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -9418,8 +9418,14 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI, *DAG.getContext()); RetCCInfo.AnalyzeCallResult(Ins, RetCC); - // Set type id for call site info. - if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall()) + // 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. + if (CB && CB->isIndirectCall() && + (MF.getTarget().Options.EmitCallGraphSection || + MF.getTarget().Options.EmitCallSiteInfo)) CSInfo = MachineFunction::CallSiteInfo(*CB); // Check callee args/returns for SVE registers and set calling convention diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 92fae71121a81..690584facc84a 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2316,8 +2316,14 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, !Subtarget->noBTIAtReturnTwice()) GuardWithBTI = AFI->branchTargetEnforcement(); - // Set type id for call site info. - if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall()) + // 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. + if (CB && CB->isIndirectCall() && + (MF.getTarget().Options.EmitCallGraphSection || + MF.getTarget().Options.EmitCallSiteInfo)) CSInfo = MachineFunction::CallSiteInfo(*CB); // Determine whether this is a non-secure function call. diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index 2fd73275721b1..c7d3247a7e758 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -3400,8 +3400,15 @@ 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()) + + // 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. + if (CB && CB->isIndirectCall() && + (MF.getTarget().Options.EmitCallGraphSection || + MF.getTarget().Options.EmitCallSiteInfo)) CSInfo = MachineFunction::CallSiteInfo(*CB); // Check if it's really possible to do a tail call. Restrict it to functions diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 637f1943b8511..0cf1a862db501 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -23601,8 +23601,14 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, MachineFunction &MF = DAG.getMachineFunction(); MachineFunction::CallSiteInfo CSInfo; - // Set type id for call site info. - if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall()) + // 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. + if (CB && CB->isIndirectCall() && + (MF.getTarget().Options.EmitCallGraphSection || + MF.getTarget().Options.EmitCallSiteInfo)) CSInfo = MachineFunction::CallSiteInfo(*CB); // Analyze the operands of the call, assigning locations to each operand. diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp index a61bbe56d9c26..1c56e77b1335f 100644 --- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp +++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp @@ -2050,8 +2050,14 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (CallConv == CallingConv::X86_INTR) 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()) + // 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. + if (CB && CB->isIndirectCall() && + (MF.getTarget().Options.EmitCallGraphSection || + MF.getTarget().Options.EmitCallSiteInfo)) CSInfo = MachineFunction::CallSiteInfo(*CB); if (IsIndirectCall && !IsWin64 && 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.