xref: /aosp_15_r20/external/mesa3d/src/gallium/auxiliary/tgsi/tgsi_scan.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 "tgsi/tgsi_info.h"
41 #include "tgsi/tgsi_parse.h"
42 #include "tgsi/tgsi_util.h"
43 #include "tgsi/tgsi_scan.h"
44 
45 
46 static bool
is_memory_file(enum tgsi_file_type file)47 is_memory_file(enum tgsi_file_type file)
48 {
49    return file == TGSI_FILE_SAMPLER ||
50           file == TGSI_FILE_SAMPLER_VIEW ||
51           file == TGSI_FILE_IMAGE ||
52           file == TGSI_FILE_BUFFER ||
53           file == TGSI_FILE_HW_ATOMIC;
54 }
55 
56 
57 static bool
is_mem_query_inst(enum tgsi_opcode opcode)58 is_mem_query_inst(enum tgsi_opcode 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(enum tgsi_opcode opcode)71 is_texture_inst(enum tgsi_opcode opcode)
72 {
73    return (!is_mem_query_inst(opcode) &&
74            tgsi_get_opcode_info(opcode)->is_tex);
75 }
76 
77 
78 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_mem_inst)79 scan_src_operand(struct tgsi_shader_info *info,
80                  const struct tgsi_full_instruction *fullinst,
81                  const struct tgsi_full_src_register *src,
82                  unsigned src_index,
83                  unsigned usage_mask_after_swizzle,
84                  bool *is_mem_inst)
85 {
86    int ind = src->Register.Index;
87 
88    if (info->processor == PIPE_SHADER_COMPUTE &&
89        src->Register.File == TGSI_FILE_SYSTEM_VALUE) {
90       unsigned name;
91 
92       name = info->system_value_semantic_name[src->Register.Index];
93 
94       switch (name) {
95       case TGSI_SEMANTIC_GRID_SIZE:
96          info->uses_grid_size = true;
97          break;
98       }
99    }
100 
101    /* Mark which inputs are effectively used */
102    if (src->Register.File == TGSI_FILE_INPUT) {
103       if (src->Register.Indirect) {
104          for (ind = 0; ind < info->num_inputs; ++ind) {
105             info->input_usage_mask[ind] |= usage_mask_after_swizzle;
106          }
107       } else {
108          assert(ind >= 0);
109          assert(ind < PIPE_MAX_SHADER_INPUTS);
110          info->input_usage_mask[ind] |= usage_mask_after_swizzle;
111       }
112 
113       if (info->processor == PIPE_SHADER_FRAGMENT) {
114          unsigned name, input;
115 
116          if (src->Register.Indirect && src->Indirect.ArrayID)
117             input = info->input_array_first[src->Indirect.ArrayID];
118          else
119             input = src->Register.Index;
120 
121          name = info->input_semantic_name[input];
122 
123          if (name == TGSI_SEMANTIC_POSITION &&
124              usage_mask_after_swizzle & TGSI_WRITEMASK_Z)
125             info->reads_z = true;
126       }
127    }
128 
129    if (info->processor == PIPE_SHADER_TESS_CTRL &&
130        src->Register.File == TGSI_FILE_OUTPUT) {
131       unsigned input;
132 
133       if (src->Register.Indirect && src->Indirect.ArrayID)
134          input = info->output_array_first[src->Indirect.ArrayID];
135       else
136          input = src->Register.Index;
137 
138       switch (info->output_semantic_name[input]) {
139       case TGSI_SEMANTIC_PATCH:
140          info->reads_perpatch_outputs = true;
141          break;
142       case TGSI_SEMANTIC_TESSINNER:
143       case TGSI_SEMANTIC_TESSOUTER:
144          info->reads_tessfactor_outputs = true;
145          break;
146       default:
147          info->reads_pervertex_outputs = true;
148       }
149    }
150 
151    /* check for indirect register reads */
152    if (src->Register.Indirect)
153       info->indirect_files |= (1 << src->Register.File);
154 
155    if (src->Register.Dimension && src->Dimension.Indirect)
156       info->dim_indirect_files |= 1u << src->Register.File;
157 
158    /* Texture samplers */
159    if (src->Register.File == TGSI_FILE_SAMPLER) {
160       const unsigned index = src->Register.Index;
161 
162       assert(fullinst->Instruction.Texture);
163       assert(index < PIPE_MAX_SAMPLERS);
164 
165       if (is_texture_inst(fullinst->Instruction.Opcode)) {
166          const unsigned target = fullinst->Texture.Texture;
167          assert(target < TGSI_TEXTURE_UNKNOWN);
168          /* for texture instructions, check that the texture instruction
169           * target matches the previous sampler view declaration (if there
170           * was one.)
171           */
172          if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) {
173             /* probably no sampler view declaration */
174             info->sampler_targets[index] = target;
175          } else {
176             /* Make sure the texture instruction's sampler/target info
177              * agrees with the sampler view declaration.
178              */
179             assert(info->sampler_targets[index] == target);
180          }
181       }
182    }
183 
184    if (is_memory_file(src->Register.File) &&
185        !is_mem_query_inst(fullinst->Instruction.Opcode)) {
186       *is_mem_inst = true;
187 
188       if (src->Register.File == TGSI_FILE_IMAGE &&
189           (fullinst->Memory.Texture == TGSI_TEXTURE_2D_MSAA ||
190            fullinst->Memory.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) {
191          if (src->Register.Indirect)
192             info->msaa_images_declared = info->images_declared;
193          else
194             info->msaa_images_declared |= 1 << src->Register.Index;
195       }
196 
197       if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) {
198          info->writes_memory = true;
199 
200          if (src->Register.File == TGSI_FILE_BUFFER) {
201             if (src->Register.Indirect)
202                info->shader_buffers_atomic = info->shader_buffers_declared;
203             else
204                info->shader_buffers_atomic |= 1 << src->Register.Index;
205          }
206       } else {
207          if (src->Register.File == TGSI_FILE_BUFFER) {
208             if (src->Register.Indirect)
209                info->shader_buffers_load = info->shader_buffers_declared;
210             else
211                info->shader_buffers_load |= 1 << src->Register.Index;
212          }
213       }
214    }
215 }
216 
217 
218 static void
scan_instruction(struct tgsi_shader_info * info,const struct tgsi_full_instruction * fullinst,unsigned * current_depth)219 scan_instruction(struct tgsi_shader_info *info,
220                  const struct tgsi_full_instruction *fullinst,
221                  unsigned *current_depth)
222 {
223    unsigned i;
224    bool is_mem_inst = false;
225 
226    assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
227    info->opcode_count[fullinst->Instruction.Opcode]++;
228 
229    switch (fullinst->Instruction.Opcode) {
230    case TGSI_OPCODE_IF:
231    case TGSI_OPCODE_UIF:
232    case TGSI_OPCODE_BGNLOOP:
233       (*current_depth)++;
234       break;
235    case TGSI_OPCODE_ENDIF:
236    case TGSI_OPCODE_ENDLOOP:
237       (*current_depth)--;
238       break;
239    case TGSI_OPCODE_FBFETCH:
240       info->uses_fbfetch = true;
241       break;
242    default:
243       break;
244    }
245 
246    for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
247       scan_src_operand(info, fullinst, &fullinst->Src[i], i,
248                        tgsi_util_get_inst_usage_mask(fullinst, i),
249                        &is_mem_inst);
250 
251       if (fullinst->Src[i].Register.Indirect) {
252          struct tgsi_full_src_register src = {{0}};
253 
254          src.Register.File = fullinst->Src[i].Indirect.File;
255          src.Register.Index = fullinst->Src[i].Indirect.Index;
256 
257          scan_src_operand(info, fullinst, &src, -1,
258                           1 << fullinst->Src[i].Indirect.Swizzle,
259                           NULL);
260       }
261 
262       if (fullinst->Src[i].Register.Dimension &&
263           fullinst->Src[i].Dimension.Indirect) {
264          struct tgsi_full_src_register src = {{0}};
265 
266          src.Register.File = fullinst->Src[i].DimIndirect.File;
267          src.Register.Index = fullinst->Src[i].DimIndirect.Index;
268 
269          scan_src_operand(info, fullinst, &src, -1,
270                           1 << fullinst->Src[i].DimIndirect.Swizzle,
271                           NULL);
272       }
273    }
274 
275    if (fullinst->Instruction.Texture) {
276       for (i = 0; i < fullinst->Texture.NumOffsets; i++) {
277          struct tgsi_full_src_register src = {{0}};
278 
279          src.Register.File = fullinst->TexOffsets[i].File;
280          src.Register.Index = fullinst->TexOffsets[i].Index;
281 
282          /* The usage mask is suboptimal but should be safe. */
283          scan_src_operand(info, fullinst, &src, -1,
284                           (1 << fullinst->TexOffsets[i].SwizzleX) |
285                           (1 << fullinst->TexOffsets[i].SwizzleY) |
286                           (1 << fullinst->TexOffsets[i].SwizzleZ),
287                           &is_mem_inst);
288       }
289    }
290 
291    /* check for indirect register writes */
292    for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
293       const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
294 
295       if (dst->Register.Indirect) {
296          struct tgsi_full_src_register src = {{0}};
297 
298          src.Register.File = dst->Indirect.File;
299          src.Register.Index = dst->Indirect.Index;
300 
301          scan_src_operand(info, fullinst, &src, -1,
302                           1 << dst->Indirect.Swizzle, NULL);
303 
304          info->indirect_files |= (1 << dst->Register.File);
305       }
306 
307       if (dst->Register.Dimension && dst->Dimension.Indirect) {
308          struct tgsi_full_src_register src = {{0}};
309 
310          src.Register.File = dst->DimIndirect.File;
311          src.Register.Index = dst->DimIndirect.Index;
312 
313          scan_src_operand(info, fullinst, &src, -1,
314                           1 << dst->DimIndirect.Swizzle, NULL);
315 
316          info->dim_indirect_files |= 1u << dst->Register.File;
317       }
318 
319       if (is_memory_file(dst->Register.File)) {
320          assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE);
321 
322          is_mem_inst = true;
323          info->writes_memory = true;
324 
325          if (dst->Register.File == TGSI_FILE_IMAGE) {
326             if (fullinst->Memory.Texture == TGSI_TEXTURE_2D_MSAA ||
327                 fullinst->Memory.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA) {
328                if (dst->Register.Indirect)
329                   info->msaa_images_declared = info->images_declared;
330                else
331                   info->msaa_images_declared |= 1 << dst->Register.Index;
332             }
333          } else if (dst->Register.File == TGSI_FILE_BUFFER) {
334             if (dst->Register.Indirect)
335                info->shader_buffers_store = info->shader_buffers_declared;
336             else
337                info->shader_buffers_store |= 1 << dst->Register.Index;
338          }
339       }
340    }
341 
342    info->num_instructions++;
343 }
344 
345 
346 static void
scan_declaration(struct tgsi_shader_info * info,const struct tgsi_full_declaration * fulldecl)347 scan_declaration(struct tgsi_shader_info *info,
348                  const struct tgsi_full_declaration *fulldecl)
349 {
350    enum tgsi_file_type file = fulldecl->Declaration.File;
351    const unsigned procType = info->processor;
352    unsigned reg;
353 
354    if (fulldecl->Declaration.Array) {
355       unsigned array_id = fulldecl->Array.ArrayID;
356 
357       switch (file) {
358       case TGSI_FILE_INPUT:
359          assert(array_id < ARRAY_SIZE(info->input_array_first));
360          info->input_array_first[array_id] = fulldecl->Range.First;
361          break;
362       case TGSI_FILE_OUTPUT:
363          assert(array_id < ARRAY_SIZE(info->output_array_first));
364          info->output_array_first[array_id] = fulldecl->Range.First;
365          break;
366 
367       case TGSI_FILE_NULL:
368          unreachable("unexpected file");
369 
370       default:
371          break;
372       }
373    }
374 
375    for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) {
376       unsigned semName = fulldecl->Semantic.Name;
377       unsigned semIndex = fulldecl->Semantic.Index +
378          (reg - fulldecl->Range.First);
379       int buffer;
380       unsigned index, target, type;
381 
382       /*
383        * only first 32 regs will appear in this bitfield, if larger
384        * bits will wrap around.
385        */
386       info->file_mask[file] |= (1u << (reg & 31));
387       info->file_count[file]++;
388       info->file_max[file] = MAX2(info->file_max[file], (int)reg);
389 
390       switch (file) {
391       case TGSI_FILE_CONSTANT:
392          buffer = 0;
393 
394          if (fulldecl->Declaration.Dimension)
395             buffer = fulldecl->Dim.Index2D;
396 
397          info->const_file_max[buffer] =
398             MAX2(info->const_file_max[buffer], (int)reg);
399          info->const_buffers_declared |= 1u << buffer;
400          break;
401 
402       case TGSI_FILE_IMAGE:
403          info->images_declared |= 1u << reg;
404          if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER)
405             info->images_buffers |= 1 << reg;
406          break;
407 
408       case TGSI_FILE_BUFFER:
409          info->shader_buffers_declared |= 1u << reg;
410          break;
411 
412       case TGSI_FILE_HW_ATOMIC:
413          info->hw_atomic_declared |= 1u << reg;
414          break;
415 
416       case TGSI_FILE_INPUT:
417          info->input_semantic_name[reg] = (uint8_t) semName;
418          info->input_semantic_index[reg] = (uint8_t) semIndex;
419          info->input_interpolate[reg] = (uint8_t)fulldecl->Interp.Interpolate;
420          info->input_interpolate_loc[reg] = (uint8_t)fulldecl->Interp.Location;
421 
422          /* Vertex shaders can have inputs with holes between them. */
423          info->num_inputs = MAX2(info->num_inputs, reg + 1);
424 
425          switch (semName) {
426          case TGSI_SEMANTIC_PRIMID:
427             info->uses_primid = true;
428             break;
429          case TGSI_SEMANTIC_FACE:
430             info->uses_frontface = true;
431             break;
432          }
433          break;
434 
435       case TGSI_FILE_SYSTEM_VALUE:
436          index = fulldecl->Range.First;
437 
438          info->system_value_semantic_name[index] = semName;
439          info->num_system_values = MAX2(info->num_system_values, index + 1);
440 
441          switch (semName) {
442          case TGSI_SEMANTIC_INSTANCEID:
443             info->uses_instanceid = true;
444             break;
445          case TGSI_SEMANTIC_VERTEXID:
446             info->uses_vertexid = true;
447             break;
448          case TGSI_SEMANTIC_VERTEXID_NOBASE:
449             info->uses_vertexid_nobase = true;
450             break;
451          case TGSI_SEMANTIC_BASEVERTEX:
452             info->uses_basevertex = true;
453             break;
454          case TGSI_SEMANTIC_PRIMID:
455             info->uses_primid = true;
456             break;
457          case TGSI_SEMANTIC_INVOCATIONID:
458             info->uses_invocationid = true;
459             break;
460          case TGSI_SEMANTIC_FACE:
461             info->uses_frontface = true;
462             break;
463          }
464          break;
465 
466       case TGSI_FILE_OUTPUT:
467          info->output_semantic_name[reg] = (uint8_t) semName;
468          info->output_semantic_index[reg] = (uint8_t) semIndex;
469          info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask;
470          info->num_outputs = MAX2(info->num_outputs, reg + 1);
471 
472          if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) {
473             info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamX;
474             info->num_stream_output_components[fulldecl->Semantic.StreamX]++;
475          }
476          if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) {
477             info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamY << 2;
478             info->num_stream_output_components[fulldecl->Semantic.StreamY]++;
479          }
480          if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) {
481             info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamZ << 4;
482             info->num_stream_output_components[fulldecl->Semantic.StreamZ]++;
483          }
484          if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) {
485             info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamW << 6;
486             info->num_stream_output_components[fulldecl->Semantic.StreamW]++;
487          }
488 
489          switch (semName) {
490          case TGSI_SEMANTIC_VIEWPORT_INDEX:
491             info->writes_viewport_index = true;
492             break;
493          case TGSI_SEMANTIC_LAYER:
494             info->writes_layer = true;
495             break;
496          case TGSI_SEMANTIC_PSIZE:
497             info->writes_psize = true;
498             break;
499          case TGSI_SEMANTIC_CLIPVERTEX:
500             info->writes_clipvertex = true;
501             break;
502          case TGSI_SEMANTIC_STENCIL:
503             info->writes_stencil = true;
504             break;
505          case TGSI_SEMANTIC_SAMPLEMASK:
506             info->writes_samplemask = true;
507             break;
508          case TGSI_SEMANTIC_EDGEFLAG:
509             info->writes_edgeflag = true;
510             break;
511          case TGSI_SEMANTIC_POSITION:
512             if (procType == PIPE_SHADER_FRAGMENT)
513                info->writes_z = true;
514             else
515                info->writes_position = true;
516             break;
517          }
518          break;
519 
520       case TGSI_FILE_SAMPLER:
521          STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS);
522          info->samplers_declared |= 1u << reg;
523          break;
524 
525       case TGSI_FILE_SAMPLER_VIEW:
526          target = fulldecl->SamplerView.Resource;
527          type = fulldecl->SamplerView.ReturnTypeX;
528 
529          assert(target < TGSI_TEXTURE_UNKNOWN);
530          if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) {
531             /* Save sampler target for this sampler index */
532             info->sampler_targets[reg] = target;
533             info->sampler_type[reg] = type;
534          } else {
535             /* if previously declared, make sure targets agree */
536             assert(info->sampler_targets[reg] == target);
537             assert(info->sampler_type[reg] == type);
538          }
539          break;
540 
541       case TGSI_FILE_NULL:
542          unreachable("unexpected file");
543 
544       default:
545          break;
546       }
547    }
548 }
549 
550 
551 static void
scan_immediate(struct tgsi_shader_info * info)552 scan_immediate(struct tgsi_shader_info *info)
553 {
554    unsigned reg = info->immediate_count++;
555    enum tgsi_file_type file = TGSI_FILE_IMMEDIATE;
556 
557    info->file_mask[file] |= (1 << reg);
558    info->file_count[file]++;
559    info->file_max[file] = MAX2(info->file_max[file], (int)reg);
560 }
561 
562 
563 static void
scan_property(struct tgsi_shader_info * info,const struct tgsi_full_property * fullprop)564 scan_property(struct tgsi_shader_info *info,
565               const struct tgsi_full_property *fullprop)
566 {
567    unsigned name = fullprop->Property.PropertyName;
568    unsigned value = fullprop->u[0].Data;
569 
570    assert(name < ARRAY_SIZE(info->properties));
571    info->properties[name] = value;
572 
573    switch (name) {
574    case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:
575       info->num_written_clipdistance = value;
576       break;
577    case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:
578       info->num_written_culldistance = value;
579       break;
580    }
581 }
582 
583 
584 /**
585  * Scan the given TGSI shader to collect information such as number of
586  * registers used, special instructions used, etc.
587  * \return info  the result of the scan
588  */
589 void
tgsi_scan_shader(const struct tgsi_token * tokens,struct tgsi_shader_info * info)590 tgsi_scan_shader(const struct tgsi_token *tokens,
591                  struct tgsi_shader_info *info)
592 {
593    unsigned procType, i;
594    struct tgsi_parse_context parse;
595    unsigned current_depth = 0;
596 
597    memset(info, 0, sizeof(*info));
598    for (i = 0; i < TGSI_FILE_COUNT; i++)
599       info->file_max[i] = -1;
600    for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++)
601       info->const_file_max[i] = -1;
602    for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++)
603       info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN;
604 
605    /**
606     ** Setup to begin parsing input shader
607     **/
608    if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
609       debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
610       return;
611    }
612    procType = parse.FullHeader.Processor.Processor;
613    assert(procType == PIPE_SHADER_FRAGMENT ||
614           procType == PIPE_SHADER_VERTEX ||
615           procType == PIPE_SHADER_GEOMETRY ||
616           procType == PIPE_SHADER_TESS_CTRL ||
617           procType == PIPE_SHADER_TESS_EVAL ||
618           procType == PIPE_SHADER_COMPUTE);
619    info->processor = procType;
620 
621    if (procType == PIPE_SHADER_GEOMETRY)
622       info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;
623 
624    /**
625     ** Loop over incoming program tokens/instructions
626     */
627    while (!tgsi_parse_end_of_tokens(&parse)) {
628       tgsi_parse_token( &parse );
629 
630       switch( parse.FullToken.Token.Type ) {
631       case TGSI_TOKEN_TYPE_INSTRUCTION:
632          scan_instruction(info, &parse.FullToken.FullInstruction,
633                           &current_depth);
634          break;
635       case TGSI_TOKEN_TYPE_DECLARATION:
636          scan_declaration(info, &parse.FullToken.FullDeclaration);
637          break;
638       case TGSI_TOKEN_TYPE_IMMEDIATE:
639          scan_immediate(info);
640          break;
641       case TGSI_TOKEN_TYPE_PROPERTY:
642          scan_property(info, &parse.FullToken.FullProperty);
643          break;
644       default:
645          assert(!"Unexpected TGSI token type");
646       }
647    }
648 
649    info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
650                       info->opcode_count[TGSI_OPCODE_KILL]);
651 
652    /* The dimensions of the IN decleration in geometry shader have
653     * to be deduced from the type of the input primitive.
654     */
655    if (procType == PIPE_SHADER_GEOMETRY) {
656       unsigned input_primitive =
657             info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
658       int num_verts = mesa_vertices_per_prim(input_primitive);
659       int j;
660       info->file_count[TGSI_FILE_INPUT] = num_verts;
661       info->file_max[TGSI_FILE_INPUT] =
662             MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
663       for (j = 0; j < num_verts; ++j) {
664          info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
665       }
666    }
667 
668    tgsi_parse_free(&parse);
669 }
670 
671