Coverage Report

Created: 2025-11-16 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-cross/spirv_cross_parsed_ir.cpp
Line
Count
Source
1
/*
2
 * Copyright 2018-2021 Arm Limited
3
 * SPDX-License-Identifier: Apache-2.0 OR MIT
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
/*
19
 * At your option, you may choose to accept this material under either:
20
 *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
21
 *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
22
 */
23
24
#include "spirv_cross_parsed_ir.hpp"
25
#include <algorithm>
26
#include <assert.h>
27
28
using namespace std;
29
using namespace SPIRV_CROSS_SPV_HEADER_NAMESPACE;
30
31
namespace SPIRV_CROSS_NAMESPACE
32
{
33
ParsedIR::ParsedIR()
34
255
{
35
  // If we move ParsedIR, we need to make sure the pointer stays fixed since the child Variant objects consume a pointer to this group,
36
  // so need an extra pointer here.
37
255
  pool_group.reset(new ObjectPoolGroup);
38
39
255
  pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>);
40
255
  pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>);
41
255
  pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>);
42
255
  pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>);
43
255
  pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>);
44
255
  pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>);
45
255
  pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>);
46
255
  pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>);
47
255
  pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>);
48
255
  pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>);
49
255
  pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
50
255
  pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
51
255
  pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
52
255
}
53
54
// Should have been default-implemented, but need this on MSVC 2013.
55
ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
56
0
{
57
0
  *this = std::move(other);
58
0
}
59
60
ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
61
0
{
62
0
  if (this != &other)
63
0
  {
64
0
    pool_group = std::move(other.pool_group);
65
0
    spirv = std::move(other.spirv);
66
0
    meta = std::move(other.meta);
67
0
    for (int i = 0; i < TypeCount; i++)
68
0
      ids_for_type[i] = std::move(other.ids_for_type[i]);
69
0
    ids_for_constant_undef_or_type = std::move(other.ids_for_constant_undef_or_type);
70
0
    ids_for_constant_or_variable = std::move(other.ids_for_constant_or_variable);
71
0
    declared_capabilities = std::move(other.declared_capabilities);
72
0
    declared_extensions = std::move(other.declared_extensions);
73
0
    block_meta = std::move(other.block_meta);
74
0
    continue_block_to_loop_header = std::move(other.continue_block_to_loop_header);
75
0
    entry_points = std::move(other.entry_points);
76
0
    ids = std::move(other.ids);
77
0
    addressing_model = other.addressing_model;
78
0
    memory_model = other.memory_model;
79
80
0
    default_entry_point = other.default_entry_point;
81
0
    source = other.source;
82
0
    loop_iteration_depth_hard = other.loop_iteration_depth_hard;
83
0
    loop_iteration_depth_soft = other.loop_iteration_depth_soft;
84
85
0
    meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
86
0
    load_type_width = std::move(other.load_type_width);
87
0
  }
88
0
  return *this;
89
0
}
90
91
ParsedIR::ParsedIR(const ParsedIR &other)
92
0
    : ParsedIR()
