[Mesa-dev] [PATCH 12/22] spirv/nir: implement DF conversions

Juan A. Suarez Romero jasuarez at igalia.com
Fri Nov 25 08:52:42 UTC 2016


From: Samuel Iglesias Gonsálvez <siglesias at igalia.com>

SPIR-V does not have special opcodes for DF conversions. We need to identify
them by checking the bit size of the operand and the result.

Signed-off-by: Samuel Iglesias Gonsálvez <siglesias at igalia.com>
---
 src/compiler/spirv/spirv_to_nir.c | 29 ++++++++++++++++++++++-------
 src/compiler/spirv/vtn_alu.c      | 37 +++++++++++++++++++++++++++----------
 src/compiler/spirv/vtn_private.h  |  3 ++-
 3 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index a13f72a..81c73da 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -1211,12 +1211,21 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
 
       default: {
          bool swap;
-         nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
-
-         unsigned num_components = glsl_get_vector_elements(val->const_type);
          unsigned bit_size =
             glsl_get_bit_size(val->const_type);
 
+         bool is_double_dst = bit_size == 64;
+         bool is_double_src = is_double_dst;
+         /* We assume there is no double conversion here */
+         assert(bit_size != 64 ||
+                (opcode != SpvOpConvertFToU && opcode != SpvOpConvertFToS &&
+                 opcode != SpvOpConvertSToF && opcode != SpvOpConvertUToF &&
+                 opcode != SpvOpFConvert));
+         nir_op op =
+            vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+                                            is_double_dst, is_double_src);
+
+         unsigned num_components = glsl_get_vector_elements(val->const_type);
          nir_const_value src[4];
          assert(count <= 7);
          for (unsigned i = 0; i < count - 4; i++) {
@@ -1224,16 +1233,22 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
                vtn_value(b, w[4 + i], vtn_value_type_constant)->constant;
 
             unsigned j = swap ? 1 - i : i;
-            assert(bit_size == 32);
             for (unsigned k = 0; k < num_components; k++)
-               src[j].u32[k] = c->value.u[k];
+               if (!is_double_src)
+                  src[j].u32[k] = c->value.u[k];
+               else
+                  src[j].f64[k] = c->value.d[k];
          }
 
          nir_const_value res = nir_eval_const_opcode(op, num_components,
                                                      bit_size, src);
 
-         for (unsigned k = 0; k < num_components; k++)
-            val->constant->value.u[k] = res.u32[k];
+         for (unsigned k = 0; k < num_components; k++) {
+            if (!is_double_dst)
+               val->constant->value.u[k] = res.u32[k];
+            else
+               val->constant->value.d[k] = res.f64[k];
+         }
 
          break;
       } /* default */
diff --git a/src/compiler/spirv/vtn_alu.c b/src/compiler/spirv/vtn_alu.c
index 95ff2b1..e444d3f 100644
--- a/src/compiler/spirv/vtn_alu.c
+++ b/src/compiler/spirv/vtn_alu.c
@@ -211,7 +211,8 @@ vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode,
 }
 
 nir_op
-vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap)
+vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
+                                bool is_double_dst, bool is_double_src)
 {
    /* Indicates that the first two arguments should be swapped.  This is
     * used for implementing greater-than and less-than-or-equal.
@@ -284,16 +285,21 @@ vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap)
    case SpvOpFUnordGreaterThanEqual:               return nir_op_fge;
 
    /* Conversions: */
-   case SpvOpConvertFToU:           return nir_op_f2u;
-   case SpvOpConvertFToS:           return nir_op_f2i;
-   case SpvOpConvertSToF:           return nir_op_i2f;
-   case SpvOpConvertUToF:           return nir_op_u2f;
+   case SpvOpConvertFToU:           return is_double_src ? nir_op_d2u : nir_op_f2u;
+   case SpvOpConvertFToS:           return is_double_src ? nir_op_d2i : nir_op_f2i;
+   case SpvOpConvertSToF:           return is_double_dst ? nir_op_i2d : nir_op_i2f;
+   case SpvOpConvertUToF:           return is_double_dst ? nir_op_u2d : nir_op_u2f;
    case SpvOpBitcast:               return nir_op_imov;
    case SpvOpUConvert:
    case SpvOpQuantizeToF16:         return nir_op_fquantize2f16;
-   /* TODO: NIR is 32-bit only; these are no-ops. */
+   /* TODO: int64 is not supported yet. This is a no-op. */
    case SpvOpSConvert:              return nir_op_imov;
-   case SpvOpFConvert:              return nir_op_fmov;
+   case SpvOpFConvert:
+      if (is_double_src && !is_double_dst)
+         return nir_op_d2f;
+      if (!is_double_src && is_double_dst)
+         return nir_op_f2d;
+      return nir_op_fmov;
 
    /* Derivatives: */
    case SpvOpDPdx:         return nir_op_fddx;
@@ -457,7 +463,10 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
    case SpvOpFUnordLessThanEqual:
    case SpvOpFUnordGreaterThanEqual: {
       bool swap;
-      nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
+      bool is_double_src = src[0]->bit_size;
+      bool is_double_dst = glsl_get_bit_size(val->ssa->type);
+      nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+                                                  is_double_dst, is_double_src);
 
       if (swap) {
          nir_ssa_def *tmp = src[0];
@@ -481,7 +490,10 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
    case SpvOpFOrdLessThanEqual:
    case SpvOpFOrdGreaterThanEqual: {
       bool swap;
-      nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
+      bool is_double_src = src[0]->bit_size;
+      bool is_double_dst = glsl_get_bit_size(val->ssa->type);
+      nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+                                                  is_double_dst, is_double_src);
 
       if (swap) {
          nir_ssa_def *tmp = src[0];
@@ -500,7 +512,12 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
 
    default: {
       bool swap;
-      nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap);
+      bool is_double_src = src[0]->bit_size == 64;
+      bool is_double_dst =
+         glsl_get_bit_size(val->ssa->type) == 64;
+
+      nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap,
+                                                  is_double_dst, is_double_src);
 
       if (swap) {
          nir_ssa_def *tmp = src[0];
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 47579fe..7159f8b 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -480,7 +480,8 @@ typedef void (*vtn_execution_mode_foreach_cb)(struct vtn_builder *,
 void vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value,
                                 vtn_execution_mode_foreach_cb cb, void *data);
 
-nir_op vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap);
+nir_op vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap,
+                                       bool is_double_dst, bool is_double_src);
 
 void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
                     const uint32_t *w, unsigned count);
-- 
2.7.4



More information about the mesa-dev mailing list