Lots of vartable clean-ups, fixes. Report an error message when we run out
authorBrian <brian@yutani.localnet.net>
Sun, 28 Jan 2007 19:49:47 +0000 (12:49 -0700)
committerBrian <brian@yutani.localnet.net>
Sun, 28 Jan 2007 19:49:47 +0000 (12:49 -0700)
of registers, rather than crash.

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_compile.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_vartable.c
src/mesa/shader/slang/slang_vartable.h

index ff42db9def50fb8f3f71e35d5652476fdb20e03e..3dc4fb36e719f09909b2afeaecb7a36861ba6386 100644 (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 */
index c459eb29e744a72baea680004c666cc59bf3a7f0..43f8a303698c5c33ebf9fce7bcda68a8c9f308cf 100644 (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) {
index a4c1c2fad70ab2a718320416808618d1d07ec380..e9cbb895f85738f978abaff33c66bec330b3407f 100644 (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:
index 0271455428200a6efa37363f41b8050167effeed..1299696670414c648faa53a92e621dd1c4471447 100644 (file)
@@ -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;
index 51c2a1f77c5109bce3a7e6f084303941a5006c90..8a3b992c9696df474d35e66741ff88843f1bf886 100644 (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 */