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_TYPE_MANAGER_H_ 16 #define SOURCE_OPT_TYPE_MANAGER_H_ 17 18 #include <memory> 19 #include <unordered_map> 20 #include <unordered_set> 21 #include <utility> 22 #include <vector> 23 24 #include "source/opt/module.h" 25 #include "source/opt/types.h" 26 #include "spirv-tools/libspirv.hpp" 27 28 namespace spvtools { 29 namespace opt { 30 31 class IRContext; 32 33 namespace analysis { 34 35 // Hashing functor. 36 // 37 // All type pointers must be non-null. 38 struct HashTypePointer { 39 size_t operator()(const Type* type) const { 40 assert(type); 41 return type->HashValue(); 42 } 43 }; 44 struct HashTypeUniquePointer { 45 size_t operator()(const std::unique_ptr<Type>& type) const { 46 assert(type); 47 return type->HashValue(); 48 } 49 }; 50 51 // Equality functor. 52 // 53 // Checks if two types pointers are the same type. 54 // 55 // All type pointers must be non-null. 56 struct CompareTypePointers { 57 bool operator()(const Type* lhs, const Type* rhs) const { 58 assert(lhs && rhs); 59 return lhs->IsSame(rhs); 60 } 61 }; 62 struct CompareTypeUniquePointers { 63 bool operator()(const std::unique_ptr<Type>& lhs, 64 const std::unique_ptr<Type>& rhs) const { 65 assert(lhs && rhs); 66 return lhs->IsSame(rhs.get()); 67 } 68 }; 69 70 // A class for managing the SPIR-V type hierarchy. 71 class TypeManager { 72 public: 73 using IdToTypeMap = std::unordered_map<uint32_t, Type*>; 74 75 // Constructs a type manager from the given |module|. All internal messages 76 // will be communicated to the outside via the given message |consumer|. 77 // This instance only keeps a reference to the |consumer|, so the |consumer| 78 // should outlive this instance. 79 TypeManager(const MessageConsumer& consumer, IRContext* c); 80 81 TypeManager(const TypeManager&) = delete; 82 TypeManager(TypeManager&&) = delete; 83 TypeManager& operator=(const TypeManager&) = delete; 84 TypeManager& operator=(TypeManager&&) = delete; 85 86 // Returns the type for the given type |id|. Returns nullptr if the given |id| 87 // does not define a type. 88 Type* GetType(uint32_t id) const; 89 // Returns the id for the given |type|. Returns 0 if can not find the given 90 // |type|. 91 uint32_t GetId(const Type* type) const; 92 // Returns the number of types hold in this manager. 93 size_t NumTypes() const { return id_to_type_.size(); } 94 // Iterators for all types contained in this manager. 95 IdToTypeMap::const_iterator begin() const { return id_to_type_.cbegin(); } 96 IdToTypeMap::const_iterator end() const { return id_to_type_.cend(); } 97 98 // Returns a pair of the type and pointer to the type in |sc|. 99 // 100 // |id| must be a registered type. 101 std::pair<Type*, std::unique_ptr<Pointer>> GetTypeAndPointerType( 102 uint32_t id, SpvStorageClass sc) const; 103 104 // Returns an id for a declaration representing |type|. 105 // 106 // If |type| is registered, then the registered id is returned. Otherwise, 107 // this function recursively adds type and annotation instructions as 108 // necessary to fully define |type|. 109 uint32_t GetTypeInstruction(const Type* type); 110 111 // Find pointer to type and storage in module, return its resultId. If it is 112 // not found, a new type is created, and its id is returned. 113 uint32_t FindPointerToType(uint32_t type_id, SpvStorageClass storage_class); 114 115 // Registers |id| to |type|. 116 // 117 // If GetId(|type|) already returns a non-zero id, that mapping will be 118 // unchanged. 119 void RegisterType(uint32_t id, const Type& type); 120 121 Type* GetRegisteredType(const Type* type); 122 123 // Removes knowledge of |id| from the manager. 124 // 125 // If |id| is an ambiguous type the multiple ids may be registered to |id|'s 126 // type (e.g. %struct1 and %struct1 might hash to the same type). In that 127 // case, calling GetId() with |id|'s type will return another suitable id 128 // defining that type. 129 void RemoveId(uint32_t id); 130 131 // Returns the type of the member of |parent_type| that is identified by 132 // |access_chain|. The vector |access_chain| is a series of integers that are 133 // used to pick members as in the |OpCompositeExtract| instructions. If you 134 // want a member of an array, vector, or matrix that does not have a constant 135 // index, you can use 0 in that position. All elements have the same type. 136 const Type* GetMemberType(const Type* parent_type, 137 const std::vector<uint32_t>& access_chain); 138 139 private: 140 using TypeToIdMap = std::unordered_map<const Type*, uint32_t, HashTypePointer, 141 CompareTypePointers>; 142 using TypePool = 143 std::unordered_set<std::unique_ptr<Type>, HashTypeUniquePointer, 144 CompareTypeUniquePointers>; 145 146 class UnresolvedType { 147 public: 148 UnresolvedType(uint32_t i, Type* t) : id_(i), type_(t) {} 149 UnresolvedType(const UnresolvedType&) = delete; 150 UnresolvedType(UnresolvedType&& that) 151 : id_(that.id_), type_(std::move(that.type_)) {} 152 153 uint32_t id() { return id_; } 154 Type* type() { return type_.get(); } 155 std::unique_ptr<Type>&& ReleaseType() { return std::move(type_); } 156 void ResetType(Type* t) { type_.reset(t); } 157 158 private: 159 uint32_t id_; 160 std::unique_ptr<Type> type_; 161 }; 162 using IdToUnresolvedType = std::vector<UnresolvedType>; 163 164 // Analyzes the types and decorations on types in the given |module|. 165 void AnalyzeTypes(const Module& module); 166 167 IRContext* context() { return context_; } 168 169 // Attaches the decorations on |type| to |id|. 170 void AttachDecorations(uint32_t id, const Type* type); 171 172 // Create the annotation instruction. 173 // 174 // If |element| is zero, an OpDecorate is created, other an OpMemberDecorate 175 // is created. The annotation is registered with the DefUseManager and the 176 // DecorationManager. 177 void CreateDecoration(uint32_t id, const std::vector<uint32_t>& decoration, 178 uint32_t element = 0); 179 180 // Creates and returns a type from the given SPIR-V |inst|. Returns nullptr if 181 // the given instruction is not for defining a type. 182 Type* RecordIfTypeDefinition(const Instruction& inst); 183 // Attaches the decoration encoded in |inst| to |type|. Does nothing if the 184 // given instruction is not a decoration instruction. Assumes the target is 185 // |type| (e.g. should be called in loop of |type|'s decorations). 186 void AttachDecoration(const Instruction& inst, Type* type); 187 188 // Returns an equivalent pointer to |type| built in terms of pointers owned by 189 // |type_pool_|. For example, if |type| is a vec3 of bool, it will be rebuilt 190 // replacing the bool subtype with one owned by |type_pool_|. 191 Type* RebuildType(const Type& type); 192 193 // Completes the incomplete type |type|, by replaces all references to 194 // ForwardPointer by the defining Pointer. 195 void ReplaceForwardPointers(Type* type); 196 197 // Replaces all references to |original_type| in |incomplete_types_| by 198 // |new_type|. 199 void ReplaceType(Type* new_type, Type* original_type); 200 201 const MessageConsumer& consumer_; // Message consumer. 202 IRContext* context_; 203 IdToTypeMap id_to_type_; // Mapping from ids to their type representations. 204 TypeToIdMap type_to_id_; // Mapping from types to their defining ids. 205 TypePool type_pool_; // Memory owner of type pointers. 206 IdToUnresolvedType incomplete_types_; // All incomplete types. Stored in an 207 // std::vector to make traversals 208 // deterministic. 209 210 IdToTypeMap id_to_incomplete_type_; // Maps ids to their type representations 211 // for incomplete types. 212 }; 213 214 } // namespace analysis 215 } // namespace opt 216 } // namespace spvtools 217 218 #endif // SOURCE_OPT_TYPE_MANAGER_H_ 219