93
0
{
94
0
  *this = other;
95
0
}
96
97
ParsedIR &ParsedIR::operator=(const ParsedIR &other)
98
0
{
99
0
  if (this != &other)
100
0
  {
101
0
    spirv = other.spirv;
102
0
    meta = other.meta;
103
0
    for (int i = 0; i < TypeCount; i++)
104
0
      ids_for_type[i] = other.ids_for_type[i];
105
0
    ids_for_constant_undef_or_type = other.ids_for_constant_undef_or_type;
106
0
    ids_for_constant_or_variable = other.ids_for_constant_or_variable;
107
0
    declared_capabilities = other.declared_capabilities;
108
0
    declared_extensions = other.declared_extensions;
109
0
    block_meta = other.block_meta;
110
0
    continue_block_to_loop_header = other.continue_block_to_loop_header;
111
0
    entry_points = other.entry_points;
112
0
    default_entry_point = other.default_entry_point;
113
0
    source = other.source;
114
0
    loop_iteration_depth_hard = other.loop_iteration_depth_hard;
115
0
    loop_iteration_depth_soft = other.loop_iteration_depth_soft;
116
0
    addressing_model = other.addressing_model;
117
0
    memory_model = other.memory_model;
118
119
120
0
    meta_needing_name_fixup = other.meta_needing_name_fixup;
121
0
    load_type_width = other.load_type_width;
122
123
    // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
124
    // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
125
0
    ids.clear();
126
0
    ids.reserve(other.ids.size());
127
0
    for (size_t i = 0; i < other.ids.size(); i++)
128
0
    {
129
0
      ids.emplace_back(pool_group.get());
130
0
      ids.back() = other.ids[i];
131
0
    }
132
0
  }
133
0
  return *this;
134
0
}
135
136
void ParsedIR::set_id_bounds(uint32_t bounds)
137
248
{
138
248
  ids.reserve(bounds);
139
31.8M
  while (ids.size() < bounds)
140
31.8M
    ids.emplace_back(pool_group.get());
141
142
248
  block_meta.resize(bounds);
143
248
}
144
145
// Roll our own versions of these functions to avoid potential locale shenanigans.
146
static bool is_alpha(char c)
147
99.8k
{
148
99.8k
  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
149
99.8k
}
150
151
static bool is_numeric(char c)
152
43.3k
{
153
43.3k
  return c >= '0' && c <= '9';
154
43.3k
}
155
156
static bool is_alphanumeric(char c)
157
99.8k
{
158
99.8k
  return is_alpha(c) || is_numeric(c);
159
99.8k
}
160
161
static bool is_valid_identifier(const string &name)
162
13.7k
{
163
13.7k
  if (name.empty())
164
147
    return true;
165
166
13.6k
  if (is_numeric(name[0]))
167
4
    return false;
168
169
13.6k
  for (auto c : name)
170
99.8k
    if (!is_alphanumeric(c) && c != '_')
171
4.57k
      return false;
172
173
9.05k
  bool saw_underscore = false;
174
  // Two underscores in a row is not a valid identifier either.
175
  // Technically reserved, but it's easier to treat it as invalid.
176
9.05k
  for (auto c : name)
177
89.1k
  {
178
89.1k
    bool is_underscore = c == '_';
179
89.1k
    if (is_underscore && saw_underscore)
180
1.26k
      return false;
181
87.8k
    saw_underscore = is_underscore;
182
87.8k
  }
183
184
7.78k
  return true;
185
9.05k
}
186
187
static bool is_reserved_prefix(const string &name)
188
7.93k
{
189
  // Generic reserved identifiers used by the implementation.
190
7.93k
  return name.compare(0, 3, "gl_", 3) == 0 ||
191
         // Ignore this case for now, might rewrite internal code to always use spv prefix.
192
         //name.compare(0, 11, "SPIRV_Cross", 11) == 0 ||
193
7.85k
         name.compare(0, 3, "spv", 3) == 0;
194
7.93k
}
195
196
static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes)
197
7.93k
{
198
7.93k
  if (!allow_reserved_prefixes && is_reserved_prefix(name))
199
77
    return true;
200
201
7.85k
  if (member)
202
1.27k
  {
203
    // Reserved member identifiers come in one form:
204
    // _m[0-9]+$.
205
1.27k
    if (name.size() < 3)
206
519
      return false;
207
208
752
    if (name.compare(0, 2, "_m", 2) != 0)
209
752
      return false;
210
211
0
    size_t index = 2;
212
0
    while (index < name.size() && is_numeric(name[index]))
213
0
      index++;
214
215
0
    return index == name.size();
216
752
  }
217
6.58k
  else
218
6.58k
  {
219
    // Reserved non-member identifiers come in two forms:
220
    // _[0-9]+$, used for temporaries which map directly to a SPIR-V ID.
221
    // _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID.
222
6.58k
    if (name.size() < 2)
223
668
      return false;
224
225
5.91k
    if (name[0] != '_' || !is_numeric(name[1]))
226
3.74k
      return false;
227
228
2.17k
    size_t index = 2;
229
6.77k
    while (index < name.size() && is_numeric(name[index]))
230
4.59k
      index++;
231
232
2.17k
    return index == name.size() || (index < name.size() && name[index] == '_');
233
5.91k
  }
234
7.85k
}
235
236
bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes)
237
0
{
238
0
  return is_reserved_identifier(str, false, allow_reserved_prefixes);
239
0
}
240
241
uint32_t ParsedIR::get_spirv_version() const
242
0
{
243
0
  return spirv[1];
244
0
}
245
246
static string make_unreserved_identifier(const string &name)
247
0
{
248
0
  if (is_reserved_prefix(name))
249
0
    return "_RESERVED_IDENTIFIER_FIXUP_" + name;
250
0
  else
251
0
    return "_RESERVED_IDENTIFIER_FIXUP" + name;
252
0
}
253
254
void ParsedIR::sanitize_underscores(std::string &str)
255
0
{
256
  // Compact adjacent underscores to make it valid.
257
0
  auto dst = str.begin();
258
0
  auto src = dst;
259
0
  bool saw_underscore = false;
260
0
  while (src != str.end())
261
0
  {
262
0
    bool is_underscore = *src == '_';
263
0
    if (saw_underscore && is_underscore)
264
0
    {
265
0
      src++;
266
0
    }
267
0
    else
268
0
    {
269
0
      if (dst != src)
270
0
        *dst = *src;
271
0
      dst++;
272
0
      src++;
273
0
      saw_underscore = is_underscore;
274
0
    }
275
0
  }
276
0
  str.erase(dst, str.end());
277
0
}
278
279
static string ensure_valid_identifier(const string &name)
280
0
{
281
  // Functions in glslangValidator are mangled with name(<mangled> stuff.
282
  // Normally, we would never see '(' in any legal identifiers, so just strip them out.
283
0
  auto str = name.substr(0, name.find('('));
284
285
0
  if (str.empty())
286
0
    return str;
287
288
0
  if (is_numeric(str[0]))
289
0
    str[0] = '_';
290
291
0
  for (auto &c : str)
292
0
    if (!is_alphanumeric(c) && c != '_')
293
0
      c = '_';
294
295
0
  ParsedIR::sanitize_underscores(str);
296
0
  return str;
297
0
}
298
299
const string &ParsedIR::get_name(ID id) const
300
5.65k
{
301
5.65k
  auto *m = find_meta(id);
302
5.65k
  if (m)
303
3.63k
    return m->decoration.alias;
304
2.01k
  else
305
2.01k
    return empty_string;
306
5.65k
}
307
308
const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
309
0
{
310
0
  auto *m = find_meta(id);
311
0
  if (m)
312
0
  {
313
0
    if (index >= m->members.size())
314
0
      return empty_string;
315
0
    return m->members[index].alias;
316
0
  }
317
0
  else
318
0
    return empty_string;
319
0
}
320
321
void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes)
322
0
{
323
0
  if (!is_valid_identifier(name))
324
0
    name = ensure_valid_identifier(name);
325
0
  if (is_reserved_identifier(name, member, allow_reserved_prefixes))
326
0
    name = make_unreserved_identifier(name);
327
0
}
328
329
void ParsedIR::fixup_reserved_names()
330
0
{
331
0
  for (uint32_t id : meta_needing_name_fixup)
332
0
  {
333
    // Don't rename remapped variables like 'gl_LastFragDepthARM'.
334
0
    if (ids[id].get_type() == TypeVariable && get<SPIRVariable>(id).remapped_variable)
335
0
      continue;
336
337
0
    auto &m = meta[id];
338
0
    sanitize_identifier(m.decoration.alias, false, false);
339
0
    for (auto &memb : m.members)
340
0
      sanitize_identifier(memb.alias, true, false);
341
0
  }
342
0
  meta_needing_name_fixup.clear();
343
0
}
344
345
void ParsedIR::set_name(ID id, const string &name)
346
10.3k
{
347
10.3k
  auto &m = meta[id];
348
10.3k
  m.decoration.alias = name;
349
10.3k
  if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
350
3.79k
    meta_needing_name_fixup.insert(id);
351
10.3k
}
352
353
void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
354
3.39k
{
355
3.39k
  auto &m = meta[id];
356
3.39k
  m.members.resize(max(m.members.size(), size_t(index) + 1));
357
3.39k
  m.members[index].alias = name;
358
3.39k
  if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
359
2.12k
    meta_needing_name_fixup.insert(id);
360
3.39k
}
361
362
void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
363
0
{
364
0
  auto &dec = meta[id].decoration;
365
0
  dec.decoration_flags.set(decoration);
366
367
0
  switch (decoration)
368
0
  {
369
0
  case DecorationHlslSemanticGOOGLE:
370
0
    dec.hlsl_semantic = argument;
371
0
    break;
372
373
0
  case DecorationUserTypeGOOGLE:
374
0
    dec.user_type = argument;
375
0
    break;
376
377
0
  default:
378
0
    break;
379
0
  }
380
0
}
381
382
void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
383
21.1k
{
384
21.1k
  auto &dec = meta[id].decoration;
385
21.1k
  dec.decoration_flags.set(decoration);
386
387
21.1k
  switch (decoration)
388
21.1k
  {
389
1.34k
  case DecorationBuiltIn:
390
1.34k
    dec.builtin = true;
391
1.34k
    dec.builtin_type = static_cast<BuiltIn>(argument);
392
1.34k
    break;
393
394
1.12k
  case DecorationLocation:
395
1.12k
    dec.location = argument;
396
1.12k
    break;
397
398
5.38k
  case DecorationComponent:
399
5.38k
    dec.component = argument;
400
5.38k
    break;
401
402
138
  case DecorationOffset:
403
138
    dec.offset = argument;
404
138
    break;
405
406
0
  case DecorationXfbBuffer:
407
0
    dec.xfb_buffer = argument;
408
0
    break;
409
410
0
  case DecorationXfbStride:
411
0
    dec.xfb_stride = argument;
412
0
    break;
413
414
0
  case DecorationStream:
415
0
    dec.stream = argument;
416
0
    break;
417
418
7
  case DecorationArrayStride:
419
7
    dec.array_stride = argument;
420
7
    break;
421
422
0
  case DecorationMatrixStride:
423
0
    dec.matrix_stride = argument;
424
0
    break;
425
426
3.03k
  case DecorationBinding:
427
3.03k
    dec.binding = argument;
428
3.03k
    break;
429
430
1.73k
  case DecorationDescriptorSet:
431
1.73k
    dec.set = argument;
432
1.73k
    break;
433
434
0
  case DecorationInputAttachmentIndex:
435
0
    dec.input_attachment = argument;
436
0
    break;
437
438
28
  case DecorationSpecId:
439
28
    dec.spec_id = argument;
440
28
    break;
441
442
10
  case DecorationIndex:
443
10
    dec.index = argument;
444
10
    break;
445
446
0
  case DecorationHlslCounterBufferGOOGLE:
447
0
    meta[id].hlsl_magic_counter_buffer = argument;
448
0
    meta[argument].hlsl_is_magic_counter_buffer = true;
449
0
    break;
450
451
0
  case DecorationFPRoundingMode:
452
0
    dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
453
0
    break;
454
455
0
  case DecorationFPFastMathMode:
456
0
    dec.fp_fast_math_mode = static_cast<FPFastMathModeMask>(argument);
457
0
    break;
458
459
8.35k
  default:
460
8.35k
    break;
461
21.1k
  }
462
21.1k
}
463
464
void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
465
20.1k
{
466
20.1k
  auto &m = meta[id];
467
20.1k
  m.members.resize(max(m.members.size(), size_t(index) + 1));
468
20.1k
  auto &dec = m.members[index];
469
20.1k
  dec.decoration_flags.set(decoration);
470
471
20.1k
  switch (decoration)
472
20.1k
  {
473
5.60k
  case DecorationBuiltIn:
474
5.60k
    dec.builtin = true;
475
5.60k
    dec.builtin_type = static_cast<BuiltIn>(argument);
476
5.60k
    break;
477
478
0
  case DecorationLocation:
479
0
    dec.location = argument;
480
0
    break;
481
482
215
  case DecorationComponent:
483
215
    dec.component = argument;
484
215
    break;
485
486
0
  case DecorationBinding:
487
0
    dec.binding = argument;
488
0
    break;
489
490
386
  case DecorationOffset:
491
386
    dec.offset = argument;
492
386
    break;
493
494
0
  case DecorationXfbBuffer:
495
0
    dec.xfb_buffer = argument;
496
0
    break;
497
498
0
  case DecorationXfbStride:
499
0
    dec.xfb_stride = argument;
500
0
    break;
501
502
0
  case DecorationStream:
503
0
    dec.stream = argument;
504
0
    break;
505
506
2.58k
  case DecorationSpecId:
507
2.58k
    dec.spec_id = argument;
508
2.58k
    break;
509
510
0
  case DecorationMatrixStride:
511
0
    dec.matrix_stride = argument;
512
0
    break;
513
514
0
  case DecorationIndex:
515
0
    dec.index = argument;
516
0
    break;
517
518
11.3k
  default:
519
11.3k
    break;
520
20.1k
  }
521
20.1k
}
522
523
// Recursively marks any constants referenced by the specified constant instruction as being used
524
// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
525
void ParsedIR::mark_used_as_array_length(ID id)
526
2.10k
{
527
2.10k
  switch (ids[id].get_type())
528
2.10k
  {
529
2.10k
  case TypeConstant:
530
2.10k
  {
531
2.10k
    auto &c = get<SPIRConstant>(id);
532
2.10k
    c.is_used_as_array_length = true;
533
534
    // Mark composite dependencies as well.
535
2.10k
    for (auto &sub_id: c.m.id)
536
8.40k
      if (sub_id)
537
0
        mark_used_as_array_length(sub_id);
538
539
4.20k
    for (uint32_t col = 0; col < c.m.columns; col++)
540
2.10k
    {
541
2.10k
      for (auto &sub_id : c.m.c[col].id)
542
8.40k
        if (sub_id)
543
0
          mark_used_as_array_length(sub_id);
544
2.10k
    }
545
546
2.10k
    for (auto &sub_id : c.subconstants)
547
0
      if (sub_id)
548
0
        mark_used_as_array_length(sub_id);
549
2.10k
    break;
550
0
  }
551
552
1
  case TypeConstantOp:
553
1
  {
554
1
    auto &cop = get<SPIRConstantOp>(id);
555
1
    if (cop.opcode == OpCompositeExtract)
556
0
      mark_used_as_array_length(cop.arguments[0]);
557
1
    else if (cop.opcode == OpCompositeInsert)
558
0
    {
559
0
      mark_used_as_array_length(cop.arguments[0]);
560
0
      mark_used_as_array_length(cop.arguments[1]);
561
0
    }
562
1
    else
563
1
      for (uint32_t arg_id : cop.arguments)
564
0
        mark_used_as_array_length(arg_id);
565
1
    break;
566
0
  }
567
568
0
  case TypeUndef:
569
0
    break;
570
571
0
  default:
572
0
    assert(0);
573
2.10k
  }
574
2.10k
}
575
576
Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
577
0
{
578
0
  if (type.member_types.empty())
579
0
    return {};
580
581
0
  Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
582
0
  for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
583
0
    all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
584
0
  return all_members_flags;
585
0
}
586
587
Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
588
0
{
589
0
  auto &type = get<SPIRType>(var.basetype);
590
0
  if (type.basetype != SPIRType::Struct)
591
0
    SPIRV_CROSS_THROW("Cannot get buffer block flags for non-buffer variable.");
592
593
  // Some flags like non-writable, non-readable are actually found
594
  // as member decorations. If all members have a decoration set, propagate
595
  // the decoration up as a regular variable decoration.
596
0
  Bitset base_flags;
597
0
  auto *m = find_meta(var.self);
598
0
  if (m)
599
0
    base_flags = m->decoration.decoration_flags;
600
601
0
  if (type.member_types.empty())
602
0
    return base_flags;
603
604
0
  auto all_members_flags = get_buffer_block_type_flags(type);
605
0
  base_flags.merge_or(all_members_flags);
606
0
  return base_flags;
607
0
}
608
609
const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
610
0
{
611
0
  auto *m = find_meta(id);
612
0
  if (m)
613
0
  {
614
0
    if (index >= m->members.size())
615
0
      return cleared_bitset;
616
0
    return m->members[index].decoration_flags;
617
0
  }
618
0
  else
619
0
    return cleared_bitset;
620
0
}
621
622
bool ParsedIR::has_decoration(ID id, Decoration decoration) const
623
0
{
624
0
  return get_decoration_bitset(id).get(decoration);
625
0
}
626
627
uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
628
19.8k
{
629
19.8k
  auto *m = find_meta(id);
630
19.8k
  if (!m)
631
0
    return 0;
632
633
19.8k
  auto &dec = m->decoration;
634
19.8k
  if (!dec.decoration_flags.get(decoration))
635
0
    return 0;
636
637
19.8k
  switch (decoration)
638
19.8k
  {
639
5.60k
  case DecorationBuiltIn:
640
5.60k
    return dec.builtin_type;
641
13
  case DecorationLocation:
642
13
    return dec.location;
643
13
  case DecorationComponent:
644
13
    return dec.component;
645
136
  case DecorationOffset:
646
136
    return dec.offset;
647
0
  case DecorationXfbBuffer:
648
0
    return dec.xfb_buffer;
649
0
  case DecorationXfbStride:
650
0
    return dec.xfb_stride;
651
0
  case DecorationStream:
652
0
    return dec.stream;
653
13
  case DecorationBinding:
654
13
    return dec.binding;
655
4.00k
  case DecorationDescriptorSet:
656
4.00k
    return dec.set;
657
0
  case DecorationInputAttachmentIndex:
658
0
    return dec.input_attachment;
659
2.59k
  case DecorationSpecId:
660
2.59k
    return dec.spec_id;
661
0
  case DecorationArrayStride:
662
0
    return dec.array_stride;
663
0
  case DecorationMatrixStride:
664
0
    return dec.matrix_stride;
665
8
  case DecorationIndex:
666
8
    return dec.index;
667
0
  case DecorationFPRoundingMode:
668
0
    return dec.fp_rounding_mode;
669
0
  case DecorationFPFastMathMode:
670
0
    return dec.fp_fast_math_mode;
671
7.45k
  default:
672
7.45k
    return 1;
673
19.8k
  }
674
19.8k
}
675
676
const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
677
0
{
678
0
  auto *m = find_meta(id);
679
0
  if (!m)
680
0
    return empty_string;
681
682
0
  auto &dec = m->decoration;
683
684
0
  if (!dec.decoration_flags.get(decoration))
685
0
    return empty_string;
686
687
0
  switch (decoration)
688
0
  {
689
0
  case DecorationHlslSemanticGOOGLE:
690
0
    return dec.hlsl_semantic;
691
692
0
  case DecorationUserTypeGOOGLE:
693
0
    return dec.user_type;
694
695
0
  default:
696
0
    return empty_string;
697
0
  }
698
0
}
699
700
void ParsedIR::unset_decoration(ID id, Decoration decoration)
701
0
{
702
0
  auto &dec = meta[id].decoration;
703
0
  dec.decoration_flags.clear(decoration);
704
0
  switch (decoration)
705
0
  {
706
0
  case DecorationBuiltIn:
707
0
    dec.builtin = false;
708
0
    break;
709
710
0
  case DecorationLocation:
711
0
    dec.location = 0;
712
0
    break;
713
714
0
  case DecorationComponent:
715
0
    dec.component = 0;
716
0
    break;
717
718
0
  case DecorationOffset:
719
0
    dec.offset = 0;
720
0
    break;
721
722
0
  case DecorationXfbBuffer:
723
0
    dec.xfb_buffer = 0;
724
0
    break;
725
726
0
  case DecorationXfbStride:
727
0
    dec.xfb_stride = 0;
728
0
    break;
729
730
0
  case DecorationStream:
731
0
    dec.stream = 0;
732
0
    break;
733
734
0
  case DecorationBinding:
735
0
    dec.binding = 0;
736
0
    break;
737
738
0
  case DecorationDescriptorSet:
739
0
    dec.set = 0;
740
0
    break;
741
742
0
  case DecorationInputAttachmentIndex:
743
0
    dec.input_attachment = 0;
744
0
    break;
745
746
0
  case DecorationSpecId:
747
0
    dec.spec_id = 0;
748
0
    break;
749
750
0
  case DecorationHlslSemanticGOOGLE:
751
0
    dec.hlsl_semantic.clear();
752
0
    break;
753
754
0
  case DecorationFPRoundingMode:
755
0
    dec.fp_rounding_mode = FPRoundingModeMax;
756
0
    break;
757
758
0
  case DecorationFPFastMathMode:
759
0
    dec.fp_fast_math_mode = FPFastMathModeMaskNone;
760
0
    break;
761
762
0
  case DecorationHlslCounterBufferGOOGLE:
763
0
  {
764
0
    auto &counter = meta[id].hlsl_magic_counter_buffer;
765
0
    if (counter)
766
0
    {
767
0
      meta[counter].hlsl_is_magic_counter_buffer = false;
768
0
      counter = 0;
769
0
    }
770
0
    break;
771
0
  }
772
773
0
  default:
774
0
    break;
775
0
  }
776
0
}
777
778
bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
779
0
{
780
0
  return get_member_decoration_bitset(id, index).get(decoration);
781
0
}
782
783
uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
784
0
{
785
0
  auto *m = find_meta(id);
786
0
  if (!m)
787
0
    return 0;
788
789
0
  if (index >= m->members.size())
790
0
    return 0;
791
792
0
  auto &dec = m->members[index];
793
0
  if (!dec.decoration_flags.get(decoration))
794
0
    return 0;
795
796
0
  switch (decoration)
797
0
  {
798
0
  case DecorationBuiltIn:
799
0
    return dec.builtin_type;
800
0
  case DecorationLocation:
801
0
    return dec.location;
802
0
  case DecorationComponent:
803
0
    return dec.component;
804
0
  case DecorationBinding:
805
0
    return dec.binding;
806
0
  case DecorationOffset:
807
0
    return dec.offset;
808
0
  case DecorationXfbBuffer:
809
0
    return dec.xfb_buffer;
810
0
  case DecorationXfbStride:
811
0
    return dec.xfb_stride;
812
0
  case DecorationStream:
813
0
    return dec.stream;
814
0
  case DecorationSpecId:
815
0
    return dec.spec_id;
816
0
  case DecorationMatrixStride:
817
0
    return dec.matrix_stride;
818
0
  case DecorationIndex:
819
0
    return dec.index;
820
0
  default:
821
0
    return 1;
822
0
  }
823
0
}
824
825
const Bitset &ParsedIR::get_decoration_bitset(ID id) const
826
0
{
827
0
  auto *m = find_meta(id);
828
0
  if (m)
829
0
  {
830
0
    auto &dec = m->decoration;
831
0
    return dec.decoration_flags;
832
0
  }
833
0
  else
834
0
    return cleared_bitset;
835
0
}
836
837
void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
838
0
{
839
0
  auto &m = meta[id];
840
0
  m.members.resize(max(m.members.size(), size_t(index) + 1));
841
0
  auto &dec = meta[id].members[index];
842
0
  dec.decoration_flags.set(decoration);
843
844
0
  switch (decoration)
845
0
  {
846
0
  case DecorationHlslSemanticGOOGLE:
847
0
    dec.hlsl_semantic = argument;
848
0
    break;
849
850
0
  default:
851
0
    break;
852
0
  }
853
0
}
854
855
const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
856
0
{
857
0
  auto *m = find_meta(id);
858
0
  if (m)
859
0
  {
860
0
    if (!has_member_decoration(id, index, decoration))
861
0
      return empty_string;
862
863
0
    auto &dec = m->members[index];
864
865
0
    switch (decoration)
866
0
    {
867
0
    case DecorationHlslSemanticGOOGLE:
868
0
      return dec.hlsl_semantic;
869
870
0
    default:
871
0
      return empty_string;
872
0
    }
873
0
  }
874
0
  else
875
0
    return empty_string;
876
0
}
877
878
void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
879
0
{
880
0
  auto &m = meta[id];
881
0
  if (index >= m.members.size())
882
0
    return;
883
884
0
  auto &dec = m.members[index];
885
886
0
  dec.decoration_flags.clear(decoration);
887
0
  switch (decoration)
888
0
  {
889
0
  case DecorationBuiltIn:
890
0
    dec.builtin = false;
891
0
    break;
892
893
0
  case DecorationLocation:
894
0
    dec.location = 0;
895
0
    break;
896
897
0
  case DecorationComponent:
898
0
    dec.component = 0;
899
0
    break;
900
901
0
  case DecorationOffset:
902
0
    dec.offset = 0;
903
0
    break;
904
905
0
  case DecorationXfbBuffer:
906
0
    dec.xfb_buffer = 0;
907
0
    break;
908
909
0
  case DecorationXfbStride:
910
0
    dec.xfb_stride = 0;
911
0
    break;
912
913
0
  case DecorationStream:
914
0
    dec.stream = 0;
915
0
    break;
916
917
0
  case DecorationSpecId:
918
0
    dec.spec_id = 0;
919
0
    break;
920
921
0
  case DecorationHlslSemanticGOOGLE:
922
0
    dec.hlsl_semantic.clear();
923
0
    break;
924
925
0
  default:
926
0
    break;
927
0
  }
928
0
}
929
930
uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
931
41.8k
{
932
41.8k
  auto curr_bound = ids.size();
933
41.8k
  auto new_bound = curr_bound + incr_amount;
934
935
41.8k
  ids.reserve(ids.size() + incr_amount);
936
85.4k
  for (uint32_t i = 0; i < incr_amount; i++)
937
43.6k
    ids.emplace_back(pool_group.get());
938
939
41.8k
  block_meta.resize(new_bound);
940
41.8k
  return uint32_t(curr_bound);
941
41.8k
}
942
943
void ParsedIR::remove_typed_id(Types type, ID id)
944
7
{
945
7
  auto &type_ids = ids_for_type[type];
946
7
  type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
947
7
}
948
949
void ParsedIR::reset_all_of_type(Types type)
950
0
{
951
0
  for (auto &id : ids_for_type[type])
952
0
    if (ids[id].get_type() == type)
953
0
      ids[id].reset();
954
955
0
  ids_for_type[type].clear();
956
0
}
957
958
void ParsedIR::add_typed_id(Types type, ID id)
959
344k
{
960
344k
  assert(id < ids.size());
961
962
344k
  if (loop_iteration_depth_hard != 0)
963
0
    SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
964
965
344k
  if (loop_iteration_depth_soft != 0)
966
0
  {
967
0
    if (!ids[id].empty())
968
0
      SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
969
0
    return;
970
0
  }
971
972
344k
  if (ids[id].empty() || ids[id].get_type() != type)
973
55.4k
  {
974
55.4k
    switch (type)
975
55.4k
    {
976
46.1k
    case TypeConstant:
977
46.1k
      ids_for_constant_or_variable.push_back(id);
978
46.1k
      ids_for_constant_undef_or_type.push_back(id);
979
46.1k
      break;
980
981
2.29k
    case TypeVariable:
982
2.29k
      ids_for_constant_or_variable.push_back(id);
983
2.29k
      break;
984
985
2.15k
    case TypeType:
986
2.15k
    case TypeConstantOp:
987
2.17k
    case TypeUndef:
988
2.17k
      ids_for_constant_undef_or_type.push_back(id);
989
2.17k
      break;
990
991
4.79k
    default:
992
4.79k
      break;
993
55.4k
    }
994
55.4k
  }
995
996
344k
  if (ids[id].empty())
997
55.4k
  {
998
55.4k
    ids_for_type[type].push_back(id);
999
55.4k
  }
1000
288k
  else if (ids[id].get_type() != type)
1001
7
  {
1002
7
    remove_typed_id(ids[id].get_type(), id);
1003
7
    ids_for_type[type].push_back(id);
1004
7
  }
1005
344k
}
1006
1007
const Meta *ParsedIR::find_meta(ID id) const
1008
25.4k
{
1009
25.4k
  auto itr = meta.find(id);
1010
25.4k
  if (itr != end(meta))
1011
23.4k
    return &itr->second;
1012
2.01k
  else
1013
2.01k
    return nullptr;
1014
25.4k
}
1015
1016
Meta *ParsedIR::find_meta(ID id)
1017
0
{
1018
0
  auto itr = meta.find(id);
1019
0
  if (itr != end(meta))
1020
0
    return &itr->second;
1021
0
  else
1022
0
    return nullptr;
1023
0
}
1024
1025
ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
1026
0
{
1027
0
  return ParsedIR::LoopLock(&loop_iteration_depth_hard);
1028
0
}
1029
1030
ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
1031
0
{
1032
0
  return ParsedIR::LoopLock(&loop_iteration_depth_soft);
1033
0
}
1034
1035
ParsedIR::LoopLock::~LoopLock()
1036
0
{
1037
0
  if (lock)
1038
0
    (*lock)--;
1039
0
}
1040
1041
ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
1042
0
    : lock(lock_)
