Mesa (main): microsoft/compiler: Lower fquantize2f16

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jun 10 08:05:40 UTC 2022


Module: Mesa
Branch: main
Commit: b12417a2c717747e79e572b6d31337d92050f18f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=b12417a2c717747e79e572b6d31337d92050f18f

Author: Boris Brezillon <boris.brezillon at collabora.com>
Date:   Mon Feb 14 06:58:02 2022 -0800

microsoft/compiler: Lower fquantize2f16

As far as I can't tell, there's no native operation doing this
equivalent of fquantize2f16. Let's lower this operation to

   if (val < MIN_FLOAT16)
      return -INFINITY;
   else if (val > MAX_FLOAT16)
      return -INFINITY;
   else if (fabs(val) < SMALLER_NORMALIZED_FLOAT16)
      return 0;
   else
      return val;

which matches the definition of OpQuantizeToF16:

"
If Value is an infinity, the result is the same infinity.
If Value is a NaN, the result is a NaN, but not necessarily the same NaN.
If Value is positive with a magnitude too large to represent as a 16-bit
floating-point value, the result is positive infinity. If Value is negative
with a magnitude too large to represent as a 16-bit floating-point value,
the result is negative infinity. If the magnitude of Value is too small to
represent as a normalized 16-bit floating-point value, the result may be
either +0 or -0.
"

Reviewed-by: Jesse Natalie <jenatali at microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16959>

---

 src/microsoft/compiler/dxil_nir.c    | 66 ++++++++++++++++++++++++++++++++++++
 src/microsoft/compiler/dxil_nir.h    |  1 +
 src/microsoft/compiler/nir_to_dxil.c |  1 +
 3 files changed, 68 insertions(+)

diff --git a/src/microsoft/compiler/dxil_nir.c b/src/microsoft/compiler/dxil_nir.c
index 350576aee98..97a28515565 100644
--- a/src/microsoft/compiler/dxil_nir.c
+++ b/src/microsoft/compiler/dxil_nir.c
@@ -1902,3 +1902,69 @@ dxil_nir_lower_ubo_array_one_to_static(nir_shader *s)
 
    return progress;
 }
+
+static bool
+is_fquantize2f16(const nir_instr *instr, const void *data)
+{
+   if (instr->type != nir_instr_type_alu)
+      return false;
+
+   nir_alu_instr *alu = nir_instr_as_alu(instr);
+   return alu->op == nir_op_fquantize2f16;
+}
+
+static nir_ssa_def *
+lower_fquantize2f16(struct nir_builder *b, nir_instr *instr, void *data)
+{
+   /*
+    * SpvOpQuantizeToF16 documentation says:
+    *
+    * "
+    * If Value is an infinity, the result is the same infinity.
+    * If Value is a NaN, the result is a NaN, but not necessarily the same NaN.
+    * If Value is positive with a magnitude too large to represent as a 16-bit
+    * floating-point value, the result is positive infinity. If Value is negative
+    * with a magnitude too large to represent as a 16-bit floating-point value,
+    * the result is negative infinity. If the magnitude of Value is too small to
+    * represent as a normalized 16-bit floating-point value, the result may be
+    * either +0 or -0.
+    * "
+    *
+    * which we turn into:
+    *
+    *   if (val < MIN_FLOAT16)
+    *      return -INFINITY;
+    *   else if (val > MAX_FLOAT16)
+    *      return -INFINITY;
+    *   else if (fabs(val) < SMALLEST_NORMALIZED_FLOAT16 && sign(val) != 0)
+    *      return -0.0f;
+    *   else if (fabs(val) < SMALLEST_NORMALIZED_FLOAT16 && sign(val) == 0)
+    *      return +0.0f;
+    *   else
+    *      return round(val);
+    */
+   nir_alu_instr *alu = nir_instr_as_alu(instr);
+   nir_ssa_def *src =
+      nir_ssa_for_src(b, alu->src[0].src, nir_src_num_components(alu->src[0].src));
+
+   nir_ssa_def *neg_inf_cond =
+      nir_flt(b, src, nir_imm_float(b, -65504.0f));
+   nir_ssa_def *pos_inf_cond =
+      nir_flt(b, nir_imm_float(b, 65504.0f), src);
+   nir_ssa_def *zero_cond =
+      nir_flt(b, nir_fabs(b, src), nir_imm_float(b, ldexpf(1.0, -14)));
+   nir_ssa_def *zero = nir_iand_imm(b, src, 1 << 31);
+   nir_ssa_def *round = nir_iand_imm(b, src, ~BITFIELD_MASK(13));
+
+   nir_ssa_def *res =
+      nir_bcsel(b, neg_inf_cond, nir_imm_float(b, -INFINITY), round);
+   res = nir_bcsel(b, pos_inf_cond, nir_imm_float(b, INFINITY), res);
+   res = nir_bcsel(b, zero_cond, zero, res);
+   return res;
+}
+
+bool
+dxil_nir_lower_fquantize2f16(nir_shader *s)
+{
+   return nir_shader_lower_instructions(s, is_fquantize2f16, lower_fquantize2f16, NULL);
+}
diff --git a/src/microsoft/compiler/dxil_nir.h b/src/microsoft/compiler/dxil_nir.h
index 1d04fe73c95..1d271347966 100644
--- a/src/microsoft/compiler/dxil_nir.h
+++ b/src/microsoft/compiler/dxil_nir.h
@@ -35,6 +35,7 @@ extern "C" {
 bool dxil_nir_lower_8bit_conv(nir_shader *shader);
 bool dxil_nir_lower_16bit_conv(nir_shader *shader);
 bool dxil_nir_lower_x2b(nir_shader *shader);
+bool dxil_nir_lower_fquantize2f16(nir_shader *shader);
 bool dxil_nir_lower_ubo_to_temp(nir_shader *shader);
 bool dxil_nir_lower_loads_stores_to_dxil(nir_shader *shader);
 bool dxil_nir_lower_atomics_to_dxil(nir_shader *shader);
diff --git a/src/microsoft/compiler/nir_to_dxil.c b/src/microsoft/compiler/nir_to_dxil.c
index b8641233fa9..c8a17c4ef9e 100644
--- a/src/microsoft/compiler/nir_to_dxil.c
+++ b/src/microsoft/compiler/nir_to_dxil.c
@@ -5710,6 +5710,7 @@ nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts,
    ctx->mod.major_version = 6;
    ctx->mod.minor_version = 1;
 
+   NIR_PASS_V(s, dxil_nir_lower_fquantize2f16);
    NIR_PASS_V(s, nir_lower_frexp);
    NIR_PASS_V(s, nir_lower_flrp, 16 | 32 | 64, true);
    NIR_PASS_V(s, nir_lower_io, nir_var_shader_in | nir_var_shader_out, type_size_vec4, nir_lower_io_lower_64bit_to_32);



More information about the mesa-commit mailing list