X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Flower_instructions.cpp;h=d79eb0a7ffb0d69f41d5fcef8e9d1674514dcb45;hb=7199b0b6811b3340cb5c531c8625220e964fa16c;hp=d460ba1a97abd2d3fe00f368c2ef5eba4f0e7d55;hpb=63684a9ae7a66f68df1f2c68cd9358e5622122a3;p=mesa.git diff --git a/src/glsl/lower_instructions.cpp b/src/glsl/lower_instructions.cpp index d460ba1a97a..d79eb0a7ffb 100644 --- a/src/glsl/lower_instructions.cpp +++ b/src/glsl/lower_instructions.cpp @@ -32,7 +32,9 @@ * 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 * @@ -46,8 +48,8 @@ * want to recognize add(op0, neg(op1)) or the other way around to * produce a subtract anyway. * - * DIV_TO_MUL_RCP: - * --------------- + * DIV_TO_MUL_RCP and INT_DIV_TO_MUL_RCP: + * -------------------------------------- * Breaks an ir_unop_div expression down to op0 * (rcp(op1)). * * Many GPUs don't have a divide instruction (945 and 965 included), @@ -55,12 +57,21 @@ * 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 * do have base 2 versions, so this pass converts exp and log to exp2 * and log2 operations. * + * POW_TO_EXP2: + * ----------- + * Many older GPUs don't have an x**y instruction. For these GPUs, convert + * x**y to 2**(y * log2(x)). + * * MOD_TO_FRACT: * ------------- * Breaks an ir_unop_mod expression down to (op1 * fract(op0 / op1)) @@ -70,7 +81,7 @@ * opportunity to do things like constant fold the (1.0 / op1) easily. */ -#include "main/core.h" /* for M_E */ +#include "main/core.h" /* for M_LOG2E */ #include "glsl_types.h" #include "ir.h" #include "ir_optimization.h" @@ -89,8 +100,10 @@ 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 *); }; @@ -120,51 +133,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; - } 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; + 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; - vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, - ir->operands[1]->type->vector_elements, - ir->operands[1]->type->matrix_columns); + this->progress = true; +} - 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); +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; - op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL); + vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, + ir->operands[1]->type->vector_elements, + ir->operands[1]->type->matrix_columns); - vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, - ir->operands[0]->type->vector_elements, - ir->operands[0]->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); - 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); + op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL); - op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1); + 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; - ir->operands[1] = NULL; + } else { + ir->operation = ir_unop_i2u; + ir->operands[0] = new(ir) ir_expression(ir_unop_f2i, op0); } + ir->operands[1] = NULL; this->progress = true; } @@ -172,7 +201,7 @@ lower_instructions_visitor::div_to_mul_rcp(ir_expression *ir) void lower_instructions_visitor::exp_to_exp2(ir_expression *ir) { - ir_constant *log2_e = new(ir) ir_constant(log2f(M_E)); + ir_constant *log2_e = new(ir) ir_constant(float(M_LOG2E)); ir->operation = ir_unop_exp2; ir->operands[0] = new(ir) ir_expression(ir_binop_mul, ir->operands[0]->type, @@ -180,13 +209,27 @@ lower_instructions_visitor::exp_to_exp2(ir_expression *ir) this->progress = true; } +void +lower_instructions_visitor::pow_to_exp2(ir_expression *ir) +{ + ir_expression *const log2_x = + new(ir) ir_expression(ir_unop_log2, ir->operands[0]->type, + ir->operands[0]); + + ir->operation = ir_unop_exp2; + ir->operands[0] = new(ir) ir_expression(ir_binop_mul, ir->operands[1]->type, + ir->operands[1], log2_x); + ir->operands[1] = NULL; + this->progress = true; +} + void lower_instructions_visitor::log_to_log2(ir_expression *ir) { ir->operation = ir_binop_mul; ir->operands[0] = new(ir) ir_expression(ir_unop_log2, ir->operands[0]->type, ir->operands[0], NULL); - ir->operands[1] = new(ir) ir_constant(1.0f / log2f(M_E)); + ir->operands[1] = new(ir) ir_constant(float(1.0 / M_LOG2E)); this->progress = true; } @@ -235,7 +278,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; @@ -250,10 +295,15 @@ lower_instructions_visitor::visit_leave(ir_expression *ir) break; case ir_binop_mod: - if (lowering(MOD_TO_FRACT)) + if (lowering(MOD_TO_FRACT) && ir->type->is_float()) mod_to_fract(ir); break; + case ir_binop_pow: + if (lowering(POW_TO_EXP2)) + pow_to_exp2(ir); + break; + default: return visit_continue; }