nir: Support sysval tess levels in SPIR-V to NIR
[mesa.git] / src / compiler / spirv / vtn_glsl450.c
index 59ff4b88485552d4963d82287c1be60ef3c09b99..947d33c6bf644784253f268c20f72b99f0c9a4e9 100644 (file)
@@ -40,7 +40,7 @@ static nir_ssa_def *
 build_mat2_det(nir_builder *b, nir_ssa_def *col[2])
 {
    unsigned swiz[2] = {1, 0 };
-   nir_ssa_def *p = nir_fmul(b, col[0], nir_swizzle(b, col[1], swiz, 2, true));
+   nir_ssa_def *p = nir_fmul(b, col[0], nir_swizzle(b, col[1], swiz, 2));
    return nir_fsub(b, nir_channel(b, p, 0), nir_channel(b, p, 1));
 }
 
@@ -52,12 +52,12 @@ build_mat3_det(nir_builder *b, nir_ssa_def *col[3])
 
    nir_ssa_def *prod0 =
       nir_fmul(b, col[0],
-               nir_fmul(b, nir_swizzle(b, col[1], yzx, 3, true),
-                           nir_swizzle(b, col[2], zxy, 3, true)));
+               nir_fmul(b, nir_swizzle(b, col[1], yzx, 3),
+                           nir_swizzle(b, col[2], zxy, 3)));
    nir_ssa_def *prod1 =
       nir_fmul(b, col[0],
-               nir_fmul(b, nir_swizzle(b, col[1], zxy, 3, true),
-                           nir_swizzle(b, col[2], yzx, 3, true)));
+               nir_fmul(b, nir_swizzle(b, col[1], zxy, 3),
+                           nir_swizzle(b, col[2], yzx, 3)));
 
    nir_ssa_def *diff = nir_fsub(b, prod0, prod1);
 
@@ -76,9 +76,9 @@ build_mat4_det(nir_builder *b, nir_ssa_def **col)
          swiz[j] = j + (j >= i);
 
       nir_ssa_def *subcol[3];
-      subcol[0] = nir_swizzle(b, col[1], swiz, 3, true);
-      subcol[1] = nir_swizzle(b, col[2], swiz, 3, true);
-      subcol[2] = nir_swizzle(b, col[3], swiz, 3, true);
+      subcol[0] = nir_swizzle(b, col[1], swiz, 3);
+      subcol[1] = nir_swizzle(b, col[2], swiz, 3);
+      subcol[2] = nir_swizzle(b, col[3], swiz, 3);
 
       subdet[i] = build_mat3_det(b, subcol);
    }
@@ -121,7 +121,7 @@ build_mat_subdet(struct nir_builder *b, struct vtn_ssa_value *src,
       return nir_channel(b, src->elems[1 - col]->def, 1 - row);
    } else {
       /* Swizzle to get all but the specified row */
-      unsigned swiz[3];
+      unsigned swiz[NIR_MAX_VEC_COMPONENTS] = {0};
       for (unsigned j = 0; j < 3; j++)
          swiz[j] = j + (j >= row);
 
@@ -130,7 +130,7 @@ build_mat_subdet(struct nir_builder *b, struct vtn_ssa_value *src,
       for (unsigned j = 0; j < size; j++) {
          if (j != col) {
             subcol[j - (j > col)] = nir_swizzle(b, src->elems[j]->def,
-                                                swiz, size - 1, true);
+                                                swiz, size - 1);
          }
       }
 
@@ -172,35 +172,18 @@ matrix_inverse(struct vtn_builder *b, struct vtn_ssa_value *src)
 }
 
 /**
- * Return e^x.
- */
-static nir_ssa_def *
-build_exp(nir_builder *b, nir_ssa_def *x)
-{
-   return nir_fexp2(b, nir_fmul_imm(b, x, M_LOG2E));
-}
-
-/**
- * Return ln(x) - the natural logarithm of x.
- */
-static nir_ssa_def *
-build_log(nir_builder *b, nir_ssa_def *x)
-{
-   return nir_fmul_imm(b, nir_flog2(b, x), 1.0 / M_LOG2E);
-}
-
-/**
- * Approximate asin(x) by the formula:
- *    asin~(x) = sign(x) * (pi/2 - sqrt(1 - |x|) * (pi/2 + |x|(pi/4 - 1 + |x|(p0 + |x|p1))))
+ * Approximate asin(x) by the piecewise formula:
+ * for |x| < 0.5, asin~(x) = x * (1 + x²(pS0 + x²(pS1 + x²*pS2)) / (1 + x²*qS1))
+ * for |x| ≥ 0.5, asin~(x) = sign(x) * (π/2 - sqrt(1 - |x|) * (π/2 + |x|(π/4 - 1 + |x|(p0 + |x|p1))))
  *
- * which is correct to first order at x=0 and x=±1 regardless of the p
+ * The latter is correct to first order at x=0 and x=±1 regardless of the p
  * coefficients but can be made second-order correct at both ends by selecting
  * the fit coefficients appropriately.  Different p coefficients can be used
  * in the asin and acos implementation to minimize some relative error metric
  * in each case.
  */
 static nir_ssa_def *
