blob: 6d80fcb3b3b8c9e5820f76107b707cae162087d4 [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);
29 meta.resize(bounds);
30 block_meta.resize(bounds);
31}
32
33static string ensure_valid_identifier(const string &name, bool member)
34{
35 // Functions in glslangValidator are mangled with name(<mangled> stuff.
36 // Normally, we would never see '(' in any legal identifiers, so just strip them out.
37 auto str = name.substr(0, name.find('('));
38
39 for (uint32_t i = 0; i < str.size(); i++)
40 {
41 auto &c = str[i];
42
43 if (member)
44 {
45 // _m<num> variables are reserved by the internal implementation,
46 // otherwise, make sure the name is a valid identifier.
47 if (i == 0)
48 c = isalpha(c) ? c : '_';
49 else if (i == 2 && str[0] == '_' && str[1] == 'm')
50 c = isalpha(c) ? c : '_';
51 else
52 c = isalnum(c) ? c : '_';
53 }
54 else
55 {
56 // _<num> variables are reserved by the internal implementation,
57 // otherwise, make sure the name is a valid identifier.
58 if (i == 0 || (str[0] == '_' && i == 1))
59 c = isalpha(c) ? c : '_';
60 else
61 c = isalnum(c) ? c : '_';
62 }
63 }
64 return str;
65}
66
67const string &ParsedIR::get_name(uint32_t id) const
68{
69 return meta[id].decoration.alias;
70}
71
72const string &ParsedIR::get_member_name(uint32_t id, uint32_t index) const
73{
74 auto &m = meta[id];
75 if (index >= m.members.size())
76 {
77 static string empty;
78 return empty;
79 }
80
81 return m.members[index].alias;
82}
83
84void ParsedIR::set_name(uint32_t id, const string &name)
85{
86 auto &str = meta[id].decoration.alias;
87 str.clear();
88
89 if (name.empty())
90 return;
91
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020092 // Reserved for temporaries.
93 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
94 return;
95
96 str = ensure_valid_identifier(name, false);
97}
98
99void ParsedIR::set_member_name(uint32_t id, uint32_t index, const string &name)
100{
101 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
102
103 auto &str = meta[id].members[index].alias;
104 str.clear();
105 if (name.empty())
106 return;
107
108 // Reserved for unnamed members.
109 if (name[0] == '_' && name.size() >= 3 && name[1] == 'm' && isdigit(name[2]))
110 return;
111
112 str = ensure_valid_identifier(name, true);
113}
114
115void ParsedIR::set_decoration_string(uint32_t id, Decoration decoration, const string &argument)
116{
117 auto &dec = meta[id].decoration;
118 dec.decoration_flags.set(decoration);
119
120 switch (decoration)
121 {
122 case DecorationHlslSemanticGOOGLE:
123 dec.hlsl_semantic = argument;
124 break;
125
126 default:
127 break;
128 }
129}
130
131void ParsedIR::set_decoration(uint32_t id, Decoration decoration, uint32_t argument)
132{
133 auto &dec = meta[id].decoration;
134 dec.decoration_flags.set(decoration);
135
136 switch (decoration)
137 {
138 case DecorationBuiltIn:
139 dec.builtin = true;
140 dec.builtin_type = static_cast<BuiltIn>(argument);
141 break;
142
143 case DecorationLocation:
144 dec.location = argument;
145 break;
146
147 case DecorationComponent:
148 dec.component = argument;
149 break;
150
151 case DecorationOffset:
152 dec.offset = argument;
153 break;
154
155 case DecorationArrayStride:
156 dec.array_stride = argument;
157 break;
158
159 case DecorationMatrixStride:
160 dec.matrix_stride = argument;
161 break;
162
163 case DecorationBinding:
164 dec.binding = argument;
165 break;
166
167 case DecorationDescriptorSet:
168 dec.set = argument;
169 break;
170
171 case DecorationInputAttachmentIndex:
172 dec.input_attachment = argument;
173 break;
174
175 case DecorationSpecId:
176 dec.spec_id = argument;
177 break;
178
179 case DecorationIndex:
180 dec.index = argument;
181 break;
182
183 case DecorationHlslCounterBufferGOOGLE:
184 meta[id].hlsl_magic_counter_buffer = argument;
Hans-Kristian Arntzen9aa623a2018-11-22 10:23:58 +0100185 meta[argument].hlsl_is_magic_counter_buffer = true;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200186 break;
187
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100188 case DecorationFPRoundingMode:
189 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
190 break;
191
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200192 default:
193 break;
194 }
195}
196
197void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument)
198{
199 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
200 auto &dec = meta[id].members[index];
201 dec.decoration_flags.set(decoration);
202
203 switch (decoration)
204 {
205 case DecorationBuiltIn:
206 dec.builtin = true;
207 dec.builtin_type = static_cast<BuiltIn>(argument);
208 break;
209
210 case DecorationLocation:
211 dec.location = argument;
212 break;
213
214 case DecorationComponent:
215 dec.component = argument;
216 break;
217
218 case DecorationBinding:
219 dec.binding = argument;
220 break;
221
222 case DecorationOffset:
223 dec.offset = argument;
224 break;
225
226 case DecorationSpecId:
227 dec.spec_id = argument;
228 break;
229
230 case DecorationMatrixStride:
231 dec.matrix_stride = argument;
232 break;
233
234 case DecorationIndex:
235 dec.index = argument;
236 break;
237
238 default:
239 break;
240 }
241}
242
243// Recursively marks any constants referenced by the specified constant instruction as being used
244// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
245void ParsedIR::mark_used_as_array_length(uint32_t id)
246{
247 switch (ids[id].get_type())
248 {
249 case TypeConstant:
250 get<SPIRConstant>(id).is_used_as_array_length = true;
251 break;
252
253 case TypeConstantOp:
254 {
255 auto &cop = get<SPIRConstantOp>(id);
256 for (uint32_t arg_id : cop.arguments)
257 mark_used_as_array_length(arg_id);
258 break;
259 }
260
261 case TypeUndef:
262 break;
263
264 default:
265 assert(0);
266 }
267}
268
269Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
270{
271 auto &type = get<SPIRType>(var.basetype);
272 assert(type.basetype == SPIRType::Struct);
273
274 // Some flags like non-writable, non-readable are actually found
275 // as member decorations. If all members have a decoration set, propagate
276 // the decoration up as a regular variable decoration.
277 Bitset base_flags = meta[var.self].decoration.decoration_flags;
278
279 if (type.member_types.empty())
280 return base_flags;
281
282 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
283 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
284 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
285
286 base_flags.merge_or(all_members_flags);
287 return base_flags;
288}
289
290const Bitset &ParsedIR::get_member_decoration_bitset(uint32_t id, uint32_t index) const
291{
292 auto &m = meta[id];
293 if (index >= m.members.size())
294 {
295 static const Bitset cleared = {};
296 return cleared;
297 }
298
299 return m.members[index].decoration_flags;
300}
301
302bool ParsedIR::has_decoration(uint32_t id, Decoration decoration) const
303{
304 return get_decoration_bitset(id).get(decoration);
305}
306
307uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const
308{
309 auto &dec = meta[id].decoration;
310 if (!dec.decoration_flags.get(decoration))
311 return 0;
312
313 switch (decoration)
314 {
315 case DecorationBuiltIn:
316 return dec.builtin_type;
317 case DecorationLocation:
318 return dec.location;
319 case DecorationComponent:
320 return dec.component;
321 case DecorationOffset:
322 return dec.offset;
323 case DecorationBinding:
324 return dec.binding;
325 case DecorationDescriptorSet:
326 return dec.set;
327 case DecorationInputAttachmentIndex:
328 return dec.input_attachment;
329 case DecorationSpecId:
330 return dec.spec_id;
331 case DecorationArrayStride:
332 return dec.array_stride;
333 case DecorationMatrixStride:
334 return dec.matrix_stride;
335 case DecorationIndex:
336 return dec.index;
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100337 case DecorationFPRoundingMode:
338 return dec.fp_rounding_mode;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200339 default:
340 return 1;
341 }
342}
343
344const string &ParsedIR::get_decoration_string(uint32_t id, Decoration decoration) const
345{
346 auto &dec = meta[id].decoration;
347 static const string empty;
348
349 if (!dec.decoration_flags.get(decoration))
350 return empty;
351
352 switch (decoration)
353 {
354 case DecorationHlslSemanticGOOGLE:
355 return dec.hlsl_semantic;
356
357 default:
358 return empty;
359 }
360}
361
362void ParsedIR::unset_decoration(uint32_t id, Decoration decoration)
363{
364 auto &dec = meta[id].decoration;
365 dec.decoration_flags.clear(decoration);
366 switch (decoration)
367 {
368 case DecorationBuiltIn:
369 dec.builtin = false;
370 break;
371
372 case DecorationLocation:
373 dec.location = 0;
374 break;
375
376 case DecorationComponent:
377 dec.component = 0;
378 break;
379
380 case DecorationOffset:
381 dec.offset = 0;
382 break;
383
384 case DecorationBinding:
385 dec.binding = 0;
386 break;
387
388 case DecorationDescriptorSet:
389 dec.set = 0;
390 break;
391
392 case DecorationInputAttachmentIndex:
393 dec.input_attachment = 0;
394 break;
395
396 case DecorationSpecId:
397 dec.spec_id = 0;
398 break;
399
400 case DecorationHlslSemanticGOOGLE:
401 dec.hlsl_semantic.clear();
402 break;
403
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100404 case DecorationFPRoundingMode:
405 dec.fp_rounding_mode = FPRoundingModeMax;
406 break;
407
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200408 case DecorationHlslCounterBufferGOOGLE:
409 {
410 auto &counter = meta[id].hlsl_magic_counter_buffer;
411 if (counter)
412 {
413 meta[counter].hlsl_is_magic_counter_buffer = false;
414 counter = 0;
415 }
416 break;
417 }
418
419 default:
420 break;
421 }
422}
423
424bool ParsedIR::has_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
425{
426 return get_member_decoration_bitset(id, index).get(decoration);
427}
428
429uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
430{
431 auto &m = meta[id];
432 if (index >= m.members.size())
433 return 0;
434
435 auto &dec = m.members[index];
436 if (!dec.decoration_flags.get(decoration))
437 return 0;
438
439 switch (decoration)
440 {
441 case DecorationBuiltIn:
442 return dec.builtin_type;
443 case DecorationLocation:
444 return dec.location;
445 case DecorationComponent:
446 return dec.component;
447 case DecorationBinding:
448 return dec.binding;
449 case DecorationOffset:
450 return dec.offset;
451 case DecorationSpecId:
452 return dec.spec_id;
453 case DecorationIndex:
454 return dec.index;
455 default:
456 return 1;
457 }
458}
459
460const Bitset &ParsedIR::get_decoration_bitset(uint32_t id) const
461{
462 auto &dec = meta[id].decoration;
463 return dec.decoration_flags;
464}
465
466void ParsedIR::set_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration, const string &argument)
467{
468 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
469 auto &dec = meta[id].members[index];
470 dec.decoration_flags.set(decoration);
471
472 switch (decoration)
473 {
474 case DecorationHlslSemanticGOOGLE:
475 dec.hlsl_semantic = argument;
476 break;
477
478 default:
479 break;
480 }
481}
482
483const string &ParsedIR::get_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration) const
484{
485 static const string empty;
486 auto &m = meta[id];
487
488 if (!has_member_decoration(id, index, decoration))
489 return empty;
490
491 auto &dec = m.members[index];
492
493 switch (decoration)
494 {
495 case DecorationHlslSemanticGOOGLE:
496 return dec.hlsl_semantic;
497
498 default:
499 return empty;
500 }
501}
502
503void ParsedIR::unset_member_decoration(uint32_t id, uint32_t index, Decoration decoration)
504{
505 auto &m = meta[id];
506 if (index >= m.members.size())
507 return;
508
509 auto &dec = m.members[index];
510
511 dec.decoration_flags.clear(decoration);
512 switch (decoration)
513 {
514 case DecorationBuiltIn:
515 dec.builtin = false;
516 break;
517
518 case DecorationLocation:
519 dec.location = 0;
520 break;
521
522 case DecorationComponent:
523 dec.component = 0;
524 break;
525
526 case DecorationOffset:
527 dec.offset = 0;
528 break;
529
530 case DecorationSpecId:
531 dec.spec_id = 0;
532 break;
533
534 case DecorationHlslSemanticGOOGLE:
535 dec.hlsl_semantic.clear();
536 break;
537
538 default:
539 break;
540 }
541}
542
543uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
544{
545 auto curr_bound = ids.size();
546 auto new_bound = curr_bound + incr_amount;
547 ids.resize(new_bound);
548 meta.resize(new_bound);
549 block_meta.resize(new_bound);
550 return uint32_t(curr_bound);
551}
552
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100553void ParsedIR::remove_typed_id(Types type, uint32_t id)
554{
555 auto &type_ids = ids_for_type[type];
556 type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
557}
558
559void ParsedIR::reset_all_of_type(Types type)
560{
561 for (auto &id : ids_for_type[type])
562 if (ids[id].get_type() == type)
563 ids[id].reset();
564
565 ids_for_type[type].clear();
566}
567
568void ParsedIR::add_typed_id(Types type, uint32_t id)
569{
570 if (loop_iteration_depth)
571 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
572
573 switch (type)
574 {
575 case TypeConstant:
576 ids_for_constant_or_variable.push_back(id);
577 ids_for_constant_or_type.push_back(id);
578 break;
579
580 case TypeVariable:
581 ids_for_constant_or_variable.push_back(id);
582 break;
583
584 case TypeType:
585 case TypeConstantOp:
586 ids_for_constant_or_type.push_back(id);
587 break;
588
589 default:
590 break;
591 }
592
593 if (ids[id].empty())
594 {
595 ids_for_type[type].push_back(id);
596 }
597 else if (ids[id].get_type() != type)
598 {
599 remove_typed_id(ids[id].get_type(), id);
600 ids_for_type[type].push_back(id);
601 }
602}
603
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +0100604} // namespace spirv_cross