[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