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