"opt-bisect-print-ir-path",
cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
+static cl::opt<bool> PrintPassNumbers(
+ "print-pass-numbers", cl::init(false), cl::Hidden,
+ cl::desc("Print pass names and their ordinals"));
+
+static cl::opt<unsigned>
+ 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
// 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)
if (isIgnored(PassID))
return;
- if (!shouldPrintAfterPass(PassID))
+ if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() &&
+ !shouldPrintAtPassNumber())
return;
const Module *M;
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;
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);
}
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);
--- /dev/null
+; 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