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) {
89 _mesa_GetIntegerv(info
[i
].Token
, values
);
90 ASSERT(values
[0] >= 0); /* sanity check that glGetFloatv worked */
98 static slang_operation_type
99 literal_type(slang_operation_type t1
, slang_operation_type t2
)
101 if (t1
== SLANG_OPER_LITERAL_FLOAT
|| t2
== SLANG_OPER_LITERAL_FLOAT
)
102 return SLANG_OPER_LITERAL_FLOAT
;
104 return SLANG_OPER_LITERAL_INT
;
109 * Recursively traverse an AST tree, applying simplifications wherever
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];
116 _slang_simplify(slang_operation
*oper
,
117 const slang_name_space
* space
,
118 slang_atom_pool
* atoms
)
120 GLboolean isFloat
[4];
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);*/
132 oper
->literal
[3] = (GLfloat
) value
;
133 oper
->type
= SLANG_OPER_LITERAL_INT
;
136 /* look for user-defined constant */
139 var
= _slang_variable_locate(oper
->locals
, oper
->a_id
, GL_TRUE
);
141 if (var
->type
.qualifier
== SLANG_QUAL_CONST
&&
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
;
152 printf("value[%s] = %f\n",
153 (char*) oper->a_id, oper->literal[0]);
161 /* first, simplify children */
162 for (i
= 0; i
< oper
->num_children
; i
++) {
163 _slang_simplify(&oper
->children
[i
], space
, atoms
);
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
);
174 if (oper
->num_children
== 2 && isFloat
[0] && isFloat
[1]) {
175 /* probably simple arithmetic */
176 switch (oper
->type
) {
178 for (i
= 0; i
< 4; i
++) {
180 = oper
->children
[0].literal
[i
] + oper
->children
[1].literal
[i
];
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 */
187 case SLANG_OPER_SUBTRACT
:
188 for (i
= 0; i
< 4; i
++) {
190 = oper
->children
[0].literal
[i
] - oper
->children
[1].literal
[i
];
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
);
197 case SLANG_OPER_MULTIPLY
:
198 for (i
= 0; i
< 4; i
++) {
200 = oper
->children
[0].literal
[i
] * oper
->children
[1].literal
[i
];
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
);
207 case SLANG_OPER_DIVIDE
:
208 for (i
= 0; i
< 4; i
++) {
210 = oper
->children
[0].literal
[i
] / oper
->children
[1].literal
[i
];
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
);
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
];
228 oper
->literal_size
= oper
->children
[0].literal_size
;
229 slang_operation_destruct(oper
);
230 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
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
;
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
);
252 oper
->literal_size
= oper
->children
[0].literal_size
;
253 slang_operation_destruct(oper
);
254 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
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
);
262 oper
->literal_size
= oper
->children
[0].literal_size
;
263 slang_operation_destruct(oper
);
264 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
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
);
272 oper
->literal_size
= oper
->children
[0].literal_size
;
273 slang_operation_destruct(oper
);
274 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
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
;
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
;
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);
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') {
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);
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.
358 * void foo(int i, bool b) {}
360 * Gets translated into:
361 * x = foo(int(3.15), bool(9))
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
)
368 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
369 const int numParams
= fun
->param_count
- haveRetValue
;
374 printf("Adapt call of %d args to func %s (%d params)\n",
375 callOper
->num_children
, (char*) fun
->header
.a_name
, numParams
);
377 for (i
= 0; i
< numParams
; i
++) {
378 slang_typeinfo argType
;
379 slang_variable
*paramVar
= fun
->parameters
->variables
[i
];
381 /* Get type of arg[i] */
382 if (!slang_typeinfo_construct(&argType
))
384 if (!_slang_typeof_operation(&callOper
->children
[i
], space
,
385 &argType
, atoms
, log
)) {
386 slang_typeinfo_destruct(&argType
);
390 /* see if arg type matches parameter type */
391 if (!slang_type_specifier_equal(&argType
.spec
,
392 ¶mVar
->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);
399 printf("Need to adapt types of arg %d\n", i
);
401 slang_operation_copy(child
, &callOper
->children
[i
]);
402 child
->locals
->outer_scope
= callOper
->children
[i
].locals
;
405 if (_slang_sizeof_type_specifier(&argType
.spec
) >
406 _slang_sizeof_type_specifier(¶mVar
->type
.specifier
)) {
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
;
416 slang_typeinfo_destruct(&argType
);
420 printf("===== New call to %s with cast arguments ===============\n",
421 (char*) fun
->header
.a_name
);
422 slang_print_tree(callOper
, 5);
430 * Adapt the arguments for a function call to match the parameters of
431 * the given function.
433 * 1. converting/casting argument types to match parameters
434 * 2. breaking up vector/matrix types into individual components to
435 * satisfy constructors.
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
)
442 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
443 const int numParams
= fun
->param_count
- haveRetValue
;
448 printf("Adapt %d args to %d parameters for %s\n",
449 callOper
->num_children
, numParams
, (char *) fun
->header
.a_name
);
451 /* Only try adapting for constructors */
452 if (fun
->kind
!= SLANG_FUNC_CONSTRUCTOR
)
455 if (callOper
->num_children
!= numParams
) {
456 /* number of arguments doesn't match number of parameters */
458 /* For constructor calls, we can try to unroll vector/matrix args
459 * into individual floats/ints and try to match the function params.
461 for (i
= 0; i
< numParams
; i
++) {
462 slang_typeinfo argType
;
465 /* Get type of arg[i] */
466 if (!slang_typeinfo_construct(&argType
))
468 if (!_slang_typeof_operation(&callOper
->children
[i
], space
,
469 &argType
, atoms
, log
)) {
470 slang_typeinfo_destruct(&argType
);
475 paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier);
476 assert(paramSz == 1);
478 argSz
= _slang_sizeof_type_specifier(&argType
.spec
);
480 slang_operation origArg
;
481 /* break up arg[i] into components */
483 printf("Break up arg %d from 1 to %d elements\n", i
, argSz
);
485 slang_operation_construct(&origArg
);
486 slang_operation_copy(&origArg
, &callOper
->children
[i
]);
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
);
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],
502 callOper
->children
[i
+ j
].children
[1].type
503 = SLANG_OPER_LITERAL_INT
;
504 callOper
->children
[i
+ j
].children
[1].literal
[0] = (GLfloat
) j
;
510 if (callOper
->num_children
< (GLuint
) numParams
) {
511 /* still not enough args for all params */
514 else if (callOper
->num_children
> (GLuint
) numParams
) {
515 /* now too many arguments */
517 callOper
->num_children
= (GLuint
) numParams
;
521 printf("===== New call to %s with adapted arguments ===============\n",
522 (char*) fun
->header
.a_name
);
523 slang_print_tree(callOper
, 5);