glsl/ast: Explicitly track the set of case labels that occur after default

Previously the instruction stream was walked looking for comparisons
with case-label values.  This should generate nearly identical code.
For at least fs-default-notlast-fallthrough.shader_test, the code is
identical.

This change will make later changes possible.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
This commit is contained in:
Ian Romanick
2017-09-19 15:47:52 -05:00
parent f307de2838
commit 3e5cd2aba9

View File

@@ -6365,13 +6365,28 @@ ast_selection_statement::hir(exec_list *instructions,
} }
struct case_label {
/** Value of the case label. */
unsigned value;
/** Does this label occur after the default? */
bool after_default;
/**
* AST for the case label.
*
* This is only used to generate error messages for duplicate labels.
*/
ast_expression *ast;
};
/* Used for detection of duplicate case values, compare /* Used for detection of duplicate case values, compare
* given contents directly. * given contents directly.
*/ */
static bool static bool
compare_case_value(const void *a, const void *b) compare_case_value(const void *a, const void *b)
{ {
return *(unsigned *) a == *(unsigned *) b; return ((struct case_label *) a)->value == ((struct case_label *) b)->value;
} }
@@ -6381,7 +6396,7 @@ compare_case_value(const void *a, const void *b)
static unsigned static unsigned
key_contents(const void *key) key_contents(const void *key)
{ {
return *(unsigned *) key; return ((struct case_label *) key)->value;
} }
@@ -6582,24 +6597,26 @@ ast_case_statement_list::hir(exec_list *instructions,
return NULL; return NULL;
} }
foreach_in_list(ir_instruction, ir, &after_default) { struct hash_entry *entry;
ir_assignment *assign = ir->as_assignment(); ir_factory body(instructions, state);
if (!assign) hash_table_foreach(state->switch_state.labels_ht, entry) {
continue; const struct case_label *const l = (struct case_label *) entry->data;
/* Clone the check between case label and init expression. */ /* If the switch init-value is the value of one of the labels that
ir_expression *exp = (ir_expression*) assign->condition; * occurs after the default case, disable execution of the default
ir_expression *clone = exp->clone(state, NULL); * case.
*/
if (l->after_default) {
ir_constant *const cnst =
state->switch_state.test_var->type->base_type == GLSL_TYPE_UINT
? body.constant(unsigned(l->value))
: body.constant(int(l->value));
ir_dereference_variable *deref_var = body.emit(assign(state->switch_state.run_default,
new(state) ir_dereference_variable(state->switch_state.run_default); body.constant(false),
ir_rvalue *const false_val = new (state) ir_constant(false); equal(cnst, state->switch_state.test_var)));
}
ir_assignment *const set_false =
new(state) ir_assignment(deref_var, false_val, clone);
instructions->push_tail(set_false);
} }
/* Append default case and all cases after it. */ /* Append default case and all cases after it. */
@@ -6672,19 +6689,29 @@ ast_case_label::hir(exec_list *instructions,
} else { } else {
hash_entry *entry = hash_entry *entry =
_mesa_hash_table_search(state->switch_state.labels_ht, _mesa_hash_table_search(state->switch_state.labels_ht,
(void *)(uintptr_t)&label_const->value.u[0]); &label_const->value.u[0]);
if (entry) { if (entry) {
ast_expression *previous_label = (ast_expression *) entry->data; const struct case_label *const l =
(struct case_label *) entry->data;
const ast_expression *const previous_label = l->ast;
YYLTYPE loc = this->test_value->get_location(); YYLTYPE loc = this->test_value->get_location();
_mesa_glsl_error(& loc, state, "duplicate case value"); _mesa_glsl_error(& loc, state, "duplicate case value");
loc = previous_label->get_location(); loc = previous_label->get_location();
_mesa_glsl_error(& loc, state, "this is the previous case label"); _mesa_glsl_error(& loc, state, "this is the previous case label");
} else { } else {
struct case_label *l = ralloc(state->switch_state.labels_ht,
struct case_label);
l->value = label_const->value.u[0];
l->after_default = state->switch_state.previous_default != NULL;
l->ast = this->test_value;
_mesa_hash_table_insert(state->switch_state.labels_ht, _mesa_hash_table_insert(state->switch_state.labels_ht,
(void *)(uintptr_t)&label_const->value.u[0], &label_const->value.u[0],
this->test_value); l);
} }
} }