X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Floop_controls.cpp;h=51804bb5fe8563077fab5efe69326b0b9bca792d;hb=41acdae2e9eedb697a0f91815e201daf92d74ab4;hp=f2e1ecb904daf2cb3cff29f1ccc040cc018a78fe;hpb=3bcfafcf0320ee5407716ff67062e80d162760d4;p=mesa.git diff --git a/src/glsl/loop_controls.cpp b/src/glsl/loop_controls.cpp index f2e1ecb904d..51804bb5fe8 100644 --- a/src/glsl/loop_controls.cpp +++ b/src/glsl/loop_controls.cpp @@ -21,7 +21,7 @@ * DEALINGS IN THE SOFTWARE. */ -#include +#include #include "main/compiler.h" #include "glsl_types.h" #include "loop_analysis.h" @@ -85,7 +85,10 @@ int calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, enum ir_expression_operation op) { - void *mem_ctx = talloc_init(__func__); + if (from == NULL || to == NULL || increment == NULL) + return -1; + + void *mem_ctx = ralloc_context(NULL); ir_expression *const sub = new(mem_ctx) ir_expression(ir_binop_sub, from->type, to, from); @@ -99,9 +102,10 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, return -1; if (!iter->type->is_integer()) { + const ir_expression_operation op = iter->type->is_double() + ? ir_unop_d2i : ir_unop_f2i; ir_rvalue *cast = - new(mem_ctx) ir_expression(ir_unop_f2i, glsl_type::int_type, iter, - NULL); + new(mem_ctx) ir_expression(op, glsl_type::int_type, iter, NULL); iter = cast->constant_expression_value(); } @@ -119,10 +123,24 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, const int bias[] = { -1, 0, 1 }; bool valid_loop = false; - for (unsigned i = 0; i < Elements(bias); i++) { - iter = (increment->type->is_integer()) - ? new(mem_ctx) ir_constant(iter_value + bias[i]) - : new(mem_ctx) ir_constant(float(iter_value + bias[i])); + for (unsigned i = 0; i < ARRAY_SIZE(bias); i++) { + /* Increment may be of type int, uint or float. */ + switch (increment->type->base_type) { + case GLSL_TYPE_INT: + iter = new(mem_ctx) ir_constant(iter_value + bias[i]); + break; + case GLSL_TYPE_UINT: + iter = new(mem_ctx) ir_constant(unsigned(iter_value + bias[i])); + break; + case GLSL_TYPE_FLOAT: + iter = new(mem_ctx) ir_constant(float(iter_value + bias[i])); + break; + case GLSL_TYPE_DOUBLE: + iter = new(mem_ctx) ir_constant(double(iter_value + bias[i])); + break; + default: + unreachable("Unsupported type for loop iterator."); + } ir_expression *const mul = new(mem_ctx) ir_expression(ir_binop_mul, increment->type, iter, @@ -144,10 +162,11 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment, } } - talloc_free(mem_ctx); + ralloc_free(mem_ctx); return (valid_loop) ? iter_value : -1; } +namespace { class loop_control_visitor : public ir_hierarchical_visitor { public: @@ -164,6 +183,7 @@ public: bool progress; }; +} /* anonymous namespace */ ir_visitor_status loop_control_visitor::visit_leave(ir_loop *ir) @@ -178,104 +198,38 @@ loop_control_visitor::visit_leave(ir_loop *ir) return visit_continue; } - /* Search the loop terminating conditions for one of the form 'i < c' where - * i is a loop induction variable, c is a constant, and < is any relative - * operator. - */ - int max_iterations = INT_MAX; - foreach_list(node, &ls->terminators) { - loop_terminator *t = (loop_terminator *) node; - ir_if *if_stmt = t->ir; - - /* If-statements can be either 'if (expr)' or 'if (deref)'. We only care - * about the former here. + if (ls->limiting_terminator != NULL) { + /* If the limiting terminator has an iteration count of zero, then we've + * proven that the loop cannot run, so delete it. */ - ir_expression *cond = if_stmt->condition->as_expression(); - if (cond == NULL) - continue; - - switch (cond->operation) { - case ir_binop_less: - case ir_binop_greater: - case ir_binop_lequal: - case ir_binop_gequal: { - /* The expressions that we care about will either be of the form - * 'counter < limit' or 'limit < counter'. Figure out which is - * which. - */ - ir_rvalue *counter = cond->operands[0]->as_dereference_variable(); - ir_constant *limit = cond->operands[1]->constant_expression_value(); - enum ir_expression_operation cmp = cond->operation; - - if (limit == NULL) { - counter = cond->operands[1]->as_dereference_variable(); - limit = cond->operands[0]->constant_expression_value(); - - switch (cmp) { - case ir_binop_less: cmp = ir_binop_gequal; break; - case ir_binop_greater: cmp = ir_binop_lequal; break; - case ir_binop_lequal: cmp = ir_binop_greater; break; - case ir_binop_gequal: cmp = ir_binop_less; break; - default: assert(!"Should not get here."); - } - } - - if ((counter == NULL) || (limit == NULL)) - break; - - ir_variable *var = counter->variable_referenced(); - - ir_rvalue *init = find_initial_value(ir, var); - - foreach_list(iv_node, &ls->induction_variables) { - loop_variable *lv = (loop_variable *) iv_node; - - if (lv->var == var) { - const int iterations = calculate_iterations(init, limit, - lv->increment, - cmp); - if (iterations >= 0) { - /* If the new iteration count is lower than the previously - * believed iteration count, update the loop control values. - */ - if (iterations < max_iterations) { - ir->from = init->clone(ir, NULL); - ir->to = limit->clone(ir, NULL); - ir->increment = lv->increment->clone(ir, NULL); - ir->counter = lv->var; - ir->cmp = cmp; - - max_iterations = iterations; - } - - /* Remove the conditional break statement. The loop - * controls are now set such that the exit condition will be - * satisfied. - */ - if_stmt->remove(); - - assert(ls->num_loop_jumps > 0); - ls->num_loop_jumps--; - - this->progress = true; - } - - break; - } - } - break; - } - - default: - break; + int iterations = ls->limiting_terminator->iterations; + if (iterations == 0) { + ir->remove(); + this->progress = true; + return visit_continue; } } - /* If we have proven the one of the loop exit conditions is satisifed before - * running the loop once, remove the loop. + /* Remove the conditional break statements associated with all terminators + * that are associated with a fixed iteration count, except for the one + * associated with the limiting terminator--that one needs to stay, since + * it terminates the loop. Exception: if the loop still has a normative + * bound, then that terminates the loop, so we don't even need the limiting + * terminator. */ - if (max_iterations == 0) - ir->remove(); + foreach_in_list(loop_terminator, t, &ls->terminators) { + if (t->iterations < 0) + continue; + + if (t != ls->limiting_terminator) { + t->ir->remove(); + + assert(ls->num_loop_jumps > 0); + ls->num_loop_jumps--; + + this->progress = true; + } + } return visit_continue; }