diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md index f3881c9a640a9..d65cf39e16b29 100644 --- a/bolt/docs/CommandLineArgumentReference.md +++ b/bolt/docs/CommandLineArgumentReference.md @@ -138,6 +138,12 @@ Dump function CFGs to graphviz format after each stage;enable '-print-loops' for color-coded blocks +- `--dump-dot-func=` + + Dump function CFGs to graphviz format for specified functions only; + takes function name patterns (regex supported). Note: C++ function names + must be passed using their mangled names + - `--dump-linux-exceptions` Dump Linux kernel exception table 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 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 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 PrintAll; extern cl::opt PrintDynoStats; extern cl::opt DumpDotAll; +extern bool shouldDumpDot(const bolt::BinaryFunction &Function); extern cl::opt AsmDump; extern cl::opt PLT; extern cl::opt DumpDotAll( "enable '-print-loops' for color-coded blocks"), cl::Hidden, cl::cat(BoltCategory)); +cl::list 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 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) { diff --git a/bolt/test/Inputs/multi-func.cpp b/bolt/test/Inputs/multi-func.cpp new file mode 100644 index 0000000000000..61c968fc27f98 --- /dev/null +++ b/bolt/test/Inputs/multi-func.cpp @@ -0,0 +1,24 @@ +#include + +// 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() { + std::cout << "Helper function" << std::endl; + return 42; +} + +int main_secondary() { return add(5, 3); } + +void other_function() { std::cout << "Other function" << std::endl; } + +int main() { + int result = add(10, 20); + result = multiply(result, 2); + main_helper(); + main_secondary(); + other_function(); + return result; +} diff --git a/bolt/test/dump-dot-func.test b/bolt/test/dump-dot-func.test new file mode 100644 index 0000000000000..510713dde6167 --- /dev/null +++ b/bolt/test/dump-dot-func.test @@ -0,0 +1,52 @@ +# Test the --dump-dot-func option with multiple functions +# (includes tests for both mangled/unmangled names) + +RUN: %clang++ %p/Inputs/multi-func.cpp -o %t.exe -Wl,-q + +# Test 1: --dump-dot-func with specific function name (mangled) +RUN: llvm-bolt %t.exe -o %t.bolt1 --dump-dot-func=_Z3addii -v=1 2>&1 | FileCheck %s --check-prefix=ADD + +# Test 2: --dump-dot-func with regex pattern (main.*) +RUN: llvm-bolt %t.exe -o %t.bolt2 --dump-dot-func="main.*" -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-REGEX + +# Test 3: --dump-dot-func with multiple specific functions (mangled names) +RUN: llvm-bolt %t.exe -o %t.bolt3 --dump-dot-func=_Z3addii,_Z8multiplyii -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 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 -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 -v=1 2>&1 | FileCheck %s --check-prefix=ALL + +# Test 7: Test with unmangled function name (main function) +RUN: llvm-bolt %t.exe -o %t.bolt7 --dump-dot-func=main -v=1 2>&1 | FileCheck %s --check-prefix=MAIN-UNMANGLED + +# Check that specific functions are dumped +ADD: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot +ADD-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot +ADD-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot +ADD-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-00_build-cfg.dot + +MAIN-REGEX-DAG: BOLT-INFO: dumping CFG to main-00_build-cfg.dot +MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot +MAIN-REGEX-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot + +MULTI-DAG: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot +MULTI-DAG: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot +MULTI-NOT: BOLT-INFO: dumping CFG to main-00_build-cfg.dot +MULTI-NOT: BOLT-INFO: dumping CFG to _Z11main_helperv-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 + +MAIN-UNMANGLED: BOLT-INFO: dumping CFG to main-00_build-cfg.dot +MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z3addii-00_build-cfg.dot +MAIN-UNMANGLED-NOT: BOLT-INFO: dumping CFG to _Z8multiplyii-00_build-cfg.dot \ No newline at end of file