1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2008 VMware, Inc.
4848b8605Smrg * All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the
8848b8605Smrg * "Software"), to deal in the Software without restriction, including
9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
12848b8605Smrg * the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice (including the
15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
16848b8605Smrg * of the Software.
17848b8605Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg *
26848b8605Smrg **************************************************************************/
27848b8605Smrg
28848b8605Smrg#include "util/u_debug.h"
29848b8605Smrg#include "util/u_memory.h"
30848b8605Smrg#include "util/u_prim.h"
31848b8605Smrg#include "cso_cache/cso_hash.h"
32848b8605Smrg#include "tgsi_sanity.h"
33848b8605Smrg#include "tgsi_info.h"
34848b8605Smrg#include "tgsi_iterate.h"
35848b8605Smrg
36848b8605Smrg
37848b8605SmrgDEBUG_GET_ONCE_BOOL_OPTION(print_sanity, "TGSI_PRINT_SANITY", FALSE)
38848b8605Smrg
39848b8605Smrg
40848b8605Smrgtypedef struct {
41848b8605Smrg   uint file : 28;
42848b8605Smrg   /* max 2 dimensions */
43848b8605Smrg   uint dimensions : 4;
44848b8605Smrg   uint indices[2];
45848b8605Smrg} scan_register;
46848b8605Smrg
47848b8605Smrgstruct sanity_check_ctx
48848b8605Smrg{
49848b8605Smrg   struct tgsi_iterate_context iter;
50848b8605Smrg   struct cso_hash *regs_decl;
51848b8605Smrg   struct cso_hash *regs_used;
52848b8605Smrg   struct cso_hash *regs_ind_used;
53848b8605Smrg
54848b8605Smrg   uint num_imms;
55848b8605Smrg   uint num_instructions;
56848b8605Smrg   uint index_of_END;
57848b8605Smrg
58848b8605Smrg   uint errors;
59848b8605Smrg   uint warnings;
60848b8605Smrg   uint implied_array_size;
61b8e80941Smrg   uint implied_out_array_size;
62848b8605Smrg
63848b8605Smrg   boolean print;
64848b8605Smrg};
65848b8605Smrg
66b8e80941Smrgstatic inline unsigned
67848b8605Smrgscan_register_key(const scan_register *reg)
68848b8605Smrg{
69848b8605Smrg   unsigned key = reg->file;
70848b8605Smrg   key |= (reg->indices[0] << 4);
71848b8605Smrg   key |= (reg->indices[1] << 18);
72848b8605Smrg
73848b8605Smrg   return key;
74848b8605Smrg}
75848b8605Smrg
76848b8605Smrgstatic void
77848b8605Smrgfill_scan_register1d(scan_register *reg,
78848b8605Smrg                     uint file, uint index)
79848b8605Smrg{
80848b8605Smrg   reg->file = file;
81848b8605Smrg   reg->dimensions = 1;
82848b8605Smrg   reg->indices[0] = index;
83848b8605Smrg   reg->indices[1] = 0;
84848b8605Smrg}
85848b8605Smrg
86848b8605Smrgstatic void
87848b8605Smrgfill_scan_register2d(scan_register *reg,
88848b8605Smrg                     uint file, uint index1, uint index2)
89848b8605Smrg{
90848b8605Smrg   reg->file = file;
91848b8605Smrg   reg->dimensions = 2;
92848b8605Smrg   reg->indices[0] = index1;
93848b8605Smrg   reg->indices[1] = index2;
94848b8605Smrg}
95848b8605Smrg
96848b8605Smrgstatic void
97848b8605Smrgscan_register_dst(scan_register *reg,
98848b8605Smrg                  struct tgsi_full_dst_register *dst)
99848b8605Smrg{
100848b8605Smrg   if (dst->Register.Dimension) {
101848b8605Smrg      /*FIXME: right now we don't support indirect
102848b8605Smrg       * multidimensional addressing */
103848b8605Smrg      fill_scan_register2d(reg,
104848b8605Smrg                           dst->Register.File,
105848b8605Smrg                           dst->Register.Index,
106848b8605Smrg                           dst->Dimension.Index);
107848b8605Smrg   } else {
108848b8605Smrg      fill_scan_register1d(reg,
109848b8605Smrg                           dst->Register.File,
110848b8605Smrg                           dst->Register.Index);
111848b8605Smrg   }
112848b8605Smrg}
113848b8605Smrg
114848b8605Smrgstatic void
115848b8605Smrgscan_register_src(scan_register *reg,
116848b8605Smrg                  struct tgsi_full_src_register *src)
117848b8605Smrg{
118848b8605Smrg   if (src->Register.Dimension) {
119848b8605Smrg      /*FIXME: right now we don't support indirect
120848b8605Smrg       * multidimensional addressing */
121848b8605Smrg      fill_scan_register2d(reg,
122848b8605Smrg                           src->Register.File,
123848b8605Smrg                           src->Register.Index,
124848b8605Smrg                           src->Dimension.Index);
125848b8605Smrg   } else {
126848b8605Smrg      fill_scan_register1d(reg,
127848b8605Smrg                           src->Register.File,
128848b8605Smrg                           src->Register.Index);
129848b8605Smrg   }
130848b8605Smrg}
131848b8605Smrg
132848b8605Smrgstatic scan_register *
133848b8605Smrgcreate_scan_register_src(struct tgsi_full_src_register *src)
134848b8605Smrg{
135848b8605Smrg   scan_register *reg = MALLOC(sizeof(scan_register));
136848b8605Smrg   scan_register_src(reg, src);
137848b8605Smrg
138848b8605Smrg   return reg;
139848b8605Smrg}
140848b8605Smrg
141848b8605Smrgstatic scan_register *
142848b8605Smrgcreate_scan_register_dst(struct tgsi_full_dst_register *dst)
143848b8605Smrg{
144848b8605Smrg   scan_register *reg = MALLOC(sizeof(scan_register));
145848b8605Smrg   scan_register_dst(reg, dst);
146848b8605Smrg
147848b8605Smrg   return reg;
148848b8605Smrg}
149848b8605Smrg
150848b8605Smrgstatic void
151848b8605Smrgreport_error(
152848b8605Smrg   struct sanity_check_ctx *ctx,
153848b8605Smrg   const char *format,
154848b8605Smrg   ... )
155848b8605Smrg{
156848b8605Smrg   va_list args;
157848b8605Smrg
158848b8605Smrg   if (!ctx->print)
159848b8605Smrg      return;
160848b8605Smrg
161848b8605Smrg   debug_printf( "Error  : " );
162848b8605Smrg   va_start( args, format );
163848b8605Smrg   _debug_vprintf( format, args );
164848b8605Smrg   va_end( args );
165848b8605Smrg   debug_printf( "\n" );
166848b8605Smrg   ctx->errors++;
167848b8605Smrg}
168848b8605Smrg
169848b8605Smrgstatic void
170848b8605Smrgreport_warning(
171848b8605Smrg   struct sanity_check_ctx *ctx,
172848b8605Smrg   const char *format,
173848b8605Smrg   ... )
174848b8605Smrg{
175848b8605Smrg   va_list args;
176848b8605Smrg
177848b8605Smrg   if (!ctx->print)
178848b8605Smrg      return;
179848b8605Smrg
180848b8605Smrg   debug_printf( "Warning: " );
181848b8605Smrg   va_start( args, format );
182848b8605Smrg   _debug_vprintf( format, args );
183848b8605Smrg   va_end( args );
184848b8605Smrg   debug_printf( "\n" );
185848b8605Smrg   ctx->warnings++;
186848b8605Smrg}
187848b8605Smrg
188848b8605Smrgstatic boolean
189848b8605Smrgcheck_file_name(
190848b8605Smrg   struct sanity_check_ctx *ctx,
191848b8605Smrg   uint file )
192848b8605Smrg{
193848b8605Smrg   if (file <= TGSI_FILE_NULL || file >= TGSI_FILE_COUNT) {
194848b8605Smrg      report_error( ctx, "(%u): Invalid register file name", file );
195848b8605Smrg      return FALSE;
196848b8605Smrg   }
197848b8605Smrg   return TRUE;
198848b8605Smrg}
199848b8605Smrg
200848b8605Smrgstatic boolean
201848b8605Smrgis_register_declared(
202848b8605Smrg   struct sanity_check_ctx *ctx,
203848b8605Smrg   const scan_register *reg)
204848b8605Smrg{
205848b8605Smrg   void *data = cso_hash_find_data_from_template(
206848b8605Smrg      ctx->regs_decl, scan_register_key(reg),
207848b8605Smrg      (void*)reg, sizeof(scan_register));
208848b8605Smrg   return  data ? TRUE : FALSE;
209848b8605Smrg}
210848b8605Smrg
211848b8605Smrgstatic boolean
212848b8605Smrgis_any_register_declared(
213848b8605Smrg   struct sanity_check_ctx *ctx,
214848b8605Smrg   uint file )
215848b8605Smrg{
216848b8605Smrg   struct cso_hash_iter iter =
217848b8605Smrg      cso_hash_first_node(ctx->regs_decl);
218848b8605Smrg
219848b8605Smrg   while (!cso_hash_iter_is_null(iter)) {
220848b8605Smrg      scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
221848b8605Smrg      if (reg->file == file)
222848b8605Smrg         return TRUE;
223848b8605Smrg      iter = cso_hash_iter_next(iter);
224848b8605Smrg   }
225848b8605Smrg
226848b8605Smrg   return FALSE;
227848b8605Smrg}
228848b8605Smrg
229848b8605Smrgstatic boolean
230848b8605Smrgis_register_used(
231848b8605Smrg   struct sanity_check_ctx *ctx,
232848b8605Smrg   scan_register *reg)
233848b8605Smrg{
234848b8605Smrg   void *data = cso_hash_find_data_from_template(
235848b8605Smrg      ctx->regs_used, scan_register_key(reg),
236848b8605Smrg      reg, sizeof(scan_register));
237848b8605Smrg   return  data ? TRUE : FALSE;
238848b8605Smrg}
239848b8605Smrg
240848b8605Smrg
241848b8605Smrgstatic boolean
242848b8605Smrgis_ind_register_used(
243848b8605Smrg   struct sanity_check_ctx *ctx,
244848b8605Smrg   scan_register *reg)
245848b8605Smrg{
246848b8605Smrg   return cso_hash_contains(ctx->regs_ind_used, reg->file);
247848b8605Smrg}
248848b8605Smrg
249848b8605Smrgstatic const char *file_names[TGSI_FILE_COUNT] =
250848b8605Smrg{
251848b8605Smrg   "NULL",
252848b8605Smrg   "CONST",
253848b8605Smrg   "IN",
254848b8605Smrg   "OUT",
255848b8605Smrg   "TEMP",
256848b8605Smrg   "SAMP",
257848b8605Smrg   "ADDR",
258848b8605Smrg   "IMM",
259848b8605Smrg   "SV",
260848b8605Smrg   "RES"
261848b8605Smrg};
262848b8605Smrg
263848b8605Smrgstatic boolean
264848b8605Smrgcheck_register_usage(
265848b8605Smrg   struct sanity_check_ctx *ctx,
266848b8605Smrg   scan_register *reg,
267848b8605Smrg   const char *name,
268848b8605Smrg   boolean indirect_access )
269848b8605Smrg{
270848b8605Smrg   if (!check_file_name( ctx, reg->file )) {
271848b8605Smrg      FREE(reg);
272848b8605Smrg      return FALSE;
273848b8605Smrg   }
274848b8605Smrg
275848b8605Smrg   if (indirect_access) {
276848b8605Smrg      /* Note that 'index' is an offset relative to the value of the
277848b8605Smrg       * address register.  No range checking done here.*/
278848b8605Smrg      reg->indices[0] = 0;
279848b8605Smrg      reg->indices[1] = 0;
280848b8605Smrg      if (!is_any_register_declared( ctx, reg->file ))
281848b8605Smrg         report_error( ctx, "%s: Undeclared %s register", file_names[reg->file], name );
282848b8605Smrg      if (!is_ind_register_used(ctx, reg))
283848b8605Smrg         cso_hash_insert(ctx->regs_ind_used, reg->file, reg);
284848b8605Smrg      else
285848b8605Smrg         FREE(reg);
286848b8605Smrg   }
287848b8605Smrg   else {
288848b8605Smrg      if (!is_register_declared( ctx, reg )) {
289848b8605Smrg         if (reg->dimensions == 2) {
290848b8605Smrg            report_error( ctx, "%s[%d][%d]: Undeclared %s register", file_names[reg->file],
291848b8605Smrg                          reg->indices[0], reg->indices[1], name );
292848b8605Smrg         }
293848b8605Smrg         else {
294848b8605Smrg            report_error( ctx, "%s[%d]: Undeclared %s register", file_names[reg->file],
295848b8605Smrg                          reg->indices[0], name );
296848b8605Smrg         }
297848b8605Smrg      }
298848b8605Smrg      if (!is_register_used( ctx, reg ))
299848b8605Smrg         cso_hash_insert(ctx->regs_used, scan_register_key(reg), reg);
300848b8605Smrg      else
301848b8605Smrg         FREE(reg);
302848b8605Smrg   }
303848b8605Smrg   return TRUE;
304848b8605Smrg}
305848b8605Smrg
306848b8605Smrgstatic boolean
307848b8605Smrgiter_instruction(
308848b8605Smrg   struct tgsi_iterate_context *iter,
309848b8605Smrg   struct tgsi_full_instruction *inst )
310848b8605Smrg{
311848b8605Smrg   struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
312848b8605Smrg   const struct tgsi_opcode_info *info;
313848b8605Smrg   uint i;
314848b8605Smrg
315848b8605Smrg   if (inst->Instruction.Opcode == TGSI_OPCODE_END) {
316b8e80941Smrg      if (ctx->index_of_END != ~0u) {
317848b8605Smrg         report_error( ctx, "Too many END instructions" );
318848b8605Smrg      }
319848b8605Smrg      ctx->index_of_END = ctx->num_instructions;
320848b8605Smrg   }
321848b8605Smrg
322848b8605Smrg   info = tgsi_get_opcode_info( inst->Instruction.Opcode );
323b8e80941Smrg   if (!info) {
324848b8605Smrg      report_error( ctx, "(%u): Invalid instruction opcode", inst->Instruction.Opcode );
325848b8605Smrg      return TRUE;
326848b8605Smrg   }
327848b8605Smrg
328848b8605Smrg   if (info->num_dst != inst->Instruction.NumDstRegs) {
329b8e80941Smrg      report_error( ctx, "%s: Invalid number of destination operands, should be %u",
330b8e80941Smrg                    tgsi_get_opcode_name(inst->Instruction.Opcode), info->num_dst );
331848b8605Smrg   }
332848b8605Smrg   if (info->num_src != inst->Instruction.NumSrcRegs) {
333b8e80941Smrg      report_error( ctx, "%s: Invalid number of source operands, should be %u",
334b8e80941Smrg                    tgsi_get_opcode_name(inst->Instruction.Opcode), info->num_src );
335848b8605Smrg   }
336848b8605Smrg
337848b8605Smrg   /* Check destination and source registers' validity.
338848b8605Smrg    * Mark the registers as used.
339848b8605Smrg    */
340848b8605Smrg   for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
341848b8605Smrg      scan_register *reg = create_scan_register_dst(&inst->Dst[i]);
342848b8605Smrg      check_register_usage(
343848b8605Smrg         ctx,
344848b8605Smrg         reg,
345848b8605Smrg         "destination",
346848b8605Smrg         FALSE );
347848b8605Smrg      if (!inst->Dst[i].Register.WriteMask) {
348848b8605Smrg         report_error(ctx, "Destination register has empty writemask");
349848b8605Smrg      }
350848b8605Smrg   }
351848b8605Smrg   for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
352848b8605Smrg      scan_register *reg = create_scan_register_src(&inst->Src[i]);
353848b8605Smrg      check_register_usage(
354848b8605Smrg         ctx,
355848b8605Smrg         reg,
356848b8605Smrg         "source",
357848b8605Smrg         (boolean)inst->Src[i].Register.Indirect );
358848b8605Smrg      if (inst->Src[i].Register.Indirect) {
359848b8605Smrg         scan_register *ind_reg = MALLOC(sizeof(scan_register));
360848b8605Smrg
361848b8605Smrg         fill_scan_register1d(ind_reg,
362848b8605Smrg                              inst->Src[i].Indirect.File,
363848b8605Smrg                              inst->Src[i].Indirect.Index);
364848b8605Smrg         check_register_usage(
365848b8605Smrg            ctx,
366848b8605Smrg            ind_reg,
367848b8605Smrg            "indirect",
368848b8605Smrg            FALSE );
369848b8605Smrg      }
370848b8605Smrg   }
371848b8605Smrg
372848b8605Smrg   ctx->num_instructions++;
373848b8605Smrg
374848b8605Smrg   return TRUE;
375848b8605Smrg}
376848b8605Smrg
377848b8605Smrgstatic void
378848b8605Smrgcheck_and_declare(struct sanity_check_ctx *ctx,
379848b8605Smrg                  scan_register *reg)
380848b8605Smrg{
381848b8605Smrg   if (is_register_declared( ctx, reg))
382848b8605Smrg      report_error( ctx, "%s[%u]: The same register declared more than once",
383848b8605Smrg                    file_names[reg->file], reg->indices[0] );
384848b8605Smrg   cso_hash_insert(ctx->regs_decl,
385848b8605Smrg                   scan_register_key(reg),
386848b8605Smrg                   reg);
387848b8605Smrg}
388848b8605Smrg
389848b8605Smrg
390848b8605Smrgstatic boolean
391848b8605Smrgiter_declaration(
392848b8605Smrg   struct tgsi_iterate_context *iter,
393848b8605Smrg   struct tgsi_full_declaration *decl )
394848b8605Smrg{
395848b8605Smrg   struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
396848b8605Smrg   uint file;
397848b8605Smrg   uint i;
398848b8605Smrg
399848b8605Smrg   /* No declarations allowed after the first instruction.
400848b8605Smrg    */
401848b8605Smrg   if (ctx->num_instructions > 0)
402848b8605Smrg      report_error( ctx, "Instruction expected but declaration found" );
403848b8605Smrg
404848b8605Smrg   /* Check registers' validity.
405848b8605Smrg    * Mark the registers as declared.
406848b8605Smrg    */
407848b8605Smrg   file = decl->Declaration.File;
408848b8605Smrg   if (!check_file_name( ctx, file ))
409848b8605Smrg      return TRUE;
410848b8605Smrg   for (i = decl->Range.First; i <= decl->Range.Last; i++) {
411b8e80941Smrg      /* declared TGSI_FILE_INPUT's for geometry and tessellation
412848b8605Smrg       * have an implied second dimension */
413b8e80941Smrg      uint processor = ctx->iter.processor.Processor;
414b8e80941Smrg      uint patch = decl->Semantic.Name == TGSI_SEMANTIC_PATCH ||
415b8e80941Smrg         decl->Semantic.Name == TGSI_SEMANTIC_TESSOUTER ||
416b8e80941Smrg         decl->Semantic.Name == TGSI_SEMANTIC_TESSINNER;
417b8e80941Smrg      if (file == TGSI_FILE_INPUT && !patch && (
418b8e80941Smrg                processor == PIPE_SHADER_GEOMETRY ||
419b8e80941Smrg                processor == PIPE_SHADER_TESS_CTRL ||
420b8e80941Smrg                processor == PIPE_SHADER_TESS_EVAL)) {
421848b8605Smrg         uint vert;
422848b8605Smrg         for (vert = 0; vert < ctx->implied_array_size; ++vert) {
423848b8605Smrg            scan_register *reg = MALLOC(sizeof(scan_register));
424848b8605Smrg            fill_scan_register2d(reg, file, i, vert);
425848b8605Smrg            check_and_declare(ctx, reg);
426848b8605Smrg         }
427b8e80941Smrg      } else if (file == TGSI_FILE_OUTPUT && !patch &&
428b8e80941Smrg                 processor == PIPE_SHADER_TESS_CTRL) {
429b8e80941Smrg         uint vert;
430b8e80941Smrg         for (vert = 0; vert < ctx->implied_out_array_size; ++vert) {
431b8e80941Smrg            scan_register *reg = MALLOC(sizeof(scan_register));
432b8e80941Smrg            fill_scan_register2d(reg, file, i, vert);
433b8e80941Smrg            check_and_declare(ctx, reg);
434b8e80941Smrg         }
435848b8605Smrg      } else {
436848b8605Smrg         scan_register *reg = MALLOC(sizeof(scan_register));
437848b8605Smrg         if (decl->Declaration.Dimension) {
438848b8605Smrg            fill_scan_register2d(reg, file, i, decl->Dim.Index2D);
439848b8605Smrg         } else {
440848b8605Smrg            fill_scan_register1d(reg, file, i);
441848b8605Smrg         }
442848b8605Smrg         check_and_declare(ctx, reg);
443848b8605Smrg      }
444848b8605Smrg   }
445848b8605Smrg
446848b8605Smrg   return TRUE;
447848b8605Smrg}
448848b8605Smrg
449848b8605Smrgstatic boolean
450848b8605Smrgiter_immediate(
451848b8605Smrg   struct tgsi_iterate_context *iter,
452848b8605Smrg   struct tgsi_full_immediate *imm )
453848b8605Smrg{
454848b8605Smrg   struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
455848b8605Smrg   scan_register *reg;
456848b8605Smrg
457848b8605Smrg   /* No immediates allowed after the first instruction.
458848b8605Smrg    */
459848b8605Smrg   if (ctx->num_instructions > 0)
460848b8605Smrg      report_error( ctx, "Instruction expected but immediate found" );
461848b8605Smrg
462848b8605Smrg   /* Mark the register as declared.
463848b8605Smrg    */
464848b8605Smrg   reg = MALLOC(sizeof(scan_register));
465848b8605Smrg   fill_scan_register1d(reg, TGSI_FILE_IMMEDIATE, ctx->num_imms);
466848b8605Smrg   cso_hash_insert(ctx->regs_decl, scan_register_key(reg), reg);
467848b8605Smrg   ctx->num_imms++;
468848b8605Smrg
469848b8605Smrg   /* Check data type validity.
470848b8605Smrg    */
471848b8605Smrg   if (imm->Immediate.DataType != TGSI_IMM_FLOAT32 &&
472848b8605Smrg       imm->Immediate.DataType != TGSI_IMM_UINT32 &&
473848b8605Smrg       imm->Immediate.DataType != TGSI_IMM_INT32) {
474848b8605Smrg      report_error( ctx, "(%u): Invalid immediate data type", imm->Immediate.DataType );
475848b8605Smrg      return TRUE;
476848b8605Smrg   }
477848b8605Smrg
478848b8605Smrg   return TRUE;
479848b8605Smrg}
480848b8605Smrg
481848b8605Smrg
482848b8605Smrgstatic boolean
483848b8605Smrgiter_property(
484848b8605Smrg   struct tgsi_iterate_context *iter,
485848b8605Smrg   struct tgsi_full_property *prop )
486848b8605Smrg{
487848b8605Smrg   struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
488848b8605Smrg
489b8e80941Smrg   if (iter->processor.Processor == PIPE_SHADER_GEOMETRY &&
490848b8605Smrg       prop->Property.PropertyName == TGSI_PROPERTY_GS_INPUT_PRIM) {
491848b8605Smrg      ctx->implied_array_size = u_vertices_per_prim(prop->u[0].Data);
492848b8605Smrg   }
493b8e80941Smrg   if (iter->processor.Processor == PIPE_SHADER_TESS_CTRL &&
494b8e80941Smrg       prop->Property.PropertyName == TGSI_PROPERTY_TCS_VERTICES_OUT)
495b8e80941Smrg      ctx->implied_out_array_size = prop->u[0].Data;
496b8e80941Smrg   return TRUE;
497b8e80941Smrg}
498b8e80941Smrg
499b8e80941Smrgstatic boolean
500b8e80941Smrgprolog(struct tgsi_iterate_context *iter)
501b8e80941Smrg{
502b8e80941Smrg   struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
503b8e80941Smrg   if (iter->processor.Processor == PIPE_SHADER_TESS_CTRL ||
504b8e80941Smrg       iter->processor.Processor == PIPE_SHADER_TESS_EVAL)
505b8e80941Smrg      ctx->implied_array_size = 32;
506848b8605Smrg   return TRUE;
507848b8605Smrg}
508848b8605Smrg
509848b8605Smrgstatic boolean
510848b8605Smrgepilog(
511848b8605Smrg   struct tgsi_iterate_context *iter )
512848b8605Smrg{
513848b8605Smrg   struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
514848b8605Smrg
515848b8605Smrg   /* There must be an END instruction somewhere.
516848b8605Smrg    */
517b8e80941Smrg   if (ctx->index_of_END == ~0u) {
518848b8605Smrg      report_error( ctx, "Missing END instruction" );
519848b8605Smrg   }
520848b8605Smrg
521848b8605Smrg   /* Check if all declared registers were used.
522848b8605Smrg    */
523848b8605Smrg   {
524848b8605Smrg      struct cso_hash_iter iter =
525848b8605Smrg         cso_hash_first_node(ctx->regs_decl);
526848b8605Smrg
527848b8605Smrg      while (!cso_hash_iter_is_null(iter)) {
528848b8605Smrg         scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
529848b8605Smrg         if (!is_register_used(ctx, reg) && !is_ind_register_used(ctx, reg)) {
530848b8605Smrg            report_warning( ctx, "%s[%u]: Register never used",
531848b8605Smrg                            file_names[reg->file], reg->indices[0] );
532848b8605Smrg         }
533848b8605Smrg         iter = cso_hash_iter_next(iter);
534848b8605Smrg      }
535848b8605Smrg   }
536848b8605Smrg
537848b8605Smrg   /* Print totals, if any.
538848b8605Smrg    */
539848b8605Smrg   if (ctx->errors || ctx->warnings)
540848b8605Smrg      debug_printf( "%u errors, %u warnings\n", ctx->errors, ctx->warnings );
541848b8605Smrg
542848b8605Smrg   return TRUE;
543848b8605Smrg}
544848b8605Smrg
545848b8605Smrgstatic void
546848b8605Smrgregs_hash_destroy(struct cso_hash *hash)
547848b8605Smrg{
548848b8605Smrg   struct cso_hash_iter iter = cso_hash_first_node(hash);
549848b8605Smrg   while (!cso_hash_iter_is_null(iter)) {
550848b8605Smrg      scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
551848b8605Smrg      iter = cso_hash_erase(hash, iter);
552848b8605Smrg      assert(reg->file < TGSI_FILE_COUNT);
553848b8605Smrg      FREE(reg);
554848b8605Smrg   }
555848b8605Smrg   cso_hash_delete(hash);
556848b8605Smrg}
557848b8605Smrg
558848b8605Smrgboolean
559848b8605Smrgtgsi_sanity_check(
560848b8605Smrg   const struct tgsi_token *tokens )
561848b8605Smrg{
562848b8605Smrg   struct sanity_check_ctx ctx;
563b8e80941Smrg   boolean retval;
564848b8605Smrg
565b8e80941Smrg   ctx.iter.prolog = prolog;
566848b8605Smrg   ctx.iter.iterate_instruction = iter_instruction;
567848b8605Smrg   ctx.iter.iterate_declaration = iter_declaration;
568848b8605Smrg   ctx.iter.iterate_immediate = iter_immediate;
569848b8605Smrg   ctx.iter.iterate_property = iter_property;
570848b8605Smrg   ctx.iter.epilog = epilog;
571848b8605Smrg
572848b8605Smrg   ctx.regs_decl = cso_hash_create();
573848b8605Smrg   ctx.regs_used = cso_hash_create();
574848b8605Smrg   ctx.regs_ind_used = cso_hash_create();
575848b8605Smrg
576848b8605Smrg   ctx.num_imms = 0;
577848b8605Smrg   ctx.num_instructions = 0;
578848b8605Smrg   ctx.index_of_END = ~0;
579848b8605Smrg
580848b8605Smrg   ctx.errors = 0;
581848b8605Smrg   ctx.warnings = 0;
582848b8605Smrg   ctx.implied_array_size = 0;
583848b8605Smrg   ctx.print = debug_get_option_print_sanity();
584848b8605Smrg
585b8e80941Smrg   retval = tgsi_iterate_shader( tokens, &ctx.iter );
586848b8605Smrg   regs_hash_destroy(ctx.regs_decl);
587848b8605Smrg   regs_hash_destroy(ctx.regs_used);
588848b8605Smrg   regs_hash_destroy(ctx.regs_ind_used);
589b8e80941Smrg   if (retval == FALSE)
590b8e80941Smrg      return FALSE;
591b8e80941Smrg
592848b8605Smrg   return ctx.errors == 0;
593848b8605Smrg}
594