blob: 3b4d6e5caedbaf96ff4449c57c06d2a10410b17f [file] [log] [blame]
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2018-2021 Arm Limited
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004 *
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
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010018/*
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>.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010022 */
23
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020024#include "spirv_cross_parsed_ir.hpp"
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +010025#include <algorithm>
Hans-Kristian Arntzen6e1c3cc2019-01-11 12:56:00 +010026#include <assert.h>
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020027
28using namespace std;
29using namespace spv;
30
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010031namespace SPIRV_CROSS_NAMESPACE
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020032{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020033ParsedIR::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>);
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +020051 pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020052}
53
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020054// Should have been default-implemented, but need this on MSVC 2013.
55ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
56{
Daniel Thornburgh44c33332022-03-02 23:02:38 +000057 *this = std::move(other);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020058}
59
60ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
61{
62 if (this != &other)
63 {
Daniel Thornburgh44c33332022-03-02 23:02:38 +000064 pool_group = std::move(other.pool_group);
65 spirv = std::move(other.spirv);
66 meta = std::move(other.meta);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020067 for (int i = 0; i < TypeCount; i++)
Daniel Thornburgh44c33332022-03-02 23:02:38 +000068 ids_for_type[i] = std::move(other.ids_for_type[i]);
69 ids_for_constant_or_type = std::move(other.ids_for_constant_or_type);
70 ids_for_constant_or_variable = std::move(other.ids_for_constant_or_variable);
71 declared_capabilities = std::move(other.declared_capabilities);
72 declared_extensions = std::move(other.declared_extensions);
73 block_meta = std::move(other.block_meta);
74 continue_block_to_loop_header = std::move(other.continue_block_to_loop_header);
75 entry_points = std::move(other.entry_points);
76 ids = std::move(other.ids);
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +020077 addressing_model = other.addressing_model;
78 memory_model = other.memory_model;
Hans-Kristian Arntzen9f31a942019-04-09 15:16:37 +020079
80 default_entry_point = other.default_entry_point;
81 source = other.source;
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +020082 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
83 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +020084
85 meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
Sebastián Aedo250a0292021-11-03 16:12:14 -030086 load_type_width = std::move(other.load_type_width);
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020087 }
88 return *this;
89}
90
Hans-Kristian Arntzen9f31a942019-04-09 15:16:37 +020091ParsedIR::ParsedIR(const ParsedIR &other)
92 : ParsedIR()
93{
94 *this = other;
95}
96
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020097ParsedIR &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;
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200114 loop_iteration_depth_hard = other.loop_iteration_depth_hard;
115 loop_iteration_depth_soft = other.loop_iteration_depth_soft;
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200116 addressing_model = other.addressing_model;
117 memory_model = other.memory_model;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200118
Sebastián Aedo250a0292021-11-03 16:12:14 -0300119
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200120 meta_needing_name_fixup = other.meta_needing_name_fixup;
Sebastián Aedo250a0292021-11-03 16:12:14 -0300121 load_type_width = other.load_type_width;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200122
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200123 // 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
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200136void ParsedIR::set_id_bounds(uint32_t bounds)
137{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200138 ids.reserve(bounds);
139 while (ids.size() < bounds)
140 ids.emplace_back(pool_group.get());
141
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200142 block_meta.resize(bounds);
143}
144
Hans-Kristian Arntzenfc4a07c2020-01-06 13:04:57 +0100145// Roll our own versions of these functions to avoid potential locale shenanigans.
146static bool is_alpha(char c)
147{
148 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
149}
150
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200151static bool is_numeric(char c)
Hans-Kristian Arntzenfc4a07c2020-01-06 13:04:57 +0100152{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200153 return c >= '0' && c <= '9';
Hans-Kristian Arntzenfc4a07c2020-01-06 13:04:57 +0100154}
155
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200156static bool is_alphanumeric(char c)
157{
158 return is_alpha(c) || is_numeric(c);
159}
160
161static 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
187static 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
196static 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
236bool 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
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100241uint32_t ParsedIR::get_spirv_version() const
242{
243 return spirv[1];
244}
245
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200246static 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
254void 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
279static string ensure_valid_identifier(const string &name)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200280{
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
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200285 if (str.empty())
286 return str;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200287
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200288 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);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200296 return str;
297}
298
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200299const string &ParsedIR::get_name(ID id) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200300{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100301 auto *m = find_meta(id);
302 if (m)
303 return m->decoration.alias;
304 else
305 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200306}
307
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200308const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200309{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100310 auto *m = find_meta(id);
311 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200312 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100313 if (index >= m->members.size())
314 return empty_string;
315 return m->members[index].alias;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200316 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100317 else
318 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200319}
320
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200321void 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
329void ParsedIR::fixup_reserved_names()
330{
331 for (uint32_t id : meta_needing_name_fixup)
332 {
Yuwen Wu10f2aa72022-08-24 11:06:09 +0800333 // Don't rename remapped variables like 'gl_LastFragDepthARM'.
334 if (ids[id].get_type() == TypeVariable && get<SPIRVariable>(id).remapped_variable)
335 continue;
336
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200337 auto &m = meta[id];
338 sanitize_identifier(m.decoration.alias, false, false);
339 for (auto &memb : m.members)
340 sanitize_identifier(memb.alias, true, false);
341 }
342 meta_needing_name_fixup.clear();
343}
344
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200345void ParsedIR::set_name(ID id, const string &name)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200346{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200347 auto &m = meta[id];
348 m.decoration.alias = name;
349 if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
350 meta_needing_name_fixup.insert(id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200351}
352
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200353void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200354{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200355 auto &m = meta[id];
Hans-Kristian Arntzen39bad2c2022-03-12 12:03:39 +0100356 m.members.resize(max(m.members.size(), size_t(index) + 1));
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200357 m.members[index].alias = name;
358 if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
359 meta_needing_name_fixup.insert(id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200360}
361
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200362void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200363{
364 auto &dec = meta[id].decoration;
365 dec.decoration_flags.set(decoration);
366
367 switch (decoration)
368 {
369 case DecorationHlslSemanticGOOGLE:
370 dec.hlsl_semantic = argument;
371 break;
372
373 default:
374 break;
375 }
376}
377
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200378void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200379{
380 auto &dec = meta[id].decoration;
381 dec.decoration_flags.set(decoration);
382
383 switch (decoration)
384 {
385 case DecorationBuiltIn:
386 dec.builtin = true;
387 dec.builtin_type = static_cast<BuiltIn>(argument);
388 break;
389
390 case DecorationLocation:
391 dec.location = argument;
392 break;
393
394 case DecorationComponent:
395 dec.component = argument;
396 break;
397
398 case DecorationOffset:
399 dec.offset = argument;
400 break;
401
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100402 case DecorationXfbBuffer:
403 dec.xfb_buffer = argument;
404 break;
405
406 case DecorationXfbStride:
407 dec.xfb_stride = argument;
408 break;
409
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200410 case DecorationStream:
411 dec.stream = argument;
412 break;
413
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200414 case DecorationArrayStride:
415 dec.array_stride = argument;
416 break;
417
418 case DecorationMatrixStride:
419 dec.matrix_stride = argument;
420 break;
421
422 case DecorationBinding:
423 dec.binding = argument;
424 break;
425
426 case DecorationDescriptorSet:
427 dec.set = argument;
428 break;
429
430 case DecorationInputAttachmentIndex:
431 dec.input_attachment = argument;
432 break;
433
434 case DecorationSpecId:
435 dec.spec_id = argument;
436 break;
437
438 case DecorationIndex:
439 dec.index = argument;
440 break;
441
442 case DecorationHlslCounterBufferGOOGLE:
443 meta[id].hlsl_magic_counter_buffer = argument;
Hans-Kristian Arntzen9aa623a2018-11-22 10:23:58 +0100444 meta[argument].hlsl_is_magic_counter_buffer = true;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200445 break;
446
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100447 case DecorationFPRoundingMode:
448 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
449 break;
450
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200451 default:
452 break;
453 }
454}
455
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200456void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200457{
Hans-Kristian Arntzen39bad2c2022-03-12 12:03:39 +0100458 auto &m = meta[id];
459 m.members.resize(max(m.members.size(), size_t(index) + 1));
460 auto &dec = m.members[index];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200461 dec.decoration_flags.set(decoration);
462
463 switch (decoration)
464 {
465 case DecorationBuiltIn:
466 dec.builtin = true;
467 dec.builtin_type = static_cast<BuiltIn>(argument);
468 break;
469
470 case DecorationLocation:
471 dec.location = argument;
472 break;
473
474 case DecorationComponent:
475 dec.component = argument;
476 break;
477
478 case DecorationBinding:
479 dec.binding = argument;
480 break;
481
482 case DecorationOffset:
483 dec.offset = argument;
484 break;
485
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100486 case DecorationXfbBuffer:
487 dec.xfb_buffer = argument;
488 break;
489
490 case DecorationXfbStride:
491 dec.xfb_stride = argument;
492 break;
493
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200494 case DecorationStream:
495 dec.stream = argument;
496 break;
497
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200498 case DecorationSpecId:
499 dec.spec_id = argument;
500 break;
501
502 case DecorationMatrixStride:
503 dec.matrix_stride = argument;
504 break;
505
506 case DecorationIndex:
507 dec.index = argument;
508 break;
509
510 default:
511 break;
512 }
513}
514
515// Recursively marks any constants referenced by the specified constant instruction as being used
516// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200517void ParsedIR::mark_used_as_array_length(ID id)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200518{
519 switch (ids[id].get_type())
520 {
521 case TypeConstant:
522 get<SPIRConstant>(id).is_used_as_array_length = true;
523 break;
524
525 case TypeConstantOp:
526 {
527 auto &cop = get<SPIRConstantOp>(id);
lifpan89e7d212019-09-05 06:56:05 +0800528 if (cop.opcode == OpCompositeExtract)
529 mark_used_as_array_length(cop.arguments[0]);
530 else if (cop.opcode == OpCompositeInsert)
531 {
532 mark_used_as_array_length(cop.arguments[0]);
533 mark_used_as_array_length(cop.arguments[1]);
534 }
535 else
536 for (uint32_t arg_id : cop.arguments)
537 mark_used_as_array_length(arg_id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200538 break;
539 }
540
541 case TypeUndef:
542 break;
543
544 default:
545 assert(0);
546 }
547}
548
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +0100549Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
550{
551 if (type.member_types.empty())
552 return {};
553
554 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
555 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
556 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
557 return all_members_flags;
558}
559
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200560Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
561{
562 auto &type = get<SPIRType>(var.basetype);
563 assert(type.basetype == SPIRType::Struct);
564
565 // Some flags like non-writable, non-readable are actually found
566 // as member decorations. If all members have a decoration set, propagate
567 // the decoration up as a regular variable decoration.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100568 Bitset base_flags;
569 auto *m = find_meta(var.self);
570 if (m)
571 base_flags = m->decoration.decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200572
573 if (type.member_types.empty())
574 return base_flags;
575
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +0100576 auto all_members_flags = get_buffer_block_type_flags(type);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200577 base_flags.merge_or(all_members_flags);
578 return base_flags;
579}
580
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200581const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200582{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100583 auto *m = find_meta(id);
584 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200585 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100586 if (index >= m->members.size())
587 return cleared_bitset;
588 return m->members[index].decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200589 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100590 else
591 return cleared_bitset;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200592}
593
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200594bool ParsedIR::has_decoration(ID id, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200595{
596 return get_decoration_bitset(id).get(decoration);
597}
598
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200599uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200600{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100601 auto *m = find_meta(id);
602 if (!m)
603 return 0;
604
605 auto &dec = m->decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200606 if (!dec.decoration_flags.get(decoration))
607 return 0;
608
609 switch (decoration)
610 {
611 case DecorationBuiltIn:
612 return dec.builtin_type;
613 case DecorationLocation:
614 return dec.location;
615 case DecorationComponent:
616 return dec.component;
617 case DecorationOffset:
618 return dec.offset;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100619 case DecorationXfbBuffer:
620 return dec.xfb_buffer;
621 case DecorationXfbStride:
622 return dec.xfb_stride;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200623 case DecorationStream:
624 return dec.stream;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200625 case DecorationBinding:
626 return dec.binding;
627 case DecorationDescriptorSet:
628 return dec.set;
629 case DecorationInputAttachmentIndex:
630 return dec.input_attachment;
631 case DecorationSpecId:
632 return dec.spec_id;
633 case DecorationArrayStride:
634 return dec.array_stride;
635 case DecorationMatrixStride:
636 return dec.matrix_stride;
637 case DecorationIndex:
638 return dec.index;
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100639 case DecorationFPRoundingMode:
640 return dec.fp_rounding_mode;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200641 default:
642 return 1;
643 }
644}
645
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200646const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200647{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100648 auto *m = find_meta(id);
649 if (!m)
650 return empty_string;
651
652 auto &dec = m->decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200653
654 if (!dec.decoration_flags.get(decoration))
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100655 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200656
657 switch (decoration)
658 {
659 case DecorationHlslSemanticGOOGLE:
660 return dec.hlsl_semantic;
661
662 default:
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100663 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200664 }
665}
666
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200667void ParsedIR::unset_decoration(ID id, Decoration decoration)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200668{
669 auto &dec = meta[id].decoration;
670 dec.decoration_flags.clear(decoration);
671 switch (decoration)
672 {
673 case DecorationBuiltIn:
674 dec.builtin = false;
675 break;
676
677 case DecorationLocation:
678 dec.location = 0;
679 break;
680
681 case DecorationComponent:
682 dec.component = 0;
683 break;
684
685 case DecorationOffset:
686 dec.offset = 0;
687 break;
688
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100689 case DecorationXfbBuffer:
690 dec.xfb_buffer = 0;
691 break;
692
693 case DecorationXfbStride:
694 dec.xfb_stride = 0;
695 break;
696
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200697 case DecorationStream:
698 dec.stream = 0;
699 break;
700
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200701 case DecorationBinding:
702 dec.binding = 0;
703 break;
704
705 case DecorationDescriptorSet:
706 dec.set = 0;
707 break;
708
709 case DecorationInputAttachmentIndex:
710 dec.input_attachment = 0;
711 break;
712
713 case DecorationSpecId:
714 dec.spec_id = 0;
715 break;
716
717 case DecorationHlslSemanticGOOGLE:
718 dec.hlsl_semantic.clear();
719 break;
720
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100721 case DecorationFPRoundingMode:
722 dec.fp_rounding_mode = FPRoundingModeMax;
723 break;
724
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200725 case DecorationHlslCounterBufferGOOGLE:
726 {
727 auto &counter = meta[id].hlsl_magic_counter_buffer;
728 if (counter)
729 {
730 meta[counter].hlsl_is_magic_counter_buffer = false;
731 counter = 0;
732 }
733 break;
734 }
735
736 default:
737 break;
738 }
739}
740
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200741bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200742{
743 return get_member_decoration_bitset(id, index).get(decoration);
744}
745
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200746uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200747{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100748 auto *m = find_meta(id);
749 if (!m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200750 return 0;
751
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100752 if (index >= m->members.size())
753 return 0;
754
755 auto &dec = m->members[index];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200756 if (!dec.decoration_flags.get(decoration))
757 return 0;
758
759 switch (decoration)
760 {
761 case DecorationBuiltIn:
762 return dec.builtin_type;
763 case DecorationLocation:
764 return dec.location;
765 case DecorationComponent:
766 return dec.component;
767 case DecorationBinding:
768 return dec.binding;
769 case DecorationOffset:
770 return dec.offset;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100771 case DecorationXfbBuffer:
772 return dec.xfb_buffer;
773 case DecorationXfbStride:
774 return dec.xfb_stride;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200775 case DecorationStream:
776 return dec.stream;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200777 case DecorationSpecId:
778 return dec.spec_id;
779 case DecorationIndex:
780 return dec.index;
781 default:
782 return 1;
783 }
784}
785
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200786const Bitset &ParsedIR::get_decoration_bitset(ID id) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200787{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100788 auto *m = find_meta(id);
789 if (m)
790 {
791 auto &dec = m->decoration;
792 return dec.decoration_flags;
793 }
794 else
795 return cleared_bitset;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200796}
797
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200798void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200799{
Hans-Kristian Arntzen39bad2c2022-03-12 12:03:39 +0100800 auto &m = meta[id];
801 m.members.resize(max(m.members.size(), size_t(index) + 1));
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200802 auto &dec = meta[id].members[index];
803 dec.decoration_flags.set(decoration);
804
805 switch (decoration)
806 {
807 case DecorationHlslSemanticGOOGLE:
808 dec.hlsl_semantic = argument;
809 break;
810
811 default:
812 break;
813 }
814}
815
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200816const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200817{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100818 auto *m = find_meta(id);
819 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200820 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100821 if (!has_member_decoration(id, index, decoration))
822 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200823
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100824 auto &dec = m->members[index];
825
826 switch (decoration)
827 {
828 case DecorationHlslSemanticGOOGLE:
829 return dec.hlsl_semantic;
830
831 default:
832 return empty_string;
833 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200834 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100835 else
836 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200837}
838
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200839void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200840{
841 auto &m = meta[id];
842 if (index >= m.members.size())
843 return;
844
845 auto &dec = m.members[index];
846
847 dec.decoration_flags.clear(decoration);
848 switch (decoration)
849 {
850 case DecorationBuiltIn:
851 dec.builtin = false;
852 break;
853
854 case DecorationLocation:
855 dec.location = 0;
856 break;
857
858 case DecorationComponent:
859 dec.component = 0;
860 break;
861
862 case DecorationOffset:
863 dec.offset = 0;
864 break;
865
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +0100866 case DecorationXfbBuffer:
867 dec.xfb_buffer = 0;
868 break;
869
870 case DecorationXfbStride:
871 dec.xfb_stride = 0;
872 break;
873
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +0200874 case DecorationStream:
875 dec.stream = 0;
876 break;
877
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200878 case DecorationSpecId:
879 dec.spec_id = 0;
880 break;
881
882 case DecorationHlslSemanticGOOGLE:
883 dec.hlsl_semantic.clear();
884 break;
885
886 default:
887 break;
888 }
889}
890
891uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
892{
893 auto curr_bound = ids.size();
894 auto new_bound = curr_bound + incr_amount;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200895
896 ids.reserve(ids.size() + incr_amount);
897 for (uint32_t i = 0; i < incr_amount; i++)
898 ids.emplace_back(pool_group.get());
899
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200900 block_meta.resize(new_bound);
901 return uint32_t(curr_bound);
902}
903
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200904void ParsedIR::remove_typed_id(Types type, ID id)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100905{
906 auto &type_ids = ids_for_type[type];
907 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
908}
909
910void ParsedIR::reset_all_of_type(Types type)
911{
912 for (auto &id : ids_for_type[type])
913 if (ids[id].get_type() == type)
914 ids[id].reset();
915
916 ids_for_type[type].clear();
917}
918
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200919void ParsedIR::add_typed_id(Types type, ID id)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100920{
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200921 if (loop_iteration_depth_hard != 0)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100922 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
923
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200924 if (loop_iteration_depth_soft != 0)
925 {
926 if (!ids[id].empty())
927 SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
928 return;
929 }
930
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200931 if (ids[id].empty() || ids[id].get_type() != type)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100932 {
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200933 switch (type)
934 {
935 case TypeConstant:
936 ids_for_constant_or_variable.push_back(id);
937 ids_for_constant_or_type.push_back(id);
938 break;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100939
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200940 case TypeVariable:
941 ids_for_constant_or_variable.push_back(id);
942 break;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100943
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200944 case TypeType:
945 case TypeConstantOp:
946 ids_for_constant_or_type.push_back(id);
947 break;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100948
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200949 default:
950 break;
951 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100952 }
953
954 if (ids[id].empty())
955 {
956 ids_for_type[type].push_back(id);
957 }
958 else if (ids[id].get_type() != type)
959 {
960 remove_typed_id(ids[id].get_type(), id);
961 ids_for_type[type].push_back(id);
962 }
963}
964
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200965const Meta *ParsedIR::find_meta(ID id) const
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100966{
967 auto itr = meta.find(id);
968 if (itr != end(meta))
969 return &itr->second;
970 else
971 return nullptr;
972}
973
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200974Meta *ParsedIR::find_meta(ID id)
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100975{
976 auto itr = meta.find(id);
977 if (itr != end(meta))
978 return &itr->second;
979 else
980 return nullptr;
981}
982
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200983ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200984{
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200985 return ParsedIR::LoopLock(&loop_iteration_depth_hard);
986}
987
988ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
989{
990 return ParsedIR::LoopLock(&loop_iteration_depth_soft);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200991}
992
993ParsedIR::LoopLock::~LoopLock()
994{
995 if (lock)
996 (*lock)--;
997}
998
999ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
Hans-Kristian Arntzen3fa2b142019-07-23 12:23:41 +02001000 : lock(lock_)
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001001{
1002 if (lock)
1003 (*lock)++;
1004}
1005
1006ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1007{
Daniel Thornburgh44c33332022-03-02 23:02:38 +00001008 *this = std::move(other);
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001009}
1010
1011ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
1012{
1013 if (lock)
1014 (*lock)--;
1015 lock = other.lock;
1016 other.lock = nullptr;
1017 return *this;
1018}
1019
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01001020void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
1021{
1022 auto &constant_type = get<SPIRType>(type);
1023
1024 if (constant_type.pointer)
1025 {
1026 if (add_to_typed_id_set)
1027 add_typed_id(TypeConstant, id);
1028 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1029 constant.self = id;
1030 constant.make_null(constant_type);
1031 }
1032 else if (!constant_type.array.empty())
1033 {
1034 assert(constant_type.parent_type);
1035 uint32_t parent_id = increase_bound_by(1);
1036 make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
1037
1038 if (!constant_type.array_size_literal.back())
1039 SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
1040
1041 SmallVector<uint32_t> elements(constant_type.array.back());
1042 for (uint32_t i = 0; i < constant_type.array.back(); i++)
1043 elements[i] = parent_id;
1044
1045 if (add_to_typed_id_set)
1046 add_typed_id(TypeConstant, id);
1047 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1048 }
1049 else if (!constant_type.member_types.empty())
1050 {
1051 uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
1052 SmallVector<uint32_t> elements(constant_type.member_types.size());
1053 for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
1054 {
1055 make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
1056 elements[i] = member_ids + i;
1057 }
1058
1059 if (add_to_typed_id_set)
1060 add_typed_id(TypeConstant, id);
1061 variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
1062 }
1063 else
1064 {
1065 if (add_to_typed_id_set)
1066 add_typed_id(TypeConstant, id);
1067 auto &constant = variant_set<SPIRConstant>(ids[id], type);
1068 constant.self = id;
1069 constant.make_null(constant_type);
1070 }
1071}
1072
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001073} // namespace SPIRV_CROSS_NAMESPACE