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-after-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 @@ -106,6 +106,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 @@ -691,7 +700,8 @@ // 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)) @@ -709,7 +719,8 @@ if (isIgnored(PassID)) return; - if (!shouldPrintAfterPass(PassID)) + if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() && + !shouldPrintAtPassNumber()) return; const Module *M; @@ -721,15 +732,28 @@ if (!shouldPrintIR(IR)) return; - dbgs() << "*** IR Dump After " << PassID << " on " << IRName << " ***\n"; + ++CurrentPassNumber; + + if (shouldPrintPassNumbers()) + dbgs() << " Running pass " << CurrentPassNumber << " " << PassID << "\n"; + + if (!shouldPrintAfterPass(PassID)) + return; + + 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; @@ -742,8 +766,22 @@ if (!M) return; - SmallString<20> Banner = - formatv("*** IR Dump After {0} on {1} (invalidated) ***", PassID, IRName); + ++CurrentPassNumber; + + if (shouldPrintPassNumbers()) + dbgs() << "Running pass " << CurrentPassNumber << " " << PassID << "\n"; + + StringRef PassName = PIC->getPassNameForClassName(PassID); + if (!shouldPrintAfterPass(PassName)) + return; + + 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); } @@ -760,21 +798,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,47 @@ +; 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 + +define i32 @bar(i32 %arg) { +; AT: *** IR Dump At 3-IndVarSimplifyPass on bb1 *** +; AT: define i32 @bar +; AT-SAME: (i32 [[ARG:%.*]]) { +; AT-NEXT: bb: +; AT-NEXT: [[SMAX:%.*]] = call i32 @llvm.smax.i32(i32 [[ARG]], i32 0) +; AT-NEXT: [[TMP0:%.*]] = shl nuw i32 [[SMAX]], 1 +; AT-NEXT: [[TMP1:%.*]] = zext i32 [[SMAX]] to i33 +; AT-NEXT: [[TMP2:%.*]] = add nsw i32 [[SMAX]], -1 +; AT-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i33 +; AT-NEXT: [[TMP4:%.*]] = mul i33 [[TMP1]], [[TMP3]] +; AT-NEXT: [[TMP5:%.*]] = lshr i33 [[TMP4]], 1 +; AT-NEXT: [[TMP6:%.*]] = trunc i33 [[TMP5]] to i32 +; AT-NEXT: [[TMP7:%.*]] = add i32 [[TMP0]], [[TMP6]] +; AT-NEXT: br label [[BB1:%.*]] +; AT: bb1: +; AT-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[BB:%.*]] ], [ [[ADD:%.*]], [[BB1]] ] +; AT-NEXT: [[ADD]] = add nuw i32 [[PHI]], 1 +; AT-NEXT: br i1 false, label [[BB1]], label [[BB4:%.*]] +; AT: bb4: +; AT-NEXT: [[TMP8:%.*]] = add i32 [[TMP7]], 1 +; AT-NEXT: ret i32 [[TMP8]] +; +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