Coverage Report

Created: 2025-11-16 06:14

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