blob: 1a67fa472e212f21d95f66b5813b656f79197b70 [file] [log] [blame]
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001/*
Hans-Kristian Arntzenf9818f02020-01-16 15:24:37 +01002 * Copyright 2018-2020 Arm Limited
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "spirv_cross_parsed_ir.hpp"
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +010018#include <algorithm>
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +010019#include <assert.h>
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020020
21using namespace std;
22using namespace spv;
23
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010024namespace SPIRV_CROSS_NAMESPACE
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020025{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020026ParsedIR::ParsedIR()
27{
28 // If we move ParsedIR, we need to make sure the pointer stays fixed since the child Variant objects consume a pointer to this group,
29 // so need an extra pointer here.
30 pool_group.reset(new ObjectPoolGroup);
31
32 pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>);
33 pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>);
34 pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>);
35 pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>);
36 pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>);
37 pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>);
38 pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>);
39 pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>);
40 pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>);
41 pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>);
42 pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
43 pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020044 pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020045}
46
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020047// Should have been default-implemented, but need this on MSVC 2013.
48ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
49{
50 *this = move(other);
51}
52
53ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
54{
55 if (this != &other)
56 {
Hans-Kristian Arntzen02bb9862019-04-09 10:54:28 +020057 pool_group = move(other.pool_group);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020058 spirv = move(other.spirv);
59 meta = move(other.meta);
60 for (int i = 0; i < TypeCount; i++)
Hans-Kristian Arntzen9f31a942019-04-09 15:16:37 +020061 ids_for_type[i] = move(other.ids_for_type[i]);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020062 ids_for_constant_or_type = move(other.ids_for_constant_or_type);
63 ids_for_constant_or_variable = move(other.ids_for_constant_or_variable);
64 declared_capabilities = move(other.declared_capabilities);
65 declared_extensions = move(other.declared_extensions);
66 block_meta = move(other.block_meta);
67 continue_block_to_loop_header = move(other.continue_block_to_loop_header);
68 entry_points = move(other.entry_points);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020069 ids = move(other.ids);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020070 addressing_model = other.addressing_model;
71 memory_model = other.memory_model;
Hans-Kristian Arntzen9f31a942019-04-09 15:16:37 +020072
73 default_entry_point = other.default_entry_point;
74 source = other.source;
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +020075 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
76 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020077
78 meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020079 }
80 return *this;
81}
82
Hans-Kristian Arntzen9f31a942019-04-09 15:16:37 +020083ParsedIR::ParsedIR(const ParsedIR &other)
84 : ParsedIR()
85{
86 *this = other;
87}
88
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020089ParsedIR &ParsedIR::operator=(const ParsedIR &other)
90{
91 if (this != &other)
92 {
93 spirv = other.spirv;
94 meta = other.meta;
95 for (int i = 0; i < TypeCount; i++)
96 ids_for_type[i] = other.ids_for_type[i];
97 ids_for_constant_or_type = other.ids_for_constant_or_type;
98 ids_for_constant_or_variable = other.ids_for_constant_or_variable;
99 declared_capabilities = other.declared_capabilities;
100 declared_extensions = other.declared_extensions;
101 block_meta = other.block_meta;
102 continue_block_to_loop_header = other.continue_block_to_loop_header;
103 entry_points = other.entry_points;
104 default_entry_point = other.default_entry_point;
105 source = other.source;
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200106 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
107 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200108 addressing_model = other.addressing_model;
109 memory_model = other.memory_model;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200110
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200111 meta_needing_name_fixup = other.meta_needing_name_fixup;
112
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200113 // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
114 // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
115 ids.clear();
116 ids.reserve(other.ids.size());
117 for (size_t i = 0; i < other.ids.size(); i++)
118 {
119 ids.emplace_back(pool_group.get());
120 ids.back() = other.ids[i];
121 }
122 }
123 return *this;
124}
125
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200126void ParsedIR::set_id_bounds(uint32_t bounds)
127{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200128 ids.reserve(bounds);
129 while (ids.size() < bounds)
130 ids.emplace_back(pool_group.get());
131
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200132 block_meta.resize(bounds);
133}
134
Hans-Kristian Arntzenfc4a07c2020-01-06 13:04:57 +0100135// Roll our own versions of these functions to avoid potential locale shenanigans.
136static bool is_alpha(char c)
137{
138 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
139}
140
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200141static bool is_numeric(char c)
Hans-Kristian Arntzenfc4a07c2020-01-06 13:04:57 +0100142{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200143 return c >= '0' && c <= '9';
Hans-Kristian Arntzenfc4a07c2020-01-06 13:04:57 +0100144}
145
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200146static bool is_alphanumeric(char c)
147{
148 return is_alpha(c) || is_numeric(c);
149}
150
151static bool is_valid_identifier(const string &name)
152{
153 if (name.empty())
154 return true;
155
156 if (is_numeric(name[0]))
157 return false;
158
159 for (auto c : name)
160 if (!is_alphanumeric(c) && c != '_')
161 return false;
162
163 bool saw_underscore = false;
164 // Two underscores in a row is not a valid identifier either.
165 // Technically reserved, but it's easier to treat it as invalid.
166 for (auto c : name)
167 {
168 bool is_underscore = c == '_';
169 if (is_underscore && saw_underscore)
170 return false;
171 saw_underscore = is_underscore;
172 }
173
174 return true;
175}
176
177static bool is_reserved_prefix(const string &name)
178{
179 // Generic reserved identifiers used by the implementation.
180 return name.compare(0, 3, "gl_", 3) == 0 ||
181 // Ignore this case for now, might rewrite internal code to always use spv prefix.
182 //name.compare(0, 11, "SPIRV_Cross", 11) == 0 ||
183 name.compare(0, 3, "spv", 3) == 0;
184}
185
186static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes)
187{
188 if (!allow_reserved_prefixes && is_reserved_prefix(name))
189 return true;
190
191 if (member)
192 {
193 // Reserved member identifiers come in one form:
194 // _m[0-9]+$.
195 if (name.size() < 3)
196 return false;
197
198 if (name.compare(0, 2, "_m", 2) != 0)
199 return false;
200
201 size_t index = 2;
202 while (index < name.size() && is_numeric(name[index]))
203 index++;
204
205 return index == name.size();
206 }
207 else
208 {
209 // Reserved non-member identifiers come in two forms:
210 // _[0-9]+$, used for temporaries which map directly to a SPIR-V ID.
211 // _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID.
212 if (name.size() < 2)
213 return false;
214
215 if (name[0] != '_' || !is_numeric(name[1]))
216 return false;
217
218 size_t index = 2;
219 while (index < name.size() && is_numeric(name[index]))
220 index++;
221
222 return index == name.size() || (index < name.size() && name[index] == '_');
223 }
224}
225
226bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes)
227{
228 return is_reserved_identifier(str, false, allow_reserved_prefixes);
229}
230
231static string make_unreserved_identifier(const string &name)
232{
233 if (is_reserved_prefix(name))
234 return "_RESERVED_IDENTIFIER_FIXUP_" + name;
235 else
236 return "_RESERVED_IDENTIFIER_FIXUP" + name;
237}
238
239void ParsedIR::sanitize_underscores(std::string &str)
240{
241 // Compact adjacent underscores to make it valid.
242 auto dst = str.begin();
243 auto src = dst;
244 bool saw_underscore = false;
245 while (src != str.end())
246 {
247 bool is_underscore = *src == '_';
248 if (saw_underscore && is_underscore)
249 {
250 src++;
251 }
252 else
253 {
254 if (dst != src)
255 *dst = *src;
256 dst++;
257 src++;
258 saw_underscore = is_underscore;
259 }
260 }
261 str.erase(dst, str.end());
262}
263
264static string ensure_valid_identifier(const string &name)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200265{
266 // Functions in glslangValidator are mangled with name(<mangled> stuff.
267 // Normally, we would never see '(' in any legal identifiers, so just strip them out.
268 auto str = name.substr(0, name.find('('));
269
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200270 if (str.empty())
271 return str;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200272
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200273 if (is_numeric(str[0]))
274 str[0] = '_';
275
276 for (auto &c : str)
277 if (!is_alphanumeric(c) && c != '_')
278 c = '_';
279
280 ParsedIR::sanitize_underscores(str);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200281 return str;
282}
283
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200284const string &ParsedIR::get_name(ID id) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200285{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100286 auto *m = find_meta(id);
287 if (m)
288 return m->decoration.alias;
289 else
290 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200291}
292
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200293const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200294{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100295 auto *m = find_meta(id);
296 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200297 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100298 if (index >= m->members.size())
299 return empty_string;
300 return m->members[index].alias;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200301 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100302 else
303 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200304}
305
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200306void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes)
307{
308 if (!is_valid_identifier(name))
309 name = ensure_valid_identifier(name);
310 if (is_reserved_identifier(name, member, allow_reserved_prefixes))
311 name = make_unreserved_identifier(name);
312}
313
314void ParsedIR::fixup_reserved_names()
315{
316 for (uint32_t id : meta_needing_name_fixup)
317 {
318 auto &m = meta[id];
319 sanitize_identifier(m.decoration.alias, false, false);
320 for (auto &memb : m.members)
321 sanitize_identifier(memb.alias, true, false);
322 }
323 meta_needing_name_fixup.clear();
324}
325
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200326void ParsedIR::set_name(ID id, const string &name)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200327{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200328 auto &m = meta[id];
329 m.decoration.alias = name;
330 if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
331 meta_needing_name_fixup.insert(id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200332}
333
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200334void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200335{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200336 auto &m = meta[id];
337 m.members.resize(max(meta[id].members.size(), size_t(index) + 1));
338 m.members[index].alias = name;
339 if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
340 meta_needing_name_fixup.insert(id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200341}
342
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200343void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200344{
345 auto &dec = meta[id].decoration;
346 dec.decoration_flags.set(decoration);
347
348 switch (decoration)
349 {
350 case DecorationHlslSemanticGOOGLE:
351 dec.hlsl_semantic = argument;
352 break;
353
354 default:
355 break;
356 }
357}
358
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200359void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200360{
361 auto &dec = meta[id].decoration;
362 dec.decoration_flags.set(decoration);
363
364 switch (decoration)
365 {
366 case DecorationBuiltIn:
367 dec.builtin = true;
368 dec.builtin_type = static_cast<BuiltIn>(argument);
369 break;
370
371 case DecorationLocation:
372 dec.location = argument;
373 break;
374
375 case DecorationComponent:
376 dec.component = argument;
377 break;
378
379 case DecorationOffset:
380 dec.offset = argument;
381 break;
382
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100383 case DecorationXfbBuffer:
384 dec.xfb_buffer = argument;
385 break;
386
387 case DecorationXfbStride:
388 dec.xfb_stride = argument;
389 break;
390
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200391 case DecorationStream:
392 dec.stream = argument;
393 break;
394
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200395 case DecorationArrayStride:
396 dec.array_stride = argument;
397 break;
398
399 case DecorationMatrixStride:
400 dec.matrix_stride = argument;
401 break;
402
403 case DecorationBinding:
404 dec.binding = argument;
405 break;
406
407 case DecorationDescriptorSet:
408 dec.set = argument;
409 break;
410
411 case DecorationInputAttachmentIndex:
412 dec.input_attachment = argument;
413 break;
414
415 case DecorationSpecId:
416 dec.spec_id = argument;
417 break;
418
419 case DecorationIndex:
420 dec.index = argument;
421 break;
422
423 case DecorationHlslCounterBufferGOOGLE:
424 meta[id].hlsl_magic_counter_buffer = argument;
Hans-Kristian Arntzen9aa623a2018-11-22 10:23:58 +0100425 meta[argument].hlsl_is_magic_counter_buffer = true;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200426 break;
427
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100428 case DecorationFPRoundingMode:
429 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
430 break;
431
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200432 default:
433 break;
434 }
435}
436
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200437void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200438{
439 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
440 auto &dec = meta[id].members[index];
441 dec.decoration_flags.set(decoration);
442
443 switch (decoration)
444 {
445 case DecorationBuiltIn:
446 dec.builtin = true;
447 dec.builtin_type = static_cast<BuiltIn>(argument);
448 break;
449
450 case DecorationLocation:
451 dec.location = argument;
452 break;
453
454 case DecorationComponent:
455 dec.component = argument;
456 break;
457
458 case DecorationBinding:
459 dec.binding = argument;
460 break;
461
462 case DecorationOffset:
463 dec.offset = argument;
464 break;
465
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100466 case DecorationXfbBuffer:
467 dec.xfb_buffer = argument;
468 break;
469
470 case DecorationXfbStride:
471 dec.xfb_stride = argument;
472 break;
473
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200474 case DecorationStream:
475 dec.stream = argument;
476 break;
477
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200478 case DecorationSpecId:
479 dec.spec_id = argument;
480 break;
481
482 case DecorationMatrixStride:
483 dec.matrix_stride = argument;
484 break;
485
486 case DecorationIndex:
487 dec.index = argument;
488 break;
489
490 default:
491 break;
492 }
493}
494
495// Recursively marks any constants referenced by the specified constant instruction as being used
496// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200497void ParsedIR::mark_used_as_array_length(ID id)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200498{
499 switch (ids[id].get_type())
500 {
501 case TypeConstant:
502 get<SPIRConstant>(id).is_used_as_array_length = true;
503 break;
504
505 case TypeConstantOp:
506 {
507 auto &cop = get<SPIRConstantOp>(id);
lifpan89e7d212019-09-05 06:56:05 +0800508 if (cop.opcode == OpCompositeExtract)
509 mark_used_as_array_length(cop.arguments[0]);
510 else if (cop.opcode == OpCompositeInsert)
511 {
512 mark_used_as_array_length(cop.arguments[0]);
513 mark_used_as_array_length(cop.arguments[1]);
514 }
515 else
516 for (uint32_t arg_id : cop.arguments)
517 mark_used_as_array_length(arg_id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200518 break;
519 }
520
521 case TypeUndef:
522 break;
523
524 default:
525 assert(0);
526 }
527}
528
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +0100529Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
530{
531 if (type.member_types.empty())
532 return {};
533
534 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
535 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
536 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
537 return all_members_flags;
538}
539
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200540Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
541{
542 auto &type = get<SPIRType>(var.basetype);
543 assert(type.basetype == SPIRType::Struct);
544
545 // Some flags like non-writable, non-readable are actually found
546 // as member decorations. If all members have a decoration set, propagate
547 // the decoration up as a regular variable decoration.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100548 Bitset base_flags;
549 auto *m = find_meta(var.self);
550 if (m)
551 base_flags = m->decoration.decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200552
553 if (type.member_types.empty())
554 return base_flags;
555
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +0100556 auto all_members_flags = get_buffer_block_type_flags(type);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200557 base_flags.merge_or(all_members_flags);
558 return base_flags;
559}
560
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200561const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200562{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100563 auto *m = find_meta(id);
564 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200565 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100566 if (index >= m->members.size())
567 return cleared_bitset;
568 return m->members[index].decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200569 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100570 else
571 return cleared_bitset;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200572}
573
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200574bool ParsedIR::has_decoration(ID id, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200575{
576 return get_decoration_bitset(id).get(decoration);
577}
578
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200579uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200580{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100581 auto *m = find_meta(id);
582 if (!m)
583 return 0;
584
585 auto &dec = m->decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200586 if (!dec.decoration_flags.get(decoration))
587 return 0;
588
589 switch (decoration)
590 {
591 case DecorationBuiltIn:
592 return dec.builtin_type;
593 case DecorationLocation:
594 return dec.location;
595 case DecorationComponent:
596 return dec.component;
597 case DecorationOffset:
598 return dec.offset;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100599 case DecorationXfbBuffer:
600 return dec.xfb_buffer;
601 case DecorationXfbStride:
602 return dec.xfb_stride;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200603 case DecorationStream:
604 return dec.stream;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200605 case DecorationBinding:
606 return dec.binding;
607 case DecorationDescriptorSet:
608 return dec.set;
609 case DecorationInputAttachmentIndex:
610 return dec.input_attachment;
611 case DecorationSpecId:
612 return dec.spec_id;
613 case DecorationArrayStride:
614 return dec.array_stride;
615 case DecorationMatrixStride:
616 return dec.matrix_stride;
617 case DecorationIndex:
618 return dec.index;
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100619 case DecorationFPRoundingMode:
620 return dec.fp_rounding_mode;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200621 default:
622 return 1;
623 }
624}
625
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200626const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200627{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100628 auto *m = find_meta(id);
629 if (!m)
630 return empty_string;
631
632 auto &dec = m->decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200633
634 if (!dec.decoration_flags.get(decoration))
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100635 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200636
637 switch (decoration)
638 {
639 case DecorationHlslSemanticGOOGLE:
640 return dec.hlsl_semantic;
641
642 default:
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100643 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200644 }
645}
646
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200647void ParsedIR::unset_decoration(ID id, Decoration decoration)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200648{
649 auto &dec = meta[id].decoration;
650 dec.decoration_flags.clear(decoration);
651 switch (decoration)
652 {
653 case DecorationBuiltIn:
654 dec.builtin = false;
655 break;
656
657 case DecorationLocation:
658 dec.location = 0;
659 break;
660
661 case DecorationComponent:
662 dec.component = 0;
663 break;
664
665 case DecorationOffset:
666 dec.offset = 0;
667 break;
668
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100669 case DecorationXfbBuffer:
670 dec.xfb_buffer = 0;
671 break;
672
673 case DecorationXfbStride:
674 dec.xfb_stride = 0;
675 break;
676
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200677 case DecorationStream:
678 dec.stream = 0;
679 break;
680
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200681 case DecorationBinding:
682 dec.binding = 0;
683 break;
684
685 case DecorationDescriptorSet:
686 dec.set = 0;
687 break;
688
689 case DecorationInputAttachmentIndex:
690 dec.input_attachment = 0;
691 break;
692
693 case DecorationSpecId:
694 dec.spec_id = 0;
695 break;
696
697 case DecorationHlslSemanticGOOGLE:
698 dec.hlsl_semantic.clear();
699 break;
700
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100701 case DecorationFPRoundingMode:
702 dec.fp_rounding_mode = FPRoundingModeMax;
703 break;
704
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200705 case DecorationHlslCounterBufferGOOGLE:
706 {
707 auto &counter = meta[id].hlsl_magic_counter_buffer;
708 if (counter)
709 {
710 meta[counter].hlsl_is_magic_counter_buffer = false;
711 counter = 0;
712 }
713 break;
714 }
715
716 default:
717 break;
718 }
719}
720
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200721bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200722{
723 return get_member_decoration_bitset(id, index).get(decoration);
724}
725
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200726uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200727{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100728 auto *m = find_meta(id);
729 if (!m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200730 return 0;
731
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100732 if (index >= m->members.size())
733 return 0;
734
735 auto &dec = m->members[index];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200736 if (!dec.decoration_flags.get(decoration))
737 return 0;
738
739 switch (decoration)
740 {
741 case DecorationBuiltIn:
742 return dec.builtin_type;
743 case DecorationLocation:
744 return dec.location;
745 case DecorationComponent:
746 return dec.component;
747 case DecorationBinding:
748 return dec.binding;
749 case DecorationOffset:
750 return dec.offset;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100751 case DecorationXfbBuffer:
752 return dec.xfb_buffer;
753 case DecorationXfbStride:
754 return dec.xfb_stride;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200755 case DecorationStream:
756 return dec.stream;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200757 case DecorationSpecId:
758 return dec.spec_id;
759 case DecorationIndex:
760 return dec.index;
761 default:
762 return 1;
763 }
764}
765
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200766const Bitset &ParsedIR::get_decoration_bitset(ID id) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200767{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100768 auto *m = find_meta(id);
769 if (m)
770 {
771 auto &dec = m->decoration;
772 return dec.decoration_flags;
773 }
774 else
775 return cleared_bitset;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200776}
777
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200778void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200779{
780 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
781 auto &dec = meta[id].members[index];
782 dec.decoration_flags.set(decoration);
783
784 switch (decoration)
785 {
786 case DecorationHlslSemanticGOOGLE:
787 dec.hlsl_semantic = argument;
788 break;
789
790 default:
791 break;
792 }
793}
794
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200795const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200796{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100797 auto *m = find_meta(id);
798 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200799 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100800 if (!has_member_decoration(id, index, decoration))
801 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200802
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100803 auto &dec = m->members[index];
804
805 switch (decoration)
806 {
807 case DecorationHlslSemanticGOOGLE:
808 return dec.hlsl_semantic;
809
810 default:
811 return empty_string;
812 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200813 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100814 else
815 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200816}
817
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200818void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200819{
820 auto &m = meta[id];
821 if (index >= m.members.size())
822 return;
823
824 auto &dec = m.members[index];
825
826 dec.decoration_flags.clear(decoration);
827 switch (decoration)
828 {
829 case DecorationBuiltIn:
830 dec.builtin = false;
831 break;
832
833 case DecorationLocation:
834 dec.location = 0;
835 break;
836
837 case DecorationComponent:
838 dec.component = 0;
839 break;
840
841 case DecorationOffset:
842 dec.offset = 0;
843 break;
844
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100845 case DecorationXfbBuffer:
846 dec.xfb_buffer = 0;
847 break;
848
849 case DecorationXfbStride:
850 dec.xfb_stride = 0;
851 break;
852
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200853 case DecorationStream:
854 dec.stream = 0;
855 break;
856
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200857 case DecorationSpecId:
858 dec.spec_id = 0;
859 break;
860
861 case DecorationHlslSemanticGOOGLE:
862 dec.hlsl_semantic.clear();
863 break;
864
865 default:
866 break;
867 }
868}
869
870uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
871{
872 auto curr_bound = ids.size();
873 auto new_bound = curr_bound + incr_amount;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200874
875 ids.reserve(ids.size() + incr_amount);
876 for (uint32_t i = 0; i < incr_amount; i++)
877 ids.emplace_back(pool_group.get());
878
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200879 block_meta.resize(new_bound);
880 return uint32_t(curr_bound);
881}
882
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200883void ParsedIR::remove_typed_id(Types type, ID id)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100884{
885 auto &type_ids = ids_for_type[type];
886 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
887}
888
889void ParsedIR::reset_all_of_type(Types type)
890{
891 for (auto &id : ids_for_type[type])
892 if (ids[id].get_type() == type)
893 ids[id].reset();
894
895 ids_for_type[type].clear();
896}
897
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200898void ParsedIR::add_typed_id(Types type, ID id)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100899{
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200900 if (loop_iteration_depth_hard != 0)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100901 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
902
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200903 if (loop_iteration_depth_soft != 0)
904 {
905 if (!ids[id].empty())
906 SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
907 return;
908 }
909
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200910 if (ids[id].empty() || ids[id].get_type() != type)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100911 {
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200912 switch (type)
913 {
914 case TypeConstant:
915 ids_for_constant_or_variable.push_back(id);
916 ids_for_constant_or_type.push_back(id);
917 break;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100918
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200919 case TypeVariable:
920 ids_for_constant_or_variable.push_back(id);
921 break;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100922
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200923 case TypeType:
924 case TypeConstantOp:
925 ids_for_constant_or_type.push_back(id);
926 break;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100927
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200928 default:
929 break;
930 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100931 }
932
933 if (ids[id].empty())
934 {
935 ids_for_type[type].push_back(id);
936 }
937 else if (ids[id].get_type() != type)
938 {
939 remove_typed_id(ids[id].get_type(), id);
940 ids_for_type[type].push_back(id);
941 }
942}
943
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200944const Meta *ParsedIR::find_meta(ID id) const
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100945{
946 auto itr = meta.find(id);
947 if (itr != end(meta))
948 return &itr->second;
949 else
950 return nullptr;
951}
952
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200953Meta *ParsedIR::find_meta(ID id)
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100954{
955 auto itr = meta.find(id);
956 if (itr != end(meta))
957 return &itr->second;
958 else
959 return nullptr;
960}
961
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200962ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200963{
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200964 return ParsedIR::LoopLock(&loop_iteration_depth_hard);
965}
966
967ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
968{
969 return ParsedIR::LoopLock(&loop_iteration_depth_soft);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200970}
971
972ParsedIR::LoopLock::~LoopLock()
973{
974 if (lock)
975 (*lock)--;
976}
977
978ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +0200979 : lock(lock_)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200980{
981 if (lock)
982 (*lock)++;
983}
984
985ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
986{
987 *this = move(other);
988}
989
990ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
991{
992 if (lock)
993 (*lock)--;
994 lock = other.lock;
995 other.lock = nullptr;
996 return *this;
997}
998
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +0100999void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
1000{
1001 auto &constant_type = get<SPIRType>(type);
1002
1003 if (constant_type.pointer)
1004 {
1005 if (add_to_typed_id_set)
1006 add_typed_id(TypeConstant, id);
1007 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1008 constant.self = id;
1009 constant.make_null(constant_type);
1010 }
1011 else if (!constant_type.array.empty())
1012 {
1013 assert(constant_type.parent_type);
1014 uint32_t parent_id = increase_bound_by(1);
1015 make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
1016
1017 if (!constant_type.array_size_literal.back())
1018 SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
1019
1020 SmallVector<uint32_t> elements(constant_type.array.back());
1021 for (uint32_t i = 0; i < constant_type.array.back(); i++)
1022 elements[i] = parent_id;
1023
1024 if (add_to_typed_id_set)
1025 add_typed_id(TypeConstant, id);
1026 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1027 }
1028 else if (!constant_type.member_types.empty())
1029 {
1030 uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
1031 SmallVector<uint32_t> elements(constant_type.member_types.size());
1032 for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
1033 {
1034 make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
1035 elements[i] = member_ids + i;
1036 }
1037
1038 if (add_to_typed_id_set)
1039 add_typed_id(TypeConstant, id);
1040 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1041 }
1042 else
1043 {
1044 if (add_to_typed_id_set)
1045 add_typed_id(TypeConstant, id);
1046 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1047 constant.self = id;
1048 constant.make_null(constant_type);
1049 }
1050}
1051
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001052} // namespace SPIRV_CROSS_NAMESPACE