tgsi: add missing support for two dimensional arrays in various places

in particular asm text parsing and sanity checking were missing code
to handle multi-dimensional arrays/geometry shaders
This commit is contained in:
Zack Rusin 2009-12-23 12:40:39 -05:00
parent 8a39f5dfdd
commit 22370990f2
3 changed files with 500 additions and 211 deletions

View file

@ -183,6 +183,12 @@ _dump_register(
int last )
{
ENM( file, file_names );
/* all geometry shader inputs are two dimensional */
if (file == TGSI_FILE_INPUT &&
ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY)
TXT("[]");
CHR( '[' );
SID( first );
if (first != last) {

View file

@ -26,32 +26,112 @@
**************************************************************************/
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "pipe/p_inlines.h"
#include "cso_cache/cso_hash.h"
#include "tgsi_sanity.h"
#include "tgsi_info.h"
#include "tgsi_iterate.h"
typedef uint reg_flag;
#define BITS_IN_REG_FLAG (sizeof( reg_flag ) * 8)
#define MAX_REGISTERS 1024
#define MAX_REG_FLAGS ((MAX_REGISTERS + BITS_IN_REG_FLAG - 1) / BITS_IN_REG_FLAG)
typedef struct {
uint file : 28;
/* max 2 dimensions */
uint dimensions : 4;
uint indices[2];
} scan_register;
struct sanity_check_ctx
{
struct tgsi_iterate_context iter;
struct cso_hash *regs_decl;
struct cso_hash *regs_used;
struct cso_hash *regs_ind_used;
reg_flag regs_decl[TGSI_FILE_COUNT][MAX_REG_FLAGS];
reg_flag regs_used[TGSI_FILE_COUNT][MAX_REG_FLAGS];
boolean regs_ind_used[TGSI_FILE_COUNT];
uint num_imms;
uint num_instructions;
uint index_of_END;
uint errors;
uint warnings;
uint implied_array_size;
};
static INLINE unsigned
scan_register_key(const scan_register *reg)
{
unsigned key = reg->file;
key |= (reg->indices[0] << 4);
key |= (reg->indices[1] << 18);
return key;
}
static void
fill_scan_register1d(scan_register *reg,
uint file, uint index)
{
reg->file = file;
reg->dimensions = 1;
reg->indices[0] = index;
reg->indices[1] = 0;
}
static void
fill_scan_register2d(scan_register *reg,
uint file, uint index1, uint index2)
{
reg->file = file;
reg->dimensions = 2;
reg->indices[0] = index1;
reg->indices[1] = index2;
}
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 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 scan_register *
create_scan_register_src(struct tgsi_full_src_register *src)
{
scan_register *reg = MALLOC(sizeof(scan_register));
scan_register_src(reg, src);
return reg;
}
static scan_register *
create_scan_register_dst(struct tgsi_full_dst_register *dst)
{
scan_register *reg = MALLOC(sizeof(scan_register));
scan_register_dst(reg, dst);
return reg;
}
static void
report_error(
struct sanity_check_ctx *ctx,
@ -99,12 +179,12 @@ check_file_name(
static boolean
is_register_declared(
struct sanity_check_ctx *ctx,
uint file,
int index )
const scan_register *reg)
{
assert( index >= 0 && index < MAX_REGISTERS );
return (ctx->regs_decl[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE;
void *data = cso_hash_find_data_from_template(
ctx->regs_decl, scan_register_key(reg),
(void*)reg, sizeof(scan_register));
return data ? TRUE : FALSE;
}
static boolean
@ -112,23 +192,37 @@ is_any_register_declared(
struct sanity_check_ctx *ctx,
uint file )
{
uint i;
struct cso_hash_iter iter =
cso_hash_first_node(ctx->regs_decl);
for (i = 0; i < MAX_REG_FLAGS; i++)
if (ctx->regs_decl[file][i])
while (cso_hash_iter_is_null(iter)) {
scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
if (reg->file == file)
return TRUE;
iter = cso_hash_iter_next(iter);
}
return FALSE;
}
static boolean
is_register_used(
struct sanity_check_ctx *ctx,
uint file,
int index )
scan_register *reg)
{
assert( index < MAX_REGISTERS );
void *data = cso_hash_find_data_from_template(
ctx->regs_used, scan_register_key(reg),
reg, sizeof(scan_register));
return data ? TRUE : FALSE;
}
return (ctx->regs_used[file][index / BITS_IN_REG_FLAG] & (1 << (index % BITS_IN_REG_FLAG))) ? TRUE : FALSE;
static boolean
is_ind_register_used(
struct sanity_check_ctx *ctx,
scan_register *reg)
{
return cso_hash_contains(ctx->regs_ind_used, reg->file);
}
static const char *file_names[TGSI_FILE_COUNT] =
@ -148,31 +242,40 @@ static const char *file_names[TGSI_FILE_COUNT] =
static boolean
check_register_usage(
struct sanity_check_ctx *ctx,
uint file,
int index,
scan_register *reg,
const char *name,
boolean indirect_access )
{
if (!check_file_name( ctx, file ))
if (!check_file_name( ctx, reg->file )) {
free(reg);
return FALSE;
}
if (indirect_access) {
/* Note that 'index' is an offset relative to the value of the
* address register. No range checking done here.
*/
if (!is_any_register_declared( ctx, file ))
report_error( ctx, "%s: Undeclared %s register", file_names[file], name );
ctx->regs_ind_used[file] = TRUE;
* address register. No range checking done here.*/
reg->indices[0] = 0;
reg->indices[1] = 0;
if (!is_any_register_declared( ctx, reg->file ))
report_error( ctx, "%s: Undeclared %s register", file_names[reg->file], name );
if (!is_ind_register_used(ctx, reg))
cso_hash_insert(ctx->regs_ind_used, reg->file, reg);
else
free(reg);
}
else {
if (index < 0 || index >= MAX_REGISTERS) {
report_error( ctx, "%s[%d]: Invalid %s index", file_names[file], index, name );
return FALSE;
}
if (!is_register_declared( ctx, file, index ))
report_error( ctx, "%s[%d]: Undeclared %s register", file_names[file], index, name );
ctx->regs_used[file][index / BITS_IN_REG_FLAG] |= (1 << (index % BITS_IN_REG_FLAG));
if (!is_register_declared( ctx, reg )) {
if (reg->dimensions == 2)
report_error( ctx, "%s[%d][%d]: Undeclared %s register", file_names[reg->file],
reg->indices[0], reg->indices[1], name );
else
report_error( ctx, "%s[%d]: Undeclared %s register", file_names[reg->file],
reg->indices[0], name );
}
if (!is_register_used( ctx, reg ))
cso_hash_insert(ctx->regs_used, scan_register_key(reg), reg);
else
free(reg);
}
return TRUE;
}
@ -210,33 +313,33 @@ iter_instruction(
* 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,
inst->Dst[i].Register.File,
inst->Dst[i].Register.Index,
reg,
"destination",
FALSE );
}
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
scan_register *reg = create_scan_register_src(&inst->Src[i]);
check_register_usage(
ctx,
inst->Src[i].Register.File,
inst->Src[i].Register.Index,
reg,
"source",
(boolean)inst->Src[i].Register.Indirect );
if (inst->Src[i].Register.Indirect) {
uint file;
int index;
scan_register *ind_reg = MALLOC(sizeof(scan_register));
file = inst->Src[i].Indirect.File;
index = inst->Src[i].Indirect.Index;
fill_scan_register1d(ind_reg,
inst->Src[i].Indirect.File,
inst->Src[i].Indirect.Index);
check_register_usage(
ctx,
file,
index,
reg,
"indirect",
FALSE );
if (!(file == TGSI_FILE_ADDRESS || file == TGSI_FILE_LOOP) || index != 0) {
if (!(reg->file == TGSI_FILE_ADDRESS || reg->file == TGSI_FILE_LOOP) ||
reg->indices[0] != 0) {
report_warning(ctx, "Indirect register neither ADDR[0] nor LOOP[0]");
}
}
@ -266,6 +369,19 @@ iter_instruction(
return TRUE;
}
static void
check_and_declare(struct sanity_check_ctx *ctx,
scan_register *reg)
{
if (is_register_declared( ctx, reg))
report_error( ctx, "%s[%u]: The same register declared more than once",
file_names[reg->file], reg->indices[0] );
cso_hash_insert(ctx->regs_decl,
scan_register_key(reg),
reg);
}
static boolean
iter_declaration(
struct tgsi_iterate_context *iter,
@ -287,9 +403,21 @@ iter_declaration(
if (!check_file_name( ctx, file ))
return TRUE;
for (i = decl->Range.First; i <= decl->Range.Last; i++) {
if (is_register_declared( ctx, file, i ))
report_error( ctx, "%s[%u]: The same register declared more than once", file_names[file], i );
ctx->regs_decl[file][i / BITS_IN_REG_FLAG] |= (1 << (i % BITS_IN_REG_FLAG));
/* declared TGSI_FILE_INPUT's for geometry processor
* have an implied second dimension */
if (file == TGSI_FILE_INPUT &&
ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
uint vert;
for (vert = 0; vert < ctx->implied_array_size; ++vert) {
scan_register *reg = MALLOC(sizeof(scan_register));
fill_scan_register2d(reg, file, vert, i);
check_and_declare(ctx, reg);
}
} else {
scan_register *reg = MALLOC(sizeof(scan_register));
fill_scan_register1d(reg, file, i);
check_and_declare(ctx, reg);
}
}
return TRUE;
@ -301,8 +429,7 @@ iter_immediate(
struct tgsi_full_immediate *imm )
{
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
assert( ctx->num_imms < MAX_REGISTERS );
scan_register *reg;
/* No immediates allowed after the first instruction.
*/
@ -311,7 +438,9 @@ iter_immediate(
/* Mark the register as declared.
*/
ctx->regs_decl[TGSI_FILE_IMMEDIATE][ctx->num_imms / BITS_IN_REG_FLAG] |= (1 << (ctx->num_imms % BITS_IN_REG_FLAG));
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.
@ -330,8 +459,13 @@ iter_property(
struct tgsi_iterate_context *iter,
struct tgsi_full_property *prop )
{
/*struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;*/
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY &&
prop->Property.PropertyName == TGSI_PROPERTY_GS_INPUT_PRIM) {
ctx->implied_array_size =
pipe_vertices_per_primitive(prop->u[0].Data);
}
return TRUE;
}
@ -340,7 +474,6 @@ epilog(
struct tgsi_iterate_context *iter )
{
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter;
uint file;
/* There must be an END instruction somewhere.
*/
@ -350,13 +483,17 @@ epilog(
/* Check if all declared registers were used.
*/
for (file = TGSI_FILE_NULL; file < TGSI_FILE_COUNT; file++) {
uint i;
{
struct cso_hash_iter iter =
cso_hash_first_node(ctx->regs_decl);
for (i = 0; i < MAX_REGISTERS; i++) {
if (is_register_declared( ctx, file, i ) && !is_register_used( ctx, file, i ) && !ctx->regs_ind_used[file]) {
report_warning( ctx, "%s[%u]: Register never used", file_names[file], i );
while (cso_hash_iter_is_null(iter)) {
scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
if (!is_register_used(ctx, reg) && !is_ind_register_used(ctx, reg)) {
report_warning( ctx, "%s[%u]: Register never used",
file_names[reg->file], reg->indices[0] );
}
iter = cso_hash_iter_next(iter);
}
}
@ -368,6 +505,18 @@ epilog(
return TRUE;
}
static void
regs_hash_destroy(struct cso_hash *hash)
{
struct cso_hash_iter iter = cso_hash_first_node(hash);
while (!cso_hash_iter_is_null(iter)) {
scan_register *reg = (scan_register *)cso_hash_iter_data(iter);
iter = cso_hash_erase(hash, iter);
free(reg);
}
cso_hash_delete(hash);
}
boolean
tgsi_sanity_check(
const struct tgsi_token *tokens )
@ -381,18 +530,23 @@ tgsi_sanity_check(
ctx.iter.iterate_property = iter_property;
ctx.iter.epilog = epilog;
memset( ctx.regs_decl, 0, sizeof( ctx.regs_decl ) );
memset( ctx.regs_used, 0, sizeof( ctx.regs_used ) );
memset( ctx.regs_ind_used, 0, sizeof( ctx.regs_ind_used ) );
ctx.regs_decl = cso_hash_create();
ctx.regs_used = cso_hash_create();
ctx.regs_ind_used = cso_hash_create();
ctx.num_imms = 0;
ctx.num_instructions = 0;
ctx.index_of_END = ~0;
ctx.errors = 0;
ctx.warnings = 0;
ctx.implied_array_size = 0;
if (!tgsi_iterate_shader( tokens, &ctx.iter ))
return FALSE;
regs_hash_destroy(ctx.regs_decl);
regs_hash_destroy(ctx.regs_used);
regs_hash_destroy(ctx.regs_ind_used);
return ctx.errors == 0;
}

View file

@ -28,6 +28,7 @@
#include "util/u_debug.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "pipe/p_inlines.h"
#include "tgsi_text.h"
#include "tgsi_build.h"
#include "tgsi_info.h"
@ -193,6 +194,8 @@ struct translate_ctx
struct tgsi_token *tokens_cur;
struct tgsi_token *tokens_end;
struct tgsi_header *header;
unsigned processor : 4;
int implied_array_size : 5;
};
static void report_error( struct translate_ctx *ctx, const char *msg )
@ -242,6 +245,7 @@ static boolean parse_header( struct translate_ctx *ctx )
if (ctx->tokens_cur >= ctx->tokens_end)
return FALSE;
*(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
ctx->processor = processor;
return TRUE;
}
@ -338,6 +342,125 @@ parse_opt_writemask(
return TRUE;
}
static boolean
parse_register_dst( struct translate_ctx *ctx,
uint *file,
int *index );
struct parsed_src_bracket {
int index;
uint ind_file;
int ind_index;
uint ind_comp;
};
static boolean
parse_register_src_bracket(
struct translate_ctx *ctx,
struct parsed_src_bracket *brackets)
{
const char *cur;
uint uindex;
memset(brackets, 0, sizeof(struct parsed_src_bracket));
eat_opt_white( &ctx->cur );
cur = ctx->cur;
if (parse_file( &cur, &brackets->ind_file )) {
if (!parse_register_dst( ctx, &brackets->ind_file,
&brackets->ind_index ))
return FALSE;
eat_opt_white( &ctx->cur );
if (*ctx->cur == '.') {
ctx->cur++;
eat_opt_white(&ctx->cur);
switch (uprcase(*ctx->cur)) {
case 'X':
brackets->ind_comp = TGSI_SWIZZLE_X;
break;
case 'Y':
brackets->ind_comp = TGSI_SWIZZLE_Y;
break;
case 'Z':
brackets->ind_comp = TGSI_SWIZZLE_Z;
break;
case 'W':
brackets->ind_comp = TGSI_SWIZZLE_W;
break;
default:
report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
return FALSE;
}
ctx->cur++;
eat_opt_white(&ctx->cur);
}
if (*ctx->cur == '+' || *ctx->cur == '-') {
boolean negate;
negate = *ctx->cur == '-';
ctx->cur++;
eat_opt_white( &ctx->cur );
if (!parse_uint( &ctx->cur, &uindex )) {
report_error( ctx, "Expected literal unsigned integer" );
return FALSE;
}
if (negate)
brackets->index = -(int) uindex;
else
brackets->index = (int) uindex;
}
else {
brackets->index = 0;
}
}
else {
if (!parse_uint( &ctx->cur, &uindex )) {
report_error( ctx, "Expected literal unsigned integer" );
return FALSE;
}
brackets->index = (int) uindex;
brackets->ind_file = TGSI_FILE_NULL;
brackets->ind_index = 0;
}
eat_opt_white( &ctx->cur );
if (*ctx->cur != ']') {
report_error( ctx, "Expected `]'" );
return FALSE;
}
ctx->cur++;
return TRUE;
}
static boolean
parse_opt_register_src_bracket(
struct translate_ctx *ctx,
struct parsed_src_bracket *brackets,
int *parsed_brackets)
{
const char *cur = ctx->cur;
*parsed_brackets = 0;
eat_opt_white( &cur );
if (cur[0] == '[') {
++cur;
ctx->cur = cur;
if (!parse_register_src_bracket(ctx, brackets))
return FALSE;
*parsed_brackets = 1;
}
return TRUE;
}
/* <register_file_bracket> ::= <file> `['
*/
static boolean
@ -379,6 +502,128 @@ parse_register_file_bracket_index(
return TRUE;
}
/* Parse source register operand.
* <register_src> ::= <register_file_bracket_index> `]' |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
*/
static boolean
parse_register_src(
struct translate_ctx *ctx,
uint *file,
struct parsed_src_bracket *brackets)
{
brackets->ind_comp = TGSI_SWIZZLE_X;
if (!parse_register_file_bracket( ctx, file ))
return FALSE;
if (!parse_register_src_bracket( ctx, brackets ))
return FALSE;
return TRUE;
}
struct parsed_dcl_bracket {
uint first;
uint last;
};
static boolean
parse_register_dcl_bracket(
struct translate_ctx *ctx,
struct parsed_dcl_bracket *bracket)
{
uint uindex;
memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
eat_opt_white( &ctx->cur );
if (!parse_uint( &ctx->cur, &uindex )) {
/* it can be an empty bracket [] which means its range
* is from 0 to some implied size */
if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
bracket->first = 0;
bracket->last = ctx->implied_array_size - 1;
goto cleanup;
}
report_error( ctx, "Expected literal unsigned integer" );
return FALSE;
}
bracket->first = (int) uindex;
eat_opt_white( &ctx->cur );
if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
uint uindex;
ctx->cur += 2;
eat_opt_white( &ctx->cur );
if (!parse_uint( &ctx->cur, &uindex )) {
report_error( ctx, "Expected literal integer" );
return FALSE;
}
bracket->last = (int) uindex;
eat_opt_white( &ctx->cur );
}
else {
bracket->last = bracket->first;
}
cleanup:
if (*ctx->cur != ']') {
report_error( ctx, "Expected `]' or `..'" );
return FALSE;
}
ctx->cur++;
return TRUE;
}
/* Parse register declaration.
* <register_dcl> ::= <register_file_bracket_index> `]' |
* <register_file_bracket_index> `..' <index> `]'
*/
static boolean
parse_register_dcl(
struct translate_ctx *ctx,
uint *file,
struct parsed_dcl_bracket *brackets,
int *num_brackets)
{
const char *cur;
*num_brackets = 0;
if (!parse_register_file_bracket( ctx, file ))
return FALSE;
if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
return FALSE;
*num_brackets = 1;
cur = ctx->cur;
eat_opt_white( &cur );
if (cur[0] == '[') {
++cur;
ctx->cur = cur;
if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
return FALSE;
/* for geometry shader we don't really care about
* the first brackets it's always the size of the
* input primitive. so we want to declare just
* the index relevant to the semantics which is in
* the second bracket */
if (ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
brackets[0] = brackets[1];
}
*num_brackets = 2;
}
return TRUE;
}
/* Parse destination register operand.
* <register_dst> ::= <register_file_bracket_index> `]'
*/
@ -399,134 +644,6 @@ parse_register_dst(
return TRUE;
}
/* Parse source register operand.
* <register_src> ::= <register_file_bracket_index> `]' |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
*/
static boolean
parse_register_src(
struct translate_ctx *ctx,
uint *file,
int *index,
uint *ind_file,
int *ind_index,
uint *ind_comp)
{
const char *cur;
uint uindex;
*ind_comp = TGSI_SWIZZLE_X;
if (!parse_register_file_bracket( ctx, file ))
return FALSE;
eat_opt_white( &ctx->cur );
cur = ctx->cur;
if (parse_file( &cur, ind_file )) {
if (!parse_register_dst( ctx, ind_file, ind_index ))
return FALSE;
eat_opt_white( &ctx->cur );
if (*ctx->cur == '.') {
ctx->cur++;
eat_opt_white(&ctx->cur);
switch (uprcase(*ctx->cur)) {
case 'X':
*ind_comp = TGSI_SWIZZLE_X;
break;
case 'Y':
*ind_comp = TGSI_SWIZZLE_Y;
break;
case 'Z':
*ind_comp = TGSI_SWIZZLE_Z;
break;
case 'W':
*ind_comp = TGSI_SWIZZLE_W;
break;
default:
report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
return FALSE;
}
ctx->cur++;
eat_opt_white(&ctx->cur);
}
if (*ctx->cur == '+' || *ctx->cur == '-') {
boolean negate;
negate = *ctx->cur == '-';
ctx->cur++;
eat_opt_white( &ctx->cur );
if (!parse_uint( &ctx->cur, &uindex )) {
report_error( ctx, "Expected literal unsigned integer" );
return FALSE;
}
if (negate)
*index = -(int) uindex;
else
*index = (int) uindex;
}
else {
*index = 0;
}
}
else {
if (!parse_uint( &ctx->cur, &uindex )) {
report_error( ctx, "Expected literal unsigned integer" );
return FALSE;
}
*index = (int) uindex;
*ind_file = TGSI_FILE_NULL;
*ind_index = 0;
}
eat_opt_white( &ctx->cur );
if (*ctx->cur != ']') {
report_error( ctx, "Expected `]'" );
return FALSE;
}
ctx->cur++;
return TRUE;
}
/* Parse register declaration.
* <register_dcl> ::= <register_file_bracket_index> `]' |
* <register_file_bracket_index> `..' <index> `]'
*/
static boolean
parse_register_dcl(
struct translate_ctx *ctx,
uint *file,
int *first,
int *last )
{
if (!parse_register_file_bracket_index( ctx, file, first ))
return FALSE;
eat_opt_white( &ctx->cur );
if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
uint uindex;
ctx->cur += 2;
eat_opt_white( &ctx->cur );
if (!parse_uint( &ctx->cur, &uindex )) {
report_error( ctx, "Expected literal integer" );
return FALSE;
}
*last = (int) uindex;
eat_opt_white( &ctx->cur );
}
else {
*last = *first;
}
if (*ctx->cur != ']') {
report_error( ctx, "Expected `]' or `..'" );
return FALSE;
}
ctx->cur++;
return TRUE;
}
static boolean
parse_dst_operand(
struct translate_ctx *ctx,
@ -595,37 +712,44 @@ parse_src_operand(
struct tgsi_full_src_register *src )
{
uint file;
int index;
uint ind_file;
int ind_index;
uint ind_comp;
uint swizzle[4];
boolean parsed_swizzle;
struct parsed_src_bracket bracket[2];
int parsed_opt_brackets;
if (*ctx->cur == '-') {
ctx->cur++;
eat_opt_white( &ctx->cur );
src->Register.Negate = 1;
}
if (*ctx->cur == '|') {
ctx->cur++;
eat_opt_white( &ctx->cur );
src->Register.Absolute = 1;
}
if (!parse_register_src(ctx, &file, &index, &ind_file, &ind_index, &ind_comp))
if (!parse_register_src(ctx, &file, &bracket[0]))
return FALSE;
if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
return FALSE;
src->Register.File = file;
src->Register.Index = index;
if (ind_file != TGSI_FILE_NULL) {
src->Register.Index = bracket[0].index;
if (bracket[0].ind_file != TGSI_FILE_NULL) {
src->Register.Indirect = 1;
src->Indirect.File = ind_file;
src->Indirect.Index = ind_index;
src->Indirect.SwizzleX = ind_comp;
src->Indirect.SwizzleY = ind_comp;
src->Indirect.SwizzleZ = ind_comp;
src->Indirect.SwizzleW = ind_comp;
src->Indirect.File = bracket[0].ind_file;
src->Indirect.Index = bracket[0].ind_index;
src->Indirect.SwizzleX = bracket[0].ind_comp;
src->Indirect.SwizzleY = bracket[0].ind_comp;
src->Indirect.SwizzleZ = bracket[0].ind_comp;
src->Indirect.SwizzleW = bracket[0].ind_comp;
}
if (parsed_opt_brackets) {
src->Register.Dimension = 1;
src->Dimension.Indirect = 0;
src->Dimension.Dimension = 0;
src->Dimension.Index = bracket[1].index;
}
/* Parse optional swizzle.
@ -820,8 +944,8 @@ static boolean parse_declaration( struct translate_ctx *ctx )
{
struct tgsi_full_declaration decl;
uint file;
int first;
int last;
struct parsed_dcl_bracket brackets[2];
int num_brackets;
uint writemask;
const char *cur;
uint advance;
@ -833,7 +957,7 @@ static boolean parse_declaration( struct translate_ctx *ctx )
report_error( ctx, "Syntax error" );
return FALSE;
}
if (!parse_register_dcl( ctx, &file, &first, &last ))
if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
return FALSE;
if (!parse_opt_writemask( ctx, &writemask ))
return FALSE;
@ -841,8 +965,8 @@ static boolean parse_declaration( struct translate_ctx *ctx )
decl = tgsi_default_full_declaration();
decl.Declaration.File = file;
decl.Declaration.UsageMask = writemask;
decl.Range.First = first;
decl.Range.Last = last;
decl.Range.First = brackets[0].first;
decl.Range.Last = brackets[0].last;
cur = ctx->cur;
eat_opt_white( &cur );
@ -1059,6 +1183,11 @@ static boolean parse_property( struct translate_ctx *ctx )
report_error( ctx, "Unknown primitive name as property!" );
return FALSE;
}
if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
ctx->implied_array_size =
pipe_vertices_per_primitive(values[0]);
}
break;
default:
if (!parse_uint(&ctx->cur, &values[0] )) {