diff options
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/builtin_functions.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/glsl/builtin_functions.cpp b/src/glsl/builtin_functions.cpp index b5be7043fcf..31f7489d18f 100644 --- a/src/glsl/builtin_functions.cpp +++ b/src/glsl/builtin_functions.cpp @@ -511,6 +511,7 @@ private: B1(findMSB) B1(fma) B2(ldexp) + B2(frexp) #undef B0 #undef B1 #undef B2 @@ -1830,6 +1831,13 @@ builtin_builder::create_builtins() _ldexp(glsl_type::vec3_type, glsl_type::ivec3_type), _ldexp(glsl_type::vec4_type, glsl_type::ivec4_type), NULL); + + add_function("frexp", + _frexp(glsl_type::float_type, glsl_type::int_type), + _frexp(glsl_type::vec2_type, glsl_type::ivec2_type), + _frexp(glsl_type::vec3_type, glsl_type::ivec3_type), + _frexp(glsl_type::vec4_type, glsl_type::ivec4_type), + NULL); #undef F #undef FI #undef FIU @@ -3528,6 +3536,54 @@ builtin_builder::_ldexp(const glsl_type *x_type, const glsl_type *exp_type) { return binop(ir_binop_ldexp, gpu_shader5, x_type, x_type, exp_type); } + +ir_function_signature * +builtin_builder::_frexp(const glsl_type *x_type, const glsl_type *exp_type) +{ + ir_variable *x = in_var(x_type, "x"); + ir_variable *exponent = out_var(exp_type, "exp"); + MAKE_SIG(x_type, gpu_shader5, 2, x, exponent); + + const unsigned vec_elem = x_type->vector_elements; + const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1); + const glsl_type *uvec = glsl_type::get_instance(GLSL_TYPE_UINT, vec_elem, 1); + + /* Single-precision floating-point values are stored as + * 1 sign bit; + * 8 exponent bits; + * 23 mantissa bits. + * + * An exponent shift of 23 will shift the mantissa out, leaving only the + * exponent and sign bit (which itself may be zero, if the absolute value + * was taken before the bitcast and shift. + */ + ir_constant *exponent_shift = imm(23); + ir_constant *exponent_bias = imm(-126, vec_elem); + + ir_constant *sign_mantissa_mask = imm(0x807fffffu, vec_elem); + + /* Exponent of floating-point values in the range [0.5, 1.0). */ + ir_constant *exponent_value = imm(0x3f000000u, vec_elem); + + ir_variable *is_not_zero = body.make_temp(bvec, "is_not_zero"); + body.emit(assign(is_not_zero, nequal(abs(x), imm(0.0f, vec_elem)))); + + /* Since abs(x) ensures that the sign bit is zero, we don't need to bitcast + * to unsigned integers to ensure that 1 bits aren't shifted in. + */ + body.emit(assign(exponent, rshift(bitcast_f2i(abs(x)), exponent_shift))); + body.emit(assign(exponent, add(exponent, csel(is_not_zero, exponent_bias, + imm(0, vec_elem))))); + + ir_variable *bits = body.make_temp(uvec, "bits"); + body.emit(assign(bits, bitcast_f2u(x))); + body.emit(assign(bits, bit_and(bits, sign_mantissa_mask))); + body.emit(assign(bits, bit_or(bits, csel(is_not_zero, exponent_value, + imm(0u, vec_elem))))); + body.emit(ret(bitcast_u2f(bits))); + + return sig; +} /** @} */ /******************************************************************************/ |