1 //===- PassManagerOptions.cpp - PassManager Command Line Options ----------===//
2 //
3 // Copyright 2019 The MLIR Authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // =============================================================================
17 
18 #include "mlir/Pass/Pass.h"
19 #include "mlir/Pass/PassManager.h"
20 #include "mlir/Pass/PassRegistry.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "llvm/Support/ManagedStatic.h"
23 
24 using namespace mlir;
25 
26 namespace {
27 struct PassManagerOptions {
28   //===--------------------------------------------------------------------===//
29   // Crash Reproducer Generator
30   //===--------------------------------------------------------------------===//
31   llvm::cl::opt<std::string> reproducerFile{
32       "pass-pipeline-crash-reproducer",
33       llvm::cl::desc("Generate a .mlir reproducer file at the given output path"
34                      " if the pass manager crashes or fails")};
35 
36   //===--------------------------------------------------------------------===//
37   // Multi-threading
38   //===--------------------------------------------------------------------===//
39   llvm::cl::opt<bool> disableThreads{
40       "disable-pass-threading",
41       llvm::cl::desc("Disable multithreading in the pass manager"),
42       llvm::cl::init(false)};
43 
44   //===--------------------------------------------------------------------===//
45   // IR Printing
46   //===--------------------------------------------------------------------===//
47   PassPipelineCLParser printBefore{"print-ir-before",
48                                    "Print IR before specified passes"};
49   PassPipelineCLParser printAfter{"print-ir-after",
50                                   "Print IR after specified passes"};
51   llvm::cl::opt<bool> printBeforeAll{
52       "print-ir-before-all", llvm::cl::desc("Print IR before each pass"),
53       llvm::cl::init(false)};
54   llvm::cl::opt<bool> printAfterAll{"print-ir-after-all",
55                                     llvm::cl::desc("Print IR after each pass"),
56                                     llvm::cl::init(false)};
57   llvm::cl::opt<bool> printModuleScope{
58       "print-ir-module-scope",
59       llvm::cl::desc("When printing IR for print-ir-[before|after]{-all} "
60                      "always print the top-level module operation"),
61       llvm::cl::init(false)};
62 
63   /// Add an IR printing instrumentation if enabled by any 'print-ir' flags.
64   void addPrinterInstrumentation(PassManager &pm);
65 
66   //===--------------------------------------------------------------------===//
67   // Pass Timing
68   //===--------------------------------------------------------------------===//
69   llvm::cl::opt<bool> passTiming{
70       "pass-timing",
71       llvm::cl::desc("Display the execution times of each pass")};
72   llvm::cl::opt<PassDisplayMode> passTimingDisplayMode{
73       "pass-timing-display",
74       llvm::cl::desc("Display method for pass timing data"),
75       llvm::cl::init(PassDisplayMode::Pipeline),
76       llvm::cl::values(
77           clEnumValN(PassDisplayMode::List, "list",
78                      "display the results in a list sorted by total time"),
79           clEnumValN(PassDisplayMode::Pipeline, "pipeline",
80                      "display the results with a nested pipeline view"))};
81 
82   //===--------------------------------------------------------------------===//
83   // Pass Statistics
84   //===--------------------------------------------------------------------===//
85   llvm::cl::opt<bool> passStatistics{
86       "pass-statistics", llvm::cl::desc("Display the statistics of each pass")};
87   llvm::cl::opt<PassDisplayMode> passStatisticsDisplayMode{
88       "pass-statistics-display",
89       llvm::cl::desc("Display method for pass statistics"),
90       llvm::cl::init(PassDisplayMode::Pipeline),
91       llvm::cl::values(
92           clEnumValN(
93               PassDisplayMode::List, "list",
94               "display the results in a merged list sorted by pass name"),
95           clEnumValN(PassDisplayMode::Pipeline, "pipeline",
96                      "display the results with a nested pipeline view"))};
97 
98   /// Add a pass timing instrumentation if enabled by 'pass-timing' flags.
99   void addTimingInstrumentation(PassManager &pm);
100 };
101 } // end anonymous namespace
102 
103 static llvm::ManagedStatic<llvm::Optional<PassManagerOptions>> options;
104 
105 /// Add an IR printing instrumentation if enabled by any 'print-ir' flags.
106 void PassManagerOptions::addPrinterInstrumentation(PassManager &pm) {
107   std::function<bool(Pass *, Operation *)> shouldPrintBeforePass;
108   std::function<bool(Pass *, Operation *)> shouldPrintAfterPass;
109 
110   // Handle print-before.
111   if (printBeforeAll) {
112     // If we are printing before all, then just return true for the filter.
113     shouldPrintBeforePass = [](Pass *, Operation *) { return true; };
114   } else if (printBefore.hasAnyOccurrences()) {
115     // Otherwise if there are specific passes to print before, then check to see
116     // if the pass info for the current pass is included in the list.
117     shouldPrintBeforePass = [&](Pass *pass, Operation *) {
118       auto *passInfo = pass->lookupPassInfo();
119       return passInfo && printBefore.contains(passInfo);
120     };
121   }
122 
123   // Handle print-after.
124   if (printAfterAll) {
125     // If we are printing after all, then just return true for the filter.
126     shouldPrintAfterPass = [](Pass *, Operation *) { return true; };
127   } else if (printAfter.hasAnyOccurrences()) {
128     // Otherwise if there are specific passes to print after, then check to see
129     // if the pass info for the current pass is included in the list.
130     shouldPrintAfterPass = [&](Pass *pass, Operation *) {
131       auto *passInfo = pass->lookupPassInfo();
132       return passInfo && printAfter.contains(passInfo);
133     };
134   }
135 
136   // If there are no valid printing filters, then just return.
137   if (!shouldPrintBeforePass && !shouldPrintAfterPass)
138     return;
139 
140   // Otherwise, add the IR printing instrumentation.
141   pm.enableIRPrinting(shouldPrintBeforePass, shouldPrintAfterPass,
142                       printModuleScope, llvm::errs());
143 }
144 
145 /// Add a pass timing instrumentation if enabled by 'pass-timing' flags.
146 void PassManagerOptions::addTimingInstrumentation(PassManager &pm) {
147   if (passTiming)
148     pm.enableTiming(passTimingDisplayMode);
149 }
150 
151 void mlir::registerPassManagerCLOptions() {
152   // Reset the options instance if it hasn't been enabled yet.
153   if (!options->hasValue())
154     options->emplace();
155 }
156 
157 void mlir::applyPassManagerCLOptions(PassManager &pm) {
158   // Generate a reproducer on crash/failure.
159   if ((*options)->reproducerFile.getNumOccurrences())
160     pm.enableCrashReproducerGeneration((*options)->reproducerFile);
161 
162   // Disable multi-threading.
163   if ((*options)->disableThreads)
164     pm.disableMultithreading();
165 
166   // Enable statistics dumping.
167   if ((*options)->passStatistics)
168     pm.enableStatistics((*options)->passStatisticsDisplayMode);
169 
170   // Add the IR printing instrumentation.
171   (*options)->addPrinterInstrumentation(pm);
172 
173   // Note: The pass timing instrumentation should be added last to avoid any
174   // potential "ghost" timing from other instrumentations being unintentionally
175   // included in the timing results.
176   (*options)->addTimingInstrumentation(pm);
177 }
178