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_H_ 16 #define SOURCE_OPT_PASS_H_ 17 18 #include <algorithm> 19 #include <map> 20 #include <unordered_map> 21 #include <unordered_set> 22 #include <utility> 23 24 #include "source/opt/basic_block.h" 25 #include "source/opt/def_use_manager.h" 26 #include "source/opt/ir_context.h" 27 #include "source/opt/module.h" 28 #include "spirv-tools/libspirv.hpp" 29 30 namespace spvtools { 31 namespace opt { 32 33 // Abstract class of a pass. All passes should implement this abstract class 34 // and all analysis and transformation is done via the Process() method. 35 class Pass { 36 public: 37 // The status of processing a module using a pass. 38 // 39 // The numbers for the cases are assigned to make sure that Failure & anything 40 // is Failure, SuccessWithChange & any success is SuccessWithChange. 41 enum class Status { 42 Failure = 0x00, 43 SuccessWithChange = 0x10, 44 SuccessWithoutChange = 0x11, 45 }; 46 47 using ProcessFunction = std::function<bool(Function*)>; 48 49 // Destructs the pass. 50 virtual ~Pass() = default; 51 52 // Returns a descriptive name for this pass. 53 // 54 // NOTE: When deriving a new pass class, make sure you make the name 55 // compatible with the corresponding spirv-opt command-line flag. For example, 56 // if you add the flag --my-pass to spirv-opt, make this function return 57 // "my-pass" (no leading hyphens). 58 virtual const char* name() const = 0; 59 60 // Sets the message consumer to the given |consumer|. |consumer| which will be 61 // invoked every time there is a message to be communicated to the outside. 62 void SetMessageConsumer(MessageConsumer c) { consumer_ = std::move(c); } 63 64 // Returns the reference to the message consumer for this pass. 65 const MessageConsumer& consumer() const { return consumer_; } 66 67 // Returns the def-use manager used for this pass. TODO(dnovillo): This should 68 // be handled by the pass manager. 69 analysis::DefUseManager* get_def_use_mgr() const { 70 return context()->get_def_use_mgr(); 71 } 72 73 analysis::DecorationManager* get_decoration_mgr() const { 74 return context()->get_decoration_mgr(); 75 } 76 77 FeatureManager* get_feature_mgr() const { 78 return context()->get_feature_mgr(); 79 } 80 81 // Returns a pointer to the current module for this pass. 82 Module* get_module() const { return context_->module(); } 83 84 // Sets the pointer to the current context for this pass. 85 void SetContextForTesting(IRContext* ctx) { context_ = ctx; } 86 87 // Returns a pointer to the current context for this pass. 88 IRContext* context() const { return context_; } 89 90 // Returns a pointer to the CFG for current module. 91 CFG* cfg() const { return context()->cfg(); } 92 93 // Run the pass on the given |module|. Returns Status::Failure if errors occur 94 // when processing. Returns the corresponding Status::Success if processing is 95 // successful to indicate whether changes are made to the module. If there 96 // were any changes it will also invalidate the analyses in the IRContext 97 // that are not preserved. 98 // 99 // It is an error if |Run| is called twice with the same instance of the pass. 100 // If this happens the return value will be |Failure|. 101 Status Run(IRContext* ctx); 102 103 // Returns the set of analyses that the pass is guaranteed to preserve. 104 virtual IRContext::Analysis GetPreservedAnalyses() { 105 return IRContext::kAnalysisNone; 106 } 107 108 // Return type id for |ptrInst|'s pointee 109 uint32_t GetPointeeTypeId(const Instruction* ptrInst) const; 110 111 protected: 112 // Constructs a new pass. 113 // 114 // The constructed instance will have an empty message consumer, which just 115 // ignores all messages from the library. Use SetMessageConsumer() to supply 116 // one if messages are of concern. 117 Pass(); 118 119 // Processes the given |module|. Returns Status::Failure if errors occur when 120 // processing. Returns the corresponding Status::Success if processing is 121 // succesful to indicate whether changes are made to the module. 122 virtual Status Process() = 0; 123 124 // Return the next available SSA id and increment it. 125 // TODO(1841): Handle id overflow. 126 uint32_t TakeNextId() { return context_->TakeNextId(); } 127 128 private: 129 MessageConsumer consumer_; // Message consumer. 130 131 // The context that this pass belongs to. 132 IRContext* context_; 133 134 // An instance of a pass can only be run once because it is too hard to 135 // enforce proper resetting of internal state for each instance. This member 136 // is used to check that we do not run the same instance twice. 137 bool already_run_; 138 }; 139 140 inline Pass::Status CombineStatus(Pass::Status a, Pass::Status b) { 141 return std::min(a, b); 142 } 143 144 } // namespace opt 145 } // namespace spvtools 146 147 #endif // SOURCE_OPT_PASS_H_ 148