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