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