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 oper
->literal
[0] = oper
->children
[0].literal
[0];
267 oper
->literal
[1] = oper
->children
[1].literal
[0];
268 oper
->literal
[2] = oper
->literal
[1];
269 oper
->literal
[3] = oper
->literal
[1];
270 oper
->literal_size
= 2;
271 slang_operation_destruct(oper
); /* XXX oper->locals goes NULL! */
272 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
273 assert(oper
->num_children
== 0);
279 if (oper
->num_children
== 1 && isFloat
[0]) {
280 /* vec2/3/4(flt, flt) constructor */
281 if (oper
->type
== SLANG_OPER_CALL
) {
282 const char *func
= (const char *) oper
->a_id
;
283 if (strncmp(func
, "vec", 3) == 0 && func
[3] >= '2' && func
[3] <= '4') {
287 oper
->literal
[3] = oper
->children
[0].literal
[0];
288 oper
->literal_size
= func
[3] - '0';
289 assert(oper
->literal_size
>= 2);
290 assert(oper
->literal_size
<= 4);
291 slang_operation_destruct(oper
); /* XXX oper->locals goes NULL! */
292 oper
->type
= SLANG_OPER_LITERAL_FLOAT
;
293 assert(oper
->num_children
== 0);
303 * Adapt the arguments for a function call to match the parameters of
304 * the given function.
306 * 1. converting/casting argument types to match parameters
307 * 2. breaking up vector/matrix types into individual components to
308 * satisfy constructors.
311 _slang_adapt_call(slang_operation
*callOper
, const slang_function
*fun
,
312 const slang_name_space
* space
,
313 slang_atom_pool
* atoms
, slang_info_log
*log
)
315 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
316 const int numParams
= fun
->param_count
- haveRetValue
;
320 if (dbg
) printf("Adapt %d args to %d parameters\n",
321 callOper
->num_children
, numParams
);
323 /* Only try adapting for constructors */
324 if (fun
->kind
!= SLANG_FUNC_CONSTRUCTOR
)
327 if (callOper
->num_children
!= numParams
) {
328 /* number of arguments doesn't match number of parameters */
330 if (fun
->kind
== SLANG_FUNC_CONSTRUCTOR
) {
331 /* For constructor calls, we can try to unroll vector/matrix args
332 * into individual floats/ints and try to match the function params.
334 for (i
= 0; i
< numParams
; i
++) {
335 slang_typeinfo argType
;
338 /* Get type of arg[i] */
339 if (!slang_typeinfo_construct(&argType
))
341 if (!_slang_typeof_operation_(&callOper
->children
[i
], space
,
342 &argType
, atoms
, log
)) {
343 slang_typeinfo_destruct(&argType
);
348 paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier);
349 assert(paramSz == 1);
351 argSz
= _slang_sizeof_type_specifier(&argType
.spec
);
353 slang_operation origArg
;
354 /* break up arg[i] into components */
356 printf("Break up arg %d from 1 to %d elements\n", i
, argSz
);
358 slang_operation_construct(&origArg
);
359 slang_operation_copy(&origArg
,
360 &callOper
->children
[i
]);
362 /* insert argSz-1 new children/args */
363 for (j
= 0; j
< argSz
- 1; j
++) {
364 (void) slang_operation_insert(&callOper
->num_children
,
365 &callOper
->children
, i
);
368 /* replace arg[i+j] with subscript/index oper */
369 for (j
= 0; j
< argSz
; j
++) {
370 callOper
->children
[i
+ j
].type
= SLANG_OPER_SUBSCRIPT
;
371 callOper
->children
[i
+ j
].num_children
= 2;
372 callOper
->children
[i
+ j
].children
= slang_operation_new(2);
373 slang_operation_copy(&callOper
->children
[i
+ j
].children
[0],
375 callOper
->children
[i
+ j
].children
[1].type
376 = SLANG_OPER_LITERAL_INT
;
377 callOper
->children
[i
+ j
].children
[1].literal
[0] = j
;
384 /* non-constructor function: number of args must match number
385 * of function params.
387 return GL_FALSE
; /* caller will record an error msg */
391 if (callOper
->num_children
< numParams
) {
392 /* still not enough args for all params */
395 else if (callOper
->num_children
> numParams
) {
396 /* now too many arguments */
397 /* XXX this isn't always an error, see spec */
402 * Second phase, argument casting.
404 * void foo(int i, bool b) {}
406 * Gets translated into:
407 * x = foo(int(3.15), bool(9))
409 for (i
= 0; i
< numParams
; i
++) {
410 slang_typeinfo argType
;
411 slang_variable
*paramVar
= fun
->parameters
->variables
[i
];
413 /* Get type of arg[i] */
414 if (!slang_typeinfo_construct(&argType
))
416 if (!_slang_typeof_operation_(&callOper
->children
[i
], space
,
417 &argType
, atoms
, log
)) {
418 slang_typeinfo_destruct(&argType
);
422 /* see if arg type matches parameter type */
423 if (!slang_type_specifier_equal(&argType
.spec
,
424 ¶mVar
->type
.specifier
)) {
425 /* need to adapt arg type to match param type */
426 const char *constructorName
=
427 slang_type_specifier_type_to_string(paramVar
->type
.specifier
.type
);
428 slang_operation
*child
= slang_operation_new(1);
430 slang_operation_copy(child
, &callOper
->children
[i
]);
431 child
->locals
->outer_scope
= callOper
->children
[i
].locals
;
433 callOper
->children
[i
].type
= SLANG_OPER_CALL
;
434 callOper
->children
[i
].a_id
= slang_atom_pool_atom(atoms
, constructorName
);
435 callOper
->children
[i
].num_children
= 1;
436 callOper
->children
[i
].children
= child
;
439 slang_typeinfo_destruct(&argType
);
443 printf("===== New call to %s with adapted arguments ===============\n",
444 (char*) fun
->header
.a_name
);
445 slang_print_tree(callOper
, 5);