Mesa (master): nir/vtn: Implement printf opcode in terms of intrinsic (v9)

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Dec 29 00:13:27 UTC 2020


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

Author: Jesse Natalie <jenatali at microsoft.com>
Date:   Sun Jun 21 14:36:00 2020 -0700

nir/vtn: Implement printf opcode in terms of intrinsic (v9)

[airlied: rebase fixup types]

v2: add support for storing strings in a sideband storage,
just store the index in print buffer.

v3: move the format strings into the nir shader as well

v4: simplify the write constant string + explicit sizes
move printf cap definition.

v5: just parse the format string to find string specifiers
using util code.
add vtn_fail_if if we can't get the correct type.

v6: use ralloc + avoid instr handler for srcs > 5

v7: use a packed struct 4 bytes align all of it

v8: simplify constant copy

v9: rework to use a single string and common string
extract code, (Jason)

Reviewed-by: Jason Ekstrand <jason at jlekstrand.net>
Reviewed-by: Dave Airlie <airlied at redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8254>

---

 src/compiler/shader_info.h      |   1 +
 src/compiler/spirv/vtn_opencl.c | 115 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 110 insertions(+), 6 deletions(-)

diff --git a/src/compiler/shader_info.h b/src/compiler/shader_info.h
index 5ff554d693a..66634697832 100644
--- a/src/compiler/shader_info.h
+++ b/src/compiler/shader_info.h
@@ -68,6 +68,7 @@ struct spirv_supported_capabilities {
    bool multiview;
    bool physical_storage_buffer_address;
    bool post_depth_coverage;
+   bool printf;
    bool ray_tracing;
    bool ray_query;
    bool ray_traversal_primitive_culling;
diff --git a/src/compiler/spirv/vtn_opencl.c b/src/compiler/spirv/vtn_opencl.c
index 2c93718a079..338b9c23f07 100644
--- a/src/compiler/spirv/vtn_opencl.c
+++ b/src/compiler/spirv/vtn_opencl.c
@@ -27,6 +27,7 @@
 #include "math.h"
 #include "nir/nir_builtin_builder.h"
 
+#include "util/u_printf.h"
 #include "vtn_private.h"
 #include "OpenCL.std.h"
 
@@ -723,13 +724,115 @@ vtn_handle_opencl_vstore_half_r(struct vtn_builder *b, enum OpenCLstd_Entrypoint
                         vtn_rounding_mode_to_nir(b, w[8]));
 }
 
