From c6f80401dc533b04341afe8d596960d1bc25efce Mon Sep 17 00:00:00 2001 From: marha Date: Tue, 10 Apr 2012 10:49:59 +0200 Subject: fontconfig mesa xkeyboard-config xserver pixman git update 10 Apr 2012 --- mesalib/src/glsl/ast.h | 82 +----- mesalib/src/glsl/ast_function.cpp | 323 +++++++++++---------- mesalib/src/glsl/ast_to_hir.cpp | 6 +- mesalib/src/glsl/ast_type.cpp | 68 +---- mesalib/src/glsl/glsl_parser.yy | 109 +++---- mesalib/src/glsl/glsl_parser_extras.cpp | 4 +- mesalib/src/glsl/glsl_types.cpp | 5 +- mesalib/src/glsl/hir_field_selection.cpp | 2 +- mesalib/src/glsl/ir.cpp | 17 +- mesalib/src/glsl/ir.h | 83 +++--- mesalib/src/glsl/ir_basic_block.cpp | 43 --- mesalib/src/glsl/ir_clone.cpp | 18 +- mesalib/src/glsl/ir_constant_expression.cpp | 33 ++- mesalib/src/glsl/ir_expression_flattening.cpp | 5 - mesalib/src/glsl/ir_function.cpp | 2 +- mesalib/src/glsl/ir_function_can_inline.cpp | 152 +++++----- mesalib/src/glsl/ir_function_detect_recursion.cpp | 2 +- mesalib/src/glsl/ir_hierarchical_visitor.cpp | 9 + mesalib/src/glsl/ir_hierarchical_visitor.h | 1 + mesalib/src/glsl/ir_hv_accept.cpp | 15 + mesalib/src/glsl/ir_print_visitor.cpp | 9 +- mesalib/src/glsl/ir_print_visitor.h | 1 + mesalib/src/glsl/ir_reader.cpp | 60 +++- mesalib/src/glsl/ir_validate.cpp | 17 +- mesalib/src/glsl/ir_visitor.h | 1 + mesalib/src/glsl/link_functions.cpp | 6 +- mesalib/src/glsl/link_uniforms.cpp | 3 +- mesalib/src/glsl/linker.cpp | 12 +- mesalib/src/glsl/loop_analysis.cpp | 28 ++ mesalib/src/glsl/loop_analysis.h | 6 + mesalib/src/glsl/lower_clip_distance.cpp | 2 +- mesalib/src/glsl/lower_output_reads.cpp | 18 +- .../glsl/lower_variable_index_to_cond_assign.cpp | 2 +- mesalib/src/glsl/opt_constant_folding.cpp | 12 +- mesalib/src/glsl/opt_constant_propagation.cpp | 2 +- mesalib/src/glsl/opt_constant_variable.cpp | 14 +- mesalib/src/glsl/opt_copy_propagation.cpp | 2 +- mesalib/src/glsl/opt_copy_propagation_elements.cpp | 2 +- mesalib/src/glsl/opt_dead_code.cpp | 3 +- mesalib/src/glsl/opt_dead_code_local.cpp | 7 +- mesalib/src/glsl/opt_dead_functions.cpp | 2 +- mesalib/src/glsl/opt_function_inlining.cpp | 62 +--- mesalib/src/glsl/opt_tree_grafting.cpp | 5 +- 43 files changed, 609 insertions(+), 646 deletions(-) (limited to 'mesalib/src/glsl') diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h index 1f78af87e..9b1e0b192 100644 --- a/mesalib/src/glsl/ast.h +++ b/mesalib/src/glsl/ast.h @@ -206,7 +206,7 @@ public: subexpressions[0] = NULL; subexpressions[1] = NULL; subexpressions[2] = NULL; - primary_expression.identifier = (char *) identifier; + primary_expression.identifier = identifier; this->non_lvalue_description = NULL; } @@ -222,7 +222,7 @@ public: ast_expression *subexpressions[3]; union { - char *identifier; + const char *identifier; int int_constant; float float_constant; unsigned uint_constant; @@ -317,11 +317,11 @@ public: class ast_declaration : public ast_node { public: - ast_declaration(char *identifier, int is_array, ast_expression *array_size, + ast_declaration(const char *identifier, int is_array, ast_expression *array_size, ast_expression *initializer); virtual void print(void) const; - char *identifier; + const char *identifier; int is_array; ast_expression *array_size; @@ -407,83 +407,23 @@ struct ast_type_qualifier { class ast_struct_specifier : public ast_node { public: - ast_struct_specifier(char *identifier, ast_node *declarator_list); + ast_struct_specifier(const char *identifier, ast_node *declarator_list); virtual void print(void) const; virtual ir_rvalue *hir(exec_list *instructions, struct _mesa_glsl_parse_state *state); - char *name; + const char *name; exec_list declarations; }; -enum ast_types { - ast_void, - ast_float, - ast_int, - ast_uint, - ast_bool, - ast_vec2, - ast_vec3, - ast_vec4, - ast_bvec2, - ast_bvec3, - ast_bvec4, - ast_ivec2, - ast_ivec3, - ast_ivec4, - ast_uvec2, - ast_uvec3, - ast_uvec4, - ast_mat2, - ast_mat2x3, - ast_mat2x4, - ast_mat3x2, - ast_mat3, - ast_mat3x4, - ast_mat4x2, - ast_mat4x3, - ast_mat4, - ast_sampler1d, - ast_sampler2d, - ast_sampler2drect, - ast_sampler3d, - ast_samplercube, - ast_samplerexternaloes, - ast_sampler1dshadow, - ast_sampler2dshadow, - ast_sampler2drectshadow, - ast_samplercubeshadow, - ast_sampler1darray, - ast_sampler2darray, - ast_sampler1darrayshadow, - ast_sampler2darrayshadow, - ast_isampler1d, - ast_isampler2d, - ast_isampler3d, - ast_isamplercube, - ast_isampler1darray, - ast_isampler2darray, - ast_usampler1d, - ast_usampler2d, - ast_usampler3d, - ast_usamplercube, - ast_usampler1darray, - ast_usampler2darray, - - ast_struct, - ast_type_name -}; - class ast_type_specifier : public ast_node { public: - ast_type_specifier(int specifier); - /** Construct a type specifier from a type name */ ast_type_specifier(const char *name) - : type_specifier(ast_type_name), type_name(name), structure(NULL), + : type_name(name), structure(NULL), is_array(false), array_size(NULL), precision(ast_precision_none), is_precision_statement(false) { @@ -492,7 +432,7 @@ public: /** Construct a type specifier from a structure definition */ ast_type_specifier(ast_struct_specifier *s) - : type_specifier(ast_struct), type_name(s->name), structure(s), + : type_name(s->name), structure(s), is_array(false), array_size(NULL), precision(ast_precision_none), is_precision_statement(false) { @@ -507,8 +447,6 @@ public: ir_rvalue *hir(exec_list *, struct _mesa_glsl_parse_state *); - enum ast_types type_specifier; - const char *type_name; ast_struct_specifier *structure; @@ -568,7 +506,7 @@ public: struct _mesa_glsl_parse_state *state); ast_fully_specified_type *type; - char *identifier; + const char *identifier; int is_array; ast_expression *array_size; @@ -599,7 +537,7 @@ public: struct _mesa_glsl_parse_state *state); ast_fully_specified_type *return_type; - char *identifier; + const char *identifier; exec_list parameters; diff --git a/mesalib/src/glsl/ast_function.cpp b/mesalib/src/glsl/ast_function.cpp index 1c2e8613c..39401017b 100644 --- a/mesalib/src/glsl/ast_function.cpp +++ b/mesalib/src/glsl/ast_function.cpp @@ -83,7 +83,7 @@ prototype_string(const glsl_type *return_type, const char *name, const char *comma = ""; foreach_list(node, parameters) { - const ir_instruction *const param = (ir_instruction *) node; + const ir_variable *const param = (ir_variable *) node; ralloc_asprintf_append(&str, "%s%s", comma, param->type->name); comma = ", "; @@ -94,76 +94,116 @@ prototype_string(const glsl_type *return_type, const char *name, } /** - * If a function call is generated, \c call_ir will point to it on exit. - * Otherwise \c call_ir will be set to \c NULL. + * Verify that 'out' and 'inout' actual parameters are lvalues. Also, verify + * that 'const_in' formal parameters (an extension in our IR) correspond to + * ir_constant actual parameters. */ -static ir_rvalue * -generate_call(exec_list *instructions, ir_function_signature *sig, - YYLTYPE *loc, exec_list *actual_parameters, - ir_call **call_ir, - struct _mesa_glsl_parse_state *state) +static bool +verify_parameter_modes(_mesa_glsl_parse_state *state, + ir_function_signature *sig, + exec_list &actual_ir_parameters, + exec_list &actual_ast_parameters) { - void *ctx = state; - exec_list post_call_conversions; + exec_node *actual_ir_node = actual_ir_parameters.head; + exec_node *actual_ast_node = actual_ast_parameters.head; - *call_ir = NULL; + foreach_list(formal_node, &sig->parameters) { + /* The lists must be the same length. */ + assert(!actual_ir_node->is_tail_sentinel()); + assert(!actual_ast_node->is_tail_sentinel()); - /* Verify that 'out' and 'inout' actual parameters are lvalues. This - * isn't done in ir_function::matching_signature because that function - * cannot generate the necessary diagnostics. - * - * Also, validate that 'const_in' formal parameters (an extension of our - * IR) correspond to ir_constant actual parameters. - * - * Also, perform implicit conversion of arguments. Note: to implicitly - * convert out parameters, we need to place them in a temporary - * variable, and do the conversion after the call takes place. Since we - * haven't emitted the call yet, we'll place the post-call conversions - * in a temporary exec_list, and emit them later. - */ - exec_list_iterator actual_iter = actual_parameters->iterator(); - exec_list_iterator formal_iter = sig->parameters.iterator(); - - while (actual_iter.has_next()) { - ir_rvalue *actual = (ir_rvalue *) actual_iter.get(); - ir_variable *formal = (ir_variable *) formal_iter.get(); + const ir_variable *const formal = (ir_variable *) formal_node; + const ir_rvalue *const actual = (ir_rvalue *) actual_ir_node; + const ast_expression *const actual_ast = + exec_node_data(ast_expression, actual_ast_node, link); - assert(actual != NULL); - assert(formal != NULL); + /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always + * FIXME: 0:0(0). + */ + YYLTYPE loc = actual_ast->get_location(); - if (formal->mode == ir_var_const_in && !actual->as_constant()) { - _mesa_glsl_error(loc, state, - "parameter `%s' must be a constant expression", + /* Verify that 'const_in' parameters are ir_constants. */ + if (formal->mode == ir_var_const_in && + actual->ir_type != ir_type_constant) { + _mesa_glsl_error(&loc, state, + "parameter `in %s' must be a constant expression", formal->name); - return ir_call::get_error_instruction(ctx); + return false; } - if ((formal->mode == ir_var_out) - || (formal->mode == ir_var_inout)) { + /* Verify that 'out' and 'inout' actual parameters are lvalues. */ + if (formal->mode == ir_var_out || formal->mode == ir_var_inout) { const char *mode = NULL; switch (formal->mode) { case ir_var_out: mode = "out"; break; case ir_var_inout: mode = "inout"; break; default: assert(false); break; } - /* FIXME: 'loc' is incorrect (as of 2011-01-21). It is always - * FIXME: 0:0(0). + + /* This AST-based check catches errors like f(i++). The IR-based + * is_lvalue() is insufficient because the actual parameter at the + * IR-level is just a temporary value, which is an l-value. */ + if (actual_ast->non_lvalue_description != NULL) { + _mesa_glsl_error(&loc, state, + "function parameter '%s %s' references a %s", + mode, formal->name, + actual_ast->non_lvalue_description); + return false; + } + if (actual->variable_referenced() && actual->variable_referenced()->read_only) { - _mesa_glsl_error(loc, state, + _mesa_glsl_error(&loc, state, "function parameter '%s %s' references the " "read-only variable '%s'", mode, formal->name, actual->variable_referenced()->name); - + return false; } else if (!actual->is_lvalue()) { - _mesa_glsl_error(loc, state, + _mesa_glsl_error(&loc, state, "function parameter '%s %s' is not an lvalue", mode, formal->name); + return false; } } + actual_ir_node = actual_ir_node->next; + actual_ast_node = actual_ast_node->next; + } + return true; +} + +/** + * If a function call is generated, \c call_ir will point to it on exit. + * Otherwise \c call_ir will be set to \c NULL. + */ +static ir_rvalue * +generate_call(exec_list *instructions, ir_function_signature *sig, + YYLTYPE *loc, exec_list *actual_parameters, + ir_call **call_ir, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + exec_list post_call_conversions; + + *call_ir = NULL; + + /* Perform implicit conversion of arguments. For out parameters, we need + * to place them in a temporary variable and do the conversion after the + * call takes place. Since we haven't emitted the call yet, we'll place + * the post-call conversions in a temporary exec_list, and emit them later. + */ + exec_list_iterator actual_iter = actual_parameters->iterator(); + exec_list_iterator formal_iter = sig->parameters.iterator(); + + while (actual_iter.has_next()) { + ir_rvalue *actual = (ir_rvalue *) actual_iter.get(); + ir_variable *formal = (ir_variable *) formal_iter.get(); + + assert(actual != NULL); + assert(formal != NULL); + if (formal->type->is_numeric() || formal->type->is_boolean()) { switch (formal->mode) { case ir_var_const_in: @@ -229,29 +269,21 @@ generate_call(exec_list *instructions, ir_function_signature *sig, formal_iter.next(); } - /* Always insert the call in the instruction stream, and return a deref - * of its return val if it returns a value, since we don't know if - * the rvalue is going to be assigned to anything or not. + /* If the function call is a constant expression, don't generate any + * instructions; just generate an ir_constant. * - * Also insert any out parameter conversions after the call. + * Function calls were first allowed to be constant expressions in GLSL 1.20. */ - ir_call *call = new(ctx) ir_call(sig, actual_parameters); - ir_dereference_variable *deref; - if (!sig->return_type->is_void()) { - /* If the function call is a constant expression, don't - * generate the instructions to call it; just generate an - * ir_constant representing the constant value. - * - * Function calls can only be constant expressions starting - * in GLSL 1.20. - */ - if (state->language_version >= 120) { - ir_constant *const_val = call->constant_expression_value(); - if (const_val) { - return const_val; - } + if (state->language_version >= 120) { + ir_constant *value = sig->constant_expression_value(actual_parameters); + if (value != NULL) { + return value; } + } + ir_dereference_variable *deref = NULL; + if (!sig->return_type->is_void()) { + /* Create a new temporary to hold the return value. */ ir_variable *var; var = new(ctx) ir_variable(sig->return_type, @@ -261,24 +293,22 @@ generate_call(exec_list *instructions, ir_function_signature *sig, instructions->push_tail(var); deref = new(ctx) ir_dereference_variable(var); - ir_assignment *assign = new(ctx) ir_assignment(deref, call, NULL); - instructions->push_tail(assign); - *call_ir = call; - - deref = new(ctx) ir_dereference_variable(var); - } else { - instructions->push_tail(call); - *call_ir = call; - deref = NULL; } + ir_call *call = new(ctx) ir_call(sig, deref, actual_parameters); + instructions->push_tail(call); + + /* Also emit any necessary out-parameter conversions. */ instructions->append_list(&post_call_conversions); - return deref; + + return deref ? deref->clone(ctx, NULL) : NULL; } -static ir_rvalue * -match_function_by_name(exec_list *instructions, const char *name, - YYLTYPE *loc, exec_list *actual_parameters, - ir_call **call_ir, +/** + * Given a function name and parameter list, find the matching signature. + */ +static ir_function_signature * +match_function_by_name(const char *name, + exec_list *actual_parameters, struct _mesa_glsl_parse_state *state) { void *ctx = state; @@ -350,43 +380,45 @@ done: } f->add_signature(sig->clone_prototype(f, NULL)); } + } + return sig; +} - /* Finally, generate a call instruction. */ - return generate_call(instructions, sig, loc, actual_parameters, - call_ir, state); - } else { - char *str = prototype_string(NULL, name, actual_parameters); - - _mesa_glsl_error(loc, state, "no matching function for call to `%s'", - str); - ralloc_free(str); - - const char *prefix = "candidates are: "; +/** + * Raise a "no matching function" error, listing all possible overloads the + * compiler considered so developers can figure out what went wrong. + */ +static void +no_matching_function_error(const char *name, + YYLTYPE *loc, + exec_list *actual_parameters, + _mesa_glsl_parse_state *state) +{ + char *str = prototype_string(NULL, name, actual_parameters); + _mesa_glsl_error(loc, state, "no matching function for call to `%s'", str); + ralloc_free(str); - for (int i = -1; i < (int) state->num_builtins_to_link; i++) { - glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols - : state->symbols; - f = syms->get_function(name); - if (f == NULL) - continue; + const char *prefix = "candidates are: "; - foreach_list (node, &f->signatures) { - ir_function_signature *sig = (ir_function_signature *) node; + for (int i = -1; i < (int) state->num_builtins_to_link; i++) { + glsl_symbol_table *syms = i >= 0 ? state->builtins_to_link[i]->symbols + : state->symbols; + ir_function *f = syms->get_function(name); + if (f == NULL) + continue; - str = prototype_string(sig->return_type, f->name, &sig->parameters); - _mesa_glsl_error(loc, state, "%s%s", prefix, str); - ralloc_free(str); + foreach_list (node, &f->signatures) { + ir_function_signature *sig = (ir_function_signature *) node; - prefix = " "; - } + str = prototype_string(sig->return_type, f->name, &sig->parameters); + _mesa_glsl_error(loc, state, "%s%s", prefix, str); + ralloc_free(str); + prefix = " "; } - - return ir_call::get_error_instruction(ctx); } } - /** * Perform automatic type conversion of constructor parameters * @@ -558,7 +590,7 @@ process_array_constructor(exec_list *instructions, "parameter%s", (constructor_type->length != 0) ? "at least" : "exactly", min_param, (min_param <= 1) ? "" : "s"); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } if (constructor_type->length == 0) { @@ -1195,7 +1227,7 @@ ast_function_expression::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "unknown type `%s' (structure name " "may be shadowed by a variable with the same name)", type->type_name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } @@ -1204,14 +1236,14 @@ ast_function_expression::hir(exec_list *instructions, if (constructor_type->is_sampler()) { _mesa_glsl_error(& loc, state, "cannot construct sampler type `%s'", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } if (constructor_type->is_array()) { if (state->language_version <= 110) { _mesa_glsl_error(& loc, state, "array constructors forbidden in GLSL 1.10"); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } return process_array_constructor(instructions, constructor_type, @@ -1242,7 +1274,7 @@ ast_function_expression::hir(exec_list *instructions, "insufficient parameters to constructor " "for `%s'", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } if (apply_implicit_conversion(constructor_type->fields.structure[i].type, @@ -1256,7 +1288,7 @@ ast_function_expression::hir(exec_list *instructions, constructor_type->fields.structure[i].name, ir->type->name, constructor_type->fields.structure[i].type->name); - return ir_call::get_error_instruction(ctx);; + return ir_rvalue::error_value(ctx);; } node = node->next; @@ -1265,7 +1297,7 @@ ast_function_expression::hir(exec_list *instructions, if (!node->is_tail_sentinel()) { _mesa_glsl_error(&loc, state, "too many parameters in constructor " "for `%s'", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } ir_rvalue *const constant = @@ -1279,7 +1311,7 @@ ast_function_expression::hir(exec_list *instructions, } if (!constructor_type->is_numeric() && !constructor_type->is_boolean()) - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); /* Total number of components of the type being constructed. */ const unsigned type_components = constructor_type->components(); @@ -1306,14 +1338,14 @@ ast_function_expression::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "too many parameters to `%s' " "constructor", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } if (!result->type->is_numeric() && !result->type->is_boolean()) { _mesa_glsl_error(& loc, state, "cannot construct `%s' from a " "non-numeric data type", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } /* Count the number of matrix and nonmatrix parameters. This @@ -1338,7 +1370,7 @@ ast_function_expression::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "cannot construct `%s' from a " "matrix in GLSL 1.10", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec: @@ -1352,7 +1384,7 @@ ast_function_expression::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "for matrix `%s' constructor, " "matrix must be only parameter", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } /* From page 28 (page 34 of the PDF) of the GLSL 1.10 spec: @@ -1366,7 +1398,7 @@ ast_function_expression::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "too few components to construct " "`%s'", constructor_type->name); - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } /* Later, we cast each parameter to the same base type as the @@ -1447,60 +1479,31 @@ ast_function_expression::hir(exec_list *instructions, } } else { const ast_expression *id = subexpressions[0]; + const char *func_name = id->primary_expression.identifier; YYLTYPE loc = id->get_location(); exec_list actual_parameters; process_parameters(instructions, &actual_parameters, &this->expressions, state); - ir_call *call = NULL; - ir_rvalue *const value = - match_function_by_name(instructions, - id->primary_expression.identifier, - &loc, &actual_parameters, &call, state); - - if (call != NULL) { - /* If a function was found, make sure that none of the 'out' or 'inout' - * parameters violate the extra l-value rules. - */ - ir_function_signature *f = call->get_callee(); - assert(f != NULL); - - exec_node *formal_node = f->parameters.head; + ir_function_signature *sig = + match_function_by_name(func_name, &actual_parameters, state); - foreach_list (actual_node, &this->expressions) { - /* Both parameter lists had better be the same length! - */ - assert(!actual_node->is_tail_sentinel()); - - const ir_variable *const formal_parameter = - (ir_variable *) formal_node; - const ast_expression *const actual_parameter = - exec_node_data(ast_expression, actual_node, link); - - if ((formal_parameter->mode == ir_var_out - || formal_parameter->mode == ir_var_inout) - && actual_parameter->non_lvalue_description != NULL) { - YYLTYPE loc = actual_parameter->get_location(); - - _mesa_glsl_error(&loc, state, - "function parameter '%s %s' references a %s", - (formal_parameter->mode == ir_var_out) - ? "out" : "inout", - formal_parameter->name, - actual_parameter->non_lvalue_description); - return ir_call::get_error_instruction(ctx); - } - - /* Only advance the formal_node pointer here because the - * foreach_list business already advances actual_node. - */ - formal_node = formal_node->next; - } + ir_call *call = NULL; + ir_rvalue *value = NULL; + if (sig == NULL) { + no_matching_function_error(func_name, &loc, &actual_parameters, state); + value = ir_rvalue::error_value(ctx); + } else if (!verify_parameter_modes(state, sig, actual_parameters, this->expressions)) { + /* an error has already been emitted */ + value = ir_rvalue::error_value(ctx); + } else { + value = generate_call(instructions, sig, &loc, &actual_parameters, + &call, state); } return value; } - return ir_call::get_error_instruction(ctx); + return ir_rvalue::error_value(ctx); } diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index ff56e33b7..f4dfc4ce3 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1699,7 +1699,7 @@ ast_expression::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "`%s' undeclared", this->primary_expression.identifier); - result = ir_call::get_error_instruction(ctx); + result = ir_rvalue::error_value(ctx); error_emitted = true; } break; @@ -3904,8 +3904,8 @@ ast_type_specifier::hir(exec_list *instructions, "arrays"); return NULL; } - if (this->type_specifier != ast_float - && this->type_specifier != ast_int) { + if (strcmp(this->type_name, "float") != 0 && + strcmp(this->type_name, "int") != 0) { _mesa_glsl_error(&loc, state, "default precision statements apply only to types " "float and int"); diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp index 79c43eefb..6c44f8c41 100644 --- a/mesalib/src/glsl/ast_type.cpp +++ b/mesalib/src/glsl/ast_type.cpp @@ -29,7 +29,7 @@ extern "C" { void ast_type_specifier::print(void) const { - if (type_specifier == ast_struct) { + if (structure) { structure->print(); } else { printf("%s ", type_name); @@ -46,72 +46,6 @@ ast_type_specifier::print(void) const } } -ast_type_specifier::ast_type_specifier(int specifier) - : type_specifier(ast_types(specifier)), type_name(NULL), structure(NULL), - is_array(false), array_size(NULL), precision(ast_precision_none), - is_precision_statement(false) -{ - static const char *const 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", - "sampler2DRect", - "sampler3D", - "samplerCube", - "samplerExternalOES", - "sampler1DShadow", - "sampler2DShadow", - "sampler2DRectShadow", - "samplerCubeShadow", - "sampler1DArray", - "sampler2DArray", - "sampler1DArrayShadow", - "sampler2DArrayShadow", - "isampler1D", - "isampler2D", - "isampler3D", - "isamplerCube", - "isampler1DArray", - "isampler2DArray", - "usampler1D", - "usampler2D", - "usampler3D", - "usamplerCube", - "usampler1DArray", - "usampler2DArray", - - NULL, /* ast_struct */ - NULL /* ast_type_name */ - }; - - type_name = names[specifier]; -} - bool ast_fully_specified_type::has_qualifiers() const { diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index 64506b635..920213c30 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -58,7 +58,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) %union { int n; float real; - char *identifier; + const char *identifier; struct ast_type_qualifier type_qualifier; @@ -156,7 +156,7 @@ static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg) %type type_specifier %type type_specifier_no_prec %type type_specifier_nonarray -%type basic_type_specifier_nonarray +%type basic_type_specifier_nonarray %type fully_specified_type %type function_prototype %type function_header @@ -1365,58 +1365,59 @@ type_specifier_nonarray: ; basic_type_specifier_nonarray: - VOID_TOK { $$ = ast_void; } - | FLOAT_TOK { $$ = ast_float; } - | INT_TOK { $$ = ast_int; } - | UINT_TOK { $$ = ast_uint; } - | BOOL_TOK { $$ = ast_bool; } - | VEC2 { $$ = ast_vec2; } - | VEC3 { $$ = ast_vec3; } - | VEC4 { $$ = ast_vec4; } - | BVEC2 { $$ = ast_bvec2; } - | BVEC3 { $$ = ast_bvec3; } - | BVEC4 { $$ = ast_bvec4; } - | IVEC2 { $$ = ast_ivec2; } - | IVEC3 { $$ = ast_ivec3; } - | IVEC4 { $$ = ast_ivec4; } - | UVEC2 { $$ = ast_uvec2; } - | UVEC3 { $$ = ast_uvec3; } - | UVEC4 { $$ = ast_uvec4; } - | MAT2X2 { $$ = ast_mat2; } - | MAT2X3 { $$ = ast_mat2x3; } - | MAT2X4 { $$ = ast_mat2x4; } - | MAT3X2 { $$ = ast_mat3x2; } - | MAT3X3 { $$ = ast_mat3; } - | MAT3X4 { $$ = ast_mat3x4; } - | MAT4X2 { $$ = ast_mat4x2; } - | MAT4X3 { $$ = ast_mat4x3; } - | MAT4X4 { $$ = ast_mat4; } - | SAMPLER1D { $$ = ast_sampler1d; } - | SAMPLER2D { $$ = ast_sampler2d; } - | SAMPLER2DRECT { $$ = ast_sampler2drect; } - | SAMPLER3D { $$ = ast_sampler3d; } - | SAMPLERCUBE { $$ = ast_samplercube; } - | SAMPLEREXTERNALOES { $$ = ast_samplerexternaloes; } - | SAMPLER1DSHADOW { $$ = ast_sampler1dshadow; } - | SAMPLER2DSHADOW { $$ = ast_sampler2dshadow; } - | SAMPLER2DRECTSHADOW { $$ = ast_sampler2drectshadow; } - | SAMPLERCUBESHADOW { $$ = ast_samplercubeshadow; } - | SAMPLER1DARRAY { $$ = ast_sampler1darray; } - | SAMPLER2DARRAY { $$ = ast_sampler2darray; } - | SAMPLER1DARRAYSHADOW { $$ = ast_sampler1darrayshadow; } - | SAMPLER2DARRAYSHADOW { $$ = ast_sampler2darrayshadow; } - | ISAMPLER1D { $$ = ast_isampler1d; } - | ISAMPLER2D { $$ = ast_isampler2d; } - | ISAMPLER3D { $$ = ast_isampler3d; } - | ISAMPLERCUBE { $$ = ast_isamplercube; } - | ISAMPLER1DARRAY { $$ = ast_isampler1darray; } - | ISAMPLER2DARRAY { $$ = ast_isampler2darray; } - | USAMPLER1D { $$ = ast_usampler1d; } - | USAMPLER2D { $$ = ast_usampler2d; } - | USAMPLER3D { $$ = ast_usampler3d; } - | USAMPLERCUBE { $$ = ast_usamplercube; } - | USAMPLER1DARRAY { $$ = ast_usampler1darray; } - | USAMPLER2DARRAY { $$ = ast_usampler2darray; } + VOID_TOK { $$ = "void"; } + | FLOAT_TOK { $$ = "float"; } + | INT_TOK { $$ = "int"; } + | UINT_TOK { $$ = "uint"; } + | BOOL_TOK { $$ = "bool"; } + | VEC2 { $$ = "vec2"; } + | VEC3 { $$ = "vec3"; } + | VEC4 { $$ = "vec4"; } + | BVEC2 { $$ = "bvec2"; } + | BVEC3 { $$ = "bvec3"; } + | BVEC4 { $$ = "bvec4"; } + | IVEC2 { $$ = "ivec2"; } + | IVEC3 { $$ = "ivec3"; } + | IVEC4 { $$ = "ivec4"; } + | UVEC2 { $$ = "uvec2"; } + | UVEC3 { $$ = "uvec3"; } + | UVEC4 { $$ = "uvec4"; } + | MAT2X2 { $$ = "mat2"; } + | MAT2X3 { $$ = "mat2x3"; } + | MAT2X4 { $$ = "mat2x4"; } + | MAT3X2 { $$ = "mat3x2"; } + | MAT3X3 { $$ = "mat3"; } + | MAT3X4 { $$ = "mat3x4"; } + | MAT4X2 { $$ = "mat4x2"; } + | MAT4X3 { $$ = "mat4x3"; } + | MAT4X4 { $$ = "mat4"; } + | SAMPLER1D { $$ = "sampler1D"; } + | SAMPLER2D { $$ = "sampler2D"; } + | SAMPLER2DRECT { $$ = "sampler2DRect"; } + | SAMPLER3D { $$ = "sampler3D"; } + | SAMPLERCUBE { $$ = "samplerCube"; } + | SAMPLEREXTERNALOES { $$ = "samplerExternalOES"; } + | SAMPLER1DSHADOW { $$ = "sampler1DShadow"; } + | SAMPLER2DSHADOW { $$ = "sampler2DShadow"; } + | SAMPLER2DRECTSHADOW { $$ = "sampler2DRectShadow"; } + | SAMPLERCUBESHADOW { $$ = "samplerCubeShadow"; } + | SAMPLER1DARRAY { $$ = "sampler1DArray"; } + | SAMPLER2DARRAY { $$ = "sampler2DArray"; } + | SAMPLER1DARRAYSHADOW { $$ = "sampler1DArrayShadow"; } + | SAMPLER2DARRAYSHADOW { $$ = "sampler2DArrayShadow"; } + | SAMPLERBUFFER { $$ = "samplerBuffer"; } + | ISAMPLER1D { $$ = "isampler1D"; } + | ISAMPLER2D { $$ = "isampler2D"; } + | ISAMPLER3D { $$ = "isampler3D"; } + | ISAMPLERCUBE { $$ = "isamplerCube"; } + | ISAMPLER1DARRAY { $$ = "isampler1DArray"; } + | ISAMPLER2DARRAY { $$ = "isampler2DArray"; } + | USAMPLER1D { $$ = "usampler1D"; } + | USAMPLER2D { $$ = "usampler2D"; } + | USAMPLER3D { $$ = "usampler3D"; } + | USAMPLERCUBE { $$ = "usamplerCube"; } + | USAMPLER1DARRAY { $$ = "usampler1DArray"; } + | USAMPLER2DARRAY { $$ = "usampler2DArray"; } ; precision_qualifier: diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index 21c3c6ec2..6547ad2d3 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -713,7 +713,7 @@ ast_declaration::print(void) const } -ast_declaration::ast_declaration(char *identifier, int is_array, +ast_declaration::ast_declaration(const char *identifier, int is_array, ast_expression *array_size, ast_expression *initializer) { @@ -979,7 +979,7 @@ ast_struct_specifier::print(void) const } -ast_struct_specifier::ast_struct_specifier(char *identifier, +ast_struct_specifier::ast_struct_specifier(const char *identifier, ast_node *declarator_list) { if (identifier == NULL) { diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 069ebd10d..8a34b8eb0 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -146,7 +146,6 @@ glsl_type::sampler_index() const case GLSL_SAMPLER_DIM_RECT: return TEXTURE_RECT_INDEX; case GLSL_SAMPLER_DIM_BUF: - assert(!"FINISHME: Implement ARB_texture_buffer_object"); return TEXTURE_BUFFER_INDEX; case GLSL_SAMPLER_DIM_EXTERNAL: return TEXTURE_EXTERNAL_INDEX; @@ -213,6 +212,10 @@ glsl_type::generate_140_types(glsl_symbol_table *symtab) add_types_to_symbol_table(symtab, builtin_140_types, Elements(builtin_140_types), false); + + add_types_to_symbol_table(symtab, builtin_EXT_texture_buffer_object_types, + Elements(builtin_EXT_texture_buffer_object_types), + false); } diff --git a/mesalib/src/glsl/hir_field_selection.cpp b/mesalib/src/glsl/hir_field_selection.cpp index 3c33127b5..260b415a8 100644 --- a/mesalib/src/glsl/hir_field_selection.cpp +++ b/mesalib/src/glsl/hir_field_selection.cpp @@ -98,5 +98,5 @@ _mesa_ast_field_selection_to_hir(const ast_expression *expr, expr->primary_expression.identifier); } - return result ? result : ir_call::get_error_instruction(ctx); + return result ? result : ir_rvalue::error_value(ctx); } diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 3c9d6e174..1ba87515e 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1458,22 +1458,15 @@ ir_function::has_user_signature() } -ir_call * -ir_call::get_error_instruction(void *ctx) +ir_rvalue * +ir_rvalue::error_value(void *mem_ctx) { - ir_call *call = new(ctx) ir_call; + ir_rvalue *v = new(mem_ctx) ir_rvalue; - call->type = glsl_type::error_type; - return call; + v->type = glsl_type::error_type; + return v; } -void -ir_call::set_callee(ir_function_signature *sig) -{ - assert((this->type == NULL) || (this->type == sig->return_type)); - - this->callee = sig; -} void visit_exec_list(exec_list *list, ir_visitor *visitor) diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 1faae3c72..b1ae6db74 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -88,7 +88,6 @@ enum ir_node_type { class ir_instruction : public exec_node { public: enum ir_node_type ir_type; - const struct glsl_type *type; /** ir_print_visitor helper for debugging. */ void print(void) const; @@ -127,16 +126,27 @@ protected: ir_instruction() { ir_type = ir_type_unset; - type = NULL; } }; +/** + * The base class for all "values"/expression trees. + */ class ir_rvalue : public ir_instruction { public: - virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const = 0; + const struct glsl_type *type; + + virtual ir_rvalue *clone(void *mem_ctx, struct hash_table *) const; + + virtual void accept(ir_visitor *v) + { + v->visit(this); + } - virtual ir_constant *constant_expression_value() = 0; + virtual ir_visitor_status accept(ir_hierarchical_visitor *); + + virtual ir_constant *constant_expression_value(); virtual ir_rvalue * as_rvalue() { @@ -209,6 +219,14 @@ public: */ virtual bool is_negative_one() const; + + /** + * Return a generic value of error_type. + * + * Allocation will be performed with 'mem_ctx' as ralloc owner. + */ + static ir_rvalue *error_value(void *mem_ctx); + protected: ir_rvalue(); }; @@ -302,6 +320,11 @@ public: */ glsl_interp_qualifier determine_interpolation_mode(bool flat_shade); + /** + * Declared type of the variable + */ + const struct glsl_type *type; + /** * Delcared name of the variable */ @@ -459,6 +482,12 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); + /** + * Attempt to evaluate this function as a constant expression, given + * a list of the actual parameters. Returns NULL for non-built-ins. + */ + ir_constant *constant_expression_value(exec_list *actual_parameters); + /** * Get the name of the function for which this is a signature */ @@ -999,16 +1028,18 @@ public: /** - * IR instruction representing a function call + * HIR instruction representing a high-level function call, containing a list + * of parameters and returning a value in the supplied temporary. */ -class ir_call : public ir_rvalue { +class ir_call : public ir_instruction { public: - ir_call(ir_function_signature *callee, exec_list *actual_parameters) - : callee(callee) + ir_call(ir_function_signature *callee, + ir_dereference_variable *return_deref, + exec_list *actual_parameters) + : return_deref(return_deref), callee(callee) { ir_type = ir_type_call; assert(callee->return_type != NULL); - type = callee->return_type; actual_parameters->move_nodes_to(& this->actual_parameters); this->use_builtin = callee->is_builtin; } @@ -1029,13 +1060,6 @@ public: virtual ir_visitor_status accept(ir_hierarchical_visitor *); - /** - * Get a generic ir_call object when an error occurs - * - * Any allocation will be performed with 'ctx' as ralloc owner. - */ - static ir_call *get_error_instruction(void *ctx); - /** * Get an iterator for the set of acutal parameters */ @@ -1053,38 +1077,27 @@ public: } /** - * Get the function signature bound to this function call + * Generates an inline version of the function before @ir, + * storing the return value in return_deref. */ - ir_function_signature *get_callee() - { - return callee; - } + void generate_inline(ir_instruction *ir); /** - * Set the function call target + * Storage for the function's return value. + * This must be NULL if the return type is void. */ - void set_callee(ir_function_signature *sig); + ir_dereference_variable *return_deref; /** - * Generates an inline version of the function before @ir, - * returning the return value of the function. + * The specific function signature being called. */ - ir_rvalue *generate_inline(ir_instruction *ir); + ir_function_signature *callee; /* List of ir_rvalue of paramaters passed in this call. */ exec_list actual_parameters; /** Should this call only bind to a built-in function? */ bool use_builtin; - -private: - ir_call() - : callee(NULL) - { - this->ir_type = ir_type_call; - } - - ir_function_signature *callee; }; diff --git a/mesalib/src/glsl/ir_basic_block.cpp b/mesalib/src/glsl/ir_basic_block.cpp index a83382596..86e0cf795 100644 --- a/mesalib/src/glsl/ir_basic_block.cpp +++ b/mesalib/src/glsl/ir_basic_block.cpp @@ -32,31 +32,6 @@ #include "ir_basic_block.h" #include "glsl_types.h" -class ir_has_call_visitor : public ir_hierarchical_visitor { -public: - ir_has_call_visitor() - { - has_call = false; - } - - virtual ir_visitor_status visit_enter(ir_call *ir) - { - (void) ir; - has_call = true; - return visit_stop; - } - - bool has_call; -}; - -bool -ir_has_call(ir_instruction *ir) -{ - ir_has_call_visitor v; - ir->accept(&v); - return v.has_call; -} - /** * Calls a user function for every basic block in the instruction stream. * @@ -122,24 +97,6 @@ void call_for_basic_blocks(exec_list *instructions, call_for_basic_blocks(&ir_sig->body, callback, data); } - } else if (ir->as_assignment()) { - /* If there's a call in the expression tree being assigned, - * then that ends the BB too. - * - * The assumption is that any consumer of the basic block - * walker is fine with the fact that the call is somewhere in - * the tree even if portions of the tree may be evaluated - * after the call. - * - * A consumer that has an issue with this could not process - * the last instruction of the basic block. If doing so, - * expression flattener may be useful before using the basic - * block finder to get more maximal basic blocks out. - */ - if (ir_has_call(ir)) { - callback(leader, ir, data); - leader = NULL; - } } last = ir; } diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp index c63615c7e..26b0d8f5f 100644 --- a/mesalib/src/glsl/ir_clone.cpp +++ b/mesalib/src/glsl/ir_clone.cpp @@ -27,6 +27,13 @@ #include "glsl_types.h" #include "program/hash_table.h" +ir_rvalue * +ir_rvalue::clone(void *mem_ctx, struct hash_table *ht) const +{ + /* The only possible instantiation is the generic error value. */ + return error_value(mem_ctx); +} + /** * Duplicate an IR variable * @@ -160,8 +167,9 @@ ir_loop::clone(void *mem_ctx, struct hash_table *ht) const ir_call * ir_call::clone(void *mem_ctx, struct hash_table *ht) const { - if (this->type == glsl_type::error_type) - return ir_call::get_error_instruction(mem_ctx); + ir_dereference_variable *new_return_ref = NULL; + if (this->return_deref != NULL) + new_return_ref = this->return_deref->clone(mem_ctx, ht); exec_list new_parameters; @@ -170,7 +178,7 @@ ir_call::clone(void *mem_ctx, struct hash_table *ht) const new_parameters.push_tail(ir->clone(mem_ctx, ht)); } - return new(mem_ctx) ir_call(this->callee, &new_parameters); + return new(mem_ctx) ir_call(this->callee, new_return_ref, &new_parameters); } ir_expression * @@ -390,9 +398,9 @@ public: * table. If it is found, replace it with the value from the table. */ ir_function_signature *sig = - (ir_function_signature *) hash_table_find(this->ht, ir->get_callee()); + (ir_function_signature *) hash_table_find(this->ht, ir->callee); if (sig != NULL) - ir->set_callee(sig); + ir->callee = sig; /* Since this may be used before function call parameters are flattened, * the children also need to be processed. diff --git a/mesalib/src/glsl/ir_constant_expression.cpp b/mesalib/src/glsl/ir_constant_expression.cpp index adca62e8d..4e1714a84 100644 --- a/mesalib/src/glsl/ir_constant_expression.cpp +++ b/mesalib/src/glsl/ir_constant_expression.cpp @@ -70,6 +70,13 @@ dot(ir_constant *op0, ir_constant *op1) return result; } +ir_constant * +ir_rvalue::constant_expression_value() +{ + assert(this->type->is_error()); + return NULL; +} + ir_constant * ir_expression::constant_expression_value() { @@ -1017,21 +1024,29 @@ ir_constant::constant_expression_value() ir_constant * ir_call::constant_expression_value() { - if (this->type == glsl_type::error_type) + return this->callee->constant_expression_value(&this->actual_parameters); +} + + +ir_constant * +ir_function_signature::constant_expression_value(exec_list *actual_parameters) +{ + const glsl_type *type = this->return_type; + if (type == glsl_type::void_type) return NULL; /* From the GLSL 1.20 spec, page 23: * "Function calls to user-defined functions (non-built-in functions) * cannot be used to form constant expressions." */ - if (!this->callee->is_builtin) + if (!this->is_builtin) return NULL; unsigned num_parameters = 0; /* Check if all parameters are constant */ ir_constant *op[3]; - foreach_list(n, &this->actual_parameters) { + foreach_list(n, actual_parameters) { ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value(); if (constant == NULL) return NULL; @@ -1053,7 +1068,7 @@ ir_call::constant_expression_value() ir_constant_data data; memset(&data, 0, sizeof(data)); - const char *callee = this->callee_name(); + const char *callee = this->function_name(); if (strcmp(callee, "abs") == 0) { expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL); } else if (strcmp(callee, "all") == 0) { @@ -1101,7 +1116,7 @@ ir_call::constant_expression_value() for (unsigned c = 0; c < op[0]->type->components(); c++) data.f[c] = atanhf(op[0]->value.f[c]); } else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) { - return ir_constant::zero(mem_ctx, this->type); + return ir_constant::zero(mem_ctx, type); } else if (strcmp(callee, "ceil") == 0) { expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL); } else if (strcmp(callee, "clamp") == 0) { @@ -1192,7 +1207,7 @@ ir_call::constant_expression_value() } else if (strcmp(callee, "fract") == 0) { expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL); } else if (strcmp(callee, "fwidth") == 0) { - return ir_constant::zero(mem_ctx, this->type); + return ir_constant::zero(mem_ctx, type); } else if (strcmp(callee, "greaterThan") == 0) { assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector()); for (unsigned c = 0; c < op[0]->type->components(); c++) { @@ -1298,7 +1313,7 @@ ir_call::constant_expression_value() float length = sqrtf(dot(op[0], op[0])); if (length == 0) - return ir_constant::zero(mem_ctx, this->type); + return ir_constant::zero(mem_ctx, type); for (unsigned c = 0; c < op[0]->type->components(); c++) data.f[c] = op[0]->value.f[c] / length; @@ -1349,7 +1364,7 @@ ir_call::constant_expression_value() const float dot_NI = dot(op[1], op[0]); const float k = 1.0F - eta * eta * (1.0F - dot_NI * dot_NI); if (k < 0.0) { - return ir_constant::zero(mem_ctx, this->type); + return ir_constant::zero(mem_ctx, type); } else { for (unsigned c = 0; c < type->components(); c++) { data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k)) @@ -1418,5 +1433,5 @@ ir_call::constant_expression_value() if (expr != NULL) return expr->constant_expression_value(); - return new(mem_ctx) ir_constant(this->type, &data); + return new(mem_ctx) ir_constant(type, &data); } diff --git a/mesalib/src/glsl/ir_expression_flattening.cpp b/mesalib/src/glsl/ir_expression_flattening.cpp index bd4ac67bc..b44e68ca3 100644 --- a/mesalib/src/glsl/ir_expression_flattening.cpp +++ b/mesalib/src/glsl/ir_expression_flattening.cpp @@ -29,11 +29,6 @@ * * This is used for breaking down matrix operations, where it's easier to * create a temporary and work on each of its vector components individually. - * - * It is also used for automatic function inlining, where we want to take - * an expression containing a call and move the call out to its own - * assignment so that we can inline it at the appropriate place in the - * instruction stream. */ #include "ir.h" diff --git a/mesalib/src/glsl/ir_function.cpp b/mesalib/src/glsl/ir_function.cpp index b34a50081..a525693ed 100644 --- a/mesalib/src/glsl/ir_function.cpp +++ b/mesalib/src/glsl/ir_function.cpp @@ -59,7 +59,7 @@ parameter_lists_match(const exec_list *list_a, const exec_list *list_b) const ir_variable *const param = (ir_variable *) node_a; - const ir_instruction *const actual = (ir_instruction *) node_b; + const ir_rvalue *const actual = (ir_rvalue *) node_b; if (param->type == actual->type) continue; diff --git a/mesalib/src/glsl/ir_function_can_inline.cpp b/mesalib/src/glsl/ir_function_can_inline.cpp index 2ed3aaa49..7b15d5df1 100644 --- a/mesalib/src/glsl/ir_function_can_inline.cpp +++ b/mesalib/src/glsl/ir_function_can_inline.cpp @@ -1,76 +1,76 @@ -/* - * Copyright © 2010 Intel Corporation - * - * 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 (including the next - * paragraph) 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 - * THE AUTHORS OR COPYRIGHT HOLDERS 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 ir_function_can_inline.cpp - * - * Determines if we can inline a function call using ir_function_inlining.cpp. - * - * The primary restriction is that we can't return from the function - * other than as the last instruction. We could potentially work - * around this for some constructs by flattening control flow and - * moving the return to the end, or by using breaks from a do {} while - * (0) loop surrounding the function body. - */ - -#include "ir.h" - -class ir_function_can_inline_visitor : public ir_hierarchical_visitor { -public: - ir_function_can_inline_visitor() - { - this->num_returns = 0; - } - - virtual ir_visitor_status visit_enter(ir_return *); - - int num_returns; -}; - -ir_visitor_status -ir_function_can_inline_visitor::visit_enter(ir_return *ir) -{ - (void) ir; - this->num_returns++; - return visit_continue; -} - -bool -can_inline(ir_call *call) -{ - ir_function_can_inline_visitor v; - const ir_function_signature *callee = call->get_callee(); - if (!callee->is_defined) - return false; - - v.run((exec_list *) &callee->body); - - /* If the function is empty (no last instruction) or does not end with a - * return statement, we need to count the implicit return. - */ - ir_instruction *last = (ir_instruction *)callee->body.get_tail(); - if (last == NULL || !last->as_return()) - v.num_returns++; - - return v.num_returns == 1; -} +/* + * Copyright © 2010 Intel Corporation + * + * 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 (including the next + * paragraph) 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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 ir_function_can_inline.cpp + * + * Determines if we can inline a function call using ir_function_inlining.cpp. + * + * The primary restriction is that we can't return from the function + * other than as the last instruction. We could potentially work + * around this for some constructs by flattening control flow and + * moving the return to the end, or by using breaks from a do {} while + * (0) loop surrounding the function body. + */ + +#include "ir.h" + +class ir_function_can_inline_visitor : public ir_hierarchical_visitor { +public: + ir_function_can_inline_visitor() + { + this->num_returns = 0; + } + + virtual ir_visitor_status visit_enter(ir_return *); + + int num_returns; +}; + +ir_visitor_status +ir_function_can_inline_visitor::visit_enter(ir_return *ir) +{ + (void) ir; + this->num_returns++; + return visit_continue; +} + +bool +can_inline(ir_call *call) +{ + ir_function_can_inline_visitor v; + const ir_function_signature *callee = call->callee; + if (!callee->is_defined) + return false; + + v.run((exec_list *) &callee->body); + + /* If the function is empty (no last instruction) or does not end with a + * return statement, we need to count the implicit return. + */ + ir_instruction *last = (ir_instruction *)callee->body.get_tail(); + if (last == NULL || !last->as_return()) + v.num_returns++; + + return v.num_returns == 1; +} diff --git a/mesalib/src/glsl/ir_function_detect_recursion.cpp b/mesalib/src/glsl/ir_function_detect_recursion.cpp index 890bc455f..0a5e647cd 100644 --- a/mesalib/src/glsl/ir_function_detect_recursion.cpp +++ b/mesalib/src/glsl/ir_function_detect_recursion.cpp @@ -217,7 +217,7 @@ public: if (this->current == NULL) return visit_continue; - function *const target = this->get_function(call->get_callee()); + function *const target = this->get_function(call->callee); /* Create a link from the caller to the callee. */ diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.cpp b/mesalib/src/glsl/ir_hierarchical_visitor.cpp index b5eacd6d2..f24414046 100644 --- a/mesalib/src/glsl/ir_hierarchical_visitor.cpp +++ b/mesalib/src/glsl/ir_hierarchical_visitor.cpp @@ -32,6 +32,15 @@ ir_hierarchical_visitor::ir_hierarchical_visitor() this->in_assignee = false; } +ir_visitor_status +ir_hierarchical_visitor::visit(ir_rvalue *ir) +{ + if (this->callback != NULL) + this->callback(ir, this->data); + + return visit_continue; +} + ir_visitor_status ir_hierarchical_visitor::visit(ir_variable *ir) { diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.h b/mesalib/src/glsl/ir_hierarchical_visitor.h index bba046db4..143eb7c88 100644 --- a/mesalib/src/glsl/ir_hierarchical_visitor.h +++ b/mesalib/src/glsl/ir_hierarchical_visitor.h @@ -82,6 +82,7 @@ public: * \name Visit methods for leaf-node classes */ /*@{*/ + virtual ir_visitor_status visit(class ir_rvalue *); virtual ir_visitor_status visit(class ir_variable *); virtual ir_visitor_status visit(class ir_constant *); virtual ir_visitor_status visit(class ir_loop_jump *); diff --git a/mesalib/src/glsl/ir_hv_accept.cpp b/mesalib/src/glsl/ir_hv_accept.cpp index 0e78fda81..3ce895924 100644 --- a/mesalib/src/glsl/ir_hv_accept.cpp +++ b/mesalib/src/glsl/ir_hv_accept.cpp @@ -65,6 +65,13 @@ visit_list_elements(ir_hierarchical_visitor *v, exec_list *l, } +ir_visitor_status +ir_rvalue::accept(ir_hierarchical_visitor *v) +{ + return v->visit(this); +} + + ir_visitor_status ir_variable::accept(ir_hierarchical_visitor *v) { @@ -326,6 +333,14 @@ ir_call::accept(ir_hierarchical_visitor *v) if (s != visit_continue) return (s == visit_continue_with_parent) ? visit_continue : s; + if (this->return_deref != NULL) { + v->in_assignee = true; + s = this->return_deref->accept(v); + v->in_assignee = false; + if (s != visit_continue) + return (s == visit_continue_with_parent) ? visit_continue : s; + } + s = visit_list_elements(v, &this->actual_parameters, false); if (s == visit_stop) return s; diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp index 1471355f3..8aa26e5d0 100644 --- a/mesalib/src/glsl/ir_print_visitor.cpp +++ b/mesalib/src/glsl/ir_print_visitor.cpp @@ -135,6 +135,10 @@ print_type(const glsl_type *t) } } +void ir_print_visitor::visit(ir_rvalue *ir) +{ + printf("error"); +} void ir_print_visitor::visit(ir_variable *ir) { @@ -404,7 +408,10 @@ void ir_print_visitor::visit(ir_constant *ir) void ir_print_visitor::visit(ir_call *ir) { - printf("(call %s (", ir->callee_name()); + printf("(call %s ", ir->callee_name()); + if (ir->return_deref) + ir->return_deref->accept(this); + printf(" ("); foreach_iter(exec_list_iterator, iter, *ir) { ir_instruction *const inst = (ir_instruction *) iter.get(); diff --git a/mesalib/src/glsl/ir_print_visitor.h b/mesalib/src/glsl/ir_print_visitor.h index c7136f11a..6c308f31e 100644 --- a/mesalib/src/glsl/ir_print_visitor.h +++ b/mesalib/src/glsl/ir_print_visitor.h @@ -54,6 +54,7 @@ public: * the hierarchy should not have \c visit methods. */ /*@{*/ + virtual void visit(ir_rvalue *); virtual void visit(ir_variable *); virtual void visit(ir_function_signature *); virtual void visit(ir_function *); diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp index 6f50cc439..7ce683ef7 100644 --- a/mesalib/src/glsl/ir_reader.cpp +++ b/mesalib/src/glsl/ir_reader.cpp @@ -51,16 +51,17 @@ private: ir_variable *read_declaration(s_expression *); ir_if *read_if(s_expression *, ir_loop *); ir_loop *read_loop(s_expression *); + ir_call *read_call(s_expression *); ir_return *read_return(s_expression *); ir_rvalue *read_rvalue(s_expression *); ir_assignment *read_assignment(s_expression *); ir_expression *read_expression(s_expression *); - ir_call *read_call(s_expression *); ir_swizzle *read_swizzle(s_expression *); ir_constant *read_constant(s_expression *); ir_texture *read_texture(s_expression *); ir_dereference *read_dereference(s_expression *); + ir_dereference_variable *read_var_ref(s_expression *); }; ir_reader::ir_reader(_mesa_glsl_parse_state *state) : state(state) @@ -348,6 +349,8 @@ ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx) inst = read_if(list, loop_ctx); } else if (strcmp(tag->value(), "loop") == 0) { inst = read_loop(list); + } else if (strcmp(tag->value(), "call") == 0) { + inst = read_call(list); } else if (strcmp(tag->value(), "return") == 0) { inst = read_return(list); } else if (strcmp(tag->value(), "function") == 0) { @@ -521,8 +524,6 @@ ir_reader::read_rvalue(s_expression *expr) rvalue = read_swizzle(list); } else if (strcmp(tag->value(), "expression") == 0) { rvalue = read_expression(list); - } else if (strcmp(tag->value(), "call") == 0) { - rvalue = read_call(list); } else if (strcmp(tag->value(), "constant") == 0) { rvalue = read_constant(list); } else { @@ -610,10 +611,20 @@ ir_reader::read_call(s_expression *expr) { s_symbol *name; s_list *params; + s_list *s_return = NULL; - s_pattern pat[] = { "call", name, params }; - if (!MATCH(expr, pat)) { - ir_read_error(expr, "expected (call ( ...))"); + ir_dereference_variable *return_deref = NULL; + + s_pattern void_pat[] = { "call", name, params }; + s_pattern non_void_pat[] = { "call", name, s_return, params }; + if (MATCH(expr, non_void_pat)) { + return_deref = read_var_ref(s_return); + if (return_deref == NULL) { + ir_read_error(s_return, "when reading a call's return storage"); + return NULL; + } + } else if (!MATCH(expr, void_pat)) { + ir_read_error(expr, "expected (call [] ( ...))"); return NULL; } @@ -643,7 +654,15 @@ ir_reader::read_call(s_expression *expr) return NULL; } - return new(mem_ctx) ir_call(callee, ¶meters); + if (callee->return_type == glsl_type::void_type && return_deref) { + ir_read_error(expr, "call has return value storage but void type"); + return NULL; + } else if (callee->return_type != glsl_type::void_type && !return_deref) { + ir_read_error(expr, "call has non-void type but no return value storage"); + return NULL; + } + + return new(mem_ctx) ir_call(callee, return_deref, ¶meters); } ir_expression * @@ -828,17 +847,11 @@ ir_reader::read_constant(s_expression *expr) return new(mem_ctx) ir_constant(type, &data); } -ir_dereference * -ir_reader::read_dereference(s_expression *expr) +ir_dereference_variable * +ir_reader::read_var_ref(s_expression *expr) { s_symbol *s_var; - s_expression *s_subject; - s_expression *s_index; - s_symbol *s_field; - s_pattern var_pat[] = { "var_ref", s_var }; - s_pattern array_pat[] = { "array_ref", s_subject, s_index }; - s_pattern record_pat[] = { "record_ref", s_subject, s_field }; if (MATCH(expr, var_pat)) { ir_variable *var = state->symbols->get_variable(s_var->value()); @@ -847,6 +860,23 @@ ir_reader::read_dereference(s_expression *expr) return NULL; } return new(mem_ctx) ir_dereference_variable(var); + } + return NULL; +} + +ir_dereference * +ir_reader::read_dereference(s_expression *expr) +{ + s_expression *s_subject; + s_expression *s_index; + s_symbol *s_field; + + s_pattern array_pat[] = { "array_ref", s_subject, s_index }; + s_pattern record_pat[] = { "record_ref", s_subject, s_field }; + + ir_dereference_variable *var_ref = read_var_ref(expr); + if (var_ref != NULL) { + return var_ref; } else if (MATCH(expr, array_pat)) { ir_rvalue *subject = read_rvalue(s_subject); if (subject == NULL) { diff --git a/mesalib/src/glsl/ir_validate.cpp b/mesalib/src/glsl/ir_validate.cpp index 101d9992d..7efb43477 100644 --- a/mesalib/src/glsl/ir_validate.cpp +++ b/mesalib/src/glsl/ir_validate.cpp @@ -541,13 +541,24 @@ ir_validate::visit_enter(ir_assignment *ir) ir_visitor_status ir_validate::visit_enter(ir_call *ir) { - ir_function_signature *const callee = ir->get_callee(); + ir_function_signature *const callee = ir->callee; if (callee->ir_type != ir_type_function_signature) { printf("IR called by ir_call is not ir_function_signature!\n"); abort(); } + if (ir->return_deref) { + if (ir->return_deref->type != callee->return_type) { + printf("callee type %s does not match return storage type %s\n", + callee->return_type->name, ir->return_deref->type->name); + abort(); + } + } else if (callee->return_type != glsl_type::void_type) { + printf("ir_call has non-void callee but no return storage\n"); + abort(); + } + const exec_node *formal_param_node = callee->parameters.head; const exec_node *actual_param_node = ir->actual_parameters.head; while (true) { @@ -611,7 +622,9 @@ check_node_type(ir_instruction *ir, void *data) printf("Instruction node with unset type\n"); ir->print(); printf("\n"); } - assert(ir->type != glsl_type::error_type); + ir_rvalue *value = ir->as_rvalue(); + if (value != NULL) + assert(value->type != glsl_type::error_type); } void diff --git a/mesalib/src/glsl/ir_visitor.h b/mesalib/src/glsl/ir_visitor.h index 7dd35fe1d..4a00155be 100644 --- a/mesalib/src/glsl/ir_visitor.h +++ b/mesalib/src/glsl/ir_visitor.h @@ -44,6 +44,7 @@ public: * the hierarchy should not have \c visit methods. */ /*@{*/ + virtual void visit(class ir_rvalue *) { assert(!"unhandled error_type"); } virtual void visit(class ir_variable *) = 0; virtual void visit(class ir_function_signature *) = 0; virtual void visit(class ir_function *) = 0; diff --git a/mesalib/src/glsl/link_functions.cpp b/mesalib/src/glsl/link_functions.cpp index acee32712..6b3e15448 100644 --- a/mesalib/src/glsl/link_functions.cpp +++ b/mesalib/src/glsl/link_functions.cpp @@ -68,7 +68,7 @@ public: * Doing so will modify the original shader. This may prevent that * shader from being linkable in other programs. */ - const ir_function_signature *const callee = ir->get_callee(); + const ir_function_signature *const callee = ir->callee; assert(callee != NULL); const char *const name = callee->function_name(); @@ -79,7 +79,7 @@ public: find_matching_signature(name, &callee->parameters, &linked, 1, ir->use_builtin); if (sig != NULL) { - ir->set_callee(sig); + ir->callee = sig; return visit_continue; } @@ -168,7 +168,7 @@ public: */ linked_sig->accept(this); - ir->set_callee(linked_sig); + ir->callee = linked_sig; return visit_continue; } diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp index 613c9b7ae..2f1c9f5f7 100644 --- a/mesalib/src/glsl/link_uniforms.cpp +++ b/mesalib/src/glsl/link_uniforms.cpp @@ -173,8 +173,7 @@ private: if (this->map->get(id, name)) return; - char *key = strdup(name); - this->map->put(this->num_active_uniforms, key); + this->map->put(this->num_active_uniforms, name); /* Each leaf uniform occupies one entry in the list of active * uniforms. diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 09ffdff63..49b6b8f4a 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -101,7 +101,7 @@ public: virtual ir_visitor_status visit_enter(ir_call *ir) { - exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + exec_list_iterator sig_iter = ir->callee->parameters.iterator(); foreach_iter(exec_list_iterator, iter, *ir) { ir_rvalue *param_rval = (ir_rvalue *)iter.get(); ir_variable *sig_param = (ir_variable *)sig_iter.get(); @@ -117,6 +117,15 @@ public: sig_iter.next(); } + if (ir->return_deref != NULL) { + ir_variable *const var = ir->return_deref->variable_referenced(); + + if (strcmp(name, var->name) == 0) { + found = true; + return visit_stop; + } + } + return visit_continue_with_parent; } @@ -830,6 +839,7 @@ move_non_declarations(exec_list *instructions, exec_node *last, continue; assert(inst->as_assignment() + || inst->as_call() || ((var != NULL) && (var->mode == ir_var_temporary))); if (make_copies) { diff --git a/mesalib/src/glsl/loop_analysis.cpp b/mesalib/src/glsl/loop_analysis.cpp index 9bba6a97c..6a0e4da51 100644 --- a/mesalib/src/glsl/loop_analysis.cpp +++ b/mesalib/src/glsl/loop_analysis.cpp @@ -110,6 +110,8 @@ public: virtual ir_visitor_status visit(ir_loop_jump *); virtual ir_visitor_status visit(ir_dereference_variable *); + virtual ir_visitor_status visit_enter(ir_call *); + virtual ir_visitor_status visit_enter(ir_loop *); virtual ir_visitor_status visit_leave(ir_loop *); virtual ir_visitor_status visit_enter(ir_assignment *); @@ -152,6 +154,21 @@ loop_analysis::visit(ir_loop_jump *ir) } +ir_visitor_status +loop_analysis::visit_enter(ir_call *ir) +{ + /* If we're not somewhere inside a loop, there's nothing to do. */ + if (this->state.is_empty()) + return visit_continue; + + loop_variable_state *const ls = + (loop_variable_state *) this->state.get_head(); + + ls->contains_calls = true; + return visit_continue_with_parent; +} + + ir_visitor_status loop_analysis::visit(ir_dereference_variable *ir) { @@ -209,6 +226,17 @@ loop_analysis::visit_leave(ir_loop *ir) loop_variable_state *const ls = (loop_variable_state *) this->state.pop_head(); + /* Function calls may contain side effects. These could alter any of our + * variables in ways that cannot be known, and may even terminate shader + * execution (say, calling discard in the fragment shader). So we can't + * rely on any of our analysis about assignments to variables. + * + * We could perform some conservative analysis (prove there's no statically + * possible assignment, etc.) but it isn't worth it for now; function + * inlining will allow us to unroll loops anyway. + */ + if (ls->contains_calls) + return visit_continue; foreach_list(node, &ir->body_instructions) { /* Skip over declarations at the start of a loop. diff --git a/mesalib/src/glsl/loop_analysis.h b/mesalib/src/glsl/loop_analysis.h index 229730836..8bed1db02 100644 --- a/mesalib/src/glsl/loop_analysis.h +++ b/mesalib/src/glsl/loop_analysis.h @@ -122,10 +122,16 @@ public: */ unsigned num_loop_jumps; + /** + * Whether this loop contains any function calls. + */ + bool contains_calls; + loop_variable_state() { this->max_iterations = -1; this->num_loop_jumps = 0; + this->contains_calls = false; this->var_hash = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare); } diff --git a/mesalib/src/glsl/lower_clip_distance.cpp b/mesalib/src/glsl/lower_clip_distance.cpp index 143e378f9..031691471 100644 --- a/mesalib/src/glsl/lower_clip_distance.cpp +++ b/mesalib/src/glsl/lower_clip_distance.cpp @@ -276,7 +276,7 @@ lower_clip_distance_visitor::visit_leave(ir_call *ir) { void *ctx = ralloc_parent(ir); - const exec_node *formal_param_node = ir->get_callee()->parameters.head; + const exec_node *formal_param_node = ir->callee->parameters.head; const exec_node *actual_param_node = ir->actual_parameters.head; while (!actual_param_node->is_tail_sentinel()) { ir_variable *formal_param = (ir_variable *) formal_param_node; diff --git a/mesalib/src/glsl/lower_output_reads.cpp b/mesalib/src/glsl/lower_output_reads.cpp index 415b541c3..90d71b04a 100644 --- a/mesalib/src/glsl/lower_output_reads.cpp +++ b/mesalib/src/glsl/lower_output_reads.cpp @@ -54,11 +54,27 @@ public: virtual ir_visitor_status visit_leave(class ir_function_signature *); }; +/** + * Hash function for the output variables - computes the hash of the name. + * NOTE: We're using the name string to ensure that the hash doesn't depend + * on any random factors, otherwise the output_read_remover could produce + * the random order of the assignments. + * + * NOTE: If you want to reuse this function please take into account that + * generally the names of the variables are non-unique. + */ +static unsigned +hash_table_var_hash(const void *key) +{ + const ir_variable * var = static_cast(key); + return hash_table_string_hash(var->name); +} + output_read_remover::output_read_remover() { mem_ctx = ralloc_context(NULL); replacements = - hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare); + hash_table_ctor(0, hash_table_var_hash, hash_table_pointer_compare); } output_read_remover::~output_read_remover() diff --git a/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp b/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp index f8e4a1de4..57771074a 100644 --- a/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp +++ b/mesalib/src/glsl/lower_variable_index_to_cond_assign.cpp @@ -117,7 +117,7 @@ compare_index_block(exec_list *instructions, ir_variable *index, } static inline bool -is_array_or_matrix(const ir_instruction *ir) +is_array_or_matrix(const ir_rvalue *ir) { return (ir->type->is_array() || ir->type->is_matrix()); } diff --git a/mesalib/src/glsl/opt_constant_folding.cpp b/mesalib/src/glsl/opt_constant_folding.cpp index 599b21525..dcad59997 100644 --- a/mesalib/src/glsl/opt_constant_folding.cpp +++ b/mesalib/src/glsl/opt_constant_folding.cpp @@ -117,7 +117,8 @@ ir_constant_folding_visitor::visit_enter(ir_assignment *ir) ir_visitor_status ir_constant_folding_visitor::visit_enter(ir_call *ir) { - exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + /* Attempt to constant fold parameters */ + exec_list_iterator sig_iter = ir->callee->parameters.iterator(); foreach_iter(exec_list_iterator, iter, *ir) { ir_rvalue *param_rval = (ir_rvalue *)iter.get(); ir_variable *sig_param = (ir_variable *)sig_iter.get(); @@ -133,6 +134,15 @@ ir_constant_folding_visitor::visit_enter(ir_call *ir) sig_iter.next(); } + /* Next, see if the call can be replaced with an assignment of a constant */ + ir_constant *const_val = ir->constant_expression_value(); + + if (const_val != NULL) { + ir_assignment *assignment = + new(ralloc_parent(ir)) ir_assignment(ir->return_deref, const_val); + ir->replace_with(assignment); + } + return visit_continue_with_parent; } diff --git a/mesalib/src/glsl/opt_constant_propagation.cpp b/mesalib/src/glsl/opt_constant_propagation.cpp index af77e4906..d3812637d 100644 --- a/mesalib/src/glsl/opt_constant_propagation.cpp +++ b/mesalib/src/glsl/opt_constant_propagation.cpp @@ -259,7 +259,7 @@ ir_visitor_status ir_constant_propagation_visitor::visit_enter(ir_call *ir) { /* Do constant propagation on call parameters, but skip any out params */ - exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator(); + exec_list_iterator sig_param_iter = ir->callee->parameters.iterator(); foreach_iter(exec_list_iterator, iter, ir->actual_parameters) { ir_variable *sig_param = (ir_variable *)sig_param_iter.get(); ir_rvalue *param = (ir_rvalue *)iter.get(); diff --git a/mesalib/src/glsl/opt_constant_variable.cpp b/mesalib/src/glsl/opt_constant_variable.cpp index 3fa7c3bad..f3bc8675e 100644 --- a/mesalib/src/glsl/opt_constant_variable.cpp +++ b/mesalib/src/glsl/opt_constant_variable.cpp @@ -127,7 +127,8 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir) ir_visitor_status ir_constant_variable_visitor::visit_enter(ir_call *ir) { - exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + /* Mark any out parameters as assigned to */ + exec_list_iterator sig_iter = ir->callee->parameters.iterator(); foreach_iter(exec_list_iterator, iter, *ir) { ir_rvalue *param_rval = (ir_rvalue *)iter.get(); ir_variable *param = (ir_variable *)sig_iter.get(); @@ -143,6 +144,17 @@ ir_constant_variable_visitor::visit_enter(ir_call *ir) } sig_iter.next(); } + + /* Mark the return storage as having been assigned to */ + if (ir->return_deref != NULL) { + ir_variable *var = ir->return_deref->variable_referenced(); + struct assignment_entry *entry; + + assert(var); + entry = get_assignment_entry(var, &this->list); + entry->assignment_count++; + } + return visit_continue; } diff --git a/mesalib/src/glsl/opt_copy_propagation.cpp b/mesalib/src/glsl/opt_copy_propagation.cpp index efa3afda3..923619db4 100644 --- a/mesalib/src/glsl/opt_copy_propagation.cpp +++ b/mesalib/src/glsl/opt_copy_propagation.cpp @@ -181,7 +181,7 @@ ir_visitor_status ir_copy_propagation_visitor::visit_enter(ir_call *ir) { /* Do copy propagation on call parameters, but skip any out params */ - exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator(); + exec_list_iterator sig_param_iter = ir->callee->parameters.iterator(); foreach_iter(exec_list_iterator, iter, ir->actual_parameters) { ir_variable *sig_param = (ir_variable *)sig_param_iter.get(); ir_instruction *ir = (ir_instruction *)iter.get(); diff --git a/mesalib/src/glsl/opt_copy_propagation_elements.cpp b/mesalib/src/glsl/opt_copy_propagation_elements.cpp index ebfd4fd3f..314db4e18 100644 --- a/mesalib/src/glsl/opt_copy_propagation_elements.cpp +++ b/mesalib/src/glsl/opt_copy_propagation_elements.cpp @@ -288,7 +288,7 @@ ir_visitor_status ir_copy_propagation_elements_visitor::visit_enter(ir_call *ir) { /* Do copy propagation on call parameters, but skip any out params */ - exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator(); + exec_list_iterator sig_param_iter = ir->callee->parameters.iterator(); foreach_iter(exec_list_iterator, iter, ir->actual_parameters) { ir_variable *sig_param = (ir_variable *)sig_param_iter.get(); ir_instruction *ir = (ir_instruction *)iter.get(); diff --git a/mesalib/src/glsl/opt_dead_code.cpp b/mesalib/src/glsl/opt_dead_code.cpp index 22c7af1c2..0578f1737 100644 --- a/mesalib/src/glsl/opt_dead_code.cpp +++ b/mesalib/src/glsl/opt_dead_code.cpp @@ -78,8 +78,7 @@ do_dead_code(exec_list *instructions, bool uniform_locations_assigned) * Don't do so if it's a shader output, though. */ if (entry->var->mode != ir_var_out && - entry->var->mode != ir_var_inout && - !ir_has_call(entry->assign)) { + entry->var->mode != ir_var_inout) { entry->assign->remove(); progress = true; diff --git a/mesalib/src/glsl/opt_dead_code_local.cpp b/mesalib/src/glsl/opt_dead_code_local.cpp index 39962bd60..a81a38fff 100644 --- a/mesalib/src/glsl/opt_dead_code_local.cpp +++ b/mesalib/src/glsl/opt_dead_code_local.cpp @@ -149,12 +149,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) } } - /* Add this instruction to the assignment list available to be removed. - * But not if the assignment has other side effects. - */ - if (ir_has_call(ir)) - return progress; - + /* Add this instruction to the assignment list available to be removed. */ assignment_entry *entry = new(ctx) assignment_entry(var, ir); assignments->push_tail(entry); diff --git a/mesalib/src/glsl/opt_dead_functions.cpp b/mesalib/src/glsl/opt_dead_functions.cpp index 51c77e3b9..017a28639 100644 --- a/mesalib/src/glsl/opt_dead_functions.cpp +++ b/mesalib/src/glsl/opt_dead_functions.cpp @@ -103,7 +103,7 @@ ir_dead_functions_visitor::visit_enter(ir_function_signature *ir) ir_visitor_status ir_dead_functions_visitor::visit_enter(ir_call *ir) { - signature_entry *entry = this->get_signature_entry(ir->get_callee()); + signature_entry *entry = this->get_signature_entry(ir->callee); entry->used = true; diff --git a/mesalib/src/glsl/opt_function_inlining.cpp b/mesalib/src/glsl/opt_function_inlining.cpp index ec8b72c63..4ff4d97d9 100644 --- a/mesalib/src/glsl/opt_function_inlining.cpp +++ b/mesalib/src/glsl/opt_function_inlining.cpp @@ -53,7 +53,6 @@ public: virtual ir_visitor_status visit_enter(ir_expression *); virtual ir_visitor_status visit_enter(ir_call *); - virtual ir_visitor_status visit_enter(ir_assignment *); virtual ir_visitor_status visit_enter(ir_return *); virtual ir_visitor_status visit_enter(ir_texture *); virtual ir_visitor_status visit_enter(ir_swizzle *); @@ -62,24 +61,11 @@ public: }; -bool -automatic_inlining_predicate(ir_instruction *ir) -{ - ir_call *call = ir->as_call(); - - if (call && can_inline(call)) - return true; - - return false; -} - bool do_function_inlining(exec_list *instructions) { ir_function_inlining_visitor v; - do_expression_flattening(instructions, automatic_inlining_predicate); - v.run(instructions); return v.progress; @@ -89,12 +75,12 @@ static void replace_return_with_assignment(ir_instruction *ir, void *data) { void *ctx = ralloc_parent(ir); - ir_variable *retval = (ir_variable *)data; + ir_dereference *orig_deref = (ir_dereference *) data; ir_return *ret = ir->as_return(); if (ret) { if (ret->value) { - ir_rvalue *lhs = new(ctx) ir_dereference_variable(retval); + ir_rvalue *lhs = orig_deref->clone(ctx, NULL); ret->replace_with(new(ctx) ir_assignment(lhs, ret->value, NULL)); } else { /* un-valued return has to be the last return, or we shouldn't @@ -106,14 +92,13 @@ replace_return_with_assignment(ir_instruction *ir, void *data) } } -ir_rvalue * +void ir_call::generate_inline(ir_instruction *next_ir) { void *ctx = ralloc_parent(this); ir_variable **parameters; int num_parameters; int i; - ir_variable *retval = NULL; struct hash_table *ht; ht = hash_table_ctor(0, hash_table_pointer_hash, hash_table_pointer_compare); @@ -124,13 +109,6 @@ ir_call::generate_inline(ir_instruction *next_ir) parameters = new ir_variable *[num_parameters]; - /* Generate storage for the return value. */ - if (!this->callee->return_type->is_void()) { - retval = new(ctx) ir_variable(this->callee->return_type, "_ret_val", - ir_var_auto); - next_ir->insert_before(retval); - } - /* Generate the declarations for the parameters to our inlined code, * and set up the mapping of real function body variables to ours. */ @@ -185,7 +163,7 @@ ir_call::generate_inline(ir_instruction *next_ir) ir_instruction *new_ir = ir->clone(ctx, ht); new_instructions.push_tail(new_ir); - visit_tree(new_ir, replace_return_with_assignment, retval); + visit_tree(new_ir, replace_return_with_assignment, this->return_deref); } /* If any samplers were passed in, replace any deref of the sampler @@ -238,11 +216,6 @@ ir_call::generate_inline(ir_instruction *next_ir) delete [] parameters; hash_table_dtor(ht); - - if (retval) - return new(ctx) ir_dereference_variable(retval); - else - return NULL; } @@ -282,13 +255,7 @@ ir_visitor_status ir_function_inlining_visitor::visit_enter(ir_call *ir) { if (can_inline(ir)) { - /* If the call was part of some tree, then it should have been - * flattened out or we shouldn't have seen it because of a - * visit_continue_with_parent in this visitor. - */ - assert(ir == base_ir); - - (void) ir->generate_inline(ir); + ir->generate_inline(ir); ir->remove(); this->progress = true; } @@ -297,25 +264,6 @@ ir_function_inlining_visitor::visit_enter(ir_call *ir) } -ir_visitor_status -ir_function_inlining_visitor::visit_enter(ir_assignment *ir) -{ - ir_call *call = ir->rhs->as_call(); - if (!call || !can_inline(call)) - return visit_continue; - - /* generates the parameter setup, function body, and returns the return - * value of the function - */ - ir_rvalue *rhs = call->generate_inline(ir); - assert(rhs); - - ir->rhs = rhs; - this->progress = true; - - return visit_continue; -} - /** * Replaces references to the "sampler" variable with a clone of "deref." * diff --git a/mesalib/src/glsl/opt_tree_grafting.cpp b/mesalib/src/glsl/opt_tree_grafting.cpp index e2aff5f80..d86eab80e 100644 --- a/mesalib/src/glsl/opt_tree_grafting.cpp +++ b/mesalib/src/glsl/opt_tree_grafting.cpp @@ -202,7 +202,7 @@ ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir) ir_visitor_status ir_tree_grafting_visitor::visit_enter(ir_call *ir) { - exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator(); + exec_list_iterator sig_iter = ir->callee->parameters.iterator(); /* Reminder: iterating ir_call iterates its parameters. */ foreach_iter(exec_list_iterator, iter, *ir) { ir_variable *sig_param = (ir_variable *)sig_iter.get(); @@ -222,6 +222,9 @@ ir_tree_grafting_visitor::visit_enter(ir_call *ir) sig_iter.next(); } + if (ir->return_deref && check_graft(ir, ir->return_deref->var) == visit_stop) + return visit_stop; + return visit_continue; } -- cgit v1.2.3