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
28using namespace std;
29using namespace spv;
30
31namespace SPIRV_CROSS_NAMESPACE
32{
33ParsedIR::ParsedIR()
34{
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 pool_group.reset(new ObjectPoolGroup);
38
39 pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>);
40 pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>);
41 pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>);
42 pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>);
43 pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>);
44 pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>);
45 pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>);
46 pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>);
47 pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>);
48 pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>);
49 pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
50 pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
51 pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
52}
53
54// Should have been default-implemented, but need this on MSVC 2013.
55ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
56{
57 *this = move(other);
58}
59
60ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
61{
62 if (this != &other)
63 {
64 pool_group = move(other.pool_group);
65 spirv = move(other.spirv);
66 meta = move(other.meta);
67 for (int i = 0; i < TypeCount; i++)
68 ids_for_type[i] = move(other.ids_for_type[i]);
69 ids_for_constant_or_type = move(other.ids_for_constant_or_type);
70 ids_for_constant_or_variable = move(other.ids_for_constant_or_variable);
71 declared_capabilities = move(other.declared_capabilities);
72 declared_extensions = move(other.declared_extensions);
73 block_meta = move(other.block_meta);
74 continue_block_to_loop_header = move(other.continue_block_to_loop_header);
75 entry_points = move(other.entry_points);
76 ids = move(other.ids);
77 addressing_model = other.addressing_model;
78 memory_model = other.memory_model;
79
80 default_entry_point = other.default_entry_point;
81 source = other.source;
82 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
83 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
84
85 meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
86 load_type_width = std::move(other.load_type_width);
87 }
88 return *this;
89}
90
91ParsedIR::ParsedIR(const ParsedIR &other)
92 : ParsedIR()
93{
94 *this = other;
95}
96
97ParsedIR &ParsedIR::operator=(const ParsedIR &other)
98{
99 if (this != &other)
100 {
101 spirv = other.spirv;
102 meta = other.meta;
103 for (int i = 0; i < TypeCount; i++)
104 ids_for_type[i] = other.ids_for_type[i];
105 ids_for_constant_or_type = other.ids_for_constant_or_type;
106 ids_for_constant_or_variable = other.ids_for_constant_or_variable;
107 declared_capabilities = other.declared_capabilities;
108 declared_extensions = other.declared_extensions;
109 block_meta = other.block_meta;
110 continue_block_to_loop_header = other.continue_block_to_loop_header;
111 entry_points = other.entry_points;
112 default_entry_point = other.default_entry_point;
113 source = other.source;
114 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
115 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
116 addressing_model = other.addressing_model;
117 memory_model = other.memory_model;
118
119
120 meta_needing_name_fixup = other.meta_needing_name_fixup;
121 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 ids.clear();
126 ids.reserve(other.ids.size());
127 for (size_t i = 0; i < other.ids.size(); i++)
128 {
129 ids.emplace_back(pool_group.get());
130 ids.back() = other.ids[i];
131 }
132 }
133 return *this;
134}
135
136void ParsedIR::set_id_bounds(uint32_t bounds)
137{
138 ids.reserve(bounds);
139 while (ids.size() < bounds)
140 ids.emplace_back(pool_group.get());
141
142 block_meta.resize(bounds);
143}
144
145// Roll our own versions of these functions to avoid potential locale shenanigans.
146static bool is_alpha(char c)
147{
148 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
149}
150
151static bool is_numeric(char c)
152{
153 return c >= '0' && c <= '9';
154}
155
156static bool is_alphanumeric(char c)
157{
158 return is_alpha(c) || is_numeric(c);
159}
160
161static bool is_valid_identifier(const string &name)
162{
163 if (name.empty())
164 return true;
165
166 if (is_numeric(name[0]))
167 return false;
168
169 for (auto c : name)
170 if (!is_alphanumeric(c) && c != '_')
171 return false;
172
173 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 for (auto c : name)
177 {
178 bool is_underscore = c == '_';
179 if (is_underscore && saw_underscore)
180 return false;
181 saw_underscore = is_underscore;
182 }
183
184 return true;
185}
186
187static bool is_reserved_prefix(const string &name)
188{
189 // Generic reserved identifiers used by the implementation.
190 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 name.compare(0, 3, "spv", 3) == 0;
194}
195
196static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes)
197{
198 if (!allow_reserved_prefixes && is_reserved_prefix(name))
199 return true;
200
201 if (member)
202 {
203 // Reserved member identifiers come in one form:
204 // _m[0-9]+$.
205 if (name.size() < 3)
206 return false;
207
208 if (name.compare(0, 2, "_m", 2) != 0)
209 return false;
210
211 size_t index = 2;
212 while (index < name.size() && is_numeric(name[index]))
213 index++;
214
215 return index == name.size();
216 }
217 else
218 {
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 if (name.size() < 2)
223 return false;
224
225 if (name[0] != '_' || !is_numeric(name[1]))
226 return false;
227
228 size_t index = 2;
229 while (index < name.size() && is_numeric(name[index]))
230 index++;
231
232 return index == name.size() || (index < name.size() && name[index] == '_');
233 }
234}
235
236bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes)
237{
238 return is_reserved_identifier(str, false, allow_reserved_prefixes);
239}
240
241uint32_t ParsedIR::get_spirv_version() const
242{
243 return spirv[1];
244}
245
246static string make_unreserved_identifier(const string &name)
247{
248 if (is_reserved_prefix(name))
249 return "_RESERVED_IDENTIFIER_FIXUP_" + name;
250 else
251 return "_RESERVED_IDENTIFIER_FIXUP" + name;
252}
253
254void ParsedIR::sanitize_underscores(std::string &str)
255{
256 // Compact adjacent underscores to make it valid.
257 auto dst = str.begin();
258 auto src = dst;
259 bool saw_underscore = false;
260 while (src != str.end())
261 {
262 bool is_underscore = *src == '_';
263 if (saw_underscore && is_underscore)
264 {
265 src++;
266 }
267 else
268 {
269 if (dst != src)
270 *dst = *src;
271 dst++;
272 src++;
273 saw_underscore = is_underscore;
274 }
275 }
276 str.erase(dst, str.end());
277}
278
279static string ensure_valid_identifier(const string &name)
280{
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 auto str = name.substr(0, name.find('('));
284
285 if (str.empty())
286 return str;
287
288 if (is_numeric(str[0]))
289 str[0] = '_';
290
291 for (auto &c : str)
292 if (!is_alphanumeric(c) && c != '_')
293 c = '_';
294
295 ParsedIR::sanitize_underscores(str);
296 return str;
297}
298
299const string &ParsedIR::get_name(ID id) const
300{
301 auto *m = find_meta(id);
302 if (m)
303 return m->decoration.alias;
304 else
305 return empty_string;
306}
307
308const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
309{
310 auto *m = find_meta(id);
311 if (m)
312 {
313 if (index >= m->members.size())
314 return empty_string;
315 return m->members[index].alias;
316 }
317 else
318 return empty_string;
319}
320
321void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes)
322{
323 if (!is_valid_identifier(name))
324 name = ensure_valid_identifier(name);
325 if (is_reserved_identifier(name, member, allow_reserved_prefixes))
326 name = make_unreserved_identifier(name);
327}
328
329void ParsedIR::fixup_reserved_names()
330{
331 for (uint32_t id : meta_needing_name_fixup)
332 {
333 auto &m = meta[id];
334 sanitize_identifier(m.decoration.alias, false, false);
335 for (auto &memb : m.members)
336 sanitize_identifier(memb.alias, true, false);
337 }
338 meta_needing_name_fixup.clear();
339}
340
341void ParsedIR::set_name(ID id, const string &name)
342{
343 auto &m = meta[id];
344 m.decoration.alias = name;
345 if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
346 meta_needing_name_fixup.insert(id);
347}
348
349void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
350{
351 auto &m = meta[id];
352 m.members.resize(max(meta[id].members.size(), size_t(index) + 1));
353 m.members[index].alias = name;
354 if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
355 meta_needing_name_fixup.insert(id);
356}
357
358void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
359{
360 auto &dec = meta[id].decoration;
361 dec.decoration_flags.set(decoration);
362
363 switch (decoration)
364 {
365 case DecorationHlslSemanticGOOGLE:
366 dec.hlsl_semantic = argument;
367 break;
368
369 default:
370 break;
371 }
372}
373
374void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
375{
376 auto &dec = meta[id].decoration;
377 dec.decoration_flags.set(decoration);
378
379 switch (decoration)
380 {
381 case DecorationBuiltIn:
382 dec.builtin = true;
383 dec.builtin_type = static_cast<BuiltIn>(argument);
384 break;
385
386 case DecorationLocation:
387 dec.location = argument;
388 break;
389
390 case DecorationComponent:
391 dec.component = argument;
392 break;
393
394 case DecorationOffset:
395 dec.offset = argument;
396 break;
397
398 case DecorationXfbBuffer:
399 dec.xfb_buffer = argument;
400 break;
401
402 case DecorationXfbStride:
403 dec.xfb_stride = argument;
404 break;
405
406 case DecorationStream:
407 dec.stream = argument;
408 break;
409
410 case DecorationArrayStride:
411 dec.array_stride = argument;
412 break;
413
414 case DecorationMatrixStride:
415 dec.matrix_stride = argument;
416 break;
417
418 case DecorationBinding:
419 dec.binding = argument;
420 break;
421
422 case DecorationDescriptorSet:
423 dec.set = argument;
424 break;
425
426 case DecorationInputAttachmentIndex:
427 dec.input_attachment = argument;
428 break;
429
430 case DecorationSpecId:
431 dec.spec_id = argument;
432 break;
433
434 case DecorationIndex:
435 dec.index = argument;
436 break;
437
438 case DecorationHlslCounterBufferGOOGLE:
439 meta[id].hlsl_magic_counter_buffer = argument;
440 meta[argument].hlsl_is_magic_counter_buffer = true;
441 break;
442
443 case DecorationFPRoundingMode:
444 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
445 break;
446
447 default:
448 break;
449 }
450}
451
452void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
453{
454 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
455 auto &dec = meta[id].members[index];
456 dec.decoration_flags.set(decoration);
457
458 switch (decoration)
459 {
460 case DecorationBuiltIn:
461 dec.builtin = true;
462 dec.builtin_type = static_cast<BuiltIn>(argument);
463 break;
464
465 case DecorationLocation:
466 dec.location = argument;
467 break;
468
469 case DecorationComponent:
470 dec.component = argument;
471 break;
472
473 case DecorationBinding:
474 dec.binding = argument;
475 break;
476
477 case DecorationOffset:
478 dec.offset = argument;
479 break;
480
481 case DecorationXfbBuffer:
482 dec.xfb_buffer = argument;
483 break;
484
485 case DecorationXfbStride:
486 dec.xfb_stride = argument;
487 break;
488
489 case DecorationStream:
490 dec.stream = argument;
491 break;
492
493 case DecorationSpecId:
494 dec.spec_id = argument;
495 break;
496
497 case DecorationMatrixStride:
498 dec.matrix_stride = argument;
499 break;
500
501 case DecorationIndex:
502 dec.index = argument;
503 break;
504
505 default:
506 break;
507 }
508}
509
510// Recursively marks any constants referenced by the specified constant instruction as being used
511// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
512void ParsedIR::mark_used_as_array_length(ID id)
513{
514 switch (ids[id].get_type())
515 {
516 case TypeConstant:
517 get<SPIRConstant>(id).is_used_as_array_length = true;
518 break;
519
520 case TypeConstantOp:
521 {
522 auto &cop = get<SPIRConstantOp>(id);
523 if (cop.opcode == OpCompositeExtract)
524 mark_used_as_array_length(cop.arguments[0]);
525 else if (cop.opcode == OpCompositeInsert)
526 {
527 mark_used_as_array_length(cop.arguments[0]);
528 mark_used_as_array_length(cop.arguments[1]);
529 }
530 else
531 for (uint32_t arg_id : cop.arguments)
532 mark_used_as_array_length(arg_id);
533 break;
534 }
535
536 case TypeUndef:
537 break;
538
539 default:
540 assert(0);
541 }
542}
543
544Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
545{
546 if (type.member_types.empty())
547 return {};
548
549 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
550 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
551 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
552 return all_members_flags;
553}
554
555Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
556{
557 auto &type = get<SPIRType>(var.basetype);
558 assert(type.basetype == SPIRType::Struct);
559
560 // Some flags like non-writable, non-readable are actually found
561 // as member decorations. If all members have a decoration set, propagate
562 // the decoration up as a regular variable decoration.
563 Bitset base_flags;
564 auto *m = find_meta(var.self);
565 if (m)
566 base_flags = m->decoration.decoration_flags;
567
568 if (type.member_types.empty())
569 return base_flags;
570
571 auto all_members_flags = get_buffer_block_type_flags(type);
572 base_flags.merge_or(all_members_flags);
573 return base_flags;
574}
575
576const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
577{
578 auto *m = find_meta(id);
579 if (m)
580 {
581 if (index >= m->members.size())
582 return cleared_bitset;
583 return m->members[index].decoration_flags;
584 }
585 else
586 return cleared_bitset;
587}
588
589bool ParsedIR::has_decoration(ID id, Decoration decoration) const
590{
591 return get_decoration_bitset(id).get(decoration);
592}
593
594uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
595{
596 auto *m = find_meta(id);
597 if (!m)
598 return 0;
599
600 auto &dec = m->decoration;
601 if (!dec.decoration_flags.get(decoration))
602 return 0;
603
604 switch (decoration)
605 {
606 case DecorationBuiltIn:
607 return dec.builtin_type;
608 case DecorationLocation:
609 return dec.location;
610 case DecorationComponent:
611 return dec.component;
612 case DecorationOffset:
613 return dec.offset;
614 case DecorationXfbBuffer:
615 return dec.xfb_buffer;
616 case DecorationXfbStride:
617 return dec.xfb_stride;
618 case DecorationStream:
619 return dec.stream;
620 case DecorationBinding:
621 return dec.binding;
622 case DecorationDescriptorSet:
623 return dec.set;
624 case DecorationInputAttachmentIndex:
625 return dec.input_attachment;
626 case DecorationSpecId:
627 return dec.spec_id;
628 case DecorationArrayStride:
629 return dec.array_stride;
630 case DecorationMatrixStride:
631 return dec.matrix_stride;
632 case DecorationIndex:
633 return dec.index;
634 case DecorationFPRoundingMode:
635 return dec.fp_rounding_mode;
636 default:
637 return 1;
638 }
639}
640
641const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
642{
643 auto *m = find_meta(id);
644 if (!m)
645 return empty_string;
646
647 auto &dec = m->decoration;
648
649 if (!dec.decoration_flags.get(decoration))
650 return empty_string;
651
652 switch (decoration)
653 {
654 case DecorationHlslSemanticGOOGLE:
655 return dec.hlsl_semantic;
656
657 default:
658 return empty_string;
659 }
660}
661
662void ParsedIR::unset_decoration(ID id, Decoration decoration)
663{
664 auto &dec = meta[id].decoration;
665 dec.decoration_flags.clear(decoration);
666 switch (decoration)
667 {
668 case DecorationBuiltIn:
669 dec.builtin = false;
670 break;
671
672 case DecorationLocation:
673 dec.location = 0;
674 break;
675
676 case DecorationComponent:
677 dec.component = 0;
678 break;
679
680 case DecorationOffset:
681 dec.offset = 0;
682 break;
683
684 case DecorationXfbBuffer:
685 dec.xfb_buffer = 0;
686 break;
687
688 case DecorationXfbStride:
689 dec.xfb_stride = 0;
690 break;
691
692 case DecorationStream:
693 dec.stream = 0;
694 break;
695
696 case DecorationBinding:
697 dec.binding = 0;
698 break;
699
700 case DecorationDescriptorSet:
701 dec.set = 0;
702 break;
703
704 case DecorationInputAttachmentIndex:
705 dec.input_attachment = 0;
706 break;
707
708 case DecorationSpecId:
709 dec.spec_id = 0;
710 break;
711
712 case DecorationHlslSemanticGOOGLE:
713 dec.hlsl_semantic.clear();
714 break;
715
716 case DecorationFPRoundingMode:
717 dec.fp_rounding_mode = FPRoundingModeMax;
718 break;
719
720 case DecorationHlslCounterBufferGOOGLE:
721 {
722 auto &counter = meta[id].hlsl_magic_counter_buffer;
723 if (counter)
724 {
725 meta[counter].hlsl_is_magic_counter_buffer = false;
726 counter = 0;
727 }
728 break;
729 }
730
731 default:
732 break;
733 }
734}
735
736bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
737{
738 return get_member_decoration_bitset(id, index).get(decoration);
739}
740
741uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
742{
743 auto *m = find_meta(id);
744 if (!m)
745 return 0;
746
747 if (index >= m->members.size())
748 return 0;
749
750 auto &dec = m->members[index];
751 if (!dec.decoration_flags.get(decoration))
752 return 0;
753
754 switch (decoration)
755 {
756 case DecorationBuiltIn:
757 return dec.builtin_type;
758 case DecorationLocation:
759 return dec.location;
760 case DecorationComponent:
761 return dec.component;
762 case DecorationBinding:
763 return dec.binding;
764 case DecorationOffset:
765 return dec.offset;
766 case DecorationXfbBuffer:
767 return dec.xfb_buffer;
768 case DecorationXfbStride:
769 return dec.xfb_stride;
770 case DecorationStream:
771 return dec.stream;
772 case DecorationSpecId:
773 return dec.spec_id;
774 case DecorationIndex:
775 return dec.index;
776 default:
777 return 1;
778 }
779}
780
781const Bitset &ParsedIR::get_decoration_bitset(ID id) const
782{
783 auto *m = find_meta(id);
784 if (m)
785 {
786 auto &dec = m->decoration;
787 return dec.decoration_flags;
788 }
789 else
790 return cleared_bitset;
791}
792
793void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
794{
795 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
796 auto &dec = meta[id].members[index];
797 dec.decoration_flags.set(decoration);
798
799 switch (decoration)
800 {
801 case DecorationHlslSemanticGOOGLE:
802 dec.hlsl_semantic = argument;
803 break;
804
805 default:
806 break;
807 }
808}
809
810const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
811{
812 auto *m = find_meta(id);
813 if (m)
814 {
815 if (!has_member_decoration(id, index, decoration))
816 return empty_string;
817
818 auto &dec = m->members[index];
819
820 switch (decoration)
821 {
822 case DecorationHlslSemanticGOOGLE:
823 return dec.hlsl_semantic;
824
825 default:
826 return empty_string;
827 }
828 }
829 else
830 return empty_string;
831}
832
833void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
834{
835 auto &m = meta[id];
836 if (index >= m.members.size())
837 return;
838
839 auto &dec = m.members[index];
840
841 dec.decoration_flags.clear(decoration);
842 switch (decoration)
843 {
844 case DecorationBuiltIn:
845 dec.builtin = false;
846 break;
847
848 case DecorationLocation:
849 dec.location = 0;
850 break;
851
852 case DecorationComponent:
853 dec.component = 0;
854 break;
855
856 case DecorationOffset:
857 dec.offset = 0;
858 break;
859
860 case DecorationXfbBuffer:
861 dec.xfb_buffer = 0;
862 break;
863
864 case DecorationXfbStride:
865 dec.xfb_stride = 0;
866 break;
867
868 case DecorationStream:
869 dec.stream = 0;
870 break;
871
872 case DecorationSpecId:
873 dec.spec_id = 0;
874 break;
875
876 case DecorationHlslSemanticGOOGLE:
877 dec.hlsl_semantic.clear();
878 break;
879
880 default:
881 break;
882 }
883}
884
885uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
886{
887 auto curr_bound = ids.size();
888 auto new_bound = curr_bound + incr_amount;
889
890 ids.reserve(ids.size() + incr_amount);
891 for (uint32_t i = 0; i < incr_amount; i++)
892 ids.emplace_back(pool_group.get());
893
894 block_meta.resize(new_bound);
895 return uint32_t(curr_bound);
896}
897
898void ParsedIR::remove_typed_id(Types type, ID id)
899{
900 auto &type_ids = ids_for_type[type];
901 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
902}
903
904void ParsedIR::reset_all_of_type(Types type)
905{
906 for (auto &id : ids_for_type[type])
907 if (ids[id].get_type() == type)
908 ids[id].reset();
909
910 ids_for_type[type].clear();
911}
912
913void ParsedIR::add_typed_id(Types type, ID id)
914{
915 if (loop_iteration_depth_hard != 0)
916 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
917
918 if (loop_iteration_depth_soft != 0)
919 {
920 if (!ids[id].empty())
921 SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
922 return;
923 }
924
925 if (ids[id].empty() || ids[id].get_type() != type)
926 {
927 switch (type)
928 {
929 case TypeConstant:
930 ids_for_constant_or_variable.push_back(id);
931 ids_for_constant_or_type.push_back(id);
932 break;
933
934 case TypeVariable:
935 ids_for_constant_or_variable.push_back(id);
936 break;
937
938 case TypeType:
939 case TypeConstantOp:
940 ids_for_constant_or_type.push_back(id);
941 break;
942
943 default:
944 break;
945 }
946 }
947
948 if (ids[id].empty())
949 {
950 ids_for_type[type].push_back(id);
951 }
952 else if (ids[id].get_type() != type)
953 {
954 remove_typed_id(ids[id].get_type(), id);
955 ids_for_type[type].push_back(id);
956 }
957}
958
959const Meta *ParsedIR::find_meta(ID id) const
960{
961 auto itr = meta.find(id);
962 if (itr != end(meta))
963 return &itr->second;
964 else
965 return nullptr;
966}
967
968Meta *ParsedIR::find_meta(ID id)
969{
970 auto itr = meta.find(id);
971 if (itr != end(meta))
972 return &itr->second;
973 else
974 return nullptr;
975}
976
977ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
978{
979 return ParsedIR::LoopLock(&loop_iteration_depth_hard);
980}
981
982ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
983{
984 return ParsedIR::LoopLock(&loop_iteration_depth_soft);
985}
986
987ParsedIR::LoopLock::~LoopLock()
988{
989 if (lock)
990 (*lock)--;
991}
992
993ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
994 : lock(lock_)
995{
996 if (lock)
997 (*lock)++;
998}
999
1000ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1001{
1002 *this = move(other);
1003}
1004
1005ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1006{
1007 if (lock)
1008 (*lock)--;
1009 lock = other.lock;
1010 other.lock = nullptr;
1011 return *this;
1012}
1013
1014void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
1015{
1016 auto &constant_type = get<SPIRType>(type);
1017
1018 if (constant_type.pointer)
1019 {
1020 if (add_to_typed_id_set)
1021 add_typed_id(TypeConstant, id);
1022 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1023 constant.self = id;
1024 constant.make_null(constant_type);
1025 }
1026 else if (!constant_type.array.empty())
1027 {
1028 assert(constant_type.parent_type);
1029 uint32_t parent_id = increase_bound_by(1);
1030 make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
1031
1032 if (!constant_type.array_size_literal.back())
1033 SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
1034
1035 SmallVector<uint32_t> elements(constant_type.array.back());
1036 for (uint32_t i = 0; i < constant_type.array.back(); i++)
1037 elements[i] = parent_id;
1038
1039 if (add_to_typed_id_set)
1040 add_typed_id(TypeConstant, id);
1041 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1042 }
1043 else if (!constant_type.member_types.empty())
1044 {
1045 uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
1046 SmallVector<uint32_t> elements(constant_type.member_types.size());
1047 for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
1048 {
1049 make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
1050 elements[i] = member_ids + i;
1051 }
1052
1053 if (add_to_typed_id_set)
1054 add_typed_id(TypeConstant, id);
1055 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1056 }
1057 else
1058 {
1059 if (add_to_typed_id_set)
1060 add_typed_id(TypeConstant, id);
1061 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1062 constant.self = id;
1063 constant.make_null(constant_type);
1064 }
1065}
1066
1067} // namespace SPIRV_CROSS_NAMESPACE
1068