Merge branch 'master' into i915-unification
[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 "slang_mem.h"
30 #include "shader/prog_print.h"
31
32
33 static const slang_ir_info IrInfo[] = {
34 /* binary ops */
35 { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 },
36 { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 },
37 { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 },
38 { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */
39 { IR_DOT4, "IR_DOT_4", OPCODE_DP4, 1, 2 },
40 { IR_DOT3, "IR_DOT_3", OPCODE_DP3, 1, 2 },
41 { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 },
42 { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 },
43 { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 },
44 { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 },
45 { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */
46 { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 },
47 { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 },
48 { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 },
49 { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 },
50 { IR_SLE, "IR_SLE", OPCODE_SLE, 4, 2 },
51 { IR_SLT, "IR_SLT", OPCODE_SLT, 4, 2 },
52 { IR_POW, "IR_POW", OPCODE_POW, 1, 2 },
53 /* unary ops */
54 { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 },
55 { IR_F_TO_I, "IR_F_TO_I", OPCODE_INT, 4, 1 }, /* 4 floats to 4 ints */
56 { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 },
57 { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 },
58 { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 },
59 { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 },
60 { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 },
61 { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
62 { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
63 { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
64 { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */
65 { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 },
66 { IR_DDY, "IR_DDY", OPCODE_DDY, 4, 1 },
67 { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
68 { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
69 { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 },
70 { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 },
71 { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 },
72 { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 },
73
74 /* other */
75 { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 },
76 { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 },
77 { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 },
78 { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 },
79 { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 },
80 { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 },
81 { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 },
82 { IR_MOVE, "IR_MOVE", OPCODE_NOP, 0, 1 },
83 { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 },
84 { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 },
85 { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 },
86 { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
87 { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 },
88 { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 },
89 { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */
90 { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 },
91 { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 },
92 { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 },
93 { IR_NOP, NULL, OPCODE_NOP, 0, 0 }
94 };
95
96
97 const slang_ir_info *
98 _slang_ir_info(slang_ir_opcode opcode)
99 {
100 GLuint i;
101 for (i = 0; IrInfo[i].IrName; i++) {
102 if (IrInfo[i].IrOpcode == opcode) {
103 return IrInfo + i;
104 }
105 }
106 return NULL;
107 }
108
109
110 static const char *
111 _slang_ir_name(slang_ir_opcode opcode)
112 {
113 return _slang_ir_info(opcode)->IrName;
114 }
115
116
117 #if 0 /* no longer needed with mempool */
118 /**
119 * Since many IR nodes might point to the same IR storage info, we need
120 * to be careful when deleting things.
121 * Before deleting an IR tree, traverse it and do refcounting on the
122 * IR storage nodes. Use the refcount info during delete to free things
123 * properly.
124 */
125 static void
126 _slang_refcount_storage(slang_ir_node *n)
127 {
128 GLuint i;
129 if (!n)
130 return;
131 if (n->Store)
132 n->Store->RefCount++;
133 for (i = 0; i < 3; i++)
134 _slang_refcount_storage(n->Children[i]);
135 }
136 #endif
137
138
139 static void
140 _slang_free_ir(slang_ir_node *n)
141 {
142 GLuint i;
143 if (!n)
144 return;
145
146 #if 0
147 if (n->Store) {
148 n->Store->RefCount--;
149 if (n->Store->RefCount == 0) {
150 _slang_free(n->Store);
151 n->Store = NULL;
152 }
153 }
154 #endif
155
156 for (i = 0; i < 3; i++)
157 _slang_free_ir(n->Children[i]);
158 /* Do not free n->List since it's a child elsewhere */
159 _slang_free(n);
160 }
161
162
163 /**
164 * Recursively free an IR tree.
165 */
166 void
167 _slang_free_ir_tree(slang_ir_node *n)
168 {
169 #if 0
170 _slang_refcount_storage(n);
171 #endif
172 _slang_free_ir(n);
173 }
174
175
176
177 static const char *
178 swizzle_string(GLuint swizzle)
179 {
180 static char s[6];
181 GLuint i;
182 s[0] = '.';
183 for (i = 1; i < 5; i++) {
184 s[i] = "xyzw"[GET_SWZ(swizzle, i-1)];
185 }
186 s[i] = 0;
187 return s;
188 }
189
190
191 static const char *
192 writemask_string(GLuint writemask)
193 {
194 static char s[6];
195 GLuint i, j = 0;
196 s[j++] = '.';
197 for (i = 0; i < 4; i++) {
198 if (writemask & (1 << i))
199 s[j++] = "xyzw"[i];
200 }
201 s[j] = 0;
202 return s;
203 }
204
205
206 static const char *
207 storage_string(const slang_ir_storage *st)
208 {
209 static const char *files[] = {
210 "TEMP",
211 "LOCAL_PARAM",
212 "ENV_PARAM",
213 "STATE",
214 "INPUT",
215 "OUTPUT",
216 "NAMED_PARAM",
217 "CONSTANT",
218 "UNIFORM",
219 "WRITE_ONLY",
220 "ADDRESS",
221 "SAMPLER",
222 "UNDEFINED"
223 };
224 static char s[100];
225 #if 0
226 if (st->Size == 1)
227 sprintf(s, "%s[%d]", files[st->File], st->Index);
228 else
229 sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
230 st->Index + st->Size - 1);
231 #endif
232 assert(st->File < (GLint) (sizeof(files) / sizeof(files[0])));
233 sprintf(s, "%s[%d]", files[st->File], st->Index);
234 return s;
235 }
236
237
238 static void
239 spaces(int n)
240 {
241 while (n-- > 0) {
242 printf(" ");
243 }
244 }
245
246
247 void
248 _slang_print_ir_tree(const slang_ir_node *n, int indent)
249 {
250 #define IND 0
251
252 if (!n)
253 return;
254 #if !IND
255 if (n->Opcode != IR_SEQ)
256 #else
257 printf("%3d:", indent);
258 #endif
259 spaces(indent);
260
261 switch (n->Opcode) {
262 case IR_SEQ:
263 #if IND
264 printf("SEQ at %p\n", (void*) n);
265 #endif
266 assert(n->Children[0]);
267 assert(n->Children[1]);
268 _slang_print_ir_tree(n->Children[0], indent + IND);
269 _slang_print_ir_tree(n->Children[1], indent + IND);
270 break;
271 case IR_SCOPE:
272 printf("NEW SCOPE\n");
273 assert(!n->Children[1]);
274 _slang_print_ir_tree(n->Children[0], indent + 3);
275 break;
276 case IR_MOVE:
277 printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask));
278 _slang_print_ir_tree(n->Children[0], indent+3);
279 _slang_print_ir_tree(n->Children[1], indent+3);
280 break;
281 case IR_LABEL:
282 printf("LABEL: %s\n", n->Label->Name);
283 break;
284 case IR_COND:
285 printf("COND\n");
286 _slang_print_ir_tree(n->Children[0], indent + 3);
287 break;
288
289 case IR_IF:
290 printf("IF \n");
291 _slang_print_ir_tree(n->Children[0], indent+3);
292 spaces(indent);
293 printf("THEN\n");
294 _slang_print_ir_tree(n->Children[1], indent+3);
295 if (n->Children[2]) {
296 spaces(indent);
297 printf("ELSE\n");
298 _slang_print_ir_tree(n->Children[2], indent+3);
299 }
300 spaces(indent);
301 printf("ENDIF\n");
302 break;
303
304 case IR_BEGIN_SUB:
305 printf("BEGIN_SUB\n");
306 break;
307 case IR_END_SUB:
308 printf("END_SUB\n");
309 break;
310 case IR_RETURN:
311 printf("RETURN\n");
312 break;
313 case IR_CALL:
314 printf("CALL %s\n", n->Label->Name);
315 break;
316
317 case IR_LOOP:
318 printf("LOOP\n");
319 _slang_print_ir_tree(n->Children[0], indent+3);
320 if (n->Children[1]) {
321 spaces(indent);
322 printf("TAIL:\n");
323 _slang_print_ir_tree(n->Children[1], indent+3);
324 }
325 spaces(indent);
326 printf("ENDLOOP\n");
327 break;
328 case IR_CONT:
329 printf("CONT\n");
330 break;
331 case IR_BREAK:
332 printf("BREAK\n");
333 break;
334 case IR_BREAK_IF_TRUE:
335 printf("BREAK_IF_TRUE\n");
336 _slang_print_ir_tree(n->Children[0], indent+3);
337 break;
338 case IR_CONT_IF_TRUE:
339 printf("CONT_IF_TRUE\n");
340 _slang_print_ir_tree(n->Children[0], indent+3);
341 break;
342
343 case IR_VAR:
344 printf("VAR %s%s at %s store %p\n",
345 (n->Var ? (char *) n->Var->a_name : "TEMP"),
346 swizzle_string(n->Store->Swizzle),
347 storage_string(n->Store), (void*) n->Store);
348 break;
349 case IR_VAR_DECL:
350 printf("VAR_DECL %s (%p) at %s store %p\n",
351 (n->Var ? (char *) n->Var->a_name : "TEMP"),
352 (void*) n->Var, storage_string(n->Store),
353 (void*) n->Store);
354 break;
355 case IR_FIELD:
356 printf("FIELD %s of\n", n->Field);
357 _slang_print_ir_tree(n->Children[0], indent+3);
358 break;
359 case IR_FLOAT:
360 printf("FLOAT %g %g %g %g\n",
361 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
362 break;
363 case IR_I_TO_F:
364 printf("INT_TO_FLOAT\n");
365 _slang_print_ir_tree(n->Children[0], indent+3);
366 break;
367 case IR_F_TO_I:
368 printf("FLOAT_TO_INT\n");
369 _slang_print_ir_tree(n->Children[0], indent+3);
370 break;
371 case IR_SWIZZLE:
372 printf("SWIZZLE %s of (store %p) \n",
373 swizzle_string(n->Store->Swizzle), (void*) n->Store);
374 _slang_print_ir_tree(n->Children[0], indent + 3);
375 break;
376 default:
377 printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode),
378 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
379 _slang_print_ir_tree(n->Children[0], indent+3);
380 _slang_print_ir_tree(n->Children[1], indent+3);
381 }
382 }