1 // Copyright (c) 2016 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SOURCE_OPT_PASS_MANAGER_H_ 16 #define SOURCE_OPT_PASS_MANAGER_H_ 17 18 #include <memory> 19 #include <ostream> 20 #include <utility> 21 #include <vector> 22 23 #include "source/opt/log.h" 24 #include "source/opt/module.h" 25 #include "source/opt/pass.h" 26 27 #include "source/opt/ir_context.h" 28 #include "spirv-tools/libspirv.hpp" 29 30 namespace spvtools { 31 namespace opt { 32 33 // The pass manager, responsible for tracking and running passes. 34 // Clients should first call AddPass() to add passes and then call Run() 35 // to run on a module. Passes are executed in the exact order of addition. 36 class PassManager { 37 public: 38 // Constructs a pass manager. 39 // 40 // The constructed instance will have an empty message consumer, which just 41 // ignores all messages from the library. Use SetMessageConsumer() to supply 42 // one if messages are of concern. 43 PassManager() 44 : consumer_(nullptr), 45 print_all_stream_(nullptr), 46 time_report_stream_(nullptr) {} 47 48 // Sets the message consumer to the given |consumer|. 49 void SetMessageConsumer(MessageConsumer c) { consumer_ = std::move(c); } 50 51 // Adds an externally constructed pass. 52 void AddPass(std::unique_ptr<Pass> pass); 53 // Uses the argument |args| to construct a pass instance of type |T|, and adds 54 // the pass instance to this pass manger. The pass added will use this pass 55 // manager's message consumer. 56 template <typename T, typename... Args> 57 void AddPass(Args&&... args); 58 59 // Returns the number of passes added. 60 uint32_t NumPasses() const; 61 // Returns a pointer to the |index|th pass added. 62 inline Pass* GetPass(uint32_t index) const; 63 64 // Returns the message consumer. 65 inline const MessageConsumer& consumer() const; 66 67 // Runs all passes on the given |module|. Returns Status::Failure if errors 68 // occur when processing using one of the registered passes. All passes 69 // registered after the error-reporting pass will be skipped. Returns the 70 // corresponding Status::Success if processing is succesful to indicate 71 // whether changes are made to the module. 72 // 73 // After running all the passes, they are removed from the list. 74 Pass::Status Run(IRContext* context); 75 76 // Sets the option to print the disassembly before each pass and after the 77 // last pass. Output is written to |out| if that is not null. No output 78 // is generated if |out| is null. 79 PassManager& SetPrintAll(std::ostream* out) { 80 print_all_stream_ = out; 81 return *this; 82 } 83 84 // Sets the option to print the resource utilization of each pass. Output is 85 // written to |out| if that is not null. No output is generated if |out| is 86 // null. 87 PassManager& SetTimeReport(std::ostream* out) { 88 time_report_stream_ = out; 89 return *this; 90 } 91 92 private: 93 // Consumer for messages. 94 MessageConsumer consumer_; 95 // A vector of passes. Order matters. 96 std::vector<std::unique_ptr<Pass>> passes_; 97 // The output stream to write disassembly to before each pass, and after 98 // the last pass. If this is null, no output is generated. 99 std::ostream* print_all_stream_; 100 // The output stream to write the resource utilization of each pass. If this 101 // is null, no output is generated. 102 std::ostream* time_report_stream_; 103 }; 104 105 inline void PassManager::AddPass(std::unique_ptr<Pass> pass) { 106 passes_.push_back(std::move(pass)); 107 } 108 109 template <typename T, typename... Args> 110 inline void PassManager::AddPass(Args&&... args) { 111 passes_.emplace_back(new T(std::forward<Args>(args)...)); 112 passes_.back()->SetMessageConsumer(consumer_); 113 } 114 115 inline uint32_t PassManager::NumPasses() const { 116 return static_cast<uint32_t>(passes_.size()); 117 } 118 119 inline Pass* PassManager::GetPass(uint32_t index) const { 120 SPIRV_ASSERT(consumer_, index < passes_.size(), "index out of bound"); 121 return passes_[index].get(); 122 } 123 124 inline const MessageConsumer& PassManager::consumer() const { 125 return consumer_; 126 } 127 128 } // namespace opt 129 } // namespace spvtools 130 131 #endif // SOURCE_OPT_PASS_MANAGER_H_ 132