[Mesa-dev] [PATCH 4/9] spirv: Rework logging

Jason Ekstrand jason at jlekstrand.net
Thu Aug 17 17:22:18 UTC 2017


This commit reworks the way that logging works in SPIR-V to provide
richer and more detailed logging infrastructure.  This commit contains
several improvements over the old mechanism:

 1) Log messages are now more detailed.  They contain the SPIR-V byte
    offset as well as source language information from OpSource and
    OpLine.

 2) There is now a logging callback mechanism so that errors can get
    propagated to the client through debug callbak extensions.
---
 src/amd/vulkan/radv_pipeline.c    |   2 +-
 src/compiler/spirv/nir_spirv.h    |  17 ++++++-
 src/compiler/spirv/spirv2nir.c    |   3 +-
 src/compiler/spirv/spirv_to_nir.c | 100 ++++++++++++++++++++++++++++++++------
 src/compiler/spirv/vtn_private.h  |  22 +++++++--
 src/intel/vulkan/anv_pipeline.c   |   2 +-
 6 files changed, 124 insertions(+), 22 deletions(-)

diff --git a/src/amd/vulkan/radv_pipeline.c b/src/amd/vulkan/radv_pipeline.c
index bd5eeb7..2bf0e99 100644
--- a/src/amd/vulkan/radv_pipeline.c
+++ b/src/amd/vulkan/radv_pipeline.c
@@ -234,7 +234,7 @@ radv_shader_compile_to_nir(struct radv_device *device,
 		};
 		entry_point = spirv_to_nir(spirv, module->size / 4,
 					   spec_entries, num_spec_entries,
-					   stage, entrypoint_name, &supported_ext, &nir_options);
+					   stage, entrypoint_name, &supported_ext, &nir_options, NULL);
 		nir = entry_point->shader;
 		assert(nir->stage == stage);
 		nir_validate_shader(nir);
diff --git a/src/compiler/spirv/nir_spirv.h b/src/compiler/spirv/nir_spirv.h
index 83577fb..9c92eb1 100644
--- a/src/compiler/spirv/nir_spirv.h
+++ b/src/compiler/spirv/nir_spirv.h
@@ -54,12 +54,27 @@ struct nir_spirv_supported_extensions {
    bool variable_pointers;
 };
 
+enum nir_spirv_debug_level {
+   NIR_SPIRV_DEBUG_LEVEL_INFO,
+   NIR_SPIRV_DEBUG_LEVEL_WARNING,
+   NIR_SPIRV_DEBUG_LEVEL_ERROR,
+};
+
+struct nir_spirv_debug_callback {
+   void (*func)(void *private_data,
+                enum nir_spirv_debug_level level,
+                size_t spirv_offset,
+                const char *message);
+   void *private_data;
+};
+
 nir_function *spirv_to_nir(const uint32_t *words, size_t word_count,
                            struct nir_spirv_specialization *specializations,
                            unsigned num_specializations,
                            gl_shader_stage stage, const char *entry_point_name,
                            const struct nir_spirv_supported_extensions *ext,
-                           const nir_shader_compiler_options *options);
+                           const nir_shader_compiler_options *options,
+                           struct nir_spirv_debug_callback *debug_cb);
 
 #ifdef __cplusplus
 }
diff --git a/src/compiler/spirv/spirv2nir.c b/src/compiler/spirv/spirv2nir.c
index 0ae14fb..2b1c0e8 100644
--- a/src/compiler/spirv/spirv2nir.c
+++ b/src/compiler/spirv/spirv2nir.c
@@ -73,7 +73,8 @@ int main(int argc, char **argv)
    }
 
    nir_function *func = spirv_to_nir(map, word_count, NULL, 0,
-                                     MESA_SHADER_FRAGMENT, "main", NULL, NULL);
+                                     MESA_SHADER_FRAGMENT, "main",
+                                     NULL, NULL, NULL);
    nir_print_shader(func->shader, stderr);
 
    return 0;
diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index a3e143a..6174ec7 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -31,29 +31,87 @@
 #include "nir/nir_constant_expressions.h"
 #include "spirv_info.h"
 
-struct spec_constant_value {
-   bool is_double;
-   union {
-      uint32_t data32;
-      uint64_t data64;
-   };
-};
+void
+vtn_log(struct vtn_builder *b, enum nir_spirv_debug_level level,
+        size_t spirv_offset, const char *message)
+{
+   if (b->debug && b->debug->func)
+      b->debug->func(b->debug->private_data, level, spirv_offset, message);
+
+#ifndef NDEBUG
+   if (level >= NIR_SPIRV_DEBUG_LEVEL_WARNING)
+      fprintf(stderr, "%s\n", message);
+#endif
+}
 
 void
-_vtn_warn(const char *file, int line, const char *msg, ...)
+vtn_logf(struct vtn_builder *b, enum nir_spirv_debug_level level,
+         size_t spirv_offset, const char *fmt, ...)
 {
-   char *formatted;
    va_list args;
+   char *msg;
 
-   va_start(args, msg);
-   formatted = ralloc_vasprintf(NULL, msg, args);
+   va_start(args, fmt);
+   msg = ralloc_vasprintf(NULL, fmt, args);
    va_end(args);
 
-   fprintf(stderr, "%s:%d WARNING: %s\n", file, line, formatted);
+   vtn_log(b, level, spirv_offset, msg);
+
+   ralloc_free(msg);
+}
+
+static void
+vtn_log_err(struct vtn_builder *b,
+            enum nir_spirv_debug_level level, const char *prefix,
+            const char *file, unsigned line,
+            const char *fmt, va_list args)
+{
+   char *msg;
+
+   msg = ralloc_strdup(NULL, prefix);
+
+#ifndef NDEBUG
+   ralloc_asprintf_append(&msg, "    In file %s:%u\n", file, line);
+#endif
+
+   ralloc_asprintf_append(&msg, "    ");
+
+   ralloc_vasprintf_append(&msg, fmt, args);
+
+   ralloc_asprintf_append(&msg, "\n    %zu bytes into the SPIR-V binary",
+                          b->spirv_offset);
+
+   if (b->file) {
+      ralloc_asprintf_append(&msg,
+                             "\n    in SPIR-V source file %s, line %d, col %d",
+                             b->file, b->line, b->col);
+   }
+
+   vtn_log(b, level, b->spirv_offset, msg);
 
-   ralloc_free(formatted);
+   ralloc_free(msg);
 }
 
