Mesa (master): spirv: Add a 64-bit implementation of Frexp

Neil Roberts nroberts at kemper.freedesktop.org
Wed Mar 21 19:30:02 UTC 2018


Module: Mesa
Branch: master
Commit: 61603f0e4219fee2d288ece9d1b4105a8657fe38
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=61603f0e4219fee2d288ece9d1b4105a8657fe38

Author: Neil Roberts <nroberts at igalia.com>
Date:   Thu Mar  8 17:07:46 2018 +0100

spirv: Add a 64-bit implementation of Frexp

The implementation is inspired by
lower_instructions_visitor::dfrexp_sig_to_arith.

This has been tested against the arb_gpu_shader_fp64/fs-frexp-dvec4
test using the ARB_gl_spirv branch.

Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>

---

 src/compiler/spirv/vtn_glsl450.c | 60 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 56 insertions(+), 4 deletions(-)

diff --git a/src/compiler/spirv/vtn_glsl450.c b/src/compiler/spirv/vtn_glsl450.c
index 46ef40f5e3..7d32914d51 100644
--- a/src/compiler/spirv/vtn_glsl450.c
+++ b/src/compiler/spirv/vtn_glsl450.c
@@ -380,7 +380,7 @@ build_atan2(nir_builder *b, nir_ssa_def *y, nir_ssa_def *x)
 }
 
 static nir_ssa_def *
-build_frexp(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent)
+build_frexp32(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent)
 {
    nir_ssa_def *abs_x = nir_fabs(b, x);
    nir_ssa_def *zero = nir_imm_float(b, 0.0f);
@@ -412,6 +412,51 @@ build_frexp(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent)
                      nir_bcsel(b, is_not_zero, exponent_value, zero));
 }
 
+static nir_ssa_def *
+build_frexp64(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent)
+{
+   nir_ssa_def *abs_x = nir_fabs(b, x);
+   nir_ssa_def *zero = nir_imm_double(b, 0.0);
+   nir_ssa_def *zero32 = nir_imm_float(b, 0.0f);
+
+   /* Double-precision floating-point values are stored as
+    *   1 sign bit;
+    *   11 exponent bits;
+    *   52 mantissa bits.
+    *
+    * We only need to deal with the exponent so first we extract the upper 32
+    * bits using nir_unpack_64_2x32_split_y.
+    */
+   nir_ssa_def *upper_x = nir_unpack_64_2x32_split_y(b, x);
+   nir_ssa_def *abs_upper_x = nir_unpack_64_2x32_split_y(b, abs_x);
+
+   /* An exponent shift of 20 will shift the remaining mantissa bits out,
+    * leaving only the exponent and sign bit (which itself may be zero, if the
+    * absolute value was taken before the bitcast and shift.
+    */
+   nir_ssa_def *exponent_shift = nir_imm_int(b, 20);
+   nir_ssa_def *exponent_bias = nir_imm_int(b, -1022);
+
+   nir_ssa_def *sign_mantissa_mask = nir_imm_int(b, 0x800fffffu);
+
+   /* Exponent of floating-point values in the range [0.5, 1.0). */
+   nir_ssa_def *exponent_value = nir_imm_int(b, 0x3fe00000u);
+
+   nir_ssa_def *is_not_zero = nir_fne(b, abs_x, zero);
+
+   *exponent =
+      nir_iadd(b, nir_ushr(b, abs_upper_x, exponent_shift),
+                  nir_bcsel(b, is_not_zero, exponent_bias, zero32));
+
+   nir_ssa_def *new_upper =
+      nir_ior(b, nir_iand(b, upper_x, sign_mantissa_mask),
+                 nir_bcsel(b, is_not_zero, exponent_value, zero32));
+
+   nir_ssa_def *lower_x = nir_unpack_64_2x32_split_x(b, x);
+
+   return nir_pack_64_2x32_split(b, lower_x, new_upper);
+}
+
 static nir_op
 vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b,
                                      enum GLSLstd450 opcode)
@@ -685,15 +730,22 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint,
 
    case GLSLstd450Frexp: {
       nir_ssa_def *exponent;
-      val->ssa->def = build_frexp(nb, src[0], &exponent);
+      if (src[0]->bit_size == 64)
+         val->ssa->def = build_frexp64(nb, src[0], &exponent);
+      else
+         val->ssa->def = build_frexp32(nb, src[0], &exponent);
       nir_store_deref_var(nb, vtn_nir_deref(b, w[6]), exponent, 0xf);
       return;
    }
 
    case GLSLstd450FrexpStruct: {
       vtn_assert(glsl_type_is_struct(val->ssa->type));
-      val->ssa->elems[0]->def = build_frexp(nb, src[0],
-                                            &val->ssa->elems[1]->def);
+      if (src[0]->bit_size == 64)
+         val->ssa->elems[0]->def = build_frexp64(nb, src[0],
+                                                 &val->ssa->elems[1]->def);
+      else
+         val->ssa->elems[0]->def = build_frexp32(nb, src[0],
+                                                 &val->ssa->elems[1]->def);
       return;
    }
 




More information about the mesa-commit mailing list