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