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 @@ -215,8 +215,6 @@ virtual void handleFiltered(StringRef PassID, std::string &Name) = 0; // Called when an ignored pass is encountered. virtual void handleIgnored(StringRef PassID, std::string &Name) = 0; - // Called to compare the before and after representations of the IR. - virtual bool same(const IRUnitT &Before, const IRUnitT &After) = 0; // Stack of IRs before passes. std::vector BeforeStack; @@ -269,50 +267,47 @@ void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override; - // Called to compare the before and after representations of the IR. - bool same(const std::string &Before, const std::string &After) override; }; -// The following classes hold a representation of the IR for a change -// reporter that uses string comparisons of the basic blocks -// that are created using print (ie, similar to dump()). -// These classes respect the filtering of passes and functions using -// -filter-passes and -filter-print-funcs. -// // Information that needs to be saved for a basic block in order to compare // before and after the pass to determine if it was changed by a pass. -class ChangedBlockData { +template class BlockDataT { public: - ChangedBlockData(const BasicBlock &B); - - bool operator==(const ChangedBlockData &That) const { - return Body == That.Body; - } - bool operator!=(const ChangedBlockData &That) const { - return Body != That.Body; + BlockDataT(const BasicBlock &B) : Label(B.getName().str()), Data(B) { + raw_string_ostream SS(Body); + B.print(SS, nullptr, true, true); } + bool operator==(const BlockDataT &That) const { return Body == That.Body; } + bool operator!=(const BlockDataT &That) const { return Body != That.Body; } + // Return the label of the represented basic block. StringRef getLabel() const { return Label; } // Return the string representation of the basic block. StringRef getBody() const { return Body; } + // Return the associated data + const T &getData() const { return Data; } + protected: std::string Label; std::string Body; + + // Extra data associated with a basic block + T Data; }; -template class OrderedChangedData { +template class OrderedChangedData { public: // Return the names in the order they were saved std::vector &getOrder() { return Order; } const std::vector &getOrder() const { return Order; } // Return a map of names to saved representations - StringMap &getData() { return Data; } - const StringMap &getData() const { return Data; } + StringMap &getData() { return Data; } + const StringMap &getData() const { return Data; } - bool operator==(const OrderedChangedData &That) const { + bool operator==(const OrderedChangedData &That) const { return Data == That.getData(); } @@ -321,55 +316,56 @@ // with ones that are only in \p Before interspersed based on where they // occur in \p Before. This is used to present the output in an order // based on how the data is ordered in LLVM. - static void - report(const OrderedChangedData &Before, const OrderedChangedData &After, - function_ref HandlePair); + static void report(const OrderedChangedData &Before, + const OrderedChangedData &After, + function_ref HandlePair); protected: std::vector Order; - StringMap Data; + StringMap Data; +}; + +// Do not need extra information for patch-style change reporter. +class EmptyData { +public: + EmptyData(const BasicBlock &) {} }; // The data saved for comparing functions. -using ChangedFuncData = OrderedChangedData; +template +class FuncDataT : public OrderedChangedData> {}; -// A map of names to the saved data. -using ChangedIRData = OrderedChangedData; +// The data saved for comparing IRs. +template +class IRDataT : public OrderedChangedData> {}; -// A class that compares two IRs and does a diff between them. The -// added lines are prefixed with a '+', the removed lines are prefixed -// with a '-' and unchanged lines are prefixed with a space (to have -// things line up). -class ChangedIRComparer { +// Abstract template base class for a class that compares two IRs. The +// class is created with the 2 IRs to compare and then compare is called. +// The static function analyzeIR is used to build up the IR representation. +template class IRComparer { public: - ChangedIRComparer(raw_ostream &OS, const ChangedIRData &Before, - const ChangedIRData &After, bool ColourMode) - : Before(Before), After(After), Out(OS), UseColour(ColourMode) {} + IRComparer(const IRDataT &Before, const IRDataT &After) + : Before(Before), After(After) {} - // Compare the 2 IRs. - void compare(Any IR, StringRef Prefix, StringRef PassID, StringRef Name); + // Compare the 2 IRs. \p handleFunctionCompare is called to handle the + // compare of a function. When \p InModule is set, + // this function is being handled as part of comparing a module. + + void compare( + bool CompareModule, + std::function &Before, const FuncDataT &After)> + CompareFunc); // Analyze \p IR and build the IR representation in \p Data. - static void analyzeIR(Any IR, ChangedIRData &Data); + static void analyzeIR(Any IR, IRDataT &Data); protected: - // Return the module when that is the appropriate level of - // comparison for \p IR. - static const Module *getModuleForComparison(Any IR); - // Generate the data for \p F into \p Data. - static bool generateFunctionData(ChangedIRData &Data, const Function &F); - - // Called to handle the compare of a function. When \p InModule is set, - // this function is being handled as part of comparing a module. - void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, - bool InModule, const ChangedFuncData &Before, - const ChangedFuncData &After); + static bool generateFunctionData(IRDataT &Data, const Function &F); - const ChangedIRData &Before; - const ChangedIRData &After; - raw_ostream &Out; - bool UseColour; + const IRDataT &Before; + const IRDataT &After; }; // A change printer that prints out in-line differences in the basic @@ -378,25 +374,28 @@ // and added, respectively. Changes to the IR that do not affect basic // blocks are not reported as having changed the IR. The option // -print-module-scope does not affect this change reporter. -class InLineChangePrinter : public TextChangeReporter { +class InLineChangePrinter : public TextChangeReporter> { public: InLineChangePrinter(bool VerboseMode, bool ColourMode) - : TextChangeReporter(VerboseMode), UseColour(ColourMode) {} + : TextChangeReporter>(VerboseMode), + UseColour(ColourMode) {} ~InLineChangePrinter() override; void registerCallbacks(PassInstrumentationCallbacks &PIC); protected: // Create a representation of the IR. virtual void generateIRRepresentation(Any IR, StringRef PassID, - ChangedIRData &Output) override; + IRDataT &Output) override; // Called when an interesting IR has changed. virtual void handleAfter(StringRef PassID, std::string &Name, - const ChangedIRData &Before, - const ChangedIRData &After, Any) override; - // Called to compare the before and after representations of the IR. - virtual bool same(const ChangedIRData &Before, - const ChangedIRData &After) override; + const IRDataT &Before, + const IRDataT &After, Any) override; + + void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, + StringRef Divider, bool InModule, unsigned Minor, + const FuncDataT &Before, + const FuncDataT &After); bool UseColour; }; @@ -440,8 +439,12 @@ extern template class ChangeReporter; extern template class TextChangeReporter; -extern template class ChangeReporter; -extern template class TextChangeReporter; +extern template class BlockDataT; +extern template class FuncDataT; +extern template class IRDataT; +extern template class ChangeReporter>; +extern template class TextChangeReporter>; +extern template class IRComparer; } // namespace llvm 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 @@ -166,7 +166,8 @@ SmallString<128> ULF = formatv("--unchanged-line-format={0}", UnchangedLineFormat); - StringRef Args[] = {"-w", "-d", OLF, NLF, ULF, FileName[0], FileName[1]}; + StringRef Args[] = {DiffBinary, "-w", "-d", OLF, + NLF, ULF, FileName[0], FileName[1]}; Optional Redirects[] = {None, StringRef(FileName[2]), None}; int Result = sys::ExecuteAndWait(*DiffExe, Args, None, Redirects); if (Result < 0) @@ -366,20 +367,31 @@ "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass"}); } +// Return the module when that is the appropriate level of comparison for \p IR. +const Module *getModuleForComparison(Any IR) { + if (any_isa(IR)) + return any_cast(IR); + if (any_isa(IR)) + return any_cast(IR) + ->begin() + ->getFunction() + .getParent(); + return nullptr; +} + } // namespace -template -ChangeReporter::~ChangeReporter() { +template ChangeReporter::~ChangeReporter() { assert(BeforeStack.empty() && "Problem with Change Printer stack."); } -template -bool ChangeReporter::isInterestingFunction(const Function &F) { +template +bool ChangeReporter::isInterestingFunction(const Function &F) { return isFunctionInPrintList(F.getName()); } -template -bool ChangeReporter::isInterestingPass(StringRef PassID) { +template +bool ChangeReporter::isInterestingPass(StringRef PassID) { if (isIgnored(PassID)) return false; @@ -390,8 +402,8 @@ // Return true when this is a pass on IR for which printing // of changes is desired. -template -bool ChangeReporter::isInteresting(Any IR, StringRef PassID) { +template +bool ChangeReporter::isInteresting(Any IR, StringRef PassID) { if (!isInterestingPass(PassID)) return false; if (any_isa(IR)) @@ -399,8 +411,8 @@ return true; } -template -void ChangeReporter::saveIRBeforePass(Any IR, StringRef PassID) { +template +void ChangeReporter::saveIRBeforePass(Any IR, StringRef PassID) { // Always need to place something on the stack because invalidated passes // are not given the IR so it cannot be determined whether the pass was for // something that was filtered out. @@ -416,12 +428,12 @@ } // Save the IR representation on the stack. - IRUnitT &Data = BeforeStack.back(); + T &Data = BeforeStack.back(); generateIRRepresentation(IR, PassID, Data); } -template -void ChangeReporter::handleIRAfterPass(Any IR, StringRef PassID) { +template +void ChangeReporter::handleIRAfterPass(Any IR, StringRef PassID) { assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); std::string Name = getIRName(IR); @@ -434,13 +446,13 @@ handleFiltered(PassID, Name); } else { // Get the before rep from the stack - IRUnitT &Before = BeforeStack.back(); + T &Before = BeforeStack.back(); // Create the after rep - IRUnitT After; + T After; generateIRRepresentation(IR, PassID, After); // Was there a change in IR? - if (same(Before, After)) { + if (Before == After) { if (VerboseMode) omitAfter(PassID, Name); } else @@ -449,8 +461,8 @@ BeforeStack.pop_back(); } -template -void ChangeReporter::handleInvalidatedPass(StringRef PassID) { +template +void ChangeReporter::handleInvalidatedPass(StringRef PassID) { assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); // Always flag it as invalidated as we cannot determine when @@ -462,8 +474,8 @@ BeforeStack.pop_back(); } -template -void ChangeReporter::registerRequiredCallbacks( +template +void ChangeReporter::registerRequiredCallbacks( PassInstrumentationCallbacks &PIC) { PIC.registerBeforeNonSkippedPassCallback( [this](StringRef P, Any IR) { saveIRBeforePass(IR, P); }); @@ -478,18 +490,11 @@ }); } -ChangedBlockData::ChangedBlockData(const BasicBlock &B) - : Label(B.getName().str()) { - raw_string_ostream SS(Body); - B.print(SS, nullptr, true, true); -} - -template -TextChangeReporter::TextChangeReporter(bool Verbose) - : ChangeReporter(Verbose), Out(dbgs()) {} +template +TextChangeReporter::TextChangeReporter(bool Verbose) + : ChangeReporter(Verbose), Out(dbgs()) {} -template -void TextChangeReporter::handleInitialIR(Any IR) { +template void TextChangeReporter::handleInitialIR(Any IR) { // Always print the module. // Unwrap and print directly to avoid filtering problems in general routines. auto *M = unwrapModule(IR, /*Force=*/true); @@ -498,29 +503,27 @@ M->print(Out, nullptr); } -template -void TextChangeReporter::omitAfter(StringRef PassID, - std::string &Name) { +template +void TextChangeReporter::omitAfter(StringRef PassID, std::string &Name) { Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n", PassID, Name); } -template -void TextChangeReporter::handleInvalidated(StringRef PassID) { +template +void TextChangeReporter::handleInvalidated(StringRef PassID) { Out << formatv("*** IR Pass {0} invalidated ***\n", PassID); } -template -void TextChangeReporter::handleFiltered(StringRef PassID, - std::string &Name) { +template +void TextChangeReporter::handleFiltered(StringRef PassID, + std::string &Name) { SmallString<20> Banner = formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name); Out << Banner; } -template -void TextChangeReporter::handleIgnored(StringRef PassID, - std::string &Name) { +template +void TextChangeReporter::handleIgnored(StringRef PassID, std::string &Name) { Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name); } @@ -557,14 +560,10 @@ Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After; } -bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) { - return S1 == S2; -} - -template -void OrderedChangedData::report( +template +void OrderedChangedData::report( const OrderedChangedData &Before, const OrderedChangedData &After, - function_ref HandlePair) { + function_ref HandlePair) { const auto &BFD = Before.getData(); const auto &AFD = After.getData(); std::vector::const_iterator BI = Before.getOrder().begin(); @@ -572,21 +571,21 @@ std::vector::const_iterator AI = After.getOrder().begin(); std::vector::const_iterator AE = After.getOrder().end(); - auto handlePotentiallyRemovedIRData = [&](std::string S) { + auto HandlePotentiallyRemovedData = [&](std::string S) { // The order in LLVM may have changed so check if still exists. if (!AFD.count(S)) { // This has been removed. HandlePair(&BFD.find(*BI)->getValue(), nullptr); } }; - auto handleNewIRData = [&](std::vector &Q) { + auto HandleNewData = [&](std::vector &Q) { // Print out any queued up new sections - for (const IRData *NBI : Q) + for (const T *NBI : Q) HandlePair(nullptr, NBI); Q.clear(); }; - // Print out the IRData in the after order, with before ones interspersed + // Print out the data in the after order, with before ones interspersed // appropriately (ie, somewhere near where they were in the before list). // Start at the beginning of both lists. Loop through the // after list. If an element is common, then advance in the before list @@ -595,26 +594,26 @@ // common, then enqueue it for reporting. When the after list is exhausted, // loop through the before list, reporting any removed ones. Finally, // report the rest of the enqueued new ones. - std::vector NewIRDataQueue; + std::vector NewDataQueue; while (AI != AE) { if (!BFD.count(*AI)) { // This section is new so place it in the queue. This will cause it // to be reported after deleted sections. - NewIRDataQueue.emplace_back(&AFD.find(*AI)->getValue()); + NewDataQueue.emplace_back(&AFD.find(*AI)->getValue()); ++AI; continue; } // This section is in both; advance and print out any before-only // until we get to it. while (*BI != *AI) { - handlePotentiallyRemovedIRData(*BI); + HandlePotentiallyRemovedData(*BI); ++BI; } // Report any new sections that were queued up and waiting. - handleNewIRData(NewIRDataQueue); + HandleNewData(NewDataQueue); - const IRData &AData = AFD.find(*AI)->getValue(); - const IRData &BData = BFD.find(*AI)->getValue(); + const T &AData = AFD.find(*AI)->getValue(); + const T &BData = BFD.find(*AI)->getValue(); HandlePair(&BData, &AData); ++BI; ++AI; @@ -622,38 +621,42 @@ // Check any remaining before sections to see if they have been removed while (BI != BE) { - handlePotentiallyRemovedIRData(*BI); + HandlePotentiallyRemovedData(*BI); ++BI; } - handleNewIRData(NewIRDataQueue); + HandleNewData(NewDataQueue); } -void ChangedIRComparer::compare(Any IR, StringRef Prefix, StringRef PassID, - StringRef Name) { - if (!getModuleForComparison(IR)) { - // Not a module so just handle the single function. - assert(Before.getData().size() == 1 && "Expected only one function."); - assert(After.getData().size() == 1 && "Expected only one function."); - handleFunctionCompare(Name, Prefix, PassID, false, - Before.getData().begin()->getValue(), - After.getData().begin()->getValue()); +template +void IRComparer::compare( + bool CompareModule, + std::function &Before, const FuncDataT &After)> + CompareFunc) { + if (!CompareModule) { + // Just handle the single function. + assert(Before.getData().size() == 1 && After.getData().size() == 1 && + "Expected only one function."); + CompareFunc(false, 0, Before.getData().begin()->getValue(), + After.getData().begin()->getValue()); return; } - ChangedIRData::report( - Before, After, [&](const ChangedFuncData *B, const ChangedFuncData *A) { - assert((B || A) && "Both functions cannot be missing."); - ChangedFuncData Missing; - if (!B) - B = &Missing; - else if (!A) - A = &Missing; - handleFunctionCompare(Name, Prefix, PassID, true, *B, *A); - }); + unsigned Minor = 0; + FuncDataT Missing; + IRDataT::report(Before, After, + [&](const FuncDataT *B, const FuncDataT *A) { + assert((B || A) && "Both functions cannot be missing."); + if (!B) + B = &Missing; + else if (!A) + A = &Missing; + CompareFunc(true, Minor++, *B, *A); + }); } -void ChangedIRComparer::analyzeIR(Any IR, ChangedIRData &Data) { +template void IRComparer::analyzeIR(Any IR, IRDataT &Data) { if (const Module *M = getModuleForComparison(IR)) { // Create data for each existing/interesting function in the module. for (const Function &F : *M) @@ -673,27 +676,16 @@ generateFunctionData(Data, *F); } -const Module *ChangedIRComparer::getModuleForComparison(Any IR) { - if (any_isa(IR)) - return any_cast(IR); - if (any_isa(IR)) - return any_cast(IR) - ->begin() - ->getFunction() - .getParent(); - return nullptr; -} - -bool ChangedIRComparer::generateFunctionData(ChangedIRData &Data, - const Function &F) { +template +bool IRComparer::generateFunctionData(IRDataT &Data, const Function &F) { if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { - ChangedFuncData CFD; + FuncDataT FD; for (const auto &B : F) { - CFD.getOrder().emplace_back(B.getName()); - CFD.getData().insert({B.getName(), B}); + FD.getOrder().emplace_back(B.getName()); + FD.getData().insert({B.getName(), B}); } Data.getOrder().emplace_back(F.getName()); - Data.getData().insert({F.getName(), CFD}); + Data.getData().insert({F.getName(), FD}); return true; } return false; @@ -787,7 +779,7 @@ return true; StringRef PassName = PIC->getPassNameForClassName(PassID); - return llvm::is_contained(printBeforePasses(), PassName); + return is_contained(printBeforePasses(), PassName); } bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) { @@ -795,7 +787,7 @@ return true; StringRef PassName = PIC->getPassNameForClassName(PassID); - return llvm::is_contained(printAfterPasses(), PassName); + return is_contained(printAfterPasses(), PassName); } void PrintIRInstrumentation::registerCallbacks( @@ -869,14 +861,13 @@ SpecialPasses.emplace_back("PassAdaptor"); } - PIC.registerBeforeSkippedPassCallback( - [this, SpecialPasses](StringRef PassID, Any IR) { - assert(!isSpecialPass(PassID, SpecialPasses) && - "Unexpectedly skipping special pass"); + PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID, + Any IR) { + assert(!isSpecialPass(PassID, SpecialPasses) && + "Unexpectedly skipping special pass"); - print() << "Skipping pass: " << PassID << " on " << getIRName(IR) - << "\n"; - }); + print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n"; + }); PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses]( StringRef PassID, Any IR) { if (isSpecialPass(PassID, SpecialPasses)) @@ -1074,19 +1065,18 @@ report_fatal_error(Twine("CFG unexpectedly changed by ", Pass)); }; - PIC.registerBeforeNonSkippedPassCallback( - [this, &FAM](StringRef P, Any IR) { + PIC.registerBeforeNonSkippedPassCallback([this, &FAM](StringRef P, Any IR) { #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS - assert(&PassStack.emplace_back(P)); + assert(&PassStack.emplace_back(P)); #endif - (void)this; - if (!any_isa(IR)) - return; + (void)this; + if (!any_isa(IR)) + return; - const auto *F = any_cast(IR); - // Make sure a fresh CFG snapshot is available before the pass. - FAM.getResult(*const_cast(F)); - }); + const auto *F = any_cast(IR); + // Make sure a fresh CFG snapshot is available before the pass. + FAM.getResult(*const_cast(F)); + }); PIC.registerAfterPassInvalidatedCallback( [this](StringRef P, const PreservedAnalyses &PassPA) { @@ -1160,36 +1150,38 @@ InLineChangePrinter::~InLineChangePrinter() {} void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID, - ChangedIRData &D) { - ChangedIRComparer::analyzeIR(IR, D); + IRDataT &D) { + IRComparer::analyzeIR(IR, D); } void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name, - const ChangedIRData &Before, - const ChangedIRData &After, Any IR) { + const IRDataT &Before, + const IRDataT &After, Any IR) { SmallString<20> Banner = formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name); Out << Banner; - ChangedIRComparer(Out, Before, After, UseColour) - .compare(IR, "", PassID, Name); + IRComparer(Before, After) + .compare(getModuleForComparison(IR), + [&](bool InModule, unsigned Minor, + const FuncDataT &Before, + const FuncDataT &After) -> void { + handleFunctionCompare(Name, "", PassID, " on ", InModule, + Minor, Before, After); + }); Out << "\n"; } -bool InLineChangePrinter::same(const ChangedIRData &D1, - const ChangedIRData &D2) { - return D1 == D2; -} - -void ChangedIRComparer::handleFunctionCompare(StringRef Name, StringRef Prefix, - StringRef PassID, bool InModule, - const ChangedFuncData &Before, - const ChangedFuncData &After) { +void InLineChangePrinter::handleFunctionCompare( + StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, + bool InModule, unsigned Minor, const FuncDataT &Before, + const FuncDataT &After) { // Print a banner when this is being shown in the context of a module if (InModule) Out << "\n*** IR for function " << Name << " ***\n"; - ChangedFuncData::report( - Before, After, [&](const ChangedBlockData *B, const ChangedBlockData *A) { + FuncDataT::report( + Before, After, + [&](const BlockDataT *B, const BlockDataT *A) { StringRef BStr = B ? B->getBody() : "\n"; StringRef AStr = A ? A->getBody() : "\n"; const std::string Removed = @@ -1205,9 +1197,11 @@ PrintChanged == ChangePrinter::PrintChangedDiffQuiet || PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose || PrintChanged == ChangePrinter::PrintChangedColourDiffQuiet) - TextChangeReporter::registerRequiredCallbacks(PIC); + TextChangeReporter>::registerRequiredCallbacks(PIC); } +namespace llvm { + StandardInstrumentations::StandardInstrumentations( bool DebugLogging, bool VerifyEach, PrintPassOptions PrintPassOpts) : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging), @@ -1235,12 +1229,14 @@ PrintChangedDiff.registerCallbacks(PIC); } -namespace llvm { - template class ChangeReporter; template class TextChangeReporter; -template class ChangeReporter; -template class TextChangeReporter; +template class BlockDataT; +template class FuncDataT; +template class IRDataT; +template class ChangeReporter>; +template class TextChangeReporter>; +template class IRComparer; } // namespace llvm