|  | //===- Standard pass instrumentations handling ----------------*- C++ -*--===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// \file | 
|  | /// | 
|  | /// This file defines IR-printing pass instrumentation callbacks as well as | 
|  | /// StandardInstrumentations class that manages standard pass instrumentations. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Passes/StandardInstrumentations.h" | 
|  | #include "llvm/ADT/Optional.h" | 
|  | #include "llvm/Analysis/CallGraphSCCPass.h" | 
|  | #include "llvm/Analysis/LazyCallGraph.h" | 
|  | #include "llvm/Analysis/LoopInfo.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/IRPrintingPasses.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/IR/PassInstrumentation.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/FormatVariadic.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// Extracting Module out of \p IR unit. Also fills a textual description | 
|  | /// of \p IR for use in header when printing. | 
|  | Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) { | 
|  | if (any_isa<const Module *>(IR)) | 
|  | return std::make_pair(any_cast<const Module *>(IR), std::string()); | 
|  |  | 
|  | if (any_isa<const Function *>(IR)) { | 
|  | const Function *F = any_cast<const Function *>(IR); | 
|  | if (!llvm::isFunctionInPrintList(F->getName())) | 
|  | return None; | 
|  | const Module *M = F->getParent(); | 
|  | return std::make_pair(M, formatv(" (function: {0})", F->getName()).str()); | 
|  | } | 
|  |  | 
|  | if (any_isa<const LazyCallGraph::SCC *>(IR)) { | 
|  | const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); | 
|  | for (const LazyCallGraph::Node &N : *C) { | 
|  | const Function &F = N.getFunction(); | 
|  | if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { | 
|  | const Module *M = F.getParent(); | 
|  | return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str()); | 
|  | } | 
|  | } | 
|  | return None; | 
|  | } | 
|  |  | 
|  | if (any_isa<const Loop *>(IR)) { | 
|  | const Loop *L = any_cast<const Loop *>(IR); | 
|  | const Function *F = L->getHeader()->getParent(); | 
|  | if (!isFunctionInPrintList(F->getName())) | 
|  | return None; | 
|  | const Module *M = F->getParent(); | 
|  | std::string LoopName; | 
|  | raw_string_ostream ss(LoopName); | 
|  | L->getHeader()->printAsOperand(ss, false); | 
|  | return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str()); | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Unknown IR unit"); | 
|  | } | 
|  |  | 
|  | void printIR(const Module *M, StringRef Banner, StringRef Extra = StringRef()) { | 
|  | dbgs() << Banner << Extra << "\n"; | 
|  | M->print(dbgs(), nullptr, false); | 
|  | } | 
|  | void printIR(const Function *F, StringRef Banner, | 
|  | StringRef Extra = StringRef()) { | 
|  | if (!llvm::isFunctionInPrintList(F->getName())) | 
|  | return; | 
|  | dbgs() << Banner << Extra << "\n" << static_cast<const Value &>(*F); | 
|  | } | 
|  | void printIR(const LazyCallGraph::SCC *C, StringRef Banner, | 
|  | StringRef Extra = StringRef()) { | 
|  | bool BannerPrinted = false; | 
|  | for (const LazyCallGraph::Node &N : *C) { | 
|  | const Function &F = N.getFunction(); | 
|  | if (!F.isDeclaration() && llvm::isFunctionInPrintList(F.getName())) { | 
|  | if (!BannerPrinted) { | 
|  | dbgs() << Banner << Extra << "\n"; | 
|  | BannerPrinted = true; | 
|  | } | 
|  | F.print(dbgs()); | 
|  | } | 
|  | } | 
|  | } | 
|  | void printIR(const Loop *L, StringRef Banner) { | 
|  | const Function *F = L->getHeader()->getParent(); | 
|  | if (!llvm::isFunctionInPrintList(F->getName())) | 
|  | return; | 
|  | llvm::printLoop(const_cast<Loop &>(*L), dbgs(), Banner); | 
|  | } | 
|  |  | 
|  | /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into | 
|  | /// llvm::Any and does actual print job. | 
|  | void unwrapAndPrint(Any IR, StringRef Banner, bool ForceModule = false) { | 
|  | if (ForceModule) { | 
|  | if (auto UnwrappedModule = unwrapModule(IR)) | 
|  | printIR(UnwrappedModule->first, Banner, UnwrappedModule->second); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (any_isa<const Module *>(IR)) { | 
|  | const Module *M = any_cast<const Module *>(IR); | 
|  | assert(M && "module should be valid for printing"); | 
|  | printIR(M, Banner); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (any_isa<const Function *>(IR)) { | 
|  | const Function *F = any_cast<const Function *>(IR); | 
|  | assert(F && "function should be valid for printing"); | 
|  | printIR(F, Banner); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (any_isa<const LazyCallGraph::SCC *>(IR)) { | 
|  | const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); | 
|  | assert(C && "scc should be valid for printing"); | 
|  | std::string Extra = formatv(" (scc: {0})", C->getName()); | 
|  | printIR(C, Banner, Extra); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (any_isa<const Loop *>(IR)) { | 
|  | const Loop *L = any_cast<const Loop *>(IR); | 
|  | assert(L && "Loop should be valid for printing"); | 
|  | printIR(L, Banner); | 
|  | return; | 
|  | } | 
|  | llvm_unreachable("Unknown wrapped IR type"); | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | PrintIRInstrumentation::~PrintIRInstrumentation() { | 
|  | assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); | 
|  | } | 
|  |  | 
|  | void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { | 
|  | assert(StoreModuleDesc); | 
|  | const Module *M = nullptr; | 
|  | std::string Extra; | 
|  | if (auto UnwrappedModule = unwrapModule(IR)) | 
|  | std::tie(M, Extra) = UnwrappedModule.getValue(); | 
|  | ModuleDescStack.emplace_back(M, Extra, PassID); | 
|  | } | 
|  |  | 
|  | PrintIRInstrumentation::PrintModuleDesc | 
|  | PrintIRInstrumentation::popModuleDesc(StringRef PassID) { | 
|  | assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); | 
|  | PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); | 
|  | assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); | 
|  | return ModuleDesc; | 
|  | } | 
|  |  | 
|  | bool PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { | 
|  | if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) | 
|  | return true; | 
|  |  | 
|  | // Saving Module for AfterPassInvalidated operations. | 
|  | // Note: here we rely on a fact that we do not change modules while | 
|  | // traversing the pipeline, so the latest captured module is good | 
|  | // for all print operations that has not happen yet. | 
|  | if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID)) | 
|  | pushModuleDesc(PassID, IR); | 
|  |  | 
|  | if (!llvm::shouldPrintBeforePass(PassID)) | 
|  | return true; | 
|  |  | 
|  | SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); | 
|  | unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { | 
|  | if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) | 
|  | return; | 
|  |  | 
|  | if (!llvm::shouldPrintAfterPass(PassID)) | 
|  | return; | 
|  |  | 
|  | if (StoreModuleDesc) | 
|  | popModuleDesc(PassID); | 
|  |  | 
|  | SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); | 
|  | unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); | 
|  | } | 
|  |  | 
|  | void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { | 
|  | if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID)) | 
|  | return; | 
|  |  | 
|  | if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) | 
|  | return; | 
|  |  | 
|  | const Module *M; | 
|  | std::string Extra; | 
|  | StringRef StoredPassID; | 
|  | std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID); | 
|  | // Additional filtering (e.g. -filter-print-func) can lead to module | 
|  | // printing being skipped. | 
|  | if (!M) | 
|  | return; | 
|  |  | 
|  | SmallString<20> Banner = | 
|  | formatv("*** IR Dump After {0} *** invalidated: ", PassID); | 
|  | printIR(M, Banner, Extra); | 
|  | } | 
|  |  | 
|  | void PrintIRInstrumentation::registerCallbacks( | 
|  | PassInstrumentationCallbacks &PIC) { | 
|  | // BeforePass callback is not just for printing, it also saves a Module | 
|  | // for later use in AfterPassInvalidated. | 
|  | StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass(); | 
|  | if (llvm::shouldPrintBeforePass() || StoreModuleDesc) | 
|  | PIC.registerBeforePassCallback( | 
|  | [this](StringRef P, Any IR) { return this->printBeforePass(P, IR); }); | 
|  |  | 
|  | if (llvm::shouldPrintAfterPass()) { | 
|  | PIC.registerAfterPassCallback( | 
|  | [this](StringRef P, Any IR) { this->printAfterPass(P, IR); }); | 
|  | PIC.registerAfterPassInvalidatedCallback( | 
|  | [this](StringRef P) { this->printAfterPassInvalidated(P); }); | 
|  | } | 
|  | } | 
|  |  | 
|  | void StandardInstrumentations::registerCallbacks( | 
|  | PassInstrumentationCallbacks &PIC) { | 
|  | PrintIR.registerCallbacks(PIC); | 
|  | TimePasses.registerCallbacks(PIC); | 
|  | } |