tgsi/scan: scan address operands (v2)
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_scan.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 * Copyright 2008 VMware, Inc. All rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 /**
30 * TGSI program scan utility.
31 * Used to determine which registers and instructions are used by a shader.
32 *
33 * Authors: Brian Paul
34 */
35
36
37 #include "util/u_debug.h"
38 #include "util/u_math.h"
39 #include "util/u_memory.h"
40 #include "util/u_prim.h"
41 #include "tgsi/tgsi_info.h"
42 #include "tgsi/tgsi_parse.h"
43 #include "tgsi/tgsi_util.h"
44 #include "tgsi/tgsi_scan.h"
45
46
47 static bool
48 is_memory_file(unsigned file)
49 {
50 return file == TGSI_FILE_SAMPLER ||
51 file == TGSI_FILE_SAMPLER_VIEW ||
52 file == TGSI_FILE_IMAGE ||
53 file == TGSI_FILE_BUFFER;
54 }
55
56
57 static bool
58 is_mem_query_inst(unsigned opcode)
59 {
60 return opcode == TGSI_OPCODE_RESQ ||
61 opcode == TGSI_OPCODE_TXQ ||
62 opcode == TGSI_OPCODE_TXQS ||
63 opcode == TGSI_OPCODE_LODQ;
64 }
65
66 /**
67 * Is the opcode a "true" texture instruction which samples from a
68 * texture map?
69 */
70 static bool
71 is_texture_inst(unsigned opcode)
72 {
73 return (!is_mem_query_inst(opcode) &&
74 tgsi_get_opcode_info(opcode)->is_tex);
75 }
76
77
78 /**
79 * Is the opcode an instruction which computes a derivative explicitly or
80 * implicitly?
81 */
82 static bool
83 computes_derivative(unsigned opcode)
84 {
85 if (tgsi_get_opcode_info(opcode)->is_tex) {
86 return opcode != TGSI_OPCODE_TG4 &&
87 opcode != TGSI_OPCODE_TXD &&
88 opcode != TGSI_OPCODE_TXF &&
89 opcode != TGSI_OPCODE_TXF_LZ &&
90 opcode != TGSI_OPCODE_TEX_LZ &&
91 opcode != TGSI_OPCODE_TXL &&
92 opcode != TGSI_OPCODE_TXL2 &&
93 opcode != TGSI_OPCODE_TXQ &&
94 opcode != TGSI_OPCODE_TXQS;
95 }
96
97 return opcode == TGSI_OPCODE_DDX || opcode == TGSI_OPCODE_DDX_FINE ||
98 opcode == TGSI_OPCODE_DDY || opcode == TGSI_OPCODE_DDY_FINE ||
99 opcode == TGSI_OPCODE_SAMPLE ||
100 opcode == TGSI_OPCODE_SAMPLE_B ||
101 opcode == TGSI_OPCODE_SAMPLE_C;
102 }
103
104
105 static void
106 scan_src_operand(struct tgsi_shader_info *info,
107 const struct tgsi_full_instruction *fullinst,
108 const struct tgsi_full_src_register *src,
109 unsigned src_index,
110 unsigned usage_mask_after_swizzle,
111 bool is_interp_instruction,
112 bool *is_mem_inst)
113 {
114 int ind = src->Register.Index;
115
116 if (info->processor == PIPE_SHADER_COMPUTE &&
117 src->Register.File == TGSI_FILE_SYSTEM_VALUE) {
118 unsigned name, mask;
119
120 name = info->system_value_semantic_name[src->Register.Index];
121
122 switch (name) {
123 case TGSI_SEMANTIC_THREAD_ID:
124 case TGSI_SEMANTIC_BLOCK_ID:
125 mask = usage_mask_after_swizzle & TGSI_WRITEMASK_XYZ;
126 while (mask) {
127 unsigned i = u_bit_scan(&mask);
128
129 if (name == TGSI_SEMANTIC_THREAD_ID)
130 info->uses_thread_id[i] = true;
131 else
132 info->uses_block_id[i] = true;
133 }
134 break;
135 case TGSI_SEMANTIC_BLOCK_SIZE:
136 /* The block size is translated to IMM with a fixed block size. */
137 if (info->properties[TGSI_PROPERTY_CS_FIXED_BLOCK_WIDTH] == 0)
138 info->uses_block_size = true;
139 break;
140 case TGSI_SEMANTIC_GRID_SIZE:
141 info->uses_grid_size = true;
142 break;
143 }
144 }
145
146 /* Mark which inputs are effectively used */
147 if (src->Register.File == TGSI_FILE_INPUT) {
148 if (src->Register.Indirect) {
149 for (ind = 0; ind < info->num_inputs; ++ind) {
150 info->input_usage_mask[ind] |= usage_mask_after_swizzle;
151 }
152 } else {
153 assert(ind >= 0);
154 assert(ind < PIPE_MAX_SHADER_INPUTS);
155 info->input_usage_mask[ind] |= usage_mask_after_swizzle;
156 }
157
158 if (info->processor == PIPE_SHADER_FRAGMENT) {
159 unsigned name, index, input;
160
161 if (src->Register.Indirect && src->Indirect.ArrayID)
162 input = info->input_array_first[src->Indirect.ArrayID];
163 else
164 input = src->Register.Index;
165
166 name = info->input_semantic_name[input];
167 index = info->input_semantic_index[input];
168
169 if (name == TGSI_SEMANTIC_POSITION &&
170 usage_mask_after_swizzle & TGSI_WRITEMASK_Z)
171 info->reads_z = true;
172
173 if (name == TGSI_SEMANTIC_COLOR)
174 info->colors_read |= usage_mask_after_swizzle << (index * 4);
175
176 /* Process only interpolated varyings. Don't include POSITION.
177 * Don't include integer varyings, because they are not
178 * interpolated. Don't process inputs interpolated by INTERP
179 * opcodes. Those are tracked separately.
180 */
181 if ((!is_interp_instruction || src_index != 0) &&
182 (name == TGSI_SEMANTIC_GENERIC ||
183 name == TGSI_SEMANTIC_TEXCOORD ||
184 name == TGSI_SEMANTIC_COLOR ||
185 name == TGSI_SEMANTIC_BCOLOR ||
186 name == TGSI_SEMANTIC_FOG ||
187 name == TGSI_SEMANTIC_CLIPDIST)) {
188 switch (info->input_interpolate[input]) {
189 case TGSI_INTERPOLATE_COLOR:
190 case TGSI_INTERPOLATE_PERSPECTIVE:
191 switch (info->input_interpolate_loc[input]) {
192 case TGSI_INTERPOLATE_LOC_CENTER:
193 info->uses_persp_center = TRUE;
194 break;
195 case TGSI_INTERPOLATE_LOC_CENTROID:
196 info->uses_persp_centroid = TRUE;
197 break;
198 case TGSI_INTERPOLATE_LOC_SAMPLE:
199 info->uses_persp_sample = TRUE;
200 break;
201 }
202 break;
203 case TGSI_INTERPOLATE_LINEAR:
204 switch (info->input_interpolate_loc[input]) {
205 case TGSI_INTERPOLATE_LOC_CENTER:
206 info->uses_linear_center = TRUE;
207 break;
208 case TGSI_INTERPOLATE_LOC_CENTROID:
209 info->uses_linear_centroid = TRUE;
210 break;
211 case TGSI_INTERPOLATE_LOC_SAMPLE:
212 info->uses_linear_sample = TRUE;
213 break;
214 }
215 break;
216 /* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */
217 }
218 }
219 }
220 }
221
222 if (info->processor == PIPE_SHADER_TESS_CTRL &&
223 src->Register.File == TGSI_FILE_OUTPUT) {
224 unsigned input;
225
226 if (src->Register.Indirect && src->Indirect.ArrayID)
227 input = info->output_array_first[src->Indirect.ArrayID];
228 else
229 input = src->Register.Index;
230
231 switch (info->output_semantic_name[input]) {
232 case TGSI_SEMANTIC_PATCH:
233 info->reads_perpatch_outputs = true;
234 break;
235 case TGSI_SEMANTIC_TESSINNER:
236 case TGSI_SEMANTIC_TESSOUTER:
237 info->reads_tessfactor_outputs = true;
238 break;
239 default:
240 info->reads_pervertex_outputs = true;
241 }
242 }
243
244 /* check for indirect register reads */
245 if (src->Register.Indirect) {
246 info->indirect_files |= (1 << src->Register.File);
247 info->indirect_files_read |= (1 << src->Register.File);
248
249 /* record indirect constant buffer indexing */
250 if (src->Register.File == TGSI_FILE_CONSTANT) {
251 if (src->Register.Dimension) {
252 if (src->Dimension.Indirect)
253 info->const_buffers_indirect = info->const_buffers_declared;
254 else
255 info->const_buffers_indirect |= 1u << src->Dimension.Index;
256 } else {
257 info->const_buffers_indirect |= 1;
258 }
259 }
260 }
261
262 if (src->Register.Dimension && src->Dimension.Indirect)
263 info->dim_indirect_files |= 1u << src->Register.File;
264
265 /* Texture samplers */
266 if (src->Register.File == TGSI_FILE_SAMPLER) {
267 const unsigned index = src->Register.Index;
268
269 assert(fullinst->Instruction.Texture);
270 assert(index < ARRAY_SIZE(info->is_msaa_sampler));
271 assert(index < PIPE_MAX_SAMPLERS);
272
273 if (is_texture_inst(fullinst->Instruction.Opcode)) {
274 const unsigned target = fullinst->Texture.Texture;
275 assert(target < TGSI_TEXTURE_UNKNOWN);
276 /* for texture instructions, check that the texture instruction
277 * target matches the previous sampler view declaration (if there
278 * was one.)
279 */
280 if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) {
281 /* probably no sampler view declaration */
282 info->sampler_targets[index] = target;
283 } else {
284 /* Make sure the texture instruction's sampler/target info
285 * agrees with the sampler view declaration.
286 */
287 assert(info->sampler_targets[index] == target);
288 }
289 /* MSAA samplers */
290 if (target == TGSI_TEXTURE_2D_MSAA ||
291 target == TGSI_TEXTURE_2D_ARRAY_MSAA) {
292 info->is_msaa_sampler[src->Register.Index] = TRUE;
293 }
294 }
295 }
296
297 if (is_memory_file(src->Register.File) &&
298 !is_mem_query_inst(fullinst->Instruction.Opcode)) {
299 *is_mem_inst = true;
300
301 if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) {
302 info->writes_memory = TRUE;
303
304 if (src->Register.File == TGSI_FILE_IMAGE) {
305 if (src->Register.Indirect)
306 info->images_atomic = info->images_declared;
307 else
308 info->images_atomic |= 1 << src->Register.Index;
309 } else if (src->Register.File == TGSI_FILE_BUFFER) {
310 if (src->Register.Indirect)
311 info->shader_buffers_atomic = info->shader_buffers_declared;
312 else
313 info->shader_buffers_atomic |= 1 << src->Register.Index;
314 }
315 } else {
316 if (src->Register.File == TGSI_FILE_IMAGE) {
317 if (src->Register.Indirect)
318 info->images_load = info->images_declared;
319 else
320 info->images_load |= 1 << src->Register.Index;
321 } else if (src->Register.File == TGSI_FILE_BUFFER) {
322 if (src->Register.Indirect)
323 info->shader_buffers_load = info->shader_buffers_declared;
324 else
325 info->shader_buffers_load |= 1 << src->Register.Index;
326 }
327 }
328 }
329 }
330
331
332 static void
333 scan_instruction(struct tgsi_shader_info *info,
334 const struct tgsi_full_instruction *fullinst,
335 unsigned *current_depth)
336 {
337 unsigned i;
338 bool is_mem_inst = false;
339 bool is_interp_instruction = false;
340 unsigned sampler_src;
341
342 assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
343 info->opcode_count[fullinst->Instruction.Opcode]++;
344
345 switch (fullinst->Instruction.Opcode) {
346 case TGSI_OPCODE_IF:
347 case TGSI_OPCODE_UIF:
348 case TGSI_OPCODE_BGNLOOP:
349 (*current_depth)++;
350 info->max_depth = MAX2(info->max_depth, *current_depth);
351 break;
352 case TGSI_OPCODE_ENDIF:
353 case TGSI_OPCODE_ENDLOOP:
354 (*current_depth)--;
355 break;
356 case TGSI_OPCODE_TEX:
357 case TGSI_OPCODE_TEX_LZ:
358 case TGSI_OPCODE_TXB:
359 case TGSI_OPCODE_TXD:
360 case TGSI_OPCODE_TXL:
361 case TGSI_OPCODE_TXP:
362 case TGSI_OPCODE_TXQ:
363 case TGSI_OPCODE_TXQS:
364 case TGSI_OPCODE_TXF:
365 case TGSI_OPCODE_TXF_LZ:
366 case TGSI_OPCODE_TEX2:
367 case TGSI_OPCODE_TXB2:
368 case TGSI_OPCODE_TXL2:
369 case TGSI_OPCODE_TG4:
370 case TGSI_OPCODE_LODQ:
371 sampler_src = fullinst->Instruction.NumSrcRegs - 1;
372 if (fullinst->Src[sampler_src].Register.File != TGSI_FILE_SAMPLER)
373 info->uses_bindless_samplers = true;
374 break;
375 case TGSI_OPCODE_RESQ:
376 case TGSI_OPCODE_LOAD:
377 case TGSI_OPCODE_ATOMUADD:
378 case TGSI_OPCODE_ATOMXCHG:
379 case TGSI_OPCODE_ATOMCAS:
380 case TGSI_OPCODE_ATOMAND:
381 case TGSI_OPCODE_ATOMOR:
382 case TGSI_OPCODE_ATOMXOR:
383 case TGSI_OPCODE_ATOMUMIN:
384 case TGSI_OPCODE_ATOMUMAX:
385 case TGSI_OPCODE_ATOMIMIN:
386 case TGSI_OPCODE_ATOMIMAX:
387 if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File))
388 info->uses_bindless_images = true;
389 break;
390 case TGSI_OPCODE_STORE:
391 if (tgsi_is_bindless_image_file(fullinst->Dst[0].Register.File))
392 info->uses_bindless_images = true;
393 break;
394 default:
395 break;
396 }
397
398 if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID ||
399 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
400 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
401 const struct tgsi_full_src_register *src0 = &fullinst->Src[0];
402 unsigned input;
403
404 is_interp_instruction = true;
405
406 if (src0->Register.Indirect && src0->Indirect.ArrayID)
407 input = info->input_array_first[src0->Indirect.ArrayID];
408 else
409 input = src0->Register.Index;
410
411 /* For the INTERP opcodes, the interpolation is always
412 * PERSPECTIVE unless LINEAR is specified.
413 */
414 switch (info->input_interpolate[input]) {
415 case TGSI_INTERPOLATE_COLOR:
416 case TGSI_INTERPOLATE_CONSTANT:
417 case TGSI_INTERPOLATE_PERSPECTIVE:
418 switch (fullinst->Instruction.Opcode) {
419 case TGSI_OPCODE_INTERP_CENTROID:
420 info->uses_persp_opcode_interp_centroid = TRUE;
421 break;
422 case TGSI_OPCODE_INTERP_OFFSET:
423 info->uses_persp_opcode_interp_offset = TRUE;
424 break;
425 case TGSI_OPCODE_INTERP_SAMPLE:
426 info->uses_persp_opcode_interp_sample = TRUE;
427 break;
428 }
429 break;
430
431 case TGSI_INTERPOLATE_LINEAR:
432 switch (fullinst->Instruction.Opcode) {
433 case TGSI_OPCODE_INTERP_CENTROID:
434 info->uses_linear_opcode_interp_centroid = TRUE;
435 break;
436 case TGSI_OPCODE_INTERP_OFFSET:
437 info->uses_linear_opcode_interp_offset = TRUE;
438 break;
439 case TGSI_OPCODE_INTERP_SAMPLE:
440 info->uses_linear_opcode_interp_sample = TRUE;
441 break;
442 }
443 break;
444 }
445 }
446
447 if ((fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D &&
448 fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) ||
449 fullinst->Instruction.Opcode == TGSI_OPCODE_DFMA ||
450 fullinst->Instruction.Opcode == TGSI_OPCODE_DDIV ||
451 fullinst->Instruction.Opcode == TGSI_OPCODE_D2U64 ||
452 fullinst->Instruction.Opcode == TGSI_OPCODE_D2I64 ||
453 fullinst->Instruction.Opcode == TGSI_OPCODE_U642D ||
454 fullinst->Instruction.Opcode == TGSI_OPCODE_I642D)
455 info->uses_doubles = TRUE;
456
457 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
458 scan_src_operand(info, fullinst, &fullinst->Src[i], i,
459 tgsi_util_get_inst_usage_mask(fullinst, i),
460 is_interp_instruction, &is_mem_inst);
461
462 if (fullinst->Src[i].Register.Indirect) {
463 struct tgsi_full_src_register src = {{0}};
464
465 src.Register.File = fullinst->Src[i].Indirect.File;
466 src.Register.Index = fullinst->Src[i].Indirect.Index;
467
468 scan_src_operand(info, fullinst, &src, -1,
469 1 << fullinst->Src[i].Indirect.Swizzle,
470 false, NULL);
471 }
472
473 if (fullinst->Src[i].Register.Dimension &&
474 fullinst->Src[i].Dimension.Indirect) {
475 struct tgsi_full_src_register src = {{0}};
476
477 src.Register.File = fullinst->Src[i].DimIndirect.File;
478 src.Register.Index = fullinst->Src[i].DimIndirect.Index;
479
480 scan_src_operand(info, fullinst, &src, -1,
481 1 << fullinst->Src[i].DimIndirect.Swizzle,
482 false, NULL);
483 }
484 }
485
486 if (fullinst->Instruction.Texture) {
487 for (i = 0; i < fullinst->Texture.NumOffsets; i++) {
488 struct tgsi_full_src_register src = {{0}};
489
490 src.Register.File = fullinst->TexOffsets[i].File;
491 src.Register.Index = fullinst->TexOffsets[i].Index;
492
493 /* The usage mask is suboptimal but should be safe. */
494 scan_src_operand(info, fullinst, &src, -1,
495 (1 << fullinst->TexOffsets[i].SwizzleX) |
496 (1 << fullinst->TexOffsets[i].SwizzleY) |
497 (1 << fullinst->TexOffsets[i].SwizzleZ),
498 false, &is_mem_inst);
499 }
500 }
501
502 /* check for indirect register writes */
503 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
504 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
505
506 if (dst->Register.Indirect) {
507 struct tgsi_full_src_register src = {{0}};
508
509 src.Register.File = dst->Indirect.File;
510 src.Register.Index = dst->Indirect.Index;
511
512 scan_src_operand(info, fullinst, &src, -1,
513 1 << dst->Indirect.Swizzle, false, NULL);
514
515 info->indirect_files |= (1 << dst->Register.File);
516 info->indirect_files_written |= (1 << dst->Register.File);
517 }
518
519 if (dst->Register.Dimension && dst->Dimension.Indirect) {
520 struct tgsi_full_src_register src = {{0}};
521
522 src.Register.File = dst->DimIndirect.File;
523 src.Register.Index = dst->DimIndirect.Index;
524
525 scan_src_operand(info, fullinst, &src, -1,
526 1 << dst->DimIndirect.Swizzle, false, NULL);
527
528 info->dim_indirect_files |= 1u << dst->Register.File;
529 }
530
531 if (is_memory_file(dst->Register.File)) {
532 assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE);
533
534 is_mem_inst = true;
535 info->writes_memory = TRUE;
536
537 if (dst->Register.File == TGSI_FILE_IMAGE) {
538 if (dst->Register.Indirect)
539 info->images_store = info->images_declared;
540 else
541 info->images_store |= 1 << dst->Register.Index;
542 } else if (dst->Register.File == TGSI_FILE_BUFFER) {
543 if (dst->Register.Indirect)
544 info->shader_buffers_store = info->shader_buffers_declared;
545 else
546 info->shader_buffers_store |= 1 << dst->Register.Index;
547 }
548 }
549 }
550
551 if (is_mem_inst)
552 info->num_memory_instructions++;
553
554 if (computes_derivative(fullinst->Instruction.Opcode))
555 info->uses_derivatives = true;
556
557 info->num_instructions++;
558 }
559
560
561 static void
562 scan_declaration(struct tgsi_shader_info *info,
563 const struct tgsi_full_declaration *fulldecl)
564 {
565 const uint file = fulldecl->Declaration.File;
566 const unsigned procType = info->processor;
567 uint reg;
568
569 if (fulldecl->Declaration.Array) {
570 unsigned array_id = fulldecl->Array.ArrayID;
571
572 switch (file) {
573 case TGSI_FILE_INPUT:
574 assert(array_id < ARRAY_SIZE(info->input_array_first));
575 info->input_array_first[array_id] = fulldecl->Range.First;
576 info->input_array_last[array_id] = fulldecl->Range.Last;
577 break;
578 case TGSI_FILE_OUTPUT:
579 assert(array_id < ARRAY_SIZE(info->output_array_first));
580 info->output_array_first[array_id] = fulldecl->Range.First;
581 info->output_array_last[array_id] = fulldecl->Range.Last;
582 break;
583 }
584 info->array_max[file] = MAX2(info->array_max[file], array_id);
585 }
586
587 for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) {
588 unsigned semName = fulldecl->Semantic.Name;
589 unsigned semIndex = fulldecl->Semantic.Index +
590 (reg - fulldecl->Range.First);
591 int buffer;
592 unsigned index, target, type;
593
594 /* only first 32 regs will appear in this bitfield */
595 info->file_mask[file] |= (1 << reg);
596 info->file_count[file]++;
597 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
598
599 switch (file) {
600 case TGSI_FILE_CONSTANT:
601 buffer = 0;
602
603 if (fulldecl->Declaration.Dimension)
604 buffer = fulldecl->Dim.Index2D;
605
606 info->const_file_max[buffer] =
607 MAX2(info->const_file_max[buffer], (int)reg);
608 info->const_buffers_declared |= 1u << buffer;
609 break;
610
611 case TGSI_FILE_IMAGE:
612 info->images_declared |= 1u << reg;
613 if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER)
614 info->images_buffers |= 1 << reg;
615 break;
616
617 case TGSI_FILE_BUFFER:
618 info->shader_buffers_declared |= 1u << reg;
619 break;
620
621 case TGSI_FILE_INPUT:
622 info->input_semantic_name[reg] = (ubyte) semName;
623 info->input_semantic_index[reg] = (ubyte) semIndex;
624 info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
625 info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;
626 info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
627
628 /* Vertex shaders can have inputs with holes between them. */
629 info->num_inputs = MAX2(info->num_inputs, reg + 1);
630
631 switch (semName) {
632 case TGSI_SEMANTIC_PRIMID:
633 info->uses_primid = true;
634 break;
635 case TGSI_SEMANTIC_POSITION:
636 info->reads_position = true;
637 break;
638 case TGSI_SEMANTIC_FACE:
639 info->uses_frontface = true;
640 break;
641 }
642 break;
643
644 case TGSI_FILE_SYSTEM_VALUE:
645 index = fulldecl->Range.First;
646
647 info->system_value_semantic_name[index] = semName;
648 info->num_system_values = MAX2(info->num_system_values, index + 1);
649
650 switch (semName) {
651 case TGSI_SEMANTIC_INSTANCEID:
652 info->uses_instanceid = TRUE;
653 break;
654 case TGSI_SEMANTIC_VERTEXID:
655 info->uses_vertexid = TRUE;
656 break;
657 case TGSI_SEMANTIC_VERTEXID_NOBASE:
658 info->uses_vertexid_nobase = TRUE;
659 break;
660 case TGSI_SEMANTIC_BASEVERTEX:
661 info->uses_basevertex = TRUE;
662 break;
663 case TGSI_SEMANTIC_PRIMID:
664 info->uses_primid = TRUE;
665 break;
666 case TGSI_SEMANTIC_INVOCATIONID:
667 info->uses_invocationid = TRUE;
668 break;
669 case TGSI_SEMANTIC_POSITION:
670 info->reads_position = TRUE;
671 break;
672 case TGSI_SEMANTIC_FACE:
673 info->uses_frontface = TRUE;
674 break;
675 case TGSI_SEMANTIC_SAMPLEMASK:
676 info->reads_samplemask = TRUE;
677 break;
678 case TGSI_SEMANTIC_TESSINNER:
679 case TGSI_SEMANTIC_TESSOUTER:
680 info->reads_tess_factors = true;
681 break;
682 }
683 break;
684
685 case TGSI_FILE_OUTPUT:
686 info->output_semantic_name[reg] = (ubyte) semName;
687 info->output_semantic_index[reg] = (ubyte) semIndex;
688 info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask;
689 info->num_outputs = MAX2(info->num_outputs, reg + 1);
690
691 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) {
692 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamX;
693 info->num_stream_output_components[fulldecl->Semantic.StreamX]++;
694 }
695 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) {
696 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamY << 2;
697 info->num_stream_output_components[fulldecl->Semantic.StreamY]++;
698 }
699 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) {
700 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamZ << 4;
701 info->num_stream_output_components[fulldecl->Semantic.StreamZ]++;
702 }
703 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) {
704 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamW << 6;
705 info->num_stream_output_components[fulldecl->Semantic.StreamW]++;
706 }
707
708 switch (semName) {
709 case TGSI_SEMANTIC_PRIMID:
710 info->writes_primid = true;
711 break;
712 case TGSI_SEMANTIC_VIEWPORT_INDEX:
713 info->writes_viewport_index = true;
714 break;
715 case TGSI_SEMANTIC_LAYER:
716 info->writes_layer = true;
717 break;
718 case TGSI_SEMANTIC_PSIZE:
719 info->writes_psize = true;
720 break;
721 case TGSI_SEMANTIC_CLIPVERTEX:
722 info->writes_clipvertex = true;
723 break;
724 case TGSI_SEMANTIC_COLOR:
725 info->colors_written |= 1 << semIndex;
726 break;
727 case TGSI_SEMANTIC_STENCIL:
728 info->writes_stencil = true;
729 break;
730 case TGSI_SEMANTIC_SAMPLEMASK:
731 info->writes_samplemask = true;
732 break;
733 case TGSI_SEMANTIC_EDGEFLAG:
734 info->writes_edgeflag = true;
735 break;
736 case TGSI_SEMANTIC_POSITION:
737 if (procType == PIPE_SHADER_FRAGMENT)
738 info->writes_z = true;
739 else
740 info->writes_position = true;
741 break;
742 }
743 break;
744
745 case TGSI_FILE_SAMPLER:
746 STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS);
747 info->samplers_declared |= 1u << reg;
748 break;
749
750 case TGSI_FILE_SAMPLER_VIEW:
751 target = fulldecl->SamplerView.Resource;
752 type = fulldecl->SamplerView.ReturnTypeX;
753
754 assert(target < TGSI_TEXTURE_UNKNOWN);
755 if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) {
756 /* Save sampler target for this sampler index */
757 info->sampler_targets[reg] = target;
758 info->sampler_type[reg] = type;
759 } else {
760 /* if previously declared, make sure targets agree */
761 assert(info->sampler_targets[reg] == target);
762 assert(info->sampler_type[reg] == type);
763 }
764 break;
765 }
766 }
767 }
768
769
770 static void
771 scan_immediate(struct tgsi_shader_info *info)
772 {
773 uint reg = info->immediate_count++;
774 uint file = TGSI_FILE_IMMEDIATE;
775
776 info->file_mask[file] |= (1 << reg);
777 info->file_count[file]++;
778 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
779 }
780
781
782 static void
783 scan_property(struct tgsi_shader_info *info,
784 const struct tgsi_full_property *fullprop)
785 {
786 unsigned name = fullprop->Property.PropertyName;
787 unsigned value = fullprop->u[0].Data;
788
789 assert(name < ARRAY_SIZE(info->properties));
790 info->properties[name] = value;
791
792 switch (name) {
793 case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:
794 info->num_written_clipdistance = value;
795 info->clipdist_writemask |= (1 << value) - 1;
796 break;
797 case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:
798 info->num_written_culldistance = value;
799 info->culldist_writemask |= (1 << value) - 1;
800 break;
801 }
802 }
803
804
805 /**
806 * Scan the given TGSI shader to collect information such as number of
807 * registers used, special instructions used, etc.
808 * \return info the result of the scan
809 */
810 void
811 tgsi_scan_shader(const struct tgsi_token *tokens,
812 struct tgsi_shader_info *info)
813 {
814 uint procType, i;
815 struct tgsi_parse_context parse;
816 unsigned current_depth = 0;
817
818 memset(info, 0, sizeof(*info));
819 for (i = 0; i < TGSI_FILE_COUNT; i++)
820 info->file_max[i] = -1;
821 for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++)
822 info->const_file_max[i] = -1;
823 info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;
824 for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++)
825 info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN;
826
827 /**
828 ** Setup to begin parsing input shader
829 **/
830 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
831 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
832 return;
833 }
834 procType = parse.FullHeader.Processor.Processor;
835 assert(procType == PIPE_SHADER_FRAGMENT ||
836 procType == PIPE_SHADER_VERTEX ||
837 procType == PIPE_SHADER_GEOMETRY ||
838 procType == PIPE_SHADER_TESS_CTRL ||
839 procType == PIPE_SHADER_TESS_EVAL ||
840 procType == PIPE_SHADER_COMPUTE);
841 info->processor = procType;
842
843 /**
844 ** Loop over incoming program tokens/instructions
845 */
846 while (!tgsi_parse_end_of_tokens(&parse)) {
847 info->num_tokens++;
848
849 tgsi_parse_token( &parse );
850
851 switch( parse.FullToken.Token.Type ) {
852 case TGSI_TOKEN_TYPE_INSTRUCTION:
853 scan_instruction(info, &parse.FullToken.FullInstruction,
854 &current_depth);
855 break;
856 case TGSI_TOKEN_TYPE_DECLARATION:
857 scan_declaration(info, &parse.FullToken.FullDeclaration);
858 break;
859 case TGSI_TOKEN_TYPE_IMMEDIATE:
860 scan_immediate(info);
861 break;
862 case TGSI_TOKEN_TYPE_PROPERTY:
863 scan_property(info, &parse.FullToken.FullProperty);
864 break;
865 default:
866 assert(!"Unexpected TGSI token type");
867 }
868 }
869
870 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
871 info->opcode_count[TGSI_OPCODE_KILL]);
872
873 /* The dimensions of the IN decleration in geometry shader have
874 * to be deduced from the type of the input primitive.
875 */
876 if (procType == PIPE_SHADER_GEOMETRY) {
877 unsigned input_primitive =
878 info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
879 int num_verts = u_vertices_per_prim(input_primitive);
880 int j;
881 info->file_count[TGSI_FILE_INPUT] = num_verts;
882 info->file_max[TGSI_FILE_INPUT] =
883 MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
884 for (j = 0; j < num_verts; ++j) {
885 info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
886 }
887 }
888
889 tgsi_parse_free(&parse);
890 }
891
892 /**
893 * Collect information about the arrays of a given register file.
894 *
895 * @param tokens TGSI shader
896 * @param file the register file to scan through
897 * @param max_array_id number of entries in @p arrays; should be equal to the
898 * highest array id, i.e. tgsi_shader_info::array_max[file].
899 * @param arrays info for array of each ID will be written to arrays[ID - 1].
900 */
901 void
902 tgsi_scan_arrays(const struct tgsi_token *tokens,
903 unsigned file,
904 unsigned max_array_id,
905 struct tgsi_array_info *arrays)
906 {
907 struct tgsi_parse_context parse;
908
909 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
910 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
911 return;
912 }
913
914 memset(arrays, 0, sizeof(arrays[0]) * max_array_id);
915
916 while (!tgsi_parse_end_of_tokens(&parse)) {
917 struct tgsi_full_instruction *inst;
918
919 tgsi_parse_token(&parse);
920
921 if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) {
922 struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
923
924 if (decl->Declaration.Array && decl->Declaration.File == file &&
925 decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) {
926 struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1];
927 assert(!array->declared);
928 array->declared = true;
929 array->range = decl->Range;
930 }
931 }
932
933 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
934 continue;
935
936 inst = &parse.FullToken.FullInstruction;
937 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
938 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
939 if (dst->Register.File != file)
940 continue;
941
942 if (dst->Register.Indirect) {
943 if (dst->Indirect.ArrayID > 0 &&
944 dst->Indirect.ArrayID <= max_array_id) {
945 arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask;
946 } else {
947 /* Indirect writes without an ArrayID can write anywhere. */
948 for (unsigned j = 0; j < max_array_id; ++j)
949 arrays[j].writemask |= dst->Register.WriteMask;
950 }
951 } else {
952 /* Check whether the write falls into any of the arrays anyway. */
953 for (unsigned j = 0; j < max_array_id; ++j) {
954 struct tgsi_array_info *array = &arrays[j];
955 if (array->declared &&
956 dst->Register.Index >= array->range.First &&
957 dst->Register.Index <= array->range.Last)
958 array->writemask |= dst->Register.WriteMask;
959 }
960 }
961 }
962 }
963
964 tgsi_parse_free(&parse);
965
966 return;
967 }
968
969 static void
970 check_no_subroutines(const struct tgsi_full_instruction *inst)
971 {
972 switch (inst->Instruction.Opcode) {
973 case TGSI_OPCODE_BGNSUB:
974 case TGSI_OPCODE_ENDSUB:
975 case TGSI_OPCODE_CAL:
976 unreachable("subroutines unhandled");
977 }
978 }
979
980 static unsigned
981 get_inst_tessfactor_writemask(const struct tgsi_shader_info *info,
982 const struct tgsi_full_instruction *inst)
983 {
984 unsigned writemask = 0;
985
986 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
987 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
988
989 if (dst->Register.File == TGSI_FILE_OUTPUT &&
990 !dst->Register.Indirect) {
991 unsigned name = info->output_semantic_name[dst->Register.Index];
992
993 if (name == TGSI_SEMANTIC_TESSINNER)
994 writemask |= dst->Register.WriteMask;
995 else if (name == TGSI_SEMANTIC_TESSOUTER)
996 writemask |= dst->Register.WriteMask << 4;
997 }
998 }
999 return writemask;
1000 }
1001
1002 static unsigned
1003 get_block_tessfactor_writemask(const struct tgsi_shader_info *info,
1004 struct tgsi_parse_context *parse,
1005 unsigned end_opcode)
1006 {
1007 struct tgsi_full_instruction *inst;
1008 unsigned writemask = 0;
1009
1010 do {
1011 tgsi_parse_token(parse);
1012 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1013 inst = &parse->FullToken.FullInstruction;
1014 check_no_subroutines(inst);
1015
1016 /* Recursively process nested blocks. */
1017 switch (inst->Instruction.Opcode) {
1018 case TGSI_OPCODE_IF:
1019 case TGSI_OPCODE_UIF:
1020 writemask |=
1021 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF);
1022 continue;
1023
1024 case TGSI_OPCODE_BGNLOOP:
1025 writemask |=
1026 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
1027 continue;
1028
1029 case TGSI_OPCODE_BARRIER:
1030 unreachable("nested BARRIER is illegal");
1031 continue;
1032 }
1033
1034 writemask |= get_inst_tessfactor_writemask(info, inst);
1035 } while (inst->Instruction.Opcode != end_opcode);
1036
1037 return writemask;
1038 }
1039
1040 static void
1041 get_if_block_tessfactor_writemask(const struct tgsi_shader_info *info,
1042 struct tgsi_parse_context *parse,
1043 unsigned *upper_block_tf_writemask,
1044 unsigned *cond_block_tf_writemask)
1045 {
1046 struct tgsi_full_instruction *inst;
1047 unsigned then_tessfactor_writemask = 0;
1048 unsigned else_tessfactor_writemask = 0;
1049 bool is_then = true;
1050
1051 do {
1052 tgsi_parse_token(parse);
1053 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1054 inst = &parse->FullToken.FullInstruction;
1055 check_no_subroutines(inst);
1056
1057 switch (inst->Instruction.Opcode) {
1058 case TGSI_OPCODE_ELSE:
1059 is_then = false;
1060 continue;
1061
1062 /* Recursively process nested blocks. */
1063 case TGSI_OPCODE_IF:
1064 case TGSI_OPCODE_UIF:
1065 get_if_block_tessfactor_writemask(info, parse,
1066 is_then ? &then_tessfactor_writemask :
1067 &else_tessfactor_writemask,
1068 cond_block_tf_writemask);
1069 continue;
1070
1071 case TGSI_OPCODE_BGNLOOP:
1072 *cond_block_tf_writemask |=
1073 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
1074 continue;
1075
1076 case TGSI_OPCODE_BARRIER:
1077 unreachable("nested BARRIER is illegal");
1078 continue;
1079 }
1080
1081 /* Process an instruction in the current block. */
1082 unsigned writemask = get_inst_tessfactor_writemask(info, inst);
1083
1084 if (writemask) {
1085 if (is_then)
1086 then_tessfactor_writemask |= writemask;
1087 else
1088 else_tessfactor_writemask |= writemask;
1089 }
1090 } while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF);
1091
1092 if (then_tessfactor_writemask || else_tessfactor_writemask) {
1093 /* If both statements write the same tess factor channels,
1094 * we can say that the upper block writes them too. */
1095 *upper_block_tf_writemask |= then_tessfactor_writemask &
1096 else_tessfactor_writemask;
1097 *cond_block_tf_writemask |= then_tessfactor_writemask |
1098 else_tessfactor_writemask;
1099 }
1100 }
1101
1102 void
1103 tgsi_scan_tess_ctrl(const struct tgsi_token *tokens,
1104 const struct tgsi_shader_info *info,
1105 struct tgsi_tessctrl_info *out)
1106 {
1107 memset(out, 0, sizeof(*out));
1108
1109 if (info->processor != PIPE_SHADER_TESS_CTRL)
1110 return;
1111
1112 struct tgsi_parse_context parse;
1113 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
1114 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
1115 return;
1116 }
1117
1118 /* The pass works as follows:
1119 * If all codepaths write tess factors, we can say that all invocations
1120 * define tess factors.
1121 *
1122 * Each tess factor channel is tracked separately.
1123 */
1124 unsigned main_block_tf_writemask = 0; /* if main block writes tess factors */
1125 unsigned cond_block_tf_writemask = 0; /* if cond block writes tess factors */
1126
1127 /* Initial value = true. Here the pass will accumulate results from multiple
1128 * segments surrounded by barriers. If tess factors aren't written at all,
1129 * it's a shader bug and we don't care if this will be true.
1130 */
1131 out->tessfactors_are_def_in_all_invocs = true;
1132
1133 while (!tgsi_parse_end_of_tokens(&parse)) {
1134 tgsi_parse_token(&parse);
1135
1136 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
1137 continue;
1138
1139 struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction;
1140 check_no_subroutines(inst);
1141
1142 /* Process nested blocks. */
1143 switch (inst->Instruction.Opcode) {
1144 case TGSI_OPCODE_IF:
1145 case TGSI_OPCODE_UIF:
1146 get_if_block_tessfactor_writemask(info, &parse,
1147 &main_block_tf_writemask,
1148 &cond_block_tf_writemask);
1149 continue;
1150
1151 case TGSI_OPCODE_BGNLOOP:
1152 cond_block_tf_writemask |=
1153 get_block_tessfactor_writemask(info, &parse, TGSI_OPCODE_ENDIF);
1154 continue;
1155
1156 case TGSI_OPCODE_BARRIER:
1157 /* The following case must be prevented:
1158 * gl_TessLevelInner = ...;
1159 * barrier();
1160 * if (gl_InvocationID == 1)
1161 * gl_TessLevelInner = ...;
1162 *
1163 * If you consider disjoint code segments separated by barriers, each
1164 * such segment that writes tess factor channels should write the same
1165 * channels in all codepaths within that segment.
1166 */
1167 if (main_block_tf_writemask || cond_block_tf_writemask) {
1168 /* Accumulate the result: */
1169 out->tessfactors_are_def_in_all_invocs &=
1170 !(cond_block_tf_writemask & ~main_block_tf_writemask);
1171
1172 /* Analyze the next code segment from scratch. */
1173 main_block_tf_writemask = 0;
1174 cond_block_tf_writemask = 0;
1175 }
1176 continue;
1177 }
1178
1179 main_block_tf_writemask |= get_inst_tessfactor_writemask(info, inst);
1180 }
1181
1182 /* Accumulate the result for the last code segment separated by a barrier. */
1183 if (main_block_tf_writemask || cond_block_tf_writemask) {
1184 out->tessfactors_are_def_in_all_invocs &=
1185 !(cond_block_tf_writemask & ~main_block_tf_writemask);
1186 }
1187
1188 tgsi_parse_free(&parse);
1189 }