Coverage Report

Created: 2026-11-12 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/opt/constants.cpp
Line
Count
Source
1
// Copyright (c) 2017 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
#include "source/opt/constants.h"
16
17
#include <vector>
18
19
#include "source/opt/ir_context.h"
20
21
namespace spvtools {
22
namespace opt {
23
namespace analysis {
24
25
134k
float Constant::GetFloat() const {
26
134k
  assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 32);
27
28
134k
  if (const FloatConstant* fc = AsFloatConstant()) {
29
133k
    return fc->GetFloatValue();
30
133k
  } else {
31
1.45k
    assert(AsNullConstant() && "Must be a floating point constant.");
32
1.45k
    return 0.0f;
33
1.45k
  }
34
134k
}
35
36
0
double Constant::GetDouble() const {
37
0
  assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 64);
38
39
0
  if (const FloatConstant* fc = AsFloatConstant()) {
40
0
    return fc->GetDoubleValue();
41
0
  } else {
42
0
    assert(AsNullConstant() && "Must be a floating point constant.");
43
0
    return 0.0;
44
0
  }
45
0
}
46
47
4.21k
double Constant::GetValueAsDouble() const {
48
4.21k
  assert(type()->AsFloat() != nullptr);
49
4.21k
  if (type()->AsFloat()->width() == 32) {
50
4.21k
    return GetFloat();
51
4.21k
  } else {
52
0
    assert(type()->AsFloat()->width() == 64);
53
0
    return GetDouble();
54
0
  }
55
4.21k
}
56
57
26.6k
uint32_t Constant::GetU32() const {
58
26.6k
  assert(type()->AsInteger() != nullptr);
59
26.6k
  assert(type()->AsInteger()->width() == 32);
60
61
26.6k
  if (const IntConstant* ic = AsIntConstant()) {
62
26.5k
    return ic->GetU32BitValue();
63
26.5k
  } else {
64
8
    assert(AsNullConstant() && "Must be an integer constant.");
65
8
    return 0u;
66
8
  }
67
26.6k
}
68
69
0
uint64_t Constant::GetU64() const {
70
0
  assert(type()->AsInteger() != nullptr);
71
0
  assert(type()->AsInteger()->width() == 64);
72
73
0
  if (const IntConstant* ic = AsIntConstant()) {
74
0
    return ic->GetU64BitValue();
75
0
  } else {
76
0
    assert(AsNullConstant() && "Must be an integer constant.");
77
0
    return 0u;
78
0
  }
79
0
}
80
81
0
int32_t Constant::GetS32() const {
82
0
  assert(type()->AsInteger() != nullptr);
83
0
  assert(type()->AsInteger()->width() == 32);
84
85
0
  if (const IntConstant* ic = AsIntConstant()) {
86
0
    return ic->GetS32BitValue();
87
0
  } else {
88
0
    assert(AsNullConstant() && "Must be an integer constant.");
89
0
    return 0;
90
0
  }
91
0
}
92
93
0
int64_t Constant::GetS64() const {
94
0
  assert(type()->AsInteger() != nullptr);
95
0
  assert(type()->AsInteger()->width() == 64);
96
97
0
  if (const IntConstant* ic = AsIntConstant()) {
98
0
    return ic->GetS64BitValue();
99
0
  } else {
100
0
    assert(AsNullConstant() && "Must be an integer constant.");
101
0
    return 0;
102
0
  }
103
0
}
104
105
461k
uint64_t Constant::GetZeroExtendedValue() const {
106
461k
  const auto* int_type = type()->AsInteger();
107
461k
  assert(int_type != nullptr);
108
461k
  const auto width = int_type->width();
109
461k
  assert(width <= 64);
110
111
461k
  uint64_t value = 0;
112
461k
  if (const IntConstant* ic = AsIntConstant()) {
113
460k
    if (width <= 32) {
114
460k
      value = ic->GetU32BitValue();
115
460k
    } else {
116
0
      value = ic->GetU64BitValue();
117
0
    }
118
460k
  } else {
119
288
    assert(AsNullConstant() && "Must be an integer constant.");
120
288
  }
121
461k
  return value;
122
461k
}
123
124
238k
int64_t Constant::GetSignExtendedValue() const {
125
238k
  const auto* int_type = type()->AsInteger();
126
238k
  assert(int_type != nullptr);
127
238k
  const auto width = int_type->width();
128
238k
  assert(width <= 64);
129
130
238k
  int64_t value = 0;
131
238k
  if (const IntConstant* ic = AsIntConstant()) {
132
237k
    if (width <= 32) {
133
      // Let the C++ compiler do the sign extension.
134
237k
      value = int64_t(ic->GetS32BitValue());
135
237k
    } else {
136
0
      value = ic->GetS64BitValue();
137
0
    }
138
237k
  } else {
139
469
    assert(AsNullConstant() && "Must be an integer constant.");
140
469
  }
141
238k
  return value;
142
238k
}
143
144
12.0k
ConstantManager::ConstantManager(IRContext* ctx) : ctx_(ctx) {
145
  // Populate the constant table with values from constant declarations in the
146
  // module.  The values of each OpConstant declaration is the identity
147
  // assignment (i.e., each constant is its own value).
148
265k
  for (const auto& inst : ctx_->module()->GetConstants()) {
149
265k
    MapInst(inst);
150
265k
  }
151
12.0k
}
152
153
755k
Type* ConstantManager::GetType(const Instruction* inst) const {
154
755k
  return context()->get_type_mgr()->GetType(inst->type_id());
155
755k
}
156
157
std::vector<const Constant*> ConstantManager::GetOperandConstants(
158
5.02M
    const Instruction* inst) const {
159
5.02M
  std::vector<const Constant*> constants;
160
5.02M
  constants.reserve(inst->NumInOperands());
161
14.8M
  for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
162
9.82M
    const Operand* operand = &inst->GetInOperand(i);
163
9.82M
    if (operand->type != SPV_OPERAND_TYPE_ID) {
164
1.18M
      constants.push_back(nullptr);
165
8.64M
    } else {
166
8.64M
      uint32_t id = operand->words[0];
167
8.64M
      const analysis::Constant* constant = FindDeclaredConstant(id);
168
8.64M
      constants.push_back(constant);
169
8.64M
    }
170
9.82M
  }
171
5.02M
  return constants;
172
5.02M
}
173
174
uint32_t ConstantManager::FindDeclaredConstant(const Constant* c,
175
536k
                                               uint32_t type_id) const {
176
536k
  if (c == nullptr) {
177
0
    return 0;
178
0
  }
179
536k
  c = FindConstant(c);
180
536k
  if (c == nullptr) {
181
0
    return 0;
182
0
  }
183
184
536k
  for (auto range = const_val_to_id_.equal_range(c);
185
536k
       range.first != range.second; ++range.first) {
186
473k
    Instruction* const_def =
187
473k
        context()->get_def_use_mgr()->GetDef(range.first->second);
188
473k
    if (type_id == 0 || const_def->type_id() == type_id) {
189
473k
      return range.first->second;
190
473k
    }
191
473k
  }
192
63.0k
  return 0;
193
536k
}
194
195
std::vector<const Constant*> ConstantManager::GetConstantsFromIds(
196
84.7k
    const std::vector<uint32_t>& ids) const {
197
84.7k
  std::vector<const Constant*> constants;
198
273k
  for (uint32_t id : ids) {
199
273k
    if (const Constant* c = FindDeclaredConstant(id)) {
200
273k
      constants.push_back(c);
201
273k
    } else {
202
5
      return {};
203
5
    }
204
273k
  }
205
84.7k
  return constants;
206
84.7k
}
207
208
Instruction* ConstantManager::BuildInstructionAndAddToModule(
209
62.9k
    const Constant* new_const, Module::inst_iterator* pos, uint32_t type_id) {
210
62.9k
  if (new_const == nullptr) {
211
0
    return nullptr;
212
0
  }
213
62.9k
  uint32_t new_id = context()->TakeNextId();
214
62.9k
  if (new_id == 0) {
215
0
    return nullptr;
216
0
  }
217
218
62.9k
  auto new_inst = CreateInstruction(new_id, new_const, type_id);
219
62.9k
  if (!new_inst) {
220
0
    return nullptr;
221
0
  }
222
62.9k
  auto* new_inst_ptr = new_inst.get();
223
62.9k
  *pos = pos->InsertBefore(std::move(new_inst));
224
62.9k
  ++(*pos);
225
62.9k
  if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
226
62.9k
    context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr);
