Be more consistant with paths in #includes. Eventually, eliminate a bunch of -I...
[mesa.git] / src / mesa / shader / slang / slang_vartable.c
1
2 #include "main/imports.h"
3 #include "shader/prog_instruction.h"
4 #include "slang_compile.h"
5 #include "slang_compile_variable.h"
6 #include "slang_mem.h"
7 #include "slang_vartable.h"
8 #include "slang_ir.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 }