blob: a1804233310d736ff623fd7ab1d6c8ee2d05e6f7 [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>
19
20using namespace std;
21using namespace spv;
22
23namespace spirv_cross
24{
25void ParsedIR::set_id_bounds(uint32_t bounds)
26{
27 ids.resize(bounds);
28 meta.resize(bounds);
29 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{
68 return meta[id].decoration.alias;
69}
70
71const string &ParsedIR::get_member_name(uint32_t id, uint32_t index) const
72{
73 auto &m = meta[id];
74 if (index >= m.members.size())
75 {
76 static string empty;
77 return empty;
78 }
79
80 return m.members[index].alias;
81}
82
83void ParsedIR::set_name(uint32_t id, const string &name)
84{
85 auto &str = meta[id].decoration.alias;
86 str.clear();
87
88 if (name.empty())
89 return;
90
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020091 // Reserved for temporaries.
92 if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
93 return;
94
95 str = ensure_valid_identifier(name, false);
96}
97
98void ParsedIR::set_member_name(uint32_t id, uint32_t index, const string &name)
99{
100 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
101
102 auto &str = meta[id].members[index].alias;
103 str.clear();
104 if (name.empty())
105 return;
106
107 // Reserved for unnamed members.
108 if (name[0] == '_' && name.size() >= 3 && name[1] == 'm' && isdigit(name[2]))
109 return;
110
111 str = ensure_valid_identifier(name, true);
112}
113
114void ParsedIR::set_decoration_string(uint32_t id, Decoration decoration, const string &argument)
115{
116 auto &dec = meta[id].decoration;
117 dec.decoration_flags.set(decoration);
118
119 switch (decoration)
120 {
121 case DecorationHlslSemanticGOOGLE:
122 dec.hlsl_semantic = argument;
123 break;
124
125 default:
126 break;
127 }
128}
129
130void ParsedIR::set_decoration(uint32_t id, Decoration decoration, uint32_t argument)
131{
132 auto &dec = meta[id].decoration;
133 dec.decoration_flags.set(decoration);
134
135 switch (decoration)
136 {
137 case DecorationBuiltIn:
138 dec.builtin = true;
139 dec.builtin_type = static_cast<BuiltIn>(argument);
140 break;
141
142 case DecorationLocation:
143 dec.location = argument;
144 break;
145
146 case DecorationComponent:
147 dec.component = argument;
148 break;
149
150 case DecorationOffset:
151 dec.offset = argument;
152 break;
153
154 case DecorationArrayStride:
155 dec.array_stride = argument;
156 break;
157
158 case DecorationMatrixStride:
159 dec.matrix_stride = argument;
160 break;
161
162 case DecorationBinding:
163 dec.binding = argument;
164 break;
165
166 case DecorationDescriptorSet:
167 dec.set = argument;
168 break;
169
170 case DecorationInputAttachmentIndex:
171 dec.input_attachment = argument;
172 break;
173
174 case DecorationSpecId:
175 dec.spec_id = argument;
176 break;
177
178 case DecorationIndex:
179 dec.index = argument;
180 break;
181
182 case DecorationHlslCounterBufferGOOGLE:
183 meta[id].hlsl_magic_counter_buffer = argument;
Hans-Kristian Arntzen9aa623a2018-11-22 10:23:58 +0100184 meta[argument].hlsl_is_magic_counter_buffer = true;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200185 break;
186
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100187 case DecorationFPRoundingMode:
188 dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
189 break;
190
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200191 default:
192 break;
193 }
194}
195
196void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument)
197{
198 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
199 auto &dec = meta[id].members[index];
200 dec.decoration_flags.set(decoration);
201
202 switch (decoration)
203 {
204 case DecorationBuiltIn:
205 dec.builtin = true;
206 dec.builtin_type = static_cast<BuiltIn>(argument);
207 break;
208
209 case DecorationLocation:
210 dec.location = argument;
211 break;
212
213 case DecorationComponent:
214 dec.component = argument;
215 break;
216
217 case DecorationBinding:
218 dec.binding = argument;
219 break;
220
221 case DecorationOffset:
222 dec.offset = argument;
223 break;
224
225 case DecorationSpecId:
226 dec.spec_id = argument;
227 break;
228
229 case DecorationMatrixStride:
230 dec.matrix_stride = argument;
231 break;
232
233 case DecorationIndex:
234 dec.index = argument;
235 break;
236
237 default:
238 break;
239 }
240}
241
242// Recursively marks any constants referenced by the specified constant instruction as being used
243// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
244void ParsedIR::mark_used_as_array_length(uint32_t id)
245{
246 switch (ids[id].get_type())
247 {
248 case TypeConstant:
249 get<SPIRConstant>(id).is_used_as_array_length = true;
250 break;
251
252 case TypeConstantOp:
253 {
254 auto &cop = get<SPIRConstantOp>(id);
255 for (uint32_t arg_id : cop.arguments)
256 mark_used_as_array_length(arg_id);
257 break;
258 }
259
260 case TypeUndef:
261 break;
262
263 default:
264 assert(0);
265 }
266}
267
268Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
269{
270 auto &type = get<SPIRType>(var.basetype);
271 assert(type.basetype == SPIRType::Struct);
272
273 // Some flags like non-writable, non-readable are actually found
274 // as member decorations. If all members have a decoration set, propagate
275 // the decoration up as a regular variable decoration.
276 Bitset base_flags = meta[var.self].decoration.decoration_flags;
277
278 if (type.member_types.empty())
279 return base_flags;
280
281 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
282 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
283 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
284
285 base_flags.merge_or(all_members_flags);
286 return base_flags;
287}
288
289const Bitset &ParsedIR::get_member_decoration_bitset(uint32_t id, uint32_t index) const
290{
291 auto &m = meta[id];
292 if (index >= m.members.size())
293 {
294 static const Bitset cleared = {};
295 return cleared;
296 }
297
298 return m.members[index].decoration_flags;
299}
300
301bool ParsedIR::has_decoration(uint32_t id, Decoration decoration) const
302{
303 return get_decoration_bitset(id).get(decoration);
304}
305
306uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const
307{
308 auto &dec = meta[id].decoration;
309 if (!dec.decoration_flags.get(decoration))
310 return 0;
311
312 switch (decoration)
313 {
314 case DecorationBuiltIn:
315 return dec.builtin_type;
316 case DecorationLocation:
317 return dec.location;
318 case DecorationComponent:
319 return dec.component;
320 case DecorationOffset:
321 return dec.offset;
322 case DecorationBinding:
323 return dec.binding;
324 case DecorationDescriptorSet:
325 return dec.set;
326 case DecorationInputAttachmentIndex:
327 return dec.input_attachment;
328 case DecorationSpecId:
329 return dec.spec_id;
330 case DecorationArrayStride:
331 return dec.array_stride;
332 case DecorationMatrixStride:
333 return dec.matrix_stride;
334 case DecorationIndex:
335 return dec.index;
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100336 case DecorationFPRoundingMode:
337 return dec.fp_rounding_mode;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200338 default:
339 return 1;
340 }
341}
342
343const string &ParsedIR::get_decoration_string(uint32_t id, Decoration decoration) const
344{
345 auto &dec = meta[id].decoration;
346 static const string empty;
347
348 if (!dec.decoration_flags.get(decoration))
349 return empty;
350
351 switch (decoration)
352 {
353 case DecorationHlslSemanticGOOGLE:
354 return dec.hlsl_semantic;
355
356 default:
357 return empty;
358 }
359}
360
361void ParsedIR::unset_decoration(uint32_t id, Decoration decoration)
362{
363 auto &dec = meta[id].decoration;
364 dec.decoration_flags.clear(decoration);
365 switch (decoration)
366 {
367 case DecorationBuiltIn:
368 dec.builtin = false;
369 break;
370
371 case DecorationLocation:
372 dec.location = 0;
373 break;
374
375 case DecorationComponent:
376 dec.component = 0;
377 break;
378
379 case DecorationOffset:
380 dec.offset = 0;
381 break;
382
383 case DecorationBinding:
384 dec.binding = 0;
385 break;
386
387 case DecorationDescriptorSet:
388 dec.set = 0;
389 break;
390
391 case DecorationInputAttachmentIndex:
392 dec.input_attachment = 0;
393 break;
394
395 case DecorationSpecId:
396 dec.spec_id = 0;
397 break;
398
399 case DecorationHlslSemanticGOOGLE:
400 dec.hlsl_semantic.clear();
401 break;
402
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +0100403 case DecorationFPRoundingMode:
404 dec.fp_rounding_mode = FPRoundingModeMax;
405 break;
406
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200407 case DecorationHlslCounterBufferGOOGLE:
408 {
409 auto &counter = meta[id].hlsl_magic_counter_buffer;
410 if (counter)
411 {
412 meta[counter].hlsl_is_magic_counter_buffer = false;
413 counter = 0;
414 }
415 break;
416 }
417
418 default:
419 break;
420 }
421}
422
423bool ParsedIR::has_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
424{
425 return get_member_decoration_bitset(id, index).get(decoration);
426}
427
428uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
429{
430 auto &m = meta[id];
431 if (index >= m.members.size())
432 return 0;
433
434 auto &dec = m.members[index];
435 if (!dec.decoration_flags.get(decoration))
436 return 0;
437
438 switch (decoration)
439 {
440 case DecorationBuiltIn:
441 return dec.builtin_type;
442 case DecorationLocation:
443 return dec.location;
444 case DecorationComponent:
445 return dec.component;
446 case DecorationBinding:
447 return dec.binding;
448 case DecorationOffset:
449 return dec.offset;
450 case DecorationSpecId:
451 return dec.spec_id;
452 case DecorationIndex:
453 return dec.index;
454 default:
455 return 1;
456 }
457}
458
459const Bitset &ParsedIR::get_decoration_bitset(uint32_t id) const
460{
461 auto &dec = meta[id].decoration;
462 return dec.decoration_flags;
463}
464
465void ParsedIR::set_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration, const string &argument)
466{
467 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
468 auto &dec = meta[id].members[index];
469 dec.decoration_flags.set(decoration);
470
471 switch (decoration)
472 {
473 case DecorationHlslSemanticGOOGLE:
474 dec.hlsl_semantic = argument;
475 break;
476
477 default:
478 break;
479 }
480}
481
482const string &ParsedIR::get_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration) const
483{
484 static const string empty;
485 auto &m = meta[id];
486
487 if (!has_member_decoration(id, index, decoration))
488 return empty;
489
490 auto &dec = m.members[index];
491
492 switch (decoration)
493 {
494 case DecorationHlslSemanticGOOGLE:
495 return dec.hlsl_semantic;
496
497 default:
498 return empty;
499 }
500}
501
502void ParsedIR::unset_member_decoration(uint32_t id, uint32_t index, Decoration decoration)
503{
504 auto &m = meta[id];
505 if (index >= m.members.size())
506 return;
507
508 auto &dec = m.members[index];
509
510 dec.decoration_flags.clear(decoration);
511 switch (decoration)
512 {
513 case DecorationBuiltIn:
514 dec.builtin = false;
515 break;
516
517 case DecorationLocation:
518 dec.location = 0;
519 break;
520
521 case DecorationComponent:
522 dec.component = 0;
523 break;
524
525 case DecorationOffset:
526 dec.offset = 0;
527 break;
528
529 case DecorationSpecId:
530 dec.spec_id = 0;
531 break;
532
533 case DecorationHlslSemanticGOOGLE:
534 dec.hlsl_semantic.clear();
535 break;
536
537 default:
538 break;
539 }
540}
541
542uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
543{
544 auto curr_bound = ids.size();
545 auto new_bound = curr_bound + incr_amount;
546 ids.resize(new_bound);
547 meta.resize(new_bound);
548 block_meta.resize(new_bound);
549 return uint32_t(curr_bound);
550}
551
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +0100552} // namespace spirv_cross