Coverage Report

Created: 2026-09-03 06:33

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