1 /*
2 * Copyright 2018-2020 Arm Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "spirv_cross_parsed_ir.hpp"
18 #include <algorithm>
19 #include <assert.h>
20
21 using namespace std;
22 using namespace spv;
23
24 namespace SPIRV_CROSS_NAMESPACE
25 {
ParsedIR()26 ParsedIR::ParsedIR()
27 {
28 // If we move ParsedIR, we need to make sure the pointer stays fixed since the child Variant objects consume a pointer to this group,
29 // so need an extra pointer here.
30 pool_group.reset(new ObjectPoolGroup);
31
32 pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>);
33 pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>);
34 pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>);
35 pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>);
36 pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>);
37 pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>);
38 pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>);
39 pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>);
40 pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>);
41 pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>);
42 pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
43 pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
44 pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
45 }
46
47 // Should have been default-implemented, but need this on MSVC 2013.
ParsedIR(ParsedIR && other)48 ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
49 {
50 *this = move(other);
51 }
52
operator =(ParsedIR && other)53 ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
54 {
55 if (this != &other)
56 {
57 pool_group = move(other.pool_group);
58 spirv = move(other.spirv);
59 meta = move(other.meta);
60 for (int i = 0; i < TypeCount; i++)
61 ids_for_type[i] = move(other.ids_for_type[i]);
62 ids_for_constant_or_type = move(other.ids_for_constant_or_type);
63 ids_for_constant_or_variable = move(other.ids_for_constant_or_variable);
64 declared_capabilities = move(other.declared_capabilities);
65 declared_extensions = move(other.declared_extensions);
66 block_meta = move(other.block_meta);
67 continue_block_to_loop_header = move(other.continue_block_to_loop_header);
68 entry_points = move(other.entry_points);
69 ids = move(other.ids);
70 addressing_model = other.addressing_model;
71 memory_model = other.memory_model;
72
73 default_entry_point = other.default_entry_point;
74 source = other.source;
75 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
76 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
77 }
78 return *this;
79 }
80
ParsedIR(const ParsedIR & other)81 ParsedIR::ParsedIR(const ParsedIR &other)
82 : ParsedIR()
83 {
84 *this = other;
85 }
86
operator =(const ParsedIR & other)87 ParsedIR &ParsedIR::operator=(const ParsedIR &other)
88 {
89 if (this != &other)
90 {
91 spirv = other.spirv;
92 meta = other.meta;
93 for (int i = 0; i < TypeCount; i++)
94 ids_for_type[i] = other.ids_for_type[i];
95 ids_for_constant_or_type = other.ids_for_constant_or_type;
96 ids_for_constant_or_variable = other.ids_for_constant_or_variable;
97 declared_capabilities = other.declared_capabilities;
98 declared_extensions = other.declared_extensions;
99 block_meta = other.block_meta;
100 continue_block_to_loop_header = other.continue_block_to_loop_header;
101 entry_points = other.entry_points;
102 default_entry_point = other.default_entry_point;
103 source = other.source;
104 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
105 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
106 addressing_model = other.addressing_model;
107 memory_model = other.memory_model;
108
109 // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
110 // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
111 ids.clear();
112 ids.reserve(other.ids.size());
113 for (size_t i = 0; i < other.ids.size(); i++)
114 {
115 ids.emplace_back(pool_group.get());
116 ids.back() = other.ids[i];
117 }
118 }
119 return *this;
120 }
121
set_id_bounds(uint32_t bounds)122 void ParsedIR::set_id_bounds(uint32_t bounds)
123 {
124 ids.reserve(bounds);
125 while (ids.size() < bounds)
126 ids.emplace_back(pool_group.get());
127
128 block_meta.resize(bounds);
129 }
130
131 // Roll our own versions of these functions to avoid potential locale shenanigans.
is_alpha(char c)132 static bool is_alpha(char c)
133 {
134 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
135 }
136
is_alphanumeric(char c)137 static bool is_alphanumeric(char c)
138 {
139 return is_alpha(c) || (c >= '0' && c <= '9');
140 }
141
ensure_valid_identifier(const string & name,bool member)142 static string ensure_valid_identifier(const string &name, bool member)
143 {
144 // Functions in glslangValidator are mangled with name(<mangled> stuff.
145 // Normally, we would never see '(' in any legal identifiers, so just strip them out.
146 auto str = name.substr(0, name.find('('));
147
148 for (uint32_t i = 0; i < str.size(); i++)
149 {
150 auto &c = str[i];
151
152 if (member)
153 {
154 // _m<num> variables are reserved by the internal implementation,
155 // otherwise, make sure the name is a valid identifier.
156 if (i == 0)
157 c = is_alpha(c) ? c : '_';
158 else if (i == 2 && str[0] == '_' && str[1] == 'm')
159 c = is_alpha(c) ? c : '_';
160 else
161 c = is_alphanumeric(c) ? c : '_';
162 }
163 else
164 {
165 // _<num> variables are reserved by the internal implementation,
166 // otherwise, make sure the name is a valid identifier.
167 if (i == 0 || (str[0] == '_' && i == 1))
168 c = is_alpha(c) ? c : '_';
169 else
170 c = is_alphanumeric(c) ? c : '_';
171 }
172 }
173 return str;
174 }
175
get_name(ID id) const176 const string &ParsedIR::get_name(ID id) const
177 {
178 auto *m = find_meta(id);
179 if (m)
180 return m->decoration.alias;
181 else
182 return empty_string;
183 }
184
get_member_name(TypeID id,uint32_t index) const185 const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
186 {
187 auto *m = find_meta(id);
188 if (m)
189 {
190 if (index >= m->members.size())
191 return empty_string;
192 return m->members[index].alias;
193 }
194 else
195 return empty_string;
196 }
197
set_name(ID id,const string & name)198 void ParsedIR::set_name(ID id, const string &name)
199 {
200 auto &str = meta[id].decoration.alias;
201 str.clear();
202
203 if (name.empty())
204 return;
205
206 // Reserved for temporaries.
207 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
208 return;
209
210 str = ensure_valid_identifier(name, false);
211 }
212
set_member_name(TypeID id,uint32_t index,const string & name)213 void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
214 {
215 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
216
217 auto &str = meta[id].members[index].alias;
218 str.clear();
219 if (name.empty())
220 return;
221
222 // Reserved for unnamed members.
223 if (name[0] == '_' && name.size() >= 3 && name[1] == 'm' && isdigit(name[2]))
224 return;
225
226 str = ensure_valid_identifier(name, true);
227 }
228
set_decoration_string(ID id,Decoration decoration,const string & argument)229 void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
230 {
231 auto &dec = meta[id].decoration;
232 dec.decoration_flags.set(decoration);
233
234 switch (decoration)
235 {
236 case DecorationHlslSemanticGOOGLE:
237 dec.hlsl_semantic = argument;
238 break;
239
240 default:
241 break;
242 }
243 }
244
set_decoration(ID id,Decoration decoration,uint32_t argument)245 void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
246 {
247 auto &dec = meta[id].decoration;
248 dec.decoration_flags.set(decoration);
249
250 switch (decoration)
251 {
252 case DecorationBuiltIn:
253 dec.builtin = true;
254 dec.builtin_type = static_cast<BuiltIn>(argument);
255 break;
256
257 case DecorationLocation:
258 dec.location = argument;
259 break;
260
261 case DecorationComponent:
262 dec.component = argument;
263 break;
264
265 case DecorationOffset:
266 dec.offset = argument;
267 break;
268
269 case DecorationXfbBuffer:
270 dec.xfb_buffer = argument;
271 break;
272
273 case DecorationXfbStride:
274 dec.xfb_stride = argument;
275 break;
276
277 case DecorationArrayStride:
278 dec.array_stride = argument;
279 break;
280
281 case DecorationMatrixStride:
282 dec.matrix_stride = argument;
283 break;
284
285 case DecorationBinding:
286 dec.binding = argument;
287 break;
288
289 case DecorationDescriptorSet:
290 dec.set = argument;
291 break;
292
293 case DecorationInputAttachmentIndex:
294 dec.input_attachment = argument;
295 break;
296
297 case DecorationSpecId:
298 dec.spec_id = argument;
299 break;
300
301 case DecorationIndex:
302 dec.index = argument;
303 break;
304
305 case DecorationHlslCounterBufferGOOGLE:
306 meta[id].hlsl_magic_counter_buffer = argument;
307 meta[argument].hlsl_is_magic_counter_buffer = true;
308 break;
309
310 case DecorationFPRoundingMode:
311 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
312 break;
313
314 default:
315 break;
316 }
317 }
318
set_member_decoration(TypeID id,uint32_t index,Decoration decoration,uint32_t argument)319 void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
320 {
321 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
322 auto &dec = meta[id].members[index];
323 dec.decoration_flags.set(decoration);
324
325 switch (decoration)
326 {
327 case DecorationBuiltIn:
328 dec.builtin = true;
329 dec.builtin_type = static_cast<BuiltIn>(argument);
330 break;
331
332 case DecorationLocation:
333 dec.location = argument;
334 break;
335
336 case DecorationComponent:
337 dec.component = argument;
338 break;
339
340 case DecorationBinding:
341 dec.binding = argument;
342 break;
343
344 case DecorationOffset:
345 dec.offset = argument;
346 break;
347
348 case DecorationXfbBuffer:
349 dec.xfb_buffer = argument;
350 break;
351
352 case DecorationXfbStride:
353 dec.xfb_stride = argument;
354 break;
355
356 case DecorationSpecId:
357 dec.spec_id = argument;
358 break;
359
360 case DecorationMatrixStride:
361 dec.matrix_stride = argument;
362 break;
363
364 case DecorationIndex:
365 dec.index = argument;
366 break;
367
368 default:
369 break;
370 }
371 }
372
373 // Recursively marks any constants referenced by the specified constant instruction as being used
374 // as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
mark_used_as_array_length(ID id)375 void ParsedIR::mark_used_as_array_length(ID id)
376 {
377 switch (ids[id].get_type())
378 {
379 case TypeConstant:
380 get<SPIRConstant>(id).is_used_as_array_length = true;
381 break;
382
383 case TypeConstantOp:
384 {
385 auto &cop = get<SPIRConstantOp>(id);
386 if (cop.opcode == OpCompositeExtract)
387 mark_used_as_array_length(cop.arguments[0]);
388 else if (cop.opcode == OpCompositeInsert)
389 {
390 mark_used_as_array_length(cop.arguments[0]);
391 mark_used_as_array_length(cop.arguments[1]);
392 }
393 else
394 for (uint32_t arg_id : cop.arguments)
395 mark_used_as_array_length(arg_id);
396 break;
397 }
398
399 case TypeUndef:
400 break;
401
402 default:
403 assert(0);
404 }
405 }
406
get_buffer_block_flags(const SPIRVariable & var) const407 Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
408 {
409 auto &type = get<SPIRType>(var.basetype);
410 assert(type.basetype == SPIRType::Struct);
411
412 // Some flags like non-writable, non-readable are actually found
413 // as member decorations. If all members have a decoration set, propagate
414 // the decoration up as a regular variable decoration.
415 Bitset base_flags;
416 auto *m = find_meta(var.self);
417 if (m)
418 base_flags = m->decoration.decoration_flags;
419
420 if (type.member_types.empty())
421 return base_flags;
422
423 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
424 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
425 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
426
427 base_flags.merge_or(all_members_flags);
428 return base_flags;
429 }
430
get_member_decoration_bitset(TypeID id,uint32_t index) const431 const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
432 {
433 auto *m = find_meta(id);
434 if (m)
435 {
436 if (index >= m->members.size())
437 return cleared_bitset;
438 return m->members[index].decoration_flags;
439 }
440 else
441 return cleared_bitset;
442 }
443
has_decoration(ID id,Decoration decoration) const444 bool ParsedIR::has_decoration(ID id, Decoration decoration) const
445 {
446 return get_decoration_bitset(id).get(decoration);
447 }
448
get_decoration(ID id,Decoration decoration) const449 uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
450 {
451 auto *m = find_meta(id);
452 if (!m)
453 return 0;
454
455 auto &dec = m->decoration;
456 if (!dec.decoration_flags.get(decoration))
457 return 0;
458
459 switch (decoration)
460 {
461 case DecorationBuiltIn:
462 return dec.builtin_type;
463 case DecorationLocation:
464 return dec.location;
465 case DecorationComponent:
466 return dec.component;
467 case DecorationOffset:
468 return dec.offset;
469 case DecorationXfbBuffer:
470 return dec.xfb_buffer;
471 case DecorationXfbStride:
472 return dec.xfb_stride;
473 case DecorationBinding:
474 return dec.binding;
475 case DecorationDescriptorSet:
476 return dec.set;
477 case DecorationInputAttachmentIndex:
478 return dec.input_attachment;
479 case DecorationSpecId:
480 return dec.spec_id;
481 case DecorationArrayStride:
482 return dec.array_stride;
483 case DecorationMatrixStride:
484 return dec.matrix_stride;
485 case DecorationIndex:
486 return dec.index;
487 case DecorationFPRoundingMode:
488 return dec.fp_rounding_mode;
489 default:
490 return 1;
491 }
492 }
493
get_decoration_string(ID id,Decoration decoration) const494 const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
495 {
496 auto *m = find_meta(id);
497 if (!m)
498 return empty_string;
499
500 auto &dec = m->decoration;
501
502 if (!dec.decoration_flags.get(decoration))
503 return empty_string;
504
505 switch (decoration)
506 {
507 case DecorationHlslSemanticGOOGLE:
508 return dec.hlsl_semantic;
509
510 default:
511 return empty_string;
512 }
513 }
514
unset_decoration(ID id,Decoration decoration)515 void ParsedIR::unset_decoration(ID id, Decoration decoration)
516 {
517 auto &dec = meta[id].decoration;
518 dec.decoration_flags.clear(decoration);
519 switch (decoration)
520 {
521 case DecorationBuiltIn:
522 dec.builtin = false;
523 break;
524
525 case DecorationLocation:
526 dec.location = 0;
527 break;
528
529 case DecorationComponent:
530 dec.component = 0;
531 break;
532
533 case DecorationOffset:
534 dec.offset = 0;
535 break;
536
537 case DecorationXfbBuffer:
538 dec.xfb_buffer = 0;
539 break;
540
541 case DecorationXfbStride:
542 dec.xfb_stride = 0;
543 break;
544
545 case DecorationBinding:
546 dec.binding = 0;
547 break;
548
549 case DecorationDescriptorSet:
550 dec.set = 0;
551 break;
552
553 case DecorationInputAttachmentIndex:
554 dec.input_attachment = 0;
555 break;
556
557 case DecorationSpecId:
558 dec.spec_id = 0;
559 break;
560
561 case DecorationHlslSemanticGOOGLE:
562 dec.hlsl_semantic.clear();
563 break;
564
565 case DecorationFPRoundingMode:
566 dec.fp_rounding_mode = FPRoundingModeMax;
567 break;
568
569 case DecorationHlslCounterBufferGOOGLE:
570 {
571 auto &counter = meta[id].hlsl_magic_counter_buffer;
572 if (counter)
573 {
574 meta[counter].hlsl_is_magic_counter_buffer = false;
575 counter = 0;
576 }
577 break;
578 }
579
580 default:
581 break;
582 }
583 }
584
has_member_decoration(TypeID id,uint32_t index,Decoration decoration) const585 bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
586 {
587 return get_member_decoration_bitset(id, index).get(decoration);
588 }
589
get_member_decoration(TypeID id,uint32_t index,Decoration decoration) const590 uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
591 {
592 auto *m = find_meta(id);
593 if (!m)
594 return 0;
595
596 if (index >= m->members.size())
597 return 0;
598
599 auto &dec = m->members[index];
600 if (!dec.decoration_flags.get(decoration))
601 return 0;
602
603 switch (decoration)
604 {
605 case DecorationBuiltIn:
606 return dec.builtin_type;
607 case DecorationLocation:
608 return dec.location;
609 case DecorationComponent:
610 return dec.component;
611 case DecorationBinding:
612 return dec.binding;
613 case DecorationOffset:
614 return dec.offset;
615 case DecorationXfbBuffer:
616 return dec.xfb_buffer;
617 case DecorationXfbStride:
618 return dec.xfb_stride;
619 case DecorationSpecId:
620 return dec.spec_id;
621 case DecorationIndex:
622 return dec.index;
623 default:
624 return 1;
625 }
626 }
627
get_decoration_bitset(ID id) const628 const Bitset &ParsedIR::get_decoration_bitset(ID id) const
629 {
630 auto *m = find_meta(id);
631 if (m)
632 {
633 auto &dec = m->decoration;
634 return dec.decoration_flags;
635 }
636 else
637 return cleared_bitset;
638 }
639
set_member_decoration_string(TypeID id,uint32_t index,Decoration decoration,const string & argument)640 void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
641 {
642 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
643 auto &dec = meta[id].members[index];
644 dec.decoration_flags.set(decoration);
645
646 switch (decoration)
647 {
648 case DecorationHlslSemanticGOOGLE:
649 dec.hlsl_semantic = argument;
650 break;
651
652 default:
653 break;
654 }
655 }
656
get_member_decoration_string(TypeID id,uint32_t index,Decoration decoration) const657 const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
658 {
659 auto *m = find_meta(id);
660 if (m)
661 {
662 if (!has_member_decoration(id, index, decoration))
663 return empty_string;
664
665 auto &dec = m->members[index];
666
667 switch (decoration)
668 {
669 case DecorationHlslSemanticGOOGLE:
670 return dec.hlsl_semantic;
671
672 default:
673 return empty_string;
674 }
675 }
676 else
677 return empty_string;
678 }
679
unset_member_decoration(TypeID id,uint32_t index,Decoration decoration)680 void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
681 {
682 auto &m = meta[id];
683 if (index >= m.members.size())
684 return;
685
686 auto &dec = m.members[index];
687
688 dec.decoration_flags.clear(decoration);
689 switch (decoration)
690 {
691 case DecorationBuiltIn:
692 dec.builtin = false;
693 break;
694
695 case DecorationLocation:
696 dec.location = 0;
697 break;
698
699 case DecorationComponent:
700 dec.component = 0;
701 break;
702
703 case DecorationOffset:
704 dec.offset = 0;
705 break;
706
707 case DecorationXfbBuffer:
708 dec.xfb_buffer = 0;
709 break;
710
711 case DecorationXfbStride:
712 dec.xfb_stride = 0;
713 break;
714
715 case DecorationSpecId:
716 dec.spec_id = 0;
717 break;
718
719 case DecorationHlslSemanticGOOGLE:
720 dec.hlsl_semantic.clear();
721 break;
722
723 default:
724 break;
725 }
726 }
727
increase_bound_by(uint32_t incr_amount)728 uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
729 {
730 auto curr_bound = ids.size();
731 auto new_bound = curr_bound + incr_amount;
732
733 ids.reserve(ids.size() + incr_amount);
734 for (uint32_t i = 0; i < incr_amount; i++)
735 ids.emplace_back(pool_group.get());
736
737 block_meta.resize(new_bound);
738 return uint32_t(curr_bound);
739 }
740
remove_typed_id(Types type,ID id)741 void ParsedIR::remove_typed_id(Types type, ID id)
742 {
743 auto &type_ids = ids_for_type[type];
744 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
745 }
746
reset_all_of_type(Types type)747 void ParsedIR::reset_all_of_type(Types type)
748 {
749 for (auto &id : ids_for_type[type])
750 if (ids[id].get_type() == type)
751 ids[id].reset();
752
753 ids_for_type[type].clear();
754 }
755
add_typed_id(Types type,ID id)756 void ParsedIR::add_typed_id(Types type, ID id)
757 {
758 if (loop_iteration_depth_hard != 0)
759 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
760
761 if (loop_iteration_depth_soft != 0)
762 {
763 if (!ids[id].empty())
764 SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
765 return;
766 }
767
768 if (ids[id].empty() || ids[id].get_type() != type)
769 {
770 switch (type)
771 {
772 case TypeConstant:
773 ids_for_constant_or_variable.push_back(id);
774 ids_for_constant_or_type.push_back(id);
775 break;
776
777 case TypeVariable:
778 ids_for_constant_or_variable.push_back(id);
779 break;
780
781 case TypeType:
782 case TypeConstantOp:
783 ids_for_constant_or_type.push_back(id);
784 break;
785
786 default:
787 break;
788 }
789 }
790
791 if (ids[id].empty())
792 {
793 ids_for_type[type].push_back(id);
794 }
795 else if (ids[id].get_type() != type)
796 {
797 remove_typed_id(ids[id].get_type(), id);
798 ids_for_type[type].push_back(id);
799 }
800 }
801
find_meta(ID id) const802 const Meta *ParsedIR::find_meta(ID id) const
803 {
804 auto itr = meta.find(id);
805 if (itr != end(meta))
806 return &itr->second;
807 else
808 return nullptr;
809 }
810
find_meta(ID id)811 Meta *ParsedIR::find_meta(ID id)
812 {
813 auto itr = meta.find(id);
814 if (itr != end(meta))
815 return &itr->second;
816 else
817 return nullptr;
818 }
819
create_loop_hard_lock() const820 ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
821 {
822 return ParsedIR::LoopLock(&loop_iteration_depth_hard);
823 }
824
create_loop_soft_lock() const825 ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
826 {
827 return ParsedIR::LoopLock(&loop_iteration_depth_soft);
828 }
829
~LoopLock()830 ParsedIR::LoopLock::~LoopLock()
831 {
832 if (lock)
833 (*lock)--;
834 }
835
LoopLock(uint32_t * lock_)836 ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
837 : lock(lock_)
838 {
839 if (lock)
840 (*lock)++;
841 }
842
LoopLock(LoopLock && other)843 ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
844 {
845 *this = move(other);
846 }
847
operator =(LoopLock && other)848 ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
849 {
850 if (lock)
851 (*lock)--;
852 lock = other.lock;
853 other.lock = nullptr;
854 return *this;
855 }
856
make_constant_null(uint32_t id,uint32_t type,bool add_to_typed_id_set)857 void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
858 {
859 auto &constant_type = get<SPIRType>(type);
860
861 if (constant_type.pointer)
862 {
863 if (add_to_typed_id_set)
864 add_typed_id(TypeConstant, id);
865 auto &constant = variant_set<SPIRConstant>(ids[id], type);
866 constant.self = id;
867 constant.make_null(constant_type);
868 }
869 else if (!constant_type.array.empty())
870 {
871 assert(constant_type.parent_type);
872 uint32_t parent_id = increase_bound_by(1);
873 make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
874
875 if (!constant_type.array_size_literal.back())
876 SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
877
878 SmallVector<uint32_t> elements(constant_type.array.back());
879 for (uint32_t i = 0; i < constant_type.array.back(); i++)
880 elements[i] = parent_id;
881
882 if (add_to_typed_id_set)
883 add_typed_id(TypeConstant, id);
884 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
885 }
886 else if (!constant_type.member_types.empty())
887 {
888 uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
889 SmallVector<uint32_t> elements(constant_type.member_types.size());
890 for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
891 {
892 make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
893 elements[i] = member_ids + i;
894 }
895
896 if (add_to_typed_id_set)
897 add_typed_id(TypeConstant, id);
898 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
899 }
900 else
901 {
902 if (add_to_typed_id_set)
903 add_typed_id(TypeConstant, id);
904 auto &constant = variant_set<SPIRConstant>(ids[id], type);
905 constant.self = id;
906 constant.make_null(constant_type);
907 }
908 }
909
910 } // namespace SPIRV_CROSS_NAMESPACE
911