mesa: add comments and change Index2D to just Index2
[mesa.git] / src / mesa / slang / slang_ir.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2005-2008 Brian Paul All Rights Reserved.
5 * Copyright (C) 2009 VMware, Inc. 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 "program/prog_instruction.h"
31 #include "program/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_CMP, "IR_CMP", OPCODE_CMP, 4, 3 }, /* compare/select */
84 { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 },
85 { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 },
86 { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 },
87 { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 },
88 { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 },
89 { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 },
90 { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 },
91 { IR_COPY, "IR_COPY", OPCODE_NOP, 0, 1 },
92 { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 },
93 { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 },
94 { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 },
95 { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
96 { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 },
97 { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 },
98 { IR_TEX_SH, "IR_TEX_SH", OPCODE_TEX, 4, 1 },
99 { IR_TEXB_SH, "IR_TEXB_SH", OPCODE_TXB, 4, 1 },
100 { IR_TEXP_SH, "IR_TEXP_SH", OPCODE_TXP, 4, 1 },
101 { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */
102 { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 },
103 { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 },
104 { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 },
105 { IR_NOP, "IR_NOP", OPCODE_NOP, 0, 0 },
106 { IR_EMIT_VERTEX, "IR_EMIT_VERTEX", OPCODE_EMIT_VERTEX, 0, 0 },
107 { IR_END_PRIMITIVE, "IR_END_PRIMITIVE", OPCODE_END_PRIMITIVE, 0, 0 },
108 { 0, NULL, 0, 0, 0 }
109 };
110
111
112 const slang_ir_info *
113 _slang_ir_info(slang_ir_opcode opcode)
114 {
115 GLuint i;
116 for (i = 0; IrInfo[i].IrName; i++) {
117 if (IrInfo[i].IrOpcode == opcode) {
118 return IrInfo + i;
119 }
120 }
121 return NULL;
122 }
123
124
125 void
126 _slang_init_ir_storage(slang_ir_storage *st,
127 gl_register_file file, GLint index, GLint size,
128 GLuint swizzle)
129 {
130 st->File = file;
131 st->Index = index;
132 st->Size = size;
133 st->Swizzle = swizzle;
134 st->Parent = NULL;
135 st->IsIndirect = GL_FALSE;
136 st->Is2D = GL_FALSE;
137 st->Index2 = 0;
138 }
139
140
141 /**
142 * Return a new slang_ir_storage object.
143 */
144 slang_ir_storage *
145 _slang_new_ir_storage(gl_register_file file, GLint index, GLint size)
146 {
147 slang_ir_storage *st;
148 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
149 if (st) {
150 st->File = file;
151 st->Index = index;
152 st->Size = size;
153 st->Swizzle = SWIZZLE_NOOP;
154 st->Parent = NULL;
155 st->IsIndirect = GL_FALSE;
156 st->Is2D = GL_FALSE;
157 st->Index2 = 0;
158 }
159 return st;
160 }
161
162
163 /**
164 * Return a new slang_ir_storage object.
165 */
166 slang_ir_storage *
167 _slang_new_ir_storage_swz(gl_register_file file, GLint index, GLint size,
168 GLuint swizzle)
169 {
170 slang_ir_storage *st;
171 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
172 if (st) {
173 st->File = file;
174 st->Index = index;
175 st->Size = size;
176 st->Swizzle = swizzle;
177 st->Parent = NULL;
178 st->IsIndirect = GL_FALSE;
179 st->Is2D = GL_FALSE;
180 st->Index2 = 0;
181 }
182 return st;
183 }
184
185 /**
186 * Return a new slang_ir_storage object.
187 */
188 slang_ir_storage *
189 _slang_new_ir_storage_2d(gl_register_file file,
190 GLint index, GLint index2,
191 GLint size, GLuint swizzle)
192 {
193 slang_ir_storage *st;
194 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
195 if (st) {
196 st->File = file;
197 st->Index = index;
198 st->Size = size;
199 st->Swizzle = swizzle;
200 st->Parent = NULL;
201 st->IsIndirect = GL_FALSE;
202 st->Is2D = GL_TRUE;
203 st->Index2 = index2;
204 }
205 return st;
206 }
207
208
209
210 /**
211 * Return a new slang_ir_storage object.
212 */
213 slang_ir_storage *
214 _slang_new_ir_storage_relative(GLint index, GLint size,
215 slang_ir_storage *parent)
216 {
217 slang_ir_storage *st;
218 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
219 if (st) {
220 st->File = PROGRAM_UNDEFINED;
221 st->Index = index;
222 st->Size = size;
223 st->Swizzle = SWIZZLE_NOOP;
224 st->Parent = parent;
225 st->IsIndirect = GL_FALSE;
226 st->Is2D = GL_FALSE;
227 st->Index2 = 0;
228 }
229 return st;
230 }
231
232
233 slang_ir_storage *
234 _slang_new_ir_storage_indirect(gl_register_file file,
235 GLint index,
236 GLint size,
237 gl_register_file indirectFile,
238 GLint indirectIndex,
239 GLuint indirectSwizzle)
240 {
241 slang_ir_storage *st;
242 st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
243 if (st) {
244 st->File = file;
245 st->Index = index;
246 st->Size = size;
247 st->Swizzle = SWIZZLE_NOOP;
248 st->IsIndirect = GL_TRUE;
249 st->IndirectFile = indirectFile;
250 st->IndirectIndex = indirectIndex;
251 st->IndirectSwizzle = indirectSwizzle;
252 st->Is2D = GL_FALSE;
253 st->Index2 = 0;
254 }
255 return st;
256 }
257
258
259 /**
260 * Allocate IR storage for a texture sampler.
261 * \param sampNum the sampler number/index
262 * \param texTarget one of TEXTURE_x_INDEX values
263 * \param size number of samplers (in case of sampler array)
264 */
265 slang_ir_storage *
266 _slang_new_ir_storage_sampler(GLint sampNum, GLuint texTarget, GLint size)
267 {
268 slang_ir_storage *st;
269 assert(texTarget < NUM_TEXTURE_TARGETS);
270 st = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, size);
271 if (st) {
272 st->TexTarget = texTarget;
273 }
274 return st;
275 }
276
277
278
279 /* XXX temporary function */
280 void
281 _slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src)
282 {
283 *dst = *src;
284 dst->Parent = NULL;
285 }
286
287
288
289 static const char *
290 _slang_ir_name(slang_ir_opcode opcode)
291 {
292 return _slang_ir_info(opcode)->IrName;
293 }
294
295
296
297 #if 0 /* no longer needed with mempool */
298 /**
299 * Since many IR nodes might point to the same IR storage info, we need
300 * to be careful when deleting things.
301 * Before deleting an IR tree, traverse it and do refcounting on the
302 * IR storage nodes. Use the refcount info during delete to free things
303 * properly.
304 */
305 static void
306 _slang_refcount_storage(slang_ir_node *n)
307 {
308 GLuint i;
309 if (!n)
310 return;
311 if (n->Store)
312 n->Store->RefCount++;
313 for (i = 0; i < 3; i++)
314 _slang_refcount_storage(n->Children[i]);
315 }
316 #endif
317
318
319 static void
320 _slang_free_ir(slang_ir_node *n)
321 {
322 GLuint i;
323 if (!n)
324 return;
325
326 #if 0
327 if (n->Store) {
328 n->Store->RefCount--;
329 if (n->Store->RefCount == 0) {
330 _slang_free(n->Store);
331 n->Store = NULL;
332 }
333 }
334 #endif
335
336 for (i = 0; i < 3; i++)
337 _slang_free_ir(n->Children[i]);
338 /* Do not free n->List since it's a child elsewhere */
339 _slang_free(n);
340 }
341
342
343 /**
344 * Recursively free an IR tree.
345 */
346 void
347 _slang_free_ir_tree(slang_ir_node *n)
348 {
349 #if 0
350 _slang_refcount_storage(n);
351 #endif
352 _slang_free_ir(n);
353 }
354
355
356 static const char *
357 storage_string(const slang_ir_storage *st)
358 {
359 static const char *files[] = {
360 "TEMP",
361 "LOCAL_PARAM",
362 "ENV_PARAM",
363 "STATE",
364 "INPUT",
365 "OUTPUT",
366 "NAMED_PARAM",
367 "CONSTANT",
368 "UNIFORM",
369 "VARYING",
370 "WRITE_ONLY",
371 "ADDRESS",
372 "SAMPLER",
373 "UNDEFINED"
374 };
375 static char s[100];
376 assert(Elements(files) == PROGRAM_FILE_MAX);
377 #if 0
378 if (st->Size == 1)
379 _mesa_snprintf(s, "%s[%d]", files[st->File], st->Index);
380 else
381 _mesa_snprintf(s, "%s[%d..%d]", files[st->File], st->Index,
382 st->Index + st->Size - 1);
383 #endif
384 assert(st->File < (GLint) (sizeof(files) / sizeof(files[0])));
385 _mesa_snprintf(s, sizeof(s), "%s[%d]", files[st->File], st->Index);
386 return s;
387 }
388
389
390 static void
391 spaces(int n)
392 {
393 while (n-- > 0) {
394 printf(" ");
395 }
396 }
397
398
399 void
400 _slang_print_ir_tree(const slang_ir_node *n, int indent)
401 {
402 #define IND 0
403
404 if (!n)
405 return;
406 #if !IND
407 if (n->Opcode != IR_SEQ)
408 #else
409 printf("%3d:", indent);
410 #endif
411 spaces(indent);
412
413 switch (n->Opcode) {
414 case IR_SEQ:
415 #if IND
416 printf("SEQ at %p\n", (void*) n);
417 #endif
418 assert(n->Children[0]);
419 assert(n->Children[1]);
420 _slang_print_ir_tree(n->Children[0], indent + IND);
421 _slang_print_ir_tree(n->Children[1], indent + IND);
422 break;
423 case IR_SCOPE:
424 printf("NEW SCOPE\n");
425 assert(!n->Children[1]);
426 _slang_print_ir_tree(n->Children[0], indent + 3);
427 break;
428 case IR_COPY:
429 printf("COPY\n");
430 _slang_print_ir_tree(n->Children[0], indent+3);
431 _slang_print_ir_tree(n->Children[1], indent+3);
432 break;
433 case IR_LABEL:
434 printf("LABEL: %s\n", n->Label->Name);
435 break;
436 case IR_COND:
437 printf("COND\n");
438 _slang_print_ir_tree(n->Children[0], indent + 3);
439 break;
440
441 case IR_IF:
442 printf("IF \n");
443 _slang_print_ir_tree(n->Children[0], indent+3);
444 spaces(indent);
445 printf("THEN\n");
446 _slang_print_ir_tree(n->Children[1], indent+3);
447 if (n->Children[2]) {
448 spaces(indent);
449 printf("ELSE\n");
450 _slang_print_ir_tree(n->Children[2], indent+3);
451 }
452 spaces(indent);
453 printf("ENDIF\n");
454 break;
455
456 case IR_BEGIN_SUB:
457 printf("BEGIN_SUB\n");
458 break;
459 case IR_END_SUB:
460 printf("END_SUB\n");
461 break;
462 case IR_RETURN:
463 printf("RETURN\n");
464 break;
465 case IR_CALL:
466 printf("CALL %s\n", n->Label->Name);
467 break;
468
469 case IR_LOOP:
470 printf("LOOP\n");
471 _slang_print_ir_tree(n->Children[0], indent+3);
472 if (n->Children[1]) {
473 spaces(indent);
474 printf("TAIL:\n");
475 _slang_print_ir_tree(n->Children[1], indent+3);
476 }
477 spaces(indent);
478 printf("ENDLOOP\n");
479 break;
480 case IR_CONT:
481 printf("CONT\n");
482 break;
483 case IR_BREAK:
484 printf("BREAK\n");
485 break;
486 case IR_BREAK_IF_TRUE:
487 printf("BREAK_IF_TRUE\n");
488 _slang_print_ir_tree(n->Children[0], indent+3);
489 break;
490 case IR_CONT_IF_TRUE:
491 printf("CONT_IF_TRUE\n");
492 _slang_print_ir_tree(n->Children[0], indent+3);
493 break;
494
495 case IR_VAR:
496 printf("VAR %s%s at %s store %p\n",
497 (n->Var ? (char *) n->Var->a_name : "TEMP"),
498 _mesa_swizzle_string(n->Store->Swizzle, 0, 0),
499 storage_string(n->Store), (void*) n->Store);
500 break;
501 case IR_VAR_DECL:
502 printf("VAR_DECL %s (%p) at %s store %p\n",
503 (n->Var ? (char *) n->Var->a_name : "TEMP"),
504 (void*) n->Var, storage_string(n->Store),
505 (void*) n->Store);
506 break;
507 case IR_FIELD:
508 printf("FIELD %s of\n", n->Field);
509 _slang_print_ir_tree(n->Children[0], indent+3);
510 break;
511 case IR_FLOAT:
512 printf("FLOAT %g %g %g %g\n",
513 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
514 break;
515 case IR_I_TO_F:
516 printf("INT_TO_FLOAT\n");
517 _slang_print_ir_tree(n->Children[0], indent+3);
518 break;
519 case IR_F_TO_I:
520 printf("FLOAT_TO_INT\n");
521 _slang_print_ir_tree(n->Children[0], indent+3);
522 break;
523 case IR_SWIZZLE:
524 printf("SWIZZLE %s of (store %p) \n",
525 _mesa_swizzle_string(n->Store->Swizzle, 0, 0), (void*) n->Store);
526 _slang_print_ir_tree(n->Children[0], indent + 3);
527 break;
528 default:
529 printf("%s (%p, %p) (store %p)\n", _slang_ir_name(n->Opcode),
530 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
531 _slang_print_ir_tree(n->Children[0], indent+3);
532 _slang_print_ir_tree(n->Children[1], indent+3);
533 }
534 }