aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2012-05-21 09:28:15 +0200
committermarha <marha@users.sourceforge.net>2012-05-21 09:28:15 +0200
commitd4b066581bc9a4bf7b0a5ffa11ff0adb47d2075c (patch)
treedb56fe01d61a824e4bd975cbf8603b11e9c5ecdf /mesalib/src/glsl
parentd2dacc6bc44f7dc245dee6e66723013afb49cfb5 (diff)
parentf543ceaca6820260f15a4eff86938214cf43c7d2 (diff)
downloadvcxsrv-d4b066581bc9a4bf7b0a5ffa11ff0adb47d2075c.tar.gz
vcxsrv-d4b066581bc9a4bf7b0a5ffa11ff0adb47d2075c.tar.bz2
vcxsrv-d4b066581bc9a4bf7b0a5ffa11ff0adb47d2075c.zip
Merge remote-tracking branch 'origin/released'
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp577
-rw-r--r--mesalib/src/glsl/opt_dead_code_local.cpp149
2 files changed, 399 insertions, 327 deletions
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 86bb8741b..e23718bdb 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -760,13 +760,11 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
ir_var_temporary);
ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
instructions->push_tail(var);
- instructions->push_tail(new(ctx) ir_assignment(deref_var,
- rhs,
- NULL));
+ instructions->push_tail(new(ctx) ir_assignment(deref_var, rhs));
deref_var = new(ctx) ir_dereference_variable(var);
if (!error_emitted)
- instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var, NULL));
+ instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
return new(ctx) ir_dereference_variable(var);
}
@@ -783,7 +781,7 @@ get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue)
var->mode = ir_var_auto;
instructions->push_tail(new(ctx) ir_assignment(new(ctx) ir_dereference_variable(var),
- lvalue, NULL));
+ lvalue));
return new(ctx) ir_dereference_variable(var);
}
@@ -1223,12 +1221,12 @@ ast_expression::hir(exec_list *instructions,
stmt->then_instructions.append_list(&rhs_instructions);
ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, op[1], NULL);
+ new(ctx) ir_assignment(then_deref, op[1]);
stmt->then_instructions.push_tail(then_assign);
ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false), NULL);
+ new(ctx) ir_assignment(else_deref, new(ctx) ir_constant(false));
stmt->else_instructions.push_tail(else_assign);
result = new(ctx) ir_dereference_variable(tmp);
@@ -1258,13 +1256,13 @@ ast_expression::hir(exec_list *instructions,
ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true), NULL);
+ new(ctx) ir_assignment(then_deref, new(ctx) ir_constant(true));
stmt->then_instructions.push_tail(then_assign);
stmt->else_instructions.append_list(&rhs_instructions);
ir_dereference *const else_deref = new(ctx) ir_dereference_variable(tmp);
ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, op[1], NULL);
+ new(ctx) ir_assignment(else_deref, op[1]);
stmt->else_instructions.push_tail(else_assign);
result = new(ctx) ir_dereference_variable(tmp);
@@ -1452,14 +1450,14 @@ ast_expression::hir(exec_list *instructions,
ir_dereference *const then_deref =
new(ctx) ir_dereference_variable(tmp);
ir_assignment *const then_assign =
- new(ctx) ir_assignment(then_deref, op[1], NULL);
+ new(ctx) ir_assignment(then_deref, op[1]);
stmt->then_instructions.push_tail(then_assign);
else_instructions.move_nodes_to(& stmt->else_instructions);
ir_dereference *const else_deref =
new(ctx) ir_dereference_variable(tmp);
ir_assignment *const else_assign =
- new(ctx) ir_assignment(else_deref, op[2], NULL);
+ new(ctx) ir_assignment(else_deref, op[2]);
stmt->else_instructions.push_tail(else_assign);
result = new(ctx) ir_dereference_variable(tmp);
@@ -3438,9 +3436,7 @@ ast_jump_statement::hir(exec_list *instructions,
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);
+ new(ctx) ir_assignment(deref_is_break_var, true_val);
instructions->push_tail(set_break_var);
}
@@ -3521,11 +3517,9 @@ ast_switch_statement::hir(exec_list *instructions,
*
* "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()) {
+ if (!test_expression->type->is_scalar() ||
+ !test_expression->type->is_integer()) {
YYLTYPE loc = this->test_expression->get_location();
_mesa_glsl_error(& loc,
@@ -3556,8 +3550,7 @@ ast_switch_statement::hir(exec_list *instructions,
ir_dereference_variable *deref_is_fallthru_var =
new(ctx) ir_dereference_variable(state->switch_state.is_fallthru_var);
instructions->push_tail(new(ctx) ir_assignment(deref_is_fallthru_var,
- is_fallthru_val,
- NULL));
+ is_fallthru_val));
/* Initalize is_break state to false.
*/
@@ -3570,13 +3563,12 @@ ast_switch_statement::hir(exec_list *instructions,
ir_dereference_variable *deref_is_break_var =
new(ctx) ir_dereference_variable(state->switch_state.is_break_var);
instructions->push_tail(new(ctx) ir_assignment(deref_is_break_var,
- is_break_val,
- NULL));
+ is_break_val));
/* Cache test expression.
*/
test_to_hir(instructions, state);
-
+
/* Emit code for body of switch stmt.
*/
body->hir(instructions, state);
@@ -3585,290 +3577,267 @@ ast_switch_statement::hir(exec_list *instructions,
state->switch_state = saved;
- /* 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->switch_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->switch_state.test_var);
-
- instructions->push_tail(state->switch_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->switch_state.is_fallthru_var);
- ir_dereference_variable *const deref_is_break_var =
- new(state) ir_dereference_variable(state->switch_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->switch_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->switch_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 label_rval = this->test_value->hir(instructions, state);
- ir_constant *label_const = label_rval->constant_expression_value();
-
- if (!label_const) {
- YYLTYPE loc = this->test_value->get_location();
-
- _mesa_glsl_error(& loc, state,
- "switch statement case label must be a "
- "constant expression");
-
- /* Stuff a dummy value in to allow processing to continue. */
- label_const = new(ctx) ir_constant(0);
- } else {
- ast_expression *previous_label = (ast_expression *)
- hash_table_find(state->switch_state.labels_ht,
+ /* 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->switch_state.test_var = new(ctx) ir_variable(test_val->type,
+ "switch_test_tmp",
+ ir_var_temporary);
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->switch_state.test_var);
+
+ instructions->push_tail(state->switch_state.test_var);
+ instructions->push_tail(new(ctx) ir_assignment(deref_test_var, test_val));
+}
+
+
+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->switch_state.is_fallthru_var);
+ ir_dereference_variable *const deref_is_break_var =
+ new(state) ir_dereference_variable(state->switch_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->switch_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->switch_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 label_rval = this->test_value->hir(instructions, state);
+ ir_constant *label_const = label_rval->constant_expression_value();
+
+ if (!label_const) {
+ YYLTYPE loc = this->test_value->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "switch statement case label must be a "
+ "constant expression");
+
+ /* Stuff a dummy value in to allow processing to continue. */
+ label_const = new(ctx) ir_constant(0);
+ } else {
+ ast_expression *previous_label = (ast_expression *)
+ hash_table_find(state->switch_state.labels_ht,
+ (void *)(uintptr_t)label_const->value.u[0]);
+
+ if (previous_label) {
+ YYLTYPE loc = this->test_value->get_location();
+ _mesa_glsl_error(& loc, state,
+ "duplicate case value");
+
+ loc = previous_label->get_location();
+ _mesa_glsl_error(& loc, state,
+ "this is the previous case label");
+ } else {
+ hash_table_insert(state->switch_state.labels_ht,
+ this->test_value,
(void *)(uintptr_t)label_const->value.u[0]);
+ }
+ }
+
+ ir_dereference_variable *deref_test_var =
+ new(ctx) ir_dereference_variable(state->switch_state.test_var);
+
+ ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal,
+ label_const,
+ 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 */
+ if (state->switch_state.previous_default) {
+ printf("a\n");
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(& loc, state,
+ "multiple default labels in one switch");
+
+ printf("b\n");
+
+ loc = state->switch_state.previous_default->get_location();
+ _mesa_glsl_error(& loc, state,
+ "this is the first default label");
+ }
+ state->switch_state.previous_default = this;
+
+ /* Set falltrhu state. */
+ ir_assignment *set_fallthru =
+ new(ctx) ir_assignment(deref_fallthru_var, true_val);
+
+ instructions->push_tail(set_fallthru);
+ }
- if (previous_label) {
- YYLTYPE loc = this->test_value->get_location();
- _mesa_glsl_error(& loc, state,
- "duplicate case value");
-
- loc = previous_label->get_location();
- _mesa_glsl_error(& loc, state,
- "this is the previous case label");
- } else {
- hash_table_insert(state->switch_state.labels_ht,
- this->test_value,
- (void *)(uintptr_t)label_const->value.u[0]);
- }
- }
-
- ir_dereference_variable *deref_test_var =
- new(ctx) ir_dereference_variable(state->switch_state.test_var);
-
- ir_rvalue *const test_cond = new(ctx) ir_expression(ir_binop_all_equal,
- glsl_type::bool_type,
- label_const,
- 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 */
- if (state->switch_state.previous_default) {
- printf("a\n");
- YYLTYPE loc = this->get_location();
- _mesa_glsl_error(& loc, state,
- "multiple default labels in one switch");
-
- printf("b\n");
-
- loc = state->switch_state.previous_default->get_location();
- _mesa_glsl_error(& loc, state,
- "this is the first default label");
- }
- state->switch_state.previous_default = this;
-
- /* 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)
- {
- void *ctx = state;
-
- if (condition != NULL) {
- ir_rvalue *const cond =
- condition->hir(& stmt->body_instructions, state);
-
- if ((cond == NULL)
- || !cond->type->is_boolean() || !cond->type->is_scalar()) {
- YYLTYPE loc = condition->get_location();
-
- _mesa_glsl_error(& loc, state,
- "loop condition must be scalar boolean");
- } else {
- /* As the first code in the loop body, generate a block that looks
- * like 'if (!condition) break;' as the loop termination condition.
- */
- ir_rvalue *const not_cond =
- new(ctx) ir_expression(ir_unop_logic_not, glsl_type::bool_type, cond,
- NULL);
-
- ir_if *const if_stmt = new(ctx) ir_if(not_cond);
-
- ir_jump *const break_stmt =
- new(ctx) ir_loop_jump(ir_loop_jump::jump_break);
-
- if_stmt->then_instructions.push_tail(break_stmt);
- stmt->body_instructions.push_tail(if_stmt);
- }
- }
- }
-
-
- ir_rvalue *
- ast_iteration_statement::hir(exec_list *instructions,
- struct _mesa_glsl_parse_state *state)
- {
- void *ctx = state;
-
- /* For-loops and while-loops start a new scope, but do-while loops do not.
- */
- if (mode != ast_do_while)
- state->symbols->push_scope();
-
- if (init_statement != NULL)
- init_statement->hir(instructions, state);
-
- ir_loop *const stmt = new(ctx) ir_loop();
- instructions->push_tail(stmt);
-
- /* Track the current loop nesting.
- */
- ast_iteration_statement *nesting_ast = state->loop_nesting_ast;
-
- state->loop_nesting_ast = this;
-
- /* Likewise, indicate that following code is closest to a loop,
- * NOT closest to a switch.
- */
- bool saved_is_switch_innermost = state->switch_state.is_switch_innermost;
- state->switch_state.is_switch_innermost = false;
-
- if (mode != ast_do_while)
- condition_to_hir(stmt, state);
-
- if (body != NULL)
- body->hir(& stmt->body_instructions, state);
-
- if (rest_expression != NULL)
- rest_expression->hir(& stmt->body_instructions, state);
+ /* 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)
+{
+ void *ctx = state;
+
+ if (condition != NULL) {
+ ir_rvalue *const cond =
+ condition->hir(& stmt->body_instructions, state);
+
+ if ((cond == NULL)
+ || !cond->type->is_boolean() || !cond->type->is_scalar()) {
+ YYLTYPE loc = condition->get_location();
+
+ _mesa_glsl_error(& loc, state,
+ "loop condition must be scalar boolean");
+ } else {
+ /* As the first code in the loop body, generate a block that looks
+ * like 'if (!condition) break;' as the loop termination condition.
+ */
+ ir_rvalue *const not_cond =
+ new(ctx) ir_expression(ir_unop_logic_not, cond);
+
+ ir_if *const if_stmt = new(ctx) ir_if(not_cond);
+
+ ir_jump *const break_stmt =
+ new(ctx) ir_loop_jump(ir_loop_jump::jump_break);
+
+ if_stmt->then_instructions.push_tail(break_stmt);
+ stmt->body_instructions.push_tail(if_stmt);
+ }
+ }
+}
+
+
+ir_rvalue *
+ast_iteration_statement::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ void *ctx = state;
+
+ /* For-loops and while-loops start a new scope, but do-while loops do not.
+ */
+ if (mode != ast_do_while)
+ state->symbols->push_scope();
+
+ if (init_statement != NULL)
+ init_statement->hir(instructions, state);
+
+ ir_loop *const stmt = new(ctx) ir_loop();
+ instructions->push_tail(stmt);
+
+ /* Track the current loop nesting. */
+ ast_iteration_statement *nesting_ast = state->loop_nesting_ast;
+
+ state->loop_nesting_ast = this;
+
+ /* Likewise, indicate that following code is closest to a loop,
+ * NOT closest to a switch.
+ */
+ bool saved_is_switch_innermost = state->switch_state.is_switch_innermost;
+ state->switch_state.is_switch_innermost = false;
+
+ if (mode != ast_do_while)
+ condition_to_hir(stmt, state);
+
+ if (body != NULL)
+ body->hir(& stmt->body_instructions, state);
+
+ if (rest_expression != NULL)
+ rest_expression->hir(& stmt->body_instructions, state);
+
+ if (mode == ast_do_while)
+ condition_to_hir(stmt, state);
+
+ if (mode != ast_do_while)
+ state->symbols->pop_scope();
- if (mode == ast_do_while)
- condition_to_hir(stmt, state);
-
- if (mode != ast_do_while)
- state->symbols->pop_scope();
-
- /* Restore previous nesting before returning.
- */
- state->loop_nesting_ast = nesting_ast;
- state->switch_state.is_switch_innermost = saved_is_switch_innermost;
+ /* Restore previous nesting before returning. */
+ state->loop_nesting_ast = nesting_ast;
+ state->switch_state.is_switch_innermost = saved_is_switch_innermost;
/* Loops do not have r-values.
*/
diff --git a/mesalib/src/glsl/opt_dead_code_local.cpp b/mesalib/src/glsl/opt_dead_code_local.cpp
index a81a38fff..4af78a72c 100644
--- a/mesalib/src/glsl/opt_dead_code_local.cpp
+++ b/mesalib/src/glsl/opt_dead_code_local.cpp
@@ -43,16 +43,20 @@ static bool debug = false;
class assignment_entry : public exec_node
{
public:
- assignment_entry(ir_variable *lhs, ir_instruction *ir)
+ assignment_entry(ir_variable *lhs, ir_assignment *ir)
{
assert(lhs);
assert(ir);
this->lhs = lhs;
this->ir = ir;
+ this->available = ir->write_mask;
}
ir_variable *lhs;
- ir_instruction *ir;
+ ir_assignment *ir;
+
+ /* bitmask of xyzw channels written that haven't been used so far. */
+ int available;
};
class kill_for_derefs_visitor : public ir_hierarchical_visitor {
@@ -62,23 +66,52 @@ public:
this->assignments = assignments;
}
- virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ void kill_channels(ir_variable *const var, int used)
{
- ir_variable *const var = ir->variable_referenced();
-
foreach_iter(exec_list_iterator, iter, *this->assignments) {
assignment_entry *entry = (assignment_entry *)iter.get();
if (entry->lhs == var) {
- if (debug)
- printf("kill %s\n", entry->lhs->name);
- entry->remove();
+ if (var->type->is_scalar() || var->type->is_vector()) {
+ if (debug)
+ printf("kill %s (0x%01x - 0x%01x)\n", entry->lhs->name,
+ entry->available, used);
+ entry->available &= ~used;
+ if (!entry->available)
+ entry->remove();
+ } else {
+ if (debug)
+ printf("kill %s\n", entry->lhs->name);
+ entry->remove();
+ }
}
}
+ }
+
+ virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ {
+ kill_channels(ir->var, ~0);
return visit_continue;
}
+ virtual ir_visitor_status visit(ir_swizzle *ir)
+ {
+ ir_dereference_variable *deref = ir->val->as_dereference_variable();
+ if (!deref)
+ return visit_continue;
+
+ int used = 0;
+ used |= 1 << ir->mask.x;
+ used |= 1 << ir->mask.y;
+ used |= 1 << ir->mask.z;
+ used |= 1 << ir->mask.w;
+
+ kill_channels(deref->var, used);
+
+ return visit_continue_with_parent;
+ }
+
private:
exec_list *assignments;
};
@@ -130,21 +163,91 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
assert(var);
/* Now, check if we did a whole-variable assignment. */
- if (!ir->condition && (ir->whole_variable_written() != NULL)) {
- /* We did a whole-variable assignment. So, any instruction in
- * the assignment list with the same LHS is dead.
- */
- if (debug)
- printf("looking for %s to remove\n", var->name);
- foreach_iter(exec_list_iterator, iter, *assignments) {
- assignment_entry *entry = (assignment_entry *)iter.get();
+ if (!ir->condition) {
+ ir_dereference_variable *deref_var = ir->lhs->as_dereference_variable();
- if (entry->lhs == var) {
- if (debug)
- printf("removing %s\n", var->name);
- entry->ir->remove();
- entry->remove();
- progress = true;
+ /* If it's a vector type, we can do per-channel elimination of
+ * use of the RHS.
+ */
+ if (deref_var && (deref_var->var->type->is_scalar() ||
+ deref_var->var->type->is_vector())) {
+
+ if (debug)
+ printf("looking for %s.0x%01x to remove\n", var->name,
+ ir->write_mask);
+
+ foreach_iter(exec_list_iterator, iter, *assignments) {
+ assignment_entry *entry = (assignment_entry *)iter.get();
+
+ if (entry->lhs != var)
+ continue;
+
+ int remove = entry->available & ir->write_mask;
+ if (debug) {
+ printf("%s 0x%01x - 0x%01x = 0x%01x\n",
+ var->name,
+ entry->ir->write_mask,
+ remove, entry->ir->write_mask & ~remove);
+ }
+ if (remove) {
+ progress = true;
+
+ if (debug) {
+ printf("rewriting:\n ");
+ entry->ir->print();
+ printf("\n");
+ }
+
+ entry->ir->write_mask &= ~remove;
+ entry->available &= ~remove;
+ if (entry->ir->write_mask == 0) {
+ /* Delete the dead assignment. */
+ entry->ir->remove();
+ entry->remove();
+ } else {
+ void *mem_ctx = ralloc_parent(entry->ir);
+ /* Reswizzle the RHS arguments according to the new
+ * write_mask.
+ */
+ unsigned components[4];
+ unsigned channels = 0;
+ unsigned next = 0;
+
+ for (int i = 0; i < 4; i++) {
+ if ((entry->ir->write_mask | remove) & (1 << i)) {
+ if (!(remove & (1 << i)))
+ components[channels++] = next;
+ next++;
+ }
+ }
+
+ entry->ir->rhs = new(mem_ctx) ir_swizzle(entry->ir->rhs,
+ components,
+ channels);
+ if (debug) {
+ printf("to:\n ");
+ entry->ir->print();
+ printf("\n");
+ }
+ }
+ }
+ }
+ } else if (ir->whole_variable_written() != NULL) {
+ /* We did a whole-variable assignment. So, any instruction in
+ * the assignment list with the same LHS is dead.
+ */
+ if (debug)
+ printf("looking for %s to remove\n", var->name);
+ foreach_iter(exec_list_iterator, iter, *assignments) {
+ assignment_entry *entry = (assignment_entry *)iter.get();
+
+ if (entry->lhs == var) {
+ if (debug)
+ printf("removing %s\n", var->name);
+ entry->ir->remove();
+ entry->remove();
+ progress = true;
+ }
}
}
}
@@ -160,7 +263,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
foreach_iter(exec_list_iterator, iter, *assignments) {
assignment_entry *entry = (assignment_entry *)iter.get();
- printf(" %s\n", entry->lhs->name);
+ printf(" %s (0x%01x)\n", entry->lhs->name, entry->available);
}
}