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