github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/Pass/Pass.cpp (about) 1 //===- Pass.cpp - Pass infrastructure implementation ----------------------===// 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 // This file implements common pass infrastructure. 19 // 20 //===----------------------------------------------------------------------===// 21 22 #include "mlir/Pass/Pass.h" 23 #include "PassDetail.h" 24 #include "mlir/Analysis/Verifier.h" 25 #include "mlir/IR/Diagnostics.h" 26 #include "mlir/IR/Module.h" 27 #include "mlir/Pass/PassManager.h" 28 #include "llvm/Support/CommandLine.h" 29 #include "llvm/Support/Mutex.h" 30 #include "llvm/Support/Parallel.h" 31 #include "llvm/Support/Threading.h" 32 33 using namespace mlir; 34 using namespace mlir::detail; 35 36 //===----------------------------------------------------------------------===// 37 // Pass 38 //===----------------------------------------------------------------------===// 39 40 /// Out of line virtual method to ensure vtables and metadata are emitted to a 41 /// single .o file. 42 void Pass::anchor() {} 43 44 /// Forwarding function to execute this pass. 45 LogicalResult Pass::run(Operation *op, AnalysisManager am) { 46 passState.emplace(op, am); 47 48 // Instrument before the pass has run. 49 auto pi = am.getPassInstrumentor(); 50 if (pi) 51 pi->runBeforePass(this, op); 52 53 // Invoke the virtual runOnOperation method. 54 runOnOperation(); 55 56 // Invalidate any non preserved analyses. 57 am.invalidate(passState->preservedAnalyses); 58 59 // Instrument after the pass has run. 60 bool passFailed = passState->irAndPassFailed.getInt(); 61 if (pi) { 62 if (passFailed) 63 pi->runAfterPassFailed(this, op); 64 else 65 pi->runAfterPass(this, op); 66 } 67 68 // Return if the pass signaled a failure. 69 return failure(passFailed); 70 } 71 72 //===----------------------------------------------------------------------===// 73 // PassExecutor 74 //===----------------------------------------------------------------------===// 75 76 FunctionPassExecutor::FunctionPassExecutor(const FunctionPassExecutor &rhs) 77 : PassExecutor(Kind::FunctionExecutor) { 78 for (auto &pass : rhs.passes) 79 addPass(cast<FunctionPassBase>(pass->clone())); 80 } 81 82 /// Run all of the passes in this manager over the current function. 83 LogicalResult detail::FunctionPassExecutor::run(FuncOp function, 84 AnalysisManager am) { 85 // Run each of the held passes. 86 for (auto &pass : passes) 87 if (failed(pass->run(function, am))) 88 return failure(); 89 return success(); 90 } 91 92 /// Run all of the passes in this manager over the current module. 93 LogicalResult detail::ModulePassExecutor::run(ModuleOp module, 94 AnalysisManager am) { 95 // Run each of the held passes. 96 for (auto &pass : passes) 97 if (failed(pass->run(module, am))) 98 return failure(); 99 return success(); 100 } 101 102 //===----------------------------------------------------------------------===// 103 // ModuleToFunctionPassAdaptor 104 //===----------------------------------------------------------------------===// 105 106 /// Utility to run the given function and analysis manager on a provided 107 /// function pass executor. 108 static LogicalResult runFunctionPipeline(FunctionPassExecutor &fpe, FuncOp func, 109 AnalysisManager am) { 110 // Run the function pipeline over the provided function. 111 auto result = fpe.run(func, am); 112 113 // Clear out any computed function analyses. These analyses won't be used 114 // any more in this pipeline, and this helps reduce the current working set 115 // of memory. If preserving these analyses becomes important in the future 116 // we can re-evalutate this. 117 am.clear(); 118 return result; 119 } 120 121 /// Run the held function pipeline over all non-external functions within the 122 /// module. 123 void ModuleToFunctionPassAdaptor::runOnModule() { 124 AnalysisManager am = getAnalysisManager(); 125 for (auto func : getModule().getOps<FuncOp>()) { 126 // Skip external functions. 127 if (func.isExternal()) 128 continue; 129 130 // Run the held function pipeline over the current function. 131 auto childAM = am.slice(func); 132 if (failed(runFunctionPipeline(fpe, func, childAM))) 133 return signalPassFailure(); 134 135 // Clear out any computed child analyses. These analyses won't be used 136 // any more in this pipeline, and this helps reduce the current working set 137 // of memory. If preserving these analyses becomes important in the future 138 // we can re-evalutate this. 139 am.clear(); 140 } 141 } 142 143 // Run the held function pipeline synchronously across the functions within 144 // the module. 145 void ModuleToFunctionPassAdaptorParallel::runOnModule() { 146 AnalysisManager am = getAnalysisManager(); 147 148 // Create the async executors if they haven't been created, or if the main 149 // function pipeline has changed. 150 if (asyncExecutors.empty() || asyncExecutors.front().size() != fpe.size()) 151 asyncExecutors = {llvm::hardware_concurrency(), fpe}; 152 153 // Run a prepass over the module to collect the functions to execute a over. 154 // This ensures that an analysis manager exists for each function, as well as 155 // providing a queue of functions to execute over. 156 std::vector<std::pair<FuncOp, AnalysisManager>> funcAMPairs; 157 for (auto func : getModule().getOps<FuncOp>()) 158 if (!func.isExternal()) 159 funcAMPairs.emplace_back(func, am.slice(func)); 160 161 // A parallel diagnostic handler that provides deterministic diagnostic 162 // ordering. 163 ParallelDiagnosticHandler diagHandler(&getContext()); 164 165 // An index for the current function/analysis manager pair. 166 std::atomic<unsigned> funcIt(0); 167 168 // An atomic failure variable for the async executors. 169 std::atomic<bool> passFailed(false); 170 llvm::parallel::for_each( 171 llvm::parallel::par, asyncExecutors.begin(), 172 std::next(asyncExecutors.begin(), 173 std::min(asyncExecutors.size(), funcAMPairs.size())), 174 [&](FunctionPassExecutor &executor) { 175 for (auto e = funcAMPairs.size(); !passFailed && funcIt < e;) { 176 // Get the next available function index. 177 unsigned nextID = funcIt++; 178 if (nextID >= e) 179 break; 180 181 // Set the function id for this thread in the diagnostic handler. 182 diagHandler.setOrderIDForThread(nextID); 183 184 // Run the executor over the current function. 185 auto &it = funcAMPairs[nextID]; 186 if (failed(runFunctionPipeline(executor, it.first, it.second))) { 187 passFailed = true; 188 break; 189 } 190 } 191 }); 192 193 // Signal a failure if any of the executors failed. 194 if (passFailed) 195 signalPassFailure(); 196 } 197 198 //===----------------------------------------------------------------------===// 199 // Verifier Passes 200 //===----------------------------------------------------------------------===// 201 202 void FunctionVerifierPass::runOnFunction() { 203 if (failed(verify(getFunction()))) 204 signalPassFailure(); 205 markAllAnalysesPreserved(); 206 } 207 208 void ModuleVerifierPass::runOnModule() { 209 if (failed(verify(getModule()))) 210 signalPassFailure(); 211 markAllAnalysesPreserved(); 212 } 213 214 //===----------------------------------------------------------------------===// 215 // PassManager 216 //===----------------------------------------------------------------------===// 217 218 PassManager::PassManager(bool verifyPasses) 219 : mpe(new ModulePassExecutor()), verifyPasses(verifyPasses), 220 passTiming(false), disableThreads(false) {} 221 222 PassManager::~PassManager() {} 223 224 /// Run the passes within this manager on the provided module. 225 LogicalResult PassManager::run(ModuleOp module) { 226 ModuleAnalysisManager am(module, instrumentor.get()); 227 return mpe->run(module, am); 228 } 229 230 /// Disable support for multi-threading within the pass manager. 231 void PassManager::disableMultithreading(bool disable) { 232 disableThreads = disable; 233 } 234 235 /// Add an opaque pass pointer to the current manager. This takes ownership 236 /// over the provided pass pointer. 237 void PassManager::addPass(std::unique_ptr<Pass> pass) { 238 if (isa<FunctionPassBase>(pass.get())) 239 return addPass(cast<FunctionPassBase>(std::move(pass))); 240 addPass(cast<ModulePassBase>(std::move(pass))); 241 } 242 243 /// Add a module pass to the current manager. This takes ownership over the 244 /// provided pass pointer. 245 void PassManager::addPass(std::unique_ptr<ModulePassBase> pass) { 246 nestedExecutorStack.clear(); 247 mpe->addPass(std::move(pass)); 248 249 // Add a verifier run if requested. 250 if (verifyPasses) 251 mpe->addPass(std::make_unique<ModuleVerifierPass>()); 252 } 253 254 /// Add a function pass to the current manager. This takes ownership over the 255 /// provided pass pointer. This will automatically create a function pass 256 /// executor if necessary. 257 void PassManager::addPass(std::unique_ptr<FunctionPassBase> pass) { 258 detail::FunctionPassExecutor *fpe; 259 if (nestedExecutorStack.empty()) { 260 /// Create an executor adaptor for this pass. 261 if (disableThreads || !llvm::llvm_is_multithreaded()) { 262 // If multi-threading is disabled, then create a synchronous adaptor. 263 auto adaptor = std::make_unique<ModuleToFunctionPassAdaptor>(); 264 fpe = &adaptor->getFunctionExecutor(); 265 addPass(std::unique_ptr<ModulePassBase>{adaptor.release()}); 266 } else { 267 auto adaptor = std::make_unique<ModuleToFunctionPassAdaptorParallel>(); 268 fpe = &adaptor->getFunctionExecutor(); 269 addPass(std::unique_ptr<ModulePassBase>{adaptor.release()}); 270 } 271 272 /// Add the executor to the stack. 273 nestedExecutorStack.push_back(fpe); 274 } else { 275 fpe = cast<detail::FunctionPassExecutor>(nestedExecutorStack.back()); 276 } 277 fpe->addPass(std::move(pass)); 278 279 // Add a verifier run if requested. 280 if (verifyPasses) 281 fpe->addPass(std::make_unique<FunctionVerifierPass>()); 282 } 283 284 /// Add the provided instrumentation to the pass manager. This takes ownership 285 /// over the given pointer. 286 void PassManager::addInstrumentation(PassInstrumentation *pi) { 287 if (!instrumentor) 288 instrumentor.reset(new PassInstrumentor()); 289 290 instrumentor->addInstrumentation(pi); 291 } 292 293 //===----------------------------------------------------------------------===// 294 // AnalysisManager 295 //===----------------------------------------------------------------------===// 296 297 /// Returns a pass instrumentation object for the current operation. 298 PassInstrumentor *AnalysisManager::getPassInstrumentor() const { 299 ParentPointerT curParent = parent; 300 while (auto *parentAM = curParent.dyn_cast<const AnalysisManager *>()) 301 curParent = parentAM->parent; 302 return curParent.get<const ModuleAnalysisManager *>()->getPassInstrumentor(); 303 } 304 305 /// Get an analysis manager for the given child operation. 306 AnalysisManager AnalysisManager::slice(Operation *op) { 307 assert(op->getParentOp() == impl->getOperation() && 308 "'op' has a different parent operation"); 309 auto it = impl->childAnalyses.find(op); 310 if (it == impl->childAnalyses.end()) 311 it = impl->childAnalyses 312 .try_emplace(op, std::make_unique<NestedAnalysisMap>(op)) 313 .first; 314 return {this, it->second.get()}; 315 } 316 317 /// Invalidate any non preserved analyses. 318 void detail::NestedAnalysisMap::invalidate( 319 const detail::PreservedAnalyses &pa) { 320 // If all analyses were preserved, then there is nothing to do here. 321 if (pa.isAll()) 322 return; 323 324 // Invalidate the analyses for the current operation directly. 325 analyses.invalidate(pa); 326 327 // If no analyses were preserved, then just simply clear out the child 328 // analysis results. 329 if (pa.isNone()) { 330 childAnalyses.clear(); 331 return; 332 } 333 334 // Otherwise, invalidate each child analysis map. 335 SmallVector<NestedAnalysisMap *, 8> mapsToInvalidate(1, this); 336 while (!mapsToInvalidate.empty()) { 337 auto *map = mapsToInvalidate.pop_back_val(); 338 for (auto &analysisPair : map->childAnalyses) { 339 analysisPair.second->invalidate(pa); 340 if (!analysisPair.second->childAnalyses.empty()) 341 mapsToInvalidate.push_back(analysisPair.second.get()); 342 } 343 } 344 } 345 346 //===----------------------------------------------------------------------===// 347 // PassInstrumentation 348 //===----------------------------------------------------------------------===// 349 350 PassInstrumentation::~PassInstrumentation() {} 351 352 //===----------------------------------------------------------------------===// 353 // PassInstrumentor 354 //===----------------------------------------------------------------------===// 355 356 namespace mlir { 357 namespace detail { 358 struct PassInstrumentorImpl { 359 /// Mutex to keep instrumentation access thread-safe. 360 llvm::sys::SmartMutex<true> mutex; 361 362 /// Set of registered instrumentations. 363 std::vector<std::unique_ptr<PassInstrumentation>> instrumentations; 364 }; 365 } // end namespace detail 366 } // end namespace mlir 367 368 PassInstrumentor::PassInstrumentor() : impl(new PassInstrumentorImpl()) {} 369 PassInstrumentor::~PassInstrumentor() {} 370 371 /// See PassInstrumentation::runBeforePass for details. 372 void PassInstrumentor::runBeforePass(Pass *pass, Operation *op) { 373 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 374 for (auto &instr : impl->instrumentations) 375 instr->runBeforePass(pass, op); 376 } 377 378 /// See PassInstrumentation::runAfterPass for details. 379 void PassInstrumentor::runAfterPass(Pass *pass, Operation *op) { 380 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 381 for (auto &instr : llvm::reverse(impl->instrumentations)) 382 instr->runAfterPass(pass, op); 383 } 384 385 /// See PassInstrumentation::runAfterPassFailed for details. 386 void PassInstrumentor::runAfterPassFailed(Pass *pass, Operation *op) { 387 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 388 for (auto &instr : llvm::reverse(impl->instrumentations)) 389 instr->runAfterPassFailed(pass, op); 390 } 391 392 /// See PassInstrumentation::runBeforeAnalysis for details. 393 void PassInstrumentor::runBeforeAnalysis(llvm::StringRef name, AnalysisID *id, 394 Operation *op) { 395 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 396 for (auto &instr : impl->instrumentations) 397 instr->runBeforeAnalysis(name, id, op); 398 } 399 400 /// See PassInstrumentation::runAfterAnalysis for details. 401 void PassInstrumentor::runAfterAnalysis(llvm::StringRef name, AnalysisID *id, 402 Operation *op) { 403 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 404 for (auto &instr : llvm::reverse(impl->instrumentations)) 405 instr->runAfterAnalysis(name, id, op); 406 } 407 408 /// Add the given instrumentation to the collection. This takes ownership over 409 /// the given pointer. 410 void PassInstrumentor::addInstrumentation(PassInstrumentation *pi) { 411 llvm::sys::SmartScopedLock<true> instrumentationLock(impl->mutex); 412 impl->instrumentations.emplace_back(pi); 413 } 414 415 constexpr AnalysisID mlir::detail::PreservedAnalyses::allAnalysesID;