1 | //===- PassManagerOptions.cpp - PassManager Command Line Options ----------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "mlir/Pass/Pass.h" |
10 | #include "mlir/Pass/PassManager.h" |
11 | #include "mlir/Pass/PassRegistry.h" |
12 | #include "mlir/Support/Timing.h" |
13 | #include "llvm/Support/CommandLine.h" |
14 | #include "llvm/Support/ManagedStatic.h" |
15 | |
16 | using namespace mlir; |
17 | |
18 | namespace { |
19 | struct PassManagerOptions { |
20 | //===--------------------------------------------------------------------===// |
21 | // Crash Reproducer Generator |
22 | //===--------------------------------------------------------------------===// |
23 | llvm::cl::opt<std::string> reproducerFile{ |
24 | "mlir-pass-pipeline-crash-reproducer" , |
25 | llvm::cl::desc("Generate a .mlir reproducer file at the given output path" |
26 | " if the pass manager crashes or fails" )}; |
27 | llvm::cl::opt<bool> localReproducer{ |
28 | "mlir-pass-pipeline-local-reproducer" , |
29 | llvm::cl::desc("When generating a crash reproducer, attempt to generated " |
30 | "a reproducer with the smallest pipeline." ), |
31 | llvm::cl::init(Val: false)}; |
32 | |
33 | //===--------------------------------------------------------------------===// |
34 | // IR Printing |
35 | //===--------------------------------------------------------------------===// |
36 | PassNameCLParser printBefore{"mlir-print-ir-before" , |
37 | "Print IR before specified passes" }; |
38 | PassNameCLParser printAfter{"mlir-print-ir-after" , |
39 | "Print IR after specified passes" }; |
40 | llvm::cl::opt<bool> printBeforeAll{ |
41 | "mlir-print-ir-before-all" , llvm::cl::desc("Print IR before each pass" ), |
42 | llvm::cl::init(Val: false)}; |
43 | llvm::cl::opt<bool> printAfterAll{"mlir-print-ir-after-all" , |
44 | llvm::cl::desc("Print IR after each pass" ), |
45 | llvm::cl::init(Val: false)}; |
46 | llvm::cl::opt<bool> printAfterChange{ |
47 | "mlir-print-ir-after-change" , |
48 | llvm::cl::desc( |
49 | "When printing the IR after a pass, only print if the IR changed" ), |
50 | llvm::cl::init(Val: false)}; |
51 | llvm::cl::opt<bool> printAfterFailure{ |
52 | "mlir-print-ir-after-failure" , |
53 | llvm::cl::desc( |
54 | "When printing the IR after a pass, only print if the pass failed" ), |
55 | llvm::cl::init(Val: false)}; |
56 | llvm::cl::opt<bool> printModuleScope{ |
57 | "mlir-print-ir-module-scope" , |
58 | llvm::cl::desc("When printing IR for print-ir-[before|after]{-all} " |
59 | "always print the top-level operation" ), |
60 | llvm::cl::init(Val: false)}; |
61 | |
62 | /// Add an IR printing instrumentation if enabled by any 'print-ir' flags. |
63 | void addPrinterInstrumentation(PassManager &pm); |
64 | |
65 | //===--------------------------------------------------------------------===// |
66 | // Pass Statistics |
67 | //===--------------------------------------------------------------------===// |
68 | llvm::cl::opt<bool> passStatistics{ |
69 | "mlir-pass-statistics" , |
70 | llvm::cl::desc("Display the statistics of each pass" )}; |
71 | llvm::cl::opt<PassDisplayMode> passStatisticsDisplayMode{ |
72 | "mlir-pass-statistics-display" , |
73 | llvm::cl::desc("Display method for pass statistics" ), |
74 | llvm::cl::init(Val: PassDisplayMode::Pipeline), |
75 | llvm::cl::values( |
76 | clEnumValN( |
77 | PassDisplayMode::List, "list" , |
78 | "display the results in a merged list sorted by pass name" ), |
79 | clEnumValN(PassDisplayMode::Pipeline, "pipeline" , |
80 | "display the results with a nested pipeline view" ))}; |
81 | }; |
82 | } // namespace |
83 | |
84 | static llvm::ManagedStatic<PassManagerOptions> options; |
85 | |
86 | /// Add an IR printing instrumentation if enabled by any 'print-ir' flags. |
87 | void PassManagerOptions::addPrinterInstrumentation(PassManager &pm) { |
88 | std::function<bool(Pass *, Operation *)> shouldPrintBeforePass; |
89 | std::function<bool(Pass *, Operation *)> shouldPrintAfterPass; |
90 | |
91 | // Handle print-before. |
92 | if (printBeforeAll) { |
93 | // If we are printing before all, then just return true for the filter. |
94 | shouldPrintBeforePass = [](Pass *, Operation *) { return true; }; |
95 | } else if (printBefore.hasAnyOccurrences()) { |
96 | // Otherwise if there are specific passes to print before, then check to see |
97 | // if the pass info for the current pass is included in the list. |
98 | shouldPrintBeforePass = [&](Pass *pass, Operation *) { |
99 | auto *passInfo = pass->lookupPassInfo(); |
100 | return passInfo && printBefore.contains(entry: passInfo); |
101 | }; |
102 | } |
103 | |
104 | // Handle print-after. |
105 | if (printAfterAll || printAfterFailure) { |
106 | // If we are printing after all or failure, then just return true for the |
107 | // filter. |
108 | shouldPrintAfterPass = [](Pass *, Operation *) { return true; }; |
109 | } else if (printAfter.hasAnyOccurrences()) { |
110 | // Otherwise if there are specific passes to print after, then check to see |
111 | // if the pass info for the current pass is included in the list. |
112 | shouldPrintAfterPass = [&](Pass *pass, Operation *) { |
113 | auto *passInfo = pass->lookupPassInfo(); |
114 | return passInfo && printAfter.contains(entry: passInfo); |
115 | }; |
116 | } |
117 | |
118 | // If there are no valid printing filters, then just return. |
119 | if (!shouldPrintBeforePass && !shouldPrintAfterPass) |
120 | return; |
121 | |
122 | // Otherwise, add the IR printing instrumentation. |
123 | pm.enableIRPrinting(shouldPrintBeforePass, shouldPrintAfterPass, |
124 | printModuleScope, printAfterOnlyOnChange: printAfterChange, printAfterOnlyOnFailure: printAfterFailure, |
125 | out&: llvm::errs()); |
126 | } |
127 | |
128 | void mlir::registerPassManagerCLOptions() { |
129 | // Make sure that the options struct has been constructed. |
130 | *options; |
131 | } |
132 | |
133 | LogicalResult mlir::applyPassManagerCLOptions(PassManager &pm) { |
134 | if (!options.isConstructed()) |
135 | return failure(); |
136 | |
137 | // Generate a reproducer on crash/failure. |
138 | if (options->reproducerFile.getNumOccurrences()) |
139 | pm.enableCrashReproducerGeneration(outputFile: options->reproducerFile, |
140 | genLocalReproducer: options->localReproducer); |
141 | |
142 | // Enable statistics dumping. |
143 | if (options->passStatistics) |
144 | pm.enableStatistics(displayMode: options->passStatisticsDisplayMode); |
145 | |
146 | if (options->printModuleScope && pm.getContext()->isMultithreadingEnabled()) { |
147 | emitError(UnknownLoc::get(pm.getContext())) |
148 | << "IR print for module scope can't be setup on a pass-manager " |
149 | "without disabling multi-threading first.\n" ; |
150 | return failure(); |
151 | } |
152 | |
153 | // Add the IR printing instrumentation. |
154 | options->addPrinterInstrumentation(pm); |
155 | return success(); |
156 | } |
157 | |
158 | void mlir::applyDefaultTimingPassManagerCLOptions(PassManager &pm) { |
159 | // Create a temporary timing manager for the PM to own, apply its CL options, |
160 | // and pass it to the PM. |
161 | auto tm = std::make_unique<DefaultTimingManager>(); |
162 | applyDefaultTimingManagerCLOptions(tm&: *tm); |
163 | pm.enableTiming(tm: std::move(tm)); |
164 | } |
165 | |