<div dir="ltr">On 9 September 2013 15:14, Matt Turner <span dir="ltr"><<a href="mailto:mattst88@gmail.com" target="_blank">mattst88@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I initially implemented frexp() as an IR opcode with a lowering pass,<br>
but since it returns a value and has an out-parameter, it would break<br>
assumptions our optimization passes make about ir_expressions being pure<br>
(i.e., having no side effects).<br>
<br>
For example, if opt_tree_grafting encounters this code:<br>
<br>
uniform float u;<br>
void main()<br>
{<br>
  int exp;<br>
  float f = frexp(u, out exp);<br>
  float g = float(exp)/256.0;<br>
  float h = float(exp) + 1.0;<br>
  gl_FragColor = vec4(f, g, h, g + h);<br>
}<br>
<br>
it may try to optimize it to this:<br>
<br>
uniform float u;<br>
void main()<br>
{<br>
  int exp;<br>
  float g = float(exp)/256.0;<br>
  float h = float(exp) + 1.0;<br>
  gl_FragColor = vec4(frexp(u, out exp), g, h, g + h);<br>
}<br>
<br>
Some hardware has an instruction which performs frexp(), but we would<br>
need some other compiler infrastructure to be able to generate it, such<br>
as an intrinsics system that would allow backends to emit specific code<br>
for particular bits of IR.<br>
---<br>
 src/glsl/builtin_functions.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++<br>
 1 file changed, 54 insertions(+)<br>
<br>
diff --git a/src/glsl/builtin_functions.cpp b/src/glsl/builtin_functions.cpp<br>
index dbd35f2..e9d7b74 100644<br>
--- a/src/glsl/builtin_functions.cpp<br>
+++ b/src/glsl/builtin_functions.cpp<br>
@@ -512,6 +512,7 @@ private:<br>
    B1(findMSB)<br>
    B1(fma)<br>
    B2(ldexp)<br>
+   B2(frexp)<br>
 #undef B0<br>
 #undef B1<br>
 #undef B2<br>
@@ -1828,6 +1829,13 @@ builtin_builder::create_builtins()<br>
                 _ldexp(glsl_type::vec3_type,  glsl_type::ivec3_type),<br>
                 _ldexp(glsl_type::vec4_type,  glsl_type::ivec4_type),<br>
                 NULL);<br>
+<br>
+   add_function("frexp",<br>
+                _frexp(glsl_type::float_type, glsl_type::int_type),<br>
+                _frexp(glsl_type::vec2_type,  glsl_type::ivec2_type),<br>
+                _frexp(glsl_type::vec3_type,  glsl_type::ivec3_type),<br>
+                _frexp(glsl_type::vec4_type,  glsl_type::ivec4_type),<br>
+                NULL);<br>
 #undef F<br>
 #undef FI<br>
 #undef FIU<br>
@@ -3524,6 +3532,52 @@ builtin_builder::_ldexp(const glsl_type *x_type, const glsl_type *exp_type)<br>
 {<br>
    return binop(ir_binop_ldexp, gpu_shader5, x_type, x_type, exp_type);<br>
 }<br>
+<br>
+ir_function_signature *<br>
+builtin_builder::_frexp(const glsl_type *x_type, const glsl_type *exp_type)<br>
+{<br>
+   ir_variable *x = in_var(x_type, "x");<br>
+   ir_variable *exponent = out_var(exp_type, "exp");<br>
+   MAKE_SIG(x_type, gpu_shader5, 2, x, exponent);<br>
+<br>
+   const unsigned vec_elem = x_type->vector_elements;<br>
+   const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1);<br>
+   const glsl_type *uvec = glsl_type::get_instance(GLSL_TYPE_UINT, vec_elem, 1);<br>
+<br>
+   /* Single-precision floating-point values are stored as<br>
+    *   1 sign bit;<br>
+    *   8 exponent bits;<br>
+    *   23 mantissa bits.<br>
+    *<br>
+    * An exponent shift of 23 will shift the mantissa out, leaving only the<br>
+    * exponent and sign bit (which itself may be zero, if the absolute value<br>
+    * was taken before the bitcast and shift.<br>
+    */<br>
+   ir_constant *exponent_shift = imm(23);<br>
+   ir_constant *exponent_bias = imm(-126, vec_elem);<br>
+<br>
+   ir_constant *sign_mantissa_mask = imm(0x807fffffu, vec_elem);<br>
+   ir_constant *exponent_mask = imm(0x3f000000u, vec_elem);<br></blockquote><div><br></div><div>Actually the exponent mask would be 0x7f800000u.  This is the exponent *value* corresponding to a float in the range [0.5, 1.0).  Fortunately that's what we use it for :).  I'd propose renaming it to something like "exponent_value", and maybe adding an explanatory comment.<br>
</div> <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   ir_variable *is_not_zero = body.make_temp(bvec, "is_not_zero");<br>
+   body.emit(assign(is_not_zero, nequal(abs(x), imm(0.0f, vec_elem))));<br>
+<br>
+   /* Since abs(x) ensures that the sign bit is zero, we don't need to bitcast<br>
+    * to unsigned integers to ensure that 1 bits aren't shifted in.<br>
+    */<br>
+   body.emit(assign(exponent, rshift(bitcast_f2i(abs(x)), exponent_shift)));<br>
+   body.emit(assign(exponent, add(exponent, csel(is_not_zero, exponent_bias,<br>
+                                                     imm(0, vec_elem)))));<br>
+<br>
+   ir_variable *bits = body.make_temp(uvec, "bits");<br>
+   body.emit(assign(bits, bitcast_f2u(x)));<br>
+   body.emit(assign(bits, bit_and(bits, sign_mantissa_mask)));<br>
+   body.emit(assign(bits, bit_or(bits, csel(is_not_zero, exponent_mask,<br>
+                                                imm(0u, vec_elem)))));<br>
+   body.emit(ret(bitcast_u2f(bits)));<br></blockquote><div><br></div><div>Tiny nit-pick: re-using the temporary variable "bits" like this places unnecessary constraints on the register allocator, since it forces every instance of the variable to be assigned to the same register.  There's a slight chance that by using three separate temporaries we could reduce register pressure.  (Of course, if we had SSA, this would happen automatically).<br>
<br></div><div>The potential benefit is very slight though, so I'm fine with it as is.<br><br></div><div>With exponent_mask renamed, the series is:<br></div><div><br></div><div>Reviewed-by: Paul Berry <<a href="mailto:stereotype441@gmail.com">stereotype441@gmail.com</a>><br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+   return sig;<br>
+}<br>
 /** @} */<br>
<br>
 /******************************************************************************/<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.2<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>