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