_slang_evaluate_int() no longer used
[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_assembly_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 (n == 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 slang_operation_destruct(oper);
135 oper->type = slang_oper_literal_float;
136 return;
137 case slang_oper_subtract:
138 for (i = 0; i < 4; i++) {
139 oper->literal[i]
140 = oper->children[0].literal[i] - oper->children[1].literal[i];
141 }
142 slang_operation_destruct(oper);
143 oper->type = slang_oper_literal_float;
144 return;
145 case slang_oper_multiply:
146 for (i = 0; i < 4; i++) {
147 oper->literal[i]
148 = oper->children[0].literal[i] * oper->children[1].literal[i];
149 }
150 slang_operation_destruct(oper);
151 oper->type = slang_oper_literal_float;
152 return;
153 case slang_oper_divide:
154 for (i = 0; i < 4; i++) {
155 oper->literal[i]
156 = oper->children[0].literal[i] / oper->children[1].literal[i];
157 }
158 slang_operation_destruct(oper);
159 oper->type = slang_oper_literal_float;
160 return;
161 default:
162 ; /* nothing */
163 }
164 }
165
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];
171 }
172 slang_operation_destruct(oper);
173 oper->type = slang_oper_literal_float;
174 return;
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;
179 return;
180 default:
181 ; /* nothing */
182 }
183 }
184
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);
193 }
194 slang_operation_destruct(oper);
195 oper->type = slang_oper_literal_bool;
196 return;
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);
202 }
203 slang_operation_destruct(oper);
204 oper->type = slang_oper_literal_bool;
205 return;
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);
211 }
212 slang_operation_destruct(oper);
213 oper->type = slang_oper_literal_bool;
214 return;
215 default:
216 ; /* nothing */
217 }
218 }
219
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;
230 return;
231 }
232 }
233 }
234
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;
245 return;
246 }
247 }
248 }
249
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;
260 return;
261 }
262 }
263 }
264 }
265
266
267
268 /**
269 * Adapt the arguments for a function call to match the parameters of
270 * the given function.
271 * This is for:
272 * 1. converting/casting argument types to match parameters
273 * 2. breaking up vector/matrix types into individual components to
274 * satisfy constructors.
275 */
276 GLboolean
277 _slang_adapt_call(slang_operation *callOper, const slang_function *fun,
278 const slang_assembly_name_space * space,
279 slang_atom_pool * atoms)
280 {
281 const GLboolean haveRetValue = _slang_function_has_return_value(fun);
282 const int numParams = fun->param_count - haveRetValue;
283 int i;
284 int dbg = 0;
285
286 if (dbg) printf("Adapt %d args to %d parameters\n",
287 callOper->num_children, numParams);
288
289 if (callOper->num_children != numParams) {
290 /* number of arguments doesn't match number of parameters */
291
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.
295 */
296 for (i = 0; i < numParams; i++) {
297 slang_assembly_typeinfo argType;
298 GLint argSz, j;
299
300 /* Get type of arg[i] */
301 if (!slang_assembly_typeinfo_construct(&argType))
302 return GL_FALSE;
303 if (!_slang_typeof_operation_(&callOper->children[i], space,
304 &argType, atoms)) {
305 slang_assembly_typeinfo_destruct(&argType);
306 return GL_FALSE;
307 }
308
309 /*
310 paramSz = _slang_sizeof_type_specifier(&paramVar->type.specifier);
311 assert(paramSz == 1);
312 */
313 argSz = _slang_sizeof_type_specifier(&argType.spec);
314 if (argSz > 1) {
315 slang_operation origArg;
316 /* break up arg[i] into components */
317 if (dbg)
318 printf("Break up arg %d from 1 to %d elements\n", i, argSz);
319
320 slang_operation_construct(&origArg);
321 slang_operation_copy(&origArg,
322 &callOper->children[i]);
323
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);
328 }
329
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],
336 &origArg);
337 callOper->children[i + j].children[1].type
338 = slang_oper_literal_int;
339 callOper->children[i + j].children[1].literal[0] = j;
340 }
341
342 }
343 } /* for i */
344 }
345 else {
346 /* non-constructor function: number of args must match number
347 * of function params.
348 */
349 return GL_FALSE; /* caller will record an error msg */
350 }
351 }
352
353 if (callOper->num_children < numParams) {
354 /* still not enough args for all params */
355 return GL_FALSE;
356 }
357 else if (callOper->num_children > numParams) {
358 /* now too many arguments */
359 /* XXX this isn't always an error, see spec */
360 return GL_FALSE;
361 }
362
363 /*
364 * Second phase, argument casting.
365 * Example:
366 * void foo(int i, bool b) {}
367 * x = foo(3.15, 9);
368 * Gets translated into:
369 * x = foo(int(3.15), bool(9))
370 */
371 for (i = 0; i < numParams; i++) {
372 slang_assembly_typeinfo argType;
373 slang_variable *paramVar = fun->parameters->variables[i];
374
375 /* Get type of arg[i] */
376 if (!slang_assembly_typeinfo_construct(&argType))
377 return GL_FALSE;
378 if (!_slang_typeof_operation_(&callOper->children[i], space,
379 &argType, atoms)) {
380 slang_assembly_typeinfo_destruct(&argType);
381 return GL_FALSE;
382 }
383
384 /* see if arg type matches parameter type */
385 if (!slang_type_specifier_equal(&argType.spec,
386 &paramVar->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);
391
392 slang_operation_copy(child, &callOper->children[i]);
393 child->locals->outer_scope = callOper->locals;
394
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;
399 }
400
401 slang_assembly_typeinfo_destruct(&argType);
402 }
403
404 if (dbg) {
405 printf("===== New call to %s with adapted arguments ===============\n",
406 (char*) fun->header.a_name);
407 slang_print_tree(callOper, 5);
408 }
409
410 return GL_TRUE;
411 }