Changeset View
Changeset View
Standalone View
Standalone View
lib/Passes/StandardInstrumentations.cpp
Show All 22 Lines | |||||
#include "llvm/IR/PassInstrumentation.h" | #include "llvm/IR/PassInstrumentation.h" | ||||
#include "llvm/Support/Debug.h" | #include "llvm/Support/Debug.h" | ||||
#include "llvm/Support/FormatVariadic.h" | #include "llvm/Support/FormatVariadic.h" | ||||
#include "llvm/Support/raw_ostream.h" | #include "llvm/Support/raw_ostream.h" | ||||
using namespace llvm; | using namespace llvm; | ||||
namespace { | namespace { | ||||
namespace PrintIR { | |||||
//===----------------------------------------------------------------------===// | /// Extracting Module out of \p IR unit. Also fills a textual description | ||||
// IR-printing instrumentation | /// of \p IR for use in header when printing. | ||||
//===----------------------------------------------------------------------===// | std::pair<const Module *, std::string> unwrapModule(Any IR) { | ||||
philip.pfaffe: This should be an Optional. | |||||
std::string Extra; | |||||
philip.pfaffeUnsubmitted Why this intermiate? Why not just return? philip.pfaffe: Why this intermiate? Why not just return? | |||||
philip.pfaffeUnsubmitted *intermediate philip.pfaffe: *intermediate | |||||
/// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into | |||||
/// llvm::Any and does actual print job. | |||||
void unwrapAndPrint(StringRef Banner, Any IR) { | |||||
SmallString<40> Extra{"\n"}; | |||||
const Module *M = nullptr; | const Module *M = nullptr; | ||||
if (any_isa<const Module *>(IR)) { | if (any_isa<const Module *>(IR)) { | ||||
M = any_cast<const Module *>(IR); | M = any_cast<const Module *>(IR); | ||||
assert(M && "module should be valid for printing"); | assert(M && "module should be valid for printing"); | ||||
} else if (any_isa<const Function *>(IR)) { | } else if (any_isa<const Function *>(IR)) { | ||||
const Function *F = any_cast<const Function *>(IR); | const Function *F = any_cast<const Function *>(IR); | ||||
assert(F && "function should be valid for printing"); | assert(F && "function should be valid for printing"); | ||||
if (!llvm::isFunctionInPrintList(F->getName())) | if (!llvm::isFunctionInPrintList(F->getName())) | ||||
return; | return {nullptr, std::string()}; | ||||
if (!llvm::forcePrintModuleIR()) { | |||||
dbgs() << Banner << Extra << static_cast<const Value &>(*F); | |||||
return; | |||||
} | |||||
M = F->getParent(); | M = F->getParent(); | ||||
Extra = formatv(" (function: {0})\n", F->getName()); | Extra = formatv(" (function: {0})", F->getName()); | ||||
} else if (any_isa<const LazyCallGraph::SCC *>(IR)) { | } else if (any_isa<const LazyCallGraph::SCC *>(IR)) { | ||||
const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); | const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); | ||||
assert(C); | assert(C); | ||||
if (!llvm::forcePrintModuleIR()) { | |||||
Extra = formatv(" (scc: {0})\n", C->getName()); | |||||
bool BannerPrinted = false; | |||||
for (const LazyCallGraph::Node &N : *C) { | |||||
const Function &F = N.getFunction(); | |||||
if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { | |||||
if (!BannerPrinted) { | |||||
dbgs() << Banner << Extra; | |||||
BannerPrinted = true; | |||||
} | |||||
F.print(dbgs()); | |||||
} | |||||
} | |||||
return; | |||||
} | |||||
for (const LazyCallGraph::Node &N : *C) { | for (const LazyCallGraph::Node &N : *C) { | ||||
const Function &F = N.getFunction(); | const Function &F = N.getFunction(); | ||||
if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { | if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { | ||||
M = F.getParent(); | M = F.getParent(); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (!M) | if (!M) | ||||
return; | return {nullptr, std::string()}; | ||||
Extra = formatv(" (for scc: {0})\n", C->getName()); | Extra = formatv(" (scc: {0})", C->getName()); | ||||
} else if (any_isa<const Loop *>(IR)) { | } else if (any_isa<const Loop *>(IR)) { | ||||
const Loop *L = any_cast<const Loop *>(IR); | const Loop *L = any_cast<const Loop *>(IR); | ||||
assert(L && "Loop should be valid for printing"); | assert(L && "Loop should be valid for printing"); | ||||
const Function *F = L->getHeader()->getParent(); | const Function *F = L->getHeader()->getParent(); | ||||
if (!isFunctionInPrintList(F->getName())) | if (!isFunctionInPrintList(F->getName())) | ||||
return; | return {nullptr, std::string()}; | ||||
if (!llvm::forcePrintModuleIR()) { | |||||
llvm::printLoop(const_cast<Loop &>(*L), dbgs(), Banner); | |||||
return; | |||||
} | |||||
M = F->getParent(); | M = F->getParent(); | ||||
{ | { | ||||
std::string LoopName; | std::string LoopName; | ||||
raw_string_ostream ss(LoopName); | raw_string_ostream ss(LoopName); | ||||
L->getHeader()->printAsOperand(ss, false); | L->getHeader()->printAsOperand(ss, false); | ||||
Extra = formatv(" (loop: {0})\n", ss.str()); | Extra = formatv(" (loop: {0})", ss.str()); | ||||
} | } | ||||
} | } | ||||
if (M) { | assert(M && "module should be valid for printing"); | ||||
dbgs() << Banner << Extra; | return {M, std::move(Extra)}; | ||||
} | |||||
void printIR(const Module *M, StringRef Banner, StringRef Extra = StringRef()) { | |||||
dbgs() << Banner << Extra << "\n"; | |||||
M->print(dbgs(), nullptr, false); | M->print(dbgs(), nullptr, false); | ||||
} else { | } | ||||
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, | |||||
Is this truly more readable than UnwrappedModule->first, UnwrappedModule->second? philip.pfaffe: Is this truly more readable than UnwrappedModule->first, UnwrappedModule->second?
| |||||
Definitely not, thanks for suggestion. fedor.sergeev: Definitely not, thanks for suggestion. | |||||
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) { | |||||
const Module *M; | |||||
std::string Extra; | |||||
std::tie(M, Extra) = unwrapModule(IR); | |||||
if (M) | |||||
printIR(M, Banner, Extra); | |||||
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"); | llvm_unreachable("Unknown wrapped IR type"); | ||||
} | } | ||||
} // namespace | |||||
PrintIRInstrumentation::~PrintIRInstrumentation() { | |||||
assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); | |||||
} | } | ||||
bool printBeforePass(StringRef PassID, Any IR) { | void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { | ||||
if (!llvm::shouldPrintBeforePass(PassID)) | assert(StoreModuleDesc); | ||||
return true; | const Module *M; | ||||
std::string Extra; | |||||
std::tie(M, Extra) = unwrapModule(IR); | |||||
ModuleDescStack.emplace_back(M, Extra, PassID); | |||||
} | |||||
PrintIRInstrumentation::PrintModuleDesc | |||||
PrintIRInstrumentation::popModuleDesc(StringRef PassID) { | |||||
assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); | |||||
auto ModuleDesc = ModuleDescStack.pop_back_val(); | |||||
philip.pfaffeUnsubmitted Avoid AAA philip.pfaffe: Avoid AAA | |||||
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<")) | if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) | ||||
return true; | 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); | SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); | ||||
unwrapAndPrint(Banner, IR); | unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); | ||||
return true; | return true; | ||||
} | } | ||||
void printAfterPass(StringRef PassID, Any IR) { | void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { | ||||
if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) | |||||
return; | |||||
if (!llvm::shouldPrintAfterPass(PassID)) | if (!llvm::shouldPrintAfterPass(PassID)) | ||||
return; | 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<")) | if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) | ||||
return; | return; | ||||
SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); | const Module *M; | ||||
unwrapAndPrint(Banner, IR); | 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; | 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); }); | |||||
} | |||||
} | } | ||||
} // namespace PrintIR | |||||
} // namespace | |||||
void StandardInstrumentations::registerCallbacks( | void StandardInstrumentations::registerCallbacks( | ||||
PassInstrumentationCallbacks &PIC) { | PassInstrumentationCallbacks &PIC) { | ||||
if (llvm::shouldPrintBeforePass()) | PrintIR.registerCallbacks(PIC); | ||||
PIC.registerBeforePassCallback(PrintIR::printBeforePass); | |||||
if (llvm::shouldPrintAfterPass()) | |||||
PIC.registerAfterPassCallback(PrintIR::printAfterPass); | |||||
TimePasses.registerCallbacks(PIC); | TimePasses.registerCallbacks(PIC); | ||||
} | } |
This should be an Optional.