Index: llvm/include/llvm/Passes/StandardInstrumentations.h =================================================================== --- llvm/include/llvm/Passes/StandardInstrumentations.h +++ llvm/include/llvm/Passes/StandardInstrumentations.h @@ -25,6 +25,7 @@ namespace llvm { +class Function; class Module; /// Instrumentation to print IR before/after passes. @@ -73,6 +74,91 @@ bool DebugLogging; }; +// Base class for classes that report changes to the IR. +// It presents an interface for such classes and provides callbacks +// on various events as the new pass manager transforms the IR. +// It also provides filtering of information based on hidden options +// specifying which functions are interesting. +// Callbacks are made for the following events/queries: +// 1. The initial IR processed. +// 2. To get the representation of the IR (of type \p T). +// 3. When a pass does not change the IR. +// 4. When a pass changes the IR (given both before and after representations +// of type \p T). +// 5. When an IR is invalidated. +// 6. When a pass is run on an IR that is not interesting (based on options). +// 7. When a pass is ignored (pass manager or adapter pass). +// 8. To compare two IR representations (of type \p T). +template class ChangePrinter { +protected: + ChangePrinter(std::function F1, + std::function F2, + std::function F3, + std::function + F4, + std::function F5, + std::function F6, + std::function F7, + std::function F8) + : HandleInitialIR(F1), GenerateIRRepresentation(F2), OmitAfter(F3), + HandleAfter(F4), HandleInvalidated(F5), HandleFiltered(F6), + HandleIgnored(F7), Same(F8), InitialIR(true) {} + +public: + // Not virtual as classes are expected to be referenced as derived classes. + ~ChangePrinter() { + assert(BeforeStack.empty() && "Problem with Change Printer stack."); + } + + // Determine if this pass/IR is interesting and if so, save the IR + // otherwise it is left on the stack without data + void saveIRBeforePass(Any IR, StringRef PassID); + // Compare the IR from before the pass after the pass. + void handleIRAfterPass(Any IR, StringRef PassID); + // Handle the situation where a pass is invalidated. + void handleInvalidatedPass(StringRef PassID); + +private: + // callback on the first IR processed + std::function HandleInitialIR; + // callback before and after a pass to get the representation of the IR + std::function + GenerateIRRepresentation; + // callback when the pass is not iteresting + std::function OmitAfter; + // callback when interesting IR has changed + std::function + HandleAfter; + // callback when an interesting pass is invalidated + std::function HandleInvalidated; + // callback when the IR or pass is not interesting + std::function HandleFiltered; + // callback when an ignored pass is encountered + std::function HandleIgnored; + // callback to compare the before and after representations of the IR + std::function Same; + + // stack of IRs before passes + std::vector BeforeStack; + // Is this the first IR seen? + bool InitialIR; +}; + +// A change printer based on the string representation of the IR as created +// by unwrapAndPrint. The string representation is stored in a std::string +// to preserve it as the IR changes in each pass. Note that the banner is +// included in this representation but it is massaged before reporting. +class IRChangePrinter : public ChangePrinter { +public: + IRChangePrinter(); + void registerCallbacks(PassInstrumentationCallbacks &PIC); + +protected: + raw_ostream &Out; +}; + /// This class provides an interface to register all the standard pass /// instrumentations and manages their state (if any). class StandardInstrumentations { @@ -80,6 +166,7 @@ PrintPassInstrumentation PrintPass; TimePassesHandler TimePasses; OptNoneInstrumentation OptNone; + IRChangePrinter PrintChangedIR; public: StandardInstrumentations(bool DebugLogging) : PrintPass(DebugLogging) {} Index: llvm/lib/Passes/StandardInstrumentations.cpp =================================================================== --- llvm/lib/Passes/StandardInstrumentations.cpp +++ llvm/lib/Passes/StandardInstrumentations.cpp @@ -218,167 +218,106 @@ llvm_unreachable("Unknown wrapped IR type"); } -// Base class for classes that report changes to the IR. -// It presents an interface for such classes and provides callbacks -// on various events as the new pass manager transforms the IR. -// It also provides filtering of information based on hidden options -// specifying which functions are interesting. -// Callbacks are made for the following events/queries: -// 1. The initial IR processed. -// 2. To get the representation of the IR (of type \p T). -// 3. When a pass does not change the IR. -// 4. When a pass changes the IR (given both before and after representations -// of type \p T). -// 5. When an IR is invalidated. -// 6. When a pass is run on an IR that is not interesting (based on options). -// 7. When a pass is ignored (pass manager or adapter pass). -// 8. To compare two IR representations (of type \p T). -template class ChangePrinter { -public: - // Not virtual as classes are expected to be referenced as derived classes. - ~ChangePrinter() { - assert(BeforeStack.empty() && "Problem with Change Printer stack."); - } +// Return true when this is a pass for which printing of changes is desired. +bool isIgnored(StringRef PassID) { + return PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"); +} - // Determine if this pass/IR is interesting and if so, save the IR - // otherwise it is left on the stack without data - void 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. - BeforeStack.emplace_back(); - - if (!isInteresting(IR, PassID)) - return; - // Is this the initial IR? - if (InitialIR) { - InitialIR = false; - HandleInitialIR(IR); - } +// Return true when this is a defined function for which printing +// of changes is desired. +bool isInterestingFunction(const Function &F) { + return !F.isDeclaration() && llvm::isFunctionInPrintList(F.getName()); +} - // Save the IR representation on the stack. - auto &Data = BeforeStack.back(); - GenerateIRRepresentation(IR, PassID, Data); - } - // Compare the IR from before the pass after the pass. - void handleIRAfterPass(Any IR, StringRef PassID) { - assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); - std::string Name; - - // unwrapModule has inconsistent handling of names for function IRs. - if (any_isa(IR)) { - const Function *F = any_cast(IR); - Name = formatv(" (function: {0})", F->getName()).str(); - } else { - if (auto UM = unwrapModule(IR)) - Name = UM->second; - } - if (Name == "") - Name = " (module)"; - - if (isIgnored(PassID)) - HandleIgnored(PassID, Name); - else if (!isInteresting(IR, PassID)) - HandleFiltered(PassID, Name); - else { - // Get the before rep from the stack - T &Before = BeforeStack.back(); - // Create the after rep - T After; - GenerateIRRepresentation(IR, PassID, After); - - // was there a change in IR? - if (Same(Before, After)) - OmitAfter(PassID, Name); - else - HandleAfter(Name, PassID, Before, After, IR); - } - BeforeStack.pop_back(); - } - // Handle the situation where a pass is invalidated. - void handleInvalidatedPass(StringRef PassID) { - assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); - - // Always flag it as invalidated as we cannot determine when - // a pass for a filtered function is invalidated since we do not - // get the IR in the callback. Also, the output is just alternate - // forms of the banner anyway. - HandleInvalidated(PassID); - BeforeStack.pop_back(); - } +// Return true when this is a pass for which printing of changes is desired. +bool isInterestingPass(StringRef PassID) { + if (isIgnored(PassID)) + return false; -protected: - ChangePrinter(std::function F1, - std::function F2, - std::function F3, - std::function - F4, - std::function F5, - std::function F6, - std::function F7, - std::function F8) - : HandleInitialIR(F1), GenerateIRRepresentation(F2), OmitAfter(F3), - HandleAfter(F4), HandleInvalidated(F5), HandleFiltered(F6), - HandleIgnored(F7), Same(F8), InitialIR(true) {} - -private: - // Return true when this is a pass on IR for which printing - // of changes is desired. - static bool isInteresting(Any IR, StringRef PassID) { - if (!isInterestingPass(PassID)) - return false; - if (any_isa(IR)) - return isInterestingFunction(*any_cast(IR)); - return true; - } + static std::unordered_set PrintPassNames(PrintPassesList.begin(), + PrintPassesList.end()); + return PrintPassNames.empty() || PrintPassNames.count(PassID.str()); +} - // Return true when this is a pass for which printing of changes is desired. - static bool isIgnored(StringRef PassID) { - return PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"); - } +// Return true when this is a pass on IR for which printing +// of changes is desired. +bool isInteresting(Any IR, StringRef PassID) { + if (!isInterestingPass(PassID)) + return false; + if (any_isa(IR)) + return isInterestingFunction(*any_cast(IR)); + return true; +} + +} // namespace - // Return true when this is a defined function for which printing - // of changes is desired. - static bool isInterestingFunction(const Function &F) { - return !F.isDeclaration() && llvm::isFunctionInPrintList(F.getName()); +template +void ChangePrinter::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. + BeforeStack.emplace_back(); + + if (!isInteresting(IR, PassID)) + return; + // Is this the initial IR? + if (InitialIR) { + InitialIR = false; + HandleInitialIR(IR); } - // Return true when this is a pass for which printing of changes is desired. - static bool isInterestingPass(StringRef PassID) { - if (isIgnored(PassID)) - return false; + // Save the IR representation on the stack. + auto &Data = BeforeStack.back(); + GenerateIRRepresentation(IR, PassID, Data); +} - static std::unordered_set PrintPassNames( - PrintPassesList.begin(), PrintPassesList.end()); - return PrintPassNames.empty() || PrintPassNames.count(PassID.str()); +template +void ChangePrinter::handleIRAfterPass(Any IR, StringRef PassID) { + assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); + std::string Name; + + // unwrapModule has inconsistent handling of names for function IRs. + if (any_isa(IR)) { + const Function *F = any_cast(IR); + Name = formatv(" (function: {0})", F->getName()).str(); + } else { + if (auto UM = unwrapModule(IR)) + Name = UM->second; + } + if (Name == "") + Name = " (module)"; + + if (isIgnored(PassID)) + HandleIgnored(PassID, Name); + else if (!isInteresting(IR, PassID)) + HandleFiltered(PassID, Name); + else { + // Get the before rep from the stack + T &Before = BeforeStack.back(); + // Create the after rep + T After; + GenerateIRRepresentation(IR, PassID, After); + + // was there a change in IR? + if (Same(Before, After)) + OmitAfter(PassID, Name); + else + HandleAfter(Name, PassID, Before, After, IR); } + BeforeStack.pop_back(); +} + +template +void ChangePrinter::handleInvalidatedPass(StringRef PassID) { + assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); - // callback on the first IR processed - std::function HandleInitialIR; - // callback before and after a pass to get the representation of the IR - std::function - GenerateIRRepresentation; - // callback when the pass is not iteresting - std::function OmitAfter; - // callback when interesting IR has changed - std::function - HandleAfter; - // callback when an interesting pass is invalidated - std::function HandleInvalidated; - // callback when the IR or pass is not interesting - std::function HandleFiltered; - // callback when an ignored pass is encountered - std::function HandleIgnored; - // callback to compare the before and after representations of the IR - std::function Same; - - // stack of IRs before passes - std::vector BeforeStack; - // Is this the first IR seen? - bool InitialIR; -}; + // Always flag it as invalidated as we cannot determine when + // a pass for a filtered function is invalidated since we do not + // get the IR in the callback. Also, the output is just alternate + // forms of the banner anyway. + HandleInvalidated(PassID); + BeforeStack.pop_back(); +} void handleInitialIR(Any IR, raw_ostream &Out) { StringRef Banner("*** IR Dump At Start: ***"); @@ -427,60 +366,46 @@ bool sameIR(std::string &S1, std::string &S2) { return S1.compare(S2) == 0; } -// A change printer based on the string representation of the IR as created -// by unwrapAndPrint. The string representation is stored in a std::string -// to preserve it as the IR changes in each pass. Note that the banner is -// included in this representation but it is massaged before reporting. -class IRChangePrinter : public ChangePrinter { -public: - IRChangePrinter(raw_ostream &OS) - : ChangePrinter( - [this](Any IR) -> void { ::handleInitialIR(IR, Out); }, - ::generateOutput, - [this](StringRef PassID, std::string &Name) -> void { - ::omitAfter(PassID, Name, Out); - }, - [this](std::string &Name, StringRef PassID, std::string &Before, - std::string &After, - Any IR) -> void { ::handleAfter(Name, After, Out); }, - [this](StringRef PassID) -> void { - ::handleInvalidated(PassID, Out); - }, - [this](StringRef PassID, std::string &Name) -> void { - ::handleFiltered(PassID, Name, Out); - }, - [this](StringRef PassID, std::string &Name) -> void { - ::handleIgnored(PassID, Name, Out); - }, - ::sameIR), - Out(OS) {} - -protected: - raw_ostream &Out; -}; - -void registerChangePrinters(PassInstrumentationCallbacks &PIC) { - if (PrintChanged) { - // Must be static as lifespan is across multiple callbacks. - // N.B. this may cause problems if the compiler becomes multi-threaded. - static IRChangePrinter ICP(dbgs()); - - PIC.registerBeforePassCallback([](StringRef P, Any IR) { - ICP.saveIRBeforePass(IR, P); - return true; - }); - PIC.registerAfterPassCallback( - [](StringRef P, Any IR, const PreservedAnalyses &) { - ICP.handleIRAfterPass(IR, P); - }); - PIC.registerAfterPassInvalidatedCallback( - [](StringRef P, const PreservedAnalyses &) { - ICP.handleInvalidatedPass(P); - }); - } -} +IRChangePrinter::IRChangePrinter() + : ChangePrinter( + [this](Any IR) -> void { ::handleInitialIR(IR, Out); }, + ::generateOutput, + [this](StringRef PassID, std::string &Name) -> void { + ::omitAfter(PassID, Name, Out); + }, + [this](std::string &Name, StringRef PassID, std::string &Before, + std::string &After, + Any IR) -> void { ::handleAfter(Name, After, Out); }, + [this](StringRef PassID) -> void { + ::handleInvalidated(PassID, Out); + }, + [this](StringRef PassID, std::string &Name) -> void { + ::handleFiltered(PassID, Name, Out); + }, + [this](StringRef PassID, std::string &Name) -> void { + ::handleIgnored(PassID, Name, Out); + }, + ::sameIR), + Out(dbgs()) {} + +void IRChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { + if (!PrintChanged) + return; -} // namespace + PIC.registerBeforePassCallback([this](StringRef P, Any IR) { + saveIRBeforePass(IR, P); + return true; + }); + + PIC.registerAfterPassCallback( + [this](StringRef P, Any IR, const PreservedAnalyses &) { + handleIRAfterPass(IR, P); + }); + PIC.registerAfterPassInvalidatedCallback( + [this](StringRef P, const PreservedAnalyses &) { + handleInvalidatedPass(P); + }); +} PrintIRInstrumentation::~PrintIRInstrumentation() { assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); @@ -635,5 +560,5 @@ PrintPass.registerCallbacks(PIC); TimePasses.registerCallbacks(PIC); OptNone.registerCallbacks(PIC); - registerChangePrinters(PIC); + PrintChangedIR.registerCallbacks(PIC); }