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