-build_asin(nir_builder *b, nir_ssa_def *x, float p0, float p1)
+build_asin(nir_builder *b, nir_ssa_def *x, float p0, float p1, bool piecewise)
 {
    if (x->bit_size == 16) {
       /* The polynomial approximation isn't precise enough to meet half-float
@@ -213,10 +196,10 @@ build_asin(nir_builder *b, nir_ssa_def *x, float p0, float p1)
        * approximation in 32-bit math and then we convert the result back to
        * 16-bit.
        */
-      return nir_f2f16(b, build_asin(b, nir_f2f32(b, x), p0, p1));
+      return nir_f2f16(b, build_asin(b, nir_f2f32(b, x), p0, p1, piecewise));
    }
-
    nir_ssa_def *one = nir_imm_floatN_t(b, 1.0f, x->bit_size);
+   nir_ssa_def *half = nir_imm_floatN_t(b, 0.5f, x->bit_size);
    nir_ssa_def *abs_x = nir_fabs(b, x);
 
    nir_ssa_def *p0_plus_xp1 = nir_fadd_imm(b, nir_fmul_imm(b, abs_x, p1), p0);
@@ -228,284 +211,42 @@ build_asin(nir_builder *b, nir_ssa_def *x, float p0, float p1)
                                                   M_PI_4f - 1.0f)),
                       M_PI_2f);
 
