Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / shader / slang / slang_ir.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 2005-2008 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 "main/imports.h"
27 #include "main/context.h"
28 #include "slang_ir.h"
29 #include "slang_mem.h"
30 #include "shader/prog_instruction.h"
31 #include "shader/prog_print.h"
32
33
34 static const slang_ir_info IrInfo[] = {
35 /* binary ops */
36 { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 },
37 { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 },
38 { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 },
39 { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */
40 { IR_DOT4, "IR_DOT4", OPCODE_DP4, 1, 2 },
41 { IR_DOT3, "IR_DOT3", OPCODE_DP3, 1, 2 },
42 { IR_DOT2, "IR_DOT2", OPCODE_DP2, 1, 2 },
43 { IR_NRM4, "IR_NRM4", OPCODE_NRM4, 1, 1 },
44 { IR_NRM3, "IR_NRM3", OPCODE_NRM3, 1, 1 },
45 { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 },
46 { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 },
47 { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 },
48 { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 },
49 { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */
50 { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 },
51 { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 },
52 { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 },
53 { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 },
54 { IR_SLE, "IR_SLE", OPCODE_SLE, 4, 2 },
55 { IR_SLT, "IR_SLT", OPCODE_SLT, 4, 2 },
56 { IR_POW, "IR_POW", OPCODE_POW, 1, 2 },
57 { IR_EQUAL, "IR_EQUAL", OPCODE_NOP, 1, 2 },
58 { IR_NOTEQUAL, "IR_NOTEQUAL", OPCODE_NOP, 1, 2 },
59
60 /* unary ops */
61 { IR_MOVE, "IR_MOVE", OPCODE_MOV, 4, 1 },
62 { IR_I_TO_F, "IR_I_TO_F", OPCODE_MOV, 4, 1 }, /* int[4] to float[4] */
63 { IR_F_TO_I, "IR_F_TO_I", OPCODE_TRUNC, 4, 1 },
64 { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 },
65 { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 },
66 { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 },
67 { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 },
68 { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 },
69 { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
70 { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
71 { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
72 { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */
73 { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 },
74 { IR_DDY, "IR_DDY", OPCODE_DDY, 4, 1 },
75 { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
76 { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
77 { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 },
78 { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 },
79 { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 },
80 { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 },
81
82 /* other */
83 { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 },
84 { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 },
85 { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 },
86 { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 },
87 { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 },
88 { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 },
89 { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 },
90 { IR_COPY, "IR_COPY", OPCODE_NOP, 0, 1 },
91 { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 },
92 { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 },
93 { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 },
94 { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
95 { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 },
96 { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 },
97 { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */
98 { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 },
99 { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 },
100 { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 },
101 { IR_NOP, "IR_NOP", OPCODE_NOP, 0, 0 },
102 { 0, NULL, 0, 0, 0 }
103 };
104
105
106 const slang_ir_info *
107 _slang_ir_info(slang_ir_opcode opcode)
108 {
109 GLuint i;
110 for (i = 0; IrInfo[i].IrName; i++) {
111 if (IrInfo[i].IrOpcode == opcode) {
112 return IrInfo + i;
113 }
114 }
115 return NULL;
116 }
117
118
119 void
120 _slang_init_ir_storage(slang_ir_storage *st,
121 enum register_file file, GLint index, GLint size,
122 GLuint swizzle)
123 {
124 st->File = file;
125 st->Index = index;
126 st->Size = size;
127 st->Swizzle = swizzle;
128 st->Parent = NULL;
129 st->IsIndirect = GL_FALSE;
130 }
131
132
133 /**
134 * Return a new slang_ir_storage object.
135 */
136 slang_ir_storage *
137 _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
138 {
139 slang_ir_storage *st;
140 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
141 if (st) {
142 st->File = file;
143 st->Index = index;
144 st->Size = size;
145 st->Swizzle = SWIZZLE_NOOP;
146 st->Parent = NULL;
147 st->IsIndirect = GL_FALSE;
148 }
149 return st;
150 }
151
152
153 /**
154 * Return a new slang_ir_storage object.
155 */
156 slang_ir_storage *
157 _slang_new_ir_storage_swz(enum register_file file, GLint index, GLint size,
158 GLuint swizzle)
159 {
160 slang_ir_storage *st;
161 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
162 if (st) {
163 st->File = file;
164 st->Index = index;
165 st->Size = size;
166 st->Swizzle = swizzle;
167 st->Parent = NULL;
168 st->IsIndirect = GL_FALSE;
169 }
170 return st;
171 }
172
173
174 /**
175 * Return a new slang_ir_storage object.
176 */
177 slang_ir_storage *
178 _slang_new_ir_storage_relative(GLint index, GLint size,
179 slang_ir_storage *parent)
180 {
181 slang_ir_storage *st;
182 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
183 if (st) {
184 st->File = PROGRAM_UNDEFINED;
185 st->Index = index;
186 st->Size = size;
187 st->Swizzle = SWIZZLE_NOOP;
188 st->Parent = parent;
189 st->IsIndirect = GL_FALSE;
190 }
191 return st;
192 }
193
194
195 slang_ir_storage *
196 _slang_new_ir_storage_indirect(enum register_file file,
197 GLint index,
198 GLint size,
199 enum register_file indirectFile,
200 GLint indirectIndex,
201 GLuint indirectSwizzle)
202 {
203 slang_ir_storage *st;
204 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
205 if (st) {
206 st->File = file;
207 st->Index = index;
208 st->Size = size;
209 st->Swizzle = SWIZZLE_NOOP;
210 st->IsIndirect = GL_TRUE;
211 st->IndirectFile = indirectFile;
212 st->IndirectIndex = indirectIndex;
213 st->IndirectSwizzle = indirectSwizzle;
214 }
215 return st;
216 }
217
218
219 /* XXX temporary function */
220 void
221 _slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src)
222 {
223 *dst = *src;
224 dst->Parent = NULL;
225 }
226
227
228
229 static const char *
230 _slang_ir_name(slang_ir_opcode opcode)
231 {
232 return _slang_ir_info(opcode)->IrName;
233 }
234
235
236
237 #if 0 /* no longer needed with mempool */
238 /**
239 * Since many IR nodes might point to the same IR storage info, we need
240 * to be careful when deleting things.
241 * Before deleting an IR tree, traverse it and do refcounting on the
242 * IR storage nodes. Use the refcount info during delete to free things
243 * properly.
244 */
245 static void
246 _slang_refcount_storage(slang_ir_node *n)
247 {
248 GLuint i;
249 if (!n)
250 return;
251 if (n->Store)
252 n->Store->RefCount++;
253 for (i = 0; i < 3; i++)
254 _slang_refcount_storage(n->Children[i]);
255 }
256 #endif
257
258
259 static void
260 _slang_free_ir(slang_ir_node *n)
261 {
262 GLuint i;
263 if (!n)
264 return;
265
266 #if 0
267 if (n->Store) {
268 n->Store->RefCount--;
269 if (n->Store->RefCount == 0) {
270 _slang_free(n->Store);
271 n->Store = NULL;
272 }
273 }
274 #endif
275
276 for (i = 0; i < 3; i++)
277 _slang_free_ir(n->Children[i]);
278 /* Do not free n->List since it's a child elsewhere */
279 _slang_free(n);
280 }
281
282
283 /**
284 * Recursively free an IR tree.
285 */
286 void
287 _slang_free_ir_tree(slang_ir_node *n)
288 {
289 #if 0
290 _slang_refcount_storage(n);
291 #endif
292 _slang_free_ir(n);
293 }
294
295
296 static const char *
297 storage_string(const slang_ir_storage *st)
298 {
299 static const char *files[] = {
300 "TEMP",
301 "LOCAL_PARAM",
302 "ENV_PARAM",
303 "STATE",
304 "INPUT",
305 "OUTPUT",
306 "NAMED_PARAM",
307 "CONSTANT",
308 "UNIFORM",
309 "VARYING",
310 "WRITE_ONLY",
311 "ADDRESS",
312 "SAMPLER",
313 "UNDEFINED"
314 };
315 static char s[100];
316 assert(Elements(files) == PROGRAM_FILE_MAX);
317 #if 0
318 if (st->Size == 1)
319 sprintf(s, "%s[%d]", files[st->File], st->Index);
320 else
321 sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
322 st->Index + st->Size - 1);
323 #endif
324 assert(st->File < (GLint) (sizeof(files) / sizeof(files[0])));
325 sprintf(s, "%s[%d]", files[st->File], st->Index);
326 return s;
327 }
328
329
330 static void
331 spaces(int n)
332 {
333 while (n-- > 0) {
334 printf(" ");
335 }
336 }
337
338
339 void
340 _slang_print_ir_tree(const slang_ir_node *n, int indent)
341 {
342 #define IND 0
343
344 if (!n)
345 return;
346 #if !IND
347 if (n->Opcode != IR_SEQ)
348 #else
349 printf("%3d:", indent);
350 #endif
351 spaces(indent);
352
353 switch (n->Opcode) {
354 case IR_SEQ:
355 #if IND
356 printf("SEQ at %p\n", (void*) n);
357 #endif
358 assert(n->Children[0]);
359 assert(n->Children[1]);
360 _slang_print_ir_tree(n->Children[0], indent + IND);
361 _slang_print_ir_tree(n->Children[1], indent + IND);
362 break;
363 case IR_SCOPE:
364 printf("NEW SCOPE\n");
365 assert(!n->Children[1]);
366 _slang_print_ir_tree(n->Children[0], indent + 3);
367 break;
368 case IR_COPY:
369 printf("COPY\n");
370 _slang_print_ir_tree(n->Children[0], indent+3);
371 _slang_print_ir_tree(n->Children[1], indent+3);
372 break;
373 case IR_LABEL:
374 printf("LABEL: %s\n", n->Label->Name);
375 break;
376 case IR_COND:
377 printf("COND\n");
378 _slang_print_ir_tree(n->Children[0], indent + 3);
379 break;
380
381 case IR_IF:
382 printf("IF \n");
383 _slang_print_ir_tree(n->Children[0], indent+3);
384 spaces(indent);
385 printf("THEN\n");
386 _slang_print_ir_tree(n->Children[1], indent+3);
387 if (n->Children[2]) {
388 spaces(indent);
389 printf("ELSE\n");
390 _slang_print_ir_tree(n->Children[2], indent+3);
391 }
392 spaces(indent);
393 printf("ENDIF\n");
394 break;
395
396 case IR_BEGIN_SUB:
397 printf("BEGIN_SUB\n");
398 break;
399 case IR_END_SUB:
400 printf("END_SUB\n");
401 break;
402 case IR_RETURN:
403 printf("RETURN\n");
404 break;
405 case IR_CALL:
406 printf("CALL %s\n", n->Label->Name);
407 break;
408
409 case IR_LOOP:
410 printf("LOOP\n");
411 _slang_print_ir_tree(n->Children[0], indent+3);
412 if (n->Children[1]) {
413 spaces(indent);
414 printf("TAIL:\n");
415 _slang_print_ir_tree(n->Children[1], indent+3);
416 }
417 spaces(indent);
418 printf("ENDLOOP\n");
419 break;
420 case IR_CONT:
421 printf("CONT\n");
422 break;
423 case IR_BREAK:
424 printf("BREAK\n");
425 break;
426 case IR_BREAK_IF_TRUE:
427 printf("BREAK_IF_TRUE\n");
428 _slang_print_ir_tree(n->Children[0], indent+3);
429 break;
430 case IR_CONT_IF_TRUE:
431 printf("CONT_IF_TRUE\n");
432 _slang_print_ir_tree(n->Children[0], indent+3);
433 break;
434
435 case IR_VAR:
436 printf("VAR %s%s at %s store %p\n",
437 (n->Var ? (char *) n->Var->a_name : "TEMP"),
438 _mesa_swizzle_string(n->Store->Swizzle, 0, 0),
439 storage_string(n->Store), (void*) n->Store);
440 break;
441 case IR_VAR_DECL:
442 printf("VAR_DECL %s (%p) at %s store %p\n",
443 (n->Var ? (char *) n->Var->a_name : "TEMP"),
444 (void*) n->Var, storage_string(n->Store),
445 (void*) n->Store);
446 break;
447 case IR_FIELD:
448 printf("FIELD %s of\n", n->Field);
449 _slang_print_ir_tree(n->Children[0], indent+3);
450 break;
451 case IR_FLOAT:
452 printf("FLOAT %g %g %g %g\n",
453 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
454 break;
455 case IR_I_TO_F:
456 printf("INT_TO_FLOAT\n");
457 _slang_print_ir_tree(n->Children[0], indent+3);
458 break;
459 case IR_F_TO_I:
460 printf("FLOAT_TO_INT\n");
461 _slang_print_ir_tree(n->Children[0], indent+3);
462 break;
463 case IR_SWIZZLE:
464 printf("SWIZZLE %s of (store %p) \n",
465 _mesa_swizzle_string(n->Store->Swizzle, 0, 0), (void*) n->Store);
466 _slang_print_ir_tree(n->Children[0], indent + 3);
467 break;
468 default:
469 printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode),
470 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
471 _slang_print_ir_tree(n->Children[0], indent+3);
472 _slang_print_ir_tree(n->Children[1], indent+3);
473 }
474 }