227
62.9k
  MapConstantToInst(new_const, new_inst_ptr);
228
62.9k
  return new_inst_ptr;
229
62.9k
}
230
231
Instruction* ConstantManager::GetDefiningInstruction(
232
398k
    const Constant* c, uint32_t type_id, Module::inst_iterator* pos) {
233
398k
  if (c == nullptr) {
234
0
    return nullptr;
235
0
  }
236
398k
  uint32_t decl_id = FindDeclaredConstant(c, type_id);
237
398k
  if (decl_id == 0) {
238
62.9k
    auto iter = context()->types_values_end();
239
62.9k
    if (pos == nullptr) pos = &iter;
240
62.9k
    return BuildInstructionAndAddToModule(c, pos, type_id);
241
335k
  } else {
242
335k
    auto def = context()->get_def_use_mgr()->GetDef(decl_id);
243
335k
    assert(def != nullptr);
244
335k
    assert((type_id == 0 || def->type_id() == type_id) &&
245
335k
           "This constant already has an instruction with a different type.");
246
335k
    return def;
247
335k
  }
248
398k
}
249
250
std::unique_ptr<Constant> ConstantManager::CreateConstant(
251
932k
    const Type* type, const std::vector<uint32_t>& literal_words_or_ids) const {
252
932k
  if (literal_words_or_ids.size() == 0) {
253
    // Constant declared with OpConstantNull
254
3.86k
    return MakeUnique<NullConstant>(type);
255
928k
  } else if (auto* bt = type->AsBool()) {
256
111k
    assert(literal_words_or_ids.size() == 1 &&
257
111k
           "Bool constant should be declared with one operand");
258
111k
    return MakeUnique<BoolConstant>(bt, literal_words_or_ids.front());
259
816k
  } else if (auto* it = type->AsInteger()) {
260
595k
    return MakeUnique<IntConstant>(it, literal_words_or_ids);
261
595k
  } else if (auto* ft = type->AsFloat()) {
262
136k
    return MakeUnique<FloatConstant>(ft, literal_words_or_ids);
263
136k
  } else if (auto* vt = type->AsVector()) {
264
77.1k
    auto components = GetConstantsFromIds(literal_words_or_ids);
265
77.1k
    if (components.empty()) return nullptr;
266
    // All components of VectorConstant must be of type Bool, Integer or Float.
267
77.1k
    if (!std::all_of(components.begin(), components.end(),
268
235k
                     [](const Constant* c) {
269
235k
                       if (c->type()->AsBool() || c->type()->AsInteger() ||
270
235k
                           c->type()->AsFloat()) {
271
235k
                         return true;
272
235k
                       } else {
273
0
                         return false;
274
0
                       }
275
235k
                     }))
276
0
      return nullptr;
277
    // All components of VectorConstant must be in the same type.
278
77.1k
    const auto* component_type = components.front()->type();
279
77.1k
    if (!std::all_of(components.begin(), components.end(),
280
235k
                     [&component_type](const Constant* c) {
281
235k
                       if (c->type() == component_type) return true;
282
0
                       return false;
283
235k
                     }))
284
0
      return nullptr;
285
77.1k
    return MakeUnique<VectorConstant>(vt, components);
286
77.1k
  } else if (auto* mt = type->AsMatrix()) {
287
232
    auto components = GetConstantsFromIds(literal_words_or_ids);
288
232
    if (components.empty()) return nullptr;
289
232
    return MakeUnique<MatrixConstant>(mt, components);
290
7.41k
  } else if (auto* st = type->AsStruct()) {
291
6.50k
    auto components = GetConstantsFromIds(literal_words_or_ids);
292
6.50k
    if (components.empty()) return nullptr;
293
6.50k
    return MakeUnique<StructConstant>(st, components);
294
6.50k
  } else if (auto* at = type->AsArray()) {
295
909
    auto components = GetConstantsFromIds(literal_words_or_ids);
296
909
    if (components.empty()) return nullptr;
297
909
    return MakeUnique<ArrayConstant>(at, components);
298
909
  } else if (auto* tt = type->AsTensorARM()) {
299
0
    auto components = GetConstantsFromIds(literal_words_or_ids);
300
0
    if (components.empty()) return nullptr;
301
0
    return MakeUnique<TensorConstant>(tt, components);
302
0
  } else {
303
0
    return nullptr;
304
0
  }
305
932k
}
306
307
628k
const Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) {
308
628k
  std::vector<uint32_t> literal_words_or_ids;
309
310
  // Collect the constant defining literals or component ids.
311
1.37M
  for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
312
743k
    literal_words_or_ids.insert(literal_words_or_ids.end(),
313
743k
                                inst->GetInOperand(i).words.begin(),
314
743k
                                inst->GetInOperand(i).words.end());
315
743k
  }
