glsl_precision higher_precision (ir_instruction* a, ir_instruction* b) { if (!a && !b) return glsl_precision_undefined; if (!a) return precision_from_ir (b); if (!b) return precision_from_ir (a); return higher_precision (precision_from_ir(a), precision_from_ir(b)); }
void lower_instructions_visitor::mod_to_fract(ir_expression *ir) { ir_variable *temp = new(ir) ir_variable(ir->operands[1]->type, "mod_b", ir_var_temporary, precision_from_ir(ir->operands[1])); this->base_ir->insert_before(temp); ir_assignment *const assign = new(ir) ir_assignment(new(ir) ir_dereference_variable(temp), ir->operands[1], NULL); this->base_ir->insert_before(assign); ir_expression *const div_expr = new(ir) ir_expression(ir_binop_div, ir->operands[0]->type, ir->operands[0], new(ir) ir_dereference_variable(temp)); /* Don't generate new IR that would need to be lowered in an additional * pass. */ if (lowering(DIV_TO_MUL_RCP)) div_to_mul_rcp(div_expr); ir_rvalue *expr = new(ir) ir_expression(ir_unop_fract, ir->operands[0]->type, div_expr, NULL); ir->operation = ir_binop_mul; ir->operands[0] = new(ir) ir_dereference_variable(temp); ir->operands[1] = expr; this->progress = true; }
ir_expression::ir_expression(int op, const struct glsl_type *type, ir_rvalue *op0) : ir_rvalue(precision_from_ir(op0)) { assert(get_num_operands(ir_expression_operation(op)) == 1); this->ir_type = ir_type_expression; this->type = type; this->operation = ir_expression_operation(op); this->operands[0] = op0; this->operands[1] = NULL; this->operands[2] = NULL; this->operands[3] = NULL; }
/** * Generate a comparison value for a block of indices * * Lowering passes for non-constant indexing of arrays, matrices, or vectors * can use this to generate blocks of index comparison values. * * \param instructions List where new instructions will be appended * \param index \c ir_variable containing the desired index * \param base Base value for this block of comparisons * \param components Number of unique index values to compare. This must * be on the range [1, 4]. * \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. */ ir_rvalue * compare_index_block(exec_list *instructions, ir_variable *index, unsigned base, unsigned components, void *mem_ctx) { ir_rvalue *broadcast_index = new(mem_ctx) ir_dereference_variable(index); assert(index->type->is_scalar()); assert(index->type->base_type == GLSL_TYPE_INT); 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); } /* Compare the desired index value with the next block of four indices. */ ir_constant_data test_indices_data; memset(&test_indices_data, 0, sizeof(test_indices_data)); test_indices_data.i[0] = base; test_indices_data.i[1] = base + 1; test_indices_data.i[2] = base + 2; 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::bool_type[components - 1], broadcast_index, test_indices); ir_variable *const condition = new(mem_ctx) ir_variable(condition_val->type, "dereference_condition", ir_var_temporary, precision_from_ir(condition_val)); 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; }
ir_expression::ir_expression(int op, ir_rvalue *op0) : ir_rvalue(precision_from_ir(op0)) { this->ir_type = ir_type_expression; this->operation = ir_expression_operation(op); this->operands[0] = op0; this->operands[1] = NULL; this->operands[2] = NULL; this->operands[3] = NULL; assert(op <= ir_last_unop); switch (this->operation) { case ir_unop_bit_not: case ir_unop_logic_not: case ir_unop_neg: case ir_unop_abs: case ir_unop_sign: case ir_unop_rcp: case ir_unop_rsq: case ir_unop_sqrt: case ir_unop_normalize: case ir_unop_exp: case ir_unop_log: case ir_unop_exp2: case ir_unop_log2: case ir_unop_trunc: case ir_unop_ceil: case ir_unop_floor: case ir_unop_fract: case ir_unop_round_even: case ir_unop_sin: case ir_unop_cos: case ir_unop_sin_reduced: case ir_unop_cos_reduced: case ir_unop_dFdx: case ir_unop_dFdy: this->type = op0->type; break; case ir_unop_f2i: case ir_unop_b2i: case ir_unop_u2i: case ir_unop_bitcast_f2i: this->type = glsl_type::get_instance(GLSL_TYPE_INT, op0->type->vector_elements, 1); break; case ir_unop_b2f: case ir_unop_i2f: case ir_unop_u2f: case ir_unop_bitcast_i2f: case ir_unop_bitcast_u2f: this->type = glsl_type::get_instance(GLSL_TYPE_FLOAT, op0->type->vector_elements, 1); break; case ir_unop_f2b: case ir_unop_i2b: this->type = glsl_type::get_instance(GLSL_TYPE_BOOL, op0->type->vector_elements, 1); break; case ir_unop_i2u: case ir_unop_f2u: case ir_unop_bitcast_f2u: this->type = glsl_type::get_instance(GLSL_TYPE_UINT, op0->type->vector_elements, 1); break; case ir_unop_noise: this->type = glsl_type::float_type; break; case ir_unop_any: this->type = glsl_type::bool_type; break; default: assert(!"not reached: missing automatic type setup for ir_expression"); this->type = op0->type; break; } }
void lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue) { if (!*rvalue) return; ir_expression *expr = (*rvalue)->as_expression(); if ((expr == NULL) || (expr->operation != ir_quadop_vector)) return; if (this->dont_lower_swz && is_extended_swizzle(expr)) return; /* FINISHME: Is this the right thing to use for the ralloc context? */ void *const mem_ctx = expr; assert(expr->type->vector_elements == expr->get_num_operands()); /* Generate a temporary with the same type as the ir_quadop_operation. */ ir_variable *const temp = new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary, precision_from_ir(expr)); this->base_ir->insert_before(temp); /* Counter of the number of components collected so far. */ unsigned assigned; /* Write-mask in the destination that receives counted by 'assigned'. */ unsigned write_mask; /* Generate upto four assignments to that variable. Try to group component * assignments together: * * - All constant components can be assigned at once. * - All assigments of components from a single variable with the same * unary operator can be assigned at once. */ ir_constant_data d = { { 0 } }; assigned = 0; write_mask = 0; for (unsigned i = 0; i < expr->type->vector_elements; i++) { const ir_constant *const c = expr->operands[i]->as_constant(); if (c == NULL) continue; switch (expr->type->base_type) { case GLSL_TYPE_UINT: d.u[assigned] = c->value.u[0]; break; case GLSL_TYPE_INT: d.i[assigned] = c->value.i[0]; break; case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break; case GLSL_TYPE_BOOL: d.b[assigned] = c->value.b[0]; break; default: assert(!"Should not get here."); break; } write_mask |= (1U << i); assigned++; } assert((write_mask == 0) == (assigned == 0)); /* If there were constant values, generate an assignment. */ if (assigned > 0) { ir_constant *const c = new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type, assigned, 1), &d); ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp); ir_assignment *const assign = new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask); this->base_ir->insert_before(assign); } /* FINISHME: This should try to coalesce assignments. */ for (unsigned i = 0; i < expr->type->vector_elements; i++) { if (expr->operands[i]->ir_type == ir_type_constant) continue; ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp); ir_assignment *const assign = new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i)); this->base_ir->insert_before(assign); assigned++; } assert(assigned == expr->type->vector_elements); *rvalue = new(mem_ctx) ir_dereference_variable(temp); this->progress = true; }
ir_variable *convert_dereference_array(ir_dereference_array *orig_deref, ir_assignment* orig_assign, ir_dereference *orig_base) { 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. */ ir_variable *var; if (orig_assign) { var = new(mem_ctx) ir_variable(orig_assign->rhs->type, "dereference_array_value", ir_var_temporary, precision_from_ir(orig_deref)); 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); base_ir->insert_before(assign); } else { var = new(mem_ctx) ir_variable(orig_deref->type, "dereference_array_value", ir_var_temporary, precision_from_ir(orig_deref)); base_ir->insert_before(var); } /* 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, precision_from_ir(orig_deref->array_index)); base_ir->insert_before(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); orig_deref->array_index = lhs->clone(mem_ctx, NULL); assignment_generator ag; ag.rvalue = orig_base; ag.base_ir = base_ir; ag.old_index = index; ag.var = var; if (orig_assign) { ag.is_write = true; ag.write_mask = orig_assign->write_mask; } else { ag.is_write = false; } switch_generator sg(ag, index, 4, 4); /* If the original assignment has a condition, respect that original * 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; sg.generate(0, length, &list); base_ir->insert_before(&list); } return var; }
ir_rvalue * ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir) { ir_dereference_array *orig_deref = ir->as_dereference_array(); ir_assignment *assign; ir_variable *index, *var; ir_dereference *deref; int i; if (!orig_deref) return ir; if (orig_deref->array->type->is_matrix() || orig_deref->array->type->is_array()) return ir; void *mem_ctx = ralloc_parent(ir); assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT); exec_list list; /* Store the index to a temporary to avoid reusing its tree. */ index = new(base_ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i", ir_var_temporary, glsl_precision_undefined); list.push_tail(index); deref = new(base_ir) ir_dereference_variable(index); assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL); list.push_tail(assign); /* Temporary where we store whichever value we swizzle out. */ var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v", ir_var_temporary, precision_from_ir(ir)); list.push_tail(var); /* Generate a single comparison condition "mask" for all of the components * in the vector. */ ir_rvalue *const cond_deref = compare_index_block(&list, index, 0, orig_deref->array->type->vector_elements, mem_ctx); /* Generate a conditional move of each vector element to the temp. */ for (i = 0; i < (int)orig_deref->array->type->vector_elements; i++) { ir_rvalue *condition_swizzle = new(base_ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1); /* Just clone the rest of the deref chain when trying to get at the * underlying variable. */ ir_rvalue *swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL), i, 0, 0, 0, 1); deref = new(base_ir) ir_dereference_variable(var); assign = new(base_ir) ir_assignment(deref, swizzle, condition_swizzle); list.push_tail(assign); } /* Put all of the new instructions in the IR stream before the old * instruction. */ base_ir->insert_before(&list); this->progress = true; return new(base_ir) ir_dereference_variable(var); }
ir_visitor_status ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir) { ir_variable *index, *var; ir_dereference_variable *deref; ir_assignment *assign; int i; ir->rhs = convert_vec_index_to_cond_assign(ir->rhs); if (ir->condition) ir->condition = convert_vec_index_to_cond_assign(ir->condition); /* Last, handle the LHS */ ir_dereference_array *orig_deref = ir->lhs->as_dereference_array(); if (!orig_deref || orig_deref->array->type->is_matrix() || orig_deref->array->type->is_array()) return visit_continue; void *mem_ctx = ralloc_parent(ir); assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT); exec_list list; /* Store the index to a temporary to avoid reusing its tree. */ index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i", ir_var_temporary, glsl_precision_undefined); list.push_tail(index); deref = new(ir) ir_dereference_variable(index); assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL); list.push_tail(assign); /* Store the RHS to a temporary to avoid reusing its tree. */ var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v", ir_var_temporary, precision_from_ir(ir->rhs)); list.push_tail(var); deref = new(ir) ir_dereference_variable(var); assign = new(ir) ir_assignment(deref, ir->rhs, NULL); list.push_tail(assign); /* Generate a single comparison condition "mask" for all of the components * in the vector. */ ir_rvalue *const cond_deref = compare_index_block(&list, index, 0, orig_deref->array->type->vector_elements, mem_ctx); /* Generate a conditional move of each vector element to the temp. */ for (i = 0; i < (int)orig_deref->array->type->vector_elements; i++) { ir_rvalue *condition_swizzle = new(ir) ir_swizzle(cond_deref->clone(ir, NULL), i, 0, 0, 0, 1); /* Just clone the rest of the deref chain when trying to get at the * underlying variable. */ ir_rvalue *swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL), i, 0, 0, 0, 1); deref = new(ir) ir_dereference_variable(var); assign = new(ir) ir_assignment(swizzle, deref, condition_swizzle); list.push_tail(assign); } /* If the original assignment has a condition, respect that original * condition! This is acomplished by wrapping the new conditional * assignments in an if-statement that uses the original condition. */ if (ir->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(ir->condition); list.move_nodes_to(&if_stmt->then_instructions); ir->insert_before(if_stmt); } else { ir->insert_before(&list); } ir->remove(); this->progress = true; return visit_continue; }