[Mesa-dev] [PATCH v3 09/19] nir/vtn: initial OpenCL.std extension

Karol Herbst kherbst at redhat.com
Fri Mar 23 19:33:46 UTC 2018


From: Rob Clark <robdclark at gmail.com>

Not complete, mostly just adding things as I encounter them in CTS.  But
not getting far enough yet to hit most of the OpenCL.std instructions.

v2: update hadd definition (Karol Herbst <kherbst at redhat.com>)

Signed-off-by: Rob Clark <robdclark at gmail.com>
Signed-off-by: Karol Herbst <kherbst at redhat.com>
---
 src/compiler/nir/meson.build      |   1 +
 src/compiler/nir/nir_opcodes.py   |   3 +-
 src/compiler/spirv/spirv_to_nir.c |   2 +
 src/compiler/spirv/vtn_opencl.c   | 266 ++++++++++++++++++++++++++++++++++++++
 src/compiler/spirv/vtn_private.h  |   3 +
 5 files changed, 274 insertions(+), 1 deletion(-)
 create mode 100644 src/compiler/spirv/vtn_opencl.c

diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
index a70c236b958..213a139a1b8 100644
--- a/src/compiler/nir/meson.build
+++ b/src/compiler/nir/meson.build
@@ -192,6 +192,7 @@ files_libnir = files(
   '../spirv/vtn_amd.c',
   '../spirv/vtn_cfg.c',
   '../spirv/vtn_glsl450.c',
+  '../spirv/vtn_opencl.c',
   '../spirv/vtn_private.h',
   '../spirv/vtn_subgroup.c',
   '../spirv/vtn_variables.c',
diff --git a/src/compiler/nir/nir_opcodes.py b/src/compiler/nir/nir_opcodes.py
index 65d13200624..86fd6b6d68e 100644
--- a/src/compiler/nir/nir_opcodes.py
+++ b/src/compiler/nir/nir_opcodes.py
@@ -768,4 +768,5 @@ dst.z = src2.x;
 dst.w = src3.x;
 """)
 
-
+binop("ihadd", tint, commutative, "(src0 >> 1) + (src1 >> 1) + (src0 & src1 & 1)")
+binop("uhadd", tuint, commutative, "(src0 >> 1) + (src1 >> 1) + (src0 & src1 & 1)")
diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index 3acb3fc0b42..6a16d77a771 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -379,6 +379,8 @@ vtn_handle_extension(struct vtn_builder *b, SpvOp opcode,
       } else if ((strcmp((const char *)&w[2], "SPV_AMD_gcn_shader") == 0)
                 && (b->options && b->options->caps.gcn_shader)) {
          val->ext_handler = vtn_handle_amd_gcn_shader_instruction;
+      } else if (strcmp(ext, "OpenCL.std") == 0) {
+         val->ext_handler = vtn_handle_opencl_instruction;
       } else {
          vtn_fail("Unsupported extension: %s", ext);
       }
diff --git a/src/compiler/spirv/vtn_opencl.c b/src/compiler/spirv/vtn_opencl.c
new file mode 100644
index 00000000000..3c5ecd22452
--- /dev/null
+++ b/src/compiler/spirv/vtn_opencl.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright © 2018 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark (robdclark at gmail.com)
+ */
+
+#include "vtn_private.h"
+#include "OpenCL.std.h"
+
+typedef nir_ssa_def *(*nir_handler)(struct vtn_builder *b, enum OpenCLstd opcode,
+                                    unsigned num_srcs, nir_ssa_def **srcs);
+
+static void
+handle_instr(struct vtn_builder *b, enum OpenCLstd opcode, const uint32_t *w,
+             unsigned count, nir_handler handler)
+{
+   const struct glsl_type *dest_type =
+      vtn_value(b, w[1], vtn_value_type_type)->type->type;
+
+   unsigned num_srcs = count - 5;
+   nir_ssa_def *srcs[3] = { NULL, };
+   vtn_assert(num_srcs <= ARRAY_SIZE(srcs));
+   for (unsigned i = 0; i < num_srcs; i++) {
+      srcs[i] = vtn_ssa_value(b, w[i + 5])->def;
+   }
+
+   nir_ssa_def *result = handler(b, opcode, num_srcs, srcs);
+   if (result) {
+      struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+      val->ssa = vtn_create_ssa_value(b, dest_type);
+      val->ssa->def = result;
+   } else {
+      vtn_assert(dest_type == glsl_void_type());
+   }
+}
+
+static nir_op
+nir_alu_op_for_opencl_opcode(struct vtn_builder *b, enum OpenCLstd opcode)
+{
+   switch (opcode) {
+   case SHadd: return nir_op_ihadd;
+   case UHadd: return nir_op_uhadd;
+   default:
+      vtn_fail("No NIR equivalent");
+   }
+}
+
+static nir_ssa_def *
+handle_alu(struct vtn_builder *b, enum OpenCLstd opcode, unsigned num_srcs,
+           nir_ssa_def **srcs)
+{
+   return nir_build_alu(&b->nb, nir_alu_op_for_opencl_opcode(b, opcode),
+                        srcs[0], srcs[1], srcs[2], NULL);
+}
+
+static nir_ssa_def *
+handle_printf(struct vtn_builder *b, enum OpenCLstd opcode, unsigned num_srcs,
+              nir_ssa_def **srcs)
+{
+   /* hahah, yeah, right.. */
+   return nir_imm_int(&b->nb, -1);
+}
+
+static void
+vtn_handle_opencl_vload(struct vtn_builder *b, enum OpenCLstd opcode,
+                        const uint32_t *w, unsigned count)
+{
+   const struct glsl_type *dest_type =
+      vtn_value(b, w[1], vtn_value_type_type)->type->type;
+   unsigned num_components, bit_size;
+
+   struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+   val->ssa = vtn_create_ssa_value(b, dest_type);
+
+   switch (opcode) {
+   case Vload_half:
+   case Vload_halfn:
+   case Vloada_halfn:
+      bit_size = 16;
+      break;
+   default:
+      bit_size = glsl_get_bit_size(dest_type);
+      break;
+   }
+
+   nir_ssa_def *offset = vtn_ssa_value(b, w[5])->def;
+   nir_ssa_def *p      = vtn_ssa_value(b, w[6])->def;
+
+   if (count >= 7) {
+      num_components = w[7];
+
+      unsigned off;
+      if ((opcode == Vloada_halfn) && (num_components == 3)) {
+         off = 4 * bit_size / 8;
+      } else {
+         off = num_components * bit_size / 8;
+      }
+
+      nir_ssa_def *n = (b->ptr_size == 64) ?
+            nir_imm_int64(&b->nb, off) :
+            nir_imm_int(&b->nb, off);
+
+      offset = nir_imul(&b->nb, offset, n);
+   } else {
+      num_components = 1;
+   }
+
+   /* add offset to pointer: */
+   p = nir_iadd(&b->nb, p, offset);
+
+   nir_intrinsic_op op = nir_intrinsic_load_global;
+
+   nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b->shader, op);
+   intrin->num_components = num_components;
+   intrin->src[0] = nir_src_for_ssa(p);
+
+   nir_ssa_dest_init(&intrin->instr, &intrin->dest,
+                     intrin->num_components,
+                     bit_size,
+                     NULL);
+   val->ssa->def = &intrin->dest.ssa;
+
+   nir_builder_instr_insert(&b->nb, &intrin->instr);
+
+   switch (opcode) {
+   case Vload_half:
+   case Vload_halfn:
+   case Vloada_halfn:
+      /* convert f16->f32: */
+      val->ssa->def = nir_f2f32(&b->nb, val->ssa->def);
+      break;
+   default:
+      break;
+   }
+}
+
+static void
+vtn_handle_opencl_vstore(struct vtn_builder *b, enum OpenCLstd opcode,
+                         const uint32_t *w, unsigned count)
+{
+   unsigned num_components, bit_size;
+   const struct glsl_type *src_type = vtn_ssa_value(b, w[5])->type;
+
+   nir_ssa_def *data   = vtn_ssa_value(b, w[5])->def;
+   nir_ssa_def *offset = vtn_ssa_value(b, w[6])->def;
+   nir_ssa_def *p      = vtn_ssa_value(b, w[7])->def;
+
+   // ??? MAX2(1, glsl_get_vector_elements(src_type));
+   num_components = data->num_components;
+
+   switch (opcode) {
+   case Vstore_half_r:
+   case Vstore_halfn_r:
+   case Vstorea_halfn_r:
+      bit_size = 16;
+      switch (w[8]) {
+      case SpvFPRoundingModeRTE:
+         data = nir_f2f16_rtne(&b->nb, data);
+         break;
+      case SpvFPRoundingModeRTZ:
+         data = nir_f2f16_rtz(&b->nb, data);
+         break;
+      case SpvFPRoundingModeRTP:
+      case SpvFPRoundingModeRTN:
+      default:
+         vtn_fail("unsupported rounding mode: %u\n", w[8]);
+         break;
+      }
+      break;
+   case Vstore_half:
+   case Vstore_halfn:
+   case Vstorea_halfn:
+      bit_size = 16;
+      data = nir_f2f16_undef(&b->nb, data);
+      break;
+   default:
+      bit_size = glsl_get_bit_size(src_type);
+      break;
+   }
+
+   if (num_components > 1) {
+      unsigned off;
+
+      if (((opcode == Vstorea_halfn_r) || (opcode == Vstorea_halfn)) &&
+          (num_components == 3)) {
+         off = 4 * bit_size / 8;
+      } else {
+         off = num_components * bit_size / 8;
+      }
+
+      nir_ssa_def *n = (b->ptr_size == 64) ?
+            nir_imm_int64(&b->nb, off) :
+            nir_imm_int(&b->nb, off);
+
+      offset = nir_imul(&b->nb, offset, n);
+   }
+
+   /* add offset to pointer: */
+   p = nir_iadd(&b->nb, p, offset);
+
+   nir_intrinsic_op op = nir_intrinsic_store_global;
+
+   nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b->shader, op);
+   intrin->num_components = num_components;
+   intrin->src[0] = nir_src_for_ssa(data);
+   intrin->src[1] = nir_src_for_ssa(p);
+   nir_intrinsic_set_write_mask(intrin, (1 << num_components) - 1);
+
+   nir_builder_instr_insert(&b->nb, &intrin->instr);
+}
+
+bool
+vtn_handle_opencl_instruction(struct vtn_builder *b, uint32_t ext_opcode,
+                              const uint32_t *w, unsigned count)
+{
+   switch (ext_opcode) {
+   case SHadd:
+   case UHadd:
+      handle_instr(b, ext_opcode, w, count, handle_alu);
+      return true;
+   case Vloadn:
+   case Vload_half:
+   case Vload_halfn:
+   case Vloada_halfn:
+      vtn_handle_opencl_vload(b, ext_opcode, w, count);
+      return true;
+   case Vstoren:
+   case Vstore_half:
+   case Vstore_half_r:
+   case Vstore_halfn:
+   case Vstore_halfn_r:
+   case Vstorea_halfn:
+   case Vstorea_halfn_r:
+      vtn_handle_opencl_vstore(b, ext_opcode, w, count);
+      return true;
+   case Printf:
+      handle_instr(b, ext_opcode, w, count, handle_printf);
+      return true;
+   case Prefetch:
+      /* TODO maybe add a nir instruction for this? */
+      return true;
+   default:
+      vtn_fail("unhandled opencl opc: %u\n", ext_opcode);
+      return false;
+   }
+}
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index dbfe9eab58a..510c12faa87 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -744,6 +744,9 @@ void vtn_handle_subgroup(struct vtn_builder *b, SpvOp opcode,
 bool vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode,
                                     const uint32_t *words, unsigned count);
 
+bool vtn_handle_opencl_instruction(struct vtn_builder *b, uint32_t ext_opcode,
+                                   const uint32_t *words, unsigned count);
+
 static inline uint32_t
 vtn_align_u32(uint32_t v, uint32_t a)
 {
-- 
2.14.3



More information about the mesa-dev mailing list