316
317
628k
  const Type* type = GetType(inst);
318
319
628k
  switch (inst->opcode()) {
320
    // OpConstant{True|False} have the value embedded in the opcode. So they
321
    // are not handled by the for-loop above. Here we add the value explicitly.
322
6.11k
    case spv::Op::OpConstantTrue:
323
6.11k
      literal_words_or_ids.push_back(true);
324
6.11k
      break;
325
5.92k
    case spv::Op::OpConstantFalse:
326
5.92k
      literal_words_or_ids.push_back(false);
327
5.92k
      break;
328
1.09k
    case spv::Op::OpConstantNull:
329
537k
    case spv::Op::OpConstant:
330
567k
    case spv::Op::OpConstantComposite:
331
567k
    case spv::Op::OpSpecConstantComposite:
332
567k
      break;
333
    // Replicated composite constant instructions have a single operand for the
334
    // value. We need to replicate it as many times as there are components.
335
0
    case spv::Op::OpConstantCompositeReplicateEXT:
336
0
    case spv::Op::OpSpecConstantCompositeReplicateEXT: {
337
0
      uint32_t value = literal_words_or_ids[0];
338
0
      uint64_t component_count = type->NumberOfComponents();
339
0
      if (const auto* tensor_type = type->AsTensorARM()) {
340
        // TensorARM shape is stored as an ID, so resolve the outer
341
        // dimension here instead of using Type::NumberOfComponents().
342
0
        if (!tensor_type->is_shaped()) {
343
0
          return nullptr;
344
0
        }
345
0
        const auto* shape_inst =
346
0
            context()->get_def_use_mgr()->GetDef(tensor_type->shape_id());
347
0
        if (!shape_inst) {
348
0
          return nullptr;
349
0
        }
350
0
        const auto* shape_cst = GetConstantFromInst(shape_inst);
351
0
        if (!shape_cst || !shape_cst->AsArrayConstant()) {
352
0
          return nullptr;
353
0
        }
354
0
        const auto& shape_components =
355
0
            shape_cst->AsArrayConstant()->GetComponents();
356
0
        if (shape_components.empty()) {
357
0
          return nullptr;
358
0
        }
359
0
        const auto* outer_dim_cst = shape_components.front()->AsIntConstant();
360
0
        if (!outer_dim_cst) {
361
0
          return nullptr;
362
0
        }
363
0
        component_count = outer_dim_cst->GetZeroExtendedValue();
364
0
      }
365
      // Cooperative matrix types have no component count and no constant
366
      // class. Do not turn an empty component list into a null constant.
367
0
      if (component_count == 0) {
368
0
        return nullptr;
369
0
      }
370
0
      literal_words_or_ids.assign(static_cast<size_t>(component_count), value);
371
0
      break;
372
0
    }
373
49.1k
    default:
374
49.1k
      return nullptr;
375
628k
  }
