HLSL: Don't emit the builtin PerVertex array as inout.
[KhronosGroup/SPIRV-Cross.git] / spirv_cross_parsed_ir.cpp
blobb05afeb3f57e3f485789a67f17fe8668b5983bc2
1 /*
2 * Copyright 2018-2021 Arm Limited
3 * SPDX-License-Identifier: Apache-2.0 OR MIT
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>.
24 #include "spirv_cross_parsed_ir.hpp"
25 #include <algorithm>
26 #include <assert.h>
28 using namespace std;
29 using namespace spv;
31 namespace SPIRV_CROSS_NAMESPACE
33 ParsedIR::ParsedIR()
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);
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>);
54 // Should have been default-implemented, but need this on MSVC 2013.
55 ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
57 *this = std::move(other);
60 ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
62 if (this != &other)
64 pool_group = std::move(other.pool_group);
65 spirv = std::move(other.spirv);
66 meta = std::move(other.meta);
67 for (int i = 0; i < TypeCount; i++)
68 ids_for_type[i] = std::move(other.ids_for_type[i]);
69 ids_for_constant_undef_or_type = std::move(other.ids_for_constant_undef_or_type);
70 ids_for_constant_or_variable = std::move(other.ids_for_constant_or_variable);
71 declared_capabilities = std::move(other.declared_capabilities);
72 declared_extensions = std::move(other.declared_extensions);
73 block_meta = std::move(other.block_meta);
74 continue_block_to_loop_header = std::move(other.continue_block_to_loop_header);
75 entry_points = std::move(other.entry_points);
76 ids = std::move(other.ids);
77 addressing_model = other.addressing_model;
78 memory_model = other.memory_model;
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;
85 meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
86 load_type_width = std::move(other.load_type_width);
88 return *this;
91 ParsedIR::ParsedIR(const ParsedIR &other)
92 : ParsedIR()
94 *this = other;
97 ParsedIR &ParsedIR::operator=(const ParsedIR &other)
99 if (this != &other)
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_undef_or_type = other.ids_for_constant_undef_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;
120 meta_needing_name_fixup = other.meta_needing_name_fixup;
121 load_type_width = other.load_type_width;
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++)
129 ids.emplace_back(pool_group.get());
130 ids.back() = other.ids[i];
133 return *this;
136 void ParsedIR::set_id_bounds(uint32_t bounds)
138 ids.reserve(bounds);
139 while (ids.size() < bounds)
140 ids.emplace_back(pool_group.get());
142 block_meta.resize(bounds);
145 // Roll our own versions of these functions to avoid potential locale shenanigans.
146 static bool is_alpha(char c)
148 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
151 static bool is_numeric(char c)
153 return c >= '0' && c <= '9';
156 static bool is_alphanumeric(char c)
158 return is_alpha(c) || is_numeric(c);
161 static bool is_valid_identifier(const string &name)
163 if (name.empty())
164 return true;
166 if (is_numeric(name[0]))
167 return false;
169 for (auto c : name)
170 if (!is_alphanumeric(c) && c != '_')
171 return false;
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)
178 bool is_underscore = c == '_';
179 if (is_underscore && saw_underscore)
180 return false;
181 saw_underscore = is_underscore;
184 return true;
187 static bool is_reserved_prefix(const string &name)
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;
196 static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes)
198 if (!allow_reserved_prefixes && is_reserved_prefix(name))
199 return true;
201 if (member)
203 // Reserved member identifiers come in one form:
204 // _m[0-9]+$.
205 if (name.size() < 3)
206 return false;
208 if (name.compare(0, 2, "_m", 2) != 0)
209 return false;
211 size_t index = 2;
212 while (index < name.size() && is_numeric(name[index]))
213 index++;
215 return index == name.size();
217 else
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;
225 if (name[0] != '_' || !is_numeric(name[1]))
226 return false;
228 size_t index = 2;
229 while (index < name.size() && is_numeric(name[index]))
230 index++;
232 return index == name.size() || (index < name.size() && name[index] == '_');
236 bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes)
238 return is_reserved_identifier(str, false, allow_reserved_prefixes);
241 uint32_t ParsedIR::get_spirv_version() const
243 return spirv[1];
246 static string make_unreserved_identifier(const string &name)
248 if (is_reserved_prefix(name))
249 return "_RESERVED_IDENTIFIER_FIXUP_" + name;
250 else
251 return "_RESERVED_IDENTIFIER_FIXUP" + name;
254 void ParsedIR::sanitize_underscores(std::string &str)
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())
262 bool is_underscore = *src == '_';
263 if (saw_underscore && is_underscore)
265 src++;
267 else
269 if (dst != src)
270 *dst = *src;
271 dst++;
272 src++;
273 saw_underscore = is_underscore;
276 str.erase(dst, str.end());
279 static string ensure_valid_identifier(const string &name)
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('('));
285 if (str.empty())
286 return str;
288 if (is_numeric(str[0]))
289 str[0] = '_';
291 for (auto &c : str)
292 if (!is_alphanumeric(c) && c != '_')
293 c = '_';
295 ParsedIR::sanitize_underscores(str);
296 return str;
299 const string &ParsedIR::get_name(ID id) const
301 auto *m = find_meta(id);
302 if (m)
303 return m->decoration.alias;
304 else
305 return empty_string;
308 const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
310 auto *m = find_meta(id);
311 if (m)
313 if (index >= m->members.size())
314 return empty_string;
315 return m->members[index].alias;
317 else
318 return empty_string;
321 void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes)
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);
329 void ParsedIR::fixup_reserved_names()
331 for (uint32_t id : meta_needing_name_fixup)
333 // Don't rename remapped variables like 'gl_LastFragDepthARM'.
334 if (ids[id].get_type() == TypeVariable && get<SPIRVariable>(id).remapped_variable)
335 continue;
337 auto &m = meta[id];
338 sanitize_identifier(m.decoration.alias, false, false);
339 for (auto &memb : m.members)
340 sanitize_identifier(memb.alias, true, false);
342 meta_needing_name_fixup.clear();
345 void ParsedIR::set_name(ID id, const string &name)
347 auto &m = meta[id];
348 m.decoration.alias = name;
349 if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
350 meta_needing_name_fixup.insert(id);
353 void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
355 auto &m = meta[id];
356 m.members.resize(max(m.members.size(), size_t(index) + 1));
357 m.members[index].alias = name;
358 if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
359 meta_needing_name_fixup.insert(id);
362 void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
364 auto &dec = meta[id].decoration;
365 dec.decoration_flags.set(decoration);
367 switch (decoration)
369 case DecorationHlslSemanticGOOGLE:
370 dec.hlsl_semantic = argument;
371 break;
373 case DecorationUserTypeGOOGLE:
374 dec.user_type = argument;
375 break;
377 default:
378 break;
382 void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
384 auto &dec = meta[id].decoration;
385 dec.decoration_flags.set(decoration);
387 switch (decoration)
389 case DecorationBuiltIn:
390 dec.builtin = true;
391 dec.builtin_type = static_cast<BuiltIn>(argument);
392 break;
394 case DecorationLocation:
395 dec.location = argument;
396 break;
398 case DecorationComponent:
399 dec.component = argument;
400 break;
402 case DecorationOffset:
403 dec.offset = argument;
404 break;
406 case DecorationXfbBuffer:
407 dec.xfb_buffer = argument;
408 break;
410 case DecorationXfbStride:
411 dec.xfb_stride = argument;
412 break;
414 case DecorationStream:
415 dec.stream = argument;
416 break;
418 case DecorationArrayStride:
419 dec.array_stride = argument;
420 break;
422 case DecorationMatrixStride:
423 dec.matrix_stride = argument;
424 break;
426 case DecorationBinding:
427 dec.binding = argument;
428 break;
430 case DecorationDescriptorSet:
431 dec.set = argument;
432 break;
434 case DecorationInputAttachmentIndex:
435 dec.input_attachment = argument;
436 break;
438 case DecorationSpecId:
439 dec.spec_id = argument;
440 break;
442 case DecorationIndex:
443 dec.index = argument;
444 break;
446 case DecorationHlslCounterBufferGOOGLE:
447 meta[id].hlsl_magic_counter_buffer = argument;
448 meta[argument].hlsl_is_magic_counter_buffer = true;
449 break;
451 case DecorationFPRoundingMode:
452 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
453 break;
455 default:
456 break;
460 void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
462 auto &m = meta[id];
463 m.members.resize(max(m.members.size(), size_t(index) + 1));
464 auto &dec = m.members[index];
465 dec.decoration_flags.set(decoration);
467 switch (decoration)
469 case DecorationBuiltIn:
470 dec.builtin = true;
471 dec.builtin_type = static_cast<BuiltIn>(argument);
472 break;
474 case DecorationLocation:
475 dec.location = argument;
476 break;
478 case DecorationComponent:
479 dec.component = argument;
480 break;
482 case DecorationBinding:
483 dec.binding = argument;
484 break;
486 case DecorationOffset:
487 dec.offset = argument;
488 break;
490 case DecorationXfbBuffer:
491 dec.xfb_buffer = argument;
492 break;
494 case DecorationXfbStride:
495 dec.xfb_stride = argument;
496 break;
498 case DecorationStream:
499 dec.stream = argument;
500 break;
502 case DecorationSpecId:
503 dec.spec_id = argument;
504 break;
506 case DecorationMatrixStride:
507 dec.matrix_stride = argument;
508 break;
510 case DecorationIndex:
511 dec.index = argument;
512 break;
514 default:
515 break;
519 // Recursively marks any constants referenced by the specified constant instruction as being used
520 // as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
521 void ParsedIR::mark_used_as_array_length(ID id)
523 switch (ids[id].get_type())
525 case TypeConstant:
526 get<SPIRConstant>(id).is_used_as_array_length = true;
527 break;
529 case TypeConstantOp:
531 auto &cop = get<SPIRConstantOp>(id);
532 if (cop.opcode == OpCompositeExtract)
533 mark_used_as_array_length(cop.arguments[0]);
534 else if (cop.opcode == OpCompositeInsert)
536 mark_used_as_array_length(cop.arguments[0]);
537 mark_used_as_array_length(cop.arguments[1]);
539 else
540 for (uint32_t arg_id : cop.arguments)
541 mark_used_as_array_length(arg_id);
542 break;
545 case TypeUndef:
546 break;
548 default:
549 assert(0);
553 Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
555 if (type.member_types.empty())
556 return {};
558 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
559 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
560 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
561 return all_members_flags;
564 Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
566 auto &type = get<SPIRType>(var.basetype);
567 if (type.basetype != SPIRType::Struct)
568 SPIRV_CROSS_THROW("Cannot get buffer block flags for non-buffer variable.");
570 // Some flags like non-writable, non-readable are actually found
571 // as member decorations. If all members have a decoration set, propagate
572 // the decoration up as a regular variable decoration.
573 Bitset base_flags;
574 auto *m = find_meta(var.self);
575 if (m)
576 base_flags = m->decoration.decoration_flags;
578 if (type.member_types.empty())
579 return base_flags;
581 auto all_members_flags = get_buffer_block_type_flags(type);
582 base_flags.merge_or(all_members_flags);
583 return base_flags;
586 const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
588 auto *m = find_meta(id);
589 if (m)
591 if (index >= m->members.size())
592 return cleared_bitset;
593 return m->members[index].decoration_flags;
595 else
596 return cleared_bitset;
599 bool ParsedIR::has_decoration(ID id, Decoration decoration) const
601 return get_decoration_bitset(id).get(decoration);
604 uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
606 auto *m = find_meta(id);
607 if (!m)
608 return 0;
610 auto &dec = m->decoration;
611 if (!dec.decoration_flags.get(decoration))
612 return 0;
614 switch (decoration)
616 case DecorationBuiltIn:
617 return dec.builtin_type;
618 case DecorationLocation:
619 return dec.location;
620 case DecorationComponent:
621 return dec.component;
622 case DecorationOffset:
623 return dec.offset;
624 case DecorationXfbBuffer:
625 return dec.xfb_buffer;
626 case DecorationXfbStride:
627 return dec.xfb_stride;
628 case DecorationStream:
629 return dec.stream;
630 case DecorationBinding:
631 return dec.binding;
632 case DecorationDescriptorSet:
633 return dec.set;
634 case DecorationInputAttachmentIndex:
635 return dec.input_attachment;
636 case DecorationSpecId:
637 return dec.spec_id;
638 case DecorationArrayStride:
639 return dec.array_stride;
640 case DecorationMatrixStride:
641 return dec.matrix_stride;
642 case DecorationIndex:
643 return dec.index;
644 case DecorationFPRoundingMode:
645 return dec.fp_rounding_mode;
646 default:
647 return 1;
651 const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
653 auto *m = find_meta(id);
654 if (!m)
655 return empty_string;
657 auto &dec = m->decoration;
659 if (!dec.decoration_flags.get(decoration))
660 return empty_string;
662 switch (decoration)
664 case DecorationHlslSemanticGOOGLE:
665 return dec.hlsl_semantic;
667 case DecorationUserTypeGOOGLE:
668 return dec.user_type;
670 default:
671 return empty_string;
675 void ParsedIR::unset_decoration(ID id, Decoration decoration)
677 auto &dec = meta[id].decoration;
678 dec.decoration_flags.clear(decoration);
679 switch (decoration)
681 case DecorationBuiltIn:
682 dec.builtin = false;
683 break;
685 case DecorationLocation:
686 dec.location = 0;
687 break;
689 case DecorationComponent:
690 dec.component = 0;
691 break;
693 case DecorationOffset:
694 dec.offset = 0;
695 break;
697 case DecorationXfbBuffer:
698 dec.xfb_buffer = 0;
699 break;
701 case DecorationXfbStride:
702 dec.xfb_stride = 0;
703 break;
705 case DecorationStream:
706 dec.stream = 0;
707 break;
709 case DecorationBinding:
710 dec.binding = 0;
711 break;
713 case DecorationDescriptorSet:
714 dec.set = 0;
715 break;
717 case DecorationInputAttachmentIndex:
718 dec.input_attachment = 0;
719 break;
721 case DecorationSpecId:
722 dec.spec_id = 0;
723 break;
725 case DecorationHlslSemanticGOOGLE:
726 dec.hlsl_semantic.clear();
727 break;
729 case DecorationFPRoundingMode:
730 dec.fp_rounding_mode = FPRoundingModeMax;
731 break;
733 case DecorationHlslCounterBufferGOOGLE:
735 auto &counter = meta[id].hlsl_magic_counter_buffer;
736 if (counter)
738 meta[counter].hlsl_is_magic_counter_buffer = false;
739 counter = 0;
741 break;
744 default:
745 break;
749 bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
751 return get_member_decoration_bitset(id, index).get(decoration);
754 uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
756 auto *m = find_meta(id);
757 if (!m)
758 return 0;
760 if (index >= m->members.size())
761 return 0;
763 auto &dec = m->members[index];
764 if (!dec.decoration_flags.get(decoration))
765 return 0;
767 switch (decoration)
769 case DecorationBuiltIn:
770 return dec.builtin_type;
771 case DecorationLocation:
772 return dec.location;
773 case DecorationComponent:
774 return dec.component;
775 case DecorationBinding:
776 return dec.binding;
777 case DecorationOffset:
778 return dec.offset;
779 case DecorationXfbBuffer:
780 return dec.xfb_buffer;
781 case DecorationXfbStride:
782 return dec.xfb_stride;
783 case DecorationStream:
784 return dec.stream;
785 case DecorationSpecId:
786 return dec.spec_id;
787 case DecorationMatrixStride:
788 return dec.matrix_stride;
789 case DecorationIndex:
790 return dec.index;
791 default:
792 return 1;
796 const Bitset &ParsedIR::get_decoration_bitset(ID id) const
798 auto *m = find_meta(id);
799 if (m)
801 auto &dec = m->decoration;
802 return dec.decoration_flags;
804 else
805 return cleared_bitset;
808 void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
810 auto &m = meta[id];
811 m.members.resize(max(m.members.size(), size_t(index) + 1));
812 auto &dec = meta[id].members[index];
813 dec.decoration_flags.set(decoration);
815 switch (decoration)
817 case DecorationHlslSemanticGOOGLE:
818 dec.hlsl_semantic = argument;
819 break;
821 default:
822 break;
826 const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
828 auto *m = find_meta(id);
829 if (m)
831 if (!has_member_decoration(id, index, decoration))
832 return empty_string;
834 auto &dec = m->members[index];
836 switch (decoration)
838 case DecorationHlslSemanticGOOGLE:
839 return dec.hlsl_semantic;
841 default:
842 return empty_string;
845 else
846 return empty_string;
849 void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
851 auto &m = meta[id];
852 if (index >= m.members.size())
853 return;
855 auto &dec = m.members[index];
857 dec.decoration_flags.clear(decoration);
858 switch (decoration)
860 case DecorationBuiltIn:
861 dec.builtin = false;
862 break;
864 case DecorationLocation:
865 dec.location = 0;
866 break;
868 case DecorationComponent:
869 dec.component = 0;
870 break;
872 case DecorationOffset:
873 dec.offset = 0;
874 break;
876 case DecorationXfbBuffer:
877 dec.xfb_buffer = 0;
878 break;
880 case DecorationXfbStride:
881 dec.xfb_stride = 0;
882 break;
884 case DecorationStream:
885 dec.stream = 0;
886 break;
888 case DecorationSpecId:
889 dec.spec_id = 0;
890 break;
892 case DecorationHlslSemanticGOOGLE:
893 dec.hlsl_semantic.clear();
894 break;
896 default:
897 break;
901 uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
903 auto curr_bound = ids.size();
904 auto new_bound = curr_bound + incr_amount;
906 ids.reserve(ids.size() + incr_amount);
907 for (uint32_t i = 0; i < incr_amount; i++)
908 ids.emplace_back(pool_group.get());
910 block_meta.resize(new_bound);
911 return uint32_t(curr_bound);
914 void ParsedIR::remove_typed_id(Types type, ID id)
916 auto &type_ids = ids_for_type[type];
917 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
920 void ParsedIR::reset_all_of_type(Types type)
922 for (auto &id : ids_for_type[type])
923 if (ids[id].get_type() == type)
924 ids[id].reset();
926 ids_for_type[type].clear();
929 void ParsedIR::add_typed_id(Types type, ID id)
931 assert(id < ids.size());
933 if (loop_iteration_depth_hard != 0)
934 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
936 if (loop_iteration_depth_soft != 0)
938 if (!ids[id].empty())
939 SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
940 return;
943 if (ids[id].empty() || ids[id].get_type() != type)
945 switch (type)
947 case TypeConstant:
948 ids_for_constant_or_variable.push_back(id);
949 ids_for_constant_undef_or_type.push_back(id);
950 break;
952 case TypeVariable:
953 ids_for_constant_or_variable.push_back(id);
954 break;
956 case TypeType:
957 case TypeConstantOp:
958 case TypeUndef:
959 ids_for_constant_undef_or_type.push_back(id);
960 break;
962 default:
963 break;
967 if (ids[id].empty())
969 ids_for_type[type].push_back(id);
971 else if (ids[id].get_type() != type)
973 remove_typed_id(ids[id].get_type(), id);
974 ids_for_type[type].push_back(id);
978 const Meta *ParsedIR::find_meta(ID id) const
980 auto itr = meta.find(id);
981 if (itr != end(meta))
982 return &itr->second;
983 else
984 return nullptr;
987 Meta *ParsedIR::find_meta(ID id)
989 auto itr = meta.find(id);
990 if (itr != end(meta))
991 return &itr->second;
992 else
993 return nullptr;
996 ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
998 return ParsedIR::LoopLock(&loop_iteration_depth_hard);
1001 ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
1003 return ParsedIR::LoopLock(&loop_iteration_depth_soft);
1006 ParsedIR::LoopLock::~LoopLock()
1008 if (lock)
1009 (*lock)--;
1012 ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
1013 : lock(lock_)
1015 if (lock)
1016 (*lock)++;
1019 ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1021 *this = std::move(other);
1024 ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1026 if (lock)
1027 (*lock)--;
1028 lock = other.lock;
1029 other.lock = nullptr;
1030 return *this;
1033 void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
1035 assert(id < ids.size());
1037 auto &constant_type = get<SPIRType>(type);
1039 if (constant_type.pointer)
1041 if (add_to_typed_id_set)
1042 add_typed_id(TypeConstant, id);
1043 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1044 constant.self = id;
1045 constant.make_null(constant_type);
1047 else if (!constant_type.array.empty())
1049 assert(constant_type.parent_type);
1050 uint32_t parent_id = increase_bound_by(1);
1051 make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
1053 if (!constant_type.array_size_literal.back())
1054 SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
1056 SmallVector<uint32_t> elements(constant_type.array.back());
1057 for (uint32_t i = 0; i < constant_type.array.back(); i++)
1058 elements[i] = parent_id;
1060 if (add_to_typed_id_set)
1061 add_typed_id(TypeConstant, id);
1062 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1064 else if (!constant_type.member_types.empty())
1066 uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
1067 SmallVector<uint32_t> elements(constant_type.member_types.size());
1068 for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
1070 make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
1071 elements[i] = member_ids + i;
1074 if (add_to_typed_id_set)
1075 add_typed_id(TypeConstant, id);
1076 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1078 else
1080 if (add_to_typed_id_set)
1081 add_typed_id(TypeConstant, id);
1082 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1083 constant.self = id;
1084 constant.make_null(constant_type);
1088 } // namespace SPIRV_CROSS_NAMESPACE