diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h --- a/llvm/include/llvm/Passes/StandardInstrumentations.h +++ b/llvm/include/llvm/Passes/StandardInstrumentations.h @@ -52,6 +52,8 @@ bool shouldPrintBeforePass(StringRef PassID); bool shouldPrintAfterPass(StringRef PassID); + bool shouldPrintPassNumbers(); + bool shouldPrintAtPassNumber(); using PrintModuleDesc = std::tuple; @@ -62,6 +64,9 @@ /// Stack of Module description, enough to print the module after a given /// pass. SmallVector ModuleDescStack; + + /// Used for print-at-pass-number + unsigned CurrentPassNumber = 0; }; class OptNoneInstrumentation { diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp --- a/llvm/lib/Passes/StandardInstrumentations.cpp +++ b/llvm/lib/Passes/StandardInstrumentations.cpp @@ -111,6 +111,15 @@ "opt-bisect-print-ir-path", cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden); +static cl::opt PrintPassNumbers( + "print-pass-numbers", cl::init(false), cl::Hidden, + cl::desc("Print pass names and their ordinals")); + +static cl::opt + PrintAtPassNumber("print-at-pass-number", cl::init(0), cl::Hidden, + cl::desc("Print IR at pass with this number as " + "reported by print-passes-names")); + namespace { // An option for specifying an executable that will be called with the IR @@ -696,13 +705,19 @@ // 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 (shouldPrintAfterPass(PassID)) + if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() || + shouldPrintAfterPass(PassID)) pushModuleDesc(PassID, IR); - if (!shouldPrintBeforePass(PassID)) + if (!shouldPrintIR(IR)) return; - if (!shouldPrintIR(IR)) + ++CurrentPassNumber; + + if (shouldPrintPassNumbers()) + dbgs() << " Running pass " << CurrentPassNumber << " " << PassID << "\n"; + + if (!shouldPrintBeforePass(PassID)) return; dbgs() << "*** IR Dump Before " << PassID << " on " << getIRName(IR) @@ -714,7 +729,8 @@ if (isIgnored(PassID)) return; - if (!shouldPrintAfterPass(PassID)) + if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() && + !shouldPrintAtPassNumber()) return; const Module *M; @@ -723,18 +739,23 @@ std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID); assert(StoredPassID == PassID && "mismatched PassID"); - if (!shouldPrintIR(IR)) + if (!shouldPrintIR(IR) || !shouldPrintAfterPass(PassID)) return; - dbgs() << "*** IR Dump After " << PassID << " on " << IRName << " ***\n"; + dbgs() << "*** IR Dump " + << (shouldPrintAtPassNumber() + ? StringRef(formatv("At {0}-{1}", CurrentPassNumber, PassID)) + : StringRef(formatv("After {0}", PassID))) + << " on " << IRName << " ***\n"; unwrapAndPrint(dbgs(), IR); } void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { - if (!shouldPrintAfterPass(PassID)) + if (isIgnored(PassID)) return; - if (isIgnored(PassID)) + if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() && + !shouldPrintAtPassNumber()) return; const Module *M; @@ -744,11 +765,16 @@ assert(StoredPassID == PassID && "mismatched PassID"); // Additional filtering (e.g. -filter-print-func) can lead to module // printing being skipped. - if (!M) + if (!M || !shouldPrintAfterPass(PassID)) return; - SmallString<20> Banner = - formatv("*** IR Dump After {0} on {1} (invalidated) ***", PassID, IRName); + SmallString<20> Banner; + if (shouldPrintAtPassNumber()) + Banner = formatv("*** IR Dump At {0}-{1} on {2} (invalidated) ***", + CurrentPassNumber, PassID, IRName); + else + Banner = formatv("*** IR Dump After {0} on {1} (invalidated) ***", + PassID, IRName); dbgs() << Banner << "\n"; printIR(dbgs(), M); } @@ -765,21 +791,34 @@ if (shouldPrintAfterAll()) return true; + if (shouldPrintAtPassNumber() && CurrentPassNumber == PrintAtPassNumber) + return true; + StringRef PassName = PIC->getPassNameForClassName(PassID); return is_contained(printAfterPasses(), PassName); } +bool PrintIRInstrumentation::shouldPrintPassNumbers() { + return PrintPassNumbers; +} + +bool PrintIRInstrumentation::shouldPrintAtPassNumber() { + return PrintAtPassNumber > 0; +} + void PrintIRInstrumentation::registerCallbacks( PassInstrumentationCallbacks &PIC) { this->PIC = &PIC; // BeforePass callback is not just for printing, it also saves a Module // for later use in AfterPassInvalidated. - if (shouldPrintBeforeSomePass() || shouldPrintAfterSomePass()) + if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() || + shouldPrintBeforeSomePass() || shouldPrintAfterSomePass()) PIC.registerBeforeNonSkippedPassCallback( [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); - if (shouldPrintAfterSomePass()) { + if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() || + shouldPrintAfterSomePass()) { PIC.registerAfterPassCallback( [this](StringRef P, Any IR, const PreservedAnalyses &) { this->printAfterPass(P, IR); diff --git a/llvm/test/Other/print-at-pass-number.ll b/llvm/test/Other/print-at-pass-number.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/print-at-pass-number.ll @@ -0,0 +1,32 @@ +; RUN: opt -passes="loop(indvars,loop-deletion,loop-unroll-full)" -print-pass-numbers -S -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=NUMBER +; RUN: opt -passes="loop(indvars,loop-deletion,loop-unroll-full)" -print-module-scope -print-at-pass-number=3 -S -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=AT +; RUN: opt -passes="loop(indvars,loop-deletion,loop-unroll-full)" -print-module-scope -print-at-pass-number=4 -S -o /dev/null %s 2>&1 | FileCheck %s --check-prefix=AT-INVALIDATE + +define i32 @bar(i32 %arg) { +; AT: *** IR Dump At 3-IndVarSimplifyPass on bb1 *** +; AT: define i32 @bar(i32 %arg) { + +; AT-INVALIDATE: *** IR Dump At 4-LoopDeletionPass on bb1 (invalidated) *** +; AT-INVALIDATE: define i32 @bar(i32 %arg) { + +bb: + br label %bb1 + +bb1: ; preds = %bb1, %bb + %phi = phi i32 [ 0, %bb ], [ %add, %bb1 ] + %phi2 = phi i32 [ 0, %bb ], [ %add3, %bb1 ] + %add = add i32 %phi, 1 + %add3 = add i32 %phi2, %add + %icmp = icmp slt i32 %phi, %arg + br i1 %icmp, label %bb1, label %bb4 + +bb4: ; preds = %bb1 + ret i32 %add3 +} + +; NUMBER: Running pass 1 LoopSimplifyPass +; NUMBER-NEXT: Running pass 2 LCSSAPass +; NUMBER-NEXT: Running pass 3 IndVarSimplifyPass +; NUMBER-NEXT: Running pass 4 LoopDeletionPass +; NUMBER-NEXT: Running pass 5 VerifierPass +; NUMBER-NEXT: Running pass 6 PrintModulePass