376
377
579k
  return GetConstant(type, literal_words_or_ids);
378
628k
}
379
380
std::unique_ptr<Instruction> ConstantManager::CreateInstruction(
381
62.9k
    uint32_t id, const Constant* c, uint32_t type_id) const {
382
62.9k
  uint32_t type =
383
62.9k
      (type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id;
384
62.9k
  if (c->AsNullConstant()) {
385
512
    return MakeUnique<Instruction>(context(), spv::Op::OpConstantNull, type, id,
386
512
                                   std::initializer_list<Operand>{});
387
62.4k
  } else if (const BoolConstant* bc = c->AsBoolConstant()) {
388
6.79k
    return MakeUnique<Instruction>(
389
6.79k
        context(),
390
6.79k
        bc->value() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse, type,
391
6.79k
        id, std::initializer_list<Operand>{});
392
55.6k
  } else if (const IntConstant* ic = c->AsIntConstant()) {
393
32.4k
    return MakeUnique<Instruction>(
394
32.4k
        context(), spv::Op::OpConstant, type, id,
395
32.4k
        std::initializer_list<Operand>{
396
32.4k
            Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
397
32.4k
                    ic->words())});
398
32.4k
  } else if (const FloatConstant* fc = c->AsFloatConstant()) {
399
12.5k
    return MakeUnique<Instruction>(
400
12.5k
        context(), spv::Op::OpConstant, type, id,
401
12.5k
        std::initializer_list<Operand>{
402
12.5k
            Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
403
12.5k
                    fc->words())});
404
12.5k
  } else if (const CompositeConstant* cc = c->AsCompositeConstant()) {
405
10.6k
    return CreateCompositeInstruction(id, cc, type_id);
406
10.6k
  } else {
407
0
    return nullptr;
408
0
  }
