OSDN Git Service

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