diff options
Diffstat (limited to 'src/glsl/loop_analysis.cpp')
-rw-r--r-- | src/glsl/loop_analysis.cpp | 92 |
1 files changed, 67 insertions, 25 deletions
diff --git a/src/glsl/loop_analysis.cpp b/src/glsl/loop_analysis.cpp index b08241af527..9f1b1d2b1f9 100644 --- a/src/glsl/loop_analysis.cpp +++ b/src/glsl/loop_analysis.cpp @@ -33,6 +33,43 @@ static bool all_expression_operands_are_loop_constant(ir_rvalue *, static ir_rvalue *get_basic_induction_increment(ir_assignment *, hash_table *); +/** + * Record the fact that the given loop variable was referenced inside the loop. + * + * \arg in_assignee is true if the reference was on the LHS of an assignment. + * + * \arg in_conditional_code is true if the reference occurred inside an if + * statement. + * + * \arg current_assignment is the ir_assignment node that the loop variable is + * on the LHS of, if any (ignored if \c in_assignee is false). + */ +void +loop_variable::record_reference(bool in_assignee, bool in_conditional_code, + ir_assignment *current_assignment) +{ + if (in_assignee) { + assert(current_assignment != NULL); + + this->conditional_assignment = in_conditional_code + || current_assignment->condition != NULL; + + if (this->first_assignment == NULL) { + assert(this->num_assignments == 0); + + this->first_assignment = current_assignment; + } + + this->num_assignments++; + } else if (this->first_assignment == current_assignment) { + /* This catches the case where the variable is used in the RHS of an + * assignment where it is also in the LHS. + */ + this->read_before_write = true; + } +} + + loop_state::loop_state() { this->ht = hash_table_ctor(0, hash_table_pointer_hash, @@ -102,6 +139,33 @@ loop_variable_state::insert(ir_if *if_stmt) return t; } + +/** + * If the given variable already is recorded in the state for this loop, + * return the corresponding loop_variable object that records information + * about it. + * + * Otherwise, create a new loop_variable object to record information about + * the variable, and set its \c read_before_write field appropriately based on + * \c in_assignee. + * + * \arg in_assignee is true if this variable was encountered on the LHS of an + * assignment. + */ +loop_variable * +loop_variable_state::get_or_insert(ir_variable *var, bool in_assignee) +{ + loop_variable *lv = this->get(var); + + if (lv == NULL) { + lv = this->insert(var); + lv->read_before_write = !in_assignee; + } + + return lv; +} + + namespace { class loop_analysis : public ir_hierarchical_visitor { @@ -181,32 +245,10 @@ loop_analysis::visit(ir_dereference_variable *ir) (loop_variable_state *) this->state.get_head(); ir_variable *var = ir->variable_referenced(); - loop_variable *lv = ls->get(var); - - if (lv == NULL) { - lv = ls->insert(var); - lv->read_before_write = !this->in_assignee; - } - - if (this->in_assignee) { - assert(this->current_assignment != NULL); + loop_variable *lv = ls->get_or_insert(var, this->in_assignee); - lv->conditional_assignment = (this->if_statement_depth > 0) - || (this->current_assignment->condition != NULL); - - if (lv->first_assignment == NULL) { - assert(lv->num_assignments == 0); - - lv->first_assignment = this->current_assignment; - } - - lv->num_assignments++; - } else if (lv->first_assignment == this->current_assignment) { - /* This catches the case where the variable is used in the RHS of an - * assignment where it is also in the LHS. - */ - lv->read_before_write = true; - } + lv->record_reference(this->in_assignee, this->if_statement_depth > 0, + this->current_assignment); return visit_continue; } |