/* * Mesa 3-D graphics library * Version: 6.5.2 * * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * \file slang_assemble_typeinfo.c * slang type info * \author Michal Krol */ #include "imports.h" #include "macros.h" #include "get.h" #include "slang_compile.h" #include "slang_codegen.h" #include "slang_simplify.h" #include "slang_print.h" /** * Lookup the value of named constant, such as gl_MaxLights. * \return value of constant, or -1 if unknown */ GLint _slang_lookup_constant(const char *name) { struct constant_info { const char *Name; const GLenum Token; }; static const struct constant_info info[] = { { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES }, { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS }, { "gl_MaxDrawBuffers", GL_MAX_DRAW_BUFFERS }, { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS }, { "gl_MaxLights", GL_MAX_LIGHTS }, { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS }, { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS }, { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS }, { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS }, { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS }, { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS }, { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS }, { NULL, 0 } }; GLuint i; for (i = 0; info[i].Name; i++) { if (strcmp(info[i].Name, name) == 0) { /* found */ GLint value = -1.0; _mesa_GetIntegerv(info[i].Token, &value); ASSERT(value >= 0); /* sanity check that glGetFloatv worked */ return value; } } return -1; } /** * Recursively traverse an AST tree, applying simplifications wherever * possible. * At the least, we do constant folding. We need to do that much so that * compile-time expressions can be evaluated for things like array * declarations. I.e.: float foo[3 + 5]; */ void _slang_simplify(slang_operation *oper, const slang_assembly_name_space * space, slang_atom_pool * atoms) { GLboolean isFloat[4]; GLboolean isBool[4]; GLuint i, n; if (oper->type == slang_oper_identifier) { /* see if it's a named constant */ GLint value = _slang_lookup_constant((char *) oper->a_id); if (value >= 0) { oper->literal[0] = oper->literal[1] = oper->literal[2] = oper->literal[3] = value; oper->type = slang_oper_literal_int; return; } } /* first, simplify children */ for (i = 0; i < oper->num_children; i++) { _slang_simplify(&oper->children[i], space, atoms); } /* examine children */ n = MIN2(oper->num_children, 4); for (i = 0; i < n; i++) { isFloat[i] = (oper->children[i].type == slang_oper_literal_float || oper->children[i].type == slang_oper_literal_int); isBool[i] = (oper->children[i].type == slang_oper_literal_bool); } if (n == 2 && isFloat[0] && isFloat[1]) { /* probably simple arithmetic */ switch (oper->type) { case slang_oper_add: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] + oper->children[1].literal[i]; } slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; case slang_oper_subtract: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] - oper->children[1].literal[i]; } slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; case slang_oper_multiply: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] * oper->children[1].literal[i]; } slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; case slang_oper_divide: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] / oper->children[1].literal[i]; } slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; default: ; /* nothing */ } } if (n == 1 && isFloat[0]) { switch (oper->type) { case slang_oper_minus: for (i = 0; i < 4; i++) { oper->literal[i] = -oper->children[0].literal[i]; } slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; case slang_oper_plus: COPY_4V(oper->literal, oper->children[0].literal); slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; default: ; /* nothing */ } } if (n == 2 && isBool[0] && isBool[1]) { /* simple boolean expression */ switch (oper->type) { case slang_oper_logicaland: for (i = 0; i < 4; i++) { const GLint a = oper->children[0].literal[i] ? 1 : 0; const GLint b = oper->children[1].literal[i] ? 1 : 0; oper->literal[i] = (GLfloat) (a && b); } slang_operation_destruct(oper); oper->type = slang_oper_literal_bool; return; case slang_oper_logicalor: for (i = 0; i < 4; i++) { const GLint a = oper->children[0].literal[i] ? 1 : 0; const GLint b = oper->children[1].literal[i] ? 1 : 0; oper->literal[i] = (GLfloat) (a || b); } slang_operation_destruct(oper); oper->type = slang_oper_literal_bool; return; case slang_oper_logicalxor: for (i = 0; i < 4; i++) { const GLint a = oper->children[0].literal[i] ? 1 : 0; const GLint b = oper->children[1].literal[i] ? 1 : 0; oper->literal[i] = (GLfloat) (a ^ b); } slang_operation_destruct(oper); oper->type = slang_oper_literal_bool; return; default: ; /* nothing */ } } if (n == 4 && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) { /* vec4(flt, flt, flt, flt) constructor */ if (oper->type == slang_oper_call) { if (strcmp((char *) oper->a_id, "vec4") == 0) { oper->literal[0] = oper->children[0].literal[0]; oper->literal[1] = oper->children[1].literal[0]; oper->literal[2] = oper->children[2].literal[0]; oper->literal[3] = oper->children[3].literal[0]; slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; } } } if (n == 3 && isFloat[0] && isFloat[1] && isFloat[2]) { /* vec3(flt, flt, flt) constructor */ if (oper->type == slang_oper_call) { if (strcmp((char *) oper->a_id, "vec3") == 0) { oper->literal[0] = oper->children[0].literal[0]; oper->literal[1] = oper->children[1].literal[0]; oper->literal[2] = oper->children[2].literal[0]; oper->literal[3] = oper->literal[2]; slang_operation_destruct(oper); oper->type = slang_oper_literal_float; return; } } } if (n == 2 && isFloat[0] && isFloat[1]) { /* vec4(flt, flt) constructor */ if (oper->type == slang_oper_call) { if (strcmp((char *) oper->a_id, "vec2") == 0) { oper->literal[0] = oper->children[0].literal[0]; oper->literal[1] = oper->children[1].literal[0]; oper->literal[2] = oper->literal[1]; oper->literal[3] = oper->literal[1]; slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ oper->type = slang_oper_literal_float; return; } } } } /** * Adapt the arguments for a function call to match the parameters of * the given function. * This is for: * 1. converting/casting argument types to match parameters * 2. breaking up vector/matrix types into individual components to * satisfy constructors. */ GLboolean _slang_adapt_call(slang_operation *callOper, const slang_function *fun, const slang_assembly_name_space * space, slang_atom_pool * atoms) { const GLboolean haveRetValue = _slang_function_has_return_value(fun); const int numParams = fun->param_count - haveRetValue; int i; int dbg = 0; if (dbg) printf("Adapt %d args to %d parameters\n", callOper->num_children, numParams); if (callOper->num_children != numParams) { /* number of arguments doesn't match number of parameters */ if (fun->kind == slang_func_constructor) { /* For constructor calls, we can try to unroll vector/matrix args * into individual floats/ints and try to match the function params. */ for (i = 0; i < numParams; i++) { slang_assembly_typeinfo argType; GLint argSz, j; /* Get type of arg[i] */ if (!slang_assembly_typeinfo_construct(&argType)) return GL_FALSE; if (!_slang_typeof_operation_(&callOper->children[i], space, &argType, atoms)) { slang_assembly_typeinfo_destruct(&argType); return GL_FALSE; } /* paramSz = _slang_sizeof_type_specifier(¶mVar->type.specifier); assert(paramSz == 1); */ argSz = _slang_sizeof_type_specifier(&argType.spec); if (argSz > 1) { slang_operation origArg; /* break up arg[i] into components */ if (dbg) printf("Break up arg %d from 1 to %d elements\n", i, argSz); slang_operation_construct(&origArg); slang_operation_copy(&origArg, &callOper->children[i]); /* insert argSz-1 new children/args */ for (j = 0; j < argSz - 1; j++) { (void) slang_operation_insert(&callOper->num_children, &callOper->children, i); } /* replace arg[i+j] with subscript/index oper */ for (j = 0; j < argSz; j++) { callOper->children[i + j].type = slang_oper_subscript; callOper->children[i + j].num_children = 2; callOper->children[i + j].children = slang_operation_new(2); slang_operation_copy(&callOper->children[i + j].children[0], &origArg); callOper->children[i + j].children[1].type = slang_oper_literal_int; callOper->children[i + j].children[1].literal[0] = j; } } } /* for i */ } else { /* non-constructor function: number of args must match number * of function params. */ return GL_FALSE; /* caller will record an error msg */ } } if (callOper->num_children < numParams) { /* still not enough args for all params */ return GL_FALSE; } else if (callOper->num_children > numParams) { /* now too many arguments */ /* XXX this isn't always an error, see spec */ return GL_FALSE; } /* * Second phase, argument casting. * Example: * void foo(int i, bool b) {} * x = foo(3.15, 9); * Gets translated into: * x = foo(int(3.15), bool(9)) */ for (i = 0; i < numParams; i++) { slang_assembly_typeinfo argType; slang_variable *paramVar = fun->parameters->variables[i]; /* Get type of arg[i] */ if (!slang_assembly_typeinfo_construct(&argType)) return GL_FALSE; if (!_slang_typeof_operation_(&callOper->children[i], space, &argType, atoms)) { slang_assembly_typeinfo_destruct(&argType); return GL_FALSE; } /* see if arg type matches parameter type */ if (!slang_type_specifier_equal(&argType.spec, ¶mVar->type.specifier)) { /* need to adapt arg type to match param type */ const char *constructorName = slang_type_specifier_type_to_string(paramVar->type.specifier.type); slang_operation *child = slang_operation_new(1); slang_operation_copy(child, &callOper->children[i]); child->locals->outer_scope = callOper->locals; callOper->children[i].type = slang_oper_call; callOper->children[i].a_id = slang_atom_pool_atom(atoms, constructorName); callOper->children[i].num_children = 1; callOper->children[i].children = child; } slang_assembly_typeinfo_destruct(&argType); } if (dbg) { printf("===== New call to %s with adapted arguments ===============\n", (char*) fun->header.a_name); slang_print_tree(callOper, 5); } return GL_TRUE; }