X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=ast_to_hir.cpp;h=f7c82fab4bf627bce1dc8d6480fef098a4281c1e;hb=afbe26fd61abb3c28c1b0165427b77fd2fed355d;hp=1379ec9801357c2ef4b70adaef9f390b3f580f9e;hpb=adfb0cd7401251bef0c854ac945fce78f0ed11db;p=mesa.git diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp index 1379ec98013..f7c82fab4bf 100644 --- a/ast_to_hir.cpp +++ b/ast_to_hir.cpp @@ -50,7 +50,7 @@ */ #include #include "main/imports.h" -#include "symbol_table.h" +#include "glsl_symbol_table.h" #include "glsl_parser_extras.h" #include "ast.h" #include "glsl_types.h" @@ -63,6 +63,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) _mesa_glsl_initialize_variables(instructions, state); + state->current_function = NULL; + foreach (ptr, & state->translation_unit) { ((ast_node *)ptr)->hir(instructions, state); } @@ -208,8 +210,7 @@ arithmetic_result_type(const struct glsl_type *type_a, type_name[6] = '\0'; } - t = (glsl_type *) - _mesa_symbol_table_find_symbol(state->symbols, 0, type_name); + t = state->symbols->get_type(type_name); return (t != NULL) ? t : glsl_error_type; } } else if (type_a->is_matrix()) { @@ -330,6 +331,45 @@ relational_result_type(const struct glsl_type *type_a, } +/** + * Validates that a value can be assigned to a location with a specified type + * + * Validates that \c rhs can be assigned to some location. If the types are + * not an exact match but an automatic conversion is possible, \c rhs will be + * converted. + * + * \return + * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type. + * Otherwise the actual RHS to be assigned will be returned. This may be + * \c rhs, or it may be \c rhs after some type conversion. + * + * \note + * In addition to being used for assignments, this function is used to + * type-check return values. + */ +ir_instruction * +validate_assignment(const glsl_type *lhs_type, ir_instruction *rhs) +{ + const glsl_type *const rhs_type = rhs->type; + + /* If there is already some error in the RHS, just return it. Anything + * else will lead to an avalanche of error message back to the user. + */ + if (rhs_type->is_error()) + return rhs; + + /* FINISHME: For GLSL 1.10, check that the types are not arrays. */ + + /* If the types are identical, the assignment can trivially proceed. + */ + if (rhs_type == lhs_type) + return rhs; + + /* FINISHME: Check for and apply automatic conversions. */ + return NULL; +} + + ir_instruction * ast_node::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -447,8 +487,11 @@ ast_expression::hir(exec_list *instructions, } } - /* FINISHME: Check that the LHS and RHS have matching types. */ - /* FINISHME: For GLSL 1.10, check that the types are not arrays. */ + ir_instruction *rhs = validate_assignment(op[0]->type, op[1]); + if (rhs == NULL) { + type = glsl_error_type; + rhs = op[1]; + } ir_instruction *tmp = new ir_assignment(op[0], op[1], NULL); instructions->push_tail(tmp); @@ -630,21 +673,10 @@ ast_expression::hir(exec_list *instructions, break; case ast_function_call: - /* There are three sorts of function calls. - * - * 1. contstructors - The first subexpression is an ast_type_specifier. - * 2. methods - Only the .length() method of array types. - * 3. functions - Calls to regular old functions. - * - * Method calls are actually detected when the ast_field_selection - * expression is handled. + /* Should *NEVER* get here. ast_function_call should always be handled + * by ast_function_expression::hir. */ -#if 0 - result = _mesa_ast_function_call_to_hir(this->subexpressions[0], - this->subexpressions[1], - state); - type = result->type; -#endif + assert(0); break; case ast_identifier: { @@ -652,16 +684,15 @@ ast_expression::hir(exec_list *instructions, * tree. This particular use must be at location specified in the grammar * as 'variable_identifier'. */ - ir_variable *var = (ir_variable *) - _mesa_symbol_table_find_symbol(state->symbols, 0, - this->primary_expression.identifier); + ir_variable *var = + state->symbols->get_variable(this->primary_expression.identifier); result = new ir_dereference(var); if (var != NULL) { type = result->type; } else { - _mesa_glsl_error(& loc, NULL, "`%s' undeclared", + _mesa_glsl_error(& loc, state, "`%s' undeclared", this->primary_expression.identifier); error_emitted = true; @@ -715,7 +746,7 @@ ast_expression::hir(exec_list *instructions, } if (is_error_type(type) && !error_emitted) - _mesa_glsl_error(& loc, NULL, "type mismatch"); + _mesa_glsl_error(& loc, state, "type mismatch"); return result; } @@ -751,13 +782,13 @@ ast_compound_statement::hir(exec_list *instructions, if (new_scope) - _mesa_symbol_table_push_scope(state->symbols); + state->symbols->push_scope(); foreach (ptr, &statements) ((ast_node *)ptr)->hir(instructions, state); if (new_scope) - _mesa_symbol_table_pop_scope(state->symbols); + state->symbols->pop_scope(); /* Compound statements do not have r-values. */ @@ -770,76 +801,17 @@ type_specifier_to_glsl_type(const struct ast_type_specifier *spec, const char **name, struct _mesa_glsl_parse_state *state) { - static const char *const type_names[] = { - "void", - "float", - "int", - "uint", - "bool", - "vec2", - "vec3", - "vec4", - "bvec2", - "bvec3", - "bvec4", - "ivec2", - "ivec3", - "ivec4", - "uvec2", - "uvec3", - "uvec4", - "mat2", - "mat2x3", - "mat2x4", - "mat3x2", - "mat3", - "mat3x4", - "mat4x2", - "mat4x3", - "mat4", - "sampler1D", - "sampler2D", - "sampler3D", - "samplerCube", - "sampler1DShadow", - "sampler2DShadow", - "samplerCubeShadow", - "sampler1DArray", - "sampler2DArray", - "sampler1DArrayShadow", - "sampler2DArrayShadow", - "isampler1D", - "isampler2D", - "isampler3D", - "isamplerCube", - "isampler1DArray", - "isampler2DArray", - "usampler1D", - "usampler2D", - "usampler3D", - "usamplerCube", - "usampler1DArray", - "usampler2DArray", - - NULL, /* ast_struct */ - NULL /* ast_type_name */ - }; struct glsl_type *type; - const char *type_name = NULL; if (spec->type_specifier == ast_struct) { /* FINISHME: Handle annonymous structures. */ type = NULL; } else { - type_name = (spec->type_specifier == ast_type_name) - ? spec->type_name : type_names[spec->type_specifier]; - - type = (glsl_type *) - _mesa_symbol_table_find_symbol(state->symbols, 0, type_name); - *name = type_name; + type = state->symbols->get_type(spec->type_name); + *name = spec->type_name; /* FINISHME: Handle array declarations. Note that this requires complete - * FINSIHME: handling of constant expressions. + * FINISHME: handling of constant expressions. */ } @@ -911,7 +883,7 @@ ast_declarator_list::hir(exec_list *instructions, * FINISHME: declaration at a higher scope. */ - if (decl_type == NULL) { + if ((decl_type == NULL) || decl_type->is_void()) { YYLTYPE loc; loc = this->get_location(); @@ -939,7 +911,7 @@ ast_declarator_list::hir(exec_list *instructions, var = new ir_variable(var_type, decl->identifier); - /* FINSIHME: Variables that are attribute, uniform, varying, in, or + /* FINISHME: Variables that are attribute, uniform, varying, in, or * FINISHME: out varibles must be declared either at global scope or * FINISHME: in a parameter list (in and out only). */ @@ -949,8 +921,7 @@ ast_declarator_list::hir(exec_list *instructions, /* Attempt to add the variable to the symbol table. If this fails, it * means the variable has already been declared at this scope. */ - if (_mesa_symbol_table_add_symbol(state->symbols, 0, decl->identifier, - var) != 0) { + if (state->symbols->name_declared_this_scope(decl->identifier)) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "`%s' redeclared", @@ -958,6 +929,10 @@ ast_declarator_list::hir(exec_list *instructions, continue; } + const bool added_variable = + state->symbols->add_variable(decl->identifier, var); + assert(added_variable); + instructions->push_tail(var); /* FINISHME: Process the declaration initializer. */ @@ -1000,7 +975,12 @@ ast_parameter_declarator::hir(exec_list *instructions, * FINISHME: complete handling of constant expressions. */ + /* Apply any specified qualifiers to the parameter declaration. Note that + * for function parameters the default mode is 'in'. + */ apply_type_qualifier_to_variable(& this->type->qualifier, var, state); + if (var->mode == ir_var_auto) + var->mode = ir_var_in; instructions->push_tail(var); @@ -1068,14 +1048,20 @@ ast_function_definition::hir(exec_list *instructions, ast_function_parameters_to_hir(& this->prototype->parameters, & parameters, state); + const char *return_type_name; + const glsl_type *return_type = + type_specifier_to_glsl_type(this->prototype->return_type->specifier, + & return_type_name, state); + + assert(return_type != NULL); + /* Verify that this function's signature either doesn't match a previously * seen signature for a function with the same name, or, if a match is found, * that the previously seen signature does not have an associated definition. */ - f = (ir_function *) - _mesa_symbol_table_find_symbol(state->symbols, 0, - this->prototype->identifier); + const char *const name = this->prototype->identifier; + f = state->symbols->get_function(name); if (f != NULL) { foreach_iter(exec_list_iterator, iter, f->signatures) { signature = (struct ir_function_signature *) iter.get(); @@ -1091,8 +1077,7 @@ ast_function_definition::hir(exec_list *instructions, if (signature->definition != NULL) { YYLTYPE loc = this->get_location(); - _mesa_glsl_error(& loc, state, "function `%s' redefined", - this->prototype->identifier); + _mesa_glsl_error(& loc, state, "function `%s' redefined", name); signature = NULL; break; } @@ -1101,18 +1086,24 @@ ast_function_definition::hir(exec_list *instructions, signature = NULL; } - } else { - f = new ir_function(); - f->name = this->prototype->identifier; + } else if (state->symbols->name_declared_this_scope(name)) { + /* This function name shadows a non-function use of the same name. + */ + YYLTYPE loc = this->get_location(); - _mesa_symbol_table_add_symbol(state->symbols, 0, f->name, f); + _mesa_glsl_error(& loc, state, "function name `%s' conflicts with " + "non-function", name); + signature = NULL; + } else { + f = new ir_function(name); + state->symbols->add_function(f->name, f); } /* Finish storing the information about this new function in its signature. */ if (signature == NULL) { - signature = new ir_function_signature(); + signature = new ir_function_signature(return_type); f->signatures.push_tail(signature); } else { /* Destroy all of the previous parameter information. The previous @@ -1128,12 +1119,15 @@ ast_function_definition::hir(exec_list *instructions, } + assert(state->current_function == NULL); + state->current_function = signature; + ast_function_parameters_to_hir(& this->prototype->parameters, & signature->parameters, state); /* FINISHME: Set signature->return_type */ - label = new ir_label(this->prototype->identifier); + label = new ir_label(name); if (signature->definition == NULL) { signature->definition = label; } @@ -1144,16 +1138,25 @@ ast_function_definition::hir(exec_list *instructions, * to the instruction list. There are other more efficient ways to do this, * but they involve ugly linked-list gymnastics. */ - _mesa_symbol_table_push_scope(state->symbols); + state->symbols->push_scope(); foreach_iter(exec_list_iterator, iter, parameters) { ir_variable *const var = (ir_variable *) iter.get(); - assert(var->mode == ir_op_var_decl); + assert(((ir_instruction *)var)->mode == ir_op_var_decl); iter.remove(); instructions->push_tail(var); - _mesa_symbol_table_add_symbol(state->symbols, 0, var->name, var); + /* The only way a parameter would "exist" is if two parameters have + * the same name. + */ + if (state->symbols->name_declared_this_scope(var->name)) { + YYLTYPE loc = this->get_location(); + + _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name); + } else { + state->symbols->add_variable(var->name, var); + } } /* Convert the body of the function to HIR, and append the resulting @@ -1162,10 +1165,49 @@ ast_function_definition::hir(exec_list *instructions, */ this->body->hir(instructions, state); - _mesa_symbol_table_pop_scope(state->symbols); + state->symbols->pop_scope(); + assert(state->current_function == signature); + state->current_function = NULL; /* Function definitions do not have r-values. */ return NULL; } + + +ir_instruction * +ast_jump_statement::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + + if (mode == ast_return) { + ir_return *inst; + + if (opt_return_value) { + /* FINISHME: Make sure the enclosing function has a non-void return + * FINISHME: type. + */ + + ir_expression *const ret = (ir_expression *) + opt_return_value->hir(instructions, state); + assert(ret != NULL); + + /* FINISHME: Make sure the type of the return value matches the return + * FINISHME: type of the enclosing function. + */ + + inst = new ir_return(ret); + } else { + /* FINISHME: Make sure the enclosing function has a void return type. + */ + inst = new ir_return; + } + + instructions->push_tail(inst); + } + + /* Jump instructions do not have r-values. + */ + return NULL; +}