blob: 82bc561117c30b2e828b55ab8ed5ac201f11295c [file] [log] [blame]
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001/*
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +01002 * Copyright 2018-2019 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"
18#include <assert.h>
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +010019#include <algorithm>
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020020
21using namespace std;
22using namespace spv;
23
24namespace spirv_cross
25{
26void ParsedIR::set_id_bounds(uint32_t bounds)
27{
28 ids.resize(bounds);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020029 block_meta.resize(bounds);
30}
31
32static string ensure_valid_identifier(const string &name, bool member)
33{
34 // Functions in glslangValidator are mangled with name(<mangled> stuff.
35 // Normally, we would never see '(' in any legal identifiers, so just strip them out.
36 auto str = name.substr(0, name.find('('));
37
38 for (uint32_t i = 0; i < str.size(); i++)
39 {
40 auto &c = str[i];
41
42 if (member)
43 {
44 // _m<num> variables are reserved by the internal implementation,
45 // otherwise, make sure the name is a valid identifier.
46 if (i == 0)
47 c = isalpha(c) ? c : '_';
48 else if (i == 2 && str[0] == '_' && str[1] == 'm')
49 c = isalpha(c) ? c : '_';
50 else
51 c = isalnum(c) ? c : '_';
52 }
53 else
54 {
55 // _<num> variables are reserved by the internal implementation,
56 // otherwise, make sure the name is a valid identifier.
57 if (i == 0 || (str[0] == '_' && i == 1))
58 c = isalpha(c) ? c : '_';
59 else
60 c = isalnum(c) ? c : '_';
61 }
62 }
63 return str;
64}
65
66const string &ParsedIR::get_name(uint32_t id) const
67{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010068 auto *m = find_meta(id);
69 if (m)
70 return m->decoration.alias;
71 else
72 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020073}
74
75const string &ParsedIR::get_member_name(uint32_t id, uint32_t index) const
76{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010077 auto *m = find_meta(id);
78 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020079 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010080 if (index >= m->members.size())
81 return empty_string;
82 return m->members[index].alias;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020083 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +010084 else
85 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020086}
87
88void ParsedIR::set_name(uint32_t id, const string &name)
89{
90 auto &str = meta[id].decoration.alias;
91 str.clear();
92
93 if (name.empty())
94 return;
95
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020096 // Reserved for temporaries.
97 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
98 return;
99
100 str = ensure_valid_identifier(name, false);
101}
102
103void ParsedIR::set_member_name(uint32_t id, uint32_t index, const string &name)
104{
105 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
106
107 auto &str = meta[id].members[index].alias;
108 str.clear();
109 if (name.empty())
110 return;
111
112 // Reserved for unnamed members.
113 if (name[0] == '_' && name.size() >= 3 && name[1] == 'm' && isdigit(name[2]))
114 return;
115
116 str = ensure_valid_identifier(name, true);
117}
118
119void ParsedIR::set_decoration_string(uint32_t id, Decoration decoration, const string &argument)
120{
121 auto &dec = meta[id].decoration;
122 dec.decoration_flags.set(decoration);
123
124 switch (decoration)
125 {
126 case DecorationHlslSemanticGOOGLE:
127 dec.hlsl_semantic = argument;
128 break;
129
130 default:
131 break;
132 }
133}
134
135void ParsedIR::set_decoration(uint32_t id, Decoration decoration, uint32_t argument)
136{
137 auto &dec = meta[id].decoration;
138 dec.decoration_flags.set(decoration);
139
140 switch (decoration)
141 {
142 case DecorationBuiltIn:
143 dec.builtin = true;
144 dec.builtin_type = static_cast<BuiltIn>(argument);
145 break;
146
147 case DecorationLocation:
148 dec.location = argument;
149 break;
150
151 case DecorationComponent:
152 dec.component = argument;
153 break;
154
155 case DecorationOffset:
156 dec.offset = argument;
157 break;
158
159 case DecorationArrayStride:
160 dec.array_stride = argument;
161 break;
162
163 case DecorationMatrixStride:
164 dec.matrix_stride = argument;
165 break;
166
167 case DecorationBinding:
168 dec.binding = argument;
169 break;
170
171 case DecorationDescriptorSet:
172 dec.set = argument;
173 break;
174
175 case DecorationInputAttachmentIndex:
176 dec.input_attachment = argument;
177 break;
178
179 case DecorationSpecId:
180 dec.spec_id = argument;
181 break;
182
183 case DecorationIndex:
184 dec.index = argument;
185 break;
186
187 case DecorationHlslCounterBufferGOOGLE:
188 meta[id].hlsl_magic_counter_buffer = argument;
Hans-Kristian Arntzen9aa623a2018-11-22 10:23:58 +0100189 meta[argument].hlsl_is_magic_counter_buffer = true;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200190 break;
191
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100192 case DecorationFPRoundingMode:
193 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
194 break;
195
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200196 default:
197 break;
198 }
199}
200
201void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument)
202{
203 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
204 auto &dec = meta[id].members[index];
205 dec.decoration_flags.set(decoration);
206
207 switch (decoration)
208 {
209 case DecorationBuiltIn:
210 dec.builtin = true;
211 dec.builtin_type = static_cast<BuiltIn>(argument);
212 break;
213
214 case DecorationLocation:
215 dec.location = argument;
216 break;
217
218 case DecorationComponent:
219 dec.component = argument;
220 break;
221
222 case DecorationBinding:
223 dec.binding = argument;
224 break;
225
226 case DecorationOffset:
227 dec.offset = argument;
228 break;
229
230 case DecorationSpecId:
231 dec.spec_id = argument;
232 break;
233
234 case DecorationMatrixStride:
235 dec.matrix_stride = argument;
236 break;
237
238 case DecorationIndex:
239 dec.index = argument;
240 break;
241
242 default:
243 break;
244 }
245}
246
247// Recursively marks any constants referenced by the specified constant instruction as being used
248// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
249void ParsedIR::mark_used_as_array_length(uint32_t id)
250{
251 switch (ids[id].get_type())
252 {
253 case TypeConstant:
254 get<SPIRConstant>(id).is_used_as_array_length = true;
255 break;
256
257 case TypeConstantOp:
258 {
259 auto &cop = get<SPIRConstantOp>(id);
260 for (uint32_t arg_id : cop.arguments)
261 mark_used_as_array_length(arg_id);
262 break;
263 }
264
265 case TypeUndef:
266 break;
267
268 default:
269 assert(0);
270 }
271}
272
273Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
274{
275 auto &type = get<SPIRType>(var.basetype);
276 assert(type.basetype == SPIRType::Struct);
277
278 // Some flags like non-writable, non-readable are actually found
279 // as member decorations. If all members have a decoration set, propagate
280 // the decoration up as a regular variable decoration.
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100281 Bitset base_flags;
282 auto *m = find_meta(var.self);
283 if (m)
284 base_flags = m->decoration.decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200285
286 if (type.member_types.empty())
287 return base_flags;
288
289 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
290 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
291 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
292
293 base_flags.merge_or(all_members_flags);
294 return base_flags;
295}
296
297const Bitset &ParsedIR::get_member_decoration_bitset(uint32_t id, uint32_t index) const
298{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100299 auto *m = find_meta(id);
300 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200301 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100302 if (index >= m->members.size())
303 return cleared_bitset;
304 return m->members[index].decoration_flags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200305 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100306 else
307 return cleared_bitset;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200308}
309
310bool ParsedIR::has_decoration(uint32_t id, Decoration decoration) const
311{
312 return get_decoration_bitset(id).get(decoration);
313}
314
315uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const
316{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100317 auto *m = find_meta(id);
318 if (!m)
319 return 0;
320
321 auto &dec = m->decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200322 if (!dec.decoration_flags.get(decoration))
323 return 0;
324
325 switch (decoration)
326 {
327 case DecorationBuiltIn:
328 return dec.builtin_type;
329 case DecorationLocation:
330 return dec.location;
331 case DecorationComponent:
332 return dec.component;
333 case DecorationOffset:
334 return dec.offset;
335 case DecorationBinding:
336 return dec.binding;
337 case DecorationDescriptorSet:
338 return dec.set;
339 case DecorationInputAttachmentIndex:
340 return dec.input_attachment;
341 case DecorationSpecId:
342 return dec.spec_id;
343 case DecorationArrayStride:
344 return dec.array_stride;
345 case DecorationMatrixStride:
346 return dec.matrix_stride;
347 case DecorationIndex:
348 return dec.index;
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100349 case DecorationFPRoundingMode:
350 return dec.fp_rounding_mode;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200351 default:
352 return 1;
353 }
354}
355
356const string &ParsedIR::get_decoration_string(uint32_t id, Decoration decoration) const
357{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100358 auto *m = find_meta(id);
359 if (!m)
360 return empty_string;
361
362 auto &dec = m->decoration;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200363
364 if (!dec.decoration_flags.get(decoration))
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100365 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200366
367 switch (decoration)
368 {
369 case DecorationHlslSemanticGOOGLE:
370 return dec.hlsl_semantic;
371
372 default:
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100373 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200374 }
375}
376
377void ParsedIR::unset_decoration(uint32_t id, Decoration decoration)
378{
379 auto &dec = meta[id].decoration;
380 dec.decoration_flags.clear(decoration);
381 switch (decoration)
382 {
383 case DecorationBuiltIn:
384 dec.builtin = false;
385 break;
386
387 case DecorationLocation:
388 dec.location = 0;
389 break;
390
391 case DecorationComponent:
392 dec.component = 0;
393 break;
394
395 case DecorationOffset:
396 dec.offset = 0;
397 break;
398
399 case DecorationBinding:
400 dec.binding = 0;
401 break;
402
403 case DecorationDescriptorSet:
404 dec.set = 0;
405 break;
406
407 case DecorationInputAttachmentIndex:
408 dec.input_attachment = 0;
409 break;
410
411 case DecorationSpecId:
412 dec.spec_id = 0;
413 break;
414
415 case DecorationHlslSemanticGOOGLE:
416 dec.hlsl_semantic.clear();
417 break;
418
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100419 case DecorationFPRoundingMode:
420 dec.fp_rounding_mode = FPRoundingModeMax;
421 break;
422
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200423 case DecorationHlslCounterBufferGOOGLE:
424 {
425 auto &counter = meta[id].hlsl_magic_counter_buffer;
426 if (counter)
427 {
428 meta[counter].hlsl_is_magic_counter_buffer = false;
429 counter = 0;
430 }
431 break;
432 }
433
434 default:
435 break;
436 }
437}
438
439bool ParsedIR::has_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
440{
441 return get_member_decoration_bitset(id, index).get(decoration);
442}
443
444uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
445{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100446 auto *m = find_meta(id);
447 if (!m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200448 return 0;
449
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100450 if (index >= m->members.size())
451 return 0;
452
453 auto &dec = m->members[index];
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200454 if (!dec.decoration_flags.get(decoration))
455 return 0;
456
457 switch (decoration)
458 {
459 case DecorationBuiltIn:
460 return dec.builtin_type;
461 case DecorationLocation:
462 return dec.location;
463 case DecorationComponent:
464 return dec.component;
465 case DecorationBinding:
466 return dec.binding;
467 case DecorationOffset:
468 return dec.offset;
469 case DecorationSpecId:
470 return dec.spec_id;
471 case DecorationIndex:
472 return dec.index;
473 default:
474 return 1;
475 }
476}
477
478const Bitset &ParsedIR::get_decoration_bitset(uint32_t id) const
479{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100480 auto *m = find_meta(id);
481 if (m)
482 {
483 auto &dec = m->decoration;
484 return dec.decoration_flags;
485 }
486 else
487 return cleared_bitset;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200488}
489
490void ParsedIR::set_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration, const string &argument)
491{
492 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
493 auto &dec = meta[id].members[index];
494 dec.decoration_flags.set(decoration);
495
496 switch (decoration)
497 {
498 case DecorationHlslSemanticGOOGLE:
499 dec.hlsl_semantic = argument;
500 break;
501
502 default:
503 break;
504 }
505}
506
507const string &ParsedIR::get_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration) const
508{
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100509 auto *m = find_meta(id);
510 if (m)
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200511 {
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100512 if (!has_member_decoration(id, index, decoration))
513 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200514
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100515 auto &dec = m->members[index];
516
517 switch (decoration)
518 {
519 case DecorationHlslSemanticGOOGLE:
520 return dec.hlsl_semantic;
521
522 default:
523 return empty_string;
524 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200525 }
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100526 else
527 return empty_string;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200528}
529
530void ParsedIR::unset_member_decoration(uint32_t id, uint32_t index, Decoration decoration)
531{
532 auto &m = meta[id];
533 if (index >= m.members.size())
534 return;
535
536 auto &dec = m.members[index];
537
538 dec.decoration_flags.clear(decoration);
539 switch (decoration)
540 {
541 case DecorationBuiltIn:
542 dec.builtin = false;
543 break;
544
545 case DecorationLocation:
546 dec.location = 0;
547 break;
548
549 case DecorationComponent:
550 dec.component = 0;
551 break;
552
553 case DecorationOffset:
554 dec.offset = 0;
555 break;
556
557 case DecorationSpecId:
558 dec.spec_id = 0;
559 break;
560
561 case DecorationHlslSemanticGOOGLE:
562 dec.hlsl_semantic.clear();
563 break;
564
565 default:
566 break;
567 }
568}
569
570uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
571{
572 auto curr_bound = ids.size();
573 auto new_bound = curr_bound + incr_amount;
574 ids.resize(new_bound);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200575 block_meta.resize(new_bound);
576 return uint32_t(curr_bound);
577}
578
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100579void ParsedIR::remove_typed_id(Types type, uint32_t id)
580{
581 auto &type_ids = ids_for_type[type];
582 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
583}
584
585void ParsedIR::reset_all_of_type(Types type)
586{
587 for (auto &id : ids_for_type[type])
588 if (ids[id].get_type() == type)
589 ids[id].reset();
590
591 ids_for_type[type].clear();
592}
593
594void ParsedIR::add_typed_id(Types type, uint32_t id)
595{
596 if (loop_iteration_depth)
597 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
598
599 switch (type)
600 {
601 case TypeConstant:
602 ids_for_constant_or_variable.push_back(id);
603 ids_for_constant_or_type.push_back(id);
604 break;
605
606 case TypeVariable:
607 ids_for_constant_or_variable.push_back(id);
608 break;
609
610 case TypeType:
611 case TypeConstantOp:
612 ids_for_constant_or_type.push_back(id);
613 break;
614
615 default:
616 break;
617 }
618
619 if (ids[id].empty())
620 {
621 ids_for_type[type].push_back(id);
622 }
623 else if (ids[id].get_type() != type)
624 {
625 remove_typed_id(ids[id].get_type(), id);
626 ids_for_type[type].push_back(id);
627 }
628}
629
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100630const Meta *ParsedIR::find_meta(uint32_t id) const
631{
632 auto itr = meta.find(id);
633 if (itr != end(meta))
634 return &itr->second;
635 else
636 return nullptr;
637}
638
639Meta *ParsedIR::find_meta(uint32_t id)
640{
641 auto itr = meta.find(id);
642 if (itr != end(meta))
643 return &itr->second;
644 else
645 return nullptr;
646}
647
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +0100648} // namespace spirv_cross