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 LIBSPIRV_OPT_FOLD_SPEC_CONSTANT_OP_AND_COMPOSITE_PASS_H_
     16 #define LIBSPIRV_OPT_FOLD_SPEC_CONSTANT_OP_AND_COMPOSITE_PASS_H_
     17 
     18 #include <memory>
     19 #include <unordered_map>
     20 #include <vector>
     21 
     22 #include "constants.h"
     23 #include "def_use_manager.h"
     24 #include "module.h"
     25 #include "pass.h"
     26 #include "type_manager.h"
     27 
     28 namespace spvtools {
     29 namespace opt {
     30 
     31 // See optimizer.hpp for documentation.
     32 class FoldSpecConstantOpAndCompositePass : public Pass {
     33  public:
     34   FoldSpecConstantOpAndCompositePass();
     35 
     36   const char* name() const override { return "fold-spec-const-op-composite"; }
     37 
     38   Status Process(ir::Module* module) override;
     39 
     40  private:
     41   // Initializes the type manager, def-use manager and get the maximal id used
     42   // in the module.
     43   void Initialize(ir::Module* module);
     44 
     45   // The real entry of processing. Iterates through the types-constants-globals
     46   // section of the given module, finds the Spec Constants defined with
     47   // OpSpecConstantOp and OpSpecConstantComposite instructions. If the result
     48   // value of those spec constants can be folded, fold them to their
     49   // corresponding normal constants.
     50   Status ProcessImpl(ir::Module*);
     51 
     52   // Processes the OpSpecConstantOp instruction pointed by the given
     53   // instruction iterator, folds it to normal constants if possible. Returns
     54   // true if the spec constant is folded to normal constants. New instructions
     55   // will be inserted before the OpSpecConstantOp instruction pointed by the
     56   // instruction iterator. The instruction iterator, which is passed by
     57   // pointer, will still point to the original OpSpecConstantOp instruction. If
     58   // folding is done successfully, the original OpSpecConstantOp instruction
     59   // will be changed to Nop and new folded instruction will be inserted before
     60   // it.
     61   bool ProcessOpSpecConstantOp(ir::Module::inst_iterator* pos);
     62 
     63   // Try to fold the OpSpecConstantOp CompositeExtract instruction pointed by
     64   // the given instruction iterator to a normal constant defining instruction.
     65   // Returns the pointer to the new constant defining instruction if succeeded.
     66   // Otherwise returns nullptr.
     67   ir::Instruction* DoCompositeExtract(ir::Module::inst_iterator* inst_iter_ptr);
     68 
     69   // Try to fold the OpSpecConstantOp VectorShuffle instruction pointed by the
     70   // given instruction iterator to a normal constant defining instruction.
     71   // Returns the pointer to the new constant defining instruction if succeeded.
     72   // Otherwise return nullptr.
     73   ir::Instruction* DoVectorShuffle(ir::Module::inst_iterator* inst_iter_ptr);
     74 
     75   // Try to fold the OpSpecConstantOp <component wise operations> instruction
     76   // pointed by the given instruction iterator to a normal constant defining
     77   // instruction. Returns the pointer to the new constant defining instruction
     78   // if succeeded, otherwise return nullptr.
     79   ir::Instruction* DoComponentWiseOperation(
     80       ir::Module::inst_iterator* inst_iter_ptr);
     81 
     82   // Creates a constant defining instruction for the given Constant instance
     83   // and inserts the instruction at the position specified by the given
     84   // instruction iterator. Returns a pointer to the created instruction if
     85   // succeeded, otherwise returns a null pointer. The instruction iterator
     86   // points to the same instruction before and after the insertion. This is the
     87   // only method that actually manages id creation/assignment and instruction
     88   // creation/insertion for a new Constant instance.
     89   ir::Instruction* BuildInstructionAndAddToModule(
     90       std::unique_ptr<analysis::Constant> c, ir::Module::inst_iterator* pos);
     91 
     92   // Creates a Constant instance to hold the constant value of the given
     93   // instruction. If the given instruction defines a normal constants whose
     94   // value is already known in the module, returns the unique pointer to the
     95   // created Constant instance. Otherwise does not create anything and returns a
     96   // nullptr.
     97   std::unique_ptr<analysis::Constant> CreateConstFromInst(
     98       ir::Instruction* inst);
     99 
    100   // Creates a Constant instance with the given type and a vector of constant
    101   // defining words. Returns an unique pointer to the created Constant instance
    102   // if the Constant instance can be created successfully. To create scalar
    103   // type constants, the vector should contain the constant value in 32 bit
    104   // words and the given type must be of type Bool, Integer or Float. To create
    105   // composite type constants, the vector should contain the component ids, and
    106   // those component ids should have been recorded before as Normal Constants.
    107   // And the given type must be of type Struct, Vector or Array. When creating
    108   // VectorType Constant instance, the components must be scalars of the same
    109   // type, either Bool, Integer or Float. If any of the rules above failed, the
    110   // creation will fail and nullptr will be returned. If the vector is empty,
    111   // a NullConstant instance will be created with the given type.
    112   std::unique_ptr<analysis::Constant> CreateConst(
    113       const analysis::Type* type,
    114       const std::vector<uint32_t>& literal_words_or_ids);
    115 
    116   // Creates an instruction with the given result id to declare a constant
    117   // represented by the given Constant instance. Returns an unique pointer to
    118   // the created instruction if the instruction can be created successfully.
    119   // Otherwise, returns a null pointer.
    120   std::unique_ptr<ir::Instruction> CreateInstruction(uint32_t result_id,
    121                                                      analysis::Constant* c);
    122 
    123   // Creates an OpConstantComposite instruction with the given result id and
    124   // the CompositeConst instance which represents a composite constant. Returns
    125   // an unique pointer to the created instruction if succeeded. Otherwise
    126   // returns a null pointer.
    127   std::unique_ptr<ir::Instruction> CreateCompositeInstruction(
    128       uint32_t result_id, analysis::CompositeConstant* cc);
    129 
    130   // A helper function to get the collected normal constant with the given id.
    131   // Returns the pointer to the Constant instance in case it is found.
    132   // Otherwise, returns null pointer.
    133   analysis::Constant* FindRecordedConst(uint32_t id);
    134   // A helper function to get the id of a collected constant with the pointer
    135   // to the Constant instance. Returns 0 in case the constant is not found.
    136   uint32_t FindRecordedConst(const analysis::Constant* c);
    137 
    138   // A helper function to get a vector of Constant instances with the specified
    139   // ids. If can not find the Constant instance for any one of the ids, returns
    140   // an empty vector.
    141   std::vector<const analysis::Constant*> GetConstsFromIds(
    142       const std::vector<uint32_t>& ids);
    143 
    144   // A helper function to get the result type of the given instrution. Returns
    145   // nullptr if the instruction does not have a type id (type id is 0).
    146   analysis::Type* GetType(const ir::Instruction* inst) {
    147     return type_mgr_->GetType(inst->type_id());
    148   }
    149 
    150   // The maximum used ID.
    151   uint32_t max_id_;
    152   // A pointer to the module under process.
    153   ir::Module* module_;
    154   // DefUse manager
    155   std::unique_ptr<analysis::DefUseManager> def_use_mgr_;
    156   // Type manager
    157   std::unique_ptr<analysis::TypeManager> type_mgr_;
    158 
    159   // A mapping from the result ids of Normal Constants to their
    160   // analysis::Constant instances. All Normal Constants in the module, either
    161   // existing ones before optimization or the newly generated ones, should have
    162   // their Constant instance stored and their result id registered in this map.
    163   std::unordered_map<uint32_t, std::unique_ptr<analysis::Constant>>
    164       id_to_const_val_;
    165   // A mapping from the analsis::Constant instance of Normal Contants to their
    166   // result id in the module. This is a mirror map of id_to_const_val_. All
    167   // Normal Constants that defining instructions in the module should have
    168   // their analysis::Constant and their result id registered here.
    169   std::unordered_map<const analysis::Constant*, uint32_t> const_val_to_id_;
    170 };
    171 
    172 }  // namespace opt
    173 }  // namespace spvtools
    174 
    175 #endif  // LIBSPIRV_OPT_FOLD_SPEC_CONSTANT_OP_AND_COMPOSITE_PASS_H_
    176