From 3c805fd795c14c829012e922a3d3ac40462b67ac Mon Sep 17 00:00:00 2001 From: prabhukr Date: Fri, 19 Sep 2025 15:01:59 -0700 Subject: [PATCH 01/18] Callgraph section format changes. --- llvm/docs/CallGraphSection.md | 29 +++++++ llvm/include/llvm/CodeGen/AsmPrinter.h | 6 +- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 90 +++++++++++----------- 3 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 llvm/docs/CallGraphSection.md diff --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md new file mode 100644 index 0000000000000..3e4f107572716 --- /dev/null +++ b/llvm/docs/CallGraphSection.md @@ -0,0 +1,29 @@ +# .callgraph Section Layout + +The `.callgraph` section is used to store call graph information for each function, which can be used for post-link analyses and optimizations. The section contains a series of records, with each record corresponding to a single function. + +For efficiency, we make a distinction between direct and indirect call data. For direct calls, we record the unique callees, not the location of each individual call. For indirect calls, we record the location of each call site and the type ID of the callee. Post link analysis scripts which utilize this information to reconstuct the program call graph can potentially receive more information regarding indirect callsites from the user to improve the precision of the call graph. + +## Per Function Record Layout + +Each record in the `.callgraph` section has the following binary layout: + +| Field | Type | Size (bits) | Description | +| ---------------------------- | ------------- | ----------- | ------------------------------------------------------------------------------------------------------- | +| Format Version | `uint32_t` | 32 | The version of the record format. The current version is 0. | +| Function Entry PC | `uintptr_t` | 32/64 | The address of the function's entry point. | +| Function Kind | `uint8_t` | 8 | An enum indicating the function's properties (e.g., if it's an indirect call target). | +| Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is **only** present if `Function Kind` is `INDIRECT_TARGET_KNOWN_TID`. | +| Number of Indirect Callsites | `uint32_t` | 32 | The number of indirect call sites within the function. | +| Indirect Callsites Array | `Callsite[]` | Variable | An array of `Callsite` records, with a length of `Number of Indirect Callsites`. | +| Number of Unique Direct Callees | `uint32_t` | 32 | The number of unique direct call destinations from this function. | +| Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses, with a length of `Number of Direct Callees`. | + +### Indirect Callsite Record Layout + +Each record in the `Indirect Callsites Array` has the following layout: + +| Field | Type | Size (bits) | Description | +| ----------------- | ----------- | ----------- | ----------------------------------------- | +| Type ID | `uint64_t` | 64 | The type ID of the indirect call target. | +| Callsite PC | `uintptr_t` | 32/64 | The address of the indirect call site. | diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 4c744a2c0a4d2..8266c91997f37 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -200,13 +200,13 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { /// Map type identifiers to callsite labels. Labels are generated for each /// indirect callsite in the function. - SmallVector> CallSiteLabels; + SmallVector> IndirectCallsites; SmallSet DirectCallees; }; /// Enumeration of function kinds, and their mapping to function kind values /// stored in callgraph section entries. - enum class FunctionKind : uint64_t { + enum class FunctionKind : uint8_t { /// Function cannot be target to indirect calls. NOT_INDIRECT_TARGET = 0, @@ -217,7 +217,7 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { INDIRECT_TARGET_KNOWN_TID = 2, }; - enum CallGraphSectionFormatVersion : uint64_t { + enum CallGraphSectionFormatVersion : uint32_t { V_0 = 0, }; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 701a6a2f0f7a0..a78c9829b40d6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1685,58 +1685,56 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, OutStreamer->pushSection(); OutStreamer->switchSection(FuncCGSection); - // Emit format version number. - OutStreamer->emitInt64(CallGraphSectionFormatVersion::V_0); - - // Emit function's self information, which is composed of: - // 1) FunctionEntryPc - // 2) FunctionKind: Whether the function is indirect target, and if so, - // whether its type id is known. - // 3) FunctionTypeId: Emit only when the function is an indirect target - // and its type id is known. - - // Emit function entry pc. - const MCSymbol *FunctionSymbol = getFunctionBegin(); - OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); - - // If this function has external linkage or has its address taken and - // it is not a callback, then anything could call it. - const Function &F = MF.getFunction(); - bool IsIndirectTarget = - !F.hasLocalLinkage() || F.hasAddressTaken(nullptr, - /*IgnoreCallbackUses=*/true, - /*IgnoreAssumeLikeCalls=*/true, - /*IgnoreLLVMUsed=*/false); - - // FIXME: FunctionKind takes a few values but emitted as a 64-bit value. - // Can be optimized to occupy 2 bits instead. - // Emit function kind, and type id if available. - if (!IsIndirectTarget) { - OutStreamer->emitInt64( - static_cast(FunctionKind::NOT_INDIRECT_TARGET)); - } else { + auto EmitFunctionKindAndTypeId = [&]() { + const Function &F = MF.getFunction(); + // If this function has external linkage or has its address taken and + // it is not a callback, then anything could call it. + bool IsIndirectTarget = !F.hasLocalLinkage() || + F.hasAddressTaken(nullptr, + /*IgnoreCallbackUses=*/true, + /*IgnoreAssumeLikeCalls=*/true, + /*IgnoreLLVMUsed=*/false); + if (!IsIndirectTarget) { + OutStreamer->emitInt8( + static_cast(FunctionKind::NOT_INDIRECT_TARGET)); + return; + } if (const auto *TypeId = extractNumericCGTypeId(F)) { - OutStreamer->emitInt64( - static_cast(FunctionKind::INDIRECT_TARGET_KNOWN_TID)); + OutStreamer->emitInt8( + static_cast(FunctionKind::INDIRECT_TARGET_KNOWN_TID)); OutStreamer->emitInt64(TypeId->getZExtValue()); - } else { - OutStreamer->emitInt64( - static_cast(FunctionKind::INDIRECT_TARGET_UNKNOWN_TID)); + return; } - } + OutStreamer->emitInt8( + static_cast(FunctionKind::INDIRECT_TARGET_UNKNOWN_TID)); + }; - // Emit callsite labels, where each element is a pair of type id and - // indirect callsite pc. - const auto &CallSiteLabels = FuncCGInfo.CallSiteLabels; - OutStreamer->emitInt64(CallSiteLabels.size()); - for (const auto &[TypeId, Label] : CallSiteLabels) { + // Emit function's call graph information. + // 1) CallGraphSectionFormatVersion + // 2) Function entry PC. + // 3) FunctionKind: Whether the function is indirect target, and if so, + // whether its type id is known. + // 4) FunctionTypeID if the function is indirect target, and its type id is + // known. + // 5) Number of indirect callsites. + // 6) For each indirect callsite, its + // callsite PC and callee's expected type id. + // 7) Number of unique direct callees. + // 8) For each unique direct callee, the callee's PC. + + OutStreamer->emitInt32(CallGraphSectionFormatVersion::V_0); + const MCSymbol *FunctionSymbol = getFunctionBegin(); + OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); + EmitFunctionKindAndTypeId(); + const auto &IndirectCallsites = FuncCGInfo.IndirectCallsites; + OutStreamer->emitInt32(IndirectCallsites.size()); + const auto &DirectCallees = FuncCGInfo.DirectCallees; + for (const auto &[TypeId, Label] : IndirectCallsites) { OutStreamer->emitInt64(TypeId); OutStreamer->emitSymbolValue(Label, TM.getProgramPointerSize()); } - FuncCGInfo.CallSiteLabels.clear(); - - const auto &DirectCallees = FuncCGInfo.DirectCallees; - OutStreamer->emitInt64(DirectCallees.size()); + FuncCGInfo.IndirectCallsites.clear(); + OutStreamer->emitInt32(DirectCallees.size()); for (const auto &CalleeSymbol : DirectCallees) { OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize()); } @@ -1908,7 +1906,7 @@ void AsmPrinter::handleCallsiteForCallgraph( MCSymbol *S = MF->getContext().createTempSymbol(); OutStreamer->emitLabel(S); uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue(); - FuncCGInfo.CallSiteLabels.emplace_back(CalleeTypeIdVal, S); + FuncCGInfo.IndirectCallsites.emplace_back(CalleeTypeIdVal, S); } } From 6af8347010ffc39a13911595cb4b3300236686cd Mon Sep 17 00:00:00 2001 From: prabhukr Date: Fri, 19 Sep 2025 16:13:36 -0700 Subject: [PATCH 02/18] Fix tests. --- llvm/test/CodeGen/X86/call-graph-section-assembly.ll | 6 +++--- llvm/test/CodeGen/X86/call-graph-section-tailcall.ll | 4 +++- llvm/test/CodeGen/X86/call-graph-section.ll | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index f0dbc31222c89..e2f799ceb31ef 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -34,10 +34,10 @@ entry: ; CHECK: .section .callgraph,"o",@progbits,.text -; CHECK-NEXT: .quad 0 +; CHECK-NEXT: .long 0 ; CHECK-NEXT: .quad [[LABEL_FUNC]] -; CHECK-NEXT: .quad 1 -; CHECK-NEXT: .quad 3 +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .long 3 !0 = !{!1} !1 = !{i64 0, !"_ZTSFvE.generalized"} ;; Test for MD5 hash of _ZTSFvE.generalized and the generated temporary callsite label. diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll index fa14a98008b45..a83df51f702ab 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll @@ -29,6 +29,8 @@ declare !type !2 i32 @bar(i8 signext) !0 = !{i64 0, !"_ZTSFiPvcE.generalized"} !1 = !{!2} -; CHECK-DAG: 5486bc59 814b8e30 +;; Verify that the type id 0x308e4b8159bc8654 is in section. +; CHECK: 5486bc 59814b8e +; CHECK-NEXT: 0x00000020 30000000 00000000 00000000 00000000 !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{i64 0, !"_ZTSFiiE.generalized"} diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll b/llvm/test/CodeGen/X86/call-graph-section.ll index 66d009cf1221d..37f1e8e2acf16 100644 --- a/llvm/test/CodeGen/X86/call-graph-section.ll +++ b/llvm/test/CodeGen/X86/call-graph-section.ll @@ -25,12 +25,12 @@ entry: ; CHECK: Hex dump of section '.callgraph': -; CHECK-DAG: 2444f731 f5eecb3e +; CHECK-DAG: 2444f7 31f5eecb 3e !0 = !{i64 0, !"_ZTSFvE.generalized"} !1 = !{!0} -; CHECK-DAG: 5486bc59 814b8e30 +; CHECK-DAG: 5486bc 59814b8e 30 !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{!2} -; CHECK-DAG: 7ade6814 f897fd77 +; CHECK-DAG: 7ade68 14f897fd 77 !4 = !{!5} !5 = !{i64 0, !"_ZTSFPvS_E.generalized"} From 0ed5829c7c0cab4e1426cefd7269cb0986eb6dd7 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Fri, 19 Sep 2025 16:17:58 -0700 Subject: [PATCH 03/18] Update tests. --- llvm/test/CodeGen/X86/call-graph-section-tailcall.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll index a83df51f702ab..ddf1b4b95da02 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll @@ -30,7 +30,7 @@ declare !type !2 i32 @bar(i8 signext) !0 = !{i64 0, !"_ZTSFiPvcE.generalized"} !1 = !{!2} ;; Verify that the type id 0x308e4b8159bc8654 is in section. -; CHECK: 5486bc 59814b8e +; CHECK: {{.*}} 005486bc 59814b8e ; CHECK-NEXT: 0x00000020 30000000 00000000 00000000 00000000 !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{i64 0, !"_ZTSFiiE.generalized"} From 7260b40e804502e1232d9648945c5445c468853d Mon Sep 17 00:00:00 2001 From: prabhukr Date: Mon, 22 Sep 2025 22:13:59 +0000 Subject: [PATCH 04/18] Fix size of direct callee count in tests. --- llvm/test/CodeGen/X86/call-graph-section-assembly.ll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index e2f799ceb31ef..9cfb883844786 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -53,8 +53,8 @@ entry: ;; Test for MD5 hash of _ZTSFPvS_E.generalized and the generated temporary callsite label. ; CHECK-NEXT: .quad 8646233951371320954 ; CHECK-NEXT: .quad [[LABEL_TMP2]] -;; Test for number of direct calls and {callsite_label, callee} pairs. -; CHECK-NEXT: .quad 3 +;; Test for number of direct calls and direct callees. +; CHECK-NEXT: .long 3 ; CHECK-NEXT: .quad direct_foo ; CHECK-NEXT: .quad direct_bar ; CHECK-NEXT: .quad direct_baz From b22ff5920c1213a1779b7eaaa1e6d4ff2ba08159 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 15:48:44 -0700 Subject: [PATCH 05/18] More layout changes. --- llvm/docs/CallGraphSection.md | 33 +++------ llvm/include/llvm/CodeGen/AsmPrinter.h | 8 +-- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 82 +++++++++------------- 3 files changed, 50 insertions(+), 73 deletions(-) diff --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md index 3e4f107572716..48387cf041a3f 100644 --- a/llvm/docs/CallGraphSection.md +++ b/llvm/docs/CallGraphSection.md @@ -1,29 +1,18 @@ # .callgraph Section Layout -The `.callgraph` section is used to store call graph information for each function, which can be used for post-link analyses and optimizations. The section contains a series of records, with each record corresponding to a single function. - -For efficiency, we make a distinction between direct and indirect call data. For direct calls, we record the unique callees, not the location of each individual call. For indirect calls, we record the location of each call site and the type ID of the callee. Post link analysis scripts which utilize this information to reconstuct the program call graph can potentially receive more information regarding indirect callsites from the user to improve the precision of the call graph. +The `.callgraph` section is used to store call graph information for each function. The section contains a series of records, with each record corresponding to a single function. ## Per Function Record Layout Each record in the `.callgraph` section has the following binary layout: -| Field | Type | Size (bits) | Description | -| ---------------------------- | ------------- | ----------- | ------------------------------------------------------------------------------------------------------- | -| Format Version | `uint32_t` | 32 | The version of the record format. The current version is 0. | -| Function Entry PC | `uintptr_t` | 32/64 | The address of the function's entry point. | -| Function Kind | `uint8_t` | 8 | An enum indicating the function's properties (e.g., if it's an indirect call target). | -| Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is **only** present if `Function Kind` is `INDIRECT_TARGET_KNOWN_TID`. | -| Number of Indirect Callsites | `uint32_t` | 32 | The number of indirect call sites within the function. | -| Indirect Callsites Array | `Callsite[]` | Variable | An array of `Callsite` records, with a length of `Number of Indirect Callsites`. | -| Number of Unique Direct Callees | `uint32_t` | 32 | The number of unique direct call destinations from this function. | -| Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses, with a length of `Number of Direct Callees`. | - -### Indirect Callsite Record Layout - -Each record in the `Indirect Callsites Array` has the following layout: - -| Field | Type | Size (bits) | Description | -| ----------------- | ----------- | ----------- | ----------------------------------------- | -| Type ID | `uint64_t` | 64 | The type ID of the indirect call target. | -| Callsite PC | `uintptr_t` | 32/64 | The address of the indirect call site. | +| Field | Type | Size (bits) | Description | +| -------------------------------------- | ------------- | ----------- | ------------------------------------------------------------------------------------------------------- | +| Format Version | `uint8_t` | 8 | The version of the record format. The current version is 0. | +| Flags | `uint8_t` | 8 | Bit 0 is set if the function is a valid indirect call target. Other bits are reserved. | +| Function Entry PC | `uintptr_t` | 32/64 | The address of the function's entry point. | +| Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is non-zero if the function is an indirect call target and its type is known. | +| Number of Unique Direct Callees | `uint32_t` | 32 | The number of unique direct call destinations from this function. | +| Number of Unique Indirect Target Type IDs| `uint32_t` | 32 | The number of unique indirect call target type IDs within the function. | +| Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. | +| Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses. | diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 8266c91997f37..f896789c76bf0 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -198,9 +198,9 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { /// and targets. using CGTypeId = uint64_t; - /// Map type identifiers to callsite labels. Labels are generated for each - /// indirect callsite in the function. - SmallVector> IndirectCallsites; + /// Unique target type IDs. + SmallSet IndirectCalleeTypeIDs; + /// Unique direct callees. SmallSet DirectCallees; }; @@ -217,7 +217,7 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { INDIRECT_TARGET_KNOWN_TID = 2, }; - enum CallGraphSectionFormatVersion : uint32_t { + enum CallGraphSectionFormatVersion : uint8_t { V_0 = 0, }; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index a78c9829b40d6..acc58cdbba59e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1685,59 +1685,46 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, OutStreamer->pushSection(); OutStreamer->switchSection(FuncCGSection); - auto EmitFunctionKindAndTypeId = [&]() { - const Function &F = MF.getFunction(); - // If this function has external linkage or has its address taken and - // it is not a callback, then anything could call it. - bool IsIndirectTarget = !F.hasLocalLinkage() || - F.hasAddressTaken(nullptr, - /*IgnoreCallbackUses=*/true, - /*IgnoreAssumeLikeCalls=*/true, - /*IgnoreLLVMUsed=*/false); - if (!IsIndirectTarget) { - OutStreamer->emitInt8( - static_cast(FunctionKind::NOT_INDIRECT_TARGET)); - return; - } - if (const auto *TypeId = extractNumericCGTypeId(F)) { - OutStreamer->emitInt8( - static_cast(FunctionKind::INDIRECT_TARGET_KNOWN_TID)); - OutStreamer->emitInt64(TypeId->getZExtValue()); - return; - } - OutStreamer->emitInt8( - static_cast(FunctionKind::INDIRECT_TARGET_UNKNOWN_TID)); - }; + const MCSymbol *FunctionSymbol = getFunctionBegin(); + const Function &F = MF.getFunction(); + // If this function has external linkage or has its address taken and + // it is not a callback, then anything could call it. + bool IsIndirectTarget = + !F.hasLocalLinkage() || F.hasAddressTaken(nullptr, + /*IgnoreCallbackUses=*/true, + /*IgnoreAssumeLikeCalls=*/true, + /*IgnoreLLVMUsed=*/false); + + uint8_t Flags = 0; + if (IsIndirectTarget) + Flags |= 1 << 0; // Set the 0th bit to 1. // Emit function's call graph information. // 1) CallGraphSectionFormatVersion - // 2) Function entry PC. - // 3) FunctionKind: Whether the function is indirect target, and if so, - // whether its type id is known. - // 4) FunctionTypeID if the function is indirect target, and its type id is - // known. - // 5) Number of indirect callsites. - // 6) For each indirect callsite, its - // callsite PC and callee's expected type id. - // 7) Number of unique direct callees. - // 8) For each unique direct callee, the callee's PC. - - OutStreamer->emitInt32(CallGraphSectionFormatVersion::V_0); - const MCSymbol *FunctionSymbol = getFunctionBegin(); + // 2) Flags - Bit 0 is set to 1 if the function is a valid indirect target. + // Other bits are reserved for future use. 3) Function entry PC. 4) + // FunctionTypeID if the function is indirect target and its type id is known, + // otherwise it is set to 0. 5) Number of unique direct callees. 6) Number of + // unique indirect target type IDs. 7) For each unique direct callee, the + // callee's PC. 8) Each unique indirect target type id. + + OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0); + OutStreamer->emitInt8(Flags); OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); - EmitFunctionKindAndTypeId(); - const auto &IndirectCallsites = FuncCGInfo.IndirectCallsites; - OutStreamer->emitInt32(IndirectCallsites.size()); + const auto *TypeId = extractNumericCGTypeId(F); + if (IsIndirectTarget && TypeId) + OutStreamer->emitInt64(TypeId->getZExtValue()); + else + OutStreamer->emitInt64(0); const auto &DirectCallees = FuncCGInfo.DirectCallees; - for (const auto &[TypeId, Label] : IndirectCallsites) { - OutStreamer->emitInt64(TypeId); - OutStreamer->emitSymbolValue(Label, TM.getProgramPointerSize()); - } - FuncCGInfo.IndirectCallsites.clear(); + const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs; OutStreamer->emitInt32(DirectCallees.size()); - for (const auto &CalleeSymbol : DirectCallees) { + OutStreamer->emitInt32(IndirectCalleeTypeIDs.size()); + for (const auto &CalleeTypeId : IndirectCalleeTypeIDs) + OutStreamer->emitInt64(CalleeTypeId); + FuncCGInfo.IndirectCalleeTypeIDs.clear(); + for (const auto &CalleeSymbol : DirectCallees) OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize()); - } FuncCGInfo.DirectCallees.clear(); OutStreamer->popSection(); @@ -1906,7 +1893,8 @@ void AsmPrinter::handleCallsiteForCallgraph( MCSymbol *S = MF->getContext().createTempSymbol(); OutStreamer->emitLabel(S); uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue(); - FuncCGInfo.IndirectCallsites.emplace_back(CalleeTypeIdVal, S); + // FuncCGInfo.IndirectCallsites.emplace_back(CalleeTypeIdVal, S); + FuncCGInfo.IndirectCalleeTypeIDs.insert(CalleeTypeIdVal); } } From 1676b4aad964e669bdd4dcd0687f356310d98f02 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 17:04:11 -0700 Subject: [PATCH 06/18] Fix tests to match new callgraph layout. --- llvm/include/llvm/CodeGen/AsmPrinter.h | 19 ++------ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 13 +++--- .../X86/call-graph-section-assembly.ll | 45 ++++++++++--------- .../X86/call-graph-section-tailcall.ll | 16 +++---- llvm/test/CodeGen/X86/call-graph-section.ll | 14 +++--- 5 files changed, 47 insertions(+), 60 deletions(-) diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index f896789c76bf0..19ca44429af4d 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -204,19 +204,6 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { SmallSet DirectCallees; }; - /// Enumeration of function kinds, and their mapping to function kind values - /// stored in callgraph section entries. - enum class FunctionKind : uint8_t { - /// Function cannot be target to indirect calls. - NOT_INDIRECT_TARGET = 0, - - /// Function may be target to indirect calls but its type id is unknown. - INDIRECT_TARGET_UNKNOWN_TID = 1, - - /// Function may be target to indirect calls and its type id is known. - INDIRECT_TARGET_KNOWN_TID = 2, - }; - enum CallGraphSectionFormatVersion : uint8_t { V_0 = 0, }; @@ -386,9 +373,9 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { /// are available. Returns empty string otherwise. StringRef getConstantSectionSuffix(const Constant *C) const; - /// Iff MI is an indirect call, generate and emit a label after the callsites - /// which will be used to populate the .callgraph section. For direct - /// callsites add the callee symbol to direct callsites list of FuncCGInfo. + /// If MI is an indirect call, add expected type IDs to indirect type ids + /// list. If MI is a direct call add the callee symbol to direct callsites + /// list of FuncCGInfo. void handleCallsiteForCallgraph( FunctionCallGraphInfo &FuncCGInfo, const MachineFunction::CallSiteInfoMap &CallSitesInfoMap, diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index acc58cdbba59e..6d769de034c39 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1697,7 +1697,7 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, uint8_t Flags = 0; if (IsIndirectTarget) - Flags |= 1 << 0; // Set the 0th bit to 1. + Flags |= 1 << 0; // Set the LSB bit to 1. // Emit function's call graph information. // 1) CallGraphSectionFormatVersion @@ -1707,7 +1707,6 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, // otherwise it is set to 0. 5) Number of unique direct callees. 6) Number of // unique indirect target type IDs. 7) For each unique direct callee, the // callee's PC. 8) Each unique indirect target type id. - OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0); OutStreamer->emitInt8(Flags); OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); @@ -1720,13 +1719,13 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs; OutStreamer->emitInt32(DirectCallees.size()); OutStreamer->emitInt32(IndirectCalleeTypeIDs.size()); - for (const auto &CalleeTypeId : IndirectCalleeTypeIDs) - OutStreamer->emitInt64(CalleeTypeId); - FuncCGInfo.IndirectCalleeTypeIDs.clear(); for (const auto &CalleeSymbol : DirectCallees) OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize()); FuncCGInfo.DirectCallees.clear(); - + for (const auto &CalleeTypeId : IndirectCalleeTypeIDs) + OutStreamer->emitInt64(CalleeTypeId); + FuncCGInfo.IndirectCalleeTypeIDs.clear(); + // End of emitting call graph section contents. OutStreamer->popSection(); } @@ -1890,8 +1889,6 @@ void AsmPrinter::handleCallsiteForCallgraph( // Handle indirect callsite info. // Only indirect calls have type identifiers set. for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) { - MCSymbol *S = MF->getContext().createTempSymbol(); - OutStreamer->emitLabel(S); uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue(); // FuncCGInfo.IndirectCallsites.emplace_back(CalleeTypeIdVal, S); FuncCGInfo.IndirectCalleeTypeIDs.insert(CalleeTypeIdVal); diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index 9cfb883844786..2c57578ee3e13 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -15,16 +15,13 @@ declare !type !2 ptr @direct_baz(ptr) define ptr @ball() { entry: call void @direct_foo() - %fp_foo_val = load ptr, ptr null, align 8 - ; CHECK: [[LABEL_TMP0:\.L.*]]: + %fp_foo_val = load ptr, ptr null, align 8 call void (...) %fp_foo_val(), !callee_type !0 call void @direct_foo() - %fp_bar_val = load ptr, ptr null, align 8 - ; CHECK: [[LABEL_TMP1:\.L.*]]: + %fp_bar_val = load ptr, ptr null, align 8 %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !2 %call_fp_bar_direct = call i32 @direct_bar(i8 1) %fp_baz_val = load ptr, ptr null, align 8 - ; CHECK: [[LABEL_TMP2:\.L.*]]: %call_fp_baz = call ptr %fp_baz_val(ptr null), !callee_type !4 call void @direct_foo() %call_fp_baz_direct = call ptr @direct_baz(ptr null) @@ -32,29 +29,33 @@ entry: ret ptr %call_fp_baz } -; CHECK: .section .callgraph,"o",@progbits,.text - -; CHECK-NEXT: .long 0 -; CHECK-NEXT: .quad [[LABEL_FUNC]] -; CHECK-NEXT: .byte 1 -; CHECK-NEXT: .long 3 !0 = !{!1} !1 = !{i64 0, !"_ZTSFvE.generalized"} -;; Test for MD5 hash of _ZTSFvE.generalized and the generated temporary callsite label. -; CHECK-NEXT: .quad 4524972987496481828 -; CHECK-NEXT: .quad [[LABEL_TMP0]] !2 = !{!3} !3 = !{i64 0, !"_ZTSFicE.generalized"} -;; Test for MD5 hash of _ZTSFicE.generalized and the generated temporary callsite label. -; CHECK-NEXT: .quad 3498816979441845844 -; CHECK-NEXT: .quad [[LABEL_TMP1]] !4 = !{!5} !5 = !{i64 0, !"_ZTSFPvS_E.generalized"} -;; Test for MD5 hash of _ZTSFPvS_E.generalized and the generated temporary callsite label. -; CHECK-NEXT: .quad 8646233951371320954 -; CHECK-NEXT: .quad [[LABEL_TMP2]] -;; Test for number of direct calls and direct callees. -; CHECK-NEXT: .long 3 + + +; CHECK: .section .callgraph,"o",@progbits,.text + +;; Version +; CHECK-NEXT: .byte 0 +;; Flags +; CHECK-NEXT: .byte 1 +;; Function Entry PC +; CHECK-NEXT: .quad [[LABEL_FUNC]] +;; Function type ID -- set to 0 as no type metadata attached to function. +; CHECK-NEXT: .quad 0 +;; Number of unique direct callees. +; CHECK-NEXT: .long 3 +;; Number of unique indirect target type IDs. +; CHECK-NEXT: .long 3 +;; Direct callees. ; CHECK-NEXT: .quad direct_foo ; CHECK-NEXT: .quad direct_bar ; CHECK-NEXT: .quad direct_baz +;; Indirect type IDs. +; CHECK-NEXT: .quad 4524972987496481828 +; CHECK-NEXT: .quad 3498816979441845844 +; CHECK-NEXT: .quad 8646233951371320954 diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll index ddf1b4b95da02..b938516a94457 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll @@ -22,15 +22,15 @@ declare !type !2 i32 @foo(i8 signext) declare !type !2 i32 @bar(i8 signext) -;; Check that the numeric type id (md5 hash) for the below type ids are emitted -;; to the callgraph section. - -; CHECK: Hex dump of section '.callgraph': - !0 = !{i64 0, !"_ZTSFiPvcE.generalized"} !1 = !{!2} -;; Verify that the type id 0x308e4b8159bc8654 is in section. -; CHECK: {{.*}} 005486bc 59814b8e -; CHECK-NEXT: 0x00000020 30000000 00000000 00000000 00000000 !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{i64 0, !"_ZTSFiiE.generalized"} + +; CHECK: Hex dump of section '.callgraph': +; CHECK-NEXT: 0x00000000 00010000 00000000 00008e19 0b7f3326 +; CHECK-NEXT: 0x00000010 e3000000 00000100 00005486 bc59814b +; CHECK-NEXT: 0x00000020 8e300001 00000000 00000000 a150b83e +;; Verify that the type id 0x308e4b8159bc8654 is in section. +; CHECK-NEXT: 0x00000030 0cfe3cb2 00000000 01000000 5486bc59 +; CHECK-NEXT: 0x00000040 814b8e30 diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll b/llvm/test/CodeGen/X86/call-graph-section.ll index 37f1e8e2acf16..8bcf2ad5e4c79 100644 --- a/llvm/test/CodeGen/X86/call-graph-section.ll +++ b/llvm/test/CodeGen/X86/call-graph-section.ll @@ -22,15 +22,17 @@ entry: ;; Check that the numeric type id (md5 hash) for the below type ids are emitted ;; to the callgraph section. - -; CHECK: Hex dump of section '.callgraph': - -; CHECK-DAG: 2444f7 31f5eecb 3e !0 = !{i64 0, !"_ZTSFvE.generalized"} !1 = !{!0} -; CHECK-DAG: 5486bc 59814b8e 30 !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{!2} -; CHECK-DAG: 7ade68 14f897fd 77 !4 = !{!5} !5 = !{i64 0, !"_ZTSFPvS_E.generalized"} + +;; Make sure following type IDs are in call graph section +;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 +; CHECK: Hex dump of section '.callgraph': +; CHECK-NEXT: 0x00000000 00010000 00000000 00000000 00000000 +; CHECK-NEXT: 0x00000010 00000000 00000300 00002444 f731f5ee +; CHECK-NEXT: 0x00000020 cb3e5486 bc59814b 8e307ade 6814f897 +; CHECK-NEXT: 0x00000030 fd77 From fa0dd1891076eae9909adc261ce0340780c847cd Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 17:07:51 -0700 Subject: [PATCH 07/18] Remove unnecessary comment. --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 6d769de034c39..6aebeb7f4a633 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1863,8 +1863,7 @@ void AsmPrinter::handleCallsiteForCallgraph( FunctionCallGraphInfo &FuncCGInfo, const MachineFunction::CallSiteInfoMap &CallSitesInfoMap, const MachineInstr &MI) { - assert(MI.isCall() && - "Callsite labels are meant for call instructions only."); + assert(MI.isCall() && "This method is meant for call instructions only."); const MachineOperand &CalleeOperand = MI.getOperand(0); if (CalleeOperand.isGlobal() || CalleeOperand.isSymbol()) { // Handle direct calls. @@ -1890,7 +1889,6 @@ void AsmPrinter::handleCallsiteForCallgraph( // Only indirect calls have type identifiers set. for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) { uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue(); - // FuncCGInfo.IndirectCallsites.emplace_back(CalleeTypeIdVal, S); FuncCGInfo.IndirectCalleeTypeIDs.insert(CalleeTypeIdVal); } } From 3fcec5abee20b8582286bd4766675795a69e407e Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 17:09:08 -0700 Subject: [PATCH 08/18] Remove unnecessary newlines. --- llvm/test/CodeGen/X86/call-graph-section-assembly.ll | 2 -- 1 file changed, 2 deletions(-) diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index 2c57578ee3e13..a416526c7cc58 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -36,9 +36,7 @@ entry: !4 = !{!5} !5 = !{i64 0, !"_ZTSFPvS_E.generalized"} - ; CHECK: .section .callgraph,"o",@progbits,.text - ;; Version ; CHECK-NEXT: .byte 0 ;; Flags From bf00b25a3736ecc5039ef44e7523364db4e8be2f Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 17:51:02 -0700 Subject: [PATCH 09/18] Add doc file to toctree --- llvm/docs/CallGraphSection.md | 2 +- llvm/docs/CodeGenerator.rst | 7 +++++++ llvm/docs/Reference.rst | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md index 48387cf041a3f..35939b236377a 100644 --- a/llvm/docs/CallGraphSection.md +++ b/llvm/docs/CallGraphSection.md @@ -14,5 +14,5 @@ Each record in the `.callgraph` section has the following binary layout: | Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is non-zero if the function is an indirect call target and its type is known. | | Number of Unique Direct Callees | `uint32_t` | 32 | The number of unique direct call destinations from this function. | | Number of Unique Indirect Target Type IDs| `uint32_t` | 32 | The number of unique indirect call target type IDs within the function. | -| Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. | | Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses. | +| Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. | diff --git a/llvm/docs/CodeGenerator.rst b/llvm/docs/CodeGenerator.rst index 7486054b55c9f..fc704a3cdd51f 100644 --- a/llvm/docs/CodeGenerator.rst +++ b/llvm/docs/CodeGenerator.rst @@ -1662,6 +1662,13 @@ and stack sizes (unsigned LEB128). The stack size values only include the space allocated in the function prologue. Functions with dynamic stack allocations are not included. +Emitting function call graph information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A section containing metadata on function call graph will be emitted when +``TargetOptions::EmitCallGraphSection`` is set (--call-graph-section). Layout of +this section is documented in detail at :doc:`CallGraphSection`. + VLIW Packetizer --------------- diff --git a/llvm/docs/Reference.rst b/llvm/docs/Reference.rst index 5d842d339f8c9..4fbd39c0e7692 100644 --- a/llvm/docs/Reference.rst +++ b/llvm/docs/Reference.rst @@ -14,6 +14,7 @@ LLVM and API reference documentation. BlockFrequencyTerminology BranchWeightMetadata Bugpoint + CallGraphSection CalleeTypeMetadata CIBestPractices CommandGuide/index From 6d0e8d35042e6555c9d19d5a5c64a021b78cb4fb Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 17:52:37 -0700 Subject: [PATCH 10/18] Reorder toc tree to be alphabetical. --- llvm/docs/Reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/docs/Reference.rst b/llvm/docs/Reference.rst index 4fbd39c0e7692..9b1bf1be9c8bf 100644 --- a/llvm/docs/Reference.rst +++ b/llvm/docs/Reference.rst @@ -14,8 +14,8 @@ LLVM and API reference documentation. BlockFrequencyTerminology BranchWeightMetadata Bugpoint - CallGraphSection CalleeTypeMetadata + CallGraphSection CIBestPractices CommandGuide/index ContentAddressableStorage From 90265cccb3b1fe0eec5803d3c562591f2eb018ab Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 30 Sep 2025 17:57:44 -0700 Subject: [PATCH 11/18] Fix formatting of inline comment. --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 6aebeb7f4a633..b5c952b9a14a2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1702,11 +1702,14 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, // Emit function's call graph information. // 1) CallGraphSectionFormatVersion // 2) Flags - Bit 0 is set to 1 if the function is a valid indirect target. - // Other bits are reserved for future use. 3) Function entry PC. 4) - // FunctionTypeID if the function is indirect target and its type id is known, - // otherwise it is set to 0. 5) Number of unique direct callees. 6) Number of - // unique indirect target type IDs. 7) For each unique direct callee, the - // callee's PC. 8) Each unique indirect target type id. + // Other bits are reserved for future use. + // 3) Function entry PC. + // 4) FunctionTypeID if the function is indirect target and its type id is + // known, otherwise it is set to 0. + // 5) Number of unique direct callees. + // 6) Number of unique indirect target type IDs. + // 7) For each unique direct callee, the callee's PC. + // 8) Each unique indirect target type id. OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0); OutStreamer->emitInt8(Flags); OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); From 632cbbe690ea630604a751b8ef8dbd3caf3b1572 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Wed, 1 Oct 2025 18:25:49 -0700 Subject: [PATCH 12/18] Make counts ULEB128. Omit count fields using Flags if they are zero. --- llvm/docs/CallGraphSection.md | 8 ++--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 30 +++++++++++++------ .../X86/call-graph-section-assembly.ll | 6 ++-- .../X86/call-graph-section-tailcall.ll | 9 +++--- llvm/test/CodeGen/X86/call-graph-section.ll | 7 ++--- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md index 35939b236377a..2cea47f07a710 100644 --- a/llvm/docs/CallGraphSection.md +++ b/llvm/docs/CallGraphSection.md @@ -9,10 +9,10 @@ Each record in the `.callgraph` section has the following binary layout: | Field | Type | Size (bits) | Description | | -------------------------------------- | ------------- | ----------- | ------------------------------------------------------------------------------------------------------- | | Format Version | `uint8_t` | 8 | The version of the record format. The current version is 0. | -| Flags | `uint8_t` | 8 | Bit 0 is set if the function is a valid indirect call target. Other bits are reserved. | +| Flags | `uint8_t` | 8 | A bitfield where: Bit 0 is set if the function is a potential indirect call target; Bit 1 is set if there are direct callees; Bit 2 is set if there are indirect callees. The remaining 5 bits are reserved. | | Function Entry PC | `uintptr_t` | 32/64 | The address of the function's entry point. | -| Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is non-zero if the function is an indirect call target and its type is known. | -| Number of Unique Direct Callees | `uint32_t` | 32 | The number of unique direct call destinations from this function. | -| Number of Unique Indirect Target Type IDs| `uint32_t` | 32 | The number of unique indirect call target type IDs within the function. | +| Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is non-zero if the function is a potential indirect call target and its type is known. | +| Number of Unique Direct Callees | `ULEB128` | Variable | The number of unique direct call destinations from this function. This field is only present if there is at least one direct callee. | +| Number of Unique Indirect Target Type IDs| `ULEB128` | Variable | The number of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. | | Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses. | | Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. | diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index b5c952b9a14a2..571c195788547 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1695,19 +1695,30 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, /*IgnoreAssumeLikeCalls=*/true, /*IgnoreLLVMUsed=*/false); + const auto &DirectCallees = FuncCGInfo.DirectCallees; + const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs; + uint8_t Flags = 0; if (IsIndirectTarget) - Flags |= 1 << 0; // Set the LSB bit to 1. + Flags |= 1u << 0; // Set the first LSB bit to 1. + if (DirectCallees.size() > 0) + Flags |= 1u << 1; // Set the second LSB bit to 1. + if (IndirectCalleeTypeIDs.size() > 0) + Flags |= 1u << 2; // Set the third LSB bit to 1. // Emit function's call graph information. // 1) CallGraphSectionFormatVersion - // 2) Flags - Bit 0 is set to 1 if the function is a valid indirect target. - // Other bits are reserved for future use. + // 2) Flags + // a. LSB bit 0 is set to 1 if the function is a potential indirect + // target. + // b. LSB bit 1 is set to 1 if there are direct callees. + // c. LSB bit 2 is set to 1 if there are indirect callees. + // d. Rest of the 5 bits in Flags are reserved for any future use. // 3) Function entry PC. // 4) FunctionTypeID if the function is indirect target and its type id is // known, otherwise it is set to 0. - // 5) Number of unique direct callees. - // 6) Number of unique indirect target type IDs. + // 5) Number of unique direct callees, if at least one exists. + // 6) Number of unique indirect target type IDs, if at least one exists. // 7) For each unique direct callee, the callee's PC. // 8) Each unique indirect target type id. OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0); @@ -1718,10 +1729,11 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, OutStreamer->emitInt64(TypeId->getZExtValue()); else OutStreamer->emitInt64(0); - const auto &DirectCallees = FuncCGInfo.DirectCallees; - const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs; - OutStreamer->emitInt32(DirectCallees.size()); - OutStreamer->emitInt32(IndirectCalleeTypeIDs.size()); + + if (DirectCallees.size() > 0) + OutStreamer->emitULEB128IntValue(DirectCallees.size()); + if (IndirectCalleeTypeIDs.size() > 0) + OutStreamer->emitULEB128IntValue(IndirectCalleeTypeIDs.size()); for (const auto &CalleeSymbol : DirectCallees) OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize()); FuncCGInfo.DirectCallees.clear(); diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index a416526c7cc58..f1493947ca332 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -40,15 +40,15 @@ entry: ;; Version ; CHECK-NEXT: .byte 0 ;; Flags -; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 7 ;; Function Entry PC ; CHECK-NEXT: .quad [[LABEL_FUNC]] ;; Function type ID -- set to 0 as no type metadata attached to function. ; CHECK-NEXT: .quad 0 ;; Number of unique direct callees. -; CHECK-NEXT: .long 3 +; CHECK-NEXT: .byte 3 ;; Number of unique indirect target type IDs. -; CHECK-NEXT: .long 3 +; CHECK-NEXT: .byte 3 ;; Direct callees. ; CHECK-NEXT: .quad direct_foo ; CHECK-NEXT: .quad direct_bar diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll index b938516a94457..34dc5b831de6d 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll @@ -28,9 +28,8 @@ declare !type !2 i32 @bar(i8 signext) !3 = !{i64 0, !"_ZTSFiiE.generalized"} ; CHECK: Hex dump of section '.callgraph': -; CHECK-NEXT: 0x00000000 00010000 00000000 00008e19 0b7f3326 -; CHECK-NEXT: 0x00000010 e3000000 00000100 00005486 bc59814b -; CHECK-NEXT: 0x00000020 8e300001 00000000 00000000 a150b83e +; CHECK-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326 +; CHECK-NEXT: 0x00000010 e3000154 86bc5981 4b8e3000 05000000 ;; Verify that the type id 0x308e4b8159bc8654 is in section. -; CHECK-NEXT: 0x00000030 0cfe3cb2 00000000 01000000 5486bc59 -; CHECK-NEXT: 0x00000040 814b8e30 +; CHECK-NEXT: 0x00000020 00000000 00a150b8 3e0cfe3c b2015486 +; CHECK-NEXT: 0x00000030 bc59814b 8e30 diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll b/llvm/test/CodeGen/X86/call-graph-section.ll index 8bcf2ad5e4c79..c144a24439725 100644 --- a/llvm/test/CodeGen/X86/call-graph-section.ll +++ b/llvm/test/CodeGen/X86/call-graph-section.ll @@ -32,7 +32,6 @@ entry: ;; Make sure following type IDs are in call graph section ;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 ; CHECK: Hex dump of section '.callgraph': -; CHECK-NEXT: 0x00000000 00010000 00000000 00000000 00000000 -; CHECK-NEXT: 0x00000010 00000000 00000300 00002444 f731f5ee -; CHECK-NEXT: 0x00000020 cb3e5486 bc59814b 8e307ade 6814f897 -; CHECK-NEXT: 0x00000030 fd77 +; CHECK-NEXT: 0x00000000 00050000 00000000 00000000 00000000 +; CHECK-NEXT: 0x00000010 00000324 44f731f5 eecb3e54 86bc5981 +; CHECK-NEXT: 0x00000020 4b8e307a de6814f8 97fd77 From 4dffc8a3bac227ddcee045f3ba3e513cea20a31f Mon Sep 17 00:00:00 2001 From: prabhukr Date: Thu, 2 Oct 2025 10:05:53 -0700 Subject: [PATCH 13/18] Reorder fields in callgraph section. --- llvm/docs/CallGraphSection.md | 2 +- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 26 ++++++++++--------- .../X86/call-graph-section-assembly.ll | 4 +-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md index 2cea47f07a710..2f72e91f089bd 100644 --- a/llvm/docs/CallGraphSection.md +++ b/llvm/docs/CallGraphSection.md @@ -13,6 +13,6 @@ Each record in the `.callgraph` section has the following binary layout: | Function Entry PC | `uintptr_t` | 32/64 | The address of the function's entry point. | | Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is non-zero if the function is a potential indirect call target and its type is known. | | Number of Unique Direct Callees | `ULEB128` | Variable | The number of unique direct call destinations from this function. This field is only present if there is at least one direct callee. | -| Number of Unique Indirect Target Type IDs| `ULEB128` | Variable | The number of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. | | Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses. | +| Number of Unique Indirect Target Type IDs| `ULEB128` | Variable | The number of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. | | Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. | diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 8712c0f0dc176..9f2efdb656f80 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1713,11 +1713,11 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, // c. LSB bit 2 is set to 1 if there are indirect callees. // d. Rest of the 5 bits in Flags are reserved for any future use. // 3) Function entry PC. - // 4) FunctionTypeID if the function is indirect target and its type id is - // known, otherwise it is set to 0. + // 4) FunctionTypeID if the function is indirect target and its type id + // is known, otherwise it is set to 0. // 5) Number of unique direct callees, if at least one exists. - // 6) Number of unique indirect target type IDs, if at least one exists. - // 7) For each unique direct callee, the callee's PC. + // 6) For each unique direct callee, the callee's PC. + // 7) Number of unique indirect target type IDs, if at least one exists. // 8) Each unique indirect target type id. OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0); OutStreamer->emitInt8(Flags); @@ -1728,16 +1728,18 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, else OutStreamer->emitInt64(0); - if (DirectCallees.size() > 0) + if (DirectCallees.size() > 0) { OutStreamer->emitULEB128IntValue(DirectCallees.size()); - if (IndirectCalleeTypeIDs.size() > 0) + for (const auto &CalleeSymbol : DirectCallees) + OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize()); + FuncCGInfo.DirectCallees.clear(); + } + if (IndirectCalleeTypeIDs.size() > 0) { OutStreamer->emitULEB128IntValue(IndirectCalleeTypeIDs.size()); - for (const auto &CalleeSymbol : DirectCallees) - OutStreamer->emitSymbolValue(CalleeSymbol, TM.getProgramPointerSize()); - FuncCGInfo.DirectCallees.clear(); - for (const auto &CalleeTypeId : IndirectCalleeTypeIDs) - OutStreamer->emitInt64(CalleeTypeId); - FuncCGInfo.IndirectCalleeTypeIDs.clear(); + for (const auto &CalleeTypeId : IndirectCalleeTypeIDs) + OutStreamer->emitInt64(CalleeTypeId); + FuncCGInfo.IndirectCalleeTypeIDs.clear(); + } // End of emitting call graph section contents. OutStreamer->popSection(); } diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index f1493947ca332..1aabf66d471c8 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -47,12 +47,12 @@ entry: ; CHECK-NEXT: .quad 0 ;; Number of unique direct callees. ; CHECK-NEXT: .byte 3 -;; Number of unique indirect target type IDs. -; CHECK-NEXT: .byte 3 ;; Direct callees. ; CHECK-NEXT: .quad direct_foo ; CHECK-NEXT: .quad direct_bar ; CHECK-NEXT: .quad direct_baz +;; Number of unique indirect target type IDs. +; CHECK-NEXT: .byte 3 ;; Indirect type IDs. ; CHECK-NEXT: .quad 4524972987496481828 ; CHECK-NEXT: .quad 3498816979441845844 From e399ae18e70d4e74cb638e07dd5aea0737177647 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Thu, 2 Oct 2025 10:46:10 -0700 Subject: [PATCH 14/18] Add 32 bit tests. --- .../X86/call-graph-section-assembly.ll | 64 ++++++++++++++----- .../X86/call-graph-section-tailcall.ll | 23 +++++-- llvm/test/CodeGen/X86/call-graph-section.ll | 22 +++++-- 3 files changed, 82 insertions(+), 27 deletions(-) diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index 1aabf66d471c8..63892e30fbf85 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -4,14 +4,20 @@ ;; call sites annotated with !callee_type metadata. ;; Test if the .callgraph section contains unique direct callees. -; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck %s +; REQUIRES: x86-registered-target +; REQUIRES: arm-registered-target + +; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck --check-prefix=X64 %s +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | FileCheck --check-prefix=ARM32 %s declare !type !0 void @direct_foo() declare !type !1 i32 @direct_bar(i8) declare !type !2 ptr @direct_baz(ptr) -; CHECK: ball: -; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: +; X64: ball: +; X64-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: +; ARM32: ball: +; ARM32-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: define ptr @ball() { entry: call void @direct_foo() @@ -36,24 +42,50 @@ entry: !4 = !{!5} !5 = !{i64 0, !"_ZTSFPvS_E.generalized"} -; CHECK: .section .callgraph,"o",@progbits,.text +; X64: .section .callgraph,"o",@progbits,.text +;; Version +; X64-NEXT: .byte 0 +;; Flags +; X64-NEXT: .byte 7 +;; Function Entry PC +; X64-NEXT: .quad [[LABEL_FUNC]] +;; Function type ID -- set to 0 as no type metadata attached to function. +; X64-NEXT: .quad 0 +;; Number of unique direct callees. +; X64-NEXT: .byte 3 +;; Direct callees. +; X64-NEXT: .quad direct_foo +; X64-NEXT: .quad direct_bar +; X64-NEXT: .quad direct_baz +;; Number of unique indirect target type IDs. +; X64-NEXT: .byte 3 +;; Indirect type IDs. +; X64-NEXT: .quad 4524972987496481828 +; X64-NEXT: .quad 3498816979441845844 +; X64-NEXT: .quad 8646233951371320954 + +; ARM32: .section .callgraph,"o",%progbits,.text ;; Version -; CHECK-NEXT: .byte 0 +; ARM32-NEXT: .byte 0 ;; Flags -; CHECK-NEXT: .byte 7 +; ARM32-NEXT: .byte 7 ;; Function Entry PC -; CHECK-NEXT: .quad [[LABEL_FUNC]] +; ARM32-NEXT: .long [[LABEL_FUNC]] ;; Function type ID -- set to 0 as no type metadata attached to function. -; CHECK-NEXT: .quad 0 +; ARM32-NEXT: .long 0 +; ARM32-NEXT: .long 0 ;; Number of unique direct callees. -; CHECK-NEXT: .byte 3 +; ARM32-NEXT: .byte 3 ;; Direct callees. -; CHECK-NEXT: .quad direct_foo -; CHECK-NEXT: .quad direct_bar -; CHECK-NEXT: .quad direct_baz +; ARM32-NEXT: .long direct_foo +; ARM32-NEXT: .long direct_bar +; ARM32-NEXT: .long direct_baz ;; Number of unique indirect target type IDs. -; CHECK-NEXT: .byte 3 +; ARM32-NEXT: .byte 3 ;; Indirect type IDs. -; CHECK-NEXT: .quad 4524972987496481828 -; CHECK-NEXT: .quad 3498816979441845844 -; CHECK-NEXT: .quad 8646233951371320954 +; ARM32-NEXT: .long 838288420 +; ARM32-NEXT: .long 1053552373 +; ARM32-NEXT: .long 1505527380 +; ARM32-NEXT: .long 814631809 +; ARM32-NEXT: .long 342417018 +; ARM32-NEXT: .long 2013108216 diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll index 34dc5b831de6d..2b108136b56ca 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll @@ -1,7 +1,12 @@ ;; Tests that we store the type identifiers in .callgraph section of the object file for tailcalls. +; REQUIRES: x86-registered-target +; REQUIRES: arm-registered-target + ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ -; RUN: llvm-readelf -x .callgraph - | FileCheck %s +; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=X64 %s +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ +; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=ARM32 %s define i32 @check_tailcall(ptr %func, i8 %x) !type !0 { entry: @@ -27,9 +32,15 @@ declare !type !2 i32 @bar(i8 signext) !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{i64 0, !"_ZTSFiiE.generalized"} -; CHECK: Hex dump of section '.callgraph': -; CHECK-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326 -; CHECK-NEXT: 0x00000010 e3000154 86bc5981 4b8e3000 05000000 +; X64: Hex dump of section '.callgraph': +; X64-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326 +; X64-NEXT: 0x00000010 e3000154 86bc5981 4b8e3000 05000000 +;; Verify that the type id 0x308e4b8159bc8654 is in section. +; X64-NEXT: 0x00000020 00000000 00a150b8 3e0cfe3c b2015486 +; X64-NEXT: 0x00000030 bc59814b 8e30 + +; ARM32: Hex dump of section '.callgraph': +; ARM32-NEXT: 0x00000000 00050000 00008e19 0b7f3326 e3000154 +; ARM32-NEXT: 0x00000010 86bc5981 4b8e3000 05100000 00a150b8 ;; Verify that the type id 0x308e4b8159bc8654 is in section. -; CHECK-NEXT: 0x00000020 00000000 00a150b8 3e0cfe3c b2015486 -; CHECK-NEXT: 0x00000030 bc59814b 8e30 +; ARM32-NEXT: 0x00000020 3e0cfe3c b2015486 bc59814b 8e30 diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll b/llvm/test/CodeGen/X86/call-graph-section.ll index c144a24439725..c064856a1f4a8 100644 --- a/llvm/test/CodeGen/X86/call-graph-section.ll +++ b/llvm/test/CodeGen/X86/call-graph-section.ll @@ -1,7 +1,12 @@ ;; Tests that we store the type identifiers in .callgraph section of the object file. +; REQUIRES: x86-registered-target +; REQUIRES: arm-registered-target + ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ -; RUN: llvm-readelf -x .callgraph - | FileCheck %s +; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=X64 %s +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ +; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=ARM32 %s declare !type !0 void @foo() @@ -31,7 +36,14 @@ entry: ;; Make sure following type IDs are in call graph section ;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 -; CHECK: Hex dump of section '.callgraph': -; CHECK-NEXT: 0x00000000 00050000 00000000 00000000 00000000 -; CHECK-NEXT: 0x00000010 00000324 44f731f5 eecb3e54 86bc5981 -; CHECK-NEXT: 0x00000020 4b8e307a de6814f8 97fd77 +; X64: Hex dump of section '.callgraph': +; X64-NEXT: 0x00000000 00050000 00000000 00000000 00000000 +; X64-NEXT: 0x00000010 00000324 44f731f5 eecb3e54 86bc5981 +; X64-NEXT: 0x00000020 4b8e307a de6814f8 97fd77 + +;; Make sure following type IDs are in call graph section +;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 +; ARM32: Hex dump of section '.callgraph': +; ARM32-NEXT: 0x00000000 00050000 00000000 00000000 00000324 +; ARM32-NEXT: 0x00000010 44f731f5 eecb3e54 86bc5981 4b8e307a +; ARM32-NEXT: 0x00000020 de6814f8 97fd77 From 528c063381916f0c06d70c5099a0c585a78dae12 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Tue, 7 Oct 2025 17:07:57 -0700 Subject: [PATCH 15/18] Address review comments. --- llvm/docs/CallGraphSection.md | 4 +- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 12 +++- .../ARM/call-graph-section-assembly.ll | 63 ++++++++++++++++++ .../ARM/call-graph-section-tailcall.ll | 34 ++++++++++ llvm/test/CodeGen/ARM/call-graph-section.ll | 37 +++++++++++ .../X86/call-graph-section-assembly.ll | 64 +++++-------------- .../X86/call-graph-section-tailcall.ll | 23 ++----- llvm/test/CodeGen/X86/call-graph-section.ll | 22 ++----- 8 files changed, 172 insertions(+), 87 deletions(-) create mode 100644 llvm/test/CodeGen/ARM/call-graph-section-assembly.ll create mode 100644 llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll create mode 100644 llvm/test/CodeGen/ARM/call-graph-section.ll diff --git a/llvm/docs/CallGraphSection.md b/llvm/docs/CallGraphSection.md index 2f72e91f089bd..8b18727098545 100644 --- a/llvm/docs/CallGraphSection.md +++ b/llvm/docs/CallGraphSection.md @@ -13,6 +13,6 @@ Each record in the `.callgraph` section has the following binary layout: | Function Entry PC | `uintptr_t` | 32/64 | The address of the function's entry point. | | Function Type ID | `uint64_t` | 64 | The type ID of the function. This field is non-zero if the function is a potential indirect call target and its type is known. | | Number of Unique Direct Callees | `ULEB128` | Variable | The number of unique direct call destinations from this function. This field is only present if there is at least one direct callee. | -| Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses. | +| Direct Callees Array | `uintptr_t[]` | Variable | An array of unique direct callee entry point addresses. This field is only present if there is at least one direct callee. | | Number of Unique Indirect Target Type IDs| `ULEB128` | Variable | The number of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. | -| Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. | +| Indirect Target Type IDs Array | `uint64_t[]` | Variable | An array of unique indirect call target type IDs. This field is only present if there is at least one indirect target type ID. | diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 9f2efdb656f80..e42e42fb7bdfc 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1696,13 +1696,19 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, const auto &DirectCallees = FuncCGInfo.DirectCallees; const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs; + enum CallGraphFlags : uint8_t { + IsIndirectTargetFlag = 1u << 0, + HasDirectCalleesFlag = 1u << 1, + HasIndirectCalleesFlag = 1u << 2, + }; + uint8_t Flags = 0; if (IsIndirectTarget) - Flags |= 1u << 0; // Set the first LSB bit to 1. + Flags |= IsIndirectTargetFlag; if (DirectCallees.size() > 0) - Flags |= 1u << 1; // Set the second LSB bit to 1. + Flags |= HasDirectCalleesFlag; if (IndirectCalleeTypeIDs.size() > 0) - Flags |= 1u << 2; // Set the third LSB bit to 1. + Flags |= HasIndirectCalleesFlag; // Emit function's call graph information. // 1) CallGraphSectionFormatVersion diff --git a/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll new file mode 100644 index 0000000000000..bf5249eb6c208 --- /dev/null +++ b/llvm/test/CodeGen/ARM/call-graph-section-assembly.ll @@ -0,0 +1,63 @@ +;; Test if temporary labels are generated for each indirect callsite. +;; Test if the .callgraph section contains the MD5 hash of callees' type (type id) +;; is correctly paired with its corresponding temporary label generated for indirect +;; call sites annotated with !callee_type metadata. +;; Test if the .callgraph section contains unique direct callees. + +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | FileCheck %s + +declare !type !0 void @direct_foo() +declare !type !1 i32 @direct_bar(i8) +declare !type !2 ptr @direct_baz(ptr) + +; CHECK: ball: +; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: +define ptr @ball() { +entry: + call void @direct_foo() + %fp_foo_val = load ptr, ptr null, align 8 + call void (...) %fp_foo_val(), !callee_type !0 + call void @direct_foo() + %fp_bar_val = load ptr, ptr null, align 8 + %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !2 + %call_fp_bar_direct = call i32 @direct_bar(i8 1) + %fp_baz_val = load ptr, ptr null, align 8 + %call_fp_baz = call ptr %fp_baz_val(ptr null), !callee_type !4 + call void @direct_foo() + %call_fp_baz_direct = call ptr @direct_baz(ptr null) + call void @direct_foo() + ret ptr %call_fp_baz +} + +!0 = !{!1} +!1 = !{i64 0, !"_ZTSFvE.generalized"} +!2 = !{!3} +!3 = !{i64 0, !"_ZTSFicE.generalized"} +!4 = !{!5} +!5 = !{i64 0, !"_ZTSFPvS_E.generalized"} + +; CHECK: .section .callgraph,"o",%progbits,.text +;; Version +; CHECK-NEXT: .byte 0 +;; Flags +; CHECK-NEXT: .byte 7 +;; Function Entry PC +; CHECK-NEXT: .long [[LABEL_FUNC]] +;; Function type ID -- set to 0 as no type metadata attached to function. +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +;; Number of unique direct callees. +; CHECK-NEXT: .byte 3 +;; Direct callees. +; CHECK-NEXT: .long direct_foo +; CHECK-NEXT: .long direct_bar +; CHECK-NEXT: .long direct_baz +;; Number of unique indirect target type IDs. +; CHECK-NEXT: .byte 3 +;; Indirect type IDs. +; CHECK-NEXT: .long 838288420 +; CHECK-NEXT: .long 1053552373 +; CHECK-NEXT: .long 1505527380 +; CHECK-NEXT: .long 814631809 +; CHECK-NEXT: .long 342417018 +; CHECK-NEXT: .long 2013108216 diff --git a/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll new file mode 100644 index 0000000000000..d5776030a8564 --- /dev/null +++ b/llvm/test/CodeGen/ARM/call-graph-section-tailcall.ll @@ -0,0 +1,34 @@ +;; Tests that we store the type identifiers in .callgraph section of the object file for tailcalls. + +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ +; RUN: llvm-readelf -x .callgraph - | FileCheck %s + +define i32 @check_tailcall(ptr %func, i8 %x) !type !0 { +entry: + %call = tail call i32 %func(i8 signext %x), !callee_type !1 + ret i32 %call +} + +define i32 @main(i32 %argc) !type !3 { +entry: + %andop = and i32 %argc, 1 + %cmp = icmp eq i32 %andop, 0 + %foo.bar = select i1 %cmp, ptr @foo, ptr @bar + %call.i = tail call i32 %foo.bar(i8 signext 97), !callee_type !1 + ret i32 %call.i +} + +declare !type !2 i32 @foo(i8 signext) + +declare !type !2 i32 @bar(i8 signext) + +!0 = !{i64 0, !"_ZTSFiPvcE.generalized"} +!1 = !{!2} +!2 = !{i64 0, !"_ZTSFicE.generalized"} +!3 = !{i64 0, !"_ZTSFiiE.generalized"} + +; CHECK: Hex dump of section '.callgraph': +; CHECK-NEXT: 0x00000000 00050000 00008e19 0b7f3326 e3000154 +; CHECK-NEXT: 0x00000010 86bc5981 4b8e3000 05100000 00a150b8 +;; Verify that the type id 0x308e4b8159bc8654 is in section. +; CHECK-NEXT: 0x00000020 3e0cfe3c b2015486 bc59814b 8e30 diff --git a/llvm/test/CodeGen/ARM/call-graph-section.ll b/llvm/test/CodeGen/ARM/call-graph-section.ll new file mode 100644 index 0000000000000..928a1067c81e4 --- /dev/null +++ b/llvm/test/CodeGen/ARM/call-graph-section.ll @@ -0,0 +1,37 @@ +;; Tests that we store the type identifiers in .callgraph section of the object file. + +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ +; RUN: llvm-readelf -x .callgraph - | FileCheck %s + +declare !type !0 void @foo() + +declare !type !1 i32 @bar(i8) + +declare !type !2 ptr @baz(ptr) + +define void @main() { +entry: + %fp_foo_val = load ptr, ptr null, align 8 + call void (...) %fp_foo_val(), !callee_type !1 + %fp_bar_val = load ptr, ptr null, align 8 + %call_fp_bar = call i32 %fp_bar_val(i8 0), !callee_type !3 + %fp_baz_val = load ptr, ptr null, align 8 + %call_fp_baz = call ptr %fp_baz_val(ptr null), !callee_type !4 + ret void +} + +;; Check that the numeric type id (md5 hash) for the below type ids are emitted +;; to the callgraph section. +!0 = !{i64 0, !"_ZTSFvE.generalized"} +!1 = !{!0} +!2 = !{i64 0, !"_ZTSFicE.generalized"} +!3 = !{!2} +!4 = !{!5} +!5 = !{i64 0, !"_ZTSFPvS_E.generalized"} + +;; Make sure following type IDs are in call graph section +;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 +; CHECK: Hex dump of section '.callgraph': +; CHECK-NEXT: 0x00000000 00050000 00000000 00000000 00000324 +; CHECK-NEXT: 0x00000010 44f731f5 eecb3e54 86bc5981 4b8e307a +; CHECK-NEXT: 0x00000020 de6814f8 97fd77 diff --git a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll index 63892e30fbf85..1aabf66d471c8 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-assembly.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-assembly.ll @@ -4,20 +4,14 @@ ;; call sites annotated with !callee_type metadata. ;; Test if the .callgraph section contains unique direct callees. -; REQUIRES: x86-registered-target -; REQUIRES: arm-registered-target - -; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck --check-prefix=X64 %s -; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | FileCheck --check-prefix=ARM32 %s +; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck %s declare !type !0 void @direct_foo() declare !type !1 i32 @direct_bar(i8) declare !type !2 ptr @direct_baz(ptr) -; X64: ball: -; X64-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: -; ARM32: ball: -; ARM32-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: +; CHECK: ball: +; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: define ptr @ball() { entry: call void @direct_foo() @@ -42,50 +36,24 @@ entry: !4 = !{!5} !5 = !{i64 0, !"_ZTSFPvS_E.generalized"} -; X64: .section .callgraph,"o",@progbits,.text -;; Version -; X64-NEXT: .byte 0 -;; Flags -; X64-NEXT: .byte 7 -;; Function Entry PC -; X64-NEXT: .quad [[LABEL_FUNC]] -;; Function type ID -- set to 0 as no type metadata attached to function. -; X64-NEXT: .quad 0 -;; Number of unique direct callees. -; X64-NEXT: .byte 3 -;; Direct callees. -; X64-NEXT: .quad direct_foo -; X64-NEXT: .quad direct_bar -; X64-NEXT: .quad direct_baz -;; Number of unique indirect target type IDs. -; X64-NEXT: .byte 3 -;; Indirect type IDs. -; X64-NEXT: .quad 4524972987496481828 -; X64-NEXT: .quad 3498816979441845844 -; X64-NEXT: .quad 8646233951371320954 - -; ARM32: .section .callgraph,"o",%progbits,.text +; CHECK: .section .callgraph,"o",@progbits,.text ;; Version -; ARM32-NEXT: .byte 0 +; CHECK-NEXT: .byte 0 ;; Flags -; ARM32-NEXT: .byte 7 +; CHECK-NEXT: .byte 7 ;; Function Entry PC -; ARM32-NEXT: .long [[LABEL_FUNC]] +; CHECK-NEXT: .quad [[LABEL_FUNC]] ;; Function type ID -- set to 0 as no type metadata attached to function. -; ARM32-NEXT: .long 0 -; ARM32-NEXT: .long 0 +; CHECK-NEXT: .quad 0 ;; Number of unique direct callees. -; ARM32-NEXT: .byte 3 +; CHECK-NEXT: .byte 3 ;; Direct callees. -; ARM32-NEXT: .long direct_foo -; ARM32-NEXT: .long direct_bar -; ARM32-NEXT: .long direct_baz +; CHECK-NEXT: .quad direct_foo +; CHECK-NEXT: .quad direct_bar +; CHECK-NEXT: .quad direct_baz ;; Number of unique indirect target type IDs. -; ARM32-NEXT: .byte 3 +; CHECK-NEXT: .byte 3 ;; Indirect type IDs. -; ARM32-NEXT: .long 838288420 -; ARM32-NEXT: .long 1053552373 -; ARM32-NEXT: .long 1505527380 -; ARM32-NEXT: .long 814631809 -; ARM32-NEXT: .long 342417018 -; ARM32-NEXT: .long 2013108216 +; CHECK-NEXT: .quad 4524972987496481828 +; CHECK-NEXT: .quad 3498816979441845844 +; CHECK-NEXT: .quad 8646233951371320954 diff --git a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll index 2b108136b56ca..34dc5b831de6d 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-tailcall.ll @@ -1,12 +1,7 @@ ;; Tests that we store the type identifiers in .callgraph section of the object file for tailcalls. -; REQUIRES: x86-registered-target -; REQUIRES: arm-registered-target - ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ -; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=X64 %s -; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ -; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=ARM32 %s +; RUN: llvm-readelf -x .callgraph - | FileCheck %s define i32 @check_tailcall(ptr %func, i8 %x) !type !0 { entry: @@ -32,15 +27,9 @@ declare !type !2 i32 @bar(i8 signext) !2 = !{i64 0, !"_ZTSFicE.generalized"} !3 = !{i64 0, !"_ZTSFiiE.generalized"} -; X64: Hex dump of section '.callgraph': -; X64-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326 -; X64-NEXT: 0x00000010 e3000154 86bc5981 4b8e3000 05000000 -;; Verify that the type id 0x308e4b8159bc8654 is in section. -; X64-NEXT: 0x00000020 00000000 00a150b8 3e0cfe3c b2015486 -; X64-NEXT: 0x00000030 bc59814b 8e30 - -; ARM32: Hex dump of section '.callgraph': -; ARM32-NEXT: 0x00000000 00050000 00008e19 0b7f3326 e3000154 -; ARM32-NEXT: 0x00000010 86bc5981 4b8e3000 05100000 00a150b8 +; CHECK: Hex dump of section '.callgraph': +; CHECK-NEXT: 0x00000000 00050000 00000000 00008e19 0b7f3326 +; CHECK-NEXT: 0x00000010 e3000154 86bc5981 4b8e3000 05000000 ;; Verify that the type id 0x308e4b8159bc8654 is in section. -; ARM32-NEXT: 0x00000020 3e0cfe3c b2015486 bc59814b 8e30 +; CHECK-NEXT: 0x00000020 00000000 00a150b8 3e0cfe3c b2015486 +; CHECK-NEXT: 0x00000030 bc59814b 8e30 diff --git a/llvm/test/CodeGen/X86/call-graph-section.ll b/llvm/test/CodeGen/X86/call-graph-section.ll index c064856a1f4a8..c144a24439725 100644 --- a/llvm/test/CodeGen/X86/call-graph-section.ll +++ b/llvm/test/CodeGen/X86/call-graph-section.ll @@ -1,12 +1,7 @@ ;; Tests that we store the type identifiers in .callgraph section of the object file. -; REQUIRES: x86-registered-target -; REQUIRES: arm-registered-target - ; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ -; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=X64 %s -; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -filetype=obj -o - < %s | \ -; RUN: llvm-readelf -x .callgraph - | FileCheck --check-prefix=ARM32 %s +; RUN: llvm-readelf -x .callgraph - | FileCheck %s declare !type !0 void @foo() @@ -36,14 +31,7 @@ entry: ;; Make sure following type IDs are in call graph section ;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 -; X64: Hex dump of section '.callgraph': -; X64-NEXT: 0x00000000 00050000 00000000 00000000 00000000 -; X64-NEXT: 0x00000010 00000324 44f731f5 eecb3e54 86bc5981 -; X64-NEXT: 0x00000020 4b8e307a de6814f8 97fd77 - -;; Make sure following type IDs are in call graph section -;; 0x5eecb3e2444f731f, 0x814b8e305486bc59, 0xf897fd777ade6814 -; ARM32: Hex dump of section '.callgraph': -; ARM32-NEXT: 0x00000000 00050000 00000000 00000000 00000324 -; ARM32-NEXT: 0x00000010 44f731f5 eecb3e54 86bc5981 4b8e307a -; ARM32-NEXT: 0x00000020 de6814f8 97fd77 +; CHECK: Hex dump of section '.callgraph': +; CHECK-NEXT: 0x00000000 00050000 00000000 00000000 00000000 +; CHECK-NEXT: 0x00000010 00000324 44f731f5 eecb3e54 86bc5981 +; CHECK-NEXT: 0x00000020 4b8e307a de6814f8 97fd77 From 229e9d069f008d8e4f8345ace7ef4b88f1ea8a24 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Wed, 8 Oct 2025 16:39:22 -0700 Subject: [PATCH 16/18] Add test for internal linkage with address taken regresstion test which also tests callback case. --- .../ARM/call-graph-section-addrtaken.ll | 37 +++++++++++++++++++ .../X86/call-graph-section-addrtaken.ll | 36 ++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll create mode 100644 llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll diff --git a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll new file mode 100644 index 0000000000000..b63222bbbc21b --- /dev/null +++ b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll @@ -0,0 +1,37 @@ +;; Test if a potential indirect call target function which has internal linkage and +;; address taken has its type ID emitted to callgraph section. +;; This test also makes sure that callback functions which meet the above constraint +;; are handled correctly. + +; RUN: llc -mtriple=arm-unknown-linux --call-graph-section -o - < %s | FileCheck %s + +declare !type !0 void @_Z6doWorkPFviE(ptr) + +define i32 @_Z4testv() !type !1 { +entry: + call void @_Z6doWorkPFviE(ptr nonnull @_ZL10myCallbacki) + ret i32 0 +} + +define internal void @_ZL10myCallbacki(i32 %value) !type !2 { +entry: + %sink = alloca i32, align 4 + store volatile i32 %value, ptr %sink, align 4 + %i1 = load volatile i32, ptr %sink, align 4 + ret void +} + +!0 = !{i64 0, !"_ZTSFvPFviEE.generalized"} +!1 = !{i64 0, !"_ZTSFivE.generalized"} +!2 = !{i64 0, !"_ZTSFviE.generalized"} + +; CHECK: .section .callgraph,"o",%progbits,.text +;; Version +; CHECK-NEXT: .byte 0 +;; Flags -- Potential indirect target so LSB is set to 1. Other bits are 0. +; CHECK-NEXT: .byte 1 +;; Function Entry PC +; CHECK-NEXT: .long [[LABEL_FUNC]] +;; Function type ID -5212364466660467813 +; CHECK-NEXT: .long 1154849691 +; CHECK-NEXT: .long 3081369122 diff --git a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll new file mode 100644 index 0000000000000..6bc8ece28039c --- /dev/null +++ b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll @@ -0,0 +1,36 @@ +;; Test if a potential indirect call target function which has internal linkage and +;; address taken has its type ID emitted to callgraph section. +;; This test also makes sure that callback functions which meet the above constraint +;; are handled correctly. + +; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck %s + +declare !type !0 void @_Z6doWorkPFviE(ptr) + +define i32 @_Z4testv() !type !1 { +entry: + call void @_Z6doWorkPFviE(ptr nonnull @_ZL10myCallbacki) + ret i32 0 +} + +define internal void @_ZL10myCallbacki(i32 %value) !type !2 { +entry: + %sink = alloca i32, align 4 + store volatile i32 %value, ptr %sink, align 4 + %i1 = load volatile i32, ptr %sink, align 4 + ret void +} + +!0 = !{i64 0, !"_ZTSFvPFviEE.generalized"} +!1 = !{i64 0, !"_ZTSFivE.generalized"} +!2 = !{i64 0, !"_ZTSFviE.generalized"} + +; CHECK: .section .callgraph,"o",@progbits,.text +;; Version +; CHECK-NEXT: .byte 0 +;; Flags -- Potential indirect target so LSB is set to 1. Other bits are 0. +; CHECK-NEXT: .byte 1 +;; Function Entry PC +; CHECK-NEXT: .quad [[LABEL_FUNC]] +;; Function type ID +; CHECK-NEXT: .quad -5212364466660467813 From 4142fa70f28509ba7b8853fd0dcb4d855dac3600 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Wed, 8 Oct 2025 17:11:55 -0700 Subject: [PATCH 17/18] Fix tests. --- llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll | 2 ++ llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll | 2 ++ 2 files changed, 4 insertions(+) diff --git a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll index b63222bbbc21b..a2d6ca9cd6bb5 100644 --- a/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll +++ b/llvm/test/CodeGen/ARM/call-graph-section-addrtaken.ll @@ -13,6 +13,8 @@ entry: ret i32 0 } +; CHECK: _ZL10myCallbacki: +; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: define internal void @_ZL10myCallbacki(i32 %value) !type !2 { entry: %sink = alloca i32, align 4 diff --git a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll index 6bc8ece28039c..2aea9c1dde1c5 100644 --- a/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll +++ b/llvm/test/CodeGen/X86/call-graph-section-addrtaken.ll @@ -13,6 +13,8 @@ entry: ret i32 0 } +; CHECK: _ZL10myCallbacki: +; CHECK-NEXT: [[LABEL_FUNC:\.Lfunc_begin[0-9]+]]: define internal void @_ZL10myCallbacki(i32 %value) !type !2 { entry: %sink = alloca i32, align 4 From 2ef884543359687c7270d6852f1c5d36bcad1f23 Mon Sep 17 00:00:00 2001 From: prabhukr Date: Wed, 8 Oct 2025 17:14:42 -0700 Subject: [PATCH 18/18] Use llvm bitmask enum validation for flags. --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index e42e42fb7bdfc..34c1ff4692f0a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -20,6 +20,7 @@ #include "WinException.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -205,6 +206,17 @@ class AddrLabelMapCallbackPtr final : CallbackVH { }; } // namespace +namespace callgraph { +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); +enum Flags : uint8_t { + None = 0, + IsIndirectTarget = 1u << 0, + HasDirectCallees = 1u << 1, + HasIndirectCallees = 1u << 2, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ HasIndirectCallees) +}; +} // namespace callgraph + class llvm::AddrLabelMap { MCContext &Context; struct AddrLabelSymEntry { @@ -1696,19 +1708,14 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, const auto &DirectCallees = FuncCGInfo.DirectCallees; const auto &IndirectCalleeTypeIDs = FuncCGInfo.IndirectCalleeTypeIDs; - enum CallGraphFlags : uint8_t { - IsIndirectTargetFlag = 1u << 0, - HasDirectCalleesFlag = 1u << 1, - HasIndirectCalleesFlag = 1u << 2, - }; - - uint8_t Flags = 0; + using namespace callgraph; + Flags CGFlags = Flags::None; if (IsIndirectTarget) - Flags |= IsIndirectTargetFlag; + CGFlags |= Flags::IsIndirectTarget; if (DirectCallees.size() > 0) - Flags |= HasDirectCalleesFlag; + CGFlags |= Flags::HasDirectCallees; if (IndirectCalleeTypeIDs.size() > 0) - Flags |= HasIndirectCalleesFlag; + CGFlags |= Flags::HasIndirectCallees; // Emit function's call graph information. // 1) CallGraphSectionFormatVersion @@ -1726,7 +1733,7 @@ void AsmPrinter::emitCallGraphSection(const MachineFunction &MF, // 7) Number of unique indirect target type IDs, if at least one exists. // 8) Each unique indirect target type id. OutStreamer->emitInt8(CallGraphSectionFormatVersion::V_0); - OutStreamer->emitInt8(Flags); + OutStreamer->emitInt8(static_cast(CGFlags)); OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize()); const auto *TypeId = extractNumericCGTypeId(F); if (IsIndirectTarget && TypeId)