409
62.9k
}
410
411
std::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction(
412
10.6k
    uint32_t result_id, const CompositeConstant* cc, uint32_t type_id) const {
413
10.6k
  std::vector<Operand> operands;
414
10.6k
  Instruction* type_inst = context()->get_def_use_mgr()->GetDef(type_id);
415
10.6k
  uint32_t component_index = 0;
416
28.5k
  for (const Constant* component_const : cc->GetComponents()) {
417
28.5k
    uint32_t component_type_id = 0;
418
28.5k
    if (type_inst && type_inst->opcode() == spv::Op::OpTypeStruct) {
419
6.62k
      component_type_id = type_inst->GetSingleWordInOperand(component_index);
420
21.9k
    } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeArray) {
421
185
      component_type_id = type_inst->GetSingleWordInOperand(0);
422
21.7k
    } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeTensorARM) {
423
0
      component_type_id =
424
0
          context()->get_type_mgr()->GetId(component_const->type());
425
0
      if (component_type_id == 0) {
426
0
        return nullptr;
427
0
      }
428
0
    }
429
28.5k
    uint32_t id = FindDeclaredConstant(component_const, component_type_id);
430
431
28.5k
    if (id == 0) {
432
      // Cannot get the id of the component constant, while all components
433
      // should have been added to the module prior to the composite constant.
434
      // Cannot create OpConstantComposite instruction in this case.
435
0
      return nullptr;
436
0
    }
437
28.5k
    operands.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
438
28.5k
                          std::initializer_list<uint32_t>{id});
439
28.5k
    component_index++;
440
28.5k
  }
441
10.6k
  uint32_t type =
