blob: 102c74957d618fe0a0a89629ef5db6b4887647ee [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
187 default:
188 break;
189 }
190}
191
192void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument)
193{
194 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
195 auto &dec = meta[id].members[index];
196 dec.decoration_flags.set(decoration);
197
198 switch (decoration)
199 {
200 case DecorationBuiltIn:
201 dec.builtin = true;
202 dec.builtin_type = static_cast<BuiltIn>(argument);
203 break;
204
205 case DecorationLocation:
206 dec.location = argument;
207 break;
208
209 case DecorationComponent:
210 dec.component = argument;
211 break;
212
213 case DecorationBinding:
214 dec.binding = argument;
215 break;
216
217 case DecorationOffset:
218 dec.offset = argument;
219 break;
220
221 case DecorationSpecId:
222 dec.spec_id = argument;
223 break;
224
225 case DecorationMatrixStride:
226 dec.matrix_stride = argument;
227 break;
228
229 case DecorationIndex:
230 dec.index = argument;
231 break;
232
233 default:
234 break;
235 }
236}
237
238// Recursively marks any constants referenced by the specified constant instruction as being used
239// as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
240void ParsedIR::mark_used_as_array_length(uint32_t id)
241{
242 switch (ids[id].get_type())
243 {
244 case TypeConstant:
245 get<SPIRConstant>(id).is_used_as_array_length = true;
246 break;
247
248 case TypeConstantOp:
249 {
250 auto &cop = get<SPIRConstantOp>(id);
251 for (uint32_t arg_id : cop.arguments)
252 mark_used_as_array_length(arg_id);
253 break;
254 }
255
256 case TypeUndef:
257 break;
258
259 default:
260 assert(0);
261 }
262}
263
264Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
265{
266 auto &type = get<SPIRType>(var.basetype);
267 assert(type.basetype == SPIRType::Struct);
268
269 // Some flags like non-writable, non-readable are actually found
270 // as member decorations. If all members have a decoration set, propagate
271 // the decoration up as a regular variable decoration.
272 Bitset base_flags = meta[var.self].decoration.decoration_flags;
273
274 if (type.member_types.empty())
275 return base_flags;
276
277 Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
278 for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
279 all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
280
281 base_flags.merge_or(all_members_flags);
282 return base_flags;
283}
284
285const Bitset &ParsedIR::get_member_decoration_bitset(uint32_t id, uint32_t index) const
286{
287 auto &m = meta[id];
288 if (index >= m.members.size())
289 {
290 static const Bitset cleared = {};
291 return cleared;
292 }
293
294 return m.members[index].decoration_flags;
295}
296
297bool ParsedIR::has_decoration(uint32_t id, Decoration decoration) const
298{
299 return get_decoration_bitset(id).get(decoration);
300}
301
302uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const
303{
304 auto &dec = meta[id].decoration;
305 if (!dec.decoration_flags.get(decoration))
306 return 0;
307
308 switch (decoration)
309 {
310 case DecorationBuiltIn:
311 return dec.builtin_type;
312 case DecorationLocation:
313 return dec.location;
314 case DecorationComponent:
315 return dec.component;
316 case DecorationOffset:
317 return dec.offset;
318 case DecorationBinding:
319 return dec.binding;
320 case DecorationDescriptorSet:
321 return dec.set;
322 case DecorationInputAttachmentIndex:
323 return dec.input_attachment;
324 case DecorationSpecId:
325 return dec.spec_id;
326 case DecorationArrayStride:
327 return dec.array_stride;
328 case DecorationMatrixStride:
329 return dec.matrix_stride;
330 case DecorationIndex:
331 return dec.index;
332 default:
333 return 1;
334 }
335}
336
337const string &ParsedIR::get_decoration_string(uint32_t id, Decoration decoration) const
338{
339 auto &dec = meta[id].decoration;
340 static const string empty;
341
342 if (!dec.decoration_flags.get(decoration))
343 return empty;
344
345 switch (decoration)
346 {
347 case DecorationHlslSemanticGOOGLE:
348 return dec.hlsl_semantic;
349
350 default:
351 return empty;
352 }
353}
354
355void ParsedIR::unset_decoration(uint32_t id, Decoration decoration)
356{
357 auto &dec = meta[id].decoration;
358 dec.decoration_flags.clear(decoration);
359 switch (decoration)
360 {
361 case DecorationBuiltIn:
362 dec.builtin = false;
363 break;
364
365 case DecorationLocation:
366 dec.location = 0;
367 break;
368
369 case DecorationComponent:
370 dec.component = 0;
371 break;
372
373 case DecorationOffset:
374 dec.offset = 0;
375 break;
376
377 case DecorationBinding:
378 dec.binding = 0;
379 break;
380
381 case DecorationDescriptorSet:
382 dec.set = 0;
383 break;
384
385 case DecorationInputAttachmentIndex:
386 dec.input_attachment = 0;
387 break;
388
389 case DecorationSpecId:
390 dec.spec_id = 0;
391 break;
392
393 case DecorationHlslSemanticGOOGLE:
394 dec.hlsl_semantic.clear();
395 break;
396
397 case DecorationHlslCounterBufferGOOGLE:
398 {
399 auto &counter = meta[id].hlsl_magic_counter_buffer;
400 if (counter)
401 {
402 meta[counter].hlsl_is_magic_counter_buffer = false;
403 counter = 0;
404 }
405 break;
406 }
407
408 default:
409 break;
410 }
411}
412
413bool ParsedIR::has_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
414{
415 return get_member_decoration_bitset(id, index).get(decoration);
416}
417
418uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const
419{
420 auto &m = meta[id];
421 if (index >= m.members.size())
422 return 0;
423
424 auto &dec = m.members[index];
425 if (!dec.decoration_flags.get(decoration))
426 return 0;
427
428 switch (decoration)
429 {
430 case DecorationBuiltIn:
431 return dec.builtin_type;
432 case DecorationLocation:
433 return dec.location;
434 case DecorationComponent:
435 return dec.component;
436 case DecorationBinding:
437 return dec.binding;
438 case DecorationOffset:
439 return dec.offset;
440 case DecorationSpecId:
441 return dec.spec_id;
442 case DecorationIndex:
443 return dec.index;
444 default:
445 return 1;
446 }
447}
448
449const Bitset &ParsedIR::get_decoration_bitset(uint32_t id) const
450{
451 auto &dec = meta[id].decoration;
452 return dec.decoration_flags;
453}
454
455void ParsedIR::set_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration, const string &argument)
456{
457 meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
458 auto &dec = meta[id].members[index];
459 dec.decoration_flags.set(decoration);
460
461 switch (decoration)
462 {
463 case DecorationHlslSemanticGOOGLE:
464 dec.hlsl_semantic = argument;
465 break;
466
467 default:
468 break;
469 }
470}
471
472const string &ParsedIR::get_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration) const
473{
474 static const string empty;
475 auto &m = meta[id];
476
477 if (!has_member_decoration(id, index, decoration))
478 return empty;
479
480 auto &dec = m.members[index];
481
482 switch (decoration)
483 {
484 case DecorationHlslSemanticGOOGLE:
485 return dec.hlsl_semantic;
486
487 default:
488 return empty;
489 }
490}
491
492void ParsedIR::unset_member_decoration(uint32_t id, uint32_t index, Decoration decoration)
493{
494 auto &m = meta[id];
495 if (index >= m.members.size())
496 return;
497
498 auto &dec = m.members[index];
499
500 dec.decoration_flags.clear(decoration);
501 switch (decoration)
502 {
503 case DecorationBuiltIn:
504 dec.builtin = false;
505 break;
506
507 case DecorationLocation:
508 dec.location = 0;
509 break;
510
511 case DecorationComponent:
512 dec.component = 0;
513 break;
514
515 case DecorationOffset:
516 dec.offset = 0;
517 break;
518
519 case DecorationSpecId:
520 dec.spec_id = 0;
521 break;
522
523 case DecorationHlslSemanticGOOGLE:
524 dec.hlsl_semantic.clear();
525 break;
526
527 default:
528 break;
529 }
530}
531
532uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
533{
534 auto curr_bound = ids.size();
535 auto new_bound = curr_bound + incr_amount;
536 ids.resize(new_bound);
537 meta.resize(new_bound);
538 block_meta.resize(new_bound);
539 return uint32_t(curr_bound);
540}
541
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +0100542} // namespace spirv_cross