00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "pipe/p_debug.h"
00029 #include "util/u_memory.h"
00030 #include "tgsi_sanity.h"
00031 #include "tgsi_info.h"
00032 #include "tgsi_iterate.h"
00033
00034 typedef uint reg_flag;
00035
00036 #define BITS_IN_REG_FLAG (sizeof( reg_flag ) * 8)
00037
00038 #define MAX_REGISTERS 512
00039 #define MAX_REG_FLAGS ((MAX_REGISTERS + BITS_IN_REG_FLAG - 1) / BITS_IN_REG_FLAG)
00040
00041 struct sanity_check_ctx
00042 {
00043 struct tgsi_iterate_context iter;
00044
00045 reg_flag regs_decl[TGSI_FILE_COUNT][MAX_REG_FLAGS];
00046 reg_flag regs_used[TGSI_FILE_COUNT][MAX_REG_FLAGS];
00047 boolean regs_ind_used[TGSI_FILE_COUNT];
00048 uint num_imms;
00049 uint num_instructions;
00050 uint index_of_END;
00051
00052 uint errors;
00053 uint warnings;
00054 };
00055
00056 static void
00057 report_error(
00058 struct sanity_check_ctx *ctx,
00059 const char *format,
00060 ... )
00061 {
00062 va_list args;
00063
00064 debug_printf( "Error : " );
00065 va_start( args, format );
00066 _debug_vprintf( format, args );
00067 va_end( args );
00068 debug_printf( "\n" );
00069 ctx->errors++;
00070 }
00071
00072 static void
00073 report_warning(
00074 struct sanity_check_ctx *ctx,
00075 const char *format,
00076 ... )
00077 {
00078 va_list args;
00079
00080 debug_printf( "Warning: " );
00081 va_start( args, format );
00082 _debug_vprintf( format, args );
00083 va_end( args );
00084 debug_printf( "\n" );
00085 ctx->warnings++;
00086 }
00087
00088 static boolean
00089 check_file_name(
00090 struct sanity_check_ctx *ctx,
00091 uint file )
00092 {
00093 if (file <= TGSI_FILE_NULL || file >= TGSI_FILE_COUNT) {
00094 report_error( ctx, "(%u): Invalid register file name", file );
00095 return FALSE;
00096 }
00097 return TRUE;
00098 }
00099
00100 static boolean
00101 is_register_declared(
00102 struct sanity_check_ctx *ctx,
00103 uint file,
00104 int index )
00105 {
00106 assert( index >= 0 && index < MAX_REGISTERS );
00107
00108 return (ctx->regs_decl[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE;
00109 }
00110
00111 static boolean
00112 is_any_register_declared(
00113 struct sanity_check_ctx *ctx,
00114 uint file )
00115 {
00116 uint i;
00117
00118 for (i = 0; i < MAX_REG_FLAGS; i++)
00119 if (ctx->regs_decl[file][i])
00120 return TRUE;
00121 return FALSE;
00122 }
00123
00124 static boolean
00125 is_register_used(
00126 struct sanity_check_ctx *ctx,
00127 uint file,
00128 int index )
00129 {
00130 assert( index < MAX_REGISTERS );
00131
00132 return (ctx->regs_used[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE;
00133 }
00134
00135 static const char *file_names[TGSI_FILE_COUNT] =
00136 {
00137 "NULL",
00138 "CONST",
00139 "IN",
00140 "OUT",
00141 "TEMP",
00142 "SAMP",
00143 "ADDR",
00144 "IMM",
00145 "LOOP"
00146 };
00147
00148 static boolean
00149 check_register_usage(
00150 struct sanity_check_ctx *ctx,
00151 uint file,
00152 int index,
00153 const char *name,
00154 boolean indirect_access )
00155 {
00156 if (!check_file_name( ctx, file ))
00157 return FALSE;
00158
00159 if (indirect_access) {
00160
00161
00162
00163 if (!is_any_register_declared( ctx, file ))
00164 report_error( ctx, "%s: Undeclared %s register", file_names[file], name );
00165 ctx->regs_ind_used[file] = TRUE;
00166 }
00167 else {
00168 if (index < 0 || index >= MAX_REGISTERS) {
00169 report_error( ctx, "%s[%d]: Invalid %s index", file_names[file], index, name );
00170 return FALSE;
00171 }
00172
00173 if (!is_register_declared( ctx, file, index ))
00174 report_error( ctx, "%s[%d]: Undeclared %s register", file_names[file], index, name );
00175 ctx->regs_used[file][index / BITS_IN_REG_FLAG] |= (1 << (index % BITS_IN_REG_FLAG));
00176 }
00177 return TRUE;
00178 }
00179
00180 static boolean
00181 iter_instruction(
00182 struct tgsi_iterate_context *iter,
00183 struct tgsi_full_instruction *inst )
00184 {
00185 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
00186 const struct tgsi_opcode_info *info;
00187 uint i;
00188
00189 if (inst->Instruction.Opcode == TGSI_OPCODE_END) {
00190 if (ctx->index_of_END != ~0) {
00191 report_error( ctx, "Too many END instructions" );
00192 }
00193 ctx->index_of_END = ctx->num_instructions;
00194 }
00195
00196 info = tgsi_get_opcode_info( inst->Instruction.Opcode );
00197 if (info == NULL) {
00198 report_error( ctx, "(%u): Invalid instruction opcode", inst->Instruction.Opcode );
00199 return TRUE;
00200 }
00201
00202 if (info->num_dst != inst->Instruction.NumDstRegs) {
00203 report_error( ctx, "%s: Invalid number of destination operands, should be %u", info->mnemonic, info->num_dst );
00204 }
00205 if (info->num_src != inst->Instruction.NumSrcRegs) {
00206 report_error( ctx, "%s: Invalid number of source operands, should be %u", info->mnemonic, info->num_src );
00207 }
00208
00209
00210
00211
00212 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
00213 check_register_usage(
00214 ctx,
00215 inst->FullDstRegisters[i].DstRegister.File,
00216 inst->FullDstRegisters[i].DstRegister.Index,
00217 "destination",
00218 FALSE );
00219 }
00220 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
00221 check_register_usage(
00222 ctx,
00223 inst->FullSrcRegisters[i].SrcRegister.File,
00224 inst->FullSrcRegisters[i].SrcRegister.Index,
00225 "source",
00226 (boolean)inst->FullSrcRegisters[i].SrcRegister.Indirect );
00227 if (inst->FullSrcRegisters[i].SrcRegister.Indirect) {
00228 uint file;
00229 int index;
00230
00231 file = inst->FullSrcRegisters[i].SrcRegisterInd.File;
00232 index = inst->FullSrcRegisters[i].SrcRegisterInd.Index;
00233 check_register_usage(
00234 ctx,
00235 file,
00236 index,
00237 "indirect",
00238 FALSE );
00239 if (!(file == TGSI_FILE_ADDRESS || file == TGSI_FILE_LOOP) || index != 0) {
00240 report_warning(ctx, "Indirect register neither ADDR[0] nor LOOP[0]");
00241 }
00242 }
00243 }
00244
00245 ctx->num_instructions++;
00246
00247 return TRUE;
00248 }
00249
00250 static boolean
00251 iter_declaration(
00252 struct tgsi_iterate_context *iter,
00253 struct tgsi_full_declaration *decl )
00254 {
00255 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
00256 uint file;
00257 uint i;
00258
00259
00260
00261 if (ctx->num_instructions > 0)
00262 report_error( ctx, "Instruction expected but declaration found" );
00263
00264
00265
00266
00267 file = decl->Declaration.File;
00268 if (!check_file_name( ctx, file ))
00269 return TRUE;
00270 for (i = decl->DeclarationRange.First; i <= decl->DeclarationRange.Last; i++) {
00271 if (is_register_declared( ctx, file, i ))
00272 report_error( ctx, "%s[%u]: The same register declared more than once", file_names[file], i );
00273 ctx->regs_decl[file][i / BITS_IN_REG_FLAG] |= (1 << (i % BITS_IN_REG_FLAG));
00274 }
00275
00276 return TRUE;
00277 }
00278
00279 static boolean
00280 iter_immediate(
00281 struct tgsi_iterate_context *iter,
00282 struct tgsi_full_immediate *imm )
00283 {
00284 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
00285
00286 assert( ctx->num_imms < MAX_REGISTERS );
00287
00288
00289
00290 if (ctx->num_instructions > 0)
00291 report_error( ctx, "Instruction expected but immediate found" );
00292
00293
00294
00295 ctx->regs_decl[TGSI_FILE_IMMEDIATE][ctx->num_imms / BITS_IN_REG_FLAG] |= (1 << (ctx->num_imms % BITS_IN_REG_FLAG));
00296 ctx->num_imms++;
00297
00298
00299
00300 if (imm->Immediate.DataType != TGSI_IMM_FLOAT32) {
00301 report_error( ctx, "(%u): Invalid immediate data type", imm->Immediate.DataType );
00302 return TRUE;
00303 }
00304
00305 return TRUE;
00306 }
00307
00308 static boolean
00309 epilog(
00310 struct tgsi_iterate_context *iter )
00311 {
00312 struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
00313 uint file;
00314
00315
00316
00317 if (ctx->index_of_END == ~0) {
00318 report_error( ctx, "Missing END instruction" );
00319 }
00320
00321
00322
00323 for (file = TGSI_FILE_NULL; file < TGSI_FILE_COUNT; file++) {
00324 uint i;
00325
00326 for (i = 0; i < MAX_REGISTERS; i++) {
00327 if (is_register_declared( ctx, file, i ) && !is_register_used( ctx, file, i ) && !ctx->regs_ind_used[file]) {
00328 report_warning( ctx, "%s[%u]: Register never used", file_names[file], i );
00329 }
00330 }
00331 }
00332
00333
00334
00335 if (ctx->errors || ctx->warnings)
00336 debug_printf( "%u errors, %u warnings\n", ctx->errors, ctx->warnings );
00337
00338 return TRUE;
00339 }
00340
00341 boolean
00342 tgsi_sanity_check(
00343 struct tgsi_token *tokens )
00344 {
00345 struct sanity_check_ctx *ctx;
00346 boolean ret;
00347
00348 ctx = CALLOC_STRUCT(sanity_check_ctx);
00349 if(!ctx)
00350 return FALSE;
00351
00352 ctx->iter.prolog = NULL;
00353 ctx->iter.iterate_instruction = iter_instruction;
00354 ctx->iter.iterate_declaration = iter_declaration;
00355 ctx->iter.iterate_immediate = iter_immediate;
00356 ctx->iter.epilog = epilog;
00357
00358 memset( ctx->regs_decl, 0, sizeof( ctx->regs_decl ) );
00359 memset( ctx->regs_used, 0, sizeof( ctx->regs_used ) );
00360 memset( ctx->regs_ind_used, 0, sizeof( ctx->regs_ind_used ) );
00361 ctx->num_imms = 0;
00362 ctx->num_instructions = 0;
00363 ctx->index_of_END = ~0;
00364
00365 ctx->errors = 0;
00366 ctx->warnings = 0;
00367
00368 ret = tgsi_iterate_shader( tokens, &ctx->iter ) &&
00369 (ctx->errors == 0);
00370
00371 FREE(ctx);
00372
00373 return ret;
00374 }