442
10.6k
      (type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id;
443
10.6k
  return MakeUnique<Instruction>(context(), spv::Op::OpConstantComposite, type,
444
10.6k
                                 result_id, std::move(operands));
445
10.6k
}
446
447
const Constant* ConstantManager::GetConstant(
448
932k
    const Type* type, const std::vector<uint32_t>& literal_words_or_ids) {
449
932k
  if (type == nullptr) {
450
0
    return nullptr;
451
0
  }
452
932k
  auto cst = CreateConstant(type, literal_words_or_ids);
453
932k
  return cst ? RegisterConstant(std::move(cst)) : nullptr;
454
932k
}
455
456
3
const Constant* ConstantManager::GetNullCompositeConstant(const Type* type) {
457
3
  if (type == nullptr) {
458
0
    return nullptr;
459
0
  }
460
3
  std::vector<uint32_t> literal_words_or_id;
461
462
3
  if (type->AsVector()) {
463
3
    const Type* element_type = type->AsVector()->element_type();
464
3
    const uint32_t null_id = GetNullConstId(element_type);
465
3
    const uint32_t element_count = type->AsVector()->element_count();
466
9
    for (uint32_t i = 0; i < element_count; i++) {
467
6
      literal_words_or_id.push_back(null_id);
468
6
    }
469
3
  } else if (type->AsMatrix()) {
470
0
    const Type* element_type = type->AsMatrix()->element_type();
471
0
    const uint32_t null_id = GetNullConstId(element_type);
472
0
    const uint32_t element_count = type->AsMatrix()->element_count();
473
0
    for (uint32_t i = 0; i < element_count; i++) {
474
0
      literal_words_or_id.push_back(null_id);
475
0
    }
476
0
  } else if (type->AsStruct()) {
477
    // TODO (sfricke-lunarg) add proper struct support
478
0
    return nullptr;
479
0
  } else if (type->AsArray()) {
480
0
    const Type* element_type = type->AsArray()->element_type();
481
0
    const uint32_t null_id = GetNullConstId(element_type);
482
0
    assert(type->AsArray()->length_info().words[0] ==
483
0
               analysis::Array::LengthInfo::kConstant &&
484
0
           "unexpected array length");
485
0
    const uint32_t element_count = type->AsArray()->length_info().words[0];
486
0
    for (uint32_t i = 0; i < element_count; i++) {
487
0
      literal_words_or_id.push_back(null_id);
488
0
    }
489
0
  } else if (type->AsTensorARM()) {
490
0
    auto ttype = type->AsTensorARM();
491
0
    assert(ttype->is_shaped() && "Only shaped tensors are composites");
492
0
    const auto* shape_inst =
493
0
        context()->get_def_use_mgr()->GetDef(ttype->shape_id());
494
0
    if (!shape_inst) {
495
0
      return nullptr;
496
0
    }
497
0
    const auto* shape_cst = GetConstantFromInst(shape_inst);
498
0
    if (!shape_cst || !shape_cst->AsArrayConstant()) {
499
0
      return nullptr;
500
0
    }
501
0
    const auto& shape_components =
502
0
        shape_cst->AsArrayConstant()->GetComponents();
503
0
    if (shape_components.empty()) {
504
0
      return nullptr;
505
0
    }
506
0
    const auto* outer_dim_cst = shape_components.front()->AsIntConstant();
507
0
    if (!outer_dim_cst) {
508
0
      return nullptr;
509
0
    }
510
0
    const uint64_t element_count = outer_dim_cst->GetZeroExtendedValue();
511
0
    std::vector<const Constant*> components;
512
0
    components.reserve(static_cast<size_t>(element_count));
513
514
0
    if (shape_components.size() == 1) {
515
0
      const Constant* element_null = GetConstant(ttype->element_type(), {});
516
0
      for (uint64_t i = 0; i < element_count; i++) {
517
0
        components.push_back(element_null);
518
0
      }
519
0
      return RegisterConstant(
520
0
          MakeUnique<TensorConstant>(ttype, std::move(components)));
521
0
    }
522
523
0
    const Constant* rank_cst = nullptr;
524
0
    if (ttype->rank_id() != 0) {
525
0
      const auto* rank_inst =
526
0
          context()->get_def_use_mgr()->GetDef(ttype->rank_id());
527
0
      if (rank_inst) {
528
0
        rank_cst = GetConstantFromInst(rank_inst);
529
0
      }
530
0
    }
531
0
    uint64_t rank_value = shape_components.size();
532
0
    if (rank_cst && rank_cst->AsIntConstant()) {
533
0
      rank_value = rank_cst->AsIntConstant()->GetZeroExtendedValue();
534
0
    }
535
0
    if (rank_value <= 1) {
536
0
      const Constant* element_null = GetConstant(ttype->element_type(), {});
537
0
      for (uint64_t i = 0; i < element_count; i++) {
538
0
        components.push_back(element_null);
539
0
      }
540
0
      return RegisterConstant(
541
0
          MakeUnique<TensorConstant>(ttype, std::move(components)));
542
0
    }
543
544
0
    const uint64_t inner_rank = rank_value - 1;
545
0
    const auto* rank_int_type =
546
0
        rank_cst ? rank_cst->type()->AsInteger() : nullptr;
547
0
    if (!rank_int_type) {
548
0
      rank_int_type = outer_dim_cst->type()->AsInteger();
549
0
    }
550
0
    if (!rank_int_type) {
551
0
      return nullptr;
552
0
    }
553
0
    const Constant* inner_rank_cst =
554
0
        GenerateIntegerConstant(rank_int_type, inner_rank);
555
0
    const uint32_t inner_rank_id =
556
0
        GetDefiningInstruction(inner_rank_cst)->result_id();
557
558
0
    const Type* shape_elem_type = shape_components[1]->type();
559
0
    const auto* shape_elem_int = shape_elem_type->AsInteger();
560
0
    if (!shape_elem_int) {
561
0
      return nullptr;
562
0
    }
563
0
    const Constant* inner_shape_len_cst =
564
0
        GenerateIntegerConstant(shape_elem_int, inner_rank);
565
0
    const uint32_t inner_shape_len_id =
566
0
        GetDefiningInstruction(inner_shape_len_cst)->result_id();
567
0
    Array::LengthInfo inner_shape_len_info{
568
0
        inner_shape_len_id,
569
0
        {Array::LengthInfo::kConstant, static_cast<uint32_t>(inner_rank)}};
570
0
    Array inner_shape_type(shape_elem_type, inner_shape_len_info);
571
0
    const Type* inner_shape_reg_type =
572
0
        context()->get_type_mgr()->GetRegisteredType(&inner_shape_type);
573
0
    if (!inner_shape_reg_type) {
574
0
      return nullptr;
575
0
    }
576
0
    std::vector<uint32_t> inner_shape_ids;
577
0
    inner_shape_ids.reserve(shape_components.size() - 1);
578
0
    for (size_t i = 1; i < shape_components.size(); ++i) {
579
0
      inner_shape_ids.push_back(
580
0
          GetDefiningInstruction(shape_components[i])->result_id());
581
0
    }
582
0
    const Constant* inner_shape_cst =
583
0
        GetConstant(inner_shape_reg_type, inner_shape_ids);
584
0
    const uint32_t inner_shape_id =
585
0
        GetDefiningInstruction(inner_shape_cst)->result_id();
586
587
0
    TensorARM inner_tensor_type(ttype->element_type(), inner_rank_id,
588
0
                                inner_shape_id);
589
0
    const Type* inner_tensor_reg_type =
590
0
        context()->get_type_mgr()->GetRegisteredType(&inner_tensor_type);
591
0
    if (!inner_tensor_reg_type) {
592
0
      return nullptr;
593
0
    }
594
0
    const Constant* inner_null_tensor =
595
0
        GetNullCompositeConstant(inner_tensor_reg_type);
596
0
    if (!inner_null_tensor) {
597
0
      return nullptr;
598
0
    }
599
0
    for (uint64_t i = 0; i < element_count; i++) {
600
0
      components.push_back(inner_null_tensor);
601
0
    }
602
0
    return RegisterConstant(
603
0
        MakeUnique<TensorConstant>(ttype, std::move(components)));
604
0
  } else {
605
0
    return nullptr;
606
0
  }
607
608
3
  return GetConstant(type, literal_words_or_id);
609
3
}
610
611
const Constant* ConstantManager::GetNumericVectorConstantWithWords(
612
149
    const Vector* type, const std::vector<uint32_t>& literal_words) {
613
149
  const auto* element_type = type->element_type();
614
149
  uint32_t words_per_element = 0;
615
149
  if (const auto* float_type = element_type->AsFloat())
616
1
    words_per_element = float_type->width() / 32;
617
148
  else if (const auto* int_type = element_type->AsInteger())
618
148
    words_per_element = int_type->width() / 32;
619
0
  else if (element_type->AsBool() != nullptr)
620
0
    words_per_element = 1;
621
622
149
  if (words_per_element != 1 && words_per_element != 2) return nullptr;
623
624
149
  if (words_per_element * type->element_count() !=
625
149
      static_cast<uint32_t>(literal_words.size())) {
626
0
    return nullptr;
627
0
  }
628
629
149
  std::vector<uint32_t> element_ids;
630
741
  for (uint32_t i = 0; i < type->element_count(); ++i) {
631
592
    auto first_word = literal_words.begin() + (words_per_element * i);
632
592
    std::vector<uint32_t> const_data(first_word,
633
592
                                     first_word + words_per_element);
634
592
    const analysis::Constant* element_constant =
635
592
        GetConstant(element_type, const_data);
636
592
    if (!element_constant) {
637
0
      return nullptr;
638
0
    }
639
592
    Instruction* element_inst = GetDefiningInstruction(element_constant);
640
592
    if (!element_inst) {
641
0
      return nullptr;
642
0
    }
643
592
    element_ids.push_back(element_inst->result_id());
644
592
  }
645
646
149
  return GetConstant(type, element_ids);
647
149
}
648
649
0
uint32_t ConstantManager::GetFloatConstId(float val) {
650
0
  const Constant* c = GetFloatConst(val);
651
0
  Instruction* inst = GetDefiningInstruction(c);
652
0
  if (inst == nullptr) return 0;
653
0
  return inst->result_id();
654
0
}
655
656
590
const Constant* ConstantManager::GetFloatConst(float val) {
657
590
  Type* float_type = context()->get_type_mgr()->GetFloatType();
658
590
  utils::FloatProxy<float> v(val);
659
590
  const Constant* c = GetConstant(float_type, v.GetWords());
660
590
  return c;
661
590
}
662
663
0
uint32_t ConstantManager::GetDoubleConstId(double val) {
664
0
  const Constant* c = GetDoubleConst(val);
665
0
  Instruction* inst = GetDefiningInstruction(c);
666
0
  if (inst == nullptr) return 0;
667
0
  return inst->result_id();
668
0
}
669
670
0
const Constant* ConstantManager::GetDoubleConst(double val) {
671
0
  Type* float_type = context()->get_type_mgr()->GetDoubleType();
672
0
  utils::FloatProxy<double> v(val);
673
0
  const Constant* c = GetConstant(float_type, v.GetWords());
674
0
  return c;
675
0
}
676
677
0
uint32_t ConstantManager::GetSIntConstId(int32_t val) {
678
0
  Type* sint_type = context()->get_type_mgr()->GetSIntType();
679
0
  const Constant* c = GetConstant(sint_type, {static_cast<uint32_t>(val)});
680
0
  if (!c) {
681
0
    return 0;
682
0
  }
683
0
  Instruction* inst = GetDefiningInstruction(c);
684
0
  if (!inst) {
685
0
    return 0;
686
0
  }
687
0
  return inst->result_id();
688
0
}
689
690
const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth,
691
701
                                             bool isSigned) {
692
701
  Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned);
