2
* Mesa 3-D graphics library
5
* Copyright (C) 2005-2008 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
* Functions for constant folding, built-in constant lookup, and function
31
#include "main/imports.h"
32
#include "main/macros.h"
34
#include "slang_compile.h"
35
#include "slang_codegen.h"
36
#include "slang_simplify.h"
37
#include "slang_print.h"
40
#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS
41
#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
43
#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS
44
#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
46
#ifndef GL_MAX_VARYING_VECTORS
47
#define GL_MAX_VARYING_VECTORS 0x8DFC
52
* Lookup the value of named constant, such as gl_MaxLights.
53
* \return value of constant, or -1 if unknown
56
_slang_lookup_constant(const char *name)
58
struct constant_info {
62
static const struct constant_info info[] = {
63
{ "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES },
64
{ "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS },
65
{ "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS },
66
{ "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS },
67
{ "gl_MaxLights", GL_MAX_LIGHTS },
68
{ "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS },
69
{ "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS },
70
{ "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS },
71
{ "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS },
72
{ "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS },
73
{ "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS },
74
{ "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS },
76
{ "gl_MaxVertexUniformVectors", GL_MAX_VERTEX_UNIFORM_VECTORS },
77
{ "gl_MaxVaryingVectors", GL_MAX_VARYING_VECTORS },
78
{ "gl_MaxFragmentUniformVectors", GL_MAX_FRAGMENT_UNIFORM_VECTORS },
84
for (i = 0; info[i].Name; i++) {
85
if (strcmp(info[i].Name, name) == 0) {
89
_mesa_GetIntegerv(info[i].Token, values);
90
ASSERT(values[0] >= 0); /* sanity check that glGetFloatv worked */
98
static slang_operation_type
99
literal_type(slang_operation_type t1, slang_operation_type t2)
101
if (t1 == SLANG_OPER_LITERAL_FLOAT || t2 == SLANG_OPER_LITERAL_FLOAT)
102
return SLANG_OPER_LITERAL_FLOAT;
104
return SLANG_OPER_LITERAL_INT;
109
* Recursively traverse an AST tree, applying simplifications wherever
111
* At the least, we do constant folding. We need to do that much so that
112
* compile-time expressions can be evaluated for things like array
113
* declarations. I.e.: float foo[3 + 5];
116
_slang_simplify(slang_operation *oper,
117
const slang_name_space * space,
118
slang_atom_pool * atoms)
120
GLboolean isFloat[4];
124
if (oper->type == SLANG_OPER_IDENTIFIER) {
125
/* see if it's a named constant */
126
GLint value = _slang_lookup_constant((char *) oper->a_id);
127
/*printf("value[%s] = %d\n", (char*) oper->a_id, value);*/
132
oper->literal[3] = (GLfloat) value;
133
oper->type = SLANG_OPER_LITERAL_INT;
136
/* look for user-defined constant */
139
var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE);
141
if (var->type.qualifier == SLANG_QUAL_CONST &&
143
(var->initializer->type == SLANG_OPER_LITERAL_INT ||
144
var->initializer->type == SLANG_OPER_LITERAL_FLOAT)) {
145
oper->literal[0] = var->initializer->literal[0];
146
oper->literal[1] = var->initializer->literal[1];
147
oper->literal[2] = var->initializer->literal[2];
148
oper->literal[3] = var->initializer->literal[3];
149
oper->literal_size = var->initializer->literal_size;
150
oper->type = var->initializer->type;
152
printf("value[%s] = %f\n",
153
(char*) oper->a_id, oper->literal[0]);
161
/* first, simplify children */
162
for (i = 0; i < oper->num_children; i++) {
163
_slang_simplify(&oper->children[i], space, atoms);
166
/* examine children */
167
n = MIN2(oper->num_children, 4);
168
for (i = 0; i < n; i++) {
169
isFloat[i] = (oper->children[i].type == SLANG_OPER_LITERAL_FLOAT ||
170
oper->children[i].type == SLANG_OPER_LITERAL_INT);
171
isBool[i] = (oper->children[i].type == SLANG_OPER_LITERAL_BOOL);
174
if (oper->num_children == 2 && isFloat[0] && isFloat[1]) {
175
/* probably simple arithmetic */
176
switch (oper->type) {
178
for (i = 0; i < 4; i++) {
180
= oper->children[0].literal[i] + oper->children[1].literal[i];
182
oper->literal_size = oper->children[0].literal_size;
183
oper->type = literal_type(oper->children[0].type,
184
oper->children[1].type);
185
slang_operation_destruct(oper); /* frees unused children */
187
case SLANG_OPER_SUBTRACT:
188
for (i = 0; i < 4; i++) {
190
= oper->children[0].literal[i] - oper->children[1].literal[i];
192
oper->literal_size = oper->children[0].literal_size;
193
oper->type = literal_type(oper->children[0].type,
194
oper->children[1].type);
195
slang_operation_destruct(oper);
197
case SLANG_OPER_MULTIPLY:
198
for (i = 0; i < 4; i++) {
200
= oper->children[0].literal[i] * oper->children[1].literal[i];
202
oper->literal_size = oper->children[0].literal_size;
203
oper->type = literal_type(oper->children[0].type,
204
oper->children[1].type);
205
slang_operation_destruct(oper);
207
case SLANG_OPER_DIVIDE:
208
for (i = 0; i < 4; i++) {
210
= oper->children[0].literal[i] / oper->children[1].literal[i];
212
oper->literal_size = oper->children[0].literal_size;
213
oper->type = literal_type(oper->children[0].type,
214
oper->children[1].type);
215
slang_operation_destruct(oper);
222
if (oper->num_children == 1 && isFloat[0]) {
223
switch (oper->type) {
224
case SLANG_OPER_MINUS:
225
for (i = 0; i < 4; i++) {
226
oper->literal[i] = -oper->children[0].literal[i];
228
oper->literal_size = oper->children[0].literal_size;
229
slang_operation_destruct(oper);
230
oper->type = SLANG_OPER_LITERAL_FLOAT;
232
case SLANG_OPER_PLUS:
233
COPY_4V(oper->literal, oper->children[0].literal);
234
oper->literal_size = oper->children[0].literal_size;
235
slang_operation_destruct(oper);
236
oper->type = SLANG_OPER_LITERAL_FLOAT;
243
if (oper->num_children == 2 && isBool[0] && isBool[1]) {
244
/* simple boolean expression */
245
switch (oper->type) {
246
case SLANG_OPER_LOGICALAND:
247
for (i = 0; i < 4; i++) {
248
const GLint a = oper->children[0].literal[i] ? 1 : 0;
249
const GLint b = oper->children[1].literal[i] ? 1 : 0;
250
oper->literal[i] = (GLfloat) (a && b);
252
oper->literal_size = oper->children[0].literal_size;
253
slang_operation_destruct(oper);
254
oper->type = SLANG_OPER_LITERAL_BOOL;
256
case SLANG_OPER_LOGICALOR:
257
for (i = 0; i < 4; i++) {
258
const GLint a = oper->children[0].literal[i] ? 1 : 0;
259
const GLint b = oper->children[1].literal[i] ? 1 : 0;
260
oper->literal[i] = (GLfloat) (a || b);
262
oper->literal_size = oper->children[0].literal_size;
263
slang_operation_destruct(oper);
264
oper->type = SLANG_OPER_LITERAL_BOOL;
266
case SLANG_OPER_LOGICALXOR:
267
for (i = 0; i < 4; i++) {
268
const GLint a = oper->children[0].literal[i] ? 1 : 0;
269
const GLint b = oper->children[1].literal[i] ? 1 : 0;
270
oper->literal[i] = (GLfloat) (a ^ b);
272
oper->literal_size = oper->children[0].literal_size;
273
slang_operation_destruct(oper);
274
oper->type = SLANG_OPER_LITERAL_BOOL;
281
if (oper->num_children == 4
282
&& isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) {
283
/* vec4(flt, flt, flt, flt) constructor */
284
if (oper->type == SLANG_OPER_CALL) {
285
if (strcmp((char *) oper->a_id, "vec4") == 0) {
286
oper->literal[0] = oper->children[0].literal[0];
287
oper->literal[1] = oper->children[1].literal[0];
288
oper->literal[2] = oper->children[2].literal[0];
289
oper->literal[3] = oper->children[3].literal[0];
290
oper->literal_size = 4;
291
slang_operation_destruct(oper);
292
oper->type = SLANG_OPER_LITERAL_FLOAT;
298
if (oper->num_children == 3 && isFloat[0] && isFloat[1] && isFloat[2]) {
299
/* vec3(flt, flt, flt) constructor */
300
if (oper->type == SLANG_OPER_CALL) {
301
if (strcmp((char *) oper->a_id, "vec3") == 0) {
302
oper->literal[0] = oper->children[0].literal[0];
303
oper->literal[1] = oper->children[1].literal[0];
304
oper->literal[2] = oper->children[2].literal[0];
305
oper->literal[3] = oper->literal[2];
306
oper->literal_size = 3;
307
slang_operation_destruct(oper);
308
oper->type = SLANG_OPER_LITERAL_FLOAT;
314
if (oper->num_children == 2 && isFloat[0] && isFloat[1]) {
315
/* vec2(flt, flt) constructor */
316
if (oper->type == SLANG_OPER_CALL) {
317
if (strcmp((char *) oper->a_id, "vec2") == 0) {
318
oper->literal[0] = oper->children[0].literal[0];
319
oper->literal[1] = oper->children[1].literal[0];
320
oper->literal[2] = oper->literal[1];
321
oper->literal[3] = oper->literal[1];
322
oper->literal_size = 2;
323
slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */
324
oper->type = SLANG_OPER_LITERAL_FLOAT;
325
assert(oper->num_children == 0);
331
if (oper->num_children == 1 && isFloat[0]) {
332
/* vec2/3/4(flt, flt) constructor */
333
if (oper->type == SLANG_OPER_CALL) {
334
const char *func = (const char *) oper->a_id;
335
if (strncmp(func, "vec", 3) == 0 && func[3] >= '2' && func[3] <= '4') {
339
oper->literal[3] = oper->children[0].literal[0];
340
oper->literal_size = func[3] - '0';
341
assert(oper->literal_size >= 2);
342
assert(oper->literal_size <= 4);
343
slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */
344
oper->type = SLANG_OPER_LITERAL_FLOAT;
345
assert(oper->num_children == 0);
355
* Insert casts to try to adapt actual parameters to formal parameters for a
356
* function call when an exact match for the parameter types is not found.
358
* void foo(int i, bool b) {}
360
* Gets translated into:
361
* x = foo(int(3.15), bool(9))
364
_slang_cast_func_params(slang_operation *callOper, const slang_function *fun,
365
const slang_name_space * space,
366
slang_atom_pool * atoms, slang_info_log *log)
368
const GLboolean haveRetValue = _slang_function_has_return_value(fun);
369
const int numParams = fun->param_count - haveRetValue;
374
printf("Adapt call of %d args to func %s (%d params)\n",
375
callOper->num_children, (char*) fun->header.a_name, numParams);
377
for (i = 0; i < numParams; i++) {
378
slang_typeinfo argType;
379
slang_variable *paramVar = fun->parameters->variables[i];
381
/* Get type of arg[i] */
382
if (!slang_typeinfo_construct(&argType))
384
if (!_slang_typeof_operation(&callOper->children[i], space,
385
&argType, atoms, log)) {
386
slang_typeinfo_destruct(&argType);
390
/* see if arg type matches parameter type */
391
if (!slang_type_specifier_equal(&argType.spec,
392
¶mVar->type.specifier)) {
393
/* need to adapt arg type to match param type */
394
const char *constructorName =
395
slang_type_specifier_type_to_string(paramVar->type.specifier.type);
396
slang_operation *child = slang_operation_new(1);
399
printf("Need to adapt types of arg %d\n", i);
401
slang_operation_copy(child, &callOper->children[i]);
402
child->locals->outer_scope = callOper->children[i].locals;
405
if (_slang_sizeof_type_specifier(&argType.spec) >
406
_slang_sizeof_type_specifier(¶mVar->type.specifier)) {
410
callOper->children[i].type = SLANG_OPER_CALL;
411
callOper->children[i].a_id = slang_atom_pool_atom(atoms, constructorName);
412
callOper->children[i].num_children = 1;
413
callOper->children[i].children = child;
416
slang_typeinfo_destruct(&argType);
420
printf("===== New call to %s with cast arguments ===============\n",
421
(char*) fun->header.a_name);
422
slang_print_tree(callOper, 5);
430
* Adapt the arguments for a function call to match the parameters of
431
* the given function.
433
* 1. converting/casting argument types to match parameters
434
* 2. breaking up vector/matrix types into individual components to
435
* satisfy constructors.
438
_slang_adapt_call(slang_operation *callOper, const slang_function *fun,
439
const slang_name_space * space,
440
slang_atom_pool * atoms, slang_info_log *log)
442
const GLboolean haveRetValue = _slang_function_has_return_value(fun);
443
const int numParams = fun->param_count - haveRetValue;
448
printf("Adapt %d args to %d parameters for %s\n",
449
callOper->num_children, numParams, (char *) fun->header.a_name);
451
/* Only try adapting for constructors */
452
if (fun->kind != SLANG_FUNC_CONSTRUCTOR)
455
if (callOper->num_children != numParams) {
456
/* number of arguments doesn't match number of parameters */
458
/* For constructor calls, we can try to unroll vector/matrix args
459
* into individual floats/ints and try to match the function params.
461
for (i = 0; i < numParams; i++) {
462
slang_typeinfo argType;
465
/* Get type of arg[i] */
466
if (!slang_typeinfo_construct(&argType))
468
if (!_slang_typeof_operation(&callOper->children[i], space,
469
&argType, atoms, log)) {
470
slang_typeinfo_destruct(&argType);
475
paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier);
476
assert(paramSz == 1);
478
argSz = _slang_sizeof_type_specifier(&argType.spec);
480
slang_operation origArg;
481
/* break up arg[i] into components */
483
printf("Break up arg %d from 1 to %d elements\n", i, argSz);
485
slang_operation_construct(&origArg);
486
slang_operation_copy(&origArg, &callOper->children[i]);
488
/* insert argSz-1 new children/args */
489
for (j = 0; j < argSz - 1; j++) {
490
(void) slang_operation_insert(&callOper->num_children,
491
&callOper->children, i);
494
/* replace arg[i+j] with subscript/index oper */
495
for (j = 0; j < argSz; j++) {
496
callOper->children[i + j].type = SLANG_OPER_SUBSCRIPT;
497
callOper->children[i + j].locals = _slang_variable_scope_new(callOper->locals);
498
callOper->children[i + j].num_children = 2;
499
callOper->children[i + j].children = slang_operation_new(2);
500
slang_operation_copy(&callOper->children[i + j].children[0],
502
callOper->children[i + j].children[1].type
503
= SLANG_OPER_LITERAL_INT;
504
callOper->children[i + j].children[1].literal[0] = (GLfloat) j;
510
if (callOper->num_children < (GLuint) numParams) {
511
/* still not enough args for all params */
514
else if (callOper->num_children > (GLuint) numParams) {
515
/* now too many arguments */
517
callOper->num_children = (GLuint) numParams;
521
printf("===== New call to %s with adapted arguments ===============\n",
522
(char*) fun->header.a_name);
523
slang_print_tree(callOper, 5);