diff --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst index d80dd8d21eab..14131cba033c 100644 --- a/llvm/docs/Passes.rst +++ b/llvm/docs/Passes.rst @@ -127,6 +127,9 @@ postscript or some other suitable format. This pass, only available in ``opt``, prints the control flow graph into a ``.dot`` graph. This graph can then be processed with the :program:`dot` tool to convert it to postscript or some other suitable format. +Additionally the ``-cfg-func-name=`` option can be used to filter the +functions that are printed. All functions that contain the specified substring +will be printed. ``-dot-cfg-only``: Print CFG of function to "dot" file (with no function bodies) -------------------------------------------------------------------------------- @@ -135,6 +138,9 @@ This pass, only available in ``opt``, prints the control flow graph into a ``.dot`` graph, omitting the function bodies. This graph can then be processed with the :program:`dot` tool to convert it to postscript or some other suitable format. +Additionally the ``-cfg-func-name=`` option can be used to filter the +functions that are printed. All functions that contain the specified substring +will be printed. ``-dot-dom``: Print dominance tree of function to "dot" file ------------------------------------------------------------ @@ -1192,12 +1198,18 @@ instead just tries to ensure that code is well-formed. ----------------------------------- Displays the control flow graph using the GraphViz tool. +Additionally the ``-cfg-func-name=`` option can be used to filter the +functions that are displayed. All functions that contain the specified substring +will be displayed. ``-view-cfg-only``: View CFG of function (with no function bodies) ------------------------------------------------------------------ Displays the control flow graph using the GraphViz tool, but omitting function bodies. +Additionally the ``-cfg-func-name=`` option can be used to filter the +functions that are displayed. All functions that contain the specified substring +will be displayed. ``-view-dom``: View dominance tree of function ---------------------------------------------- diff --git a/llvm/lib/Analysis/CFGPrinter.cpp b/llvm/lib/Analysis/CFGPrinter.cpp index 76f9f7783863..04ccdc590845 100644 --- a/llvm/lib/Analysis/CFGPrinter.cpp +++ b/llvm/lib/Analysis/CFGPrinter.cpp @@ -100,6 +100,8 @@ struct CFGViewerLegacyPass : public FunctionPass { } bool runOnFunction(Function &F) override { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return false; auto *BPI = &getAnalysis().getBPI(); auto *BFI = &getAnalysis().getBFI(); viewCFG(F, BFI, BPI, getMaxFreq(F, BFI)); @@ -115,13 +117,15 @@ struct CFGViewerLegacyPass : public FunctionPass { AU.setPreservesAll(); } }; -} +} // namespace char CFGViewerLegacyPass::ID = 0; INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true) PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return PreservedAnalyses::all(); auto *BFI = &AM.getResult(F); auto *BPI = &AM.getResult(F); viewCFG(F, BFI, BPI, getMaxFreq(F, BFI)); @@ -136,6 +140,8 @@ struct CFGOnlyViewerLegacyPass : public FunctionPass { } bool runOnFunction(Function &F) override { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return false; auto *BPI = &getAnalysis().getBPI(); auto *BFI = &getAnalysis().getBFI(); viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true); @@ -151,7 +157,7 @@ struct CFGOnlyViewerLegacyPass : public FunctionPass { AU.setPreservesAll(); } }; -} +} // namespace char CFGOnlyViewerLegacyPass::ID = 0; INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", @@ -159,6 +165,8 @@ INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", PreservedAnalyses CFGOnlyViewerPass::run(Function &F, FunctionAnalysisManager &AM) { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return PreservedAnalyses::all(); auto *BFI = &AM.getResult(F); auto *BPI = &AM.getResult(F); viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true); @@ -173,6 +181,8 @@ struct CFGPrinterLegacyPass : public FunctionPass { } bool runOnFunction(Function &F) override { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return false; auto *BPI = &getAnalysis().getBPI(); auto *BFI = &getAnalysis().getBFI(); writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI)); @@ -188,7 +198,7 @@ struct CFGPrinterLegacyPass : public FunctionPass { AU.setPreservesAll(); } }; -} +} // namespace char CFGPrinterLegacyPass::ID = 0; INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", @@ -196,6 +206,8 @@ INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", PreservedAnalyses CFGPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return PreservedAnalyses::all(); auto *BFI = &AM.getResult(F); auto *BPI = &AM.getResult(F); writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI)); @@ -210,6 +222,8 @@ struct CFGOnlyPrinterLegacyPass : public FunctionPass { } bool runOnFunction(Function &F) override { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return false; auto *BPI = &getAnalysis().getBPI(); auto *BFI = &getAnalysis().getBFI(); writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true); @@ -224,7 +238,7 @@ struct CFGOnlyPrinterLegacyPass : public FunctionPass { AU.setPreservesAll(); } }; -} +} // namespace char CFGOnlyPrinterLegacyPass::ID = 0; INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", @@ -233,6 +247,8 @@ INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", PreservedAnalyses CFGOnlyPrinterPass::run(Function &F, FunctionAnalysisManager &AM) { + if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) + return PreservedAnalyses::all(); auto *BFI = &AM.getResult(F); auto *BPI = &AM.getResult(F); writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true); diff --git a/llvm/test/Other/cfg-printer-filter.ll b/llvm/test/Other/cfg-printer-filter.ll new file mode 100644 index 000000000000..0d3bf3df5f53 --- /dev/null +++ b/llvm/test/Other/cfg-printer-filter.ll @@ -0,0 +1,40 @@ +; RUN: rm -f %t.other.dot %t-only.other.dot + +;; Both f and func are dumped because their names contain the pattern 'f' as a substring. +; RUN: opt < %s -dot-cfg -cfg-dot-filename-prefix=%t -cfg-func-name=f 2>/dev/null +; RUN: FileCheck %s -input-file=%t.f.dot -check-prefix=F +; RUN: FileCheck %s -input-file=%t.func.dot -check-prefix=Func +; RUN: not test -f %t.other.dot + +; RUN: opt < %s -dot-cfg-only -cfg-dot-filename-prefix=%t-only -cfg-func-name=f 2>/dev/null +; RUN: FileCheck %s -input-file=%t-only.f.dot -check-prefix=F +; RUN: FileCheck %s -input-file=%t-only.func.dot -check-prefix=Func +; RUN: not test -f %t-only.other.dot + +; F: digraph "CFG for 'f' function" +define void @f(i32) { +entry: + %check = icmp sgt i32 %0, 0 + br i1 %check, label %if, label %exit +if: ; preds = %entry + br label %exit +exit: ; preds = %entry, %if + ret void +} + +; Func: digraph "CFG for 'func' function" +define void @func(i32) { +entry: + %check = icmp sgt i32 %0, 0 + br label %exit +exit: ; preds = %entry + ret void +} + +define void @other(i32) { +entry: + %check = icmp sgt i32 %0, 0 + br label %exit +exit: ; preds = %entry + ret void +}