X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fglsl%2Flower_variable_index_to_cond_assign.cpp;h=c22789c39e3cdaee338a50a7b0c3394e44280d22;hb=1b1b436fa7cf92cce23018ea923597c4d7290d57;hp=278d5450bfb5643ba83918b910a84afb5dcc7b2b;hpb=741744f691d6ef63e9f9a4c03136f969f2ffb0bf;p=mesa.git diff --git a/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp b/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp index 278d5450bfb..c22789c39e3 100644 --- a/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp +++ b/src/compiler/glsl/lower_variable_index_to_cond_assign.cpp @@ -51,6 +51,10 @@ #include "ir_optimization.h" #include "compiler/glsl_types.h" #include "main/macros.h" +#include "program/prog_instruction.h" /* For SWIZZLE_XXXX */ +#include "ir_builder.h" + +using namespace ir_builder; /** * Generate a comparison value for a block of indices @@ -66,23 +70,21 @@ * \param mem_ctx ralloc memory context to be used for all allocations. * * \returns - * An \c ir_rvalue that \b must be cloned for each use in conditional - * assignments, etc. + * An \c ir_variable containing the per-component comparison results. This + * must be dereferenced per use. */ -ir_rvalue * -compare_index_block(exec_list *instructions, ir_variable *index, - unsigned base, unsigned components, void *mem_ctx) +ir_variable * +compare_index_block(ir_factory &body, ir_variable *index, + unsigned base, unsigned components) { - ir_rvalue *broadcast_index = new(mem_ctx) ir_dereference_variable(index); - assert(index->type->is_scalar()); - assert(index->type->base_type == GLSL_TYPE_INT || index->type->base_type == GLSL_TYPE_UINT); + assert(index->type->base_type == GLSL_TYPE_INT || + index->type->base_type == GLSL_TYPE_UINT); assert(components >= 1 && components <= 4); - if (components > 1) { - const ir_swizzle_mask m = { 0, 0, 0, 0, components, false }; - broadcast_index = new(mem_ctx) ir_swizzle(broadcast_index, m); - } + ir_rvalue *const broadcast_index = components > 1 + ? swizzle(index, SWIZZLE_XXXX, components) + : operand(index).val; /* Compare the desired index value with the next block of four indices. */ @@ -94,26 +96,16 @@ compare_index_block(exec_list *instructions, ir_variable *index, test_indices_data.i[3] = base + 3; ir_constant *const test_indices = - new(mem_ctx) ir_constant(broadcast_index->type, - &test_indices_data); - - ir_rvalue *const condition_val = - new(mem_ctx) ir_expression(ir_binop_equal, - glsl_type::bvec(components), - broadcast_index, - test_indices); - - ir_variable *const condition = - new(mem_ctx) ir_variable(condition_val->type, - "dereference_condition", - ir_var_temporary); - instructions->push_tail(condition); - - ir_rvalue *const cond_deref = - new(mem_ctx) ir_dereference_variable(condition); - instructions->push_tail(new(mem_ctx) ir_assignment(cond_deref, condition_val, 0)); - - return cond_deref; + new(body.mem_ctx) ir_constant(broadcast_index->type, &test_indices_data); + + ir_rvalue *const condition_val = equal(broadcast_index, test_indices); + + ir_variable *const condition = body.make_temp(condition_val->type, + "dereference_condition"); + + body.emit(assign(condition, condition_val)); + + return condition; } static inline bool @@ -133,7 +125,7 @@ class deref_replacer : public ir_rvalue_visitor { public: deref_replacer(const ir_variable *variable_to_replace, ir_rvalue *value) : variable_to_replace(variable_to_replace), value(value), - progress(false) + progress(false) { assert(this->variable_to_replace != NULL); assert(this->value != NULL); @@ -143,9 +135,9 @@ public: { ir_dereference_variable *const dv = (*rvalue)->as_dereference_variable(); - if ((dv != NULL) && (dv->var == this->variable_to_replace)) { - this->progress = true; - *rvalue = this->value->clone(ralloc_parent(*rvalue), NULL); + if (dv != NULL && dv->var == this->variable_to_replace) { + this->progress = true; + *rvalue = this->value->clone(ralloc_parent(*rvalue), NULL); } } @@ -167,10 +159,10 @@ public: virtual ir_visitor_status visit_enter(ir_dereference_array *ir) { - if (is_array_or_matrix(ir->array) - && (ir->array_index->as_constant() == NULL)) { - this->deref = ir; - return visit_stop; + if (is_array_or_matrix(ir->array) && + ir->array_index->as_constant() == NULL) { + this->deref = ir; + return visit_stop; } return visit_continue; @@ -201,18 +193,13 @@ struct assignment_generator { } - void generate(unsigned i, ir_rvalue* condition, exec_list *list) const + void generate(unsigned i, ir_rvalue* condition, ir_factory &body) const { - /* Just clone the rest of the deref chain when trying to get at the - * underlying variable. - */ - void *mem_ctx = ralloc_parent(base_ir); - /* Clone the old r-value in its entirety. Then replace any occurances of * the old variable index with the new constant index. */ - ir_dereference *element = this->rvalue->clone(mem_ctx, NULL); - ir_constant *const index = new(mem_ctx) ir_constant(i); + ir_dereference *element = this->rvalue->clone(body.mem_ctx, NULL); + ir_constant *const index = body.constant(i); deref_replacer r(this->old_index, index); element->accept(&r); assert(r.progress); @@ -220,12 +207,11 @@ struct assignment_generator /* Generate a conditional assignment to (or from) the constant indexed * array dereference. */ - ir_rvalue *variable = new(mem_ctx) ir_dereference_variable(this->var); ir_assignment *const assignment = (is_write) - ? new(mem_ctx) ir_assignment(element, variable, condition, write_mask) - : new(mem_ctx) ir_assignment(variable, element, condition); + ? assign(element, this->var, condition, write_mask) + : assign(this->var, element, condition); - list->push_tail(assignment); + body.emit(assignment); } }; @@ -242,16 +228,16 @@ struct switch_generator void *mem_ctx; switch_generator(const TFunction& generator, ir_variable *index, - unsigned linear_sequence_max_length, - unsigned condition_components) + unsigned linear_sequence_max_length, + unsigned condition_components) : generator(generator), index(index), - linear_sequence_max_length(linear_sequence_max_length), - condition_components(condition_components) + linear_sequence_max_length(linear_sequence_max_length), + condition_components(condition_components) { this->mem_ctx = ralloc_parent(index); } - void linear_sequence(unsigned begin, unsigned end, exec_list *list) + void linear_sequence(unsigned begin, unsigned end, ir_factory &body) { if (begin == end) return; @@ -266,66 +252,57 @@ struct switch_generator */ unsigned first; if (!this->generator.is_write) { - this->generator.generate(begin, 0, list); - first = begin + 1; + this->generator.generate(begin, 0, body); + first = begin + 1; } else { - first = begin; + first = begin; } for (unsigned i = first; i < end; i += 4) { const unsigned comps = MIN2(condition_components, end - i); - - ir_rvalue *const cond_deref = - compare_index_block(list, index, i, comps, this->mem_ctx); + ir_variable *const cond = compare_index_block(body, index, i, comps); if (comps == 1) { - this->generator.generate(i, cond_deref->clone(this->mem_ctx, NULL), - list); + this->generator.generate(i, + operand(cond).val, + body); } else { for (unsigned j = 0; j < comps; j++) { - ir_rvalue *const cond_swiz = - new(this->mem_ctx) ir_swizzle(cond_deref->clone(this->mem_ctx, NULL), - j, 0, 0, 0, 1); - - this->generator.generate(i + j, cond_swiz, list); + this->generator.generate(i + j, + swizzle(cond, j, 1), + body); } } } } - void bisect(unsigned begin, unsigned end, exec_list *list) + void bisect(unsigned begin, unsigned end, ir_factory &body) { unsigned middle = (begin + end) >> 1; - assert(index->type->is_integer()); + assert(index->type->is_integer_32()); ir_constant *const middle_c = (index->type->base_type == GLSL_TYPE_UINT) - ? new(this->mem_ctx) ir_constant((unsigned)middle) - : new(this->mem_ctx) ir_constant((int)middle); - + ? new(body.mem_ctx) ir_constant((unsigned)middle) + : new(body.mem_ctx) ir_constant((int)middle); - ir_dereference_variable *deref = - new(this->mem_ctx) ir_dereference_variable(this->index); + ir_if *if_less = new(body.mem_ctx) ir_if(less(this->index, middle_c)); - ir_expression *less = - new(this->mem_ctx) ir_expression(ir_binop_less, glsl_type::bool_type, - deref, middle_c); + ir_factory then_body(&if_less->then_instructions, body.mem_ctx); + ir_factory else_body(&if_less->else_instructions, body.mem_ctx); + generate(begin, middle, then_body); + generate(middle, end, else_body); - ir_if *if_less = new(this->mem_ctx) ir_if(less); - - generate(begin, middle, &if_less->then_instructions); - generate(middle, end, &if_less->else_instructions); - - list->push_tail(if_less); + body.emit(if_less); } - void generate(unsigned begin, unsigned end, exec_list *list) + void generate(unsigned begin, unsigned end, ir_factory &body) { unsigned length = end - begin; if (length <= this->linear_sequence_max_length) - return linear_sequence(begin, end, list); + return linear_sequence(begin, end, body); else - return bisect(begin, end, list); + return bisect(begin, end, body); } }; @@ -340,13 +317,11 @@ public: bool lower_output, bool lower_temp, bool lower_uniform) + : progress(false), stage(stage), lower_inputs(lower_input), + lower_outputs(lower_output), lower_temps(lower_temp), + lower_uniforms(lower_uniform) { - this->progress = false; - this->stage = stage; - this->lower_inputs = lower_input; - this->lower_outputs = lower_output; - this->lower_temps = lower_temp; - this->lower_uniforms = lower_uniform; + /* empty */ } bool progress; @@ -367,24 +342,44 @@ public: */ const ir_variable *const var = deref->array->variable_referenced(); if (var == NULL) - return this->lower_temps; + return this->lower_temps; switch (var->data.mode) { case ir_var_auto: case ir_var_temporary: - return this->lower_temps; + return this->lower_temps; case ir_var_uniform: case ir_var_shader_storage: - return this->lower_uniforms; + return this->lower_uniforms; case ir_var_shader_shared: - return false; + return false; case ir_var_function_in: case ir_var_const_in: return this->lower_temps; + case ir_var_system_value: + /* There are only a few system values that have array types: + * + * gl_TessLevelInner[] + * gl_TessLevelOuter[] + * gl_SampleMaskIn[] + * + * The tessellation factor arrays are lowered to vec4/vec2s + * by lower_tess_level() before this pass occurs, so we'll + * never see them here. + * + * The only remaining case is gl_SampleMaskIn[], which has + * a length of ceil(ctx->Const.MaxSamples / 32). Most hardware + * supports no more than 32 samples, in which case our lowering + * produces a single read of gl_SampleMaskIn[0]. Even with 64x + * MSAA, the array length is only 2, so the lowering is fairly + * efficient. Therefore, lower unconditionally. + */ + return true; + case ir_var_shader_in: /* The input array size is unknown at compiler time for non-patch * inputs in TCS and TES. The arrays are sized to @@ -415,7 +410,7 @@ public: return this->lower_outputs; case ir_var_function_inout: - return this->lower_temps; + return this->lower_temps; } assert(!"Should not get here."); @@ -424,25 +419,27 @@ public: bool needs_lowering(ir_dereference_array *deref) const { - if (deref == NULL || deref->array_index->as_constant() - || !is_array_or_matrix(deref->array)) - return false; + if (deref == NULL || deref->array_index->as_constant() || + !is_array_or_matrix(deref->array)) + return false; return this->storage_type_needs_lowering(deref); } ir_variable *convert_dereference_array(ir_dereference_array *orig_deref, - ir_assignment* orig_assign, - ir_dereference *orig_base) + ir_assignment* orig_assign, + ir_dereference *orig_base) { + void *const mem_ctx = ralloc_parent(base_ir); + exec_list list; + ir_factory body(&list, mem_ctx); + assert(is_array_or_matrix(orig_deref->array)); const unsigned length = (orig_deref->array->type->is_array()) ? orig_deref->array->type->length : orig_deref->array->type->matrix_columns; - void *const mem_ctx = ralloc_parent(base_ir); - /* Temporary storage for either the result of the dereference of * the array, or the RHS that's being assigned into the * dereference of the array. @@ -450,36 +447,22 @@ public: ir_variable *var; if (orig_assign) { - var = new(mem_ctx) ir_variable(orig_assign->rhs->type, - "dereference_array_value", - ir_var_temporary); - base_ir->insert_before(var); - - ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(var); - ir_assignment *assign = new(mem_ctx) ir_assignment(lhs, - orig_assign->rhs, - NULL); + var = body.make_temp(orig_assign->rhs->type, + "dereference_array_value"); - base_ir->insert_before(assign); + body.emit(assign(var, orig_assign->rhs)); } else { - var = new(mem_ctx) ir_variable(orig_deref->type, - "dereference_array_value", - ir_var_temporary); - base_ir->insert_before(var); + var = body.make_temp(orig_deref->type, + "dereference_array_value"); } /* Store the index to a temporary to avoid reusing its tree. */ - ir_variable *index = - new(mem_ctx) ir_variable(orig_deref->array_index->type, - "dereference_array_index", ir_var_temporary); - base_ir->insert_before(index); + ir_variable *index = body.make_temp(orig_deref->array_index->type, + "dereference_array_index"); - ir_dereference *lhs = new(mem_ctx) ir_dereference_variable(index); - ir_assignment *assign = - new(mem_ctx) ir_assignment(lhs, orig_deref->array_index, NULL); - base_ir->insert_before(assign); + body.emit(assign(index, orig_deref->array_index)); - orig_deref->array_index = lhs->clone(mem_ctx, NULL); + orig_deref->array_index = deref(index).val; assignment_generator ag; ag.rvalue = orig_base; @@ -487,10 +470,10 @@ public: ag.old_index = index; ag.var = var; if (orig_assign) { - ag.is_write = true; - ag.write_mask = orig_assign->write_mask; + ag.is_write = true; + ag.write_mask = orig_assign->write_mask; } else { - ag.is_write = false; + ag.is_write = false; } switch_generator sg(ag, index, 4, 4); @@ -499,28 +482,27 @@ public: * condition! This is acomplished by wrapping the new conditional * assignments in an if-statement that uses the original condition. */ - if ((orig_assign != NULL) && (orig_assign->condition != NULL)) { - /* No need to clone the condition because the IR that it hangs on is - * going to be removed from the instruction sequence. - */ - ir_if *if_stmt = new(mem_ctx) ir_if(orig_assign->condition); - - sg.generate(0, length, &if_stmt->then_instructions); - base_ir->insert_before(if_stmt); - } else { - exec_list list; + if (orig_assign != NULL && orig_assign->condition != NULL) { + /* No need to clone the condition because the IR that it hangs on is + * going to be removed from the instruction sequence. + */ + ir_if *if_stmt = new(mem_ctx) ir_if(orig_assign->condition); + ir_factory then_body(&if_stmt->then_instructions, body.mem_ctx); - sg.generate(0, length, &list); - base_ir->insert_before(&list); + sg.generate(0, length, then_body); + body.emit(if_stmt); + } else { + sg.generate(0, length, body); } + base_ir->insert_before(&list); return var; } virtual void handle_rvalue(ir_rvalue **pir) { if (this->in_assignee) - return; + return; if (!*pir) return; @@ -528,7 +510,7 @@ public: ir_dereference_array* orig_deref = (*pir)->as_dereference_array(); if (needs_lowering(orig_deref)) { ir_variable *var = - convert_dereference_array(orig_deref, NULL, orig_deref); + convert_dereference_array(orig_deref, NULL, orig_deref); assert(var); *pir = new(ralloc_parent(base_ir)) ir_dereference_variable(var); this->progress = true; @@ -543,7 +525,7 @@ public: find_variable_index f; ir->lhs->accept(&f); - if ((f.deref != NULL) && storage_type_needs_lowering(f.deref)) { + if (f.deref != NULL && storage_type_needs_lowering(f.deref)) { convert_dereference_array(f.deref, ir, ir->lhs); ir->remove(); this->progress = true;