Lots of vartable clean-ups, fixes. Report an error message when we run out

of registers, rather than crash.
This commit is contained in:
Brian 2007-01-28 12:49:47 -07:00
parent 602dc1a638
commit 4de6fac4da
5 changed files with 169 additions and 97 deletions

View file

@ -2141,13 +2141,13 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
{
slang_ir_node *n;
A->vartable = _slang_push_var_table(A->vartable);
_slang_push_var_table(A->vartable);
oper->type = slang_oper_block_no_new_scope; /* temp change */
n = _slang_gen_operation(A, oper);
oper->type = slang_oper_block_new_scope; /* restore */
A->vartable = _slang_pop_var_table(A->vartable);
_slang_pop_var_table(A->vartable);
if (n)
n = new_node(IR_SCOPE, n, NULL);
@ -2640,7 +2640,7 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
A->CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunc_main_");
/* push new vartable scope */
A->vartable = _slang_push_var_table(A->vartable);
_slang_push_var_table(A->vartable);
/* Generate IR tree for the function body code */
n = _slang_gen_operation(A, fun->body);
@ -2648,7 +2648,7 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
n = new_node(IR_SCOPE, n, NULL);
/* pop vartable, restore previous */
A->vartable = _slang_pop_var_table(A->vartable);
_slang_pop_var_table(A->vartable);
if (!n) {
/* XXX record error */

View file

@ -1978,8 +1978,20 @@ static GLboolean
parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
struct gl_program *program)
{
GET_CURRENT_CONTEXT(ctx);
slang_output_ctx o;
GLboolean success;
GLuint maxRegs;
if (unit->type == slang_unit_fragment_builtin ||
unit->type == slang_unit_fragment_shader) {
maxRegs = ctx->Const.FragmentProgram.MaxTemps;
}
else {
assert(unit->type == slang_unit_vertex_builtin ||
unit->type == slang_unit_vertex_shader);
maxRegs = ctx->Const.VertexProgram.MaxTemps;
}
/* setup output context */
o.funs = &unit->funs;
@ -1989,7 +2001,8 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit,
o.global_pool = &unit->object->varpool;
o.machine = &unit->object->machine;
o.program = program;
o.vartable = _slang_push_var_table(NULL);
o.vartable = _slang_new_var_table(maxRegs);
_slang_push_var_table(o.vartable);
/* parse individual functions and declarations */
while (*C->I != EXTERNAL_NULL) {

View file

@ -332,14 +332,17 @@ slang_print_ir(const slang_ir_node *n, int indent)
* Allocate temporary storage for an intermediate result (such as for
* a multiply or add, etc.
*/
static void
static GLboolean
alloc_temp_storage(slang_var_table *vt, slang_ir_node *n, GLint size)
{
assert(!n->Var);
assert(!n->Store);
assert(size > 0);
n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
(void) _slang_alloc_temp(vt, n->Store);
if (!_slang_alloc_temp(vt, n->Store)) {
RETURN_ERROR("Ran out of registers, too many temporaries", 0);
}
return GL_TRUE;
}
@ -634,7 +637,8 @@ emit_binop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
}
if (!n->Store) {
alloc_temp_storage(vt, n, info->ResultSize);
if (!alloc_temp_storage(vt, n, info->ResultSize))
return NULL;
}
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
@ -667,7 +671,8 @@ emit_unop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
free_temp_storage(vt, n->Children[0]);
if (!n->Store) {
alloc_temp_storage(vt, n, info->ResultSize);
if (!alloc_temp_storage(vt, n, info->ResultSize))
return NULL;
}
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
@ -691,7 +696,8 @@ emit_negation(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
emit(vt, n->Children[0], prog);
if (!n->Store)
alloc_temp_storage(vt, n, n->Children[0]->Store->Size);
if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
return NULL;
inst = new_instruction(prog, OPCODE_MOV);
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
@ -768,7 +774,8 @@ emit_tex(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
}
if (!n->Store)
alloc_temp_storage(vt, n, 4);
if (!alloc_temp_storage(vt, n, 4))
return NULL;
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
@ -880,7 +887,8 @@ emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
* Note: must use full 4-component vector since all four
* condition codes must be set identically.
*/
alloc_temp_storage(vt, n, 4);
if (!alloc_temp_storage(vt, n, 4))
return NULL;
inst = new_instruction(prog, OPCODE_MOV);
inst->CondUpdate = GL_TRUE;
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
@ -912,9 +920,9 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
case IR_SCOPE:
/* new variable scope */
vt = _slang_push_var_table(vt);
_slang_push_var_table(vt);
inst = emit(vt, n->Children[0], prog);
vt = _slang_pop_var_table(vt);
_slang_pop_var_table(vt);
return inst;
case IR_VAR_DECL:
@ -925,19 +933,20 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
assert(n->Store->Index < 0);
if (!n->Var || n->Var->isTemp) {
/* a nameless/temporary variable, will be freed after first use */
(void) _slang_alloc_temp(vt, n->Store);
if (!_slang_alloc_temp(vt, n->Store))
RETURN_ERROR("Ran out of registers, too many temporaries", 0);
}
else {
/* a regular variable */
_slang_add_variable(vt, n->Var);
(void) _slang_alloc_var(vt, n->Store);
if (!_slang_alloc_var(vt, n->Store))
RETURN_ERROR("Ran out of registers, too many variables", 0);
/*
printf("IR_VAR_DECL %s %d store %p\n",
(char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
*/
assert(n->Var->aux == n->Store);
}
assert(n->Store->Index >= 0);
break;
case IR_VAR:

View file

@ -16,96 +16,132 @@ typedef enum {
TEMP
} TempState;
static int Level = 0;
/**
* Variable/register info for one variable scope.
*/
struct table
{
int Level;
int NumVars;
slang_variable **Vars; /* array [NumVars] */
TempState Temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */
int ValSize[MAX_PROGRAM_TEMPS]; /* For debug only */
struct table *Parent; /** Parent scope table */
};
/**
* A variable table is a stack of tables, one per scope.
*/
struct slang_var_table_
{
int level;
int num_entries;
slang_variable **vars; /* array [num_entries] */
TempState temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */
int size[MAX_PROGRAM_TEMPS]; /* For debug only */
struct slang_var_table_ *parent;
GLint CurLevel;
GLuint MaxRegisters;
struct table *Top; /**< Table at top of stack */
};
slang_var_table *
_slang_new_var_table(GLuint maxRegisters)
{
slang_var_table *vt
= (slang_var_table *) _mesa_calloc(sizeof(slang_var_table));
if (vt) {
vt->MaxRegisters = maxRegisters;
}
return vt;
}
void
_slang_delete_var_table(slang_var_table *vt)
{
if (vt->Top) {
_mesa_problem(NULL, "non-empty var table in _slang_delete_var_table()");
return;
}
_mesa_free(vt);
}
/**
* Create new table, put at head, return ptr to it.
* XXX we should take a maxTemps parameter to indicate how many temporaries
* are available for the current shader/program target.
*/
slang_var_table *
_slang_push_var_table(slang_var_table *parent)
void
_slang_push_var_table(slang_var_table *vt)
{
slang_var_table *t
= (slang_var_table *) _mesa_calloc(sizeof(slang_var_table));
struct table *t = (struct table *) _mesa_calloc(sizeof(struct table));
if (t) {
t->level = Level++;
t->parent = parent;
if (parent) {
t->Level = vt->CurLevel++;
t->Parent = vt->Top;
if (t->Parent) {
/* copy the info indicating which temp regs are in use */
memcpy(t->temps, parent->temps, sizeof(t->temps));
memcpy(t->size, parent->size, sizeof(t->size));
memcpy(t->Temps, t->Parent->Temps, sizeof(t->Temps));
memcpy(t->ValSize, t->Parent->ValSize, sizeof(t->ValSize));
}
if (dbg) printf("Pushing level %d\n", t->level);
vt->Top = t;
if (dbg) printf("Pushing level %d\n", t->Level);
}
return t;
}
/**
* Destroy given table, return ptr to parent
* Destroy given table, return ptr to Parent
*/
slang_var_table *
_slang_pop_var_table(slang_var_table *t)
void
_slang_pop_var_table(slang_var_table *vt)
{
slang_var_table *parent = t->parent;
struct table *t = vt->Top;
int i;
if (dbg) printf("Popping level %d\n", t->level);
if (dbg) printf("Popping level %d\n", t->Level);
/* free the storage allocated for each variable */
for (i = 0; i < t->num_entries; i++) {
slang_ir_storage *store = (slang_ir_storage *) t->vars[i]->aux;
for (i = 0; i < t->NumVars; i++) {
slang_ir_storage *store = (slang_ir_storage *) t->Vars[i]->aux;
GLint j;
const GLuint sz = store->Size;
GLuint comp;
if (dbg) printf(" Free var %s, size %d at %d\n",
(char*) t->vars[i]->a_name, store->Size,
(char*) t->Vars[i]->a_name, store->Size,
store->Index);
if (sz == 1)
if (store->Size == 1)
comp = GET_SWZ(store->Swizzle, 0);
else
comp = 0;
assert(store->Index >= 0);
for (j = 0; j < sz; j++) {
assert(t->temps[store->Index * 4 + j + comp] == VAR);
t->temps[store->Index * 4 + j + comp] = FREE;
for (j = 0; j < store->Size; j++) {
assert(t->Temps[store->Index * 4 + j + comp] == VAR);
t->Temps[store->Index * 4 + j + comp] = FREE;
}
store->Index = -1;
}
if (t->parent) {
if (t->Parent) {
/* just verify that any remaining allocations in this scope
* were for temps
*/
for (i = 0; i < MAX_PROGRAM_TEMPS * 4; i++) {
if (t->temps[i] != FREE && t->parent->temps[i] == FREE) {
for (i = 0; i < vt->MaxRegisters * 4; i++) {
if (t->Temps[i] != FREE && t->Parent->Temps[i] == FREE) {
if (dbg) printf(" Free reg %d\n", i/4);
assert(t->temps[i] == TEMP);
assert(t->Temps[i] == TEMP);
}
}
}
if (t->vars)
free(t->vars);
if (t->Vars)
free(t->Vars);
vt->Top = t->Parent;
free(t);
Level--;
return parent;
vt->CurLevel--;
}
@ -113,31 +149,35 @@ _slang_pop_var_table(slang_var_table *t)
* Add a new variable to the given symbol table.
*/
void
_slang_add_variable(slang_var_table *t, slang_variable *v)
_slang_add_variable(slang_var_table *vt, slang_variable *v)
{
struct table *t;
assert(vt);
t = vt->Top;
assert(t);
if (dbg) printf("Adding var %s\n", (char *) v->a_name);
t->vars = realloc(t->vars, (t->num_entries + 1) * sizeof(slang_variable *));
t->vars[t->num_entries] = v;
t->num_entries++;
t->Vars = realloc(t->Vars, (t->NumVars + 1) * sizeof(slang_variable *));
t->Vars[t->NumVars] = v;
t->NumVars++;
}
/**
* Look for variable by name in given table.
* If not found, parent table will be searched.
* If not found, Parent table will be searched.
*/
slang_variable *
_slang_find_variable(const slang_var_table *t, slang_atom name)
_slang_find_variable(const slang_var_table *vt, slang_atom name)
{
struct table *t = vt->Top;
while (1) {
int i;
for (i = 0; i < t->num_entries; i++) {
if (t->vars[i]->a_name == name)
return t->vars[i];
for (i = 0; i < t->NumVars; i++) {
if (t->Vars[i]->a_name == name)
return t->Vars[i];
}
if (t->parent)
t = t->parent;
if (t->Parent)
t = t->Parent;
else
return NULL;
}
@ -150,17 +190,18 @@ _slang_find_variable(const slang_var_table *t, slang_atom name)
* \return position for var, measured in floats
*/
static GLint
alloc_reg(slang_var_table *t, GLint size, GLboolean isTemp)
alloc_reg(slang_var_table *vt, GLint size, GLboolean isTemp)
{
struct table *t = vt->Top;
/* if size == 1, allocate anywhere, else, pos must be multiple of 4 */
const GLuint step = (size == 1) ? 1 : 4;
GLuint i, j;
assert(size > 0); /* number of floats */
for (i = 0; i < MAX_PROGRAM_TEMPS - size; i += step) {
for (i = 0; i <= vt->MaxRegisters * 4 - size; i += step) {
GLuint found = 0;
for (j = 0; j < size; j++) {
if (i + j < MAX_PROGRAM_TEMPS && t->temps[i + j] == FREE) {
if (i + j < vt->MaxRegisters * 4 && t->Temps[i + j] == FREE) {
found++;
}
else {
@ -172,9 +213,8 @@ alloc_reg(slang_var_table *t, GLint size, GLboolean isTemp)
if (size > 1)
assert(i % 4 == 0);
for (j = 0; j < size; j++)
t->temps[i + j] = isTemp ? TEMP : VAR;
printf("t->size[%d] = %d\n", i, size);
t->size[i] = size;
t->Temps[i + j] = isTemp ? TEMP : VAR;
t->ValSize[i] = size;
return i;
}
}
@ -189,9 +229,10 @@ alloc_reg(slang_var_table *t, GLint size, GLboolean isTemp)
* \return register allocated, or -1
*/
GLboolean
_slang_alloc_var(slang_var_table *t, slang_ir_storage *store)
_slang_alloc_var(slang_var_table *vt, slang_ir_storage *store)
{
const int i = alloc_reg(t, store->Size, GL_FALSE);
struct table *t = vt->Top;
const int i = alloc_reg(vt, store->Size, GL_FALSE);
if (i < 0)
return GL_FALSE;
@ -200,12 +241,12 @@ _slang_alloc_var(slang_var_table *t, slang_ir_storage *store)
const GLuint comp = i % 4;
store->Swizzle = MAKE_SWIZZLE4(comp, comp, comp, comp);
if (dbg) printf("Alloc var sz %d at %d.%c (level %d)\n",
store->Size, store->Index, "xyzw"[comp], t->level);
store->Size, store->Index, "xyzw"[comp], t->Level);
}
else {
store->Swizzle = SWIZZLE_NOOP;
if (dbg) printf("Alloc var sz %d at %d.xyzw (level %d)\n",
store->Size, store->Index, t->level);
store->Size, store->Index, t->Level);
}
return GL_TRUE;
}
@ -216,9 +257,10 @@ _slang_alloc_var(slang_var_table *t, slang_ir_storage *store)
* Allocate temp register(s) for storing an unnamed intermediate value.
*/
GLboolean
_slang_alloc_temp(slang_var_table *t, slang_ir_storage *store)
_slang_alloc_temp(slang_var_table *vt, slang_ir_storage *store)
{
const int i = alloc_reg(t, store->Size, GL_TRUE);
struct table *t = vt->Top;
const int i = alloc_reg(vt, store->Size, GL_TRUE);
if (i < 0)
return GL_FALSE;
@ -227,57 +269,59 @@ _slang_alloc_temp(slang_var_table *t, slang_ir_storage *store)
const GLuint comp = i % 4;
store->Swizzle = MAKE_SWIZZLE4(comp, comp, comp, comp);
if (dbg) printf("Alloc temp sz %d at %d.%c (level %d)\n",
store->Size, store->Index, "xyzw"[comp], t->level);
store->Size, store->Index, "xyzw"[comp], t->Level);
}
else {
store->Swizzle = SWIZZLE_NOOP;
if (dbg) printf("Alloc temp sz %d at %d.xyzw (level %d)\n",
store->Size, store->Index, t->level);
store->Size, store->Index, t->Level);
}
return GL_TRUE;
}
void
_slang_free_temp(slang_var_table *t, slang_ir_storage *store)
_slang_free_temp(slang_var_table *vt, slang_ir_storage *store)
{
struct table *t = vt->Top;
GLuint i;
GLuint r = store->Index;
assert(store->Size > 0);
assert(r >= 0);
assert(r + store->Size <= MAX_PROGRAM_TEMPS);
if (dbg) printf("Free temp sz %d at %d (level %d)\n", store->Size, r, t->level);
assert(r + store->Size <= vt->MaxRegisters * 4);
if (dbg) printf("Free temp sz %d at %d (level %d)\n", store->Size, r, t->Level);
if (store->Size == 1) {
const GLuint comp = GET_SWZ(store->Swizzle, 0);
assert(store->Swizzle == MAKE_SWIZZLE4(comp, comp, comp, comp));
assert(comp < 4);
assert(t->size[r * 4 + comp] == 1);
assert(t->temps[r * 4 + comp] == TEMP);
t->temps[r * 4 + comp] = FREE;
assert(t->ValSize[r * 4 + comp] == 1);
assert(t->Temps[r * 4 + comp] == TEMP);
t->Temps[r * 4 + comp] = FREE;
}
else {
assert(store->Swizzle == SWIZZLE_NOOP);
assert(t->size[r*4] == store->Size);
assert(t->ValSize[r*4] == store->Size);
for (i = 0; i < store->Size; i++) {
assert(t->temps[r * 4 + i] == TEMP);
t->temps[r * 4 + i] = FREE;
assert(t->Temps[r * 4 + i] == TEMP);
t->Temps[r * 4 + i] = FREE;
}
}
}
GLboolean
_slang_is_temp(slang_var_table *t, slang_ir_storage *store)
_slang_is_temp(const slang_var_table *vt, const slang_ir_storage *store)
{
struct table *t = vt->Top;
assert(store->Index >= 0);
assert(store->Index < MAX_PROGRAM_TEMPS);
assert(store->Index < vt->MaxRegisters);
GLuint comp;
if (store->Swizzle == SWIZZLE_NOOP)
comp = 0;
else
comp = GET_SWZ(store->Swizzle, 0);
if (t->temps[store->Index * 4 + comp] == TEMP)
if (t->Temps[store->Index * 4 + comp] == TEMP)
return GL_TRUE;
else
return GL_FALSE;

View file

@ -9,9 +9,15 @@ typedef struct slang_var_table_ slang_var_table;
struct slang_variable_;
extern slang_var_table *
_slang_new_var_table(GLuint maxRegisters);
extern void
_slang_delete_var_table(slang_var_table *vt);
extern void
_slang_push_var_table(slang_var_table *parent);
extern slang_var_table *
extern void
_slang_pop_var_table(slang_var_table *t);
extern void
@ -30,7 +36,7 @@ extern void
_slang_free_temp(slang_var_table *t, struct _slang_ir_storage *store);
extern GLboolean
_slang_is_temp(slang_var_table *t, struct _slang_ir_storage *store);
_slang_is_temp(const slang_var_table *t, const struct _slang_ir_storage *store);
#endif /* SLANG_VARTABLE_H */