tgsi_sanity.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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       /* Note that 'index' is an offset relative to the value of the
00161        * address register.  No range checking done here.
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    /* Check destination and source registers' validity.
00210     * Mark the registers as used.
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    /* No declarations allowed after the first instruction.
00260     */
00261    if (ctx->num_instructions > 0)
00262       report_error( ctx, "Instruction expected but declaration found" );
00263 
00264    /* Check registers' validity.
00265     * Mark the registers as declared.
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    /* No immediates allowed after the first instruction.
00289     */
00290    if (ctx->num_instructions > 0)
00291       report_error( ctx, "Instruction expected but immediate found" );
00292 
00293    /* Mark the register as declared.
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    /* Check data type validity.
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    /* There must be an END instruction somewhere.
00316     */
00317    if (ctx->index_of_END == ~0) {
00318       report_error( ctx, "Missing END instruction" );
00319    }
00320 
00321    /* Check if all declared registers were used.
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    /* Print totals, if any.
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 }

Generated on Tue Sep 29 06:25:15 2009 for Gallium3D by  doxygen 1.5.4