2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2006 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 * \file slang_assemble_typeinfo.c
34 #include "slang_compile.h"
35 #include "slang_codegen.h"
36 #include "slang_simplify.h"
37 #include "slang_print.h"
43 * Lookup the value of named constant, such as gl_MaxLights.
44 * \return value of constant, or -1 if unknown
47 _slang_lookup_constant(const char *name
)
49 struct constant_info
{
53 static const struct constant_info info
[] = {
54 { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES
},
55 { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
},
56 { "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS
},
57 { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
},
58 { "gl_MaxLights", GL_MAX_LIGHTS
},
59 { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS
},
60 { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS
},
61 { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS
},
62 { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS
},
63 { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS
},
64 { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
},
65 { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS
},
70 for (i
= 0; info
[i
].Name
; i
++) {
71 if (strcmp(info
[i
].Name
, name
) == 0) {
74 _mesa_GetIntegerv(info
[i
].Token
, &value
);
75 ASSERT(value
>= 0); /* sanity check that glGetFloatv worked */
85 * Recursively traverse an AST tree, applying simplifications wherever
87 * At the least, we do constant folding. We need to do that much so that
88 * compile-time expressions can be evaluated for things like array
89 * declarations. I.e.: float foo[3 + 5];
92 _slang_simplify(slang_operation
*oper
,
93 const slang_name_space
* space
,
94 slang_atom_pool
* atoms
)
100 if (oper
->type
== SLANG_OPER_IDENTIFIER
) {
101 /* see if it's a named constant */
102 GLint value
= _slang_lookup_constant((char *) oper
->a_id
);
107 oper
->literal
[3] = value
;
108 oper
->type
= SLANG_OPER_LITERAL_INT
;
113 /* first, simplify children */
114 for (i
= 0; i
< oper
->num_children
; i
++) {
115 _slang_simplify(&oper
->children
[i
], space
, atoms
);
118 /* examine children */
119 n
= MIN2(oper
->num_children
, 4);
120 for (i
= 0; i
< n
; i
++) {
121 isFloat
[i
] = (oper
->children
[i
].type
== SLANG_OPER_LITERAL_FLOAT
||
122 oper
->children
[i
].type
== SLANG_OPER_LITERAL_INT
);
123 isBool
[i
] = (oper
->children
[i
].type
== SLANG_OPER_LITERAL_BOOL
);
126 if (oper
->num_children
== 2 && isFloat
[0] && isFloat
[1]) {
127 /* probably simple arithmetic */
128 switch (oper
->type
) {
130 for (i
= 0; i
< 4; i
++) {
132 = oper
->children
[0].literal
[i
] + oper
->children
[1].literal
[i
];
134 oper
->literal_size
= oper
->children
[0].literal_size
;
135 slang_operation_destruct(oper
);
136 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
138 case SLANG_OPER_SUBTRACT
:
139 for (i
= 0; i
< 4; i
++) {
141 = oper
->children
[0].literal
[i
] - oper
->children
[1].literal
[i
];
143 oper
->literal_size
= oper
->children
[0].literal_size
;
144 slang_operation_destruct(oper
);
145 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
147 case SLANG_OPER_MULTIPLY
:
148 for (i
= 0; i
< 4; i
++) {
150 = oper
->children
[0].literal
[i
] * oper
->children
[1].literal
[i
];
152 oper
->literal_size
= oper
->children
[0].literal_size
;
153 slang_operation_destruct(oper
);
154 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
156 case SLANG_OPER_DIVIDE
:
157 for (i
= 0; i
< 4; i
++) {
159 = oper
->children
[0].literal
[i
] / oper
->children
[1].literal
[i
];
161 oper
->literal_size
= oper
->children
[0].literal_size
;
162 slang_operation_destruct(oper
);
163 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
170 if (oper
->num_children
== 1 && isFloat
[0]) {
171 switch (oper
->type
) {
172 case SLANG_OPER_MINUS
:
173 for (i
= 0; i
< 4; i
++) {
174 oper
->literal
[i
] = -oper
->children
[0].literal
[i
];
176 oper
->literal_size
= oper
->children
[0].literal_size
;
177 slang_operation_destruct(oper
);
178 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
180 case SLANG_OPER_PLUS
:
181 COPY_4V(oper
->literal
, oper
->children
[0].literal
);
182 oper
->literal_size
= oper
->children
[0].literal_size
;
183 slang_operation_destruct(oper
);
184 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
191 if (oper
->num_children
== 2 && isBool
[0] && isBool
[1]) {
192 /* simple boolean expression */
193 switch (oper
->type
) {
194 case SLANG_OPER_LOGICALAND
:
195 for (i
= 0; i
< 4; i
++) {
196 const GLint a
= oper
->children
[0].literal
[i
] ? 1 : 0;
197 const GLint b
= oper
->children
[1].literal
[i
] ? 1 : 0;
198 oper
->literal
[i
] = (GLfloat
) (a
&& b
);
200 oper
->literal_size
= oper
->children
[0].literal_size
;
201 slang_operation_destruct(oper
);
202 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
204 case SLANG_OPER_LOGICALOR
:
205 for (i
= 0; i
< 4; i
++) {
206 const GLint a
= oper
->children
[0].literal
[i
] ? 1 : 0;
207 const GLint b
= oper
->children
[1].literal
[i
] ? 1 : 0;
208 oper
->literal
[i
] = (GLfloat
) (a
|| b
);
210 oper
->literal_size
= oper
->children
[0].literal_size
;
211 slang_operation_destruct(oper
);
212 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
214 case SLANG_OPER_LOGICALXOR
:
215 for (i
= 0; i
< 4; i
++) {
216 const GLint a
= oper
->children
[0].literal
[i
] ? 1 : 0;
217 const GLint b
= oper
->children
[1].literal
[i
] ? 1 : 0;
218 oper
->literal
[i
] = (GLfloat
) (a
^ b
);
220 oper
->literal_size
= oper
->children
[0].literal_size
;
221 slang_operation_destruct(oper
);
222 oper
->type
= SLANG_OPER_LITERAL_BOOL
;
229 if (oper
->num_children
== 4
230 && isFloat
[0] && isFloat
[1] && isFloat
[2] && isFloat
[3]) {
231 /* vec4(flt, flt, flt, flt) constructor */
232 if (oper
->type
== SLANG_OPER_CALL
) {
233 if (strcmp((char *) oper
->a_id
, "vec4") == 0) {
234 oper
->literal
[0] = oper
->children
[0].literal
[0];
235 oper
->literal
[1] = oper
->children
[1].literal
[0];
236 oper
->literal
[2] = oper
->children
[2].literal
[0];
237 oper
->literal
[3] = oper
->children
[3].literal
[0];
238 oper
->literal_size
= 4;
239 slang_operation_destruct(oper
);
240 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
246 if (oper
->num_children
== 3 && isFloat
[0] && isFloat
[1] && isFloat
[2]) {
247 /* vec3(flt, flt, flt) constructor */
248 if (oper
->type
== SLANG_OPER_CALL
) {
249 if (strcmp((char *) oper
->a_id
, "vec3") == 0) {
250 oper
->literal
[0] = oper
->children
[0].literal
[0];
251 oper
->literal
[1] = oper
->children
[1].literal
[0];
252 oper
->literal
[2] = oper
->children
[2].literal
[0];
253 oper
->literal
[3] = oper
->literal
[2];
254 oper
->literal_size
= 3;
255 slang_operation_destruct(oper
);
256 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
262 if (oper
->num_children
== 2 && isFloat
[0] && isFloat
[1]) {
263 /* vec2(flt, flt) constructor */
264 if (oper
->type
== SLANG_OPER_CALL
) {
265 if (strcmp((char *) oper
->a_id
, "vec2") == 0) {
266 printf("SIMPLIFY vec2 constructor scope = %p\n",
267 (void*) oper
->locals
);
268 oper
->literal
[0] = oper
->children
[0].literal
[0];
269 oper
->literal
[1] = oper
->children
[1].literal
[0];
270 oper
->literal
[2] = oper
->literal
[1];
271 oper
->literal
[3] = oper
->literal
[1];
272 oper
->literal_size
= 2;
273 slang_operation_destruct(oper
); /* XXX oper->locals goes NULL! */
274 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
275 assert(oper
->num_children
== 0);
285 * Adapt the arguments for a function call to match the parameters of
286 * the given function.
288 * 1. converting/casting argument types to match parameters
289 * 2. breaking up vector/matrix types into individual components to
290 * satisfy constructors.
293 _slang_adapt_call(slang_operation
*callOper
, const slang_function
*fun
,
294 const slang_name_space
* space
,
295 slang_atom_pool
* atoms
, slang_info_log
*log
)
297 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
298 const int numParams
= fun
->param_count
- haveRetValue
;
302 if (dbg
) printf("Adapt %d args to %d parameters\n",
303 callOper
->num_children
, numParams
);
305 if (callOper
->num_children
!= numParams
) {
306 /* number of arguments doesn't match number of parameters */
308 if (fun
->kind
== SLANG_FUNC_CONSTRUCTOR
) {
309 /* For constructor calls, we can try to unroll vector/matrix args
310 * into individual floats/ints and try to match the function params.
312 for (i
= 0; i
< numParams
; i
++) {
313 slang_typeinfo argType
;
316 /* Get type of arg[i] */
317 if (!slang_typeinfo_construct(&argType
))
319 if (!_slang_typeof_operation_(&callOper
->children
[i
], space
,
320 &argType
, atoms
, log
)) {
321 slang_typeinfo_destruct(&argType
);
326 paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier);
327 assert(paramSz == 1);
329 argSz
= _slang_sizeof_type_specifier(&argType
.spec
);
331 slang_operation origArg
;
332 /* break up arg[i] into components */
334 printf("Break up arg %d from 1 to %d elements\n", i
, argSz
);
336 slang_operation_construct(&origArg
);
337 slang_operation_copy(&origArg
,
338 &callOper
->children
[i
]);
340 /* insert argSz-1 new children/args */
341 for (j
= 0; j
< argSz
- 1; j
++) {
342 (void) slang_operation_insert(&callOper
->num_children
,
343 &callOper
->children
, i
);
346 /* replace arg[i+j] with subscript/index oper */
347 for (j
= 0; j
< argSz
; j
++) {
348 callOper
->children
[i
+ j
].type
= SLANG_OPER_SUBSCRIPT
;
349 callOper
->children
[i
+ j
].num_children
= 2;
350 callOper
->children
[i
+ j
].children
= slang_operation_new(2);
351 slang_operation_copy(&callOper
->children
[i
+ j
].children
[0],
353 callOper
->children
[i
+ j
].children
[1].type
354 = SLANG_OPER_LITERAL_INT
;
355 callOper
->children
[i
+ j
].children
[1].literal
[0] = j
;
362 /* non-constructor function: number of args must match number
363 * of function params.
365 return GL_FALSE
; /* caller will record an error msg */
369 if (callOper
->num_children
< numParams
) {
370 /* still not enough args for all params */
373 else if (callOper
->num_children
> numParams
) {
374 /* now too many arguments */
375 /* XXX this isn't always an error, see spec */
380 * Second phase, argument casting.
382 * void foo(int i, bool b) {}
384 * Gets translated into:
385 * x = foo(int(3.15), bool(9))
387 for (i
= 0; i
< numParams
; i
++) {
388 slang_typeinfo argType
;
389 slang_variable
*paramVar
= fun
->parameters
->variables
[i
];
391 /* Get type of arg[i] */
392 if (!slang_typeinfo_construct(&argType
))
394 if (!_slang_typeof_operation_(&callOper
->children
[i
], space
,
395 &argType
, atoms
, log
)) {
396 slang_typeinfo_destruct(&argType
);
400 /* see if arg type matches parameter type */
401 if (!slang_type_specifier_equal(&argType
.spec
,
402 ¶mVar
->type
.specifier
)) {
403 /* need to adapt arg type to match param type */
404 const char *constructorName
=
405 slang_type_specifier_type_to_string(paramVar
->type
.specifier
.type
);
406 slang_operation
*child
= slang_operation_new(1);
408 slang_operation_copy(child
, &callOper
->children
[i
]);
409 child
->locals
->outer_scope
= callOper
->locals
;
411 callOper
->children
[i
].type
= SLANG_OPER_CALL
;
412 callOper
->children
[i
].a_id
= slang_atom_pool_atom(atoms
, constructorName
);
413 callOper
->children
[i
].num_children
= 1;
414 callOper
->children
[i
].children
= child
;
417 slang_typeinfo_destruct(&argType
);
421 printf("===== New call to %s with adapted arguments ===============\n",
422 (char*) fun
->header
.a_name
);
423 slang_print_tree(callOper
, 5);