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