Merge branch 'master' into r300g-glsl
[mesa.git] / src / mesa / shader / slang / slang_vartable.c
1
2 #include "main/imports.h"
3 #include "shader/program.h"
4 #include "shader/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 GLuint r = store->Index;
315 assert(store->Size > 0);
316 assert(r >= 0);
317 assert(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 }