static boolean iter_immediate( struct tgsi_iterate_context *iter, struct tgsi_full_immediate *imm ) { struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; scan_register *reg; /* No immediates allowed after the first instruction. */ if (ctx->num_instructions > 0) report_error( ctx, "Instruction expected but immediate found" ); /* Mark the register as declared. */ reg = MALLOC(sizeof(scan_register)); fill_scan_register1d(reg, TGSI_FILE_IMMEDIATE, ctx->num_imms); cso_hash_insert(ctx->regs_decl, scan_register_key(reg), reg); ctx->num_imms++; /* Check data type validity. */ if (imm->Immediate.DataType != TGSI_IMM_FLOAT32 && imm->Immediate.DataType != TGSI_IMM_UINT32 && imm->Immediate.DataType != TGSI_IMM_INT32) { report_error( ctx, "(%u): Invalid immediate data type", imm->Immediate.DataType ); return TRUE; } return TRUE; }
static void scan_register_dst(scan_register *reg, struct tgsi_full_dst_register *dst) { fill_scan_register1d(reg, dst->Register.File, dst->Register.Index); }
static boolean iter_declaration( struct tgsi_iterate_context *iter, struct tgsi_full_declaration *decl ) { struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; uint file; uint i; /* No declarations allowed after the first instruction. */ if (ctx->num_instructions > 0) report_error( ctx, "Instruction expected but declaration found" ); /* Check registers' validity. * Mark the registers as declared. */ file = decl->Declaration.File; if (!check_file_name( ctx, file )) return TRUE; for (i = decl->Range.First; i <= decl->Range.Last; i++) { /* declared TGSI_FILE_INPUT's for geometry and tessellation * have an implied second dimension */ uint processor = ctx->iter.processor.Processor; uint patch = decl->Semantic.Name == TGSI_SEMANTIC_PATCH || decl->Semantic.Name == TGSI_SEMANTIC_TESSOUTER || decl->Semantic.Name == TGSI_SEMANTIC_TESSINNER; if (file == TGSI_FILE_INPUT && !patch && ( processor == TGSI_PROCESSOR_GEOMETRY || processor == TGSI_PROCESSOR_TESS_CTRL || processor == TGSI_PROCESSOR_TESS_EVAL)) { uint vert; for (vert = 0; vert < ctx->implied_array_size; ++vert) { scan_register *reg = MALLOC(sizeof(scan_register)); fill_scan_register2d(reg, file, i, vert); check_and_declare(ctx, reg); } } else if (file == TGSI_FILE_OUTPUT && !patch && processor == TGSI_PROCESSOR_TESS_CTRL) { uint vert; for (vert = 0; vert < ctx->implied_out_array_size; ++vert) { scan_register *reg = MALLOC(sizeof(scan_register)); fill_scan_register2d(reg, file, i, vert); check_and_declare(ctx, reg); } } else { scan_register *reg = MALLOC(sizeof(scan_register)); if (decl->Declaration.Dimension) { fill_scan_register2d(reg, file, i, decl->Dim.Index2D); } else { fill_scan_register1d(reg, file, i); } check_and_declare(ctx, reg); } } return TRUE; }
static void scan_register_dst(scan_register *reg, struct tgsi_full_dst_register *dst) { if (dst->Register.Dimension) { /*FIXME: right now we don't support indirect * multidimensional addressing */ fill_scan_register2d(reg, dst->Register.File, dst->Register.Index, dst->Dimension.Index); } else { fill_scan_register1d(reg, dst->Register.File, dst->Register.Index); } }
static void scan_register_src(scan_register *reg, struct tgsi_full_src_register *src) { if (src->Register.Dimension) { /*FIXME: right now we don't support indirect * multidimensional addressing */ debug_assert(!src->Dimension.Indirect); fill_scan_register2d(reg, src->Register.File, src->Register.Index, src->Dimension.Index); } else { fill_scan_register1d(reg, src->Register.File, src->Register.Index); } }
static boolean iter_instruction( struct tgsi_iterate_context *iter, struct tgsi_full_instruction *inst ) { struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; const struct tgsi_opcode_info *info; uint i; if (inst->Instruction.Opcode == TGSI_OPCODE_END) { if (ctx->index_of_END != ~0) { report_error( ctx, "Too many END instructions" ); } ctx->index_of_END = ctx->num_instructions; } info = tgsi_get_opcode_info( inst->Instruction.Opcode ); if (!info) { report_error( ctx, "(%u): Invalid instruction opcode", inst->Instruction.Opcode ); return TRUE; } if (info->num_dst != inst->Instruction.NumDstRegs) { report_error( ctx, "%s: Invalid number of destination operands, should be %u", info->mnemonic, info->num_dst ); } if (info->num_src != inst->Instruction.NumSrcRegs) { report_error( ctx, "%s: Invalid number of source operands, should be %u", info->mnemonic, info->num_src ); } /* Check destination and source registers' validity. * Mark the registers as used. */ for (i = 0; i < inst->Instruction.NumDstRegs; i++) { scan_register *reg = create_scan_register_dst(&inst->Dst[i]); check_register_usage( ctx, reg, "destination", FALSE ); if (!inst->Dst[i].Register.WriteMask) { report_error(ctx, "Destination register has empty writemask"); } } for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { scan_register *reg = create_scan_register_src(&inst->Src[i]); check_register_usage( ctx, reg, "source", (boolean)inst->Src[i].Register.Indirect ); if (inst->Src[i].Register.Indirect) { scan_register *ind_reg = MALLOC(sizeof(scan_register)); fill_scan_register1d(ind_reg, inst->Src[i].Indirect.File, inst->Src[i].Indirect.Index); check_register_usage( ctx, ind_reg, "indirect", FALSE ); } } ctx->num_instructions++; return TRUE; }