-   return nir_fmul(b, nir_fsign(b, x),
+   nir_ssa_def *result0 = nir_fmul(b, nir_fsign(b, x),
                       nir_fsub(b, nir_imm_floatN_t(b, M_PI_2f, x->bit_size),
                                   nir_fmul(b, nir_fsqrt(b, nir_fsub(b, one, abs_x)),
                                                            expr_tail)));
-}
-
-/**
- * Compute xs[0] + xs[1] + xs[2] + ... using fadd.
- */
-static nir_ssa_def *
-build_fsum(nir_builder *b, nir_ssa_def **xs, int terms)
-{
-   nir_ssa_def *accum = xs[0];
-
-   for (int i = 1; i < terms; i++)
-      accum = nir_fadd(b, accum, xs[i]);
-
-   return accum;
-}
-
-static nir_ssa_def *
-build_atan(nir_builder *b, nir_ssa_def *y_over_x)
-{
-   const uint32_t bit_size = y_over_x->bit_size;
-
-   nir_ssa_def *abs_y_over_x = nir_fabs(b, y_over_x);
-   nir_ssa_def *one = nir_imm_floatN_t(b, 1.0f, bit_size);
-
-   /*
-    * range-reduction, first step:
-    *
-    *      / y_over_x         if |y_over_x| <= 1.0;
-    * x = <
-    *      \ 1.0 / y_over_x   otherwise
-    */
-   nir_ssa_def *x = nir_fdiv(b, nir_fmin(b, abs_y_over_x, one),
-                                nir_fmax(b, abs_y_over_x, one));
-
-   /*
-    * approximate atan by evaluating polynomial:
-    *
-    * x   * 0.9999793128310355 - x^3  * 0.3326756418091246 +
-    * x^5 * 0.1938924977115610 - x^7  * 0.1173503194786851 +
-    * x^9 * 0.0536813784310406 - x^11 * 0.0121323213173444
-    */
-   nir_ssa_def *x_2  = nir_fmul(b, x,   x);
-   nir_ssa_def *x_3  = nir_fmul(b, x_2, x);
-   nir_ssa_def *x_5  = nir_fmul(b, x_3, x_2);
-   nir_ssa_def *x_7  = nir_fmul(b, x_5, x_2);
-   nir_ssa_def *x_9  = nir_fmul(b, x_7, x_2);
-   nir_ssa_def *x_11 = nir_fmul(b, x_9, x_2);
-
-   nir_ssa_def *polynomial_terms[] = {
-      nir_fmul_imm(b, x,     0.9999793128310355f),
-      nir_fmul_imm(b, x_3,  -0.3326756418091246f),
-      nir_fmul_imm(b, x_5,   0.1938924977115610f),
-      nir_fmul_imm(b, x_7,  -0.1173503194786851f),
-      nir_fmul_imm(b, x_9,   0.0536813784310406f),
-      nir_fmul_imm(b, x_11, -0.0121323213173444f),
-   };
-
-   nir_ssa_def *tmp =
-      build_fsum(b, polynomial_terms, ARRAY_SIZE(polynomial_terms));
-
-   /* range-reduction fixup */
-   tmp = nir_fadd(b, tmp,
-                  nir_fmul(b, nir_b2f(b, nir_flt(b, one, abs_y_over_x), bit_size),
-                           nir_fadd_imm(b, nir_fmul_imm(b, tmp, -2.0f), M_PI_2f)));
-
-   /* sign fixup */
-   return nir_fmul(b, tmp, nir_fsign(b, y_over_x));
-}
-
-static nir_ssa_def *
-build_atan2(nir_builder *b, nir_ssa_def *y, nir_ssa_def *x)
-{
-   assert(y->bit_size == x->bit_size);
-   const uint32_t bit_size = x->bit_size;
-
-   nir_ssa_def *zero = nir_imm_floatN_t(b, 0, bit_size);
-   nir_ssa_def *one = nir_imm_floatN_t(b, 1, bit_size);
-
-   /* If we're on the left half-plane rotate the coordinates π/2 clock-wise
-    * for the y=0 discontinuity to end up aligned with the vertical
-    * discontinuity of atan(s/t) along t=0.  This also makes sure that we
-    * don't attempt to divide by zero along the vertical line, which may give
-    * unspecified results on non-GLSL 4.1-capable hardware.
-    */
-   nir_ssa_def *flip = nir_fge(b, zero, x);
-   nir_ssa_def *s = nir_bcsel(b, flip, nir_fabs(b, x), y);
-   nir_ssa_def *t = nir_bcsel(b, flip, y, nir_fabs(b, x));
-
-   /* If the magnitude of the denominator exceeds some huge value, scale down
-    * the arguments in order to prevent the reciprocal operation from flushing
-    * its result to zero, which would cause precision problems, and for s
-    * infinite would cause us to return a NaN instead of the correct finite
-    * value.
-    *
-    * If fmin and fmax are respectively the smallest and largest positive
-    * normalized floating point values representable by the implementation,
-    * the constants below should be in agreement with:
-    *
-    *    huge <= 1 / fmin
-    *    scale <= 1 / fmin / fmax (for |t| >= huge)
-    *
-    * In addition scale should be a negative power of two in order to avoid
-    * loss of precision.  The values chosen below should work for most usual
-    * floating point representations with at least the dynamic range of ATI's
-    * 24-bit representation.
-    */
-   const double huge_val = bit_size >= 32 ? 1e18 : 16384;
-   nir_ssa_def *huge = nir_imm_floatN_t(b,  huge_val, bit_size);
-   nir_ssa_def *scale = nir_bcsel(b, nir_fge(b, nir_fabs(b, t), huge),
-                                  nir_imm_floatN_t(b, 0.25, bit_size), one);
-   nir_ssa_def *rcp_scaled_t = nir_frcp(b, nir_fmul(b, t, scale));
-   nir_ssa_def *s_over_t = nir_fmul(b, nir_fmul(b, s, scale), rcp_scaled_t);
-
-   /* For |x| = |y| assume tan = 1 even if infinite (i.e. pretend momentarily
-    * that ∞/∞ = 1) in order to comply with the rather artificial rules
-    * inherited from IEEE 754-2008, namely:
-    *
-    *  "atan2(±∞, −∞) is ±3π/4
-    *   atan2(±∞, +∞) is ±π/4"
-    *
-    * Note that this is inconsistent with the rules for the neighborhood of
-    * zero that are based on iterated limits:
-    *
-    *  "atan2(±0, −0) is ±π
-    *   atan2(±0, +0) is ±0"
-    *
-    * but GLSL specifically allows implementations to deviate from IEEE rules
-    * at (0,0), so we take that license (i.e. pretend that 0/0 = 1 here as
-    * well).
-    */
-   nir_ssa_def *tan = nir_bcsel(b, nir_feq(b, nir_fabs(b, x), nir_fabs(b, y)),
-                                one, nir_fabs(b, s_over_t));
-
-   /* Calculate the arctangent and fix up the result if we had flipped the
-    * coordinate system.
-    */
-   nir_ssa_def *arc =
-      nir_fadd(b, nir_fmul_imm(b, nir_b2f(b, flip, bit_size), M_PI_2f),
-                  build_atan(b, tan));
-
-   /* Rather convoluted calculation of the sign of the result.  When x < 0 we
-    * cannot use fsign because we need to be able to distinguish between
-    * negative and positive zero.  We don't use bitwise arithmetic tricks for
-    * consistency with the GLSL front-end.  When x >= 0 rcp_scaled_t will
-    * always be non-negative so this won't be able to distinguish between
-    * negative and positive zero, but we don't care because atan2 is
-    * continuous along the whole positive y = 0 half-line, so it won't affect
-    * the result significantly.
-    */
-   return nir_bcsel(b, nir_flt(b, nir_fmin(b, y, rcp_scaled_t), zero),
-                    nir_fneg(b, arc), arc);
-}
-
-static nir_ssa_def *
-build_frexp16(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent)
-{
-   assert(x->bit_size == 16);
-
-   nir_ssa_def *abs_x = nir_fabs(b, x);
-   nir_ssa_def *zero = nir_imm_floatN_t(b, 0, 16);
-
-   /* Half-precision floating-point values are stored as
-    *   1 sign bit;
-    *   5 exponent bits;
-    *   10 mantissa bits.
-    *
-    * An exponent shift of 10 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).
-    */
-   nir_ssa_def *exponent_shift = nir_imm_int(b, 10);
-   nir_ssa_def *exponent_bias = nir_imm_intN_t(b, -14, 16);
-
-   nir_ssa_def *sign_mantissa_mask = nir_imm_intN_t(b, 0x83ffu, 16);
-
-   /* Exponent of floating-point values in the range [0.5, 1.0). */
-   nir_ssa_def *exponent_value = nir_imm_intN_t(b, 0x3800u, 16);
-
-   nir_ssa_def *is_not_zero = nir_fne(b, abs_x, zero);
-
-   /* Significand return must be of the same type as the input, but the
-    * exponent must be a 32-bit integer.
-    */
-   *exponent =
-      nir_i2i32(b,
-                nir_iadd(b, nir_ushr(b, abs_x, exponent_shift),
-                            nir_bcsel(b, is_not_zero, exponent_bias, zero)));
-
-   return nir_ior(b, nir_iand(b, x, sign_mantissa_mask),
-                     nir_bcsel(b, is_not_zero, exponent_value, zero));
-}
-
-static nir_ssa_def *
-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);
-
-   /* 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.
-    */
-   nir_ssa_def *exponent_shift = nir_imm_int(b, 23);
-   nir_ssa_def *exponent_bias = nir_imm_int(b, -126);
-
-   nir_ssa_def *sign_mantissa_mask = nir_imm_int(b, 0x807fffffu);
-
-   /* Exponent of floating-point values in the range [0.5, 1.0). */
-   nir_ssa_def *exponent_value = nir_imm_int(b, 0x3f000000u);
-
-   nir_ssa_def *is_not_zero = nir_fne(b, abs_x, zero);
-
-   *exponent =
-      nir_iadd(b, nir_ushr(b, abs_x, exponent_shift),
-                  nir_bcsel(b, is_not_zero, exponent_bias, zero));
-
-   return nir_ior(b, nir_iand(b, x, sign_mantissa_mask),
-                     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);
+   if (piecewise) {
+      /* approximation for |x| < 0.5 */
+      const float pS0 =  1.6666586697e-01f;
+      const float pS1 = -4.2743422091e-02f;
+      const float pS2 = -8.6563630030e-03f;
+      const float qS1 = -7.0662963390e-01f;
+
+      nir_ssa_def *x2 = nir_fmul(b, x, x);
+      nir_ssa_def *p = nir_fmul(b,
+                                x2,
+                                nir_fadd_imm(b,
+                                             nir_fmul(b,
+                                                      x2,
+                                                      nir_fadd_imm(b, nir_fmul_imm(b, x2, pS2),
+                                                                   pS1)),
+                                             pS0));
+
+      nir_ssa_def *q = nir_fadd(b, one, nir_fmul_imm(b, x2, qS1));
+      nir_ssa_def *result1 = nir_fadd(b, x, nir_fmul(b, x, nir_fdiv(b, p, q)));
+      return nir_bcsel(b, nir_flt(b, abs_x, half), result1, result0);
+   } else {
+      return result0;
+   }
 }
 
 static nir_op
 vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b,