693
694
701
  if (isSigned) {
695
    // Sign extend the value.
696
554
    int32_t num_of_bit_to_ignore = 64 - bitWidth;
697
554
    val = static_cast<int64_t>(val << num_of_bit_to_ignore) >>
698
554
          num_of_bit_to_ignore;
699
554
  } else if (bitWidth < 64) {
700
    // Clear the upper bit that are not used.
701
147
    uint64_t mask = ((1ull << bitWidth) - 1);
702
147
    val &= mask;
703
147
  }
704
705
701
  if (bitWidth <= 32) {
706
701
    return GetConstant(int_type, {static_cast<uint32_t>(val)});
707
701
  }
708
709
  // If the value is more than 32-bit, we need to split the operands into two
710
  // 32-bit integers.
711
0
  return GetConstant(
712
0
      int_type, {static_cast<uint32_t>(val), static_cast<uint32_t>(val >> 32)});
713
701
}
714
715
0
uint32_t ConstantManager::GetUIntConstId(uint32_t val) {
716
0
  Type* uint_type = context()->get_type_mgr()->GetUIntType();
717
0
  const Constant* c = GetConstant(uint_type, {val});
718
0
  if (!c) {
719
0
    return 0;
720
0
  }
721
0
  Instruction* inst = GetDefiningInstruction(c);
722
0
  if (!inst) {
723
0
    return 0;
724
0
  }
725
0
  return inst->result_id();
726
0
}
727
728
1.89k
uint32_t ConstantManager::GetNullConstId(const Type* type) {
729
1.89k
  const Constant* c = GetConstant(type, {});
730
1.89k
  if (!c) {
731
0
    return 0;
732
0
  }
733
1.89k
  Instruction* inst = GetDefiningInstruction(c);
734
1.89k
  if (!inst) {
735
0
    return 0;
736
0
  }
737
1.89k
  return inst->result_id();
738
1.89k
}
739
740
const Constant* ConstantManager::GenerateIntegerConstant(
741
78.3k
    const analysis::Integer* integer_type, uint64_t result) {
742
78.3k
  assert(integer_type != nullptr);
743
744
78.3k
  std::vector<uint32_t> words;
745
78.3k
  if (integer_type->width() == 64) {
746
    // In the 64-bit case, two words are needed to represent the value.
747
0
    words = {static_cast<uint32_t>(result),
748
0
             static_cast<uint32_t>(result >> 32)};
749
78.3k
  } else {
750
    // In all other cases, only a single word is needed.
751
78.3k
    assert(integer_type->width() <= 32);
752
78.3k
    if (integer_type->IsSigned()) {
753
77.5k
      result = utils::SignExtendValue(result, integer_type->width());
754
77.5k
    } else {
755
792
      result = utils::ZeroExtendValue(result, integer_type->width());
756
792
    }
757
78.3k
    words = {static_cast<uint32_t>(result)};
758
78.3k
  }
759
78.3k
  return GetConstant(integer_type, words);
760
78.3k
}
761
762
std::vector<const analysis::Constant*> Constant::GetVectorComponents(
763
28.5k
    analysis::ConstantManager* const_mgr) const {
764
28.5k
  std::vector<const analysis::Constant*> components;
765
28.5k
  const analysis::VectorConstant* a = this->AsVectorConstant();
766
28.5k
  const analysis::Vector* vector_type = this->type()->AsVector();
767
28.5k
  assert(vector_type != nullptr);
768
28.5k
  if (a != nullptr) {
769
112k
    for (uint32_t i = 0; i < vector_type->element_count(); ++i) {
770
84.8k
      components.push_back(a->GetComponents()[i]);
771
84.8k
    }
772
28.1k
  } else {
773
422
    const analysis::Type* element_type = vector_type->element_type();
774
422
    const analysis::Constant* element_null_const =
775
422
        const_mgr->GetConstant(element_type, {});
776
1.68k
    for (uint32_t i = 0; i < vector_type->element_count(); ++i) {
777
1.26k
      components.push_back(element_null_const);
778
1.26k
    }
779
422
  }
780
28.5k
  return components;
781
28.5k
}
782
783
}  // namespace analysis
784
}  // namespace opt
785
}  // namespace spvtools