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