Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[llvm][AsmPrinter] Emit call graph section #87576

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 44 commits into
base: users/Prabhuk/sprmain.asmprintercallgraphsection-emit-call-graph-section-4
Choose a base branch
Loading
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
d163d80
[𝘀𝗽𝗿] initial version
necipfazil Apr 3, 2024
dd26405
Updated fixme on PR 87570
necipfazil Apr 22, 2024
b5b03fd
Rebased on top of main
necipfazil Apr 24, 2024
b90a4d5
dyn_cast to isa
necipfazil Apr 29, 2024
332f2aa
Rebased on upstream main.
necipfazil May 1, 2024
1209081
Rebase patchset
necipfazil Nov 14, 2024
1981340
Update inline comment as suggested.
necipfazil Nov 14, 2024
423d5f2
Addressed review comments.
necipfazil Nov 19, 2024
e51ce07
Rebase on top of upstream main.
necipfazil Nov 20, 2024
e4684b8
Break clang and llvm parts into separate commits.
necipfazil Nov 20, 2024
7f15e6b
Reorder commits.
necipfazil Dec 10, 2024
3fad066
Rebase on top of main.
necipfazil Feb 2, 2025
1fd9775
Rename OB_type to OB_callee_type.
necipfazil Feb 5, 2025
2f763c0
Rebase on top of main
necipfazil Feb 11, 2025
5e6675b
Update IR verifier.
necipfazil Feb 11, 2025
39e5b93
Add requested tests part 1.
necipfazil Mar 13, 2025
f18f492
Update comments in tests.
necipfazil Mar 13, 2025
6b67376
Updated the test as reviewers suggested.
necipfazil Mar 13, 2025
d2bb381
Scoped enum. Simplify test.
necipfazil Mar 13, 2025
e3c95b5
Remove unnecessary cast.
necipfazil Mar 13, 2025
835c2e2
Remove unnecessary asserts. Remove autos for better readability.
necipfazil Mar 13, 2025
678008e
Reorder IR metadata and rename temporary var names in test.
necipfazil Mar 13, 2025
5831ed4
Add RISC-V support. Clean up test files.
necipfazil Mar 14, 2025
77ce9ab
Clean up test files.
necipfazil Mar 15, 2025
7d8418c
Address code refactoring comments.
necipfazil Mar 19, 2025
19043db
Use CalleeTypeIds list to emit callgraph section.
necipfazil Apr 19, 2025
0754d49
Address review comments.
necipfazil Apr 19, 2025
cf2e510
Extract callsite label emission as a private method.
necipfazil Apr 23, 2025
80df0c0
Address review comments.
necipfazil Apr 23, 2025
20679e7
Address review comments.
necipfazil Apr 23, 2025
48e878c
Address review comments.
necipfazil Apr 24, 2025
aeaa155
Separate the assembly test for callgraph section and related labels i…
necipfazil Apr 24, 2025
f248de4
Rebase on parent.
necipfazil Apr 24, 2025
516dee0
Add llvm-mc test. Address comments.
necipfazil Apr 28, 2025
b45026e
Update test inline comments.
necipfazil Apr 29, 2025
106364f
Rebase on parent.
necipfazil May 1, 2025
9a561db
Rebase on parent.
necipfazil May 5, 2025
5778238
Rebase on parent change.
necipfazil May 10, 2025
caae8ac
Remove dso_local and noundef from tests.
necipfazil May 13, 2025
dcf4495
Rebase on parent.
necipfazil May 13, 2025
9d25b19
Rebase on parent
necipfazil May 14, 2025
837e254
Rebase on main.
necipfazil May 14, 2025
65a4435
Drop local_unnamed_addr.
necipfazil May 27, 2025
e1e3fd1
Rebase change.
necipfazil May 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions 39 llvm/include/llvm/CodeGen/AsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,36 @@ class AsmPrinter : public MachineFunctionPass {
/// Emit comments in assembly output if this is true.
bool VerboseAsm;

/// Store symbols and type identifiers used to create call graph section
/// entries related to a function.
struct FunctionInfo {
/// Numeric type identifier used in call graph section for indirect calls
/// and targets.
using CGTypeId = uint64_t;

/// Enumeration of function kinds, and their mapping to function kind values
/// stored in call graph section entries.
/// Must match the enum in llvm/tools/llvm-objdump/llvm-objdump.cpp.
enum class FunctionKind : uint64_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,
};

/// Map type identifiers to callsite labels. Labels are only for indirect
/// calls and inclusive of all indirect calls of the function.
SmallVector<std::pair<CGTypeId, MCSymbol *>> CallSiteLabels;
};

enum CallGraphSectionFormatVersion : uint64_t {
V_0 = 0,
};

