/src/spirv-cross/spirv_cross_parsed_ir.cpp
Line | Count | Source |
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 SPIRV_CROSS_SPV_HEADER_NAMESPACE; |
30 | | |
31 | | namespace SPIRV_CROSS_NAMESPACE |
32 | | { |
33 | | ParsedIR::ParsedIR() |
34 | 3.93k | { |
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 | 3.93k | pool_group.reset(new ObjectPoolGroup); |
38 | | |
39 | 3.93k | pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>); |
40 | 3.93k | pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>); |
41 | 3.93k | pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>); |
42 | 3.93k | pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>); |
43 | 3.93k | pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>); |
44 | 3.93k | pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>); |
45 | 3.93k | pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>); |
46 | 3.93k | pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>); |
47 | 3.93k | pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>); |
48 | 3.93k | pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>); |
49 | 3.93k | pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>); |
50 | 3.93k | pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>); |
51 | 3.93k | pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>); |
52 | 3.93k | pool_group->pools[TypeDebugLocalVariable].reset(new ObjectPool<SPIRDebugLocalVariable>); |
53 | 3.93k | } |
54 | | |
55 | | // Should have been default-implemented, but need this on MSVC 2013. |
56 | | ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT |
57 | 0 | { |
58 | 0 | *this = std::move(other); |
59 | 0 | } |
60 | | |
61 | | ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT |
62 | 0 | { |
63 | 0 | if (this != &other) |
64 | 0 | { |
65 | 0 | pool_group = std::move(other.pool_group); |
66 | 0 | spirv = std::move(other.spirv); |
67 | 0 | meta = std::move(other.meta); |
68 | 0 | for (int i = 0; i < TypeCount; i++) |
69 | 0 | ids_for_type[i] = std::move(other.ids_for_type[i]); |
70 | 0 | ids_for_constant_undef_or_type = std::move(other.ids_for_constant_undef_or_type); |
71 | 0 | ids_for_constant_or_variable = std::move(other.ids_for_constant_or_variable); |
72 | 0 | declared_capabilities = std::move(other.declared_capabilities); |
73 | 0 | declared_extensions = std::move(other.declared_extensions); |
74 | 0 | block_meta = std::move(other.block_meta); |
75 | 0 | continue_block_to_loop_header = std::move(other.continue_block_to_loop_header); |
76 | 0 | entry_points = std::move(other.entry_points); |
77 | 0 | ids = std::move(other.ids); |
78 | 0 | addressing_model = other.addressing_model; |
79 | 0 | memory_model = other.memory_model; |
80 | |
|
81 | 0 | default_entry_point = other.default_entry_point; |
82 | 0 | is_library_module = other.is_library_module; |
83 | 0 | library_exports = std::move(other.library_exports); |
84 | 0 | library_exported_functions = std::move(other.library_exported_functions); |
85 | 0 | sources = std::move(other.sources); |
86 | 0 | loop_iteration_depth_hard = other.loop_iteration_depth_hard; |
87 | 0 | loop_iteration_depth_soft = other.loop_iteration_depth_soft; |
88 | |
|
89 | 0 | meta_needing_name_fixup = std::move(other.meta_needing_name_fixup); |
90 | 0 | load_type_width = std::move(other.load_type_width); |
91 | 0 | } |
92 | 0 | return *this; |
93 | 0 | } |
94 | | |
95 | | ParsedIR::ParsedIR(const ParsedIR &other) |
96 | 0 | : ParsedIR() |
97 | 0 | { |
98 | 0 | *this = other; |
99 | 0 | } |
100 | | |
101 | | ParsedIR &ParsedIR::operator=(const ParsedIR &other) |
102 | 0 | { |
103 | 0 | if (this != &other) |
104 | 0 | { |
105 | 0 | spirv = other.spirv; |
106 | 0 | meta = other.meta; |
107 | 0 | for (int i = 0; i < TypeCount; i++) |
108 | 0 | ids_for_type[i] = other.ids_for_type[i]; |
109 | 0 | ids_for_constant_undef_or_type = other.ids_for_constant_undef_or_type; |
110 | 0 | ids_for_constant_or_variable = other.ids_for_constant_or_variable; |
111 | 0 | declared_capabilities = other.declared_capabilities; |
112 | 0 | declared_extensions = other.declared_extensions; |
113 | 0 | block_meta = other.block_meta; |
114 | 0 | continue_block_to_loop_header = other.continue_block_to_loop_header; |
115 | 0 | entry_points = other.entry_points; |
116 | 0 | default_entry_point = other.default_entry_point; |
117 | 0 | is_library_module = other.is_library_module; |
118 | 0 | library_exports = other.library_exports; |
119 | 0 | library_exported_functions = other.library_exported_functions; |
120 | 0 | sources = other.sources; |
121 | 0 | loop_iteration_depth_hard = other.loop_iteration_depth_hard; |
122 | 0 | loop_iteration_depth_soft = other.loop_iteration_depth_soft; |
123 | 0 | addressing_model = other.addressing_model; |
124 | 0 | memory_model = other.memory_model; |
125 | | |
126 | |
|
127 | 0 | meta_needing_name_fixup = other.meta_needing_name_fixup; |
128 | 0 | load_type_width = other.load_type_width; |
129 | | |
130 | | // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor. |
131 | | // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group. |
132 | 0 | ids.clear(); |
133 | 0 | ids.reserve(other.ids.size()); |
134 | 0 | for (size_t i = 0; i < other.ids.size(); i++) |
135 | 0 | { |
136 | 0 | ids.emplace_back(pool_group.get()); |
137 | 0 | ids.back() = other.ids[i]; |
138 | 0 | } |
139 | 0 | } |
140 | 0 | return *this; |
141 | 0 | } |
142 | | |
143 | | void ParsedIR::set_id_bounds(uint32_t bounds) |
144 | 3.91k | { |
145 | 3.91k | ids.reserve(bounds); |
146 | 1.07G | while (ids.size() < bounds) |
147 | 1.07G | ids.emplace_back(pool_group.get()); |
148 | | |
149 | 3.91k | block_meta.resize(bounds); |
150 | 3.91k | } |
151 | | |
152 | | // Roll our own versions of these functions to avoid potential locale shenanigans. |
153 | | static bool is_alpha(char c) |
154 | 44.9k | { |
155 | 44.9k | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); |
156 | 44.9k | } |
157 | | |
158 | | static bool is_numeric(char c) |
159 | 30.9k | { |
160 | 30.9k | return c >= '0' && c <= '9'; |
161 | 30.9k | } |
162 | | |
163 | | static bool is_alphanumeric(char c) |
164 | 44.9k | { |
165 | 44.9k | return is_alpha(c) || is_numeric(c); |
166 | 44.9k | } |
167 | | |
168 | | static bool is_valid_identifier(const string &name) |
169 | 14.6k | { |
170 | 14.6k | if (name.empty()) |
171 | 645 | return true; |
172 | | |
173 | 13.9k | if (is_numeric(name[0])) |
174 | 1.95k | return false; |
175 | | |
176 | 12.0k | for (auto c : name) |
177 | 44.9k | if (!is_alphanumeric(c) && c != '_') |
178 | 5.73k | return false; |
179 | | |
180 | 6.30k | bool saw_underscore = false; |
181 | | // Two underscores in a row is not a valid identifier either. |
182 | | // Technically reserved, but it's easier to treat it as invalid. |
183 | 6.30k | for (auto c : name) |
184 | 32.4k | { |
185 | 32.4k | bool is_underscore = c == '_'; |
186 | 32.4k | if (is_underscore && saw_underscore) |
187 | 711 | return false; |
188 | 31.7k | saw_underscore = is_underscore; |
189 | 31.7k | } |
190 | | |
191 | 5.59k | return true; |
192 | 6.30k | } |
193 | | |
194 | | static bool is_reserved_prefix(const string &name) |
195 | 6.23k | { |
196 | | // Generic reserved identifiers used by the implementation. |
197 | 6.23k | return name.compare(0, 3, "gl_", 3) == 0 || |
198 | | // Ignore this case for now, might rewrite internal code to always use spv prefix. |
199 | | //name.compare(0, 11, "SPIRV_Cross", 11) == 0 || |
200 | 6.07k | name.compare(0, 3, "spv", 3) == 0; |
201 | 6.23k | } |
202 | | |
203 | | static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes) |
204 | 6.23k | { |
205 | 6.23k | if (!allow_reserved_prefixes && is_reserved_prefix(name)) |
206 | 189 | return true; |
207 | | |
208 | 6.04k | if (member) |
209 | 975 | { |
210 | | // Reserved member identifiers come in one form: |
211 | | // _m[0-9]+$. |
212 | 975 | if (name.size() < 3) |
213 | 249 | return false; |
214 | | |
215 | 726 | if (name.compare(0, 2, "_m", 2) != 0) |
216 | 214 | return false; |
217 | | |
218 | 512 | size_t index = 2; |
219 | 532 | while (index < name.size() && is_numeric(name[index])) |
220 | 20 | index++; |
221 | | |
222 | 512 | return index == name.size(); |
223 | 726 | } |
224 | 5.07k | else |
225 | 5.07k | { |
226 | | // Reserved non-member identifiers come in two forms: |
227 | | // _[0-9]+$, used for temporaries which map directly to a SPIR-V ID. |
228 | | // _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID. |
229 | 5.07k | if (name.size() < 2) |
230 | 1.82k | return false; |
231 | | |
232 | 3.24k | if (name[0] != '_' || !is_numeric(name[1])) |
233 | 2.53k | return false; |
234 | | |
235 | 716 | size_t index = 2; |
236 | 2.35k | while (index < name.size() && is_numeric(name[index])) |
237 | 1.64k | index++; |
238 | | |
239 | 716 | return index == name.size() || (index < name.size() && name[index] == '_'); |
240 | 3.24k | } |
241 | 6.04k | } |
242 | | |
243 | | bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes) |
244 | 0 | { |
245 | 0 | return is_reserved_identifier(str, false, allow_reserved_prefixes); |
246 | 0 | } |
247 | | |
248 | | uint32_t ParsedIR::get_spirv_version() const |
249 | 0 | { |
250 | 0 | return spirv[1]; |
251 | 0 | } |
252 | | |
253 | | static string make_unreserved_identifier(const string &name) |
254 | 0 | { |
255 | 0 | if (is_reserved_prefix(name)) |
256 | 0 | return "_RESERVED_IDENTIFIER_FIXUP_" + name; |
257 | 0 | else |
258 | 0 | return "_RESERVED_IDENTIFIER_FIXUP" + name; |
259 | 0 | } |
260 | | |
261 | | void ParsedIR::sanitize_underscores(std::string &str) |
262 | 0 | { |
263 | | // Compact adjacent underscores to make it valid. |
264 | 0 | auto dst = str.begin(); |
265 | 0 | auto src = dst; |
266 | 0 | bool saw_underscore = false; |
267 | 0 | while (src != str.end()) |
268 | 0 | { |
269 | 0 | bool is_underscore = *src == '_'; |
270 | 0 | if (saw_underscore && is_underscore) |
271 | 0 | { |
272 | 0 | src++; |
273 | 0 | } |
274 | 0 | else |
275 | 0 | { |
276 | 0 | if (dst != src) |
277 | 0 | *dst = *src; |
278 | 0 | dst++; |
279 | 0 | src++; |
280 | 0 | saw_underscore = is_underscore; |
281 | 0 | } |
282 | 0 | } |
283 | 0 | str.erase(dst, str.end()); |
284 | 0 | } |
285 | | |
286 | | static string ensure_valid_identifier(const string &name) |
287 | 0 | { |
288 | | // Functions in glslangValidator are mangled with name(<mangled> stuff. |
289 | | // Normally, we would never see '(' in any legal identifiers, so just strip them out. |
290 | 0 | auto str = name.substr(0, name.find('(')); |
291 | |
|
292 | 0 | if (str.empty()) |
293 | 0 | return str; |
294 | | |
295 | 0 | if (is_numeric(str[0])) |
296 | 0 | str[0] = '_'; |
297 | |
|
298 | 0 | for (auto &c : str) |
299 | 0 | if (!is_alphanumeric(c) && c != '_') |
300 | 0 | c = '_'; |
301 | |
|
302 | 0 | ParsedIR::sanitize_underscores(str); |
303 | 0 | return str; |
304 | 0 | } |
305 | | |
306 | | const string &ParsedIR::get_name(ID id) const |
307 | 8.40k | { |
308 | 8.40k | auto *m = find_meta(id); |
309 | 8.40k | if (m) |
310 | 5.81k | return m->decoration.alias; |
311 | 2.59k | else |
312 | 2.59k | return empty_string; |
313 | 8.40k | } |
314 | | |
315 | | const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const |
316 | 0 | { |
317 | 0 | auto *m = find_meta(id); |
318 | 0 | if (m) |
319 | 0 | { |
320 | 0 | if (index >= m->members.size()) |
321 | 0 | return empty_string; |
322 | 0 | return m->members[index].alias; |
323 | 0 | } |
324 | 0 | else |
325 | 0 | return empty_string; |
326 | 0 | } |
327 | | |
328 | | void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes) |
329 | 0 | { |
330 | 0 | if (!is_valid_identifier(name)) |
331 | 0 | name = ensure_valid_identifier(name); |
332 | 0 | if (is_reserved_identifier(name, member, allow_reserved_prefixes)) |
333 | 0 | name = make_unreserved_identifier(name); |
334 | 0 | } |
335 | | |
336 | | void ParsedIR::fixup_reserved_names() |
337 | 0 | { |
338 | 0 | for (uint32_t id : meta_needing_name_fixup) |
339 | 0 | { |
340 | | // Don't rename remapped variables like 'gl_LastFragDepthARM'. |
341 | 0 | if (ids[id].get_type() == TypeVariable && get<SPIRVariable>(id).remapped_variable) |
342 | 0 | continue; |
343 | | |
344 | 0 | auto &m = meta[id]; |
345 | 0 | sanitize_identifier(m.decoration.alias, false, false); |
346 | 0 | for (auto &memb : m.members) |
347 | 0 | sanitize_identifier(memb.alias, true, false); |
348 | 0 | } |
349 | 0 | meta_needing_name_fixup.clear(); |
350 | 0 | } |
351 | | |
352 | | void ParsedIR::set_name(ID id, const string &name) |
353 | 12.7k | { |
354 | 12.7k | auto &m = meta[id]; |
355 | 12.7k | m.decoration.alias = name; |
356 | 12.7k | if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false)) |
357 | 7.99k | meta_needing_name_fixup.insert(id); |
358 | 12.7k | } |
359 | | |
360 | | void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name) |
361 | 1.90k | { |
362 | 1.90k | auto &m = meta[id]; |
363 | 1.90k | m.members.resize(max(m.members.size(), size_t(index) + 1)); |
364 | 1.90k | m.members[index].alias = name; |
365 | 1.90k | if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false)) |
366 | 935 | meta_needing_name_fixup.insert(id); |
367 | 1.90k | } |
368 | | |
369 | | void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument) |
370 | 2.19k | { |
371 | 2.19k | auto &dec = meta[id].decoration; |
372 | 2.19k | dec.decoration_flags.set(decoration); |
373 | | |
374 | 2.19k | switch (decoration) |
375 | 2.19k | { |
376 | 2.05k | case DecorationUserSemantic: |
377 | 2.05k | dec.user_semantic = argument; |
378 | 2.05k | break; |
379 | | |
380 | 1 | case DecorationUserTypeGOOGLE: |
381 | 1 | dec.user_type = argument; |
382 | 1 | break; |
383 | | |
384 | 144 | default: |
385 | 144 | break; |
386 | 2.19k | } |
387 | 2.19k | } |
388 | | |
389 | | void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument) |
390 | 79.8k | { |
391 | 79.8k | auto &dec = meta[id].decoration; |
392 | 79.8k | dec.decoration_flags.set(decoration); |
393 | | |
394 | 79.8k | switch (decoration) |
395 | 79.8k | { |
396 | 639 | case DecorationBuiltIn: |
397 | 639 | dec.builtin = true; |
398 | 639 | dec.builtin_type = static_cast<BuiltIn>(argument); |
399 | 639 | break; |
400 | | |
401 | 754 | case DecorationLocation: |
402 | 754 | dec.location = argument; |
403 | 754 | break; |
404 | | |
405 | 3.01k | case DecorationComponent: |
406 | 3.01k | dec.component = argument; |
407 | 3.01k | break; |
408 | | |
409 | 159 | case DecorationOffset: |
410 | 159 | dec.offset = argument; |
411 | 159 | break; |
412 | | |
413 | 0 | case DecorationOffsetIdEXT: |
414 | 0 | dec.offset_id = argument; |
415 | 0 | break; |
416 | | |
417 | 100 | case DecorationXfbBuffer: |
418 | 100 | dec.xfb_buffer = argument; |
419 | 100 | break; |
420 | | |
421 | 26 | case DecorationXfbStride: |
422 | 26 | dec.xfb_stride = argument; |
423 | 26 | break; |
424 | | |
425 | 84 | case DecorationStream: |
426 | 84 | dec.stream = argument; |
427 | 84 | break; |
428 | | |
429 | 3.27k | case DecorationArrayStride: |
430 | 3.27k | dec.array_stride = argument; |
431 | 3.27k | break; |
432 | | |
433 | 443 | case DecorationArrayStrideIdEXT: |
434 | 443 | dec.array_stride_id = argument; |
435 | 443 | break; |
436 | | |
437 | 320 | case DecorationMatrixStride: |
438 | 320 | dec.matrix_stride = argument; |
439 | 320 | break; |
440 | | |
441 | 1.72k | case DecorationBinding: |
442 | 1.72k | dec.binding = argument; |
443 | 1.72k | break; |
444 | | |
445 | 853 | case DecorationDescriptorSet: |
446 | 853 | dec.set = argument; |
447 | 853 | break; |
448 | | |
449 | 98 | case DecorationInputAttachmentIndex: |
450 | 98 | dec.input_attachment = argument; |
451 | 98 | break; |
452 | | |
453 | 654 | case DecorationSpecId: |
454 | 654 | dec.spec_id = argument; |
455 | 654 | break; |
456 | | |
457 | 3.38k | case DecorationIndex: |
458 | 3.38k | dec.index = argument; |
459 | 3.38k | break; |
460 | | |
461 | 220 | case DecorationHlslCounterBufferGOOGLE: |
462 | 220 | meta[id].hlsl_magic_counter_buffer = argument; |
463 | 220 | meta[argument].hlsl_is_magic_counter_buffer = true; |
464 | 220 | break; |
465 | | |
466 | 93 | case DecorationFPRoundingMode: |
467 | 93 | dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument); |
468 | 93 | break; |
469 | | |
470 | 73 | case DecorationFPFastMathMode: |
471 | 73 | dec.fp_fast_math_mode = static_cast<FPFastMathModeMask>(argument); |
472 | 73 | break; |
473 | | |
474 | 63.9k | default: |
475 | 63.9k | break; |
476 | 79.8k | } |
477 | 79.8k | } |
478 | | |
479 | | void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument) |
480 | 14.4k | { |
481 | 14.4k | auto &m = meta[id]; |
482 | 14.4k | m.members.resize(max(m.members.size(), size_t(index) + 1)); |
483 | 14.4k | auto &dec = m.members[index]; |
484 | 14.4k | dec.decoration_flags.set(decoration); |
485 | | |
486 | 14.4k | switch (decoration) |
487 | 14.4k | { |
488 | 2.00k | case DecorationBuiltIn: |
489 | 2.00k | dec.builtin = true; |
490 | 2.00k | dec.builtin_type = static_cast<BuiltIn>(argument); |
491 | 2.00k | break; |
492 | | |
493 | 80 | case DecorationLocation: |
494 | 80 | dec.location = argument; |
495 | 80 | break; |
496 | | |
497 | 442 | case DecorationComponent: |
498 | 442 | dec.component = argument; |
499 | 442 | break; |
500 | | |
501 | 285 | case DecorationBinding: |
502 | 285 | dec.binding = argument; |
503 | 285 | break; |
504 | | |
505 | 522 | case DecorationOffset: |
506 | 522 | dec.offset = argument; |
507 | 522 | break; |
508 | | |
509 | 0 | case DecorationOffsetIdEXT: |
510 | 0 | dec.offset_id = argument; |
511 | 0 | break; |
512 | | |
513 | 439 | case DecorationXfbBuffer: |
514 | 439 | dec.xfb_buffer = argument; |
515 | 439 | break; |
516 | | |
517 | 16 | case DecorationXfbStride: |
518 | 16 | dec.xfb_stride = argument; |
519 | 16 | break; |
520 | | |
521 | 17 | case DecorationStream: |
522 | 17 | dec.stream = argument; |
523 | 17 | break; |
524 | | |
525 | 600 | case DecorationSpecId: |
526 | 600 | dec.spec_id = argument; |
527 | 600 | break; |
528 | | |
529 | 315 | case DecorationMatrixStride: |
530 | 315 | dec.matrix_stride = argument; |
531 | 315 | break; |
532 | | |
533 | 189 | case DecorationIndex: |
534 | 189 | dec.index = argument; |
535 | 189 | break; |
536 | | |
537 | 9.52k | default: |
538 | 9.52k | break; |
539 | 14.4k | } |
540 | 14.4k | } |
541 | | |
542 | | // Recursively marks any constants referenced by the specified constant instruction as being used |
543 | | // as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp). |
544 | | void ParsedIR::mark_used_as_array_length(ID id) |
545 | 1.17k | { |
546 | 1.17k | switch (ids[id].get_type()) |
547 | 1.17k | { |
548 | 289 | case TypeConstant: |
549 | 289 | { |
550 | 289 | auto &c = get<SPIRConstant>(id); |
551 | 289 | c.is_used_as_array_length = true; |
552 | | |
553 | | // Mark composite dependencies as well. |
554 | 289 | for (auto &sub_id: c.m.id) |
555 | 1.15k | if (sub_id) |
556 | 0 | mark_used_as_array_length(sub_id); |
557 | | |
558 | 578 | for (uint32_t col = 0; col < c.m.columns; col++) |
559 | 289 | { |
560 | 289 | for (auto &sub_id : c.m.c[col].id) |
561 | 1.15k | if (sub_id) |
562 | 0 | mark_used_as_array_length(sub_id); |
563 | 289 | } |
564 | | |
565 | 289 | for (auto &sub_id : c.subconstants) |
566 | 0 | if (sub_id) |
567 | 0 | mark_used_as_array_length(sub_id); |
568 | 289 | break; |
569 | 0 | } |
570 | | |
571 | 0 | case TypeConstantOp: |
572 | 0 | { |
573 | 0 | auto &cop = get<SPIRConstantOp>(id); |
574 | 0 | if (cop.opcode == OpCompositeExtract) |
575 | 0 | mark_used_as_array_length(cop.arguments[0]); |
576 | 0 | else if (cop.opcode == OpCompositeInsert) |
577 | 0 | { |
578 | 0 | mark_used_as_array_length(cop.arguments[0]); |
579 | 0 | mark_used_as_array_length(cop.arguments[1]); |
580 | 0 | } |
581 | 0 | else |
582 | 0 | for (uint32_t arg_id : cop.arguments) |
583 | 0 | mark_used_as_array_length(arg_id); |
584 | 0 | break; |
585 | 0 | } |
586 | | |
587 | 884 | case TypeUndef: |
588 | 884 | break; |
589 | | |
590 | 0 | default: |
591 | 0 | assert(0); |
592 | 1.17k | } |
593 | 1.17k | } |
594 | | |
595 | | Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const |
596 | 0 | { |
597 | 0 | if (type.member_types.empty()) |
598 | 0 | return {}; |
599 | | |
600 | 0 | Bitset all_members_flags = get_member_decoration_bitset(type.self, 0); |
601 | 0 | for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++) |
602 | 0 | all_members_flags.merge_and(get_member_decoration_bitset(type.self, i)); |
603 | 0 | return all_members_flags; |
604 | 0 | } |
605 | | |
606 | | Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const |
607 | 0 | { |
608 | 0 | auto &type = get<SPIRType>(var.basetype); |
609 | 0 | if (type.basetype != SPIRType::Struct) |
610 | 0 | SPIRV_CROSS_THROW("Cannot get buffer block flags for non-buffer variable."); |
611 | | |
612 | | // Some flags like non-writable, non-readable are actually found |
613 | | // as member decorations. If all members have a decoration set, propagate |
614 | | // the decoration up as a regular variable decoration. |
615 | 0 | Bitset base_flags; |
616 | 0 | auto *m = find_meta(var.self); |
617 | 0 | if (m) |
618 | 0 | base_flags = m->decoration.decoration_flags; |
619 | |
|
620 | 0 | if (type.member_types.empty()) |
621 | 0 | return base_flags; |
622 | | |
623 | 0 | auto all_members_flags = get_buffer_block_type_flags(type); |
624 | 0 | base_flags.merge_or(all_members_flags); |
625 | 0 | return base_flags; |
626 | 0 | } |
627 | | |
628 | | const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const |
629 | 0 | { |
630 | 0 | auto *m = find_meta(id); |
631 | 0 | if (m) |
632 | 0 | { |
633 | 0 | if (index >= m->members.size()) |
634 | 0 | return cleared_bitset; |
635 | 0 | return m->members[index].decoration_flags; |
636 | 0 | } |
637 | 0 | else |
638 | 0 | return cleared_bitset; |
639 | 0 | } |
640 | | |
641 | | bool ParsedIR::has_decoration(ID id, Decoration decoration) const |
642 | 0 | { |
643 | 0 | return get_decoration_bitset(id).get(decoration); |
644 | 0 | } |
645 | | |
646 | | uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const |
647 | 76.3k | { |
648 | 76.3k | auto *m = find_meta(id); |
649 | 76.3k | if (!m) |
650 | 0 | return 0; |
651 | | |
652 | 76.3k | auto &dec = m->decoration; |
653 | 76.3k | if (!dec.decoration_flags.get(decoration)) |
654 | 0 | return 0; |
655 | | |
656 | 76.3k | switch (decoration) |
657 | 76.3k | { |
658 | 2.02k | case DecorationBuiltIn: |
659 | 2.02k | return dec.builtin_type; |
660 | 65 | case DecorationLocation: |
661 | 65 | return dec.location; |
662 | 444 | case DecorationComponent: |
663 | 444 | return dec.component; |
664 | 144 | case DecorationOffset: |
665 | 144 | return dec.offset; |
666 | 0 | case DecorationOffsetIdEXT: |
667 | 0 | return dec.offset_id; |
668 | 503 | case DecorationXfbBuffer: |
669 | 503 | return dec.xfb_buffer; |
670 | 26 | case DecorationXfbStride: |
671 | 26 | return dec.xfb_stride; |
672 | 91 | case DecorationStream: |
673 | 91 | return dec.stream; |
674 | 473 | case DecorationBinding: |
675 | 473 | return dec.binding; |
676 | 826 | case DecorationDescriptorSet: |
677 | 826 | return dec.set; |
678 | 84 | case DecorationInputAttachmentIndex: |
679 | 84 | return dec.input_attachment; |
680 | 1.18k | case DecorationSpecId: |
681 | 1.18k | return dec.spec_id; |
682 | 3.40k | case DecorationArrayStride: |
683 | 3.40k | return dec.array_stride; |
684 | 476 | case DecorationArrayStrideIdEXT: |
685 | 476 | return dec.array_stride_id; |
686 | 593 | case DecorationMatrixStride: |
687 | 593 | return dec.matrix_stride; |
688 | 3.51k | case DecorationIndex: |
689 | 3.51k | return dec.index; |
690 | 84 | case DecorationFPRoundingMode: |
691 | 84 | return dec.fp_rounding_mode; |
692 | 61 | case DecorationFPFastMathMode: |
693 | 61 | return dec.fp_fast_math_mode; |
694 | 62.3k | default: |
695 | 62.3k | return 1; |
696 | 76.3k | } |
697 | 76.3k | } |
698 | | |
699 | | const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const |
700 | 2.39k | { |
701 | 2.39k | auto *m = find_meta(id); |
702 | 2.39k | if (!m) |
703 | 0 | return empty_string; |
704 | | |
705 | 2.39k | auto &dec = m->decoration; |
706 | | |
707 | 2.39k | if (!dec.decoration_flags.get(decoration)) |
708 | 0 | return empty_string; |
709 | | |
710 | 2.39k | switch (decoration) |
711 | 2.39k | { |
712 | 2.39k | case DecorationUserSemantic: |
713 | 2.39k | return dec.user_semantic; |
714 | | |
715 | 0 | case DecorationUserTypeGOOGLE: |
716 | 0 | return dec.user_type; |
717 | | |
718 | 0 | default: |
719 | 0 | return empty_string; |
720 | 2.39k | } |
721 | 2.39k | } |
722 | | |
723 | | void ParsedIR::unset_decoration(ID id, Decoration decoration) |
724 | 0 | { |
725 | 0 | auto &dec = meta[id].decoration; |
726 | 0 | dec.decoration_flags.clear(decoration); |
727 | 0 | switch (decoration) |
728 | 0 | { |
729 | 0 | case DecorationBuiltIn: |
730 | 0 | dec.builtin = false; |
731 | 0 | break; |
732 | | |
733 | 0 | case DecorationLocation: |
734 | 0 | dec.location = 0; |
735 | 0 | break; |
736 | | |
737 | 0 | case DecorationComponent: |
738 | 0 | dec.component = 0; |
739 | 0 | break; |
740 | | |
741 | 0 | case DecorationOffset: |
742 | 0 | dec.offset = 0; |
743 | 0 | break; |
744 | | |
745 | 0 | case DecorationOffsetIdEXT: |
746 | 0 | dec.offset_id = 0; |
747 | 0 | break; |
748 | | |
749 | 0 | case DecorationXfbBuffer: |
750 | 0 | dec.xfb_buffer = 0; |
751 | 0 | break; |
752 | | |
753 | 0 | case DecorationXfbStride: |
754 | 0 | dec.xfb_stride = 0; |
755 | 0 | break; |
756 | | |
757 | 0 | case DecorationStream: |
758 | 0 | dec.stream = 0; |
759 | 0 | break; |
760 | | |
761 | 0 | case DecorationBinding: |
762 | 0 | dec.binding = 0; |
763 | 0 | break; |
764 | | |
765 | 0 | case DecorationDescriptorSet: |
766 | 0 | dec.set = 0; |
767 | 0 | break; |
768 | | |
769 | 0 | case DecorationInputAttachmentIndex: |
770 | 0 | dec.input_attachment = 0; |
771 | 0 | break; |
772 | | |
773 | 0 | case DecorationSpecId: |
774 | 0 | dec.spec_id = 0; |
775 | 0 | break; |
776 | | |
777 | 0 | case DecorationUserSemantic: |
778 | 0 | dec.user_semantic.clear(); |
779 | 0 | break; |
780 | | |
781 | 0 | case DecorationFPRoundingMode: |
782 | 0 | dec.fp_rounding_mode = FPRoundingModeMax; |
783 | 0 | break; |
784 | | |
785 | 0 | case DecorationFPFastMathMode: |
786 | 0 | dec.fp_fast_math_mode = FPFastMathModeMaskNone; |
787 | 0 | break; |
788 | | |
789 | 0 | case DecorationHlslCounterBufferGOOGLE: |
790 | 0 | { |
791 | 0 | auto &counter = meta[id].hlsl_magic_counter_buffer; |
792 | 0 | if (counter) |
793 | 0 | { |
794 | 0 | meta[counter].hlsl_is_magic_counter_buffer = false; |
795 | 0 | counter = 0; |
796 | 0 | } |
797 | 0 | break; |
798 | 0 | } |
799 | | |
800 | 0 | default: |
801 | 0 | break; |
802 | 0 | } |
803 | 0 | } |
804 | | |
805 | | bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const |
806 | 0 | { |
807 | 0 | return get_member_decoration_bitset(id, index).get(decoration); |
808 | 0 | } |
809 | | |
810 | | uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const |
811 | 0 | { |
812 | 0 | auto *m = find_meta(id); |
813 | 0 | if (!m) |
814 | 0 | return 0; |
815 | | |
816 | 0 | if (index >= m->members.size()) |
817 | 0 | return 0; |
818 | | |
819 | 0 | auto &dec = m->members[index]; |
820 | 0 | if (!dec.decoration_flags.get(decoration)) |
821 | 0 | return 0; |
822 | | |
823 | 0 | switch (decoration) |
824 | 0 | { |
825 | 0 | case DecorationBuiltIn: |
826 | 0 | return dec.builtin_type; |
827 | 0 | case DecorationLocation: |
828 | 0 | return dec.location; |
829 | 0 | case DecorationComponent: |
830 | 0 | return dec.component; |
831 | 0 | case DecorationBinding: |
832 | 0 | return dec.binding; |
833 | 0 | case DecorationOffset: |
834 | 0 | return dec.offset; |
835 | 0 | case DecorationOffsetIdEXT: |
836 | 0 | return dec.offset_id; |
837 | 0 | case DecorationXfbBuffer: |
838 | 0 | return dec.xfb_buffer; |
839 | 0 | case DecorationXfbStride: |
840 | 0 | return dec.xfb_stride; |
841 | 0 | case DecorationStream: |
842 | 0 | return dec.stream; |
843 | 0 | case DecorationSpecId: |
844 | 0 | return dec.spec_id; |
845 | 0 | case DecorationMatrixStride: |
846 | 0 | return dec.matrix_stride; |
847 | 0 | case DecorationIndex: |
848 | 0 | return dec.index; |
849 | 0 | default: |
850 | 0 | return 1; |
851 | 0 | } |
852 | 0 | } |
853 | | |
854 | | const Bitset &ParsedIR::get_decoration_bitset(ID id) const |
855 | 0 | { |
856 | 0 | auto *m = find_meta(id); |
857 | 0 | if (m) |
858 | 0 | { |
859 | 0 | auto &dec = m->decoration; |
860 | 0 | return dec.decoration_flags; |
861 | 0 | } |
862 | 0 | else |
863 | 0 | return cleared_bitset; |
864 | 0 | } |
865 | | |
866 | | void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument) |
867 | 721 | { |
868 | 721 | auto &m = meta[id]; |
869 | 721 | m.members.resize(max(m.members.size(), size_t(index) + 1)); |
870 | 721 | auto &dec = meta[id].members[index]; |
871 | 721 | dec.decoration_flags.set(decoration); |
872 | | |
873 | 721 | switch (decoration) |
874 | 721 | { |
875 | 345 | case DecorationUserSemantic: |
876 | 345 | dec.user_semantic = argument; |
877 | 345 | break; |
878 | | |
879 | 376 | default: |
880 | 376 | break; |
881 | 721 | } |
882 | 721 | } |
883 | | |
884 | | const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const |
885 | 0 | { |
886 | 0 | auto *m = find_meta(id); |
887 | 0 | if (m) |
888 | 0 | { |
889 | 0 | if (!has_member_decoration(id, index, decoration)) |
890 | 0 | return empty_string; |
891 | | |
892 | 0 | auto &dec = m->members[index]; |
893 | |
|
894 | 0 | switch (decoration) |
895 | 0 | { |
896 | 0 | case DecorationUserSemantic: |
897 | 0 | return dec.user_semantic; |
898 | | |
899 | 0 | default: |
900 | 0 | return empty_string; |
901 | 0 | } |
902 | 0 | } |
903 | 0 | else |
904 | 0 | return empty_string; |
905 | 0 | } |
906 | | |
907 | | void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration) |
908 | 0 | { |
909 | 0 | auto &m = meta[id]; |
910 | 0 | if (index >= m.members.size()) |
911 | 0 | return; |
912 | | |
913 | 0 | auto &dec = m.members[index]; |
914 | |
|
915 | 0 | dec.decoration_flags.clear(decoration); |
916 | 0 | switch (decoration) |
917 | 0 | { |
918 | 0 | case DecorationBuiltIn: |
919 | 0 | dec.builtin = false; |
920 | 0 | break; |
921 | | |
922 | 0 | case DecorationLocation: |
923 | 0 | dec.location = 0; |
924 | 0 | break; |
925 | | |
926 | 0 | case DecorationComponent: |
927 | 0 | dec.component = 0; |
928 | 0 | break; |
929 | | |
930 | 0 | case DecorationOffset: |
931 | 0 | dec.offset = 0; |
932 | 0 | break; |
933 | | |
934 | 0 | case DecorationOffsetIdEXT: |
935 | 0 | dec.offset_id = 0; |
936 | 0 | break; |
937 | | |
938 | 0 | case DecorationXfbBuffer: |
939 | 0 | dec.xfb_buffer = 0; |
940 | 0 | break; |
941 | | |
942 | 0 | case DecorationXfbStride: |
943 | 0 | dec.xfb_stride = 0; |
944 | 0 | break; |
945 | | |
946 | 0 | case DecorationStream: |
947 | 0 | dec.stream = 0; |
948 | 0 | break; |
949 | | |
950 | 0 | case DecorationSpecId: |
951 | 0 | dec.spec_id = 0; |
952 | 0 | break; |
953 | | |
954 | 0 | case DecorationUserSemantic: |
955 | 0 | dec.user_semantic.clear(); |
956 | 0 | break; |
957 | | |
958 | 0 | default: |
959 | 0 | break; |
960 | 0 | } |
961 | 0 | } |
962 | | |
963 | | uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount) |
964 | 133k | { |
965 | 133k | auto curr_bound = ids.size(); |
966 | 133k | auto new_bound = curr_bound + incr_amount; |
967 | | |
968 | 133k | ids.reserve(ids.size() + incr_amount); |
969 | 269k | for (uint32_t i = 0; i < incr_amount; i++) |
970 | 136k | ids.emplace_back(pool_group.get()); |
971 | | |
972 | 133k | block_meta.resize(new_bound); |
973 | 133k | return uint32_t(curr_bound); |
974 | 133k | } |
975 | | |
976 | | void ParsedIR::remove_typed_id(Types type, ID id) |
977 | 75 | { |
978 | 75 | auto &type_ids = ids_for_type[type]; |
979 | 75 | type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids)); |
980 | 75 | } |
981 | | |
982 | | void ParsedIR::reset_all_of_type(Types type) |
983 | 0 | { |
984 | 0 | for (auto &id : ids_for_type[type]) |
985 | 0 | if (ids[id].get_type() == type) |
986 | 0 | ids[id].reset(); |
987 | |
|
988 | 0 | ids_for_type[type].clear(); |
989 | 0 | } |
990 | | |
991 | | void ParsedIR::add_typed_id(Types type, ID id) |
992 | 333k | { |
993 | 333k | assert(id < ids.size()); |
994 | | |
995 | 333k | if (loop_iteration_depth_hard != 0) |
996 | 0 | SPIRV_CROSS_THROW("Cannot add typed ID while looping over it."); |
997 | | |
998 | 333k | if (loop_iteration_depth_soft != 0) |
999 | 0 | { |
1000 | 0 | if (!ids[id].empty()) |
1001 | 0 | SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked."); |
1002 | 0 | return; |
1003 | 0 | } |
1004 | | |
1005 | 333k | if (ids[id].empty() || ids[id].get_type() != type) |
1006 | 158k | { |
1007 | 158k | switch (type) |
1008 | 158k | { |
1009 | 140k | case TypeConstant: |
1010 | 140k | ids_for_constant_or_variable.push_back(id); |
1011 | 140k | ids_for_constant_undef_or_type.push_back(id); |
1012 | 140k | break; |
1013 | | |
1014 | 3.14k | case TypeVariable: |
1015 | 3.14k | ids_for_constant_or_variable.push_back(id); |
1016 | 3.14k | break; |
1017 | | |
1018 | 6.50k | case TypeType: |
1019 | 6.55k | case TypeConstantOp: |
1020 | 6.65k | case TypeUndef: |
1021 | 6.65k | ids_for_constant_undef_or_type.push_back(id); |
1022 | 6.65k | break; |
1023 | | |
1024 | 7.75k | default: |
1025 | 7.75k | break; |
1026 | 158k | } |
1027 | 158k | } |
1028 | | |
1029 | 333k | if (ids[id].empty()) |
1030 | 158k | { |
1031 | 158k | ids_for_type[type].push_back(id); |
1032 | 158k | } |
1033 | 175k | else if (ids[id].get_type() != type) |
1034 | 75 | { |
1035 | 75 | remove_typed_id(ids[id].get_type(), id); |
1036 | 75 | ids_for_type[type].push_back(id); |
1037 | 75 | } |
1038 | 333k | } |
1039 | | |
1040 | | const Meta *ParsedIR::find_meta(ID id) const |
1041 | 87.1k | { |
1042 | 87.1k | auto itr = meta.find(id); |
1043 | 87.1k | if (itr != end(meta)) |
1044 | 84.5k | return &itr->second; |
1045 | 2.59k | else |
1046 | 2.59k | return nullptr; |
1047 | 87.1k | } |
1048 | | |
1049 | | Meta *ParsedIR::find_meta(ID id) |
1050 | 0 | { |
1051 | 0 | auto itr = meta.find(id); |
1052 | 0 | if (itr != end(meta)) |
1053 | 0 | return &itr->second; |
1054 | 0 | else |
1055 | 0 | return nullptr; |
1056 | 0 | } |
1057 | | |
1058 | | ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const |
1059 | 0 | { |
1060 | 0 | return ParsedIR::LoopLock(&loop_iteration_depth_hard); |
1061 | 0 | } |
1062 | | |
1063 | | ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const |
1064 | 0 | { |
1065 | 0 | return ParsedIR::LoopLock(&loop_iteration_depth_soft); |
1066 | 0 | } |
1067 | | |
1068 | | ParsedIR::LoopLock::~LoopLock() |
1069 | 0 | { |
1070 | 0 | if (lock) |
1071 | 0 | (*lock)--; |
1072 | 0 | } |
1073 | | |
1074 | | ParsedIR::LoopLock::LoopLock(uint32_t *lock_) |
1075 | 0 | : lock(lock_) |
1076 | 0 | { |
1077 | 0 | if (lock) |
1078 | 0 | (*lock)++; |
1079 | 0 | } |
1080 | | |
1081 | | ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT |
1082 | 0 | { |
1083 | 0 | *this = std::move(other); |
1084 | 0 | } |
1085 | | |
1086 | | ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT |
1087 | 0 | { |
1088 | 0 | if (lock) |
1089 | 0 | (*lock)--; |
1090 | 0 | lock = other.lock; |
1091 | 0 | other.lock = nullptr; |
1092 | 0 | return *this; |
1093 | 0 | } |
1094 | | |
1095 | | void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set) |
1096 | 269k | { |
1097 | 269k | assert(id < ids.size()); |
1098 | | |
1099 | 269k | auto &constant_type = get<SPIRType>(type); |
1100 | | |
1101 | 269k | if (constant_type.pointer) |
1102 | 98 | { |
1103 | 98 | if (add_to_typed_id_set) |
1104 | 98 | add_typed_id(TypeConstant, id); |
1105 | 98 | auto &constant = variant_set<SPIRConstant>(ids[id], type); |
1106 | 98 | constant.self = id; |
1107 | 98 | constant.make_null(constant_type); |
1108 | 98 | } |
1109 | 269k | else if (!constant_type.array.empty()) |
1110 | 130k | { |
1111 | 130k | assert(constant_type.parent_type); |
1112 | 130k | uint32_t parent_id = increase_bound_by(1); |
1113 | 130k | make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set); |
1114 | | |
1115 | | // The array size of OpConstantNull can be either literal or specialization constant. |
1116 | | // In the latter case, we cannot take the value as-is, as it can be changed to anything. |
1117 | | // Rather, we assume it to be *one* for the sake of initializer. |
1118 | 130k | bool is_literal_array_size = constant_type.array_size_literal.back(); |
1119 | 130k | uint32_t count = is_literal_array_size ? constant_type.array.back() : 1; |
1120 | | |
1121 | 130k | SmallVector<uint32_t> elements(count); |
1122 | 55.7M | for (uint32_t i = 0; i < count; i++) |
1123 | 55.5M | elements[i] = parent_id; |
1124 | | |
1125 | 130k | if (add_to_typed_id_set) |
1126 | 130k | add_typed_id(TypeConstant, id); |
1127 | 130k | auto& constant = variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false); |
1128 | 130k | constant.self = id; |
1129 | 130k | constant.is_null_array_specialized_length = !is_literal_array_size; |
1130 | 130k | } |
1131 | 138k | else if (!constant_type.member_types.empty()) |
1132 | 2.59k | { |
1133 | 2.59k | uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size())); |
1134 | 2.59k | SmallVector<uint32_t> elements(constant_type.member_types.size()); |
1135 | 8.01k | for (uint32_t i = 0; i < constant_type.member_types.size(); i++) |
1136 | 5.42k | { |
1137 | 5.42k | make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set); |
1138 | 5.42k | elements[i] = member_ids + i; |
1139 | 5.42k | } |
1140 | | |
1141 | 2.59k | if (add_to_typed_id_set) |
1142 | 2.58k | add_typed_id(TypeConstant, id); |
1143 | 2.59k | variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id; |
1144 | 2.59k | } |
1145 | 136k | else |
1146 | 136k | { |
1147 | 136k | if (add_to_typed_id_set) |
1148 | 136k | add_typed_id(TypeConstant, id); |
1149 | 136k | auto &constant = variant_set<SPIRConstant>(ids[id], type); |
1150 | 136k | constant.self = id; |
1151 | 136k | constant.make_null(constant_type); |
1152 | 136k | } |
1153 | 269k | } |
1154 | | |
1155 | | } // namespace SPIRV_CROSS_NAMESPACE |