OSDN Git Service

8a3c299d19cad48c6fe33975f785e45d82f21fe7
[android-x86/external-mesa.git] / src / mesa / shader / slang / slang_vartable.c
1
2 #include "imports.h"
3 #include "slang_compile.h"
4 #include "slang_compile_variable.h"
5 #include "slang_mem.h"
6 #include "slang_vartable.h"
7 #include "slang_ir.h"
8 #include "prog_instruction.h"
9
10
11 static int dbg = 0;
12
13
14 typedef enum {
15    FREE,
16    VAR,
17    TEMP
18 } TempState;
19
20
21 /**
22  * Variable/register info for one variable scope.
23  */
24 struct table
25 {
26    int Level;
27    int NumVars;
28    slang_variable **Vars;  /* array [NumVars] */
29
30    TempState Temps[MAX_PROGRAM_TEMPS * 4];  /* per-component state */
31    int ValSize[MAX_PROGRAM_TEMPS];     /* For debug only */
32
33    struct table *Parent;  /** Parent scope table */
34 };
35
36
37 /**
38  * A variable table is a stack of tables, one per scope.
39  */
40 struct slang_var_table_
41 {
42    GLint CurLevel;
43    GLuint MaxRegisters;
44    struct table *Top;  /**< Table at top of stack */
45 };
46
47
48
49 slang_var_table *
50 _slang_new_var_table(GLuint maxRegisters)
51 {
52    slang_var_table *vt
53       = (slang_var_table *) _slang_alloc(sizeof(slang_var_table));
54    if (vt) {
55       vt->MaxRegisters = maxRegisters;
56    }
57    return vt;
58 }
59
60
61 void
62 _slang_delete_var_table(slang_var_table *vt)
63 {
64    if (vt->Top) {
65       _mesa_problem(NULL, "non-empty var table in _slang_delete_var_table()");
66       return;
67    }
68    _slang_free(vt);
69 }
70
71
72
73 /**
74  * Create new table, put at head, return ptr to it.
75  * XXX we should take a maxTemps parameter to indicate how many temporaries
76  * are available for the current shader/program target.
77  */
78 void
79 _slang_push_var_table(slang_var_table *vt)
80 {
81    struct table *t = (struct table *) _slang_alloc(sizeof(struct table));
82    if (t) {
83       t->Level = vt->CurLevel++;
84       t->Parent = vt->Top;
85       if (t->Parent) {
86          /* copy the info indicating which temp regs are in use */
87          memcpy(t->Temps, t->Parent->Temps, sizeof(t->Temps));
88          memcpy(t->ValSize, t->Parent->ValSize, sizeof(t->ValSize));
89       }
90       vt->Top = t;
91       if (dbg) printf("Pushing level %d\n", t->Level);
92    }
93 }
94
95
96 /**
97  * Destroy given table, return ptr to Parent
98  */
99 void
100 _slang_pop_var_table(slang_var_table *vt)
101 {
102    struct table *t = vt->Top;
103    int i;
104
105    if (dbg) printf("Popping level %d\n", t->Level);
106
107    /* free the storage allocated for each variable */
108    for (i = 0; i < t->NumVars; i++) {
109       slang_ir_storage *store = (slang_ir_storage *) t->Vars[i]->aux;
110       GLint j;
111       GLuint comp;
112       if (dbg) printf("  Free var %s, size %d at %d\n",
113                       (char*) t->Vars[i]->a_name, store->Size,
114                       store->Index);
115
116       if (store->Size == 1)
117          comp = GET_SWZ(store->Swizzle, 0);
118       else
119          comp = 0;
120
121       assert(store->Index >= 0);
122       for (j = 0; j < store->Size; j++) {
123          assert(t->Temps[store->Index * 4 + j + comp] == VAR);
124          t->Temps[store->Index * 4 + j + comp] = FREE;
125       }
126       store->Index = -1;
127    }
128    if (t->Parent) {
129       /* just verify that any remaining allocations in this scope 
130        * were for temps
131        */
132       for (i = 0; i < vt->MaxRegisters * 4; i++) {
133          if (t->Temps[i] != FREE && t->Parent->Temps[i] == FREE) {
134             if (dbg) printf("  Free reg %d\n", i/4);
135             assert(t->Temps[i] == TEMP);
136          }
137       }
138    }
139
140    if (t->Vars) {
141       _slang_free(t->Vars);
142       t->Vars = NULL;
143    }
144
145    vt->Top = t->Parent;
146    _slang_free(t);
147    vt->CurLevel--;
148 }
149
150
151 /**
152  * Add a new variable to the given symbol table.
153  */
154 void
155 _slang_add_variable(slang_var_table *vt, slang_variable *v)
156 {
157    struct table *t;
158    assert(vt);
159    t = vt->Top;
160    assert(t);
161    if (dbg) printf("Adding var %s\n", (char *) v->a_name);
162    t->Vars = (slang_variable **)
163       _slang_realloc(t->Vars,
164                      t->NumVars * sizeof(slang_variable *),
165                      (t->NumVars + 1) * sizeof(slang_variable *));
166    t->Vars[t->NumVars] = v;
167    t->NumVars++;
168 }
169
170
171 /**
172  * Look for variable by name in given table.
173  * If not found, Parent table will be searched.
174  */
175 slang_variable *
176 _slang_find_variable(const slang_var_table *vt, slang_atom name)
177 {
178    struct table *t = vt->Top;
179    while (1) {
180       int i;
181       for (i = 0; i < t->NumVars; i++) {
182          if (t->Vars[i]->a_name == name)
183             return t->Vars[i];
184       }
185       if (t->Parent)
186          t = t->Parent;
187       else
188          return NULL;
189    }
190 }
191
192
193 /**
194  * Allocation helper.
195  * \param size  var size in floats
196  * \return  position for var, measured in floats
197  */
198 static GLint
199 alloc_reg(slang_var_table *vt, GLint size, GLboolean isTemp)
200 {
201    struct table *t = vt->Top;
202    /* if size == 1, allocate anywhere, else, pos must be multiple of 4 */
203    const GLuint step = (size == 1) ? 1 : 4;
204    GLuint i, j;
205    assert(size > 0); /* number of floats */
206
207    for (i = 0; i <= vt->MaxRegisters * 4 - size; i += step) {
208       GLuint found = 0;
209       for (j = 0; j < size; j++) {
210          if (i + j < vt->MaxRegisters * 4 && t->Temps[i + j] == FREE) {
211             found++;
212          }
213          else {
214             break;
215          }
216       }
217       if (found == size) {
218          /* found block of size free regs */
219          if (size > 1)
220             assert(i % 4 == 0);
221          for (j = 0; j < size; j++)
222             t->Temps[i + j] = isTemp ? TEMP : VAR;
223          t->ValSize[i] = size;
224          return i;
225       }
226    }
227    return -1;
228 }
229
230
231 /**
232  * Allocate temp register(s) for storing a variable.
233  * \param size  size needed, in floats
234  * \param swizzle  returns swizzle mask for accessing var in register
235  * \return  register allocated, or -1
236  */
237 GLboolean
238 _slang_alloc_var(slang_var_table *vt, slang_ir_storage *store)
239 {
240    struct table *t = vt->Top;
241    const int i = alloc_reg(vt, store->Size, GL_FALSE);
242    if (i < 0)
243       return GL_FALSE;
244
245    store->Index = i / 4;
246    if (store->Size == 1) {
247       const GLuint comp = i % 4;
248       store->Swizzle = MAKE_SWIZZLE4(comp, comp, comp, comp);
249       if (dbg) printf("Alloc var sz %d at %d.%c (level %d)\n",
250                       store->Size, store->Index, "xyzw"[comp], t->Level);
251    }
252    else {
253       store->Swizzle = SWIZZLE_NOOP;
254       if (dbg) printf("Alloc var sz %d at %d.xyzw (level %d)\n",
255                       store->Size, store->Index, t->Level);
256    }
257    return GL_TRUE;
258 }
259
260
261
262 /**
263  * Allocate temp register(s) for storing an unnamed intermediate value.
264  */
265 GLboolean
266 _slang_alloc_temp(slang_var_table *vt, slang_ir_storage *store)
267 {
268    struct table *t = vt->Top;
269    const int i = alloc_reg(vt, store->Size, GL_TRUE);
270    if (i < 0)
271       return GL_FALSE;
272
273    store->Index = i / 4;
274    if (store->Size == 1) {
275       const GLuint comp = i % 4;
276       store->Swizzle = MAKE_SWIZZLE4(comp, comp, comp, comp);
277       if (dbg) printf("Alloc temp sz %d at %d.%c (level %d)\n",
278                       store->Size, store->Index, "xyzw"[comp], t->Level);
279    }
280    else {
281       store->Swizzle = SWIZZLE_NOOP;
282       if (dbg) printf("Alloc temp sz %d at %d.xyzw (level %d)\n",
283                       store->Size, store->Index, t->Level);
284    }
285    return GL_TRUE;
286 }
287
288
289 void
290 _slang_free_temp(slang_var_table *vt, slang_ir_storage *store)
291 {
292    struct table *t = vt->Top;
293    GLuint i;
294    GLuint r = store->Index;
295    assert(store->Size > 0);
296    assert(r >= 0);
297    assert(r + store->Size <= vt->MaxRegisters * 4);
298    if (dbg) printf("Free temp sz %d at %d (level %d)\n", store->Size, r, t->Level);
299    if (store->Size == 1) {
300       const GLuint comp = GET_SWZ(store->Swizzle, 0);
301       assert(store->Swizzle == MAKE_SWIZZLE4(comp, comp, comp, comp));
302       assert(comp < 4);
303       assert(t->ValSize[r * 4 + comp] == 1);
304       assert(t->Temps[r * 4 + comp] == TEMP);
305       t->Temps[r * 4 + comp] = FREE;
306    }
307    else {
308       /*assert(store->Swizzle == SWIZZLE_NOOP);*/
309       assert(t->ValSize[r*4] == store->Size);
310       for (i = 0; i < store->Size; i++) {
311          assert(t->Temps[r * 4 + i] == TEMP);
312          t->Temps[r * 4 + i] = FREE;
313       }
314    }
315 }
316
317
318 GLboolean
319 _slang_is_temp(const slang_var_table *vt, const slang_ir_storage *store)
320 {
321    struct table *t = vt->Top;
322    GLuint comp;
323    assert(store->Index >= 0);
324    assert(store->Index < vt->MaxRegisters);
325    if (store->Swizzle == SWIZZLE_NOOP)
326       comp = 0;
327    else
328       comp = GET_SWZ(store->Swizzle, 0);
329
330    if (t->Temps[store->Index * 4 + comp] == TEMP)
331       return GL_TRUE;
332    else
333       return GL_FALSE;
334 }