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