Home | History | Annotate | Download | only in opt
      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