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 { operatorHashTypePointer39 size_t operator()(const Type* type) const { 40 assert(type); 41 return type->HashValue(); 42 } 43 }; 44 struct HashTypeUniquePointer { operatorHashTypeUniquePointer45 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 { operatorCompareTypePointers57 bool operator()(const Type* lhs, const Type* rhs) const { 58 assert(lhs && rhs); 59 return lhs->IsSame(rhs); 60 } 61 }; 62 struct CompareTypeUniquePointers { operatorCompareTypeUniquePointers63 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. NumTypes()93 size_t NumTypes() const { return id_to_type_.size(); } 94 // Iterators for all types contained in this manager. begin()95 IdToTypeMap::const_iterator begin() const { return id_to_type_.cbegin(); } end()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, spv::StorageClass sc) const; 103 104 // Returns an id for a declaration representing |type|. Returns 0 if the type 105 // does not exists, and could not be generated. 106 // 107 // If |type| is registered, then the registered id is returned. Otherwise, 108 // this function recursively adds type and annotation instructions as 109 // necessary to fully define |type|. 110 uint32_t GetTypeInstruction(const Type* type); 111 112 // Find pointer to type and storage in module, return its resultId. If it is 113 // not found, a new type is created, and its id is returned. Returns 0 if the 114 // type could not be created. 115 uint32_t FindPointerToType(uint32_t type_id, spv::StorageClass storage_class); 116 117 // Registers |id| to |type|. 118 // 119 // If GetId(|type|) already returns a non-zero id, that mapping will be 120 // unchanged. 121 void RegisterType(uint32_t id, const Type& type); 122 123 // Return the registered type object that is the same as |type|. 124 Type* GetRegisteredType(const Type* type); 125 126 // Removes knowledge of |id| from the manager. 127 // 128 // If |id| is an ambiguous type the multiple ids may be registered to |id|'s 129 // type (e.g. %struct1 and %struct1 might hash to the same type). In that 130 // case, calling GetId() with |id|'s type will return another suitable id 131 // defining that type. 132 void RemoveId(uint32_t id); 133 134 // Returns the type of the member of |parent_type| that is identified by 135 // |access_chain|. The vector |access_chain| is a series of integers that are 136 // used to pick members as in the |OpCompositeExtract| instructions. If you 137 // want a member of an array, vector, or matrix that does not have a constant 138 // index, you can use 0 in that position. All elements have the same type. 139 const Type* GetMemberType(const Type* parent_type, 140 const std::vector<uint32_t>& access_chain); 141 142 // Attaches the decoration encoded in |inst| to |type|. Does nothing if the 143 // given instruction is not a decoration instruction. Assumes the target is 144 // |type| (e.g. should be called in loop of |type|'s decorations). 145 void AttachDecoration(const Instruction& inst, Type* type); 146 GetUIntType()147 Type* GetUIntType() { return GetIntType(32, false); } 148 GetUIntTypeId()149 uint32_t GetUIntTypeId() { return GetTypeInstruction(GetUIntType()); } 150 GetIntType(int32_t bitWidth,bool isSigned)151 Type* GetIntType(int32_t bitWidth, bool isSigned) { 152 Integer int_type(bitWidth, isSigned); 153 return GetRegisteredType(&int_type); 154 } 155 GetSIntType()156 Type* GetSIntType() { return GetIntType(32, true); } 157 GetSIntTypeId()158 uint32_t GetSIntTypeId() { return GetTypeInstruction(GetSIntType()); } 159 GetFloatType()160 Type* GetFloatType() { 161 Float float_type(32); 162 return GetRegisteredType(&float_type); 163 } 164 GetFloatTypeId()165 uint32_t GetFloatTypeId() { return GetTypeInstruction(GetFloatType()); } 166 GetDoubleType()167 Type* GetDoubleType() { 168 Float float_type(64); 169 return GetRegisteredType(&float_type); 170 } 171 GetDoubleTypeId()172 uint32_t GetDoubleTypeId() { return GetTypeInstruction(GetDoubleType()); } 173 GetUIntVectorType(uint32_t size)174 Type* GetUIntVectorType(uint32_t size) { 175 Vector vec_type(GetUIntType(), size); 176 return GetRegisteredType(&vec_type); 177 } 178 GetUIntVectorTypeId(uint32_t size)179 uint32_t GetUIntVectorTypeId(uint32_t size) { 180 return GetTypeInstruction(GetUIntVectorType(size)); 181 } 182 GetSIntVectorType(uint32_t size)183 Type* GetSIntVectorType(uint32_t size) { 184 Vector vec_type(GetSIntType(), size); 185 return GetRegisteredType(&vec_type); 186 } 187 GetSIntVectorTypeId(uint32_t size)188 uint32_t GetSIntVectorTypeId(uint32_t size) { 189 return GetTypeInstruction(GetSIntVectorType(size)); 190 } 191 GetFloatVectorType(uint32_t size)192 Type* GetFloatVectorType(uint32_t size) { 193 Vector vec_type(GetFloatType(), size); 194 return GetRegisteredType(&vec_type); 195 } 196 GetFloatVectorTypeId(uint32_t size)197 uint32_t GetFloatVectorTypeId(uint32_t size) { 198 return GetTypeInstruction(GetFloatVectorType(size)); 199 } 200 GetBoolType()201 Type* GetBoolType() { 202 Bool bool_type; 203 return GetRegisteredType(&bool_type); 204 } 205 GetBoolTypeId()206 uint32_t GetBoolTypeId() { return GetTypeInstruction(GetBoolType()); } 207 GetVoidType()208 Type* GetVoidType() { 209 Void void_type; 210 return GetRegisteredType(&void_type); 211 } 212 GetVoidTypeId()213 uint32_t GetVoidTypeId() { return GetTypeInstruction(GetVoidType()); } 214 215 private: 216 using TypeToIdMap = std::unordered_map<const Type*, uint32_t, HashTypePointer, 217 CompareTypePointers>; 218 using TypePool = 219 std::unordered_set<std::unique_ptr<Type>, HashTypeUniquePointer, 220 CompareTypeUniquePointers>; 221 222 class UnresolvedType { 223 public: UnresolvedType(uint32_t i,Type * t)224 UnresolvedType(uint32_t i, Type* t) : id_(i), type_(t) {} 225 UnresolvedType(const UnresolvedType&) = delete; UnresolvedType(UnresolvedType && that)226 UnresolvedType(UnresolvedType&& that) 227 : id_(that.id_), type_(std::move(that.type_)) {} 228 id()229 uint32_t id() { return id_; } type()230 Type* type() { return type_.get(); } ReleaseType()231 std::unique_ptr<Type>&& ReleaseType() { return std::move(type_); } ResetType(Type * t)232 void ResetType(Type* t) { type_.reset(t); } 233 234 private: 235 uint32_t id_; 236 std::unique_ptr<Type> type_; 237 }; 238 using IdToUnresolvedType = std::vector<UnresolvedType>; 239 240 // Analyzes the types and decorations on types in the given |module|. 241 void AnalyzeTypes(const Module& module); 242 context()243 IRContext* context() { return context_; } 244 245 // Attaches the decorations on |type| to |id|. 246 void AttachDecorations(uint32_t id, const Type* type); 247 248 // Create the annotation instruction. 249 // 250 // If |is_member| is false, an OpDecorate of |decoration| on |id| is created, 251 // otherwise an OpMemberDecorate is created at |element|. The annotation is 252 // registered with the DefUseManager and the DecorationManager. 253 void CreateDecoration(uint32_t id, const std::vector<uint32_t>& decoration, 254 bool is_member = false, uint32_t element = 0); 255 256 // Creates and returns a type from the given SPIR-V |inst|. Returns nullptr if 257 // the given instruction is not for defining a type. 258 Type* RecordIfTypeDefinition(const Instruction& inst); 259 260 // Returns an equivalent pointer to |type| built in terms of pointers owned by 261 // |type_pool_|. For example, if |type| is a vec3 of bool, it will be rebuilt 262 // replacing the bool subtype with one owned by |type_pool_|. 263 Type* RebuildType(const Type& type); 264 265 // Completes the incomplete type |type|, by replaces all references to 266 // ForwardPointer by the defining Pointer. 267 void ReplaceForwardPointers(Type* type); 268 269 // Replaces all references to |original_type| in |incomplete_types_| by 270 // |new_type|. 271 void ReplaceType(Type* new_type, Type* original_type); 272 273 const MessageConsumer& consumer_; // Message consumer. 274 IRContext* context_; 275 IdToTypeMap id_to_type_; // Mapping from ids to their type representations. 276 TypeToIdMap type_to_id_; // Mapping from types to their defining ids. 277 TypePool type_pool_; // Memory owner of type pointers. 278 IdToUnresolvedType incomplete_types_; // All incomplete types. Stored in an 279 // std::vector to make traversals 280 // deterministic. 281 282 IdToTypeMap id_to_incomplete_type_; // Maps ids to their type representations 283 // for incomplete types. 284 285 std::unordered_map<uint32_t, const Instruction*> id_to_constant_inst_; 286 }; 287 288 } // namespace analysis 289 } // namespace opt 290 } // namespace spvtools 291 292 #endif // SOURCE_OPT_TYPE_MANAGER_H_ 293