silence warning, new assertion
[mesa.git] / src / mesa / shader / slang / slang_simplify.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 /**
26 * \file slang_assemble_typeinfo.c
27 * slang type info
28 * \author Michal Krol
29 */
30
31 #include "imports.h"
32 #include "macros.h"
33 #include "get.h"
34 #include "slang_compile.h"
35 #include "slang_codegen.h"
36 #include "slang_simplify.h"
37 #include "slang_print.h"
38
39
40
41
42 /**
43 * Lookup the value of named constant, such as gl_MaxLights.
44 * \return value of constant, or -1 if unknown
45 */
46 GLint
47 _slang_lookup_constant(const char *name)
48 {
49 struct constant_info {
50 const char *Name;
51 const GLenum Token;
52 };
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 },
66 { NULL, 0 }
67 };
68 GLuint i;
69
70 for (i = 0; info[i].Name; i++) {
71 if (strcmp(info[i].Name, name) == 0) {
72 /* found */
73 GLint value = -1.0;
74 _mesa_GetIntegerv(info[i].Token, &value);
75 ASSERT(value >= 0); /* sanity check that glGetFloatv worked */
76 return value;
77 }
78 }
79 return -1;
80 }
81
82
83
84 /**
85 * Recursively traverse an AST tree, applying simplifications wherever
86 * possible.
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];
90 */
91 void
92 _slang_simplify(slang_operation *oper,
93 const slang_name_space * space,
94 slang_atom_pool * atoms)
95 {
96 GLboolean isFloat[4];
97 GLboolean isBool[4];
98 GLuint i, n;
99
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);
103 if (value >= 0) {
104 oper->literal[0] =
105 oper->literal[1] =
106 oper->literal[2] =
107 oper->literal[3] = value;
108 oper->type = SLANG_OPER_LITERAL_INT;
109 return;
110 }
111 }
112
113 /* first, simplify children */
114 for (i = 0; i < oper->num_children; i++) {
115 _slang_simplify(&oper->children[i], space, atoms);
116 }
117
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);
124 }
125
126 if (oper->num_children == 2 && isFloat[0] && isFloat[1]) {
127 /* probably simple arithmetic */
128 switch (oper->type) {
129 case SLANG_OPER_ADD:
130 for (i = 0; i < 4; i++) {
131 oper->literal[i]
132 = oper->children[0].literal[i] + oper->children[1].literal[i];
133 }
134 oper->literal_size = oper->children[0].literal_size;
135 slang_operation_destruct(oper);
136 oper->type = SLANG_OPER_LITERAL_FLOAT;
137 return;
138 case SLANG_OPER_SUBTRACT:
139 for (i = 0; i < 4; i++) {
140 oper->literal[i]
141 = oper->children[0].literal[i] - oper->children[1].literal[i];
142 }
143 oper->literal_size = oper->children[0].literal_size;
144 slang_operation_destruct(oper);
145 oper->type = SLANG_OPER_LITERAL_FLOAT;
146 return;
147 case SLANG_OPER_MULTIPLY:
148 for (i = 0; i < 4; i++) {
149 oper->literal[i]
150 = oper->children[0].literal[i] * oper->children[1].literal[i];
151 }
152 oper->literal_size = oper->children[0].literal_size;
153 slang_operation_destruct(oper);
154 oper->type = SLANG_OPER_LITERAL_FLOAT;
155 return;
156 case SLANG_OPER_DIVIDE:
157 for (i = 0; i < 4; i++) {
158 oper->literal[i]
159 = oper->children[0].literal[i] / oper->children[1].literal[i];
160 }
161 oper->literal_size = oper->children[0].literal_size;
162 slang_operation_destruct(oper);
163 oper->type = SLANG_OPER_LITERAL_FLOAT;
164 return;
165 default:
166 ; /* nothing */
167 }
168 }
169
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];
175 }
176 oper->literal_size = oper->children[0].literal_size;
177 slang_operation_destruct(oper);
178 oper->type = SLANG_OPER_LITERAL_FLOAT;
179 return;
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;
185 return;
186 default:
187 ; /* nothing */
188 }
189 }
190
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);
199 }
200 oper->literal_size = oper->children[0].literal_size;
201 slang_operation_destruct(oper);
202 oper->type = SLANG_OPER_LITERAL_BOOL;
203 return;
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);
209 }
210 oper->literal_size = oper->children[0].literal_size;
211 slang_operation_destruct(oper);
212 oper->type = SLANG_OPER_LITERAL_BOOL;
213 return;
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);
219 }
220 oper->literal_size = oper->children[0].literal_size;
221 slang_operation_destruct(oper);
222 oper->type = SLANG_OPER_LITERAL_BOOL;
223 return;
224 default:
225 ; /* nothing */
226 }
227 }
228
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;
241 return;
242 }
243 }
244 }
245
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;
257 return;
258 }
259 }
260 }
261
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);
274 return;
275 }
276 }
277 }
278
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') {
284 oper->literal[0] =
285 oper->literal[1] =
286 oper->literal[2] =
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);
294 return;
295 }
296 }
297 }
298 }
299
300
301
302 /**
303 * Adapt the arguments for a function call to match the parameters of
304 * the given function.
305 * This is for:
306 * 1. converting/casting argument types to match parameters
307 * 2. breaking up vector/matrix types into individual components to
308 * satisfy constructors.
309 */
310 GLboolean
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)
314 {
315 const GLboolean haveRetValue = _slang_function_has_return_value(fun);
316 const int numParams = fun->param_count - haveRetValue;
317 int i;
318 int dbg = 0;
319
320 if (dbg) printf("Adapt %d args to %d parameters\n",
321 callOper->num_children, numParams);
322
323 /* Only try adapting for constructors */
324 if (fun->kind != SLANG_FUNC_CONSTRUCTOR)
325 return GL_FALSE;
326
327 if (callOper->num_children != numParams) {
328 /* number of arguments doesn't match number of parameters */
329
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.
333 */
334 for (i = 0; i < numParams; i++) {
335 slang_typeinfo argType;
336 GLint argSz, j;
337
338 /* Get type of arg[i] */
339 if (!slang_typeinfo_construct(&argType))
340 return GL_FALSE;
341 if (!_slang_typeof_operation_(&callOper->children[i], space,
342 &argType, atoms, log)) {
343 slang_typeinfo_destruct(&argType);
344 return GL_FALSE;
345 }
346
347 /*
348 paramSz = _slang_sizeof_type_specifier(&paramVar->type.specifier);
349 assert(paramSz == 1);
350 */
351 argSz = _slang_sizeof_type_specifier(&argType.spec);
352 if (argSz > 1) {
353 slang_operation origArg;
354 /* break up arg[i] into components */
355 if (dbg)
356 printf("Break up arg %d from 1 to %d elements\n", i, argSz);
357
358 slang_operation_construct(&origArg);
359 slang_operation_copy(&origArg,
360 &callOper->children[i]);
361
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);
366 }
367
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],
374 &origArg);
375 callOper->children[i + j].children[1].type
376 = SLANG_OPER_LITERAL_INT;
377 callOper->children[i + j].children[1].literal[0] = j;
378 }
379
380 }
381 } /* for i */
382 }
383 else {
384 /* non-constructor function: number of args must match number
385 * of function params.
386 */
387 return GL_FALSE; /* caller will record an error msg */
388 }
389 }
390
391 if (callOper->num_children < numParams) {
392 /* still not enough args for all params */
393 return GL_FALSE;
394 }
395 else if (callOper->num_children > numParams) {
396 /* now too many arguments */
397 /* XXX this isn't always an error, see spec */
398 return GL_FALSE;
399 }
400
401 /*
402 * Second phase, argument casting.
403 * Example:
404 * void foo(int i, bool b) {}
405 * x = foo(3.15, 9);
406 * Gets translated into:
407 * x = foo(int(3.15), bool(9))
408 */
409 for (i = 0; i < numParams; i++) {
410 slang_typeinfo argType;
411 slang_variable *paramVar = fun->parameters->variables[i];
412
413 /* Get type of arg[i] */
414 if (!slang_typeinfo_construct(&argType))
415 return GL_FALSE;
416 if (!_slang_typeof_operation_(&callOper->children[i], space,
417 &argType, atoms, log)) {
418 slang_typeinfo_destruct(&argType);
419 return GL_FALSE;
420 }
421
422 /* see if arg type matches parameter type */
423 if (!slang_type_specifier_equal(&argType.spec,
424 &paramVar->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);
429
430 slang_operation_copy(child, &callOper->children[i]);
431 child->locals->outer_scope = callOper->children[i].locals;
432
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;
437 }
438
439 slang_typeinfo_destruct(&argType);
440 }
441
442 if (dbg) {
443 printf("===== New call to %s with adapted arguments ===============\n",
444 (char*) fun->header.a_name);
445 slang_print_tree(callOper, 5);
446 }
447
448 return GL_TRUE;
449 }