-static nir_ssa_def *
+static unsigned
+vtn_add_printf_string(struct vtn_builder *b, uint32_t id, nir_printf_info *info)
+{
+   nir_deref_instr *deref = vtn_nir_deref(b, id);
+
+   while (deref && deref->deref_type != nir_deref_type_var)
+      deref = nir_deref_instr_parent(deref);
+
+   vtn_fail_if(deref == NULL || !nir_deref_mode_is(deref, nir_var_mem_constant),
+               "Printf string argument must be a pointer to a constant variable");
+   vtn_fail_if(deref->var->constant_initializer == NULL,
+               "Printf string argument must have an initializer");
+   vtn_fail_if(!glsl_type_is_array(deref->var->type),
+               "Printf string must be an char array");
+   const struct glsl_type *char_type = glsl_get_array_element(deref->var->type);
+   vtn_fail_if(char_type != glsl_uint8_t_type() &&
+               char_type != glsl_int8_t_type(),
+               "Printf string must be an char array");
+
+   nir_constant *c = deref->var->constant_initializer;
+   assert(c->num_elements == glsl_get_length(deref->var->type));
+
+   unsigned idx = info->string_size;
+   info->strings = reralloc_size(b->shader, info->strings,
+                                 idx + c->num_elements);
+   info->string_size += c->num_elements;
+
+   char *str = &info->strings[idx];
+   bool found_null = false;
+   for (unsigned i = 0; i < c->num_elements; i++) {
+      memcpy((char *)str + i, c->elements[i]->values, 1);
+      if (str[i] == '\0')
+         found_null = true;
+   }
+   vtn_fail_if(!found_null, "Printf string must be null terminated");
+   return idx;
+}
+
+/* printf is special because there are no limits on args */
+static void
 handle_printf(struct vtn_builder *b, uint32_t opcode,
-              unsigned num_srcs, nir_ssa_def **srcs, struct vtn_type **src_types,
-              const struct vtn_type *dest_type)
+              const uint32_t *w_src, unsigned num_srcs, const uint32_t *w_dest)
 {
-   /* hahah, yeah, right.. */
-   return nir_imm_int(&b->nb, -1);
+   if (!b->options->caps.printf) {
+      vtn_push_nir_ssa(b, w_dest[1], nir_imm_int(&b->nb, -1));
+      return;
+   }
+
+   /* Step 1. extract the format string */
+
+   /*
+    * info_idx is 1-based to match clover/llvm
+    * the backend indexes the info table at info_idx - 1.
+    */
+   b->shader->printf_info_count++;
+   unsigned info_idx = b->shader->printf_info_count;
+
+   b->shader->printf_info = reralloc(b->shader, b->shader->printf_info,
+                                     nir_printf_info, info_idx);
+   nir_printf_info *info = &b->shader->printf_info[info_idx - 1];
+
+   info->strings = NULL;
+   info->string_size = 0;
+
+   vtn_add_printf_string(b, w_src[0], info);
+
+   info->num_args = num_srcs - 1;
+   info->arg_sizes = ralloc_array(b->shader, unsigned, info->num_args);
+
+   /* Step 2, build an ad-hoc struct type out of the args */
+   unsigned field_offset = 0;
+   struct glsl_struct_field *fields =
+      rzalloc_array(b, struct glsl_struct_field, num_srcs - 1);
+   for (unsigned i = 1; i < num_srcs; ++i) {
+      struct vtn_value *val = vtn_untyped_value(b, w_src[i]);
+      struct vtn_type *src_type = val->type;
+      fields[i - 1].type = src_type->type;
+      fields[i - 1].name = ralloc_asprintf(b->shader, "arg_%u", i);
+      field_offset = align(field_offset, 4);
+      fields[i - 1].offset = field_offset;
+      info->arg_sizes[i - 1] = glsl_get_cl_size(src_type->type);
+      field_offset += glsl_get_cl_size(src_type->type);
+   }
+   const struct glsl_type *struct_type =
+      glsl_struct_type(fields, num_srcs - 1, "printf", true);
+
+   /* Step 3, create a variable of that type and populate its fields */
+   nir_variable *var = nir_local_variable_create(b->func->impl, struct_type, NULL);
+   nir_deref_instr *deref_var = nir_build_deref_var(&b->nb, var);
+   size_t fmt_pos = 0;
+   for (unsigned i = 1; i < num_srcs; ++i) {
+      nir_deref_instr *field_deref =
+         nir_build_deref_struct(&b->nb, deref_var, i - 1);
+      nir_ssa_def *field_src = vtn_ssa_value(b, w_src[i])->def;
+      /* extract strings */
+      fmt_pos = util_printf_next_spec_pos(info->strings, fmt_pos);
+      if (fmt_pos != -1 && info->strings[fmt_pos] == 's') {
+         unsigned idx = vtn_add_printf_string(b, w_src[i], info);
+         nir_store_deref(&b->nb, field_deref,
+                         nir_imm_intN_t(&b->nb, idx, field_src->bit_size),
+                         ~0 /* write_mask */);
+      } else
+         nir_store_deref(&b->nb, field_deref, field_src, ~0);
+   }
+
+   /* Lastly, the actual intrinsic */
+   nir_ssa_def *fmt_idx = nir_imm_int(&b->nb, info_idx);
+   nir_ssa_def *ret = nir_printf(&b->nb, fmt_idx, &deref_var->dest.ssa);
+   vtn_push_nir_ssa(b, w_dest[1], ret);
 }
 
 static nir_ssa_def *
@@ -977,7 +1080,7 @@ vtn_handle_opencl_instruction(struct vtn_builder *b, SpvOp ext_opcode,
       handle_instr(b, ext_opcode, w + 5, count - 5, w + 1, handle_round);
       return true;
    case OpenCLstd_Printf:
-      handle_instr(b, ext_opcode, w + 5, count - 5, w + 1, handle_printf);
+      handle_printf(b, ext_opcode, w + 5, count - 5, w + 1);
       return true;
    case OpenCLstd_Prefetch:
       /* TODO maybe add a nir instruction for this? */



More information about the mesa-commit mailing list