From 4de6fac4daecac25bb3f4339610312022b457b46 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 28 Jan 2007 12:49:47 -0700 Subject: Lots of vartable clean-ups, fixes. Report an error message when we run out of registers, rather than crash. --- src/mesa/shader/slang/slang_codegen.c | 8 +- src/mesa/shader/slang/slang_compile.c | 15 ++- src/mesa/shader/slang/slang_emit.c | 33 ++++-- src/mesa/shader/slang/slang_vartable.c | 198 ++++++++++++++++++++------------- src/mesa/shader/slang/slang_vartable.h | 10 +- 5 files changed, 168 insertions(+), 96 deletions(-) (limited to 'src/mesa/shader/slang') diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index ff42db9def..3dc4fb36e7 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -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 */ diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index c459eb29e7..43f8a30369 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -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) { diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index a4c1c2fad7..e9cbb895f8 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -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: diff --git a/src/mesa/shader/slang/slang_vartable.c b/src/mesa/shader/slang/slang_vartable.c index 0271455428..1299696670 100644 --- a/src/mesa/shader/slang/slang_vartable.c +++ b/src/mesa/shader/slang/slang_vartable.c @@ -16,96 +16,132 @@ typedef enum { TEMP } TempState; -static int Level = 0; -struct slang_var_table_ +/** + * Variable/register info for one variable scope. + */ +struct table { - int level; - int num_entries; - slang_variable **vars; /* array [num_entries] */ + int Level; + int NumVars; + slang_variable **Vars; /* array [NumVars] */ - TempState temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */ - int size[MAX_PROGRAM_TEMPS]; /* For debug only */ + TempState Temps[MAX_PROGRAM_TEMPS * 4]; /* per-component state */ + int ValSize[MAX_PROGRAM_TEMPS]; /* For debug only */ - struct slang_var_table_ *parent; + struct table *Parent; /** Parent scope table */ }; +/** + * A variable table is a stack of tables, one per scope. + */ +struct slang_var_table_ +{ + 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; diff --git a/src/mesa/shader/slang/slang_vartable.h b/src/mesa/shader/slang/slang_vartable.h index 51c2a1f77c..8a3b992c96 100644 --- a/src/mesa/shader/slang/slang_vartable.h +++ b/src/mesa/shader/slang/slang_vartable.h @@ -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 */ -- cgit v1.2.3