|  | // Copyright (c) 2016 Google Inc. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #ifndef SOURCE_OPT_PASS_H_ | 
|  | #define SOURCE_OPT_PASS_H_ | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <map> | 
|  | #include <unordered_map> | 
|  | #include <unordered_set> | 
|  | #include <utility> | 
|  |  | 
|  | #include "source/opt/basic_block.h" | 
|  | #include "source/opt/def_use_manager.h" | 
|  | #include "source/opt/ir_context.h" | 
|  | #include "source/opt/module.h" | 
|  | #include "spirv-tools/libspirv.hpp" | 
|  | #include "types.h" | 
|  |  | 
|  | namespace spvtools { | 
|  | namespace opt { | 
|  |  | 
|  | // Abstract class of a pass. All passes should implement this abstract class | 
|  | // and all analysis and transformation is done via the Process() method. | 
|  | class Pass { | 
|  | public: | 
|  | // The status of processing a module using a pass. | 
|  | // | 
|  | // The numbers for the cases are assigned to make sure that Failure & anything | 
|  | // is Failure, SuccessWithChange & any success is SuccessWithChange. | 
|  | enum class Status { | 
|  | Failure = 0x00, | 
|  | SuccessWithChange = 0x10, | 
|  | SuccessWithoutChange = 0x11, | 
|  | }; | 
|  |  | 
|  | using ProcessFunction = std::function<bool(Function*)>; | 
|  |  | 
|  | // Destructs the pass. | 
|  | virtual ~Pass() = default; | 
|  |  | 
|  | // Returns a descriptive name for this pass. | 
|  | // | 
|  | // NOTE: When deriving a new pass class, make sure you make the name | 
|  | // compatible with the corresponding spirv-opt command-line flag. For example, | 
|  | // if you add the flag --my-pass to spirv-opt, make this function return | 
|  | // "my-pass" (no leading hyphens). | 
|  | virtual const char* name() const = 0; | 
|  |  | 
|  | // Sets the message consumer to the given |consumer|. |consumer| which will be | 
|  | // invoked every time there is a message to be communicated to the outside. | 
|  | void SetMessageConsumer(MessageConsumer c) { consumer_ = std::move(c); } | 
|  |  | 
|  | // Returns the reference to the message consumer for this pass. | 
|  | const MessageConsumer& consumer() const { return consumer_; } | 
|  |  | 
|  | // Returns the def-use manager used for this pass. TODO(dnovillo): This should | 
|  | // be handled by the pass manager. | 
|  | analysis::DefUseManager* get_def_use_mgr() const { | 
|  | return context()->get_def_use_mgr(); | 
|  | } | 
|  |  | 
|  | analysis::DecorationManager* get_decoration_mgr() const { | 
|  | return context()->get_decoration_mgr(); | 
|  | } | 
|  |  | 
|  | FeatureManager* get_feature_mgr() const { | 
|  | return context()->get_feature_mgr(); | 
|  | } | 
|  |  | 
|  | // Returns a pointer to the current module for this pass. | 
|  | Module* get_module() const { return context_->module(); } | 
|  |  | 
|  | // Sets the pointer to the current context for this pass. | 
|  | void SetContextForTesting(IRContext* ctx) { context_ = ctx; } | 
|  |  | 
|  | // Returns a pointer to the current context for this pass. | 
|  | IRContext* context() const { return context_; } | 
|  |  | 
|  | // Returns a pointer to the CFG for current module. | 
|  | CFG* cfg() const { return context()->cfg(); } | 
|  |  | 
|  | // Run the pass on the given |module|. Returns Status::Failure if errors occur | 
|  | // when processing. Returns the corresponding Status::Success if processing is | 
|  | // successful to indicate whether changes are made to the module.  If there | 
|  | // were any changes it will also invalidate the analyses in the IRContext | 
|  | // that are not preserved. | 
|  | // | 
|  | // It is an error if |Run| is called twice with the same instance of the pass. | 
|  | // If this happens the return value will be |Failure|. | 
|  | Status Run(IRContext* ctx); | 
|  |  | 
|  | // Returns the set of analyses that the pass is guaranteed to preserve. | 
|  | virtual IRContext::Analysis GetPreservedAnalyses() { | 
|  | return IRContext::kAnalysisNone; | 
|  | } | 
|  |  | 
|  | // Return type id for |ptrInst|'s pointee | 
|  | uint32_t GetPointeeTypeId(const Instruction* ptrInst) const; | 
|  |  | 
|  | // Return base type of |ty_id| type | 
|  | Instruction* GetBaseType(uint32_t ty_id); | 
|  |  | 
|  | // Return true if |inst| returns scalar, vector or matrix type with base | 
|  | // float and |width| | 
|  | bool IsFloat(uint32_t ty_id, uint32_t width); | 
|  |  | 
|  | // Return the id of OpConstantNull of type |type_id|. Create if necessary. | 
|  | uint32_t GetNullId(uint32_t type_id); | 
|  |  | 
|  | protected: | 
|  | // Constructs a new pass. | 
|  | // | 
|  | // The constructed instance will have an empty message consumer, which just | 
|  | // ignores all messages from the library. Use SetMessageConsumer() to supply | 
|  | // one if messages are of concern. | 
|  | Pass(); | 
|  |  | 
|  | // Processes the given |module|. Returns Status::Failure if errors occur when | 
|  | // processing. Returns the corresponding Status::Success if processing is | 
|  | // succesful to indicate whether changes are made to the module. | 
|  | virtual Status Process() = 0; | 
|  |  | 
|  | // Return the next available SSA id and increment it. | 
|  | // TODO(1841): Handle id overflow. | 
|  | uint32_t TakeNextId() { return context_->TakeNextId(); } | 
|  |  | 
|  | // Returns the id whose value is the same as |object_to_copy| except its type | 
|  | // is |new_type_id|.  Any instructions needed to generate this value will be | 
|  | // inserted before |insertion_position|. | 
|  | uint32_t GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, | 
|  | Instruction* insertion_position); | 
|  |  | 
|  | private: | 
|  | MessageConsumer consumer_;  // Message consumer. | 
|  |  | 
|  | // The context that this pass belongs to. | 
|  | IRContext* context_; | 
|  |  | 
|  | // An instance of a pass can only be run once because it is too hard to | 
|  | // enforce proper resetting of internal state for each instance.  This member | 
|  | // is used to check that we do not run the same instance twice. | 
|  | bool already_run_; | 
|  | }; | 
|  |  | 
|  | inline Pass::Status CombineStatus(Pass::Status a, Pass::Status b) { | 
|  | return std::min(a, b); | 
|  | } | 
|  |  | 
|  | }  // namespace opt | 
|  | }  // namespace spvtools | 
|  |  | 
|  | #endif  // SOURCE_OPT_PASS_H_ |