diff options
author | marha <marha@users.sourceforge.net> | 2012-05-21 09:28:15 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2012-05-21 09:28:15 +0200 |
commit | d4b066581bc9a4bf7b0a5ffa11ff0adb47d2075c (patch) | |
tree | db56fe01d61a824e4bd975cbf8603b11e9c5ecdf /mesalib/src/glsl | |
parent | d2dacc6bc44f7dc245dee6e66723013afb49cfb5 (diff) | |
parent | f543ceaca6820260f15a4eff86938214cf43c7d2 (diff) | |
download | vcxsrv-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.cpp | 577 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_dead_code_local.cpp | 149 |
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); } } |