_mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
{
_mesa_glsl_initialize_variables(instructions, state);
- _mesa_glsl_initialize_functions(state);
state->symbols->language_version = state->language_version;
state->current_function = NULL;
+ state->toplevel_ir = instructions;
+
/* Section 4.2 of the GLSL 1.20 specification states:
* "The built-in functions are scoped in a scope outside the global scope
* users declare global variables in. That is, a shader's global scope,
ast->hir(instructions, state);
detect_recursion_unlinked(state, instructions);
+
+ state->toplevel_ir = NULL;
}
return NULL;
}
+static void
+mark_whole_array_access(ir_rvalue *access)
+{
+ ir_dereference_variable *deref = access->as_dereference_variable();
+
+ if (deref && deref->var) {
+ deref->var->max_array_access = deref->type->length - 1;
+ }
+}
+
ir_rvalue *
do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
+ const char *non_lvalue_description,
ir_rvalue *lhs, ir_rvalue *rhs, bool is_initializer,
YYLTYPE lhs_loc)
{
bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
if (!error_emitted) {
- if (lhs->variable_referenced() != NULL
- && lhs->variable_referenced()->read_only) {
+ if (non_lvalue_description != NULL) {
+ _mesa_glsl_error(&lhs_loc, state,
+ "assignment to %s",
+ non_lvalue_description);
+ error_emitted = true;
+ } else if (lhs->variable_referenced() != NULL
+ && lhs->variable_referenced()->read_only) {
_mesa_glsl_error(&lhs_loc, state,
"assignment to read-only variable '%s'",
lhs->variable_referenced()->name);
error_emitted = true;
+ } else if (state->language_version <= 110 && lhs->type->is_array()) {
+ /* From page 32 (page 38 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "Other binary or unary expressions, non-dereferenced
+ * arrays, function names, swizzles with repeated fields,
+ * and constants cannot be l-values."
+ */
+ _mesa_glsl_error(&lhs_loc, state, "whole array assignment is not "
+ "allowed in GLSL 1.10 or GLSL ES 1.00.");
+ error_emitted = true;
} else if (!lhs->is_lvalue()) {
_mesa_glsl_error(& lhs_loc, state, "non-lvalue in assignment");
error_emitted = true;
}
-
- if (state->es_shader && lhs->type->is_array()) {
- _mesa_glsl_error(&lhs_loc, state, "whole array assignment is not "
- "allowed in GLSL ES 1.00.");
- error_emitted = true;
- }
}
ir_rvalue *new_rhs =
rhs->type->array_size());
d->type = var->type;
}
+ mark_whole_array_access(rhs);
+ mark_whole_array_access(lhs);
}
/* Most callers of do_assignment (assign, add_assign, pre_inc/dec,
instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
lvalue, NULL));
- /* Once we've created this temporary, mark it read only so it's no
- * longer considered an lvalue.
- */
- var->read_only = true;
-
return new(ctx) ir_dereference_variable(var);
}
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)
{
return new(ctx) ir_constant(true);
}
+/**
+ * If name refers to a builtin array whose maximum allowed size is less than
+ * size, report an error and return true. Otherwise return false.
+ */
+static bool
+check_builtin_array_max_size(const char *name, unsigned size,
+ YYLTYPE loc, struct _mesa_glsl_parse_state *state)
+{
+ if ((strcmp("gl_TexCoord", name) == 0)
+ && (size > state->Const.MaxTextureCoords)) {
+ /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "The size [of gl_TexCoord] can be at most
+ * gl_MaxTextureCoords."
+ */
+ _mesa_glsl_error(&loc, state, "`gl_TexCoord' array size cannot "
+ "be larger than gl_MaxTextureCoords (%u)\n",
+ state->Const.MaxTextureCoords);
+ return true;
+ } else if (strcmp("gl_ClipDistance", name) == 0
+ && size > state->Const.MaxClipPlanes) {
+ /* From section 7.1 (Vertex Shader Special Variables) of the
+ * GLSL 1.30 spec:
+ *
+ * "The gl_ClipDistance array is predeclared as unsized and
+ * must be sized by the shader either redeclaring it with a
+ * size or indexing it only with integral constant
+ * expressions. ... The size can be at most
+ * gl_MaxClipDistances."
+ */
+ _mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot "
+ "be larger than gl_MaxClipDistances (%u)\n",
+ state->Const.MaxClipPlanes);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Create the constant 1, of a which is appropriate for incrementing and
+ * decrementing values of the given GLSL type. For example, if type is vec4,
+ * this creates a constant value of 1.0 having type float.
+ *
+ * If the given type is invalid for increment and decrement operators, return
+ * a floating point 1--the error will be detected later.
+ */
+static ir_rvalue *
+constant_one_for_inc_dec(void *ctx, const glsl_type *type)
+{
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ return new(ctx) ir_constant((unsigned) 1);
+ case GLSL_TYPE_INT:
+ return new(ctx) ir_constant(1);
+ default:
+ case GLSL_TYPE_FLOAT:
+ return new(ctx) ir_constant(1.0f);
+ }
+}
+
ir_rvalue *
ast_expression::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
op[0] = this->subexpressions[0]->hir(instructions, state);
op[1] = this->subexpressions[1]->hir(instructions, state);
- result = do_assignment(instructions, state, op[0], op[1], false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0], op[1], false,
this->subexpressions[0]->get_location());
error_emitted = result->type->is_error();
break;
error_emitted = true;
}
- type = op[0]->type;
+ type = error_emitted ? glsl_type::error_type : op[0]->type;
result = new(ctx) ir_expression(ir_unop_bit_not, type, op[0], NULL);
break;
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = (op[0]->type->is_error());
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = type->is_error();
&loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs, false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
break;
state, &loc);
ir_rvalue *temp_rhs = new(ctx) ir_expression(operations[this->oper],
type, op[0], op[1]);
- result = do_assignment(instructions, state, op[0]->clone(ctx, NULL),
- temp_rhs, false,
+ result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
+ op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
break;
case ast_pre_inc:
case ast_pre_dec: {
+ this->non_lvalue_description = (this->oper == ast_pre_inc)
+ ? "pre-increment operation" : "pre-decrement operation";
+
op[0] = this->subexpressions[0]->hir(instructions, state);
- if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
- op[1] = new(ctx) ir_constant(1.0f);
- else
- op[1] = new(ctx) ir_constant(1);
+ op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
type = arithmetic_result_type(op[0], op[1], false, state, & loc);
op[0], op[1]);
result = do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
error_emitted = op[0]->type->is_error();
case ast_post_inc:
case ast_post_dec: {
+ this->non_lvalue_description = (this->oper == ast_post_inc)
+ ? "post-increment operation" : "post-decrement operation";
op[0] = this->subexpressions[0]->hir(instructions, state);
- if (op[0]->type->base_type == GLSL_TYPE_FLOAT)
- op[1] = new(ctx) ir_constant(1.0f);
- else
- op[1] = new(ctx) ir_constant(1);
+ op[1] = constant_one_for_inc_dec(ctx, op[0]->type);
error_emitted = op[0]->type->is_error() || op[1]->type->is_error();
result = get_lvalue_copy(instructions, op[0]->clone(ctx, NULL));
(void)do_assignment(instructions, state,
+ this->subexpressions[0]->non_lvalue_description,
op[0]->clone(ctx, NULL), temp_rhs, false,
this->subexpressions[0]->get_location());
* FINISHME: array access limits be added to ir_dereference?
*/
ir_variable *const v = array->whole_variable_referenced();
- if ((v != NULL) && (unsigned(idx) > v->max_array_access))
+ if ((v != NULL) && (unsigned(idx) > v->max_array_access)) {
v->max_array_access = idx;
+
+ /* Check whether this access will, as a side effect, implicitly
+ * cause the size of a built-in array to be too large.
+ */
+ if (check_builtin_array_max_size(v->name, idx+1, loc, state))
+ error_emitted = true;
+ }
}
} else if (array->type->array_size() == 0) {
_mesa_glsl_error(&loc, state, "unsized array index must be constant");
{
unsigned length = 0;
- /* FINISHME: Reject delcarations of multidimensional arrays. */
+ /* From page 19 (page 25) of the GLSL 1.20 spec:
+ *
+ * "Only one-dimensional arrays may be declared."
+ */
+ if (base->is_array()) {
+ _mesa_glsl_error(loc, state,
+ "invalid array of `%s' (only one-dimensional arrays "
+ "may be declared)",
+ base->name);
+ return glsl_type::error_type;
+ }
if (array_size != NULL) {
exec_list dummy_instructions;
ir_rvalue *const ir = array_size->hir(& dummy_instructions, state);
YYLTYPE loc = array_size->get_location();
- /* FINISHME: Verify that the grammar forbids side-effects in array
- * FINISHME: sizes. i.e., 'vec4 [x = 12] data'
- */
- assert(dummy_instructions.is_empty());
-
if (ir != NULL) {
if (!ir->type->is_integer()) {
_mesa_glsl_error(& loc, state, "array size must be integer type");
} else {
assert(size->type == ir->type);
length = size->value.u[0];
+
+ /* If the array size is const (and we've verified that
+ * it is) then no instructions should have been emitted
+ * when we converted it to HIR. If they were emitted,
+ * then either the array size isn't const after all, or
+ * we are emitting unnecessary instructions.
+ */
+ assert(dummy_instructions.is_empty());
}
}
}
}
if (qual->flags.q.flat)
- var->interpolation = ir_var_flat;
+ var->interpolation = INTERP_QUALIFIER_FLAT;
else if (qual->flags.q.noperspective)
- var->interpolation = ir_var_noperspective;
+ var->interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
+ else if (qual->flags.q.smooth)
+ var->interpolation = INTERP_QUALIFIER_SMOOTH;
else
- var->interpolation = ir_var_smooth;
+ var->interpolation = INTERP_QUALIFIER_NONE;
var->pixel_center_integer = qual->flags.q.pixel_center_integer;
var->origin_upper_left = qual->flags.q.origin_upper_left;
* The following extension do not allow the deprecated keywords:
*
* GL_AMD_conservative_depth
+ * GL_ARB_conservative_depth
* GL_ARB_gpu_shader5
* GL_ARB_separate_shader_objects
* GL_ARB_tesselation_shader
+ qual->flags.q.depth_less
+ qual->flags.q.depth_unchanged;
if (depth_layout_count > 0
- && !state->AMD_conservative_depth_enable) {
+ && !state->AMD_conservative_depth_enable
+ && !state->ARB_conservative_depth_enable) {
_mesa_glsl_error(loc, state,
- "extension GL_AMD_conservative_depth must be enabled "
+ "extension GL_AMD_conservative_depth or "
+ "GL_ARB_conservative_depth must be enabled "
"to use depth layout qualifiers");
} else if (depth_layout_count > 0
&& strcmp(var->name, "gl_FragDepth") != 0) {
var->depth_layout = ir_depth_layout_unchanged;
else
var->depth_layout = ir_depth_layout_none;
-
- if (var->type->is_array() && state->language_version != 110) {
- var->array_lvalue = true;
- }
}
/**
* FINISHME: required or not.
*/
- /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec:
- *
- * "The size [of gl_TexCoord] can be at most
- * gl_MaxTextureCoords."
- */
const unsigned size = unsigned(var->type->array_size());
- if ((strcmp("gl_TexCoord", var->name) == 0)
- && (size > state->Const.MaxTextureCoords)) {
- _mesa_glsl_error(& loc, state, "`gl_TexCoord' array size cannot "
- "be larger than gl_MaxTextureCoords (%u)\n",
- state->Const.MaxTextureCoords);
- } else if ((size > 0) && (size <= earlier->max_array_access)) {
+ check_builtin_array_max_size(var->name, size, loc, state);
+ if ((size > 0) && (size <= earlier->max_array_access)) {
_mesa_glsl_error(& loc, state, "array size must be > %u due to "
"previous access",
earlier->max_array_access);
earlier->interpolation = var->interpolation;
/* Layout qualifiers for gl_FragDepth. */
- } else if (state->AMD_conservative_depth_enable
+ } else if ((state->AMD_conservative_depth_enable ||
+ state->ARB_conservative_depth_enable)
&& strcmp(var->name, "gl_FragDepth") == 0
&& earlier->type == var->type
&& earlier->mode == var->mode) {
const glsl_type *initializer_type;
if (!type->qualifier.flags.q.uniform) {
result = do_assignment(initializer_instructions, state,
+ NULL,
lhs, rhs, true,
type->get_location());
initializer_type = result->type;
} else
initializer_type = rhs->type;
+ var->constant_initializer = rhs->constant_expression_value();
+ var->has_initializer = true;
+
/* If the declared variable is an unsized array, it must inherrit
* its full type from the initializer. A declaration such as
*
decl_type = this->type->specifier->glsl_type(& type_name, state);
if (this->declarations.is_empty()) {
- /* The only valid case where the declaration list can be empty is when
- * the declaration is setting the default precision of a built-in type
- * (e.g., 'precision highp vec4;').
+ /* If there is no structure involved in the program text, there are two
+ * possible scenarios:
+ *
+ * - The program text contained something like 'vec4;'. This is an
+ * empty declaration. It is valid but weird. Emit a warning.
+ *
+ * - The program text contained something like 'S;' and 'S' is not the
+ * name of a known structure type. This is both invalid and weird.
+ * Emit an error.
+ *
+ * Note that if decl_type is NULL and there is a structure involved,
+ * there must have been some sort of error with the structure. In this
+ * case we assume that an error was already generated on this line of
+ * code for the structure. There is no need to generate an additional,
+ * confusing error.
*/
-
- if (decl_type != NULL) {
- } else {
- _mesa_glsl_error(& loc, state, "incomplete declaration");
+ assert(this->type->specifier->structure == NULL || decl_type != NULL
+ || state->error);
+ if (this->type->specifier->structure == NULL) {
+ if (decl_type != NULL) {
+ _mesa_glsl_warning(&loc, state, "empty declaration");
+ } else {
+ _mesa_glsl_error(&loc, state,
+ "invalid type `%s' in empty declaration",
+ type_name);
+ }
}
}
if (decl->is_array) {
var_type = process_array_type(&loc, decl_type, decl->array_size,
state);
+ if (var_type->is_error())
+ continue;
} else {
var_type = decl_type;
}
&& state->current_function == NULL
&& var->type->is_integer()
&& var->mode == ir_var_out
- && var->interpolation != ir_var_flat) {
+ && var->interpolation != INTERP_QUALIFIER_FLAT) {
_mesa_glsl_error(&loc, state, "If a vertex output is an integer, "
"then it must be qualified with 'flat'");
_mesa_glsl_error(& loc, state,
"identifier `%s' uses reserved `gl_' prefix",
decl->identifier);
+ else if (strstr(decl->identifier, "__")) {
+ /* From page 14 (page 20 of the PDF) of the GLSL 1.10
+ * spec:
+ *
+ * "In addition, all identifiers containing two
+ * consecutive underscores (__) are reserved as
+ * possible future keywords."
+ */
+ _mesa_glsl_error(& loc, state,
+ "identifier `%s' uses reserved `__' string",
+ decl->identifier);
+ }
/* Add the variable to the symbol table. Note that the initializer's
* IR was already processed earlier (though it hasn't been emitted
type = process_array_type(&loc, type, this->array_size, state);
}
- if (type->array_size() == 0) {
+ if (!type->is_error() && type->array_size() == 0) {
_mesa_glsl_error(&loc, state, "arrays passed as parameters must have "
"a declared size.");
type = glsl_type::error_type;
type = glsl_type::error_type;
}
+ /* From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "When calling a function, expressions that do not evaluate to
+ * l-values cannot be passed to parameters declared as out or inout."
+ *
+ * From page 32 (page 38 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "Other binary or unary expressions, non-dereferenced arrays,
+ * function names, swizzles with repeated fields, and constants
+ * cannot be l-values."
+ *
+ * So for GLSL 1.10, passing an array as an out or inout parameter is not
+ * allowed. This restriction is removed in GLSL 1.20, and in GLSL ES.
+ */
+ if ((var->mode == ir_var_inout || var->mode == ir_var_out)
+ && type->is_array() && state->language_version == 110) {
+ _mesa_glsl_error(&loc, state, "Arrays cannot be out or inout parameters in GLSL 1.10");
+ type = glsl_type::error_type;
+ }
+
instructions->push_tail(var);
/* Parameter declarations do not have r-values.
void
-emit_function(_mesa_glsl_parse_state *state, exec_list *instructions,
- ir_function *f)
+emit_function(_mesa_glsl_parse_state *state, 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 invariants disallow function declarations or definitions
+ * nested within other function definitions. But there is no
+ * requirement about the relative order of function declarations
+ * and definitions with respect to one another. So simply insert
+ * the new ir_function block at the end of the toplevel instruction
+ * list.
+ */
+ state->toplevel_ir->push_tail(f);
}
const char *const name = identifier;
+ /* New functions are always added to the top-level IR instruction stream,
+ * so this instruction list pointer is ignored. See also emit_function
+ * (called below).
+ */
+ (void) instructions;
+
/* From page 21 (page 27 of the PDF) of the GLSL 1.20 spec,
*
* "Function declarations (prototypes) cannot occur inside of functions;
return NULL;
}
- emit_function(state, instructions, f);
+ emit_function(state, f);
}
/* Verify the return type of main() */
case ast_break:
case ast_continue:
- /* FINISHME: Handle switch-statements. They cannot contain 'continue',
- * FINISHME: and they use a different IR instruction for 'break'.
- */
- /* FINISHME: Correctly handle the nesting. If a switch-statement is
- * FINISHME: inside a loop, a 'continue' is valid and will bind to the
- * FINISHME: loop.
- */
- if (state->loop_or_switch_nesting == NULL) {
+ if (mode == ast_continue &&
+ state->loop_nesting_ast == NULL) {
YYLTYPE loc = this->get_location();
_mesa_glsl_error(& loc, state,
- "`%s' may only appear in a loop",
- (mode == ast_break) ? "break" : "continue");
- } else {
- ir_loop *const loop = state->loop_or_switch_nesting->as_loop();
+ "continue may only appear in a loop");
+ } else if (mode == ast_break &&
+ state->loop_nesting_ast == NULL &&
+ state->switch_nesting_ast == NULL) {
+ YYLTYPE loc = this->get_location();
- /* Inline the for loop expression again, since we don't know
- * where near the end of the loop body the normal copy of it
+ _mesa_glsl_error(& loc, state,
+ "break may only appear in a loop or a switch");
+ } else {
+ /* For a loop, inline the for loop expression again,
+ * since we don't know where near the end of
+ * the loop body the normal copy of it
* is going to be placed.
*/
- if (mode == ast_continue &&
- state->loop_or_switch_nesting_ast->rest_expression) {
- state->loop_or_switch_nesting_ast->rest_expression->hir(instructions,
- state);
+ if (state->loop_nesting_ast != NULL &&
+ mode == ast_continue &&
+ state->loop_nesting_ast->rest_expression) {
+ state->loop_nesting_ast->rest_expression->hir(instructions,
+ state);
}
- if (loop != NULL) {
- ir_loop_jump *const jump =
+ if (state->is_switch_innermost &&
+ mode == ast_break) {
+ /* Force break out of switch by setting is_break switch state.
+ */
+ ir_variable *const is_break_var = state->is_break_var;
+ ir_dereference_variable *const deref_is_break_var =
+ new(ctx) ir_dereference_variable(is_break_var);
+ ir_constant *const true_val = new(ctx) ir_constant(true);
+ ir_assignment *const set_break_var =
+ new(ctx) ir_assignment(deref_is_break_var,
+ true_val,
+ NULL);
+
+ instructions->push_tail(set_break_var);
+ }
+ else {
+ ir_loop_jump *const jump =
new(ctx) ir_loop_jump((mode == ast_break)
? ir_loop_jump::jump_break
: ir_loop_jump::jump_continue);
}
+ir_rvalue *
+ast_switch_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_rvalue *const test_expression =
+ this->test_expression->hir(instructions, state);
+
+ /* From page 66 (page 55 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "The type of init-expression in a switch statement must be a
+ * scalar integer."
+ *
+ * The checks are separated so that higher quality diagnostics can be
+ * generated for cases where the rule is violated.
+ */
+ if (!test_expression->type->is_integer()) {
+ YYLTYPE loc = this->test_expression->get_location();
+
+ _mesa_glsl_error(& loc,
+ state,
+ "switch-statement expression must be scalar "
+ "integer");
+ }
+
+ /* Track the switch-statement nesting in a stack-like manner.
+ */
+ ir_variable *saved_test_var = state->test_var;
+ ir_variable *saved_is_fallthru_var = state->is_fallthru_var;
+
+ bool save_is_switch_innermost = state->is_switch_innermost;
+ ast_switch_statement *saved_nesting_ast = state->switch_nesting_ast;
+
+ state->is_switch_innermost = true;
+ state->switch_nesting_ast = this;
+
+ /* Initalize is_fallthru state to false.
+ */
+ ir_rvalue *const is_fallthru_val = new (ctx) ir_constant(false);
+ state->is_fallthru_var = new(ctx) ir_variable(glsl_type::bool_type,
+ "switch_is_fallthru_tmp",
+ ir_var_temporary);
+ instructions->push_tail(state->is_fallthru_var);
+
+ ir_dereference_variable *deref_is_fallthru_var =
+ new(ctx) ir_dereference_variable(state->is_fallthru_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var,
+ is_fallthru_val,
+ NULL));
+
+ /* Initalize is_break state to false.
+ */
+ ir_rvalue *const is_break_val = new (ctx) ir_constant(false);
+ state->is_break_var = new(ctx) ir_variable(glsl_type::bool_type,
+ "switch_is_break_tmp",
+ ir_var_temporary);
+ instructions->push_tail(state->is_break_var);
+
+ ir_dereference_variable *deref_is_break_var =
+ new(ctx) ir_dereference_variable(state->is_break_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
+ is_break_val,
+ NULL));
+
+ /* Cache test expression.
+ */
+ test_to_hir(instructions, state);
+
+ /* Emit code for body of switch stmt.
+ */
+ body->hir(instructions, state);
+
+ /* Restore previous nesting before returning.
+ */
+ state->switch_nesting_ast = saved_nesting_ast;
+ state->is_switch_innermost = save_is_switch_innermost;
+
+ state->test_var = saved_test_var;
+ state->is_fallthru_var = saved_is_fallthru_var;
+
+ /* Switch statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+void
+ast_switch_statement::test_to_hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ /* Cache value of test expression.
+ */
+ ir_rvalue *const test_val =
+ test_expression->hir(instructions,
+ state);
+
+ state->test_var = new(ctx) ir_variable(glsl_type::int_type,
+ "switch_test_tmp",
+ ir_var_temporary);
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->test_var);
+
+ instructions->push_tail(state->test_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_test_var,
+ test_val,
+ NULL));
+}
+
+
+ir_rvalue *
+ast_switch_body::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (stmts != NULL)
+ stmts->hir(instructions, state);
+
+ /* Switch bodies do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_statement_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ foreach_list_typed (ast_case_statement, case_stmt, link, & this->cases)
+ case_stmt->hir(instructions, state);
+
+ /* Case statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ labels->hir(instructions, state);
+
+ /* Conditionally set fallthru state based on break state.
+ */
+ ir_constant *const false_val = new(state) ir_constant(false);
+ ir_dereference_variable *const deref_is_fallthru_var =
+ new(state) ir_dereference_variable(state->is_fallthru_var);
+ ir_dereference_variable *const deref_is_break_var =
+ new(state) ir_dereference_variable(state->is_break_var);
+ ir_assignment *const reset_fallthru_on_break =
+ new(state) ir_assignment(deref_is_fallthru_var,
+ false_val,
+ deref_is_break_var);
+ instructions->push_tail(reset_fallthru_on_break);
+
+ /* Guard case statements depending on fallthru state.
+ */
+ ir_dereference_variable *const deref_fallthru_guard =
+ new(state) ir_dereference_variable(state->is_fallthru_var);
+ ir_if *const test_fallthru = new(state) ir_if(deref_fallthru_guard);
+
+ foreach_list_typed (ast_node, stmt, link, & this->stmts)
+ stmt->hir(& test_fallthru->then_instructions, state);
+
+ instructions->push_tail(test_fallthru);
+
+ /* Case statements do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_label_list::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ foreach_list_typed (ast_case_label, label, link, & this->labels)
+ label->hir(instructions, state);
+
+ /* Case labels do not have r-values.
+ */
+ return NULL;
+}
+
+
+ir_rvalue *
+ast_case_label::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ ir_dereference_variable *deref_fallthru_var =
+ new(ctx) ir_dereference_variable(state->is_fallthru_var);
+
+ ir_rvalue *const true_val = new(ctx) ir_constant(true);
+
+ /* If not default case, ...
+ */
+ if (this->test_value != NULL) {
+ /* Conditionally set fallthru state based on
+ * comparison of cached test expression value to case label.
+ */
+ ir_rvalue *const test_val = this->test_value->hir(instructions, state);
+
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->test_var);
+
+ ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal,
+ glsl_type::bool_type,
+ test_val,
+ deref_test_var);
+
+ ir_assignment *set_fallthru_on_test =
+ new(ctx) ir_assignment(deref_fallthru_var,
+ true_val,
+ test_cond);
+
+ instructions->push_tail(set_fallthru_on_test);
+ } else { /* default case */
+ /* Set falltrhu state.
+ */
+ ir_assignment *set_fallthru =
+ new(ctx) ir_assignment(deref_fallthru_var,
+ true_val,
+ NULL);
+
+ instructions->push_tail(set_fallthru);
+ }
+
+ /* Case statements do not have r-values.
+ */
+ return NULL;
+}
+
+
void
ast_iteration_statement::condition_to_hir(ir_loop *stmt,
struct _mesa_glsl_parse_state *state)
ir_loop *const stmt = new(ctx) ir_loop();
instructions->push_tail(stmt);
- /* Track the current loop and / or switch-statement nesting.
+ /* Track the current loop nesting.
*/
- ir_instruction *const nesting = state->loop_or_switch_nesting;
- ast_iteration_statement *nesting_ast = state->loop_or_switch_nesting_ast;
+ ast_iteration_statement *nesting_ast = state->loop_nesting_ast;
+
+ state->loop_nesting_ast = this;
- state->loop_or_switch_nesting = stmt;
- state->loop_or_switch_nesting_ast = this;
+ /* Likewise, indicate that following code is closest to a loop,
+ * NOT closest to a switch.
+ */
+ bool saved_is_switch_innermost = state->is_switch_innermost;
+ state->is_switch_innermost = false;
if (mode != ast_do_while)
condition_to_hir(stmt, state);
/* Restore previous nesting before returning.
*/
- state->loop_or_switch_nesting = nesting;
- state->loop_or_switch_nesting_ast = nesting_ast;
+ state->loop_nesting_ast = nesting_ast;
+ state->is_switch_innermost = saved_is_switch_innermost;
/* Loops do not have r-values.
*/