2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2008 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 * Functions for constant folding, built-in constant lookup, and function
31 #include "main/imports.h"
32 #include "main/macros.h"
34 #include "slang_compile.h"
35 #include "slang_codegen.h"
36 #include "slang_simplify.h"
37 #include "slang_print.h"
40 #ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS
41 #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
43 #ifndef GL_MAX_VERTEX_UNIFORM_VECTORS
44 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
46 #ifndef GL_MAX_VARYING_VECTORS
47 #define GL_MAX_VARYING_VECTORS 0x8DFC
52 * Lookup the value of named constant, such as gl_MaxLights.
53 * \return value of constant, or -1 if unknown
56 _slang_lookup_constant(const char *name
)
58 struct constant_info
{
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
},
76 { "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS
},
77 { "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS
},
78 { "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS
},
84 for (i
= 0; info
[i
].Name
; i
++) {
85 if (strcmp(info
[i
].Name
, name
) == 0) {
88 _mesa_GetIntegerv(info
[i
].Token
, &value
);
89 ASSERT(value
>= 0); /* sanity check that glGetFloatv worked */
97 static slang_operation_type
98 literal_type(slang_operation_type t1
, slang_operation_type t2
)
100 if (t1
== SLANG_OPER_LITERAL_FLOAT
|| t2
== SLANG_OPER_LITERAL_FLOAT
)
101 return SLANG_OPER_LITERAL_FLOAT
;
103 return SLANG_OPER_LITERAL_INT
;
108 * Recursively traverse an AST tree, applying simplifications wherever
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];
115 _slang_simplify(slang_operation
*oper
,
116 const slang_name_space
* space
,
117 slang_atom_pool
* atoms
)
119 GLboolean isFloat
[4];
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);*/
131 oper
->literal
[3] = (GLfloat
) value
;
132 oper
->type
= SLANG_OPER_LITERAL_INT
;
135 /* look for user-defined constant */
138 var
= _slang_variable_locate(oper
->locals
, oper
->a_id
, GL_TRUE
);
140 if (var
->type
.qualifier
== SLANG_QUAL_CONST
&&
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
;
151 printf("value[%s] = %f\n",
152 (char*) oper->a_id, oper->literal[0]);
160 /* first, simplify children */
161 for (i
= 0; i
< oper
->num_children
; i
++) {
162 _slang_simplify(&oper
->children
[i
], space
, atoms
);
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
);
173 if (oper
->num_children
== 2 && isFloat
[0] && isFloat
[1]) {
174 /* probably simple arithmetic */
175 switch (oper
->type
) {
177 for (i
= 0; i
< 4; i
++) {
179 = oper
->children
[0].literal
[i
] + oper
->children
[1].literal
[i
];
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 */
186 case SLANG_OPER_SUBTRACT
:
187 for (i
= 0; i
< 4; i
++) {
189 = oper
->children
[0].literal
[i
] - oper
->children
[1].literal
[i
];
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
);
196 case SLANG_OPER_MULTIPLY
:
197 for (i
= 0; i
< 4; i
++) {
199 = oper
->children
[0].literal
[i
] * oper
->children
[1].literal
[i
];
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
);
206 case SLANG_OPER_DIVIDE
:
207 for (i
= 0; i
< 4; i
++) {
209 = oper
->children
[0].literal
[i
] / oper
->children
[1].literal
[i
];
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
);
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
];
227 oper
->literal_size
= oper
->children
[0].literal_size
;
228 slang_operation_destruct(oper
);
229 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
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
;
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
);
251 oper
->literal_size
= oper
->children
[0].literal_size
;
252 slang_operation_destruct(oper
);
253 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
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
);
261 oper
->literal_size
= oper
->children
[0].literal_size
;
262 slang_operation_destruct(oper
);
263 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
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
);
271 oper
->literal_size
= oper
->children
[0].literal_size
;
272 slang_operation_destruct(oper
);
273 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
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
;
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
;
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);
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') {
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);
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.
357 * void foo(int i, bool b) {}
359 * Gets translated into:
360 * x = foo(int(3.15), bool(9))
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
)
367 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
368 const int numParams
= fun
->param_count
- haveRetValue
;
373 printf("Adapt call of %d args to func %s (%d params)\n",
374 callOper
->num_children
, (char*) fun
->header
.a_name
, numParams
);
376 for (i
= 0; i
< numParams
; i
++) {
377 slang_typeinfo argType
;
378 slang_variable
*paramVar
= fun
->parameters
->variables
[i
];
380 /* Get type of arg[i] */
381 if (!slang_typeinfo_construct(&argType
))
383 if (!_slang_typeof_operation(&callOper
->children
[i
], space
,
384 &argType
, atoms
, log
)) {
385 slang_typeinfo_destruct(&argType
);
389 /* see if arg type matches parameter type */
390 if (!slang_type_specifier_equal(&argType
.spec
,
391 ¶mVar
->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);
398 printf("Need to adapt types of arg %d\n", i
);
400 slang_operation_copy(child
, &callOper
->children
[i
]);
401 child
->locals
->outer_scope
= callOper
->children
[i
].locals
;
404 if (_slang_sizeof_type_specifier(&argType
.spec
) >
405 _slang_sizeof_type_specifier(¶mVar
->type
.specifier
)) {
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
;
415 slang_typeinfo_destruct(&argType
);
419 printf("===== New call to %s with cast arguments ===============\n",
420 (char*) fun
->header
.a_name
);
421 slang_print_tree(callOper
, 5);
429 * Adapt the arguments for a function call to match the parameters of
430 * the given function.
432 * 1. converting/casting argument types to match parameters
433 * 2. breaking up vector/matrix types into individual components to
434 * satisfy constructors.
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
)
441 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
442 const int numParams
= fun
->param_count
- haveRetValue
;
447 printf("Adapt %d args to %d parameters for %s\n",
448 callOper
->num_children
, numParams
, (char *) fun
->header
.a_name
);
450 /* Only try adapting for constructors */
451 if (fun
->kind
!= SLANG_FUNC_CONSTRUCTOR
)
454 if (callOper
->num_children
!= numParams
) {
455 /* number of arguments doesn't match number of parameters */
457 /* For constructor calls, we can try to unroll vector/matrix args
458 * into individual floats/ints and try to match the function params.
460 for (i
= 0; i
< numParams
; i
++) {
461 slang_typeinfo argType
;
464 /* Get type of arg[i] */
465 if (!slang_typeinfo_construct(&argType
))
467 if (!_slang_typeof_operation(&callOper
->children
[i
], space
,
468 &argType
, atoms
, log
)) {
469 slang_typeinfo_destruct(&argType
);
474 paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier);
475 assert(paramSz == 1);
477 argSz
= _slang_sizeof_type_specifier(&argType
.spec
);
479 slang_operation origArg
;
480 /* break up arg[i] into components */
482 printf("Break up arg %d from 1 to %d elements\n", i
, argSz
);
484 slang_operation_construct(&origArg
);
485 slang_operation_copy(&origArg
, &callOper
->children
[i
]);
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
);
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],
501 callOper
->children
[i
+ j
].children
[1].type
502 = SLANG_OPER_LITERAL_INT
;
503 callOper
->children
[i
+ j
].children
[1].literal
[0] = (GLfloat
) j
;
509 if (callOper
->num_children
< (GLuint
) numParams
) {
510 /* still not enough args for all params */
513 else if (callOper
->num_children
> (GLuint
) numParams
) {
514 /* now too many arguments */
516 callOper
->num_children
= (GLuint
) numParams
;
520 printf("===== New call to %s with adapted arguments ===============\n",
521 (char*) fun
->header
.a_name
);
522 slang_print_tree(callOper
, 5);