tgsi_sanity.c revision c208a2c791fa24c7c5887fc496738cbddbfafc72
1/************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "pipe/p_debug.h" 29#include "tgsi_sanity.h" 30#include "tgsi_iterate.h" 31 32#define MAX_REGISTERS 256 33 34typedef uint reg_flag; 35 36#define BITS_IN_REG_FLAG (sizeof( reg_flag ) * 8) 37 38struct sanity_check_ctx 39{ 40 struct tgsi_iterate_context iter; 41 42 reg_flag regs_decl[TGSI_FILE_COUNT][MAX_REGISTERS / BITS_IN_REG_FLAG]; 43 reg_flag regs_used[TGSI_FILE_COUNT][MAX_REGISTERS / BITS_IN_REG_FLAG]; 44 boolean regs_ind_used[TGSI_FILE_COUNT]; 45 uint num_imms; 46 uint num_instructions; 47 uint index_of_END; 48 49 uint errors; 50 uint warnings; 51}; 52 53static void 54report_error( 55 struct sanity_check_ctx *ctx, 56 const char *format, 57 ... ) 58{ 59 va_list args; 60 61 debug_printf( "Error : " ); 62 va_start( args, format ); 63 _debug_vprintf( format, args ); 64 va_end( args ); 65 debug_printf( "\n" ); 66 ctx->errors++; 67} 68 69static void 70report_warning( 71 struct sanity_check_ctx *ctx, 72 const char *format, 73 ... ) 74{ 75 va_list args; 76 77 debug_printf( "Warning: " ); 78 va_start( args, format ); 79 _debug_vprintf( format, args ); 80 va_end( args ); 81 debug_printf( "\n" ); 82 ctx->warnings++; 83} 84 85static boolean 86check_file_name( 87 struct sanity_check_ctx *ctx, 88 uint file ) 89{ 90 if (file <= TGSI_FILE_NULL || file >= TGSI_FILE_COUNT) { 91 report_error( ctx, "Invalid register file name" ); 92 return FALSE; 93 } 94 return TRUE; 95} 96 97static boolean 98is_register_declared( 99 struct sanity_check_ctx *ctx, 100 uint file, 101 int index ) 102{ 103 assert( index >= 0 && index < MAX_REGISTERS ); 104 105 return (ctx->regs_decl[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE; 106} 107 108static boolean 109is_any_register_declared( 110 struct sanity_check_ctx *ctx, 111 uint file ) 112{ 113 uint i; 114 115 for (i = 0; i < MAX_REGISTERS / BITS_IN_REG_FLAG; i++) 116 if (ctx->regs_decl[file][i]) 117 return TRUE; 118 return FALSE; 119} 120 121static boolean 122is_register_used( 123 struct sanity_check_ctx *ctx, 124 uint file, 125 int index ) 126{ 127 assert( index < MAX_REGISTERS ); 128 129 return (ctx->regs_used[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE; 130} 131 132static const char *file_names[] = 133{ 134 "NULL", 135 "CONST", 136 "IN", 137 "OUT", 138 "TEMP", 139 "SAMP", 140 "ADDR", 141 "IMM" 142}; 143 144static boolean 145check_register_usage( 146 struct sanity_check_ctx *ctx, 147 uint file, 148 int index, 149 const char *name, 150 boolean indirect_access ) 151{ 152 if (!check_file_name( ctx, file )) 153 return FALSE; 154 if (indirect_access) { 155 if (!is_any_register_declared( ctx, file )) 156 report_error( ctx, "%s: Undeclared %s register", file_names[file], name ); 157 ctx->regs_ind_used[file] = TRUE; 158 } 159 else { 160 if (!is_register_declared( ctx, file, index )) 161 report_error( ctx, "%s[%d]: Undeclared %s register", file_names[file], index, name ); 162 ctx->regs_used[file][index / BITS_IN_REG_FLAG] |= (1 << (index % BITS_IN_REG_FLAG)); 163 } 164 return TRUE; 165} 166 167static boolean 168iter_instruction( 169 struct tgsi_iterate_context *iter, 170 struct tgsi_full_instruction *inst ) 171{ 172 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; 173 uint i; 174 175 /* There must be no other instructions after END. 176 */ 177 if (ctx->index_of_END != ~0) { 178 report_error( ctx, "Unexpected instruction after END" ); 179 } 180 else if (inst->Instruction.Opcode == TGSI_OPCODE_END) { 181 ctx->index_of_END = ctx->num_instructions; 182 } 183 184 /* Check destination and source registers' validity. 185 * Mark the registers as used. 186 */ 187 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 188 check_register_usage( 189 ctx, 190 inst->FullDstRegisters[i].DstRegister.File, 191 inst->FullDstRegisters[i].DstRegister.Index, 192 "destination", 193 FALSE ); 194 } 195 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 196 check_register_usage( 197 ctx, 198 inst->FullSrcRegisters[i].SrcRegister.File, 199 inst->FullSrcRegisters[i].SrcRegister.Index, 200 "source", 201 (boolean)inst->FullSrcRegisters[i].SrcRegister.Indirect ); 202 if (inst->FullSrcRegisters[i].SrcRegister.Indirect) { 203 uint file; 204 int index; 205 206 file = inst->FullSrcRegisters[i].SrcRegisterInd.File; 207 index = inst->FullSrcRegisters[i].SrcRegisterInd.Index; 208 check_register_usage( 209 ctx, 210 file, 211 index, 212 "indirect", 213 FALSE ); 214 if (file != TGSI_FILE_ADDRESS || index != 0) 215 report_warning( ctx, "Indirect register not ADDR[0]" ); 216 } 217 } 218 219 ctx->num_instructions++; 220 221 return TRUE; 222} 223 224static boolean 225iter_declaration( 226 struct tgsi_iterate_context *iter, 227 struct tgsi_full_declaration *decl ) 228{ 229 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; 230 uint file; 231 uint i; 232 233 /* No declarations allowed after the first instruction. 234 */ 235 if (ctx->num_instructions > 0) 236 report_error( ctx, "Instruction expected but declaration found" ); 237 238 /* Check registers' validity. 239 * Mark the registers as declared. 240 */ 241 file = decl->Declaration.File; 242 if (!check_file_name( ctx, file )) 243 return TRUE; 244 for (i = decl->DeclarationRange.First; i <= decl->DeclarationRange.Last; i++) { 245 if (is_register_declared( ctx, file, i )) 246 report_error( ctx, "The same register declared twice" ); 247 ctx->regs_decl[file][i / BITS_IN_REG_FLAG] |= (1 << (i % BITS_IN_REG_FLAG)); 248 } 249 250 return TRUE; 251} 252 253static boolean 254iter_immediate( 255 struct tgsi_iterate_context *iter, 256 struct tgsi_full_immediate *imm ) 257{ 258 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; 259 260 assert( ctx->num_imms < MAX_REGISTERS ); 261 262 /* No immediates allowed after the first instruction. 263 */ 264 if (ctx->num_instructions > 0) 265 report_error( ctx, "Instruction expected but immediate found" ); 266 267 /* Mark the register as declared. 268 */ 269 ctx->regs_decl[TGSI_FILE_IMMEDIATE][ctx->num_imms / BITS_IN_REG_FLAG] |= (1 << (ctx->num_imms % BITS_IN_REG_FLAG)); 270 ctx->num_imms++; 271 272 /* Check data type validity. 273 */ 274 if (imm->Immediate.DataType != TGSI_IMM_FLOAT32) { 275 report_error( ctx, "Invalid immediate data type" ); 276 return TRUE; 277 } 278 279 return TRUE; 280} 281 282static boolean 283epilog( 284 struct tgsi_iterate_context *iter ) 285{ 286 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; 287 uint file; 288 289 /* There must be an END instruction at the end. 290 */ 291 if (ctx->index_of_END == ~0 || ctx->index_of_END != ctx->num_instructions - 1) { 292 report_error( ctx, "Expected END at end of instruction sequence" ); 293 } 294 295 /* Check if all declared registers were used. 296 */ 297 for (file = TGSI_FILE_NULL; file < TGSI_FILE_COUNT; file++) { 298 uint i; 299 300 for (i = 0; i < MAX_REGISTERS; i++) { 301 if (is_register_declared( ctx, file, i ) && !is_register_used( ctx, file, i ) && !ctx->regs_ind_used[file]) { 302 report_warning( ctx, "Register never used" ); 303 } 304 } 305 } 306 307 /* Print totals, if any. 308 */ 309 if (ctx->errors || ctx->warnings) 310 debug_printf( "\n%u errors, %u warnings", ctx->errors, ctx->warnings ); 311 312 return TRUE; 313} 314 315boolean 316tgsi_sanity_check( 317 struct tgsi_token *tokens ) 318{ 319 struct sanity_check_ctx ctx; 320 321 ctx.iter.prolog = NULL; 322 ctx.iter.iterate_instruction = iter_instruction; 323 ctx.iter.iterate_declaration = iter_declaration; 324 ctx.iter.iterate_immediate = iter_immediate; 325 ctx.iter.epilog = epilog; 326 327 memset( ctx.regs_decl, 0, sizeof( ctx.regs_decl ) ); 328 memset( ctx.regs_used, 0, sizeof( ctx.regs_used ) ); 329 memset( ctx.regs_ind_used, 0, sizeof( ctx.regs_ind_used ) ); 330 ctx.num_imms = 0; 331 ctx.num_instructions = 0; 332 ctx.index_of_END = ~0; 333 334 ctx.errors = 0; 335 ctx.warnings = 0; 336 337 if (!tgsi_iterate_shader( tokens, &ctx.iter )) 338 return FALSE; 339 340 return ctx.errors == 0; 341} 342