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:
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user