/// Output stream for the stack usage file (i.e., .su file).
std::unique_ptr<raw_fd_ostream> StackUsageStream;

Expand Down Expand Up @@ -342,6 +372,13 @@ class AsmPrinter : public MachineFunctionPass {
/// are available. Returns empty string otherwise.
StringRef getConstantSectionSuffix(const Constant *C) const;

/// Generate and emit labels for callees of the indirect callsites which will
/// be used to populate the .callgraph section.
void emitIndirectCalleeLabels(
FunctionInfo &FuncInfo,
const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
const MachineInstr &MI);

//===------------------------------------------------------------------===//
// XRay instrumentation implementation.
//===------------------------------------------------------------------===//
Expand Down Expand Up @@ -429,6 +466,8 @@ class AsmPrinter : public MachineFunctionPass {
void emitKCFITrapEntry(const MachineFunction &MF, const MCSymbol *Symbol);
virtual void emitKCFITypeId(const MachineFunction &MF);

void emitCallGraphSection(const MachineFunction &MF, FunctionInfo &FuncInfo);

void emitPseudoProbe(const MachineInstr &MI);

void emitRemarksSection(remarks::RemarkStreamer &RS);
Expand Down
3 changes: 2 additions & 1 deletion 3 llvm/include/llvm/CodeGen/MachineFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,12 @@ class LLVM_ABI MachineFunction {
unsigned TargetFlags;
};

using CallSiteInfoMap = DenseMap<const MachineInstr *, CallSiteInfo>;

private:
Delegate *TheDelegate = nullptr;
GISelChangeObserver *Observer = nullptr;

using CallSiteInfoMap = DenseMap<const MachineInstr *, CallSiteInfo>;
/// Map a call instruction to call site arguments forwarding info.
CallSiteInfoMap CallSitesInfo;

Expand Down
5 changes: 5 additions & 0 deletions 5 llvm/include/llvm/MC/MCObjectFileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class MCObjectFileInfo {
/// Language Specific Data Area information is emitted to.
MCSection *LSDASection = nullptr;

/// Section containing call graph metadata.
MCSection *CallGraphSection = nullptr;

/// If exception handling is supported by the target and the target can
/// support a compact representation of the CIE and FDE, this is the section
/// to emit them into.
Expand Down Expand Up @@ -360,6 +363,8 @@ class MCObjectFileInfo {
MCSection *getFaultMapSection() const { return FaultMapSection; }
MCSection *getRemarksSection() const { return RemarksSection; }

MCSection *getCallGraphSection(const MCSection &TextSec) const;

MCSection *getStackSizesSection(const MCSection &TextSec) const;

MCSection *getBBAddrMapSection(const MCSection &TextSec) const;
Expand Down
119 changes: 119 additions & 0 deletions 119 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1640,6 +1640,94 @@ void AsmPrinter::emitStackUsage(const MachineFunction &MF) {
*StackUsageStream << "static\n";
}

/// Extracts a generalized numeric type identifier of a Function's type from
/// type metadata. Returns null if metadata cannot be found.
static ConstantInt *extractNumericCGTypeId(const Function &F) {
SmallVector<MDNode *, 2> Types;
F.getMetadata(LLVMContext::MD_type, Types);
for (const auto &Type : Types) {
if (Type->hasGeneralizedMDString()) {
MDString *MDGeneralizedTypeId = cast<MDString>(Type->getOperand(1));
uint64_t TypeIdVal = llvm::MD5Hash(MDGeneralizedTypeId->getString());
IntegerType *Int64Ty = Type::getInt64Ty(F.getContext());
return ConstantInt::get(Int64Ty, TypeIdVal);
}
}

return nullptr;
}

/// Emits .callgraph section.
void AsmPrinter::emitCallGraphSection(const MachineFunction &MF,
FunctionInfo &FuncInfo) {
if (!MF.getTarget().Options.EmitCallGraphSection)
return;

// Switch to the call graph section for the function
MCSection *FuncCGSection =
getObjFileLowering().getCallGraphSection(*getCurrentSection());
Prabhuk marked this conversation as resolved.
Show resolved Hide resolved
assert(FuncCGSection && "null callgraph section");
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<uint64_t>(FunctionInfo::FunctionKind::NOT_INDIRECT_TARGET));
Prabhuk marked this conversation as resolved.
Show resolved Hide resolved
} else {
const auto *TypeId = extractNumericCGTypeId(F);
if (TypeId) {
OutStreamer->emitInt64(static_cast<uint64_t>(
FunctionInfo::FunctionKind::INDIRECT_TARGET_KNOWN_TID));
OutStreamer->emitInt64(TypeId->getZExtValue());
} else {
OutStreamer->emitInt64(static_cast<uint64_t>(
FunctionInfo::FunctionKind::INDIRECT_TARGET_UNKNOWN_TID));
}
}

// Emit callsite labels, where each element is a pair of type id and
// indirect callsite pc.
const auto &CallSiteLabels = FuncInfo.CallSiteLabels;

// Emit the count of pairs.
OutStreamer->emitInt64(CallSiteLabels.size());

// Emit the type id and call site label pairs.
for (const auto &[TypeId, Label] : CallSiteLabels) {
OutStreamer->emitInt64(TypeId);
OutStreamer->emitSymbolValue(Label, TM.getProgramPointerSize());
}
FuncInfo.CallSiteLabels.clear();

OutStreamer->popSection();
}

void AsmPrinter::emitPCSectionsLabel(const MachineFunction &MF,
const MDNode &MD) {
MCSymbol *S = MF.getContext().createTempSymbol("pcsection");
Expand Down Expand Up @@ -1770,6 +1858,28 @@ static StringRef getMIMnemonic(const MachineInstr &MI, MCStreamer &Streamer) {
return Name;
}

void AsmPrinter::emitIndirectCalleeLabels(
FunctionInfo &FuncInfo,
const MachineFunction::CallSiteInfoMap &CallSitesInfoMap,
const MachineInstr &MI) {
// Only indirect calls have type identifiers set.
const auto &CallSiteInfo = CallSitesInfoMap.find(&MI);
if (CallSiteInfo == CallSitesInfoMap.end())
return;

for (ConstantInt *CalleeTypeId : CallSiteInfo->second.CalleeTypeIds) {
// Emit label.
MCSymbol *S = MF->getContext().createTempSymbol();
OutStreamer->emitLabel(S);

// Get numeric callee_type id value.
uint64_t CalleeTypeIdVal = CalleeTypeId->getZExtValue();

// Add to function's callsite labels.
FuncInfo.CallSiteLabels.emplace_back(CalleeTypeIdVal, S);
}
}

/// EmitFunctionBody - This method emits the body and trailer for a
/// function.
void AsmPrinter::emitFunctionBody() {
Expand Down Expand Up @@ -1816,6 +1926,8 @@ void AsmPrinter::emitFunctionBody() {
MBBSectionRanges[MF->front().getSectionID()] =
MBBSectionRange{CurrentFnBegin, nullptr};

FunctionInfo FuncInfo;
const auto &CallSitesInfoMap = MF->getCallSitesInfo();
for (auto &MBB : *MF) {
// Print a label for the basic block.
emitBasicBlockStart(MBB);
Expand Down Expand Up @@ -1946,6 +2058,9 @@ void AsmPrinter::emitFunctionBody() {
break;
}

if (TM.Options.EmitCallGraphSection && MI.isCall())
emitIndirectCalleeLabels(FuncInfo, CallSitesInfoMap, MI);

// If there is a post-instruction symbol, emit a label for it here.
if (MCSymbol *S = MI.getPostInstrSymbol())
OutStreamer->emitLabel(S);
Expand Down Expand Up @@ -2125,6 +2240,9 @@ void AsmPrinter::emitFunctionBody() {
// Emit section containing stack size metadata.
emitStackSizeSection(*MF);

// Emit section containing call graph metadata.
emitCallGraphSection(*MF, FuncInfo);

// Emit .su file containing function stack size information.
emitStackUsage(*MF);

Expand Down Expand Up @@ -2799,6 +2917,7 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
F.hasFnAttribute("xray-instruction-threshold") ||
needFuncLabels(MF, *this) || NeedsLocalForSize ||
MF.getTarget().Options.EmitStackSizeSection ||
MF.getTarget().Options.EmitCallGraphSection ||
MF.getTarget().Options.BBAddrMap) {
CurrentFnBegin = createTempSymbol("func_begin");
if (NeedsLocalForSize)
Expand Down
20 changes: 20 additions & 0 deletions 20 llvm/lib/MC/MCObjectFileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
EHFrameSection =
Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags);

CallGraphSection = Ctx->getELFSection(".callgraph", ELF::SHT_PROGBITS, 0);

StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0);

PseudoProbeSection = Ctx->getELFSection(".pseudo_probe", DebugSecType, 0);
Expand Down Expand Up @@ -1081,6 +1083,24 @@ MCSection *MCObjectFileInfo::getDwarfComdatSection(const char *Name,
llvm_unreachable("Unknown ObjectFormatType");
}

MCSection *
MCObjectFileInfo::getCallGraphSection(const MCSection &TextSec) const {
if (Ctx->getObjectFileType() != MCContext::IsELF)
return CallGraphSection;

const MCSectionELF &ElfSec = static_cast<const MCSectionELF &>(TextSec);
unsigned Flags = ELF::SHF_LINK_ORDER;
StringRef GroupName;
if (const MCSymbol *Group = ElfSec.getGroup()) {
GroupName = Group->getName();
Flags |= ELF::SHF_GROUP;
}

return Ctx->getELFSection(".callgraph", ELF::SHT_PROGBITS, Flags, 0,
GroupName, true, ElfSec.getUniqueID(),
cast<MCSymbolELF>(TextSec.getBeginSymbol()));
}

MCSection *
MCObjectFileInfo::getStackSizesSection(const MCSection &TextSec) const {
if ((Ctx->getObjectFileType() != MCContext::IsELF) ||
Expand Down
60 changes: 60 additions & 0 deletions 60 llvm/test/CodeGen/X86/call-graph-section-assembly.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
;; Test if temporary labels are generated for each indirect callsite with a callee_type metadata.
;; Test if the .callgraph section contains the numerical callee type id for each of the temporary
;; labels generated.

; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -o - < %s | FileCheck %s

declare !type !0 void @foo()

declare !type !1 i32 @bar(i8 signext)

declare !type !2 ptr @baz(ptr)

; CHECK: ball:
; CHECK-NEXT: .Lfunc_begin0:
define void @ball() {
entry:
%retval = alloca i32, align 4
%fp_foo = alloca ptr, align 8
%a = alloca i8, align 1
%fp_bar = alloca ptr, align 8
%fp_baz = alloca ptr, align 8
store i32 0, ptr %retval, align 4
store ptr @foo, ptr %fp_foo, align 8
%fp_foo_val = load ptr, ptr %fp_foo, align 8
; CHECK: .Ltmp0:
call void (...) %fp_foo_val(), !callee_type !1
store ptr @bar, ptr %fp_bar, align 8
%fp_bar_val = load ptr, ptr %fp_bar, align 8
%a_val = load i8, ptr %a, align 1
; CHECK: .Ltmp1:
%call_fp_bar = call i32 %fp_bar_val(i8 signext %a_val), !callee_type !3
store ptr @baz, ptr %fp_baz, align 8
%fp_baz_val = load ptr, ptr %fp_baz, align 8
; CHECK: .Ltmp2:
%call_fp_baz = call ptr %fp_baz_val(ptr %a), !callee_type !5
call void @foo()
%a_val_2 = load i8, ptr %a, align 1
%call_bar = call i32 @bar(i8 signext %a_val_2)
%call_baz = call ptr @baz(ptr %a)
ret void
}

; CHECK: .section .callgraph,"o",@progbits,.text

; CHECK-NEXT: .quad 0
; CHECK-NEXT: .quad .Lfunc_begin0
; CHECK-NEXT: .quad 1
; CHECK-NEXT: .quad 3
; CHECK-NEXT: .quad 4524972987496481828
; CHECK-NEXT: .quad .Ltmp0
!0 = !{i64 0, !"_ZTSFvE.generalized"}
!1 = !{!0}
; CHECK-NEXT: .quad 3498816979441845844
; CHECK-NEXT: .quad .Ltmp1
!2 = !{i64 0, !"_ZTSFicE.generalized"}
!3 = !{!2}
; CHECK-NEXT: .quad 8646233951371320954
; CHECK-NEXT: .quad .Ltmp2
!4 = !{i64 0, !"_ZTSFPvS_E.generalized"}
!5 = !{!4}
34 changes: 34 additions & 0 deletions 34 llvm/test/CodeGen/X86/call-graph-section-tailcall.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
;; Tests that we store the type identifiers in .callgraph section of the object file for tailcalls.

; RUN: llc -mtriple=x86_64-unknown-linux --call-graph-section -filetype=obj -o - < %s | \
; RUN: llvm-readelf -x .callgraph - | FileCheck %s

define i32 @_Z13call_indirectPFicEc(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:
%0 = and i32 %argc, 1
%cmp = icmp eq i32 %0, 0
%_Z3fooc._Z3barc = select i1 %cmp, ptr @_Z3fooc, ptr @_Z3barc
%call.i = tail call i32 %_Z3fooc._Z3barc(i8 signext 97), !callee_type !1
ret i32 %call.i
}

declare !type !2 i32 @_Z3fooc(i8 signext)

declare !type !2 i32 @_Z3barc(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}
; CHECK-DAG: 5486bc59 814b8e30
!2 = !{i64 0, !"_ZTSFicE.generalized"}
!3 = !{i64 0, !"_ZTSFiiE.generalized"}
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.