slang: Check return value from new_instruction().
[mesa.git] / src / mesa / shader / slang / slang_simplify.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 * Functions for constant folding, built-in constant lookup, and function
27 * call casting.
28 */
29
30
31 #include "main/imports.h"
32 #include "main/macros.h"
33 #include "main/get.h"
34 #include "slang_compile.h"
35 #include "slang_codegen.h"
36 #include "slang_simplify.h"
37 #include "slang_print.h"
38
39
40 #ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS
41 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
42 #endif
43 #ifndef GL_MAX_VERTEX_UNIFORM_VECTORS
44 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
45 #endif
46 #ifndef GL_MAX_VARYING_VECTORS
47 #define GL_MAX_VARYING_VECTORS 0x8DFC
48 #endif
49
50
51 /**
52 * Lookup the value of named constant, such as gl_MaxLights.
53 * \return value of constant, or -1 if unknown
54 */
55 GLint
56 _slang_lookup_constant(const char *name)
57 {
58 struct constant_info {
59 const char *Name;
60 const GLenum Token;
61 };
62 static const struct constant_info info[] = {
63 { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES },
64 { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS },
65 { "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS },
66 { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS },
67 { "gl_MaxLights", GL_MAX_LIGHTS },
68 { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS },
69 { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS },
70 { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS },
71 { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS },
72 { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS },
73 { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS },
74 { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS },
75 #if FEATURE_es2_glsl
76 { "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS },
77 { "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS },
78 { "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS },
79 #endif
80 { NULL, 0 }
81 };
82 GLuint i;
83
84 for (i = 0; info[i].Name; i++) {
85 if (strcmp(info[i].Name, name) == 0) {
86 /* found */
87 GLint value = -1;
88 _mesa_GetIntegerv(info[i].Token, &value);
89 ASSERT(value >= 0); /* sanity check that glGetFloatv worked */
90 return value;
91 }
92 }
93 return -1;
94 }
95
96
97 static slang_operation_type
98 literal_type(slang_operation_type t1, slang_operation_type t2)
99 {
100 if (t1 == SLANG_OPER_LITERAL_FLOAT || t2 == SLANG_OPER_LITERAL_FLOAT)
101 return SLANG_OPER_LITERAL_FLOAT;
102 else
103 return SLANG_OPER_LITERAL_INT;
104 }
105
106
107 /**
108 * Recursively traverse an AST tree, applying simplifications wherever
109 * possible.
110 * At the least, we do constant folding. We need to do that much so that
111 * compile-time expressions can be evaluated for things like array
112 * declarations. I.e.: float foo[3 + 5];
113 */
114 void
115 _slang_simplify(slang_operation *oper,
116 const slang_name_space * space,
117 slang_atom_pool * atoms)
118 {
119 GLboolean isFloat[4];
120 GLboolean isBool[4];
121 GLuint i, n;
122
123 if (oper->type == SLANG_OPER_IDENTIFIER) {
124 /* see if it's a named constant */
125 GLint value = _slang_lookup_constant((char *) oper->a_id);
126 /*printf("value[%s] = %d\n", (char*) oper->a_id, value);*/
127 if (value >= 0) {
128 oper->literal[0] =
129 oper->literal[1] =
130 oper->literal[2] =
131 oper->literal[3] = (GLfloat) value;
132 oper->type = SLANG_OPER_LITERAL_INT;
133 return;
134 }
135 /* look for user-defined constant */
136 {
137 slang_variable *var;
138 var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE);
139 if (var) {
140 if (var->type.qualifier == SLANG_QUAL_CONST &&
141 var->initializer &&
142 (var->initializer->type == SLANG_OPER_LITERAL_INT ||
143 var->initializer->type == SLANG_OPER_LITERAL_FLOAT)) {
144 oper->literal[0] = var->initializer->literal[0];
145 oper->literal[1] = var->initializer->literal[1];
146 oper->literal[2] = var->initializer->literal[2];
147 oper->literal[3] = var->initializer->literal[3];
148 oper->literal_size = var->initializer->literal_size;
149 oper->type = var->initializer->type;
150 /*
151 printf("value[%s] = %f\n",
152 (char*) oper->a_id, oper->literal[0]);
153 */
154 return;
155 }
156 }
157 }
158 }
159
160 /* first, simplify children */
161 for (i = 0; i < oper->num_children; i++) {
162 _slang_simplify(&oper->children[i], space, atoms);
163 }
164
165 /* examine children */
166 n = MIN2(oper->num_children, 4);
167 for (i = 0; i < n; i++) {
168 isFloat[i] = (oper->children[i].type == SLANG_OPER_LITERAL_FLOAT ||
169 oper->children[i].type == SLANG_OPER_LITERAL_INT);
170 isBool[i] = (oper->children[i].type == SLANG_OPER_LITERAL_BOOL);
171 }
172
173 if (oper->num_children == 2 && isFloat[0] && isFloat[1]) {
174 /* probably simple arithmetic */
175 switch (oper->type) {
176 case SLANG_OPER_ADD:
177 for (i = 0; i < 4; i++) {
178 oper->literal[i]
179 = oper->children[0].literal[i] + oper->children[1].literal[i];
180 }
181 oper->literal_size = oper->children[0].literal_size;
182 oper->type = literal_type(oper->children[0].type,
183 oper->children[1].type);
184 slang_operation_destruct(oper); /* frees unused children */
185 return;
186 case SLANG_OPER_SUBTRACT:
187 for (i = 0; i < 4; i++) {
188 oper->literal[i]
189 = oper->children[0].literal[i] - oper->children[1].literal[i];
190 }
191 oper->literal_size = oper->children[0].literal_size;
192 oper->type = literal_type(oper->children[0].type,
193 oper->children[1].type);
194 slang_operation_destruct(oper);
195 return;
196 case SLANG_OPER_MULTIPLY:
197 for (i = 0; i < 4; i++) {
198 oper->literal[i]
199 = oper->children[0].literal[i] * oper->children[1].literal[i];
200 }
201 oper->literal_size = oper->children[0].literal_size;
202 oper->type = literal_type(oper->children[0].type,
203 oper->children[1].type);
204 slang_operation_destruct(oper);
205 return;
206 case SLANG_OPER_DIVIDE:
207 for (i = 0; i < 4; i++) {
208 oper->literal[i]
209 = oper->children[0].literal[i] / oper->children[1].literal[i];
210 }
211 oper->literal_size = oper->children[0].literal_size;
212 oper->type = literal_type(oper->children[0].type,
213 oper->children[1].type);
214 slang_operation_destruct(oper);
215 return;
216 default:
217 ; /* nothing */
218 }
219 }
220
221 if (oper->num_children == 1 && isFloat[0]) {
222 switch (oper->type) {
223 case SLANG_OPER_MINUS:
224 for (i = 0; i < 4; i++) {
225 oper->literal[i] = -oper->children[0].literal[i];
226 }
227 oper->literal_size = oper->children[0].literal_size;
228 slang_operation_destruct(oper);
229 oper->type = SLANG_OPER_LITERAL_FLOAT;
230 return;
231 case SLANG_OPER_PLUS:
232 COPY_4V(oper->literal, oper->children[0].literal);
233 oper->literal_size = oper->children[0].literal_size;
234 slang_operation_destruct(oper);
235 oper->type = SLANG_OPER_LITERAL_FLOAT;
236 return;
237 default:
238 ; /* nothing */
239 }
240 }
241
242 if (oper->num_children == 2 && isBool[0] && isBool[1]) {
243 /* simple boolean expression */
244 switch (oper->type) {
245 case SLANG_OPER_LOGICALAND:
246 for (i = 0; i < 4; i++) {
247 const GLint a = oper->children[0].literal[i] ? 1 : 0;
248 const GLint b = oper->children[1].literal[i] ? 1 : 0;
249 oper->literal[i] = (GLfloat) (a && b);
250 }
251 oper->literal_size = oper->children[0].literal_size;
252 slang_operation_destruct(oper);
253 oper->type = SLANG_OPER_LITERAL_BOOL;
254 return;
255 case SLANG_OPER_LOGICALOR:
256 for (i = 0; i < 4; i++) {
257 const GLint a = oper->children[0].literal[i] ? 1 : 0;
258 const GLint b = oper->children[1].literal[i] ? 1 : 0;
259 oper->literal[i] = (GLfloat) (a || b);
260 }
261 oper->literal_size = oper->children[0].literal_size;
262 slang_operation_destruct(oper);
263 oper->type = SLANG_OPER_LITERAL_BOOL;
264 return;
265 case SLANG_OPER_LOGICALXOR:
266 for (i = 0; i < 4; i++) {
267 const GLint a = oper->children[0].literal[i] ? 1 : 0;
268 const GLint b = oper->children[1].literal[i] ? 1 : 0;
269 oper->literal[i] = (GLfloat) (a ^ b);
270 }
271 oper->literal_size = oper->children[0].literal_size;
272 slang_operation_destruct(oper);
273 oper->type = SLANG_OPER_LITERAL_BOOL;
274 return;
275 default:
276 ; /* nothing */
277 }
278 }
279
280 if (oper->num_children == 4
281 && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) {
282 /* vec4(flt, flt, flt, flt) constructor */
283 if (oper->type == SLANG_OPER_CALL) {
284 if (strcmp((char *) oper->a_id, "vec4") == 0) {
285 oper->literal[0] = oper->children[0].literal[0];
286 oper->literal[1] = oper->children[1].literal[0];
287 oper->literal[2] = oper->children[2].literal[0];
288 oper->literal[3] = oper->children[3].literal[0];
289 oper->literal_size = 4;
290 slang_operation_destruct(oper);
291 oper->type = SLANG_OPER_LITERAL_FLOAT;
292 return;
293 }
294 }
295 }
296
297 if (oper->num_children == 3 && isFloat[0] && isFloat[1] && isFloat[2]) {
298 /* vec3(flt, flt, flt) constructor */
299 if (oper->type == SLANG_OPER_CALL) {
300 if (strcmp((char *) oper->a_id, "vec3") == 0) {
301 oper->literal[0] = oper->children[0].literal[0];
302 oper->literal[1] = oper->children[1].literal[0];
303 oper->literal[2] = oper->children[2].literal[0];
304 oper->literal[3] = oper->literal[2];
305 oper->literal_size = 3;
306 slang_operation_destruct(oper);
307 oper->type = SLANG_OPER_LITERAL_FLOAT;
308 return;
309 }
310 }
311 }
312
313 if (oper->num_children == 2 && isFloat[0] && isFloat[1]) {
314 /* vec2(flt, flt) constructor */
315 if (oper->type == SLANG_OPER_CALL) {
316 if (strcmp((char *) oper->a_id, "vec2") == 0) {
317 oper->literal[0] = oper->children[0].literal[0];
318 oper->literal[1] = oper->children[1].literal[0];
319 oper->literal[2] = oper->literal[1];
320 oper->literal[3] = oper->literal[1];
321 oper->literal_size = 2;
322 slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */
323 oper->type = SLANG_OPER_LITERAL_FLOAT;
324 assert(oper->num_children == 0);
325 return;
326 }
327 }
328 }
329
330 if (oper->num_children == 1 && isFloat[0]) {
331 /* vec2/3/4(flt, flt) constructor */
332 if (oper->type == SLANG_OPER_CALL) {
333 const char *func = (const char *) oper->a_id;
334 if (strncmp(func, "vec", 3) == 0 && func[3] >= '2' && func[3] <= '4') {
335 oper->literal[0] =
336 oper->literal[1] =
337 oper->literal[2] =
338 oper->literal[3] = oper->children[0].literal[0];
339 oper->literal_size = func[3] - '0';
340 assert(oper->literal_size >= 2);
341 assert(oper->literal_size <= 4);
342 slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */
343 oper->type = SLANG_OPER_LITERAL_FLOAT;
344 assert(oper->num_children == 0);
345 return;
346 }
347 }
348 }
349 }
350
351
352
353 /**
354 * Insert casts to try to adapt actual parameters to formal parameters for a
355 * function call when an exact match for the parameter types is not found.
356 * Example:
357 * void foo(int i, bool b) {}
358 * x = foo(3.15, 9);
359 * Gets translated into:
360 * x = foo(int(3.15), bool(9))
361 */
362 GLboolean
363 _slang_cast_func_params(slang_operation *callOper, const slang_function *fun,
364 const slang_name_space * space,
365 slang_atom_pool * atoms, slang_info_log *log)
366 {
367 const GLboolean haveRetValue = _slang_function_has_return_value(fun);
368 const int numParams = fun->param_count - haveRetValue;
369 int i;
370 int dbg = 0;
371
372 if (dbg)
373 printf("Adapt call of %d args to func %s (%d params)\n",
374 callOper->num_children, (char*) fun->header.a_name, numParams);
375
376 for (i = 0; i < numParams; i++) {
377 slang_typeinfo argType;
378 slang_variable *paramVar = fun->parameters->variables[i];
379
380 /* Get type of arg[i] */
381 if (!slang_typeinfo_construct(&argType))
382 return GL_FALSE;
383 if (!_slang_typeof_operation(&callOper->children[i], space,
384 &argType, atoms, log)) {
385 slang_typeinfo_destruct(&argType);
386 return GL_FALSE;
387 }
388
389 /* see if arg type matches parameter type */
390 if (!slang_type_specifier_equal(&argType.spec,
391 &paramVar->type.specifier)) {
392 /* need to adapt arg type to match param type */
393 const char *constructorName =
394 slang_type_specifier_type_to_string(paramVar->type.specifier.type);
395 slang_operation *child = slang_operation_new(1);
396
397 if (dbg)
398 printf("Need to adapt types of arg %d\n", i);
399
400 slang_operation_copy(child, &callOper->children[i]);
401 child->locals->outer_scope = callOper->children[i].locals;
402
403 #if 0
404 if (_slang_sizeof_type_specifier(&argType.spec) >
405 _slang_sizeof_type_specifier(&paramVar->type.specifier)) {
406 }
407 #endif
408
409 callOper->children[i].type = SLANG_OPER_CALL;
410 callOper->children[i].a_id = slang_atom_pool_atom(atoms, constructorName);
411 callOper->children[i].num_children = 1;
412 callOper->children[i].children = child;
413 }
414
415 slang_typeinfo_destruct(&argType);
416 }
417
418 if (dbg) {
419 printf("===== New call to %s with cast arguments ===============\n",
420 (char*) fun->header.a_name);
421 slang_print_tree(callOper, 5);
422 }
423
424 return GL_TRUE;
425 }
426
427
428 /**
429 * Adapt the arguments for a function call to match the parameters of
430 * the given function.
431 * This is for:
432 * 1. converting/casting argument types to match parameters
433 * 2. breaking up vector/matrix types into individual components to
434 * satisfy constructors.
435 */
436 GLboolean
437 _slang_adapt_call(slang_operation *callOper, const slang_function *fun,
438 const slang_name_space * space,
439 slang_atom_pool * atoms, slang_info_log *log)
440 {
441 const GLboolean haveRetValue = _slang_function_has_return_value(fun);
442 const int numParams = fun->param_count - haveRetValue;
443 int i;
444 int dbg = 0;
445
446 if (dbg)
447 printf("Adapt %d args to %d parameters for %s\n",
448 callOper->num_children, numParams, (char *) fun->header.a_name);
449
450 /* Only try adapting for constructors */
451 if (fun->kind != SLANG_FUNC_CONSTRUCTOR)
452 return GL_FALSE;
453
454 if (callOper->num_children != numParams) {
455 /* number of arguments doesn't match number of parameters */
456
457 /* For constructor calls, we can try to unroll vector/matrix args
458 * into individual floats/ints and try to match the function params.
459 */
460 for (i = 0; i < numParams; i++) {
461 slang_typeinfo argType;
462 GLint argSz, j;
463
464 /* Get type of arg[i] */
465 if (!slang_typeinfo_construct(&argType))
466 return GL_FALSE;
467 if (!_slang_typeof_operation(&callOper->children[i], space,
468 &argType, atoms, log)) {
469 slang_typeinfo_destruct(&argType);
470 return GL_FALSE;
471 }
472
473 /*
474 paramSz = _slang_sizeof_type_specifier(&paramVar->type.specifier);
475 assert(paramSz == 1);
476 */
477 argSz = _slang_sizeof_type_specifier(&argType.spec);
478 if (argSz > 1) {
479 slang_operation origArg;
480 /* break up arg[i] into components */
481 if (dbg)
482 printf("Break up arg %d from 1 to %d elements\n", i, argSz);
483
484 slang_operation_construct(&origArg);
485 slang_operation_copy(&origArg, &callOper->children[i]);
486
487 /* insert argSz-1 new children/args */
488 for (j = 0; j < argSz - 1; j++) {
489 (void) slang_operation_insert(&callOper->num_children,
490 &callOper->children, i);
491 }
492
493 /* replace arg[i+j] with subscript/index oper */
494 for (j = 0; j < argSz; j++) {
495 callOper->children[i + j].type = SLANG_OPER_SUBSCRIPT;
496 callOper->children[i + j].locals = _slang_variable_scope_new(callOper->locals);
497 callOper->children[i + j].num_children = 2;
498 callOper->children[i + j].children = slang_operation_new(2);
499 slang_operation_copy(&callOper->children[i + j].children[0],
500 &origArg);
501 callOper->children[i + j].children[1].type
502 = SLANG_OPER_LITERAL_INT;
503 callOper->children[i + j].children[1].literal[0] = (GLfloat) j;
504 }
505 }
506 }
507 }
508
509 if (callOper->num_children < (GLuint) numParams) {
510 /* still not enough args for all params */
511 return GL_FALSE;
512 }
513 else if (callOper->num_children > (GLuint) numParams) {
514 /* now too many arguments */
515 /* just truncate */
516 callOper->num_children = (GLuint) numParams;
517 }
518
519 if (dbg) {
520 printf("===== New call to %s with adapted arguments ===============\n",
521 (char*) fun->header.a_name);
522 slang_print_tree(callOper, 5);
523 }
524
525 return GL_TRUE;
526 }