X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fast_function.cpp;h=466ece67424f3542f0ced9b9bb996a476c83bfb8;hb=7a1735680007a78b0a56107871e4afdc33985604;hp=9ffbce69cb51801b49cbc0ecbabe9e1047359ae8;hpb=ac0f8bae8d39ca9f5e873ba8411472e2962890cd;p=mesa.git diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp index 9ffbce69cb5..466ece67424 100644 --- a/src/glsl/ast_function.cpp +++ b/src/glsl/ast_function.cpp @@ -26,6 +26,7 @@ #include "glsl_types.h" #include "ir.h" #include "main/core.h" /* for MIN2 */ +#include "main/shaderobj.h" static ir_rvalue * convert_component(ir_rvalue *src, const glsl_type *desired_type); @@ -41,8 +42,7 @@ process_parameters(exec_list *instructions, exec_list *actual_parameters, { unsigned count = 0; - foreach_list (n, parameters) { - ast_node *const ast = exec_node_data(ast_node, n, link); + foreach_list_typed(ast_node, ast, link, parameters) { ir_rvalue *result = ast->hir(instructions, state); ir_constant *const constant = result->constant_expression_value(); @@ -82,9 +82,7 @@ prototype_string(const glsl_type *return_type, const char *name, ralloc_asprintf_append(&str, "%s(", name); const char *comma = ""; - foreach_list(node, parameters) { - const ir_instruction *const param = (ir_instruction *) node; - + foreach_in_list(const ir_variable, param, parameters) { ralloc_asprintf_append(&str, "%s%s", comma, param->type->name); comma = ", "; } @@ -93,6 +91,82 @@ prototype_string(const glsl_type *return_type, const char *name, return str; } +static bool +verify_image_parameter(YYLTYPE *loc, _mesa_glsl_parse_state *state, + const ir_variable *formal, const ir_variable *actual) +{ + /** + * From the ARB_shader_image_load_store specification: + * + * "The values of image variables qualified with coherent, + * volatile, restrict, readonly, or writeonly may not be passed + * to functions whose formal parameters lack such + * qualifiers. [...] It is legal to have additional qualifiers + * on a formal parameter, but not to have fewer." + */ + if (actual->data.image_coherent && !formal->data.image_coherent) { + _mesa_glsl_error(loc, state, + "function call parameter `%s' drops " + "`coherent' qualifier", formal->name); + return false; + } + + if (actual->data.image_volatile && !formal->data.image_volatile) { + _mesa_glsl_error(loc, state, + "function call parameter `%s' drops " + "`volatile' qualifier", formal->name); + return false; + } + + if (actual->data.image_restrict && !formal->data.image_restrict) { + _mesa_glsl_error(loc, state, + "function call parameter `%s' drops " + "`restrict' qualifier", formal->name); + return false; + } + + if (actual->data.image_read_only && !formal->data.image_read_only) { + _mesa_glsl_error(loc, state, + "function call parameter `%s' drops " + "`readonly' qualifier", formal->name); + return false; + } + + if (actual->data.image_write_only && !formal->data.image_write_only) { + _mesa_glsl_error(loc, state, + "function call parameter `%s' drops " + "`writeonly' qualifier", formal->name); + return false; + } + + return true; +} + +static bool +verify_first_atomic_ssbo_parameter(YYLTYPE *loc, _mesa_glsl_parse_state *state, + ir_variable *var) +{ + if (!var || !var->is_in_shader_storage_block()) { + _mesa_glsl_error(loc, state, "First argument to atomic function " + "must be a buffer variable"); + return false; + } + return true; +} + +static bool +is_atomic_ssbo_function(const char *func_name) +{ + return !strcmp(func_name, "atomicAdd") || + !strcmp(func_name, "atomicMin") || + !strcmp(func_name, "atomicMax") || + !strcmp(func_name, "atomicAnd") || + !strcmp(func_name, "atomicOr") || + !strcmp(func_name, "atomicXor") || + !strcmp(func_name, "atomicExchange") || + !strcmp(func_name, "atomicCompSwap"); +} + /** * Verify that 'out' and 'inout' actual parameters are lvalues. Also, verify * that 'const_in' formal parameters (an extension in our IR) correspond to @@ -107,12 +181,11 @@ verify_parameter_modes(_mesa_glsl_parse_state *state, exec_node *actual_ir_node = actual_ir_parameters.head; exec_node *actual_ast_node = actual_ast_parameters.head; - foreach_list(formal_node, &sig->parameters) { + foreach_in_list(const ir_variable, formal, &sig->parameters) { /* The lists must be the same length. */ assert(!actual_ir_node->is_tail_sentinel()); assert(!actual_ast_node->is_tail_sentinel()); - 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); @@ -123,7 +196,7 @@ verify_parameter_modes(_mesa_glsl_parse_state *state, YYLTYPE loc = actual_ast->get_location(); /* Verify that 'const_in' parameters are ir_constants. */ - if (formal->mode == ir_var_const_in && + if (formal->data.mode == ir_var_const_in && actual->ir_type != ir_type_constant) { _mesa_glsl_error(&loc, state, "parameter `in %s' must be a constant expression", @@ -131,13 +204,32 @@ verify_parameter_modes(_mesa_glsl_parse_state *state, return false; } + /* Verify that shader_in parameters are shader inputs */ + if (formal->data.must_be_shader_input) { + ir_variable *var = actual->variable_referenced(); + if (var && var->data.mode != ir_var_shader_in) { + _mesa_glsl_error(&loc, state, + "parameter `%s` must be a shader input", + formal->name); + return false; + } + + if (actual->ir_type == ir_type_swizzle) { + _mesa_glsl_error(&loc, state, + "parameter `%s` must not be swizzled", + formal->name); + return false; + } + } + /* Verify that 'out' and 'inout' actual parameters are lvalues. */ - if (formal->mode == ir_var_out || formal->mode == ir_var_inout) { + if (formal->data.mode == ir_var_function_out + || formal->data.mode == ir_var_function_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; + switch (formal->data.mode) { + case ir_var_function_out: mode = "out"; break; + case ir_var_function_inout: mode = "inout"; break; + default: assert(false); break; } /* This AST-based check catches errors like f(i++). The IR-based @@ -152,8 +244,11 @@ verify_parameter_modes(_mesa_glsl_parse_state *state, return false; } - if (actual->variable_referenced() - && actual->variable_referenced()->read_only) { + ir_variable *var = actual->variable_referenced(); + if (var) + var->data.assigned = true; + + if (var && var->data.read_only) { _mesa_glsl_error(&loc, state, "function parameter '%s %s' references the " "read-only variable '%s'", @@ -161,158 +256,253 @@ verify_parameter_modes(_mesa_glsl_parse_state *state, actual->variable_referenced()->name); return false; } else if (!actual->is_lvalue()) { - _mesa_glsl_error(&loc, state, - "function parameter '%s %s' is not an lvalue", - mode, formal->name); - return false; + _mesa_glsl_error(&loc, state, + "function parameter '%s %s' is not an lvalue", + mode, formal->name); + return false; } } + if (formal->type->is_image() && + actual->variable_referenced()) { + if (!verify_image_parameter(&loc, state, formal, + actual->variable_referenced())) + return false; + } + actual_ir_node = actual_ir_node->next; actual_ast_node = actual_ast_node->next; } + + /* The first parameter of atomic functions must be a buffer variable */ + const char *func_name = sig->function_name(); + bool is_atomic_ssbo = is_atomic_ssbo_function(func_name); + if (is_atomic_ssbo) { + const ir_rvalue *const actual = (ir_rvalue *) actual_ir_parameters.head; + + const ast_expression *const actual_ast = + exec_node_data(ast_expression, actual_ast_parameters.head, link); + YYLTYPE loc = actual_ast->get_location(); + + if (!verify_first_atomic_ssbo_parameter(&loc, state, + actual->variable_referenced())) { + return false; + } + } + return true; } +static void +fix_parameter(void *mem_ctx, ir_rvalue *actual, const glsl_type *formal_type, + exec_list *before_instructions, exec_list *after_instructions, + bool parameter_is_inout) +{ + ir_expression *const expr = actual->as_expression(); + + /* If the types match exactly and the parameter is not a vector-extract, + * nothing needs to be done to fix the parameter. + */ + if (formal_type == actual->type + && (expr == NULL || expr->operation != ir_binop_vector_extract)) + return; + + /* To convert an out parameter, we need to create a temporary variable to + * hold the value before conversion, and then perform the conversion after + * the function call returns. + * + * This has the effect of transforming code like this: + * + * void f(out int x); + * float value; + * f(value); + * + * Into IR that's equivalent to this: + * + * void f(out int x); + * float value; + * int out_parameter_conversion; + * f(out_parameter_conversion); + * value = float(out_parameter_conversion); + * + * If the parameter is an ir_expression of ir_binop_vector_extract, + * additional conversion is needed in the post-call re-write. + */ + ir_variable *tmp = + new(mem_ctx) ir_variable(formal_type, "inout_tmp", ir_var_temporary); + + before_instructions->push_tail(tmp); + + /* If the parameter is an inout parameter, copy the value of the actual + * parameter to the new temporary. Note that no type conversion is allowed + * here because inout parameters must match types exactly. + */ + if (parameter_is_inout) { + /* Inout parameters should never require conversion, since that would + * require an implicit conversion to exist both to and from the formal + * parameter type, and there are no bidirectional implicit conversions. + */ + assert (actual->type == formal_type); + + ir_dereference_variable *const deref_tmp_1 = + new(mem_ctx) ir_dereference_variable(tmp); + ir_assignment *const assignment = + new(mem_ctx) ir_assignment(deref_tmp_1, actual); + before_instructions->push_tail(assignment); + } + + /* Replace the parameter in the call with a dereference of the new + * temporary. + */ + ir_dereference_variable *const deref_tmp_2 = + new(mem_ctx) ir_dereference_variable(tmp); + actual->replace_with(deref_tmp_2); + + + /* Copy the temporary variable to the actual parameter with optional + * type conversion applied. + */ + ir_rvalue *rhs = new(mem_ctx) ir_dereference_variable(tmp); + if (actual->type != formal_type) + rhs = convert_component(rhs, actual->type); + + ir_rvalue *lhs = actual; + if (expr != NULL && expr->operation == ir_binop_vector_extract) { + lhs = new(mem_ctx) ir_dereference_array(expr->operands[0]->clone(mem_ctx, NULL), + expr->operands[1]->clone(mem_ctx, NULL)); + } + + ir_assignment *const assignment_2 = new(mem_ctx) ir_assignment(lhs, rhs); + after_instructions->push_tail(assignment_2); +} + /** - * 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. + * Generate a function call. + * + * For non-void functions, this returns a dereference of the temporary variable + * which stores the return value for the call. For void functions, this returns + * NULL. */ static ir_rvalue * generate_call(exec_list *instructions, ir_function_signature *sig, - YYLTYPE *loc, exec_list *actual_parameters, - ir_call **call_ir, + exec_list *actual_parameters, + ir_variable *sub_var, + ir_rvalue *array_idx, 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); + foreach_two_lists(formal_node, &sig->parameters, + actual_node, actual_parameters) { + ir_rvalue *actual = (ir_rvalue *) actual_node; + ir_variable *formal = (ir_variable *) formal_node; if (formal->type->is_numeric() || formal->type->is_boolean()) { - switch (formal->mode) { + switch (formal->data.mode) { case ir_var_const_in: - case ir_var_in: { + case ir_var_function_in: { ir_rvalue *converted = convert_component(actual, formal->type); actual->replace_with(converted); break; } - case ir_var_out: - if (actual->type != formal->type) { - /* To convert an out parameter, we need to create a - * temporary variable to hold the value before conversion, - * and then perform the conversion after the function call - * returns. - * - * This has the effect of transforming code like this: - * - * void f(out int x); - * float value; - * f(value); - * - * Into IR that's equivalent to this: - * - * void f(out int x); - * float value; - * int out_parameter_conversion; - * f(out_parameter_conversion); - * value = float(out_parameter_conversion); - */ - ir_variable *tmp = - new(ctx) ir_variable(formal->type, - "out_parameter_conversion", - ir_var_temporary); - instructions->push_tail(tmp); - ir_dereference_variable *deref_tmp_1 - = new(ctx) ir_dereference_variable(tmp); - ir_dereference_variable *deref_tmp_2 - = new(ctx) ir_dereference_variable(tmp); - ir_rvalue *converted_tmp - = convert_component(deref_tmp_1, actual->type); - ir_assignment *assignment - = new(ctx) ir_assignment(actual, converted_tmp); - post_call_conversions.push_tail(assignment); - actual->replace_with(deref_tmp_2); - } - break; - case ir_var_inout: - /* Inout parameters should never require conversion, since that - * would require an implicit conversion to exist both to and - * from the formal parameter type, and there are no - * bidirectional implicit conversions. - */ - assert (actual->type == formal->type); + case ir_var_function_out: + case ir_var_function_inout: + fix_parameter(ctx, actual, formal->type, + instructions, &post_call_conversions, + formal->data.mode == ir_var_function_inout); break; default: assert (!"Illegal formal parameter mode"); break; } } - - actual_iter.next(); - 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. + /* Section 4.3.2 (Const) of the GLSL 1.10.59 spec says: + * + * "Initializers for const declarations must be formed from literal + * values, other const variables (not including function call + * paramaters), or expressions of these. + * + * Constructors may be used in such expressions, but function calls may + * not." + * + * Section 4.3.3 (Constant Expressions) of the GLSL 1.20.8 spec says: + * + * "A constant expression is one of + * + * ... + * + * - a built-in function call whose arguments are all constant + * expressions, with the exception of the texture lookup + * functions, the noise functions, and ftransform. The built-in + * functions dFdx, dFdy, and fwidth must return 0 when evaluated + * inside an initializer with an argument that is a constant + * expression." * - * Also insert any out parameter conversions after the call. + * Section 5.10 (Constant Expressions) of the GLSL ES 1.00.17 spec says: + * + * "A constant expression is one of + * + * ... + * + * - a built-in function call whose arguments are all constant + * expressions, with the exception of the texture lookup + * functions." + * + * Section 4.3.3 (Constant Expressions) of the GLSL ES 3.00.4 spec says: + * + * "A constant expression is one of + * + * ... + * + * - a built-in function call whose arguments are all constant + * expressions, with the exception of the texture lookup + * functions. The built-in functions dFdx, dFdy, and fwidth must + * return 0 when evaluated inside an initializer with an argument + * that is a constant expression." + * + * If the function call is a constant expression, don't generate any + * instructions; just generate an ir_constant. */ - 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->is_version(120, 100)) { + ir_constant *value = sig->constant_expression_value(actual_parameters, NULL); + 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. */ + char *const name = ir_variable::temporaries_allocate_names + ? ralloc_asprintf(ctx, "%s_retval", sig->function_name()) + : NULL; ir_variable *var; - var = new(ctx) ir_variable(sig->return_type, - ralloc_asprintf(ctx, "%s_retval", - sig->function_name()), - ir_var_temporary); + var = new(ctx) ir_variable(sig->return_type, name, ir_var_temporary); 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; + ralloc_free(name); 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, sub_var, array_idx); + 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; } /** @@ -333,53 +523,31 @@ match_function_by_name(const char *name, goto done; /* no match */ /* Is the function hidden by a variable (impossible in 1.10)? */ - if (state->language_version != 110 && state->symbols->get_variable(name)) + if (!state->symbols->separate_function_namespace + && state->symbols->get_variable(name)) goto done; /* no match */ if (f != NULL) { + /* In desktop GL, the presence of a user-defined signature hides any + * built-in signatures, so we must ignore them. In contrast, in ES2 + * user-defined signatures add new overloads, so we must consider them. + */ + bool allow_builtins = state->es_shader || !f->has_user_signature(); + /* Look for a match in the local shader. If exact, we're done. */ bool is_exact = false; - sig = local_sig = f->matching_signature(actual_parameters, &is_exact); + sig = local_sig = f->matching_signature(state, actual_parameters, + allow_builtins, &is_exact); if (is_exact) goto done; - if (!state->es_shader && f->has_user_signature()) { - /* In desktop GL, the presence of a user-defined signature hides any - * built-in signatures, so we must ignore them. In contrast, in ES2 - * user-defined signatures add new overloads, so we must proceed. - */ + if (!allow_builtins) goto done; - } } /* Local shader has no exact candidates; check the built-ins. */ - _mesa_glsl_initialize_functions(state); - for (unsigned i = 0; i < state->num_builtins_to_link; i++) { - ir_function *builtin = - state->builtins_to_link[i]->symbols->get_function(name); - if (builtin == NULL) - continue; - - bool is_exact = false; - ir_function_signature *builtin_sig = - builtin->matching_signature(actual_parameters, &is_exact); - - if (builtin_sig == NULL) - continue; - - /* If the built-in signature is exact, we can stop. */ - if (is_exact) { - sig = builtin_sig; - goto done; - } - - if (sig == NULL) { - /* We found an inexact match, which is better than nothing. However, - * we should keep searching for an exact match. - */ - sig = builtin_sig; - } - } + _mesa_glsl_initialize_builtin_functions(); + sig = _mesa_glsl_find_builtin_function(state, name, actual_parameters); done: if (sig != NULL) { @@ -396,6 +564,88 @@ done: return sig; } +static ir_function_signature * +match_subroutine_by_name(const char *name, + exec_list *actual_parameters, + struct _mesa_glsl_parse_state *state, + ir_variable **var_r) +{ + void *ctx = state; + ir_function_signature *sig = NULL; + ir_function *f, *found = NULL; + const char *new_name; + ir_variable *var; + bool is_exact = false; + + new_name = ralloc_asprintf(ctx, "%s_%s", _mesa_shader_stage_to_subroutine_prefix(state->stage), name); + var = state->symbols->get_variable(new_name); + if (!var) + return NULL; + + for (int i = 0; i < state->num_subroutine_types; i++) { + f = state->subroutine_types[i]; + if (strcmp(f->name, var->type->without_array()->name)) + continue; + found = f; + break; + } + + if (!found) + return NULL; + *var_r = var; + sig = found->matching_signature(state, actual_parameters, + false, &is_exact); + return sig; +} + +static ir_rvalue * +generate_array_index(void *mem_ctx, exec_list *instructions, + struct _mesa_glsl_parse_state *state, YYLTYPE loc, + const ast_expression *array, ast_expression *idx, + const char **function_name, exec_list *actual_parameters) +{ + if (array->oper == ast_array_index) { + /* This handles arrays of arrays */ + ir_rvalue *outer_array = generate_array_index(mem_ctx, instructions, + state, loc, + array->subexpressions[0], + array->subexpressions[1], + function_name, actual_parameters); + ir_rvalue *outer_array_idx = idx->hir(instructions, state); + + YYLTYPE index_loc = idx->get_location(); + return _mesa_ast_array_index_to_hir(mem_ctx, state, outer_array, + outer_array_idx, loc, + index_loc); + } else { + ir_variable *sub_var = NULL; + *function_name = array->primary_expression.identifier; + + match_subroutine_by_name(*function_name, actual_parameters, + state, &sub_var); + + ir_rvalue *outer_array_idx = idx->hir(instructions, state); + return new(mem_ctx) ir_dereference_array(sub_var, outer_array_idx); + } +} + +static void +print_function_prototypes(_mesa_glsl_parse_state *state, YYLTYPE *loc, + ir_function *f) +{ + if (f == NULL) + return; + + foreach_in_list(ir_function_signature, sig, &f->signatures) { + if (sig->is_builtin() && !sig->is_builtin_available(state)) + continue; + + char *str = prototype_string(sig->return_type, f->name, &sig->parameters); + _mesa_glsl_error(loc, state, " %s", str); + ralloc_free(str); + } +} + /** * Raise a "no matching function" error, listing all possible overloads the * compiler considered so developers can figure out what went wrong. @@ -406,27 +656,23 @@ no_matching_function_error(const char *name, 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); - - const char *prefix = "candidates are: "; - - 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; + gl_shader *sh = _mesa_glsl_get_builtin_function_shader(); - foreach_list (node, &f->signatures) { - ir_function_signature *sig = (ir_function_signature *) node; + if (state->symbols->get_function(name) == NULL + && (!state->uses_builtin_functions + || sh->symbols->get_function(name) == NULL)) { + _mesa_glsl_error(loc, state, "no function with name '%s'", name); + } else { + char *str = prototype_string(NULL, name, actual_parameters); + _mesa_glsl_error(loc, state, + "no matching function for call to `%s'; candidates are:", + str); + ralloc_free(str); - str = prototype_string(sig->return_type, f->name, &sig->parameters); - _mesa_glsl_error(loc, state, "%s%s", prefix, str); - ralloc_free(str); + print_function_prototypes(state, loc, state->symbols->get_function(name)); - prefix = " "; + if (state->uses_builtin_functions) { + print_function_prototypes(state, loc, sh->symbols->get_function(name)); } } } @@ -461,13 +707,15 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type) result = new(ctx) ir_expression(ir_unop_i2u, src); break; case GLSL_TYPE_FLOAT: - result = new(ctx) ir_expression(ir_unop_i2u, - new(ctx) ir_expression(ir_unop_f2i, src)); + result = new(ctx) ir_expression(ir_unop_f2u, src); break; case GLSL_TYPE_BOOL: result = new(ctx) ir_expression(ir_unop_i2u, new(ctx) ir_expression(ir_unop_b2i, src)); break; + case GLSL_TYPE_DOUBLE: + result = new(ctx) ir_expression(ir_unop_d2u, src); + break; } break; case GLSL_TYPE_INT: @@ -481,6 +729,9 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type) case GLSL_TYPE_BOOL: result = new(ctx) ir_expression(ir_unop_b2i, src); break; + case GLSL_TYPE_DOUBLE: + result = new(ctx) ir_expression(ir_unop_d2i, src); + break; } break; case GLSL_TYPE_FLOAT: @@ -494,6 +745,9 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type) case GLSL_TYPE_BOOL: result = new(ctx) ir_expression(ir_unop_b2f, desired_type, src, NULL); break; + case GLSL_TYPE_DOUBLE: + result = new(ctx) ir_expression(ir_unop_d2f, desired_type, src, NULL); + break; } break; case GLSL_TYPE_BOOL: @@ -508,8 +762,27 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type) case GLSL_TYPE_FLOAT: result = new(ctx) ir_expression(ir_unop_f2b, desired_type, src, NULL); break; + case GLSL_TYPE_DOUBLE: + result = new(ctx) ir_expression(ir_unop_d2b, desired_type, src, NULL); + break; } break; + case GLSL_TYPE_DOUBLE: + switch (b) { + case GLSL_TYPE_INT: + result = new(ctx) ir_expression(ir_unop_i2d, src); + break; + case GLSL_TYPE_UINT: + result = new(ctx) ir_expression(ir_unop_u2d, src); + break; + case GLSL_TYPE_BOOL: + result = new(ctx) ir_expression(ir_unop_f2d, + new(ctx) ir_expression(ir_unop_b2f, src)); + break; + case GLSL_TYPE_FLOAT: + result = new(ctx) ir_expression(ir_unop_f2d, desired_type, src, NULL); + break; + } } assert(result != NULL); @@ -561,6 +834,129 @@ dereference_component(ir_rvalue *src, unsigned component) } +static ir_rvalue * +process_vec_mat_constructor(exec_list *instructions, + const glsl_type *constructor_type, + YYLTYPE *loc, exec_list *parameters, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + + /* The ARB_shading_language_420pack spec says: + * + * "If an initializer is a list of initializers enclosed in curly braces, + * the variable being declared must be a vector, a matrix, an array, or a + * structure. + * + * int i = { 1 }; // illegal, i is not an aggregate" + */ + if (constructor_type->vector_elements <= 1) { + _mesa_glsl_error(loc, state, "aggregates can only initialize vectors, " + "matrices, arrays, and structs"); + return ir_rvalue::error_value(ctx); + } + + exec_list actual_parameters; + const unsigned parameter_count = + process_parameters(instructions, &actual_parameters, parameters, state); + + if (parameter_count == 0 + || (constructor_type->is_vector() && + constructor_type->vector_elements != parameter_count) + || (constructor_type->is_matrix() && + constructor_type->matrix_columns != parameter_count)) { + _mesa_glsl_error(loc, state, "%s constructor must have %u parameters", + constructor_type->is_vector() ? "vector" : "matrix", + constructor_type->vector_elements); + return ir_rvalue::error_value(ctx); + } + + bool all_parameters_are_constant = true; + + /* Type cast each parameter and, if possible, fold constants. */ + foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) { + ir_rvalue *result = ir; + + /* Apply implicit conversions (not the scalar constructor rules!). See + * the spec quote above. */ + if (constructor_type->base_type != result->type->base_type) { + const glsl_type *desired_type = + glsl_type::get_instance(constructor_type->base_type, + ir->type->vector_elements, + ir->type->matrix_columns); + if (result->type->can_implicitly_convert_to(desired_type, state)) { + /* Even though convert_component() implements the constructor + * conversion rules (not the implicit conversion rules), its safe + * to use it here because we already checked that the implicit + * conversion is legal. + */ + result = convert_component(ir, desired_type); + } + } + + if (constructor_type->is_matrix()) { + if (result->type != constructor_type->column_type()) { + _mesa_glsl_error(loc, state, "type error in matrix constructor: " + "expected: %s, found %s", + constructor_type->column_type()->name, + result->type->name); + return ir_rvalue::error_value(ctx); + } + } else if (result->type != constructor_type->get_scalar_type()) { + _mesa_glsl_error(loc, state, "type error in vector constructor: " + "expected: %s, found %s", + constructor_type->get_scalar_type()->name, + result->type->name); + return ir_rvalue::error_value(ctx); + } + + /* Attempt to convert the parameter to a constant valued expression. + * After doing so, track whether or not all the parameters to the + * constructor are trivially constant valued expressions. + */ + ir_rvalue *const constant = result->constant_expression_value(); + + if (constant != NULL) + result = constant; + else + all_parameters_are_constant = false; + + ir->replace_with(result); + } + + if (all_parameters_are_constant) + return new(ctx) ir_constant(constructor_type, &actual_parameters); + + ir_variable *var = new(ctx) ir_variable(constructor_type, "vec_mat_ctor", + ir_var_temporary); + instructions->push_tail(var); + + int i = 0; + + foreach_in_list(ir_rvalue, rhs, &actual_parameters) { + ir_instruction *assignment = NULL; + + if (var->type->is_matrix()) { + ir_rvalue *lhs = new(ctx) ir_dereference_array(var, + new(ctx) ir_constant(i)); + assignment = new(ctx) ir_assignment(lhs, rhs, NULL); + } else { + /* use writemask rather than index for vector */ + assert(var->type->is_vector()); + assert(i < 4); + ir_dereference *lhs = new(ctx) ir_dereference_variable(var); + assignment = new(ctx) ir_assignment(lhs, rhs, NULL, (unsigned)(1 << i)); + } + + instructions->push_tail(assignment); + + i++; + } + + return new(ctx) ir_dereference_variable(var); +} + + static ir_rvalue * process_array_constructor(exec_list *instructions, const glsl_type *constructor_type, @@ -591,43 +987,47 @@ process_array_constructor(exec_list *instructions, exec_list actual_parameters; const unsigned parameter_count = process_parameters(instructions, &actual_parameters, parameters, state); + bool is_unsized_array = constructor_type->is_unsized_array(); - if ((parameter_count == 0) - || ((constructor_type->length != 0) - && (constructor_type->length != parameter_count))) { - const unsigned min_param = (constructor_type->length == 0) - ? 1 : constructor_type->length; + if ((parameter_count == 0) || + (!is_unsized_array && (constructor_type->length != parameter_count))) { + const unsigned min_param = is_unsized_array + ? 1 : constructor_type->length; _mesa_glsl_error(loc, state, "array constructor must have %s %u " "parameter%s", - (constructor_type->length != 0) ? "at least" : "exactly", + is_unsized_array ? "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) { + if (is_unsized_array) { constructor_type = - glsl_type::get_array_instance(constructor_type->element_type(), + glsl_type::get_array_instance(constructor_type->fields.array, parameter_count); assert(constructor_type != NULL); assert(constructor_type->length == parameter_count); } bool all_parameters_are_constant = true; + const glsl_type *element_type = constructor_type->fields.array; /* Type cast each parameter and, if possible, fold constants. */ - foreach_list_safe(n, &actual_parameters) { - ir_rvalue *ir = (ir_rvalue *) n; + foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) { ir_rvalue *result = ir; + const glsl_base_type element_base_type = + constructor_type->fields.array->base_type; + /* Apply implicit conversions (not the scalar constructor rules!). See * the spec quote above. */ - if (constructor_type->element_type()->is_float()) { - const glsl_type *desired_type = - glsl_type::get_instance(GLSL_TYPE_FLOAT, - ir->type->vector_elements, - ir->type->matrix_columns); - if (result->type->can_implicitly_convert_to(desired_type)) { + if (element_base_type != result->type->base_type) { + const glsl_type *desired_type = + glsl_type::get_instance(element_base_type, + ir->type->vector_elements, + ir->type->matrix_columns); + + if (result->type->can_implicitly_convert_to(desired_type, state)) { /* Even though convert_component() implements the constructor * conversion rules (not the implicit conversion rules), its safe * to use it here because we already checked that the implicit @@ -637,11 +1037,34 @@ process_array_constructor(exec_list *instructions, } } - if (result->type != constructor_type->element_type()) { + if (constructor_type->fields.array->is_unsized_array()) { + /* As the inner parameters of the constructor are created without + * knowledge of each other we need to check to make sure unsized + * parameters of unsized constructors all end up with the same size. + * + * e.g we make sure to fail for a constructor like this: + * vec4[][] a = vec4[][](vec4[](vec4(0.0), vec4(1.0)), + * vec4[](vec4(0.0), vec4(1.0), vec4(1.0)), + * vec4[](vec4(0.0), vec4(1.0))); + */ + if (element_type->is_unsized_array()) { + /* This is the first parameter so just get the type */ + element_type = result->type; + } else if (element_type != result->type) { + _mesa_glsl_error(loc, state, "type error in array constructor: " + "expected: %s, found %s", + element_type->name, + result->type->name); + return ir_rvalue::error_value(ctx); + } + } else if (result->type != constructor_type->fields.array) { _mesa_glsl_error(loc, state, "type error in array constructor: " "expected: %s, found %s", - constructor_type->element_type()->name, + constructor_type->fields.array->name, result->type->name); + return ir_rvalue::error_value(ctx); + } else { + element_type = result->type; } /* Attempt to convert the parameter to a constant valued expression. @@ -658,6 +1081,14 @@ process_array_constructor(exec_list *instructions, ir->replace_with(result); } + if (constructor_type->fields.array->is_unsized_array()) { + constructor_type = + glsl_type::get_array_instance(element_type, + parameter_count); + assert(constructor_type != NULL); + assert(constructor_type->length == parameter_count); + } + if (all_parameters_are_constant) return new(ctx) ir_constant(constructor_type, &actual_parameters); @@ -666,8 +1097,7 @@ process_array_constructor(exec_list *instructions, instructions->push_tail(var); int i = 0; - foreach_list(node, &actual_parameters) { - ir_rvalue *rhs = (ir_rvalue *) node; + foreach_in_list(ir_rvalue, rhs, &actual_parameters) { ir_rvalue *lhs = new(ctx) ir_dereference_array(var, new(ctx) ir_constant(i)); @@ -688,8 +1118,8 @@ static ir_constant * constant_record_constructor(const glsl_type *constructor_type, exec_list *parameters, void *mem_ctx) { - foreach_list(node, parameters) { - ir_constant *constant = ((ir_instruction *) node)->as_constant(); + foreach_in_list(ir_instruction, node, parameters) { + ir_constant *constant = node->as_constant(); if (constant == NULL) return NULL; node->replace_with(constant); @@ -734,11 +1164,15 @@ emit_inline_vector_constructor(const glsl_type *type, ir_variable *var = new(ctx) ir_variable(type, "vec_ctor", ir_var_temporary); instructions->push_tail(var); - /* There are two kinds of vector constructors. + /* There are three kinds of vector constructors. * * - Construct a vector from a single scalar by replicating that scalar to * all components of the vector. * + * - Construct a vector from at least a matrix. This case should already + * have been taken care of in ast_function_expression::hir by breaking + * down the matrix into a series of column vectors. + * * - Construct a vector from an arbirary combination of vectors and * scalars. The components of the constructor parameters are assigned * to the vector in order until the vector is full. @@ -763,8 +1197,7 @@ emit_inline_vector_constructor(const glsl_type *type, memset(&data, 0, sizeof(data)); - foreach_list(node, parameters) { - ir_rvalue *param = (ir_rvalue *) node; + foreach_in_list(ir_rvalue, param, parameters) { unsigned rhs_components = param->type->components(); /* Do not try to assign more components to the vector than it has! @@ -786,6 +1219,9 @@ emit_inline_vector_constructor(const glsl_type *type, case GLSL_TYPE_FLOAT: data.f[i + base_component] = c->get_float_component(i); break; + case GLSL_TYPE_DOUBLE: + data.d[i + base_component] = c->get_double_component(i); + break; case GLSL_TYPE_BOOL: data.b[i + base_component] = c->get_bool_component(i); break; @@ -821,8 +1257,7 @@ emit_inline_vector_constructor(const glsl_type *type, } base_component = 0; - foreach_list(node, parameters) { - ir_rvalue *param = (ir_rvalue *) node; + foreach_in_list(ir_rvalue, param, parameters) { unsigned rhs_components = param->type->components(); /* Do not try to assign more components to the vector than it has! @@ -831,6 +1266,14 @@ emit_inline_vector_constructor(const glsl_type *type, rhs_components = lhs_components - base_component; } + /* If we do not have any components left to copy, break out of the + * loop. This can happen when initializing a vec4 with a mat3 as the + * mat3 would have been broken into a series of column vectors. + */ + if (rhs_components == 0) { + break; + } + const ir_constant *const c = param->as_constant(); if (c == NULL) { /* Mask of fields to be written in the assignment. @@ -931,7 +1374,7 @@ emit_inline_matrix_constructor(const glsl_type *type, * * - Construct a matrix from an arbirary combination of vectors and * scalars. The components of the constructor parameters are assigned - * to the matrix in colum-major order until the matrix is full. + * to the matrix in column-major order until the matrix is full. * * - Construct a matrix from a single matrix. The source matrix is copied * to the upper left portion of the constructed matrix, and the remaining @@ -942,16 +1385,21 @@ emit_inline_matrix_constructor(const glsl_type *type, /* Assign the scalar to the X component of a vec4, and fill the remaining * components with zero. */ + glsl_base_type param_base_type = first_param->type->base_type; + assert(param_base_type == GLSL_TYPE_FLOAT || + param_base_type == GLSL_TYPE_DOUBLE); ir_variable *rhs_var = - new(ctx) ir_variable(glsl_type::vec4_type, "mat_ctor_vec", - ir_var_temporary); + new(ctx) ir_variable(glsl_type::get_instance(param_base_type, 4, 1), + "mat_ctor_vec", + ir_var_temporary); instructions->push_tail(rhs_var); ir_constant_data zero; - zero.f[0] = 0.0; - zero.f[1] = 0.0; - zero.f[2] = 0.0; - zero.f[3] = 0.0; + for (unsigned i = 0; i < 4; i++) + if (param_base_type == GLSL_TYPE_FLOAT) + zero.f[i] = 0.0; + else + zero.d[i] = 0.0; ir_instruction *inst = new(ctx) ir_assignment(new(ctx) ir_dereference_variable(rhs_var), @@ -1105,72 +1553,59 @@ emit_inline_matrix_constructor(const glsl_type *type, } else { const unsigned cols = type->matrix_columns; const unsigned rows = type->vector_elements; + unsigned remaining_slots = rows * cols; unsigned col_idx = 0; unsigned row_idx = 0; - foreach_list (node, parameters) { - ir_rvalue *const rhs = (ir_rvalue *) node; - const unsigned components_remaining_this_column = rows - row_idx; - unsigned rhs_components = rhs->type->components(); - unsigned rhs_base = 0; - - /* Since the parameter might be used in the RHS of two assignments, - * generate a temporary and copy the paramter there. - */ - ir_variable *rhs_var = - new(ctx) ir_variable(rhs->type, "mat_ctor_vec", ir_var_temporary); - instructions->push_tail(rhs_var); - - ir_dereference *rhs_var_ref = - new(ctx) ir_dereference_variable(rhs_var); - ir_instruction *inst = new(ctx) ir_assignment(rhs_var_ref, rhs, NULL); - instructions->push_tail(inst); - - /* Assign the current parameter to as many components of the matrix - * as it will fill. - * - * NOTE: A single vector parameter can span two matrix columns. A - * single vec4, for example, can completely fill a mat2. - */ - if (rhs_components >= components_remaining_this_column) { - const unsigned count = MIN2(rhs_components, - components_remaining_this_column); - - rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var); - - ir_instruction *inst = assign_to_matrix_column(var, col_idx, - row_idx, - rhs_var_ref, 0, - count, ctx); - instructions->push_tail(inst); - - rhs_base = count; - - col_idx++; - row_idx = 0; - } - - /* If there is data left in the parameter and components left to be - * set in the destination, emit another assignment. It is possible - * that the assignment could be of a vec4 to the last element of the - * matrix. In this case col_idx==cols, but there is still data - * left in the source parameter. Obviously, don't emit an assignment - * to data outside the destination matrix. - */ - if ((col_idx < cols) && (rhs_base < rhs_components)) { - const unsigned count = rhs_components - rhs_base; - - rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var); - - ir_instruction *inst = assign_to_matrix_column(var, col_idx, - row_idx, - rhs_var_ref, - rhs_base, - count, ctx); - instructions->push_tail(inst); - - row_idx += count; - } + foreach_in_list(ir_rvalue, rhs, parameters) { + unsigned rhs_components = rhs->type->components(); + unsigned rhs_base = 0; + + if (remaining_slots == 0) + break; + + /* Since the parameter might be used in the RHS of two assignments, + * generate a temporary and copy the paramter there. + */ + ir_variable *rhs_var = + new(ctx) ir_variable(rhs->type, "mat_ctor_vec", ir_var_temporary); + instructions->push_tail(rhs_var); + + ir_dereference *rhs_var_ref = + new(ctx) ir_dereference_variable(rhs_var); + ir_instruction *inst = new(ctx) ir_assignment(rhs_var_ref, rhs, NULL); + instructions->push_tail(inst); + + do { + /* Assign the current parameter to as many components of the matrix + * as it will fill. + * + * NOTE: A single vector parameter can span two matrix columns. A + * single vec4, for example, can completely fill a mat2. + */ + unsigned count = MIN2(rows - row_idx, + rhs_components - rhs_base); + + rhs_var_ref = new(ctx) ir_dereference_variable(rhs_var); + ir_instruction *inst = assign_to_matrix_column(var, col_idx, + row_idx, + rhs_var_ref, + rhs_base, + count, ctx); + instructions->push_tail(inst); + rhs_base += count; + row_idx += count; + remaining_slots -= count; + + /* Sometimes, there is still data left in the parameters and + * components left to be set in the destination but in other + * column. + */ + if (row_idx >= rows) { + row_idx = 0; + col_idx++; + } + } while(remaining_slots > 0 && rhs_base < rhs_components); } } @@ -1211,6 +1646,127 @@ emit_inline_record_constructor(const glsl_type *type, } +static ir_rvalue * +process_record_constructor(exec_list *instructions, + const glsl_type *constructor_type, + YYLTYPE *loc, exec_list *parameters, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + exec_list actual_parameters; + + process_parameters(instructions, &actual_parameters, + parameters, state); + + exec_node *node = actual_parameters.head; + for (unsigned i = 0; i < constructor_type->length; i++) { + ir_rvalue *ir = (ir_rvalue *) node; + + if (node->is_tail_sentinel()) { + _mesa_glsl_error(loc, state, + "insufficient parameters to constructor for `%s'", + constructor_type->name); + return ir_rvalue::error_value(ctx); + } + + if (apply_implicit_conversion(constructor_type->fields.structure[i].type, + ir, state)) { + node->replace_with(ir); + } else { + _mesa_glsl_error(loc, state, + "parameter type mismatch in constructor for `%s.%s' " + "(%s vs %s)", + constructor_type->name, + constructor_type->fields.structure[i].name, + ir->type->name, + constructor_type->fields.structure[i].type->name); + return ir_rvalue::error_value(ctx);; + } + + node = node->next; + } + + if (!node->is_tail_sentinel()) { + _mesa_glsl_error(loc, state, "too many parameters in constructor " + "for `%s'", constructor_type->name); + return ir_rvalue::error_value(ctx); + } + + ir_rvalue *const constant = + constant_record_constructor(constructor_type, &actual_parameters, + state); + + return (constant != NULL) + ? constant + : emit_inline_record_constructor(constructor_type, instructions, + &actual_parameters, state); +} + +ir_rvalue * +ast_function_expression::handle_method(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + const ast_expression *field = subexpressions[0]; + ir_rvalue *op; + ir_rvalue *result; + void *ctx = state; + /* Handle "method calls" in GLSL 1.20 - namely, array.length() */ + YYLTYPE loc = get_location(); + state->check_version(120, 300, &loc, "methods not supported"); + + const char *method; + method = field->primary_expression.identifier; + + op = field->subexpressions[0]->hir(instructions, state); + if (strcmp(method, "length") == 0) { + if (!this->expressions.is_empty()) { + _mesa_glsl_error(&loc, state, "length method takes no arguments"); + goto fail; + } + + if (op->type->is_array()) { + if (op->type->is_unsized_array()) { + if (!state->has_shader_storage_buffer_objects()) { + _mesa_glsl_error(&loc, state, "length called on unsized array" + " only available with " + "ARB_shader_storage_buffer_object"); + } + /* Calculate length of an unsized array in run-time */ + result = new(ctx) ir_expression(ir_unop_ssbo_unsized_array_length, op); + } else { + result = new(ctx) ir_constant(op->type->array_size()); + } + } else if (op->type->is_vector()) { + if (state->ARB_shading_language_420pack_enable) { + /* .length() returns int. */ + result = new(ctx) ir_constant((int) op->type->vector_elements); + } else { + _mesa_glsl_error(&loc, state, "length method on matrix only available" + "with ARB_shading_language_420pack"); + goto fail; + } + } else if (op->type->is_matrix()) { + if (state->ARB_shading_language_420pack_enable) { + /* .length() returns int. */ + result = new(ctx) ir_constant((int) op->type->matrix_columns); + } else { + _mesa_glsl_error(&loc, state, "length method on matrix only available" + "with ARB_shading_language_420pack"); + goto fail; + } + } else { + _mesa_glsl_error(&loc, state, "length called on scalar."); + goto fail; + } + } else { + _mesa_glsl_error(&loc, state, "unknown method: `%s'", method); + goto fail; + } + return result; +fail: + return ir_rvalue::error_value(ctx); +} + ir_rvalue * ast_function_expression::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -1222,8 +1778,6 @@ ast_function_expression::hir(exec_list *instructions, * 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. */ if (is_constructor()) { const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0]; @@ -1239,23 +1793,22 @@ 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); } - /* Constructors for samplers are illegal. + /* Constructors for opaque types are illegal. */ - if (constructor_type->is_sampler()) { - _mesa_glsl_error(& loc, state, "cannot construct sampler type `%s'", + if (constructor_type->contains_opaque()) { + _mesa_glsl_error(& loc, state, "cannot construct opaque 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); + if (!state->check_version(120, 300, &loc, + "array constructors forbidden")) { + return ir_rvalue::error_value(ctx); } return process_array_constructor(instructions, constructor_type, @@ -1263,67 +1816,28 @@ ast_function_expression::hir(exec_list *instructions, } - /* There are two kinds of constructor call. Constructors for built-in - * language types, such as mat4 and vec2, are free form. The only - * requirement is that the parameters must provide enough values of the - * correct scalar type. Constructors for arrays and structures must - * have the exact number of parameters with matching types in the - * correct order. These constructors follow essentially the same type - * matching rules as functions. + /* There are two kinds of constructor calls. Constructors for arrays and + * structures must have the exact number of arguments with matching types + * in the correct order. These constructors follow essentially the same + * type matching rules as functions. + * + * Constructors for built-in language types, such as mat4 and vec2, are + * free form. The only requirements are that the parameters must provide + * enough values of the correct scalar type and that no arguments are + * given past the last used argument. + * + * When using the C-style initializer syntax from GLSL 4.20, constructors + * must have the exact number of arguments with matching types in the + * correct order. */ if (constructor_type->is_record()) { - exec_list actual_parameters; - - process_parameters(instructions, &actual_parameters, - &this->expressions, state); - - exec_node *node = actual_parameters.head; - for (unsigned i = 0; i < constructor_type->length; i++) { - ir_rvalue *ir = (ir_rvalue *) node; - - if (node->is_tail_sentinel()) { - _mesa_glsl_error(&loc, state, - "insufficient parameters to constructor " - "for `%s'", - constructor_type->name); - return ir_call::get_error_instruction(ctx); - } - - if (apply_implicit_conversion(constructor_type->fields.structure[i].type, - ir, state)) { - node->replace_with(ir); - } else { - _mesa_glsl_error(&loc, state, - "parameter type mismatch in constructor " - "for `%s.%s' (%s vs %s)", - constructor_type->name, - constructor_type->fields.structure[i].name, - ir->type->name, - constructor_type->fields.structure[i].type->name); - return ir_call::get_error_instruction(ctx);; - } - - node = node->next; - } - - 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); - } - - ir_rvalue *const constant = - constant_record_constructor(constructor_type, &actual_parameters, - state); - - return (constant != NULL) - ? constant - : emit_inline_record_constructor(constructor_type, instructions, - &actual_parameters, state); + return process_record_constructor(instructions, constructor_type, + &loc, &this->expressions, + state); } 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(); @@ -1337,9 +1851,8 @@ ast_function_expression::hir(exec_list *instructions, unsigned nonmatrix_parameters = 0; exec_list actual_parameters; - foreach_list (n, &this->expressions) { - ast_node *ast = exec_node_data(ast_node, n, link); - ir_rvalue *result = ast->hir(instructions, state)->as_rvalue(); + foreach_list_typed(ast_node, ast, link, &this->expressions) { + ir_rvalue *result = ast->hir(instructions, state); /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec: * @@ -1350,14 +1863,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 @@ -1377,12 +1890,12 @@ ast_function_expression::hir(exec_list *instructions, * "It is an error to construct matrices from other matrices. This * is reserved for future use." */ - if (state->language_version == 110 && matrix_parameters > 0 - && constructor_type->is_matrix()) { - _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); + if (matrix_parameters > 0 + && constructor_type->is_matrix() + && !state->check_version(120, 100, &loc, + "cannot construct `%s' from a matrix", + constructor_type->name)) { + return ir_rvalue::error_value(ctx); } /* From page 50 (page 56 of the PDF) of the GLSL 1.50 spec: @@ -1396,7 +1909,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: @@ -1410,17 +1923,15 @@ 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 - * constructor. Since there are no non-floating point matrices, we - * need to break them up into a series of column vectors. + /* Matrices can never be consumed as is by any constructor but matrix + * constructors. If the constructor type is not matrix, always break the + * matrix up into a series of column vectors. */ - if (constructor_type->base_type != GLSL_TYPE_FLOAT) { - foreach_list_safe(n, &actual_parameters) { - ir_rvalue *matrix = (ir_rvalue *) n; - + if (!constructor_type->is_matrix()) { + foreach_in_list_safe(ir_rvalue, matrix, &actual_parameters) { if (!matrix->type->is_matrix()) continue; @@ -1444,9 +1955,7 @@ ast_function_expression::hir(exec_list *instructions, bool all_parameters_are_constant = true; /* Type cast each parameter and, if possible, fold constants.*/ - foreach_list_safe(n, &actual_parameters) { - ir_rvalue *ir = (ir_rvalue *) n; - + foreach_in_list_safe(ir_rvalue, ir, &actual_parameters) { const glsl_type *desired_type = glsl_type::get_instance(constructor_type->base_type, ir->type->vector_elements, @@ -1489,33 +1998,99 @@ ast_function_expression::hir(exec_list *instructions, &actual_parameters, ctx); } + } else if (subexpressions[0]->oper == ast_field_selection) { + return handle_method(instructions, state); } else { const ast_expression *id = subexpressions[0]; - const char *func_name = id->primary_expression.identifier; - YYLTYPE loc = id->get_location(); + const char *func_name; + YYLTYPE loc = get_location(); exec_list actual_parameters; + ir_variable *sub_var = NULL; + ir_rvalue *array_idx = NULL; process_parameters(instructions, &actual_parameters, &this->expressions, state); + if (id->oper == ast_array_index) { + array_idx = generate_array_index(ctx, instructions, state, loc, + id->subexpressions[0], + id->subexpressions[1], &func_name, + &actual_parameters); + } else { + func_name = id->primary_expression.identifier; + } + ir_function_signature *sig = match_function_by_name(func_name, &actual_parameters, state); - ir_call *call = NULL; ir_rvalue *value = NULL; + if (sig == NULL) { + sig = match_subroutine_by_name(func_name, &actual_parameters, state, &sub_var); + } + if (sig == NULL) { no_matching_function_error(func_name, &loc, &actual_parameters, state); - value = ir_call::get_error_instruction(ctx); + 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_call::get_error_instruction(ctx); + value = ir_rvalue::error_value(ctx); } else { - value = generate_call(instructions, sig, &loc, &actual_parameters, - &call, state); + value = generate_call(instructions, sig, &actual_parameters, sub_var, array_idx, state); + if (!value) { + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::void_type, + "void_var", + ir_var_temporary); + instructions->push_tail(tmp); + value = new(ctx) ir_dereference_variable(tmp); + } } return value; } - return ir_call::get_error_instruction(ctx); + unreachable("not reached"); +} + +bool +ast_function_expression::has_sequence_subexpression() const +{ + foreach_list_typed(const ast_node, ast, link, &this->expressions) { + if (ast->has_sequence_subexpression()) + return true; + } + + return false; +} + +ir_rvalue * +ast_aggregate_initializer::hir(exec_list *instructions, + struct _mesa_glsl_parse_state *state) +{ + void *ctx = state; + YYLTYPE loc = this->get_location(); + + if (!this->constructor_type) { + _mesa_glsl_error(&loc, state, "type of C-style initializer unknown"); + return ir_rvalue::error_value(ctx); + } + const glsl_type *const constructor_type = this->constructor_type; + + if (!state->ARB_shading_language_420pack_enable) { + _mesa_glsl_error(&loc, state, "C-style initialization requires the " + "GL_ARB_shading_language_420pack extension"); + return ir_rvalue::error_value(ctx); + } + + if (constructor_type->is_array()) { + return process_array_constructor(instructions, constructor_type, &loc, + &this->expressions, state); + } + + if (constructor_type->is_record()) { + return process_record_constructor(instructions, constructor_type, &loc, + &this->expressions, state); + } + + return process_vec_mat_constructor(instructions, constructor_type, &loc, + &this->expressions, state); }