1043
0
{
1044
0
  if (lock)
1045
0
    (*lock)++;
1046
0
}
1047
1048
ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1049
0
{
1050
0
  *this = std::move(other);
1051
0
}
1052
1053
ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1054
0
{
1055
0
  if (lock)
1056
0
    (*lock)--;
1057
0
  lock = other.lock;
1058
0
  other.lock = nullptr;
1059
0
  return *this;
1060
0
}
1061
1062
void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
1063
85.4k
{
1064
85.4k
  assert(id < ids.size());
1065
1066
85.4k
  auto &constant_type = get<SPIRType>(type);
1067
1068
85.4k
  if (constant_type.pointer)
1069
0
  {
1070
0
    if (add_to_typed_id_set)
1071
0
      add_typed_id(TypeConstant, id);
1072
0
    auto &constant = variant_set<SPIRConstant>(ids[id], type);
1073
0
    constant.self = id;
1074
0
    constant.make_null(constant_type);
1075
0
  }
1076
85.4k
  else if (!constant_type.array.empty())
1077
40.9k
  {
1078
40.9k
    assert(constant_type.parent_type);
1079
40.9k
    uint32_t parent_id = increase_bound_by(1);
1080
40.9k
    make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
1081
1082
    // The array size of OpConstantNull can be either literal or specialization constant.
1083
    // In the latter case, we cannot take the value as-is, as it can be changed to anything.
1084
    // Rather, we assume it to be *one* for the sake of initializer.
1085
40.9k
    bool is_literal_array_size = constant_type.array_size_literal.back();
1086
40.9k
    uint32_t count = is_literal_array_size ? constant_type.array.back() : 1;
1087
1088
40.9k
    SmallVector<uint32_t> elements(count);
1089
50.1M
    for (uint32_t i = 0; i < count; i++)
1090
50.1M
      elements[i] = parent_id;
1091
1092
40.9k
    if (add_to_typed_id_set)
1093
40.9k
      add_typed_id(TypeConstant, id);
1094
40.9k
    auto& constant = variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false);
1095
40.9k
    constant.self = id;
1096
40.9k
    constant.is_null_array_specialized_length = !is_literal_array_size;
1097
40.9k
  }
1098
44.4k
  else if (!constant_type.member_types.empty())
1099
871
  {
1100
871
    uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
1101
871
    SmallVector<uint32_t> elements(constant_type.member_types.size());
1102
3.48k
    for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
1103
2.61k
    {
1104
2.61k
      make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
1105
2.61k
      elements[i] = member_ids + i;
1106
2.61k
    }
1107
1108
871
    if (add_to_typed_id_set)
1109
871
      add_typed_id(TypeConstant, id);
1110
871
    variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1111
871
  }
1112
43.6k
  else
1113
43.6k
  {
1114
43.6k
    if (add_to_typed_id_set)
1115
43.6k
      add_typed_id(TypeConstant, id);
1116
43.6k
    auto &constant = variant_set<SPIRConstant>(ids[id], type);
1117
43.6k
    constant.self = id;
1118
43.6k
    constant.make_null(constant_type);
1119
43.6k
  }
1120
85.4k
}
1121
1122
} // namespace SPIRV_CROSS_NAMESPACE