+void
+_vtn_warn(struct vtn_builder *b, const char *file, unsigned line,
+          const char *fmt, ...)
+{
+   va_list args;
+
+   va_start(args, fmt);
+   vtn_log_err(b, NIR_SPIRV_DEBUG_LEVEL_WARNING, "SPIR-V WARNING:\n",
+               file, line, fmt, args);
+   va_end(args);
+}
+
+struct spec_constant_value {
+   bool is_double;
+   union {
+      uint32_t data32;
+      uint64_t data64;
+   };
+};
+
 static struct vtn_ssa_value *
 vtn_undef_ssa_value(struct vtn_builder *b, const struct glsl_type *type)
 {
@@ -224,6 +282,8 @@ vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start,
       unsigned count = w[0] >> SpvWordCountShift;
       assert(count >= 1 && w + count <= end);
 
+      b->spirv_offset = (uint8_t *)w - (uint8_t *)b->spirv;
+
       switch (opcode) {
       case SpvOpNop:
          break; /* Do nothing */
@@ -248,6 +308,12 @@ vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start,
 
       w += count;
    }
+
+   b->spirv_offset = 0;
+   b->file = NULL;
+   b->line = -1;
+   b->col = -1;
+
    assert(w == end);
    return w;
 }
@@ -3319,10 +3385,16 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
              struct nir_spirv_specialization *spec, unsigned num_spec,
              gl_shader_stage stage, const char *entry_point_name,
              const struct nir_spirv_supported_extensions *ext,
-             const nir_shader_compiler_options *options)
+             const nir_shader_compiler_options *options,
+             struct nir_spirv_debug_callback *debug_cb)
 {
    /* Initialize the stn_builder object */
    struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);
+   b->debug = debug_cb;
+   b->spirv = words;
+   b->file = NULL;
+   b->line = -1;
+   b->col = -1;
    exec_list_make_empty(&b->functions);
    b->entry_point_stage = stage;
    b->entry_point_name = entry_point_name;
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 8458462..3eb601d 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -37,6 +37,18 @@
 struct vtn_builder;
 struct vtn_decoration;
 
+void vtn_log(struct vtn_builder *b, enum nir_spirv_debug_level level,
+             size_t spirv_offset, const char *message);
+
+void vtn_logf(struct vtn_builder *b, enum nir_spirv_debug_level level,
+              size_t spirv_offset, const char *fmt, ...) PRINTFLIKE(4, 5);
+
+#define vtn_info(...) vtn_logf(b, NIR_SPIRV_DEBUG_LEVEL_INFO, 0, __VA_ARGS__)
+
+void _vtn_warn(struct vtn_builder *b, const char *file, unsigned line,
+               const char *fmt, ...) PRINTFLIKE(4, 5);
+#define vtn_warn(...) _vtn_warn(b, __FILE__, __LINE__, __VA_ARGS__)
+
 enum vtn_value_type {
    vtn_value_type_invalid = 0,
    vtn_value_type_undef,
@@ -462,17 +474,22 @@ struct vtn_decoration {
 struct vtn_builder {
    nir_builder nb;
 
+   const uint32_t *spirv;
+
    nir_shader *shader;
    nir_function_impl *impl;
    const struct nir_spirv_supported_extensions *ext;
    struct vtn_block *block;
 
-   /* Current file, line, and column.  Useful for debugging.  Set
+   /* Current offset, file, line, and column.  Useful for debugging.  Set
     * automatically by vtn_foreach_instruction.
     */
+   size_t spirv_offset;
    char *file;
    int line, col;
 
+   struct nir_spirv_debug_callback *debug;
+
    /*
     * In SPIR-V, constants are global, whereas in NIR, the load_const
     * instruction we use is per-function. So while we parse each function, we
@@ -557,9 +574,6 @@ vtn_value(struct vtn_builder *b, uint32_t value_id,
    return val;
 }
 
-void _vtn_warn(const char *file, int line, const char *msg, ...);
-#define vtn_warn(...) _vtn_warn(__FILE__, __LINE__, __VA_ARGS__)
-
 struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id);
 
 struct vtn_ssa_value *vtn_create_ssa_value(struct vtn_builder *b,
diff --git a/src/intel/vulkan/anv_pipeline.c b/src/intel/vulkan/anv_pipeline.c
index 6ae682f..7c19e6c 100644
--- a/src/intel/vulkan/anv_pipeline.c
+++ b/src/intel/vulkan/anv_pipeline.c
@@ -135,7 +135,7 @@ anv_shader_compile_to_nir(struct anv_pipeline *pipeline,
    nir_function *entry_point =
       spirv_to_nir(spirv, module->size / 4,
                    spec_entries, num_spec_entries,
-                   stage, entrypoint_name, &supported_ext, nir_options);
+                   stage, entrypoint_name, &supported_ext, nir_options, NULL);
    nir_shader *nir = entry_point->shader;
    assert(nir->stage == stage);
    nir_validate_shader(nir);
-- 
2.5.0.400.gff86faf



More information about the mesa-dev mailing list