--- src/glsl/ir_optimization.h | 1 + src/glsl/lower_instructions.cpp | 106 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+)
diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 074686c..51c73bb 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -39,6 +39,7 @@ #define LRP_TO_ARITH 0x80 #define BITFIELD_INSERT_TO_BFM_BFI 0x100 #define LDEXP_TO_ARITH 0x200 +#define FREXP_TO_ARITH 0x400 /** * \see class lower_packing_builtins_visitor diff --git a/src/glsl/lower_instructions.cpp b/src/glsl/lower_instructions.cpp index 8b0a8e1..495c232 100644 --- a/src/glsl/lower_instructions.cpp +++ b/src/glsl/lower_instructions.cpp @@ -87,6 +87,10 @@ * ------------- * Converts ir_binop_ldexp to arithmetic and bit operations. * + * FREXP_TO_ARITH: + * ------------- + * Converts ir_binop_frexp to arithmetic and bit operations. + * * LRP_TO_ARITH: * ------------- * Converts ir_triop_lrp to (op0 * (1.0f - op2)) + (op1 * op2). @@ -131,6 +135,7 @@ private: void lrp_to_arith(ir_expression *); void bitfield_insert_to_bfm_bfi(ir_expression *); void ldexp_to_arith(ir_expression *); + void frexp_to_arith(ir_expression *); }; /** @@ -455,6 +460,102 @@ lower_instructions_visitor::ldexp_to_arith(ir_expression *ir) this->progress = true; } +void +lower_instructions_visitor::frexp_to_arith(ir_expression *ir) +{ + /* Translates + * ir_binop_frexp x_input exp + * into: + * + * x = x_input; + * exp = 0; + * + * if (abs(x) != 0.0) { + * bits = bitcast_f2u(x); + * + * exp += (bitcast_f2u(abs(x)) >> exp_shift) + exp_bias; + * bits &= sign_mantissa_mask; + * bits |= exponent_mask; + * x = bitcast_u2f(bits); + * } + * return x; + * + * which we can't actually implement as such, since the GLSL IR doesn't + * have vectorized if-statements. We actually implement it without branches + * using conditional-select: + * + * x = x_input; + * + * is_not_zero = abs(x) != 0.0f; + * + * exp = u2i(bitcast_f2u(abs(x)) >> exp_shift); + * exp += cond_sel(is_not_zero, exp_bias, 0); + * + * bits = bitcast_f2u(x); + * bits &= sign_mantissa_mask; + * bits |= cond_sel(is_not_zero, exponent_mask, 0u); + * x = bitcast_u2f(bits); + * return x; + */ + + const unsigned vec_elem = ir->type->vector_elements; + + /* Types */ + const glsl_type *uvec = glsl_type::get_instance(GLSL_TYPE_UINT, vec_elem, 1); + const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1); + const glsl_type *ivec = glsl_type::get_instance(GLSL_TYPE_INT, vec_elem, 1); + + /* Constants */ + ir_constant *zeroi = ir_constant::zero(ir, ivec); + ir_constant *zerou = ir_constant::zero(ir, uvec); + ir_constant *zerof = ir_constant::zero(ir, ir->type); + + ir_constant *exp_bias = new(ir) ir_constant(-126, vec_elem); + ir_constant *exp_shift = new(ir) ir_constant(23u, vec_elem); + + ir_constant *sign_mantissa_mask = new(ir) ir_constant(0x807fffffu, vec_elem); + ir_constant *exponent_mask = new(ir) ir_constant(0x3f000000u, vec_elem); + + /* Temporary variables */ + ir_variable *x = new(ir) ir_variable(ir->type, "x", ir_var_temporary); + + ir_variable *bits = new(ir) ir_variable(uvec, "bits", ir_var_temporary); + + ir_variable *is_not_zero = new(ir) ir_variable(bvec, "is_not_zero", + ir_var_temporary); + + /* Variable passed as <exp> parameter */ + ir_variable *exponent = ir->operands[1]->variable_referenced(); + + + ir_instruction &i = *base_ir; + + /* Initialize x = x_input; exponent = 0; */ + i.insert_before(x); + i.insert_before(assign(x, ir->operands[0])); + i.insert_before(is_not_zero); + i.insert_before(assign(is_not_zero, nequal(abs(x), zerof))); + + /* Calculate exponent */ + /* Use bitcast to unsigned to get shr, not asr. */ + i.insert_before(assign(exponent, add(u2i(rshift(bitcast_f2u(abs(x)), + exp_shift)), + cond_sel(is_not_zero, exp_bias, + zeroi)))); + + /* Calculate mantissa */ + i.insert_before(bits); + i.insert_before(assign(bits, bit_and(bitcast_f2u(x), sign_mantissa_mask))); + i.insert_before(assign(bits, bit_or(bits, cond_sel(is_not_zero, + exponent_mask, zerou)))); + + ir->operation = ir_unop_bitcast_u2f; + ir->operands[0] = new(ir) ir_dereference_variable(bits); + ir->operands[1] = NULL; + + this->progress = true; +} + ir_visitor_status lower_instructions_visitor::visit_leave(ir_expression *ir) { @@ -506,6 +607,11 @@ lower_instructions_visitor::visit_leave(ir_expression *ir) ldexp_to_arith(ir); break; + case ir_binop_frexp: + if (lowering(FREXP_TO_ARITH)) + frexp_to_arith(ir); + break; + default: return visit_continue; } -- 1.8.3.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev