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