X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Flower_instructions.cpp;h=1ce7b7c9df4d01a650346fc6c4e113b649ceeb6f;hb=7214451bdce6d553620d2b9b3f1f89d14b113357;hp=806f86399599669364377e4635cc221fb352ca1c;hpb=636d01bd61cac83e13c3c64874e7e34e828ca93a;p=mesa.git diff --git a/src/glsl/lower_instructions.cpp b/src/glsl/lower_instructions.cpp index 806f8639959..1ce7b7c9df4 100644 --- a/src/glsl/lower_instructions.cpp +++ b/src/glsl/lower_instructions.cpp @@ -32,10 +32,12 @@ * Currently supported transformations: * - SUB_TO_ADD_NEG * - DIV_TO_MUL_RCP + * - INT_DIV_TO_MUL_RCP * - EXP_TO_EXP2 * - POW_TO_EXP2 * - LOG_TO_LOG2 * - MOD_TO_FRACT + * - LRP_TO_ARITH * * SUB_TO_ADD_NEG: * --------------- @@ -47,15 +49,19 @@ * want to recognize add(op0, neg(op1)) or the other way around to * produce a subtract anyway. * - * DIV_TO_MUL_RCP: - * --------------- - * Breaks an ir_unop_div expression down to op0 * (rcp(op1)). + * DIV_TO_MUL_RCP and INT_DIV_TO_MUL_RCP: + * -------------------------------------- + * Breaks an ir_binop_div expression down to op0 * (rcp(op1)). * * Many GPUs don't have a divide instruction (945 and 965 included), * but they do have an RCP instruction to compute an approximate * reciprocal. By breaking the operation down, constant reciprocals * can get constant folded. * + * DIV_TO_MUL_RCP only lowers floating point division; INT_DIV_TO_MUL_RCP + * handles the integer case, converting to and from floating point so that + * RCP is possible. + * * EXP_TO_EXP2 and LOG_TO_LOG2: * ---------------------------- * Many GPUs don't have a base e log or exponent instruction, but they @@ -69,18 +75,25 @@ * * MOD_TO_FRACT: * ------------- - * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1)) + * Breaks an ir_binop_mod expression down to (op1 * fract(op0 / op1)) * * Many GPUs don't have a MOD instruction (945 and 965 included), and * if we have to break it down like this anyway, it gives an * opportunity to do things like constant fold the (1.0 / op1) easily. + * + * LRP_TO_ARITH: + * ------------- + * Converts ir_triop_lrp to (op0 * (1.0f - op2)) + (op1 * op2). */ #include "main/core.h" /* for M_LOG2E */ #include "glsl_types.h" #include "ir.h" +#include "ir_builder.h" #include "ir_optimization.h" +using namespace ir_builder; + class lower_instructions_visitor : public ir_hierarchical_visitor { public: lower_instructions_visitor(unsigned lower) @@ -95,10 +108,12 @@ private: void sub_to_add_neg(ir_expression *); void div_to_mul_rcp(ir_expression *); + void int_div_to_mul_rcp(ir_expression *); void mod_to_fract(ir_expression *); void exp_to_exp2(ir_expression *); void pow_to_exp2(ir_expression *); void log_to_log2(ir_expression *); + void lrp_to_arith(ir_expression *); }; /** @@ -127,56 +142,67 @@ lower_instructions_visitor::sub_to_add_neg(ir_expression *ir) void lower_instructions_visitor::div_to_mul_rcp(ir_expression *ir) { - if (!ir->operands[1]->type->is_integer()) { - /* New expression for the 1.0 / op1 */ - ir_rvalue *expr; - expr = new(ir) ir_expression(ir_unop_rcp, - ir->operands[1]->type, - ir->operands[1], - NULL); - - /* op0 / op1 -> op0 * (1.0 / op1) */ - ir->operation = ir_binop_mul; - ir->operands[1] = expr; + assert(ir->operands[1]->type->is_float()); + + /* New expression for the 1.0 / op1 */ + ir_rvalue *expr; + expr = new(ir) ir_expression(ir_unop_rcp, + ir->operands[1]->type, + ir->operands[1]); + + /* op0 / op1 -> op0 * (1.0 / op1) */ + ir->operation = ir_binop_mul; + ir->operands[1] = expr; + + this->progress = true; +} + +void +lower_instructions_visitor::int_div_to_mul_rcp(ir_expression *ir) +{ + assert(ir->operands[1]->type->is_integer()); + + /* Be careful with integer division -- we need to do it as a + * float and re-truncate, since rcp(n > 1) of an integer would + * just be 0. + */ + ir_rvalue *op0, *op1; + const struct glsl_type *vec_type; + + vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->operands[1]->type->vector_elements, + ir->operands[1]->type->matrix_columns); + + if (ir->operands[1]->type->base_type == GLSL_TYPE_INT) + op1 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[1], NULL); + else + op1 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[1], NULL); + + op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL); + + vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->operands[0]->type->vector_elements, + ir->operands[0]->type->matrix_columns); + + if (ir->operands[0]->type->base_type == GLSL_TYPE_INT) + op0 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[0], NULL); + else + op0 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[0], NULL); + + vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->type->vector_elements, + ir->type->matrix_columns); + + op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1); + + if (ir->operands[1]->type->base_type == GLSL_TYPE_INT) { + ir->operation = ir_unop_f2i; + ir->operands[0] = op0; } else { - /* Be careful with integer division -- we need to do it as a - * float and re-truncate, since rcp(n > 1) of an integer would - * just be 0. - */ - ir_rvalue *op0, *op1; - const struct glsl_type *vec_type; - - vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, - ir->operands[1]->type->vector_elements, - ir->operands[1]->type->matrix_columns); - - if (ir->operands[1]->type->base_type == GLSL_TYPE_INT) - op1 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[1], NULL); - else - op1 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[1], NULL); - - op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL); - - vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, - ir->operands[0]->type->vector_elements, - ir->operands[0]->type->matrix_columns); - - if (ir->operands[0]->type->base_type == GLSL_TYPE_INT) - op0 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[0], NULL); - else - op0 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[0], NULL); - - op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1); - - if (ir->operands[1]->type->base_type == GLSL_TYPE_INT) { - ir->operation = ir_unop_f2i; - ir->operands[0] = op0; - } else { - ir->operation = ir_unop_i2u; - ir->operands[0] = new(ir) ir_expression(ir_unop_f2i, op0); - } - ir->operands[1] = NULL; + ir->operation = ir_unop_i2u; + ir->operands[0] = new(ir) ir_expression(ir_unop_f2i, op0); } + ir->operands[1] = NULL; this->progress = true; } @@ -251,6 +277,27 @@ lower_instructions_visitor::mod_to_fract(ir_expression *ir) this->progress = true; } +void +lower_instructions_visitor::lrp_to_arith(ir_expression *ir) +{ + /* (lrp x y a) -> x*(1-a) + y*a */ + + /* Save op2 */ + ir_variable *temp = new(ir) ir_variable(ir->operands[2]->type, "lrp_factor", + ir_var_temporary); + this->base_ir->insert_before(temp); + this->base_ir->insert_before(assign(temp, ir->operands[2])); + + ir_constant *one = new(ir) ir_constant(1.0f); + + ir->operation = ir_binop_add; + ir->operands[0] = mul(ir->operands[0], sub(one, temp)); + ir->operands[1] = mul(ir->operands[1], temp); + ir->operands[2] = NULL; + + this->progress = true; +} + ir_visitor_status lower_instructions_visitor::visit_leave(ir_expression *ir) { @@ -261,7 +308,9 @@ lower_instructions_visitor::visit_leave(ir_expression *ir) break; case ir_binop_div: - if (lowering(DIV_TO_MUL_RCP)) + if (ir->operands[1]->type->is_integer() && lowering(INT_DIV_TO_MUL_RCP)) + int_div_to_mul_rcp(ir); + else if (ir->operands[1]->type->is_float() && lowering(DIV_TO_MUL_RCP)) div_to_mul_rcp(ir); break; @@ -285,6 +334,11 @@ lower_instructions_visitor::visit_leave(ir_expression *ir) pow_to_exp2(ir); break; + case ir_triop_lrp: + if (lowering(LRP_TO_ARITH)) + lrp_to_arith(ir); + break; + default: return visit_continue; }