diff options
Diffstat (limited to 'src/glsl/ast_to_hir.cpp')
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 349 |
1 files changed, 309 insertions, 40 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index d615b30..365a6e2 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -60,7 +60,7 @@ void _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) { _mesa_glsl_initialize_variables(instructions, state); - _mesa_glsl_initialize_functions(instructions, state); + _mesa_glsl_initialize_functions(state); state->symbols->language_version = state->language_version; @@ -598,17 +598,15 @@ ir_rvalue * validate_assignment(struct _mesa_glsl_parse_state *state, const glsl_type *lhs_type, ir_rvalue *rhs) { - const glsl_type *rhs_type = rhs->type; - /* If there is already some error in the RHS, just return it. Anything * else will lead to an avalanche of error message back to the user. */ - if (rhs_type->is_error()) + if (rhs->type->is_error()) return rhs; /* If the types are identical, the assignment can trivially proceed. */ - if (rhs_type == lhs_type) + if (rhs->type == lhs_type) return rhs; /* If the array element types are the same and the size of the LHS is zero, @@ -625,8 +623,7 @@ validate_assignment(struct _mesa_glsl_parse_state *state, /* Check for implicit conversion in GLSL 1.20 */ if (apply_implicit_conversion(lhs_type, rhs, state)) { - rhs_type = rhs->type; - if (rhs_type == lhs_type) + if (rhs->type == lhs_type) return rhs; } @@ -745,6 +742,94 @@ ast_node::hir(exec_list *instructions, return NULL; } +static void +mark_whole_array_access(ir_rvalue *access) +{ + ir_dereference_variable *deref = access->as_dereference_variable(); + + if (deref) { + deref->var->max_array_access = deref->type->length - 1; + } +} + +static ir_rvalue * +do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1) +{ + int join_op; + ir_rvalue *cmp = NULL; + + if (operation == ir_binop_all_equal) + join_op = ir_binop_logic_and; + else + join_op = ir_binop_logic_or; + + switch (op0->type->base_type) { + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_BOOL: + return new(mem_ctx) ir_expression(operation, op0, op1); + + case GLSL_TYPE_ARRAY: { + for (unsigned int i = 0; i < op0->type->length; i++) { + ir_rvalue *e0, *e1, *result; + + e0 = new(mem_ctx) ir_dereference_array(op0->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + e1 = new(mem_ctx) ir_dereference_array(op1->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + result = do_comparison(mem_ctx, operation, e0, e1); + + if (cmp) { + cmp = new(mem_ctx) ir_expression(join_op, cmp, result); + } else { + cmp = result; + } + } + + mark_whole_array_access(op0); + mark_whole_array_access(op1); + break; + } + + case GLSL_TYPE_STRUCT: { + for (unsigned int i = 0; i < op0->type->length; i++) { + ir_rvalue *e0, *e1, *result; + const char *field_name = op0->type->fields.structure[i].name; + + e0 = new(mem_ctx) ir_dereference_record(op0->clone(mem_ctx, NULL), + field_name); + e1 = new(mem_ctx) ir_dereference_record(op1->clone(mem_ctx, NULL), + field_name); + result = do_comparison(mem_ctx, operation, e0, e1); + + if (cmp) { + cmp = new(mem_ctx) ir_expression(join_op, cmp, result); + } else { + cmp = result; + } + } + break; + } + + case GLSL_TYPE_ERROR: + case GLSL_TYPE_VOID: + case GLSL_TYPE_SAMPLER: + /* I assume a comparison of a struct containing a sampler just + * ignores the sampler present in the type. + */ + break; + + default: + assert(!"Should not get here."); + break; + } + + if (cmp == NULL) + cmp = new(mem_ctx) ir_constant(true); + + return cmp; +} ir_rvalue * ast_expression::hir(exec_list *instructions, @@ -941,11 +1026,10 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, - op[0], op[1]); + result = do_comparison(ctx, operations[this->oper], op[0], op[1]); type = glsl_type::bool_type; - assert(result->type == glsl_type::bool_type); + assert(error_emitted || (result->type == glsl_type::bool_type)); break; case ast_bit_and: @@ -1480,6 +1564,40 @@ ast_expression::hir(exec_list *instructions, } } + /* From page 23 (29 of the PDF) of the GLSL 1.30 spec: + * + * "Samplers aggregated into arrays within a shader (using square + * brackets [ ]) can only be indexed with integral constant + * expressions [...]." + * + * This restriction was added in GLSL 1.30. Shaders using earlier version + * of the language should not be rejected by the compiler front-end for + * using this construct. This allows useful things such as using a loop + * counter as the index to an array of samplers. If the loop in unrolled, + * the code should compile correctly. Instead, emit a warning. + */ + if (array->type->is_array() && + array->type->element_type()->is_sampler() && + const_index == NULL) { + + if (state->language_version == 100) { + _mesa_glsl_warning(&loc, state, + "sampler arrays indexed with non-constant " + "expressions is optional in GLSL ES 1.00"); + } else if (state->language_version < 130) { + _mesa_glsl_warning(&loc, state, + "sampler arrays indexed with non-constant " + "expressions is forbidden in GLSL 1.30 and " + "later"); + } else { + _mesa_glsl_error(&loc, state, + "sampler arrays indexed with non-constant " + "expressions is forbidden in GLSL 1.30 and " + "later"); + error_emitted = true; + } + } + if (error_emitted) result->type = glsl_type::error_type; @@ -1505,6 +1623,7 @@ ast_expression::hir(exec_list *instructions, result = new(ctx) ir_dereference_variable(var); if (var != NULL) { + var->used = true; type = result->type; } else { _mesa_glsl_error(& loc, state, "`%s' undeclared", @@ -1679,8 +1798,16 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, struct _mesa_glsl_parse_state *state, YYLTYPE *loc) { - if (qual->flags.q.invariant) - var->invariant = 1; + if (qual->flags.q.invariant) { + if (var->used) { + _mesa_glsl_error(loc, state, + "variable `%s' may not be redeclared " + "`invariant' after being used", + var->name); + } else { + var->invariant = 1; + } + } /* FINISHME: Mark 'in' variables at global scope as read-only. */ if (qual->flags.q.constant || qual->flags.q.attribute @@ -1734,6 +1861,23 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, else if (qual->flags.q.uniform) var->mode = ir_var_uniform; + if (state->all_invariant && (state->current_function == NULL)) { + switch (state->target) { + case vertex_shader: + if (var->mode == ir_var_out) + var->invariant = true; + break; + case geometry_shader: + if ((var->mode == ir_var_in) || (var->mode == ir_var_out)) + var->invariant = true; + break; + case fragment_shader: + if (var->mode == ir_var_in) + var->invariant = true; + break; + } + } + if (qual->flags.q.flat) var->interpolation = ir_var_flat; else if (qual->flags.q.noperspective) @@ -1813,6 +1957,52 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, } } + /* Does the declaration use the 'layout' keyword? + */ + const bool uses_layout = qual->flags.q.pixel_center_integer + || qual->flags.q.origin_upper_left + || qual->flags.q.explicit_location; + + /* Does the declaration use the deprecated 'attribute' or 'varying' + * keywords? + */ + const bool uses_deprecated_qualifier = qual->flags.q.attribute + || qual->flags.q.varying; + + /* Is the 'layout' keyword used with parameters that allow relaxed checking. + * Many implementations of GL_ARB_fragment_coord_conventions_enable and some + * implementations (only Mesa?) GL_ARB_explicit_attrib_location_enable + * allowed the layout qualifier to be used with 'varying' and 'attribute'. + * These extensions and all following extensions that add the 'layout' + * keyword have been modified to require the use of 'in' or 'out'. + * + * The following extension do not allow the deprecated keywords: + * + * GL_AMD_conservative_depth + * GL_ARB_gpu_shader5 + * GL_ARB_separate_shader_objects + * GL_ARB_tesselation_shader + * GL_ARB_transform_feedback3 + * GL_ARB_uniform_buffer_object + * + * It is unknown whether GL_EXT_shader_image_load_store or GL_NV_gpu_shader5 + * allow layout with the deprecated keywords. + */ + const bool relaxed_layout_qualifier_checking = + state->ARB_fragment_coord_conventions_enable; + + if (uses_layout && uses_deprecated_qualifier) { + if (relaxed_layout_qualifier_checking) { + _mesa_glsl_warning(loc, state, + "`layout' qualifier may not be used with " + "`attribute' or `varying'"); + } else { + _mesa_glsl_error(loc, state, + "`layout' qualifier may not be used with " + "`attribute' or `varying'"); + } + } + if (var->type->is_array() && state->language_version != 110) { var->array_lvalue = true; } @@ -1870,6 +2060,11 @@ ast_declarator_list::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "`%s' cannot be marked invariant, fragment shader " "inputs only\n", decl->identifier); + } else if (earlier->used) { + _mesa_glsl_error(& loc, state, + "variable `%s' may not be redeclared " + "`invariant' after being used", + earlier->name); } else { earlier->invariant = true; } @@ -1939,20 +2134,23 @@ ast_declarator_list::hir(exec_list *instructions, * * Local variables can only use the qualifier const." * - * This is relaxed in GLSL 1.30. + * This is relaxed in GLSL 1.30. It is also relaxed by any extension + * that adds the 'layout' keyword. */ - if (state->language_version < 120) { + if ((state->language_version < 130) + && !state->ARB_explicit_attrib_location_enable + && !state->ARB_fragment_coord_conventions_enable) { if (this->type->qualifier.flags.q.out) { _mesa_glsl_error(& loc, state, "`out' qualifier in declaration of `%s' " - "only valid for function parameters in GLSL 1.10.", - decl->identifier); + "only valid for function parameters in %s.", + decl->identifier, state->version_string); } if (this->type->qualifier.flags.q.in) { _mesa_glsl_error(& loc, state, "`in' qualifier in declaration of `%s' " - "only valid for function parameters in GLSL 1.10.", - decl->identifier); + "only valid for function parameters in %s.", + decl->identifier, state->version_string); } /* FINISHME: Test for other invalid qualifiers. */ } @@ -2060,6 +2258,25 @@ ast_declarator_list::hir(exec_list *instructions, } } + /* Integer vertex outputs must be qualified with 'flat'. + * + * From section 4.3.6 of the GLSL 1.30 spec: + * "If a vertex output is a signed or unsigned integer or integer + * vector, then it must be qualified with the interpolation qualifier + * flat." + */ + if (state->language_version >= 130 + && state->target == vertex_shader + && state->current_function == NULL + && var->type->is_integer() + && var->mode == ir_var_out + && var->interpolation != ir_var_flat) { + + _mesa_glsl_error(&loc, state, "If a vertex output is an integer, " + "then it must be qualified with 'flat'"); + } + + /* Process the initializer and add its instructions to a temporary * list. This list will be added to the instruction stream (below) after * the declaration is added. This is done because in some cases (such as @@ -2143,10 +2360,37 @@ ast_declarator_list::hir(exec_list *instructions, /* Never emit code to initialize a uniform. */ - if (!this->type->qualifier.flags.q.uniform) + const glsl_type *initializer_type; + if (!this->type->qualifier.flags.q.uniform) { result = do_assignment(&initializer_instructions, state, lhs, rhs, this->get_location()); + initializer_type = result->type; + } else + initializer_type = rhs->type; + + /* If the declared variable is an unsized array, it must inherrit + * its full type from the initializer. A declaration such as + * + * uniform float a[] = float[](1.0, 2.0, 3.0, 3.0); + * + * becomes + * + * uniform float a[4] = float[](1.0, 2.0, 3.0, 3.0); + * + * The assignment generated in the if-statement (below) will also + * automatically handle this case for non-uniforms. + * + * If the declared variable is not an array, the types must + * already match exactly. As a result, the type assignment + * here can be done unconditionally. For non-uniforms the call + * to do_assignment can change the type of the initializer (via + * the implicit conversion rules). For uniforms the initializer + * must be a constant expression, and the type of that expression + * was validated above. + */ + var->type = initializer_type; + var->read_only = temp; } } @@ -2219,6 +2463,27 @@ ast_declarator_list::hir(exec_list *instructions, */ earlier->origin_upper_left = var->origin_upper_left; earlier->pixel_center_integer = var->pixel_center_integer; + + /* According to section 4.3.7 of the GLSL 1.30 spec, + * the following built-in varaibles can be redeclared with an + * interpolation qualifier: + * * gl_FrontColor + * * gl_BackColor + * * gl_FrontSecondaryColor + * * gl_BackSecondaryColor + * * gl_Color + * * gl_SecondaryColor + */ + } else if (state->language_version >= 130 + && (strcmp(var->name, "gl_FrontColor") == 0 + || strcmp(var->name, "gl_BackColor") == 0 + || strcmp(var->name, "gl_FrontSecondaryColor") == 0 + || strcmp(var->name, "gl_BackSecondaryColor") == 0 + || strcmp(var->name, "gl_Color") == 0 + || strcmp(var->name, "gl_SecondaryColor") == 0) + && earlier->type == var->type + && earlier->mode == var->mode) { + earlier->interpolation = var->interpolation; } else { YYLTYPE loc = this->get_location(); _mesa_glsl_error(&loc, state, "`%s' redeclared", decl->identifier); @@ -2253,7 +2518,7 @@ ast_declarator_list::hir(exec_list *instructions, * after the initializer if present or immediately after the name * being declared if not." */ - if (!state->symbols->add_variable(var->name, var)) { + if (!state->symbols->add_variable(var)) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(&loc, state, "name `%s' already taken in the " "current scope", decl->identifier); @@ -2393,6 +2658,27 @@ ast_parameter_declarator::parameters_to_hir(exec_list *ast_parameters, } +void +emit_function(_mesa_glsl_parse_state *state, exec_list *instructions, + ir_function *f) +{ + /* Emit the new function header */ + if (state->current_function == NULL) { + instructions->push_tail(f); + } else { + /* IR invariants disallow function declarations or definitions nested + * within other function definitions. Insert the new ir_function + * block in the instruction sequence before the ir_function block + * containing the current ir_function_signature. + */ + ir_function *const curr = + const_cast<ir_function *>(state->current_function->function()); + + curr->insert_before(f); + } +} + + ir_rvalue * ast_function::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -2495,7 +2781,7 @@ ast_function::hir(exec_list *instructions, } } else { f = new(ctx) ir_function(name); - if (!state->symbols->add_function(f->name, f)) { + if (!state->symbols->add_function(f)) { /* This function name shadows a non-function use of the same name. */ YYLTYPE loc = this->get_location(); @@ -2504,24 +2790,7 @@ ast_function::hir(exec_list *instructions, return NULL; } - /* Emit the new function header */ - if (state->current_function == NULL) - instructions->push_tail(f); - else { - /* IR invariants disallow function declarations or definitions nested - * within other function definitions. Insert the new ir_function - * block in the instruction sequence before the ir_function block - * containing the current ir_function_signature. - * - * This can only happen in a GLSL 1.10 shader. In all other GLSL - * versions this nesting is disallowed. There is a check for this at - * the top of this function. - */ - ir_function *const curr = - const_cast<ir_function *>(state->current_function->function()); - - curr->insert_before(f); - } + emit_function(state, instructions, f); } /* Verify the return type of main() */ @@ -2587,7 +2856,7 @@ ast_function_definition::hir(exec_list *instructions, _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name); } else { - state->symbols->add_variable(var->name, var); + state->symbols->add_variable(var); } } |