• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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