Fix a refcounting mistake with first_swap_fence.
[mesa.git] / src / mesa / shader / slang / slang_ir.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "imports.h"
27 #include "context.h"
28 #include "slang_ir.h"
29 #include "prog_print.h"
30
31
32 static const slang_ir_info IrInfo[] = {
33 /* binary ops */
34 { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 },
35 { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 },
36 { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 },
37 { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */
38 { IR_DOT4, "IR_DOT_4", OPCODE_DP4, 1, 2 },
39 { IR_DOT3, "IR_DOT_3", OPCODE_DP3, 1, 2 },
40 { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 },
41 { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 },
42 { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 },
43 { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 },
44 { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */
45 { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 },
46 { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 },
47 { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 },
48 { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 },
49 { IR_SLE, "IR_SLE", OPCODE_SLE, 4, 2 },
50 { IR_SLT, "IR_SLT", OPCODE_SLT, 4, 2 },
51 { IR_POW, "IR_POW", OPCODE_POW, 1, 2 },
52 /* unary ops */
53 { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 },
54 { IR_F_TO_I, "IR_F_TO_I", OPCODE_INT, 4, 1 }, /* 4 floats to 4 ints */
55 { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 },
56 { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 },
57 { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 },
58 { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 },
59 { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 },
60 { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
61 { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
62 { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
63 { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */
64 { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 },
65 { IR_DDX, "IR_DDY", OPCODE_DDX, 4, 1 },
66 { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
67 { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
68 { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 },
69 { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 },
70 { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 },
71 { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 },
72
73 /* other */
74 { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 },
75 { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 },
76 { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 },
77 { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 },
78 { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 },
79 { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 },
80 { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 },
81 { IR_MOVE, "IR_MOVE", OPCODE_NOP, 0, 1 },
82 { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 },
83 { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 },
84 { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 },
85 { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
86 { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 },
87 { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 },
88 { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */
89 { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 },
90 { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 },
91 { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 },
92 { IR_NOP, NULL, OPCODE_NOP, 0, 0 }
93 };
94
95
96 const slang_ir_info *
97 _slang_ir_info(slang_ir_opcode opcode)
98 {
99 GLuint i;
100 for (i = 0; IrInfo[i].IrName; i++) {
101 if (IrInfo[i].IrOpcode == opcode) {
102 return IrInfo + i;
103 }
104 }
105 return NULL;
106 }
107
108
109 static const char *
110 _slang_ir_name(slang_ir_opcode opcode)
111 {
112 return _slang_ir_info(opcode)->IrName;
113 }
114
115
116 /**
117 * Since many IR nodes might point to the same IR storage info, we need
118 * to be careful when deleting things.
119 * Before deleting an IR tree, traverse it and do refcounting on the
120 * IR storage nodes. Use the refcount info during delete to free things
121 * properly.
122 */
123 static void
124 _slang_refcount_storage(slang_ir_node *n)
125 {
126 GLuint i;
127 if (!n)
128 return;
129 if (n->Store)
130 n->Store->RefCount++;
131 for (i = 0; i < 3; i++)
132 _slang_refcount_storage(n->Children[i]);
133 }
134
135
136 static void
137 _slang_free_ir(slang_ir_node *n)
138 {
139 GLuint i;
140 if (!n)
141 return;
142
143 if (n->Store) {
144 n->Store->RefCount--;
145 if (n->Store->RefCount == 0) {
146 #if 0
147 free(n->Store);
148 #endif
149 n->Store = NULL;
150 }
151 }
152
153 for (i = 0; i < 3; i++)
154 _slang_free_ir(n->Children[i]);
155 /* Do not free n->List since it's a child elsewhere */
156 free(n);
157 }
158
159
160 /**
161 * Recursively free an IR tree.
162 */
163 void
164 _slang_free_ir_tree(slang_ir_node *n)
165 {
166 _slang_refcount_storage(n);
167 _slang_free_ir(n);
168 }
169
170
171
172 static const char *
173 swizzle_string(GLuint swizzle)
174 {
175 static char s[6];
176 GLuint i;
177 s[0] = '.';
178 for (i = 1; i < 5; i++) {
179 s[i] = "xyzw"[GET_SWZ(swizzle, i-1)];
180 }
181 s[i] = 0;
182 return s;
183 }
184
185
186 static const char *
187 writemask_string(GLuint writemask)
188 {
189 static char s[6];
190 GLuint i, j = 0;
191 s[j++] = '.';
192 for (i = 0; i < 4; i++) {
193 if (writemask & (1 << i))
194 s[j++] = "xyzw"[i];
195 }
196 s[j] = 0;
197 return s;
198 }
199
200
201 static const char *
202 storage_string(const slang_ir_storage *st)
203 {
204 static const char *files[] = {
205 "TEMP",
206 "LOCAL_PARAM",
207 "ENV_PARAM",
208 "STATE",
209 "INPUT",
210 "OUTPUT",
211 "NAMED_PARAM",
212 "CONSTANT",
213 "UNIFORM",
214 "WRITE_ONLY",
215 "ADDRESS",
216 "SAMPLER",
217 "UNDEFINED"
218 };
219 static char s[100];
220 #if 0
221 if (st->Size == 1)
222 sprintf(s, "%s[%d]", files[st->File], st->Index);
223 else
224 sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
225 st->Index + st->Size - 1);
226 #endif
227 assert(st->File < (GLint) (sizeof(files) / sizeof(files[0])));
228 sprintf(s, "%s[%d]", files[st->File], st->Index);
229 return s;
230 }
231
232
233 static void
234 spaces(int n)
235 {
236 while (n-- > 0) {
237 printf(" ");
238 }
239 }
240
241
242 void
243 _slang_print_ir_tree(const slang_ir_node *n, int indent)
244 {
245 #define IND 0
246
247 if (!n)
248 return;
249 #if !IND
250 if (n->Opcode != IR_SEQ)
251 #else
252 printf("%3d:", indent);
253 #endif
254 spaces(indent);
255
256 switch (n->Opcode) {
257 case IR_SEQ:
258 #if IND
259 printf("SEQ at %p\n", (void*) n);
260 #endif
261 assert(n->Children[0]);
262 assert(n->Children[1]);
263 _slang_print_ir_tree(n->Children[0], indent + IND);
264 _slang_print_ir_tree(n->Children[1], indent + IND);
265 break;
266 case IR_SCOPE:
267 printf("NEW SCOPE\n");
268 assert(!n->Children[1]);
269 _slang_print_ir_tree(n->Children[0], indent + 3);
270 break;
271 case IR_MOVE:
272 printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask));
273 _slang_print_ir_tree(n->Children[0], indent+3);
274 _slang_print_ir_tree(n->Children[1], indent+3);
275 break;
276 case IR_LABEL:
277 printf("LABEL: %s\n", n->Label->Name);
278 break;
279 case IR_COND:
280 printf("COND\n");
281 _slang_print_ir_tree(n->Children[0], indent + 3);
282 break;
283
284 case IR_IF:
285 printf("IF \n");
286 _slang_print_ir_tree(n->Children[0], indent+3);
287 spaces(indent);
288 printf("THEN\n");
289 _slang_print_ir_tree(n->Children[1], indent+3);
290 if (n->Children[2]) {
291 spaces(indent);
292 printf("ELSE\n");
293 _slang_print_ir_tree(n->Children[2], indent+3);
294 }
295 spaces(indent);
296 printf("ENDIF\n");
297 break;
298
299 case IR_BEGIN_SUB:
300 printf("BEGIN_SUB\n");
301 break;
302 case IR_END_SUB:
303 printf("END_SUB\n");
304 break;
305 case IR_RETURN:
306 printf("RETURN\n");
307 break;
308 case IR_CALL:
309 printf("CALL\n");
310 break;
311
312 case IR_LOOP:
313 printf("LOOP\n");
314 _slang_print_ir_tree(n->Children[0], indent+3);
315 if (n->Children[1]) {
316 spaces(indent);
317 printf("TAIL:\n");
318 _slang_print_ir_tree(n->Children[1], indent+3);
319 }
320 spaces(indent);
321 printf("ENDLOOP\n");
322 break;
323 case IR_CONT:
324 printf("CONT\n");
325 break;
326 case IR_BREAK:
327 printf("BREAK\n");
328 break;
329 case IR_BREAK_IF_TRUE:
330 printf("BREAK_IF_TRUE\n");
331 _slang_print_ir_tree(n->Children[0], indent+3);
332 break;
333 case IR_CONT_IF_TRUE:
334 printf("CONT_IF_TRUE\n");
335 _slang_print_ir_tree(n->Children[0], indent+3);
336 break;
337
338 case IR_VAR:
339 printf("VAR %s%s at %s store %p\n",
340 (n->Var ? (char *) n->Var->a_name : "TEMP"),
341 swizzle_string(n->Store->Swizzle),
342 storage_string(n->Store), (void*) n->Store);
343 break;
344 case IR_VAR_DECL:
345 printf("VAR_DECL %s (%p) at %s store %p\n",
346 (n->Var ? (char *) n->Var->a_name : "TEMP"),
347 (void*) n->Var, storage_string(n->Store),
348 (void*) n->Store);
349 break;
350 case IR_FIELD:
351 printf("FIELD %s of\n", n->Field);
352 _slang_print_ir_tree(n->Children[0], indent+3);
353 break;
354 case IR_FLOAT:
355 printf("FLOAT %g %g %g %g\n",
356 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
357 break;
358 case IR_I_TO_F:
359 printf("INT_TO_FLOAT\n");
360 _slang_print_ir_tree(n->Children[0], indent+3);
361 break;
362 case IR_F_TO_I:
363 printf("FLOAT_TO_INT\n");
364 _slang_print_ir_tree(n->Children[0], indent+3);
365 break;
366 case IR_SWIZZLE:
367 printf("SWIZZLE %s of (store %p) \n",
368 swizzle_string(n->Store->Swizzle), (void*) n->Store);
369 _slang_print_ir_tree(n->Children[0], indent + 3);
370 break;
371 default:
372 printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode),
373 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
374 _slang_print_ir_tree(n->Children[0], indent+3);
375 _slang_print_ir_tree(n->Children[1], indent+3);
376 }
377 }