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_assembly_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 (n
== 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 slang_operation_destruct(oper
);
135 oper
->type
= slang_oper_literal_float
;
137 case slang_oper_subtract
:
138 for (i
= 0; i
< 4; i
++) {
140 = oper
->children
[0].literal
[i
] - oper
->children
[1].literal
[i
];
142 slang_operation_destruct(oper
);
143 oper
->type
= slang_oper_literal_float
;
145 case slang_oper_multiply
:
146 for (i
= 0; i
< 4; i
++) {
148 = oper
->children
[0].literal
[i
] * oper
->children
[1].literal
[i
];
150 slang_operation_destruct(oper
);
151 oper
->type
= slang_oper_literal_float
;
153 case slang_oper_divide
:
154 for (i
= 0; i
< 4; i
++) {
156 = oper
->children
[0].literal
[i
] / oper
->children
[1].literal
[i
];
158 slang_operation_destruct(oper
);
159 oper
->type
= slang_oper_literal_float
;
166 if (n
== 1 && isFloat
[0]) {
167 switch (oper
->type
) {
168 case slang_oper_minus
:
169 for (i
= 0; i
< 4; i
++) {
170 oper
->literal
[i
] = -oper
->children
[0].literal
[i
];
172 slang_operation_destruct(oper
);
173 oper
->type
= slang_oper_literal_float
;
175 case slang_oper_plus
:
176 COPY_4V(oper
->literal
, oper
->children
[0].literal
);
177 slang_operation_destruct(oper
);
178 oper
->type
= slang_oper_literal_float
;
185 if (n
== 2 && isBool
[0] && isBool
[1]) {
186 /* simple boolean expression */
187 switch (oper
->type
) {
188 case slang_oper_logicaland
:
189 for (i
= 0; i
< 4; i
++) {
190 const GLint a
= oper
->children
[0].literal
[i
] ? 1 : 0;
191 const GLint b
= oper
->children
[1].literal
[i
] ? 1 : 0;
192 oper
->literal
[i
] = (GLfloat
) (a
&& b
);
194 slang_operation_destruct(oper
);
195 oper
->type
= slang_oper_literal_bool
;
197 case slang_oper_logicalor
:
198 for (i
= 0; i
< 4; i
++) {
199 const GLint a
= oper
->children
[0].literal
[i
] ? 1 : 0;
200 const GLint b
= oper
->children
[1].literal
[i
] ? 1 : 0;
201 oper
->literal
[i
] = (GLfloat
) (a
|| b
);
203 slang_operation_destruct(oper
);
204 oper
->type
= slang_oper_literal_bool
;
206 case slang_oper_logicalxor
:
207 for (i
= 0; i
< 4; i
++) {
208 const GLint a
= oper
->children
[0].literal
[i
] ? 1 : 0;
209 const GLint b
= oper
->children
[1].literal
[i
] ? 1 : 0;
210 oper
->literal
[i
] = (GLfloat
) (a
^ b
);
212 slang_operation_destruct(oper
);
213 oper
->type
= slang_oper_literal_bool
;
220 if (n
== 4 && isFloat
[0] && isFloat
[1] && isFloat
[2] && isFloat
[3]) {
221 /* vec4(flt, flt, flt, flt) constructor */
222 if (oper
->type
== slang_oper_call
) {
223 if (strcmp((char *) oper
->a_id
, "vec4") == 0) {
224 oper
->literal
[0] = oper
->children
[0].literal
[0];
225 oper
->literal
[1] = oper
->children
[1].literal
[0];
226 oper
->literal
[2] = oper
->children
[2].literal
[0];
227 oper
->literal
[3] = oper
->children
[3].literal
[0];
228 slang_operation_destruct(oper
);
229 oper
->type
= slang_oper_literal_float
;
235 if (n
== 3 && isFloat
[0] && isFloat
[1] && isFloat
[2]) {
236 /* vec3(flt, flt, flt) constructor */
237 if (oper
->type
== slang_oper_call
) {
238 if (strcmp((char *) oper
->a_id
, "vec3") == 0) {
239 oper
->literal
[0] = oper
->children
[0].literal
[0];
240 oper
->literal
[1] = oper
->children
[1].literal
[0];
241 oper
->literal
[2] = oper
->children
[2].literal
[0];
242 oper
->literal
[3] = oper
->literal
[2];
243 slang_operation_destruct(oper
);
244 oper
->type
= slang_oper_literal_float
;
250 if (n
== 2 && isFloat
[0] && isFloat
[1]) {
251 /* vec4(flt, flt) constructor */
252 if (oper
->type
== slang_oper_call
) {
253 if (strcmp((char *) oper
->a_id
, "vec2") == 0) {
254 oper
->literal
[0] = oper
->children
[0].literal
[0];
255 oper
->literal
[1] = oper
->children
[1].literal
[0];
256 oper
->literal
[2] = oper
->literal
[1];
257 oper
->literal
[3] = oper
->literal
[1];
258 slang_operation_destruct(oper
); /* XXX oper->locals goes NULL! */
259 oper
->type
= slang_oper_literal_float
;
269 * Adapt the arguments for a function call to match the parameters of
270 * the given function.
272 * 1. converting/casting argument types to match parameters
273 * 2. breaking up vector/matrix types into individual components to
274 * satisfy constructors.
277 _slang_adapt_call(slang_operation
*callOper
, const slang_function
*fun
,
278 const slang_assembly_name_space
* space
,
279 slang_atom_pool
* atoms
)
281 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
282 const int numParams
= fun
->param_count
- haveRetValue
;
286 if (dbg
) printf("Adapt %d args to %d parameters\n",
287 callOper
->num_children
, numParams
);
289 if (callOper
->num_children
!= numParams
) {
290 /* number of arguments doesn't match number of parameters */
292 if (fun
->kind
== slang_func_constructor
) {
293 /* For constructor calls, we can try to unroll vector/matrix args
294 * into individual floats/ints and try to match the function params.
296 for (i
= 0; i
< numParams
; i
++) {
297 slang_assembly_typeinfo argType
;
300 /* Get type of arg[i] */
301 if (!slang_assembly_typeinfo_construct(&argType
))
303 if (!_slang_typeof_operation_(&callOper
->children
[i
], space
,
305 slang_assembly_typeinfo_destruct(&argType
);
310 paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier);
311 assert(paramSz == 1);
313 argSz
= _slang_sizeof_type_specifier(&argType
.spec
);
315 slang_operation origArg
;
316 /* break up arg[i] into components */
318 printf("Break up arg %d from 1 to %d elements\n", i
, argSz
);
320 slang_operation_construct(&origArg
);
321 slang_operation_copy(&origArg
,
322 &callOper
->children
[i
]);
324 /* insert argSz-1 new children/args */
325 for (j
= 0; j
< argSz
- 1; j
++) {
326 (void) slang_operation_insert(&callOper
->num_children
,
327 &callOper
->children
, i
);
330 /* replace arg[i+j] with subscript/index oper */
331 for (j
= 0; j
< argSz
; j
++) {
332 callOper
->children
[i
+ j
].type
= slang_oper_subscript
;
333 callOper
->children
[i
+ j
].num_children
= 2;
334 callOper
->children
[i
+ j
].children
= slang_operation_new(2);
335 slang_operation_copy(&callOper
->children
[i
+ j
].children
[0],
337 callOper
->children
[i
+ j
].children
[1].type
338 = slang_oper_literal_int
;
339 callOper
->children
[i
+ j
].children
[1].literal
[0] = j
;
346 /* non-constructor function: number of args must match number
347 * of function params.
349 return GL_FALSE
; /* caller will record an error msg */
353 if (callOper
->num_children
< numParams
) {
354 /* still not enough args for all params */
357 else if (callOper
->num_children
> numParams
) {
358 /* now too many arguments */
359 /* XXX this isn't always an error, see spec */
364 * Second phase, argument casting.
366 * void foo(int i, bool b) {}
368 * Gets translated into:
369 * x = foo(int(3.15), bool(9))
371 for (i
= 0; i
< numParams
; i
++) {
372 slang_assembly_typeinfo argType
;
373 slang_variable
*paramVar
= fun
->parameters
->variables
[i
];
375 /* Get type of arg[i] */
376 if (!slang_assembly_typeinfo_construct(&argType
))
378 if (!_slang_typeof_operation_(&callOper
->children
[i
], space
,
380 slang_assembly_typeinfo_destruct(&argType
);
384 /* see if arg type matches parameter type */
385 if (!slang_type_specifier_equal(&argType
.spec
,
386 ¶mVar
->type
.specifier
)) {
387 /* need to adapt arg type to match param type */
388 const char *constructorName
=
389 slang_type_specifier_type_to_string(paramVar
->type
.specifier
.type
);
390 slang_operation
*child
= slang_operation_new(1);
392 slang_operation_copy(child
, &callOper
->children
[i
]);
393 child
->locals
->outer_scope
= callOper
->locals
;
395 callOper
->children
[i
].type
= slang_oper_call
;
396 callOper
->children
[i
].a_id
= slang_atom_pool_atom(atoms
, constructorName
);
397 callOper
->children
[i
].num_children
= 1;
398 callOper
->children
[i
].children
= child
;
401 slang_assembly_typeinfo_destruct(&argType
);
405 printf("===== New call to %s with adapted arguments ===============\n",
406 (char*) fun
->header
.a_name
);
407 slang_print_tree(callOper
, 5);