• 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_CONSTANTS_H_
16 #define SOURCE_OPT_CONSTANTS_H_
17 
18 #include <cinttypes>
19 #include <map>
20 #include <memory>
21 #include <unordered_map>
22 #include <unordered_set>
23 #include <utility>
24 #include <vector>
25 
26 #include "source/opt/module.h"
27 #include "source/opt/type_manager.h"
28 #include "source/opt/types.h"
29 #include "source/util/hex_float.h"
30 #include "source/util/make_unique.h"
31 
32 namespace spvtools {
33 namespace opt {
34 
35 class IRContext;
36 
37 namespace analysis {
38 
39 // Class hierarchy to represent the normal constants defined through
40 // OpConstantTrue, OpConstantFalse, OpConstant, OpConstantNull and
41 // OpConstantComposite instructions.
42 // TODO(qining): Add class for constants defined with OpConstantSampler.
43 class Constant;
44 class ScalarConstant;
45 class IntConstant;
46 class FloatConstant;
47 class BoolConstant;
48 class CompositeConstant;
49 class StructConstant;
50 class VectorConstant;
51 class MatrixConstant;
52 class ArrayConstant;
53 class NullConstant;
54 class ConstantManager;
55 
56 // Abstract class for a SPIR-V constant. It has a bunch of As<subclass> methods,
57 // which is used as a way to probe the actual <subclass>
58 class Constant {
59  public:
60   Constant() = delete;
~Constant()61   virtual ~Constant() {}
62 
63   // Make a deep copy of this constant.
64   virtual std::unique_ptr<Constant> Copy() const = 0;
65 
66   // reflections
AsScalarConstant()67   virtual ScalarConstant* AsScalarConstant() { return nullptr; }
AsIntConstant()68   virtual IntConstant* AsIntConstant() { return nullptr; }
AsFloatConstant()69   virtual FloatConstant* AsFloatConstant() { return nullptr; }
AsBoolConstant()70   virtual BoolConstant* AsBoolConstant() { return nullptr; }
AsCompositeConstant()71   virtual CompositeConstant* AsCompositeConstant() { return nullptr; }
AsStructConstant()72   virtual StructConstant* AsStructConstant() { return nullptr; }
AsVectorConstant()73   virtual VectorConstant* AsVectorConstant() { return nullptr; }
AsMatrixConstant()74   virtual MatrixConstant* AsMatrixConstant() { return nullptr; }
AsArrayConstant()75   virtual ArrayConstant* AsArrayConstant() { return nullptr; }
AsNullConstant()76   virtual NullConstant* AsNullConstant() { return nullptr; }
77 
AsScalarConstant()78   virtual const ScalarConstant* AsScalarConstant() const { return nullptr; }
AsIntConstant()79   virtual const IntConstant* AsIntConstant() const { return nullptr; }
AsFloatConstant()80   virtual const FloatConstant* AsFloatConstant() const { return nullptr; }
AsBoolConstant()81   virtual const BoolConstant* AsBoolConstant() const { return nullptr; }
AsCompositeConstant()82   virtual const CompositeConstant* AsCompositeConstant() const {
83     return nullptr;
84   }
AsStructConstant()85   virtual const StructConstant* AsStructConstant() const { return nullptr; }
AsVectorConstant()86   virtual const VectorConstant* AsVectorConstant() const { return nullptr; }
AsMatrixConstant()87   virtual const MatrixConstant* AsMatrixConstant() const { return nullptr; }
AsArrayConstant()88   virtual const ArrayConstant* AsArrayConstant() const { return nullptr; }
AsNullConstant()89   virtual const NullConstant* AsNullConstant() const { return nullptr; }
90 
91   // Returns the float representation of the constant. Must be a 32 bit
92   // Float type.
93   float GetFloat() const;
94 
95   // Returns the double representation of the constant. Must be a 64 bit
96   // Float type.
97   double GetDouble() const;
98 
99   // Returns the double representation of the constant. Must be a 32-bit or
100   // 64-bit Float type.
101   double GetValueAsDouble() const;
102 
103   // Returns uint32_t representation of the constant. Must be a 32 bit
104   // Integer type.
105   uint32_t GetU32() const;
106 
107   // Returns uint64_t representation of the constant. Must be a 64 bit
108   // Integer type.
109   uint64_t GetU64() const;
110 
111   // Returns int32_t representation of the constant. Must be a 32 bit
112   // Integer type.
113   int32_t GetS32() const;
114 
115   // Returns int64_t representation of the constant. Must be a 64 bit
116   // Integer type.
117   int64_t GetS64() const;
118 
119   // Returns true if the constant is a zero or a composite containing 0s.
IsZero()120   virtual bool IsZero() const { return false; }
121 
type()122   const Type* type() const { return type_; }
123 
124   // Returns an std::vector containing the elements of |constant|.  The type of
125   // |constant| must be |Vector|.
126   std::vector<const Constant*> GetVectorComponents(
127       ConstantManager* const_mgr) const;
128 
129  protected:
Constant(const Type * ty)130   Constant(const Type* ty) : type_(ty) {}
131 
132   // The type of this constant.
133   const Type* type_;
134 };
135 
136 // Abstract class for scalar type constants.
137 class ScalarConstant : public Constant {
138  public:
139   ScalarConstant() = delete;
AsScalarConstant()140   ScalarConstant* AsScalarConstant() override { return this; }
AsScalarConstant()141   const ScalarConstant* AsScalarConstant() const override { return this; }
142 
143   // Returns a const reference of the value of this constant in 32-bit words.
words()144   virtual const std::vector<uint32_t>& words() const { return words_; }
145 
146   // Returns true if the value is zero.
IsZero()147   bool IsZero() const override {
148     bool is_zero = true;
149     for (uint32_t v : words()) {
150       if (v != 0) {
151         is_zero = false;
152         break;
153       }
154     }
155     return is_zero;
156   }
157 
158  protected:
ScalarConstant(const Type * ty,const std::vector<uint32_t> & w)159   ScalarConstant(const Type* ty, const std::vector<uint32_t>& w)
160       : Constant(ty), words_(w) {}
ScalarConstant(const Type * ty,std::vector<uint32_t> && w)161   ScalarConstant(const Type* ty, std::vector<uint32_t>&& w)
162       : Constant(ty), words_(std::move(w)) {}
163   std::vector<uint32_t> words_;
164 };
165 
166 // Integer type constant.
167 class IntConstant : public ScalarConstant {
168  public:
IntConstant(const Integer * ty,const std::vector<uint32_t> & w)169   IntConstant(const Integer* ty, const std::vector<uint32_t>& w)
170       : ScalarConstant(ty, w) {}
IntConstant(const Integer * ty,std::vector<uint32_t> && w)171   IntConstant(const Integer* ty, std::vector<uint32_t>&& w)
172       : ScalarConstant(ty, std::move(w)) {}
173 
AsIntConstant()174   IntConstant* AsIntConstant() override { return this; }
AsIntConstant()175   const IntConstant* AsIntConstant() const override { return this; }
176 
GetS32BitValue()177   int32_t GetS32BitValue() const {
178     // Relies on signed values smaller than 32-bit being sign extended.  See
179     // section 2.2.1 of the SPIR-V spec.
180     assert(words().size() == 1);
181     return words()[0];
182   }
183 
GetU32BitValue()184   uint32_t GetU32BitValue() const {
185     // Relies on unsigned values smaller than 32-bit being zero extended.  See
186     // section 2.2.1 of the SPIR-V spec.
187     assert(words().size() == 1);
188     return words()[0];
189   }
190 
GetS64BitValue()191   int64_t GetS64BitValue() const {
192     // Relies on unsigned values smaller than 64-bit being sign extended.  See
193     // section 2.2.1 of the SPIR-V spec.
194     assert(words().size() == 2);
195     return static_cast<uint64_t>(words()[1]) << 32 |
196            static_cast<uint64_t>(words()[0]);
197   }
198 
GetU64BitValue()199   uint64_t GetU64BitValue() const {
200     // Relies on unsigned values smaller than 64-bit being zero extended.  See
201     // section 2.2.1 of the SPIR-V spec.
202     assert(words().size() == 2);
203     return static_cast<uint64_t>(words()[1]) << 32 |
204            static_cast<uint64_t>(words()[0]);
205   }
206 
207   // Make a copy of this IntConstant instance.
CopyIntConstant()208   std::unique_ptr<IntConstant> CopyIntConstant() const {
209     return MakeUnique<IntConstant>(type_->AsInteger(), words_);
210   }
Copy()211   std::unique_ptr<Constant> Copy() const override {
212     return std::unique_ptr<Constant>(CopyIntConstant().release());
213   }
214 };
215 
216 // Float type constant.
217 class FloatConstant : public ScalarConstant {
218  public:
FloatConstant(const Float * ty,const std::vector<uint32_t> & w)219   FloatConstant(const Float* ty, const std::vector<uint32_t>& w)
220       : ScalarConstant(ty, w) {}
FloatConstant(const Float * ty,std::vector<uint32_t> && w)221   FloatConstant(const Float* ty, std::vector<uint32_t>&& w)
222       : ScalarConstant(ty, std::move(w)) {}
223 
AsFloatConstant()224   FloatConstant* AsFloatConstant() override { return this; }
AsFloatConstant()225   const FloatConstant* AsFloatConstant() const override { return this; }
226 
227   // Make a copy of this FloatConstant instance.
CopyFloatConstant()228   std::unique_ptr<FloatConstant> CopyFloatConstant() const {
229     return MakeUnique<FloatConstant>(type_->AsFloat(), words_);
230   }
Copy()231   std::unique_ptr<Constant> Copy() const override {
232     return std::unique_ptr<Constant>(CopyFloatConstant().release());
233   }
234 
235   // Returns the float value of |this|.  The type of |this| must be |Float| with
236   // width of 32.
GetFloatValue()237   float GetFloatValue() const {
238     assert(type()->AsFloat()->width() == 32 &&
239            "Not a 32-bit floating point value.");
240     utils::FloatProxy<float> a(words()[0]);
241     return a.getAsFloat();
242   }
243 
244   // Returns the double value of |this|.  The type of |this| must be |Float|
245   // with width of 64.
GetDoubleValue()246   double GetDoubleValue() const {
247     assert(type()->AsFloat()->width() == 64 &&
248            "Not a 32-bit floating point value.");
249     uint64_t combined_words = words()[1];
250     combined_words = combined_words << 32;
251     combined_words |= words()[0];
252     utils::FloatProxy<double> a(combined_words);
253     return a.getAsFloat();
254   }
255 };
256 
257 // Bool type constant.
258 class BoolConstant : public ScalarConstant {
259  public:
BoolConstant(const Bool * ty,bool v)260   BoolConstant(const Bool* ty, bool v)
261       : ScalarConstant(ty, {static_cast<uint32_t>(v)}), value_(v) {}
262 
AsBoolConstant()263   BoolConstant* AsBoolConstant() override { return this; }
AsBoolConstant()264   const BoolConstant* AsBoolConstant() const override { return this; }
265 
266   // Make a copy of this BoolConstant instance.
CopyBoolConstant()267   std::unique_ptr<BoolConstant> CopyBoolConstant() const {
268     return MakeUnique<BoolConstant>(type_->AsBool(), value_);
269   }
Copy()270   std::unique_ptr<Constant> Copy() const override {
271     return std::unique_ptr<Constant>(CopyBoolConstant().release());
272   }
273 
value()274   bool value() const { return value_; }
275 
276  private:
277   bool value_;
278 };
279 
280 // Abstract class for composite constants.
281 class CompositeConstant : public Constant {
282  public:
283   CompositeConstant() = delete;
AsCompositeConstant()284   CompositeConstant* AsCompositeConstant() override { return this; }
AsCompositeConstant()285   const CompositeConstant* AsCompositeConstant() const override { return this; }
286 
287   // Returns a const reference of the components held in this composite
288   // constant.
GetComponents()289   virtual const std::vector<const Constant*>& GetComponents() const {
290     return components_;
291   }
292 
IsZero()293   bool IsZero() const override {
294     for (const Constant* c : GetComponents()) {
295       if (!c->IsZero()) {
296         return false;
297       }
298     }
299     return true;
300   }
301 
302  protected:
CompositeConstant(const Type * ty)303   CompositeConstant(const Type* ty) : Constant(ty), components_() {}
CompositeConstant(const Type * ty,const std::vector<const Constant * > & components)304   CompositeConstant(const Type* ty,
305                     const std::vector<const Constant*>& components)
306       : Constant(ty), components_(components) {}
CompositeConstant(const Type * ty,std::vector<const Constant * > && components)307   CompositeConstant(const Type* ty, std::vector<const Constant*>&& components)
308       : Constant(ty), components_(std::move(components)) {}
309   std::vector<const Constant*> components_;
310 };
311 
312 // Struct type constant.
313 class StructConstant : public CompositeConstant {
314  public:
StructConstant(const Struct * ty)315   StructConstant(const Struct* ty) : CompositeConstant(ty) {}
StructConstant(const Struct * ty,const std::vector<const Constant * > & components)316   StructConstant(const Struct* ty,
317                  const std::vector<const Constant*>& components)
318       : CompositeConstant(ty, components) {}
StructConstant(const Struct * ty,std::vector<const Constant * > && components)319   StructConstant(const Struct* ty, std::vector<const Constant*>&& components)
320       : CompositeConstant(ty, std::move(components)) {}
321 
AsStructConstant()322   StructConstant* AsStructConstant() override { return this; }
AsStructConstant()323   const StructConstant* AsStructConstant() const override { return this; }
324 
325   // Make a copy of this StructConstant instance.
CopyStructConstant()326   std::unique_ptr<StructConstant> CopyStructConstant() const {
327     return MakeUnique<StructConstant>(type_->AsStruct(), components_);
328   }
Copy()329   std::unique_ptr<Constant> Copy() const override {
330     return std::unique_ptr<Constant>(CopyStructConstant().release());
331   }
332 };
333 
334 // Vector type constant.
335 class VectorConstant : public CompositeConstant {
336  public:
VectorConstant(const Vector * ty)337   VectorConstant(const Vector* ty)
338       : CompositeConstant(ty), component_type_(ty->element_type()) {}
VectorConstant(const Vector * ty,const std::vector<const Constant * > & components)339   VectorConstant(const Vector* ty,
340                  const std::vector<const Constant*>& components)
341       : CompositeConstant(ty, components),
342         component_type_(ty->element_type()) {}
VectorConstant(const Vector * ty,std::vector<const Constant * > && components)343   VectorConstant(const Vector* ty, std::vector<const Constant*>&& components)
344       : CompositeConstant(ty, std::move(components)),
345         component_type_(ty->element_type()) {}
346 
AsVectorConstant()347   VectorConstant* AsVectorConstant() override { return this; }
AsVectorConstant()348   const VectorConstant* AsVectorConstant() const override { return this; }
349 
350   // Make a copy of this VectorConstant instance.
CopyVectorConstant()351   std::unique_ptr<VectorConstant> CopyVectorConstant() const {
352     auto another = MakeUnique<VectorConstant>(type_->AsVector());
353     another->components_.insert(another->components_.end(), components_.begin(),
354                                 components_.end());
355     return another;
356   }
Copy()357   std::unique_ptr<Constant> Copy() const override {
358     return std::unique_ptr<Constant>(CopyVectorConstant().release());
359   }
360 
component_type()361   const Type* component_type() const { return component_type_; }
362 
363  private:
364   const Type* component_type_;
365 };
366 
367 // Matrix type constant.
368 class MatrixConstant : public CompositeConstant {
369  public:
MatrixConstant(const Matrix * ty)370   MatrixConstant(const Matrix* ty)
371       : CompositeConstant(ty), component_type_(ty->element_type()) {}
MatrixConstant(const Matrix * ty,const std::vector<const Constant * > & components)372   MatrixConstant(const Matrix* ty,
373                  const std::vector<const Constant*>& components)
374       : CompositeConstant(ty, components),
375         component_type_(ty->element_type()) {}
MatrixConstant(const Vector * ty,std::vector<const Constant * > && components)376   MatrixConstant(const Vector* ty, std::vector<const Constant*>&& components)
377       : CompositeConstant(ty, std::move(components)),
378         component_type_(ty->element_type()) {}
379 
AsMatrixConstant()380   MatrixConstant* AsMatrixConstant() override { return this; }
AsMatrixConstant()381   const MatrixConstant* AsMatrixConstant() const override { return this; }
382 
383   // Make a copy of this MatrixConstant instance.
CopyMatrixConstant()384   std::unique_ptr<MatrixConstant> CopyMatrixConstant() const {
385     auto another = MakeUnique<MatrixConstant>(type_->AsMatrix());
386     another->components_.insert(another->components_.end(), components_.begin(),
387                                 components_.end());
388     return another;
389   }
Copy()390   std::unique_ptr<Constant> Copy() const override {
391     return std::unique_ptr<Constant>(CopyMatrixConstant().release());
392   }
393 
component_type()394   const Type* component_type() { return component_type_; }
395 
396  private:
397   const Type* component_type_;
398 };
399 
400 // Array type constant.
401 class ArrayConstant : public CompositeConstant {
402  public:
ArrayConstant(const Array * ty)403   ArrayConstant(const Array* ty) : CompositeConstant(ty) {}
ArrayConstant(const Array * ty,const std::vector<const Constant * > & components)404   ArrayConstant(const Array* ty, const std::vector<const Constant*>& components)
405       : CompositeConstant(ty, components) {}
ArrayConstant(const Array * ty,std::vector<const Constant * > && components)406   ArrayConstant(const Array* ty, std::vector<const Constant*>&& components)
407       : CompositeConstant(ty, std::move(components)) {}
408 
AsArrayConstant()409   ArrayConstant* AsArrayConstant() override { return this; }
AsArrayConstant()410   const ArrayConstant* AsArrayConstant() const override { return this; }
411 
412   // Make a copy of this ArrayConstant instance.
CopyArrayConstant()413   std::unique_ptr<ArrayConstant> CopyArrayConstant() const {
414     return MakeUnique<ArrayConstant>(type_->AsArray(), components_);
415   }
Copy()416   std::unique_ptr<Constant> Copy() const override {
417     return std::unique_ptr<Constant>(CopyArrayConstant().release());
418   }
419 };
420 
421 // Null type constant.
422 class NullConstant : public Constant {
423  public:
NullConstant(const Type * ty)424   NullConstant(const Type* ty) : Constant(ty) {}
AsNullConstant()425   NullConstant* AsNullConstant() override { return this; }
AsNullConstant()426   const NullConstant* AsNullConstant() const override { return this; }
427 
428   // Make a copy of this NullConstant instance.
CopyNullConstant()429   std::unique_ptr<NullConstant> CopyNullConstant() const {
430     return MakeUnique<NullConstant>(type_);
431   }
Copy()432   std::unique_ptr<Constant> Copy() const override {
433     return std::unique_ptr<Constant>(CopyNullConstant().release());
434   }
IsZero()435   bool IsZero() const override { return true; };
436 };
437 
438 // Hash function for Constant instances. Use the structure of the constant as
439 // the key.
440 struct ConstantHash {
add_pointerConstantHash441   void add_pointer(std::u32string* h, const void* p) const {
442     uint64_t ptr_val = reinterpret_cast<uint64_t>(p);
443     h->push_back(static_cast<uint32_t>(ptr_val >> 32));
444     h->push_back(static_cast<uint32_t>(ptr_val));
445   }
446 
operatorConstantHash447   size_t operator()(const Constant* const_val) const {
448     std::u32string h;
449     add_pointer(&h, const_val->type());
450     if (const auto scalar = const_val->AsScalarConstant()) {
451       for (const auto& w : scalar->words()) {
452         h.push_back(w);
453       }
454     } else if (const auto composite = const_val->AsCompositeConstant()) {
455       for (const auto& c : composite->GetComponents()) {
456         add_pointer(&h, c);
457       }
458     } else if (const_val->AsNullConstant()) {
459       h.push_back(0);
460     } else {
461       assert(
462           false &&
463           "Tried to compute the hash value of an invalid Constant instance.");
464     }
465 
466     return std::hash<std::u32string>()(h);
467   }
468 };
469 
470 // Equality comparison structure for two constants.
471 struct ConstantEqual {
operatorConstantEqual472   bool operator()(const Constant* c1, const Constant* c2) const {
473     if (c1->type() != c2->type()) {
474       return false;
475     }
476 
477     if (const auto& s1 = c1->AsScalarConstant()) {
478       const auto& s2 = c2->AsScalarConstant();
479       return s2 && s1->words() == s2->words();
480     } else if (const auto& composite1 = c1->AsCompositeConstant()) {
481       const auto& composite2 = c2->AsCompositeConstant();
482       return composite2 &&
483              composite1->GetComponents() == composite2->GetComponents();
484     } else if (c1->AsNullConstant()) {
485       return c2->AsNullConstant() != nullptr;
486     } else {
487       assert(false && "Tried to compare two invalid Constant instances.");
488     }
489     return false;
490   }
491 };
492 
493 // This class represents a pool of constants.
494 class ConstantManager {
495  public:
496   ConstantManager(IRContext* ctx);
497 
context()498   IRContext* context() const { return ctx_; }
499 
500   // Gets or creates a unique Constant instance of type |type| and a vector of
501   // constant defining words |words|. If a Constant instance existed already in
502   // the constant pool, it returns a pointer to it.  Otherwise, it creates one
503   // using CreateConstant. If a new Constant instance cannot be created, it
504   // returns nullptr.
505   const Constant* GetConstant(
506       const Type* type, const std::vector<uint32_t>& literal_words_or_ids);
507 
508   template <class C>
GetConstant(const Type * type,const C & literal_words_or_ids)509   const Constant* GetConstant(const Type* type, const C& literal_words_or_ids) {
510     return GetConstant(type, std::vector<uint32_t>(literal_words_or_ids.begin(),
511                                                    literal_words_or_ids.end()));
512   }
513 
514   // Gets or creates a Constant instance to hold the constant value of the given
515   // instruction. It returns a pointer to a Constant instance or nullptr if it
516   // could not create the constant.
517   const Constant* GetConstantFromInst(Instruction* inst);
518 
519   // Gets or creates a constant defining instruction for the given Constant |c|.
520   // If |c| had already been defined, it returns a pointer to the existing
521   // declaration. Otherwise, it calls BuildInstructionAndAddToModule. If the
522   // optional |pos| is given, it will insert any newly created instructions at
523   // the given instruction iterator position. Otherwise, it inserts the new
524   // instruction at the end of the current module's types section.
525   //
526   // |type_id| is an optional argument for disambiguating equivalent types. If
527   // |type_id| is specified, it is used as the type of the constant when a new
528   // instruction is created. Otherwise the type of the constant is derived by
529   // getting an id from the type manager for |c|.
530   //
531   // When |type_id| is not zero, the type of |c| must be the type returned by
532   // type manager when given |type_id|.
533   Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0,
534                                       Module::inst_iterator* pos = nullptr);
535 
536   // Creates a constant defining instruction for the given Constant instance
537   // and inserts the instruction at the position specified by the given
538   // instruction iterator. Returns a pointer to the created instruction if
539   // succeeded, otherwise returns a null pointer. The instruction iterator
540   // points to the same instruction before and after the insertion. This is the
541   // only method that actually manages id creation/assignment and instruction
542   // creation/insertion for a new Constant instance.
543   //
544   // |type_id| is an optional argument for disambiguating equivalent types. If
545   // |type_id| is specified, it is used as the type of the constant. Otherwise
546   // the type of the constant is derived by getting an id from the type manager
547   // for |c|.
548   Instruction* BuildInstructionAndAddToModule(const Constant* c,
549                                               Module::inst_iterator* pos,
550                                               uint32_t type_id = 0);
551 
552   // A helper function to get the result type of the given instruction. Returns
553   // nullptr if the instruction does not have a type id (type id is 0).
554   Type* GetType(const Instruction* inst) const;
555 
556   // A helper function to get the collected normal constant with the given id.
557   // Returns the pointer to the Constant instance in case it is found.
558   // Otherwise, it returns a null pointer.
FindDeclaredConstant(uint32_t id)559   const Constant* FindDeclaredConstant(uint32_t id) const {
560     auto iter = id_to_const_val_.find(id);
561     return (iter != id_to_const_val_.end()) ? iter->second : nullptr;
562   }
563 
564   // A helper function to get the id of a collected constant with the pointer
565   // to the Constant instance. Returns 0 in case the constant is not found.
566   uint32_t FindDeclaredConstant(const Constant* c, uint32_t type_id) const;
567 
568   // Returns the canonical constant that has the same structure and value as the
569   // given Constant |cst|. If none is found, it returns nullptr.
570   //
571   // TODO: Should be able to give a type id to disambiguate types with the same
572   // structure.
FindConstant(const Constant * c)573   const Constant* FindConstant(const Constant* c) const {
574     auto it = const_pool_.find(c);
575     return (it != const_pool_.end()) ? *it : nullptr;
576   }
577 
578   // Registers a new constant |cst| in the constant pool. If the constant
579   // existed already, it returns a pointer to the previously existing Constant
580   // in the pool. Otherwise, it returns |cst|.
RegisterConstant(std::unique_ptr<Constant> cst)581   const Constant* RegisterConstant(std::unique_ptr<Constant> cst) {
582     auto ret = const_pool_.insert(cst.get());
583     if (ret.second) {
584       owned_constants_.emplace_back(std::move(cst));
585     }
586     return *ret.first;
587   }
588 
589   // A helper function to get a vector of Constant instances with the specified
590   // ids. If it can not find the Constant instance for any one of the ids,
591   // it returns an empty vector.
592   std::vector<const Constant*> GetConstantsFromIds(
593       const std::vector<uint32_t>& ids) const;
594 
595   // Returns a vector of constants representing each in operand. If an operand
596   // is not constant its entry is nullptr.
597   std::vector<const Constant*> GetOperandConstants(Instruction* inst) const;
598 
599   // Records a mapping between |inst| and the constant value generated by it.
600   // It returns true if a new Constant was successfully mapped, false if |inst|
601   // generates no constant values.
MapInst(Instruction * inst)602   bool MapInst(Instruction* inst) {
603     if (auto cst = GetConstantFromInst(inst)) {
604       MapConstantToInst(cst, inst);
605       return true;
606     }
607     return false;
608   }
609 
RemoveId(uint32_t id)610   void RemoveId(uint32_t id) {
611     auto it = id_to_const_val_.find(id);
612     if (it != id_to_const_val_.end()) {
613       const_val_to_id_.erase(it->second);
614       id_to_const_val_.erase(it);
615     }
616   }
617 
618   // Records a new mapping between |inst| and |const_value|. This updates the
619   // two mappings |id_to_const_val_| and |const_val_to_id_|.
MapConstantToInst(const Constant * const_value,Instruction * inst)620   void MapConstantToInst(const Constant* const_value, Instruction* inst) {
621     if (id_to_const_val_.insert({inst->result_id(), const_value}).second) {
622       const_val_to_id_.insert({const_value, inst->result_id()});
623     }
624   }
625 
626  private:
627   // Creates a Constant instance with the given type and a vector of constant
628   // defining words. Returns a unique pointer to the created Constant instance
629   // if the Constant instance can be created successfully. To create scalar
630   // type constants, the vector should contain the constant value in 32 bit
631   // words and the given type must be of type Bool, Integer or Float. To create
632   // composite type constants, the vector should contain the component ids, and
633   // those component ids should have been recorded before as Normal Constants.
634   // And the given type must be of type Struct, Vector or Array. When creating
635   // VectorType Constant instance, the components must be scalars of the same
636   // type, either Bool, Integer or Float. If any of the rules above failed, the
637   // creation will fail and nullptr will be returned. If the vector is empty,
638   // a NullConstant instance will be created with the given type.
639   std::unique_ptr<Constant> CreateConstant(
640       const Type* type,
641       const std::vector<uint32_t>& literal_words_or_ids) const;
642 
643   // Creates an instruction with the given result id to declare a constant
644   // represented by the given Constant instance. Returns an unique pointer to
645   // the created instruction if the instruction can be created successfully.
646   // Otherwise, returns a null pointer.
647   //
648   // |type_id| is an optional argument for disambiguating equivalent types. If
649   // |type_id| is specified, it is used as the type of the constant. Otherwise
650   // the type of the constant is derived by getting an id from the type manager
651   // for |c|.
652   std::unique_ptr<Instruction> CreateInstruction(uint32_t result_id,
653                                                  const Constant* c,
654                                                  uint32_t type_id = 0) const;
655 
656   // Creates an OpConstantComposite instruction with the given result id and
657   // the CompositeConst instance which represents a composite constant. Returns
658   // an unique pointer to the created instruction if succeeded. Otherwise
659   // returns a null pointer.
660   //
661   // |type_id| is an optional argument for disambiguating equivalent types. If
662   // |type_id| is specified, it is used as the type of the constant. Otherwise
663   // the type of the constant is derived by getting an id from the type manager
664   // for |c|.
665   std::unique_ptr<Instruction> CreateCompositeInstruction(
666       uint32_t result_id, const CompositeConstant* cc,
667       uint32_t type_id = 0) const;
668 
669   // IR context that owns this constant manager.
670   IRContext* ctx_;
671 
672   // A mapping from the result ids of Normal Constants to their
673   // Constant instances. All Normal Constants in the module, either
674   // existing ones before optimization or the newly generated ones, should have
675   // their Constant instance stored and their result id registered in this map.
676   std::unordered_map<uint32_t, const Constant*> id_to_const_val_;
677 
678   // A mapping from the Constant instance of Normal Constants to their
679   // result id in the module. This is a mirror map of |id_to_const_val_|. All
680   // Normal Constants that defining instructions in the module should have
681   // their Constant and their result id registered here.
682   std::multimap<const Constant*, uint32_t> const_val_to_id_;
683 
684   // The constant pool.  All created constants are registered here.
685   std::unordered_set<const Constant*, ConstantHash, ConstantEqual> const_pool_;
686 
687   // The constant that are owned by the constant manager.  Every constant in
688   // |const_pool_| should be in |owned_constants_| as well.
689   std::vector<std::unique_ptr<Constant>> owned_constants_;
690 };
691 
692 }  // namespace analysis
693 }  // namespace opt
694 }  // namespace spvtools
695 
696 #endif  // SOURCE_OPT_CONSTANTS_H_
697