-                                     enum GLSLstd450 opcode)
+                                     enum GLSLstd450 opcode,
+                                     unsigned execution_mode,
+                                     bool *exact)
 {
+   *exact = false;
    switch (opcode) {
    case GLSLstd450Round:         return nir_op_fround_even;
    case GLSLstd450RoundEven:     return nir_op_fround_even;
@@ -524,11 +265,11 @@ vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b,
    case GLSLstd450Log2:          return nir_op_flog2;
    case GLSLstd450Sqrt:          return nir_op_fsqrt;
    case GLSLstd450InverseSqrt:   return nir_op_frsq;
-   case GLSLstd450NMin:          return nir_op_fmin;
+   case GLSLstd450NMin:          *exact = true; return nir_op_fmin;
    case GLSLstd450FMin:          return nir_op_fmin;
    case GLSLstd450UMin:          return nir_op_umin;
    case GLSLstd450SMin:          return nir_op_imin;
-   case GLSLstd450NMax:          return nir_op_fmax;
+   case GLSLstd450NMax:          *exact = true; return nir_op_fmax;
    case GLSLstd450FMax:          return nir_op_fmax;
    case GLSLstd450UMax:          return nir_op_umax;
    case GLSLstd450SMax:          return nir_op_imax;
@@ -550,7 +291,11 @@ vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b,
    case GLSLstd450UnpackUnorm4x8:   return nir_op_unpack_unorm_4x8;
    case GLSLstd450UnpackSnorm2x16:  return nir_op_unpack_snorm_2x16;
    case GLSLstd450UnpackUnorm2x16:  return nir_op_unpack_unorm_2x16;
-   case GLSLstd450UnpackHalf2x16:   return nir_op_unpack_half_2x16;
+   case GLSLstd450UnpackHalf2x16:
+      if (execution_mode & FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP16)
+         return nir_op_unpack_half_2x16_flush_to_zero;
+      else
+         return nir_op_unpack_half_2x16;
    case GLSLstd450UnpackDouble2x32: return nir_op_unpack_64_2x32;
 
    default:
@@ -590,8 +335,7 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint,
       val->ssa->def = nir_degrees(nb, src[0]);
       return;
    case GLSLstd450Tan:
-      val->ssa->def = nir_fdiv(nb, nir_fsin(nb, src[0]),
-                               nir_fcos(nb, src[0]));
+      val->ssa->def = nir_ftan(nb, src[0]);
       return;
 
    case GLSLstd450Modf: {
@@ -627,16 +371,20 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint,
       return;
 
    case GLSLstd450Exp:
-      val->ssa->def = build_exp(nb, src[0]);
+      val->ssa->def = nir_fexp(nb, src[0]);
       return;
 
    case GLSLstd450Log:
-      val->ssa->def = build_log(nb, src[0]);
+      val->ssa->def = nir_flog(nb, src[0]);
       return;
 
    case GLSLstd450FClamp:
+      val->ssa->def = nir_fclamp(nb, src[0], src[1], src[2]);
+      return;
    case GLSLstd450NClamp:
+      nb->exact = true;
       val->ssa->def = nir_fclamp(nb, src[0], src[1], src[2]);
+      nb->exact = false;
       return;
    case GLSLstd450UClamp:
       val->ssa->def = nir_uclamp(nb, src[0], src[1], src[2]);
@@ -707,113 +455,104 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint,
    case GLSLstd450Sinh:
       /* 0.5 * (e^x - e^(-x)) */
       val->ssa->def =
-         nir_fmul_imm(nb, nir_fsub(nb, build_exp(nb, src[0]),
-                                       build_exp(nb, nir_fneg(nb, src[0]))),
+         nir_fmul_imm(nb, nir_fsub(nb, nir_fexp(nb, src[0]),
+                                       nir_fexp(nb, nir_fneg(nb, src[0]))),
                           0.5f);
       return;
 
    case GLSLstd450Cosh:
       /* 0.5 * (e^x + e^(-x)) */
       val->ssa->def =
-         nir_fmul_imm(nb, nir_fadd(nb, build_exp(nb, src[0]),
-                                       build_exp(nb, nir_fneg(nb, src[0]))),
+         nir_fmul_imm(nb, nir_fadd(nb, nir_fexp(nb, src[0]),
+                                       nir_fexp(nb, nir_fneg(nb, src[0]))),
                           0.5f);
       return;
 
    case GLSLstd450Tanh: {
-      /* tanh(x) := (0.5 * (e^x - e^(-x))) / (0.5 * (e^x + e^(-x)))
-       *
-       * With a little algebra this reduces to (e^2x - 1) / (e^2x + 1)
+      /* tanh(x) := (e^x - e^(-x)) / (e^x + e^(-x))
        *
-       * We clamp x to (-inf, +10] to avoid precision problems.  When x > 10,
-       * e^2x is so much larger than 1.0 that 1.0 gets flushed to zero in the
-       * computation e^2x +/- 1 so it can be ignored.
+       * We clamp x to [-10, +10] to avoid precision problems.  When x > 10,
+       * e^x dominates the sum, e^(-x) is lost and tanh(x) is 1.0 for 32 bit
+       * floating point.
        *
-       * For 16-bit precision we clamp x to (-inf, +4.2] since the maximum
-       * representable number is only 65,504 and e^(2*6) exceeds that. Also,
-       * if x > 4.2, tanh(x) will return 1.0 in fp16.
+       * For 16-bit precision this we clamp x to [-4.2, +4.2].
        */
       const uint32_t bit_size = src[0]->bit_size;
       const double clamped_x = bit_size > 16 ? 10.0 : 4.2;
-      nir_ssa_def *x = nir_fmin(nb, src[0],
-                                    nir_imm_floatN_t(nb, clamped_x, bit_size));
-      nir_ssa_def *exp2x = build_exp(nb, nir_fmul_imm(nb, x, 2.0));
-      val->ssa->def = nir_fdiv(nb, nir_fadd_imm(nb, exp2x, -1.0),
-                                   nir_fadd_imm(nb, exp2x, 1.0));
+      nir_ssa_def *x = nir_fclamp(nb, src[0],
+                                  nir_imm_floatN_t(nb, -clamped_x, bit_size),
+                                  nir_imm_floatN_t(nb, clamped_x, bit_size));
+      val->ssa->def =
+         nir_fdiv(nb, nir_fsub(nb, nir_fexp(nb, x),
+                               nir_fexp(nb, nir_fneg(nb, x))),
+                  nir_fadd(nb, nir_fexp(nb, x),
+                           nir_fexp(nb, nir_fneg(nb, x))));
       return;
    }
 
    case GLSLstd450Asinh:
       val->ssa->def = nir_fmul(nb, nir_fsign(nb, src[0]),
-         build_log(nb, nir_fadd(nb, nir_fabs(nb, src[0]),
-                       nir_fsqrt(nb, nir_fadd_imm(nb, nir_fmul(nb, src[0], src[0]),
-                                                      1.0f)))));
+         nir_flog(nb, nir_fadd(nb, nir_fabs(nb, src[0]),
+                      nir_fsqrt(nb, nir_fadd_imm(nb, nir_fmul(nb, src[0], src[0]),
+                                                    1.0f)))));
       return;
    case GLSLstd450Acosh:
-      val->ssa->def = build_log(nb, nir_fadd(nb, src[0],
+      val->ssa->def = nir_flog(nb, nir_fadd(nb, src[0],
          nir_fsqrt(nb, nir_fadd_imm(nb, nir_fmul(nb, src[0], src[0]),
                                         -1.0f))));
       return;
    case GLSLstd450Atanh: {
       nir_ssa_def *one = nir_imm_floatN_t(nb, 1.0, src[0]->bit_size);
       val->ssa->def =
-         nir_fmul_imm(nb, build_log(nb, nir_fdiv(nb, nir_fadd(nb, src[0], one),
-                                        nir_fsub(nb, one, src[0]))),
+         nir_fmul_imm(nb, nir_flog(nb, nir_fdiv(nb, nir_fadd(nb, src[0], one),
+                                       nir_fsub(nb, one, src[0]))),
                           0.5f);
       return;
    }
 
    case GLSLstd450Asin:
-      val->ssa->def = build_asin(nb, src[0], 0.086566724, -0.03102955);
+      val->ssa->def = build_asin(nb, src[0], 0.086566724, -0.03102955, true);
       return;
 
    case GLSLstd450Acos:
       val->ssa->def =
          nir_fsub(nb, nir_imm_floatN_t(nb, M_PI_2f, src[0]->bit_size),
-                      build_asin(nb, src[0], 0.08132463, -0.02363318));
+                      build_asin(nb, src[0], 0.08132463, -0.02363318, false));
       return;
 
    case GLSLstd450Atan:
-      val->ssa->def = build_atan(nb, src[0]);
+      val->ssa->def = nir_atan(nb, src[0]);
       return;
 
    case GLSLstd450Atan2:
-      val->ssa->def = build_atan2(nb, src[0], src[1]);
+      val->ssa->def = nir_atan2(nb, src[0], src[1]);
       return;
 
    case GLSLstd450Frexp: {
-      nir_ssa_def *exponent;
-      if (src[0]->bit_size == 64)
-         val->ssa->def = build_frexp64(nb, src[0], &exponent);
-      else if (src[0]->bit_size == 32)
-         val->ssa->def = build_frexp32(nb, src[0], &exponent);
-      else
-         val->ssa->def = build_frexp16(nb, src[0], &exponent);
+      nir_ssa_def *exponent = nir_frexp_exp(nb, src[0]);
+      val->ssa->def = nir_frexp_sig(nb, src[0]);
       nir_store_deref(nb, vtn_nir_deref(b, w[6]), exponent, 0xf);
       return;
    }
 
    case GLSLstd450FrexpStruct: {
       vtn_assert(glsl_type_is_struct_or_ifc(val->ssa->type));
-      if (src[0]->bit_size == 64)
-         val->ssa->elems[0]->def = build_frexp64(nb, src[0],
-                                                 &val->ssa->elems[1]->def);
-      else if (src[0]->bit_size == 32)
-         val->ssa->elems[0]->def = build_frexp32(nb, src[0],
-                                                 &val->ssa->elems[1]->def);
-      else
-         val->ssa->elems[0]->def = build_frexp16(nb, src[0],
-                                                 &val->ssa->elems[1]->def);
+      val->ssa->elems[0]->def = nir_frexp_sig(nb, src[0]);
+      val->ssa->elems[1]->def = nir_frexp_exp(nb, src[0]);
       return;
    }
 
-   default:
-      val->ssa->def =
-         nir_build_alu(&b->nb,
-                       vtn_nir_alu_op_for_spirv_glsl_opcode(b, entrypoint),
-                       src[0], src[1], src[2], NULL);
+   default: {
+      unsigned execution_mode =
+         b->shader->info.float_controls_execution_mode;
+      bool exact;
+      nir_op op = vtn_nir_alu_op_for_spirv_glsl_opcode(b, entrypoint, execution_mode, &exact);
+      b->nb.exact = exact;
+      val->ssa->def = nir_build_alu(&b->nb, op, src[0], src[1], src[2], NULL);
+      b->nb.exact = false;
       return;
    }
+   }
 }
 
 static void
@@ -882,13 +621,8 @@ handle_glsl450_interpolation(struct vtn_builder *b, enum GLSLstd450 opcode,
 
    if (vec_array_deref) {
       assert(vec_deref);
-      if (nir_src_is_const(vec_deref->arr.index)) {
-         val->ssa->def = vtn_vector_extract(b, &intrin->dest.ssa,
-                                            nir_src_as_uint(vec_deref->arr.index));
-      } else {
-         val->ssa->def = vtn_vector_extract_dynamic(b, &intrin->dest.ssa,
-                                                    vec_deref->arr.index.ssa);
-      }
+      val->ssa->def = nir_vector_extract(&b->nb, &intrin->dest.ssa,
+                                         vec_deref->arr.index.ssa);
    } else {
       val->ssa->def = &intrin->dest.ssa;
    }
@@ -916,7 +650,7 @@ vtn_handle_glsl450_instruction(struct vtn_builder *b, SpvOp ext_opcode,
    case GLSLstd450InterpolateAtCentroid:
    case GLSLstd450InterpolateAtSample:
    case GLSLstd450InterpolateAtOffset:
-      handle_glsl450_interpolation(b, ext_opcode, w, count);
+      handle_glsl450_interpolation(b, (enum GLSLstd450)ext_opcode, w, count);
       break;
 
    default: