• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
is_memory_file(unsigned file)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
is_mem_query_inst(unsigned opcode)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
is_texture_inst(unsigned opcode)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
computes_derivative(unsigned opcode)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
scan_src_operand(struct tgsi_shader_info * info,const struct tgsi_full_instruction * fullinst,const struct tgsi_full_src_register * src,unsigned src_index,unsigned usage_mask_after_swizzle,bool is_interp_instruction,bool * is_mem_inst)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
scan_instruction(struct tgsi_shader_info * info,const struct tgsi_full_instruction * fullinst,unsigned * current_depth)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
scan_declaration(struct tgsi_shader_info * info,const struct tgsi_full_declaration * fulldecl)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
scan_immediate(struct tgsi_shader_info * info)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
scan_property(struct tgsi_shader_info * info,const struct tgsi_full_property * fullprop)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
tgsi_scan_shader(const struct tgsi_token * tokens,struct tgsi_shader_info * info)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
tgsi_scan_arrays(const struct tgsi_token * tokens,unsigned file,unsigned max_array_id,struct tgsi_array_info * arrays)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
check_no_subroutines(const struct tgsi_full_instruction * inst)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
get_inst_tessfactor_writemask(const struct tgsi_shader_info * info,const struct tgsi_full_instruction * inst)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
get_block_tessfactor_writemask(const struct tgsi_shader_info * info,struct tgsi_parse_context * parse,unsigned end_opcode)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
get_if_block_tessfactor_writemask(const struct tgsi_shader_info * info,struct tgsi_parse_context * parse,unsigned * upper_block_tf_writemask,unsigned * cond_block_tf_writemask)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
tgsi_scan_tess_ctrl(const struct tgsi_token * tokens,const struct tgsi_shader_info * info,struct tgsi_tessctrl_info * out)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 }
1190