[llvm] [BOLT] Check CallProfile annotation in buildCallGraph (PR #134733)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 8 13:51:16 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-bolt
Author: Amir Ayupov (aaupov)
<details>
<summary>Changes</summary>
For indirect jumps with unknown control flow, BOLT will not set a tail
call annotation, which results in skipping such sites in call graph
construction, even if the jump has CallProfile annotation.
Missing call graph edges in turn hurt function ordering, especially when
they are hot.
Example from mkl_blas_xsgemm:
```
jmpq *%rax # UNKNOWN CONTROL FLOW # CallProfile: 506787 (0 misses) :
{ mkl_blas_avx512_xsgemm: 506787 (0 misses) }
```
Explicitly check the presence of a CallProfile annotation to avoid
missing call graph edge.
Test Plan: added unknown-cf-call-graph.s
---
Full diff: https://github.com/llvm/llvm-project/pull/134733.diff
2 Files Affected:
- (modified) bolt/lib/Core/BinaryFunctionCallGraph.cpp (+4-1)
- (added) bolt/test/X86/unknown-cf-call-graph.s (+67)
``````````diff
diff --git a/bolt/lib/Core/BinaryFunctionCallGraph.cpp b/bolt/lib/Core/BinaryFunctionCallGraph.cpp
index b4b7897aa426a..5f99d008ebfe1 100644
--- a/bolt/lib/Core/BinaryFunctionCallGraph.cpp
+++ b/bolt/lib/Core/BinaryFunctionCallGraph.cpp
@@ -252,7 +252,10 @@ buildCallGraph(BinaryContext &BC, CgFilterFunction Filter, bool CgFromPerfData,
for (MCInst &Inst : *BB) {
// Find call instructions and extract target symbols from each one.
- if (BC.MIB->isCall(Inst)) {
+ // Check CallProfile annotation if the instruction is not recognized
+ // as a call, e.g. unknown control flow indirect jump.
+ if (BC.MIB->isCall(Inst) ||
+ BC.MIB->hasAnnotation(Inst, "CallProfile")) {
const CallInfoTy CallInfo = getCallInfo(BB, Inst);
if (!CallInfo.empty()) {
diff --git a/bolt/test/X86/unknown-cf-call-graph.s b/bolt/test/X86/unknown-cf-call-graph.s
new file mode 100644
index 0000000000000..07b8ce335fbde
--- /dev/null
+++ b/bolt/test/X86/unknown-cf-call-graph.s
@@ -0,0 +1,67 @@
+## Check that indirect jumps with unknown control flow and set call profile are
+## handled in call graph construction.
+
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/src -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt %t.exe -o %t.out --lite=0 -print-cfg -data %t/yaml \
+# RUN: --print-only=main --reorder-functions=cdsort --dump-cg=%t.dot \
+# RUN: --profile-ignore-hash | FileCheck %s
+# RUN: FileCheck --input-file %t.dot --check-prefix=CHECK-CG %s
+# CHECK-CG: digraph g {
+# CHECK-CG-NEXT: f0 [label="main
+# CHECK-CG-NEXT: f1 [label="foo
+# CHECK-CG-NEXT: f0 -> f1 [label="normWgt=0.000,weight=1000,callOffset=0.0"];
+# CHECK-CG-NEXT: }
+#--- src
+ .globl main
+ .type main, %function
+ .p2align 2
+main:
+ jmpq *%rax
+# CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW # CallProfile: 1000 (0 misses) :
+# CHECK-NEXT: { foo: 1000 (0 misses) }
+ jmpq *%rbx
+.size main, .-main
+
+ .globl foo
+ .type foo, %function
+ .p2align 2
+foo:
+ ud2
+.size foo, .-foo
+.reloc 0, R_X86_64_NONE
+#--- yaml
+---
+header:
+ profile-version: 1
+ binary-name: 'test'
+ binary-build-id: 0
+ profile-flags: [ lbr ]
+ profile-origin: perf data aggregator
+ profile-events: ''
+ dfs-order: false
+ hash-func: xxh3
+functions:
+ - name: main
+ fid: 1
+ hash: 0x1
+ exec: 1000
+ nblocks: 1
+ blocks:
+ - bid: 0
+ insns: 1
+ hash: 0x1
+ exec: 1000
+ calls: [ { off: 0x0, fid: 2, cnt: 1000 } ]
+ - name: foo
+ fid: 2
+ hash: 0x2
+ exec: 1000
+ nblocks: 1
+ blocks:
+ - bid: 0
+ insns: 1
+ hash: 0x1
+ exec: 1000
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/134733
More information about the llvm-commits
mailing list