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