#pragma once #include #include #include #include #include #include #include "pass.h" #include "sir/analyze/analysis.h" #include "sir/module.h" namespace codon { namespace ir { namespace transform { /// Utility class to run a series of passes. class PassManager { private: /// Manager for keys of passes. class KeyManager { private: /// mapping of raw key to number of occurences std::unordered_map keys; public: KeyManager() = default; /// Returns a unique'd key for a given raw key. /// Does so by appending ":" if the key /// has been seen. /// @param key the raw key /// @return the unique'd key std::string getUniqueKey(const std::string &key); }; /// Container for pass metadata. struct PassMetadata { /// pointer to the pass instance std::unique_ptr pass; /// vector of required analyses std::vector reqs; /// vector of invalidated analyses std::vector invalidates; PassMetadata() = default; PassMetadata(std::unique_ptr pass, std::vector reqs, std::vector invalidates) : pass(std::move(pass)), reqs(std::move(reqs)), invalidates(std::move(invalidates)) {} PassMetadata(PassMetadata &&) = default; PassMetadata &operator=(PassMetadata &&) = default; }; /// Container for analysis metadata. struct AnalysisMetadata { /// pointer to the analysis instance std::unique_ptr analysis; /// vector of required analyses std::vector reqs; /// vector of invalidated analyses std::vector invalidates; AnalysisMetadata() = default; AnalysisMetadata(std::unique_ptr analysis, std::vector reqs) : analysis(std::move(analysis)), reqs(std::move(reqs)) {} AnalysisMetadata(AnalysisMetadata &&) = default; AnalysisMetadata &operator=(AnalysisMetadata &&) = default; }; /// key manager to handle duplicate keys (i.e. passes being added twice) KeyManager km; /// map of keys to passes std::unordered_map passes; /// map of keys to analyses std::unordered_map analyses; /// reverse dependency map std::unordered_map> deps; /// execution order of passes std::vector executionOrder; /// map of valid analysis results std::unordered_map> results; /// passes to avoid registering std::vector disabled; public: /// PassManager initialization mode. enum Init { EMPTY, DEBUG, RELEASE, }; static const int PASS_IT_MAX; explicit PassManager(Init init, std::vector disabled = {}) : km(), passes(), analyses(), executionOrder(), results(), disabled(std::move(disabled)) { switch (init) { case Init::EMPTY: break; case Init::DEBUG: registerStandardPasses(true); break; case Init::RELEASE: registerStandardPasses(false); break; } } explicit PassManager(bool debug = false, std::vector disabled = {}) : PassManager(debug ? Init::DEBUG : Init::RELEASE, std::move(disabled)) {} /// Registers a pass and appends it to the execution order. /// @param pass the pass /// @param insertBefore insert pass before the pass with this given key /// @param reqs keys of passes that must be run before the current one /// @param invalidates keys of passes that are invalidated by the current one /// @return unique'd key for the added pass, or empty string if not added std::string registerPass(std::unique_ptr pass, const std::string &insertBefore = "", std::vector reqs = {}, std::vector invalidates = {}); /// Registers an analysis. /// @param analysis the analysis /// @param reqs keys of analyses that must be run before the current one /// @return unique'd key for the added analysis, or empty string if not added std::string registerAnalysis(std::unique_ptr analysis, std::vector reqs = {}); /// Run all passes. /// @param module the module void run(Module *module); /// Gets the result of a given analysis. /// @param key the (unique'd) analysis key /// @return the result analyze::Result *getAnalysisResult(const std::string &key) { auto it = results.find(key); return it != results.end() ? it->second.get() : nullptr; } /// Returns whether a given pass or analysis is disabled. /// @param key the (unique'd) pass or analysis key /// @return true if the pass or analysis is disabled bool isDisabled(const std::string &key) { return std::find(disabled.begin(), disabled.end(), key) != disabled.end(); } private: void runPass(Module *module, const std::string &name); void registerStandardPasses(bool debug = false); void runAnalysis(Module *module, const std::string &name); void invalidate(const std::string &key); }; } // namespace transform } // namespace ir } // namespace codon