[llvm] [BOLT] Add dump-dot-func option for selective function CFG dumping (PR #153007)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 11 06:58:56 PDT 2025
https://github.com/yafet-a created https://github.com/llvm/llvm-project/pull/153007
## Change:
* Added `--dump-dot-func` command-line option that allows users to dump CFGs only for specific functions instead of dumping all functions (the current only available option being `--dump-dot-all`)
## Usage:
* Users can now specify function names or regex patterns (e.g., `--dump-dot-func=main,helper` or `--dump-dot-func="init.*`") to generate .dot files only for functions of interest
* Aims to save time when analysing specific functions in large binaries (e.g., only dumping graphs for performance-critical functions identified through profiling) and we can now avoid reduce output clutter from generating thousands of unnecessary .dot files when analysing large binaries
>From 2a2216f7ae07080d823d136c801cfca99a232b07 Mon Sep 17 00:00:00 2001
From: Yafet Beyene <ybeyene at nvidia.com>
Date: Fri, 8 Aug 2025 09:01:41 -0700
Subject: [PATCH 1/2] [BOLT] dump-dot-func option added to bolt
---
bolt/include/bolt/Utils/CommandLineOpts.h | 9 +++++++
bolt/lib/Rewrite/BinaryPassManager.cpp | 3 ++-
bolt/lib/Rewrite/RewriteInstance.cpp | 31 ++++++++++++++++++++++-
3 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h
index a75b6bf720ec4..859d6f3bf6774 100644
--- a/bolt/include/bolt/Utils/CommandLineOpts.h
+++ b/bolt/include/bolt/Utils/CommandLineOpts.h
@@ -15,6 +15,12 @@
#include "llvm/Support/CommandLine.h"
+namespace llvm {
+namespace bolt {
+class BinaryFunction;
+}
+} // namespace llvm
+
namespace opts {
enum HeatmapModeKind {
@@ -100,6 +106,9 @@ extern llvm::cl::opt<unsigned> Verbosity;
/// Return true if we should process all functions in the binary.
bool processAllFunctions();
+/// Return true if we should dump dot graphs for the given function.
+bool shouldDumpDot(const llvm::bolt::BinaryFunction &Function);
+
enum GadgetScannerKind { GS_PACRET, GS_PAUTH, GS_ALL };
extern llvm::cl::bits<GadgetScannerKind> GadgetScannersToRun;
diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp
index 996d2e972599d..0ddb73f828878 100644
--- a/bolt/lib/Rewrite/BinaryPassManager.cpp
+++ b/bolt/lib/Rewrite/BinaryPassManager.cpp
@@ -52,6 +52,7 @@ namespace opts {
extern cl::opt<bool> PrintAll;
extern cl::opt<bool> PrintDynoStats;
extern cl::opt<bool> DumpDotAll;
+extern bool shouldDumpDot(const bolt::BinaryFunction &Function);
extern cl::opt<std::string> AsmDump;
extern cl::opt<bolt::PLTCall::OptType> PLT;
extern cl::opt<bolt::IdenticalCodeFolding::ICFLevel, false,
@@ -340,7 +341,7 @@ Error BinaryFunctionPassManager::runPasses() {
Function.print(BC.outs(), Message);
- if (opts::DumpDotAll)
+ if (opts::shouldDumpDot(Function))
Function.dumpGraphForPass(PassIdName);
}
}
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index fe4a23cc01382..69dcc8ce08a5b 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -114,6 +114,35 @@ cl::opt<bool> DumpDotAll(
"enable '-print-loops' for color-coded blocks"),
cl::Hidden, cl::cat(BoltCategory));
+cl::list<std::string> DumpDotFunc(
+ "dump-dot-func", cl::CommaSeparated,
+ cl::desc(
+ "dump function CFGs to graphviz format for specified functions only;"
+ "takes function name patterns (regex supported)"),
+ cl::value_desc("func1,func2,func3,..."), cl::Hidden, cl::cat(BoltCategory));
+
+bool shouldDumpDot(const bolt::BinaryFunction &Function) {
+ // If dump-dot-all is enabled, dump all functions
+ if (DumpDotAll)
+ return !Function.isIgnored();
+
+ // If no specific functions specified in dump-dot-func, don't dump any
+ if (DumpDotFunc.empty())
+ return false;
+
+ if (Function.isIgnored())
+ return false;
+
+ // Check if function matches any of the specified patterns
+ for (const std::string &Name : DumpDotFunc) {
+ if (Function.hasNameRegex(Name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static cl::list<std::string>
ForceFunctionNames("funcs",
cl::CommaSeparated,
@@ -3570,7 +3599,7 @@ void RewriteInstance::postProcessFunctions() {
if (opts::PrintAll || opts::PrintCFG)
Function.print(BC->outs(), "after building cfg");
- if (opts::DumpDotAll)
+ if (opts::shouldDumpDot(Function))
Function.dumpGraphForPass("00_build-cfg");
if (opts::PrintLoopInfo) {
>From fc1996ae472cf0b3cfb51c0805500f08c893946c Mon Sep 17 00:00:00 2001
From: Yafet Beyene <ybeyene at nvidia.com>
Date: Mon, 11 Aug 2025 06:56:45 -0700
Subject: [PATCH 2/2] [BOLT] Added dump-dot-func tests
---
bolt/docs/CommandLineArgumentReference.md | 5 +++
bolt/test/Inputs/multi-func.c | 24 +++++++++++++
bolt/test/dump-dot-func.test | 43 +++++++++++++++++++++++
3 files changed, 72 insertions(+)
create mode 100644 bolt/test/Inputs/multi-func.c
create mode 100644 bolt/test/dump-dot-func.test
diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md
index f3881c9a640a9..de54184ff8db1 100644
--- a/bolt/docs/CommandLineArgumentReference.md
+++ b/bolt/docs/CommandLineArgumentReference.md
@@ -138,6 +138,11 @@
Dump function CFGs to graphviz format after each stage;enable '-print-loops'
for color-coded blocks
+- `--dump-dot-func=<func1,func2,func3...>`
+
+ Dump function CFGs to graphviz format for specified functions only;
+ takes function name patterns (regex supported)
+
- `--dump-linux-exceptions`
Dump Linux kernel exception table
diff --git a/bolt/test/Inputs/multi-func.c b/bolt/test/Inputs/multi-func.c
new file mode 100644
index 0000000000000..622cc285570e0
--- /dev/null
+++ b/bolt/test/Inputs/multi-func.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+// Multiple functions to test selective dumping
+int add(int a, int b) { return a + b; }
+
+int multiply(int a, int b) { return a * b; }
+
+int main_helper() {
+ printf("Helper function\n");
+ return 42;
+}
+
+int main_secondary() { return add(5, 3); }
+
+void other_function() { printf("Other function\n"); }
+
+int main() {
+ int result = add(10, 20);
+ result = multiply(result, 2);
+ main_helper();
+ main_secondary();
+ other_function();
+ return result;
+}
\ No newline at end of file
diff --git a/bolt/test/dump-dot-func.test b/bolt/test/dump-dot-func.test
new file mode 100644
index 0000000000000..3b62130ef1f6d
--- /dev/null
+++ b/bolt/test/dump-dot-func.test
@@ -0,0 +1,43 @@
+# Test the --dump-dot-func option with multiple functions
+
+RUN: %clang %p/Inputs/multi-func.c -o %t.exe -Wl,-q
+
+# Test 1: --dump-dot-func with specific function name
+RUN: llvm-bolt %t.exe -o %t.bolt1 --dump-dot-func=add --print-only=add -v=1 2>&1 | FileCheck %s --check-prefix=ADD
+RUN: ls add-*.dot | wc -l | FileCheck %s --check-prefix=COUNT-ONE
+
+# Test 2: --dump-dot-func with regex pattern (main.*)
+RUN: llvm-bolt %t.exe -o %t.bolt2 --dump-dot-func="main.*" --print-only=main,main_helper,main_secondary -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-REGEX
+
+# Test 3: --dump-dot-func with multiple specific functions
+RUN: llvm-bolt %t.exe -o %t.bolt3 --dump-dot-func=add,multiply --print-only=add,multiply -v=1 2>&1 | FileCheck %s --check-prefix=MULTI
+
+# Test 4: No option specified should create no dot files
+RUN: llvm-bolt %t.exe -o %t.bolt4 --print-only=main 2>&1 | FileCheck %s --check-prefix=NONE
+
+# Test 5: --dump-dot-func with non-existent function
+RUN: llvm-bolt %t.exe -o %t.bolt5 --dump-dot-func=nonexistent --print-only=main -v=1 2>&1 | FileCheck %s --check-prefix=NONEXISTENT
+
+# Test 6: Backward compatibility - --dump-dot-all should still work
+RUN: llvm-bolt %t.exe -o %t.bolt6 --dump-dot-all --print-only=main -v=1 2>&1 | FileCheck %s --check-prefix=ALL
+
+# Check that specific functions are dumped
+ADD: BOLT-INFO: dumping CFG to add-00_build-cfg.dot
+
+MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
+MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main_helper-00_build-cfg.dot
+MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main_secondary-00_build-cfg.dot
+
+MULTI-DAG: BOLT-INFO: dumping CFG to add-00_build-cfg.dot
+MULTI-DAG: BOLT-INFO: dumping CFG to multiply-00_build-cfg.dot
+
+# Should be no dumping messages when no option is specified
+NONE-NOT: BOLT-INFO: dumping CFG
+
+# Should be no dumping messages for non-existent function
+NONEXISTENT-NOT: BOLT-INFO: dumping CFG
+
+ALL: BOLT-INFO: dumping CFG to main-00_build-cfg.dot
+
+# Count checks
+COUNT-ONE: 1
\ No newline at end of file
More information about the llvm-commits
mailing list