gallivm: Compile flag to debug TGSI execution through printfs.
authorJosé Fonseca <jfonseca@vmware.com>
Thu, 14 Nov 2013 14:02:24 +0000 (14:02 +0000)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 14 Nov 2013 14:04:28 +0000 (14:04 +0000)
It is similar to tgsi_exec.c's DEBUG_EXECUTION compile flag.

I had prototyped this for a while while debugging an issue, but finally
cleaned this up and added a few more bells and whistles.

v2: Use '$' as marker; better output. Thanks to Brian, Zack and Roland
reviews.

Here is a sample output.

    CONST[0].x =  0.00625000009 0.00625000009 0.00625000009 0.00625000009
    CONST[0].y =  -0.00714285718 -0.00714285718 -0.00714285718 -0.00714285718
    CONST[0].z =  -1 -1 -1 -1
    CONST[0].w =  1 1 1 1
    IN[0].x =  143.5 175.5 175.5 143.5
    IN[0].y =  123.5 123.5 155.5 155.5
    IN[0].z =  0 0 0 0
    IN[0].w =  1 1 1 1
$   1: RCP TEMP[0].w, IN[0].wwww
    TEMP[0].w =  1 1 1 1
$   2: MAD TEMP[0].xy, IN[0], CONST[0], CONST[0].zwzw
    TEMP[0].x =  -0.103124976 0.0968750715 0.0968750715 -0.103124976
    TEMP[0].y =  0.117857158 0.117857158 -0.110714316 -0.110714316
$   3: MUL OUT[0].xy, TEMP[0], TEMP[0].wwww
    OUT[0].x =  -0.103124976 0.0968750715 0.0968750715 -0.103124976
    OUT[0].y =  0.117857158 0.117857158 -0.110714316 -0.110714316
$   4: MUL OUT[0].z, IN[0].zzzz, TEMP[0].wwww
    OUT[0].z =  0 0 0 0
$   5: MOV OUT[0].w, TEMP[0]
    OUT[0].w =  1 1 1 1
$   6: END
    OUT[0].x =  -0.103124976 0.0968750715 0.0968750715 -0.103124976
    OUT[0].y =  0.117857158 0.117857158 -0.110714316 -0.110714316
    OUT[0].z =  0 0 0 0
    OUT[0].w =  1 1 1 1

src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
src/gallium/auxiliary/tgsi/tgsi_dump.c
src/gallium/auxiliary/tgsi/tgsi_dump.h

index 5a9e8d0a1a27e031cc14a94e9bedc14ef9a25bf8..7ffeaaf99e21039b7cf797be03f665dc021658db 100644 (file)
@@ -200,6 +200,10 @@ lp_build_tgsi_inst_llvm(
 
    bld_base->pc++;
 
+   if (bld_base->emit_debug) {
+      bld_base->emit_debug(bld_base, inst, info);
+   }
+
    /* Ignore deprecated instructions */
    switch (inst->Instruction.Opcode) {
 
index 8bcdbc8f7bd26f4dbf237781a0779bf22c0a5fd3..881cd5ba829ddd0e80d2919b5c06ec1cd8c7ffbd 100644 (file)
@@ -352,6 +352,11 @@ struct lp_build_tgsi_context
    LLVMValueRef (*emit_swizzle)(struct lp_build_tgsi_context *,
                          LLVMValueRef, unsigned, unsigned, unsigned, unsigned);
 
+
+   void (*emit_debug)(struct lp_build_tgsi_context *,
+                      const struct tgsi_full_instruction *,
+                      const struct tgsi_opcode_info *);
+
    void (*emit_store)(struct lp_build_tgsi_context *,
                       const struct tgsi_full_instruction *,
                       const struct tgsi_opcode_info *,
index 5fc47ed155babb973953134807a285f754a931bd..3e0fd1cf9914d7a94884335471033b4405639671 100644 (file)
@@ -47,6 +47,7 @@
 #include "tgsi/tgsi_parse.h"
 #include "tgsi/tgsi_util.h"
 #include "tgsi/tgsi_scan.h"
+#include "tgsi/tgsi_strings.h"
 #include "lp_bld_tgsi_action.h"
 #include "lp_bld_type.h"
 #include "lp_bld_const.h"
 
 #define DUMP_GS_EMITS 0
 
+/*
+ * If non-zero, the generated LLVM IR will print intermediate results on every TGSI
+ * instruction.
+ *
+ * TODO:
+ * - take execution masks in consideration
+ * - debug control-flow instructions
+ */
+#define DEBUG_EXECUTION 0
+
+
+/*
+ * Emit code to print a register value.
+ */
+static void
+emit_dump_reg(struct gallivm_state *gallivm,
+              unsigned file,
+              unsigned index,
+              unsigned chan,
+              LLVMValueRef value)
+{
+   char buf[32];
+
+   util_snprintf(buf, sizeof buf, "    %s[%u].%c = ",
+                 tgsi_file_name(file),
+                 index, "xyzw"[chan]);
+
+   lp_build_print_value(gallivm, buf, value);
+}
+
+
 static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld)
 {
    LLVMTypeRef int_type = LLVMInt32TypeInContext(bld->gallivm->context);
@@ -664,6 +696,43 @@ static void lp_exec_mask_endsub(struct lp_exec_mask *mask, int *pc)
 }
 
 
+static LLVMValueRef
+get_file_ptr(struct lp_build_tgsi_soa_context *bld,
+             unsigned file,
+             unsigned index,
+             unsigned chan)
+{
+   LLVMBuilderRef builder = bld->bld_base.base.gallivm->builder;
+   LLVMValueRef (*array_of_vars)[TGSI_NUM_CHANNELS];
+   LLVMValueRef var_of_array;
+
+   switch (file) {
+   case TGSI_FILE_TEMPORARY:
+      array_of_vars = bld->temps;
+      var_of_array = bld->temps_array;
+      break;
+   case TGSI_FILE_OUTPUT:
+      array_of_vars = bld->outputs;
+      var_of_array = bld->outputs_array;
+      break;
+   default:
+      assert(0);
+      return NULL;
+   }
+
+   assert(chan < 4);
+
+   if (bld->indirect_files & (1 << file)) {
+      LLVMValueRef lindex = lp_build_const_int32(bld->bld_base.base.gallivm, index * 4 + chan);
+      return LLVMBuildGEP(builder, var_of_array, &lindex, 1, "");
+   }
+   else {
+      assert(index <= bld->bld_base.info->file_max[file]);
+      return array_of_vars[index][chan];
+   }
+}
+
+
 /**
  * Return pointer to a temporary register channel (src or dest).
  * Note that indirect addressing cannot be handled here.
@@ -675,15 +744,7 @@ lp_get_temp_ptr_soa(struct lp_build_tgsi_soa_context *bld,
              unsigned index,
              unsigned chan)
 {
-   LLVMBuilderRef builder = bld->bld_base.base.gallivm->builder;
-   assert(chan < 4);
-   if (bld->indirect_files & (1 << TGSI_FILE_TEMPORARY)) {
-      LLVMValueRef lindex = lp_build_const_int32(bld->bld_base.base.gallivm, index * 4 + chan);
-      return LLVMBuildGEP(builder, bld->temps_array, &lindex, 1, "");
-   }
-   else {
-      return bld->temps[index][chan];
-   }
+   return get_file_ptr(bld, TGSI_FILE_TEMPORARY, index, chan);
 }
 
 /**
@@ -697,16 +758,7 @@ lp_get_output_ptr(struct lp_build_tgsi_soa_context *bld,
                unsigned index,
                unsigned chan)
 {
-   LLVMBuilderRef builder = bld->bld_base.base.gallivm->builder;
-   assert(chan < 4);
-   if (bld->indirect_files & (1 << TGSI_FILE_OUTPUT)) {
-      LLVMValueRef lindex = lp_build_const_int32(bld->bld_base.base.gallivm,
-                                                 index * 4 + chan);
-      return LLVMBuildGEP(builder, bld->outputs_array, &lindex, 1, "");
-   }
-   else {
-      return bld->outputs[index][chan];
-   }
+   return get_file_ptr(bld, TGSI_FILE_OUTPUT, index, chan);
 }
 
 /*
@@ -1412,6 +1464,10 @@ emit_store_chan(
                              bld_base->info->file_max[reg->Register.File]);
    }
 
+   if (DEBUG_EXECUTION) {
+      emit_dump_reg(gallivm, reg->Register.File, reg->Register.Index, chan_index, value);
+   }
+
    switch( reg->Register.File ) {
    case TGSI_FILE_OUTPUT:
       /* Outputs are always stored as floats */
@@ -1491,6 +1547,39 @@ emit_store_chan(
    (void)dtype;
 }
 
+/*
+ * Called at the beginning of the translation of each TGSI instruction, to
+ * emit some debug code.
+ */
+static void
+emit_debug(
+   struct lp_build_tgsi_context * bld_base,
+   const struct tgsi_full_instruction * inst,
+   const struct tgsi_opcode_info * info)
+
+{
+   struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
+
+   if (DEBUG_EXECUTION) {
+      /*
+       * Dump the TGSI instruction.
+       */
+
+      struct gallivm_state *gallivm = bld_base->base.gallivm;
+      char buf[512];
+      buf[0] = '$';
+      buf[1] = ' ';
+      tgsi_dump_instruction_str(inst, bld_base->pc, &buf[2], sizeof buf - 2);
+      lp_build_printf(gallivm, buf);
+
+      /* Dump the execution mask.
+       */
+      if (bld->exec_mask.has_mask) {
+         lp_build_print_value(gallivm, "    mask = ", bld->exec_mask.exec_mask);
+      }
+   }
+}
+
 static void
 emit_store(
    struct lp_build_tgsi_context * bld_base,
@@ -2250,42 +2339,78 @@ emit_kill(struct lp_build_tgsi_soa_context *bld,
  * to stdout.
  */
 static void
-emit_dump_temps(struct lp_build_tgsi_soa_context *bld)
+emit_dump_file(struct lp_build_tgsi_soa_context *bld,
+               unsigned file)
 {
+   const struct tgsi_shader_info *info = bld->bld_base.info;
    struct gallivm_state *gallivm = bld->bld_base.base.gallivm;
    LLVMBuilderRef builder = gallivm->builder;
-   LLVMValueRef temp_ptr;
-   LLVMValueRef i0 = lp_build_const_int32(gallivm, 0);
-   LLVMValueRef i1 = lp_build_const_int32(gallivm, 1);
-   LLVMValueRef i2 = lp_build_const_int32(gallivm, 2);
-   LLVMValueRef i3 = lp_build_const_int32(gallivm, 3);
+   LLVMValueRef reg_ptr;
    int index;
-   int n = bld->bld_base.info->file_max[TGSI_FILE_TEMPORARY];
+   int max_index = info->file_max[file];
 
-   for (index = 0; index < n; index++) {
-      LLVMValueRef idx = lp_build_const_int32(gallivm, index);
-      LLVMValueRef v[4][4], res;
+   /*
+    * Some register files, particularly constants, can be very large,
+    * and dumping everything could make this unusably slow.
+    */
+   max_index = MIN2(max_index, 32);
+
+   for (index = 0; index <= max_index; index++) {
+      LLVMValueRef res;
+      unsigned mask;
       int chan;
 
-      lp_build_printf(gallivm, "TEMP[%d]:\n", idx);
+      if (index < 8 * sizeof(unsigned) &&
+          (info->file_mask[file] & (1 << index)) == 0)  {
+         /* This was not declared.*/
+         continue;
+      }
 
-      for (chan = 0; chan < 4; chan++) {
-         temp_ptr = lp_get_temp_ptr_soa(bld, index, chan);
-         res = LLVMBuildLoad(builder, temp_ptr, "");
-         v[chan][0] = LLVMBuildExtractElement(builder, res, i0, "");
-         v[chan][1] = LLVMBuildExtractElement(builder, res, i1, "");
-         v[chan][2] = LLVMBuildExtractElement(builder, res, i2, "");
-         v[chan][3] = LLVMBuildExtractElement(builder, res, i3, "");
+      if (file == TGSI_FILE_INPUT) {
+         mask = info->input_usage_mask[index];
+      } else {
+         mask = TGSI_WRITEMASK_XYZW;
       }
 
-      lp_build_printf(gallivm, "  X: %f %f %f %f\n",
-                      v[0][0], v[0][1], v[0][2], v[0][3]);
-      lp_build_printf(gallivm, "  Y: %f %f %f %f\n",
-                      v[1][0], v[1][1], v[1][2], v[1][3]);
-      lp_build_printf(gallivm, "  Z: %f %f %f %f\n",
-                      v[2][0], v[2][1], v[2][2], v[2][3]);
-      lp_build_printf(gallivm, "  W: %f %f %f %f\n",
-                      v[3][0], v[3][1], v[3][2], v[3][3]);
+      for (chan = 0; chan < 4; chan++) {
+         if ((mask & (1 << chan)) == 0) {
+            /* This channel is not used.*/
+            continue;
+         }
+
+         if (file == TGSI_FILE_CONSTANT) {
+            struct tgsi_full_src_register reg;
+            memset(&reg, 0, sizeof reg);
+            reg.Register.File = file;
+            reg.Register.Index = index;
+            reg.Register.SwizzleX = 0;
+            reg.Register.SwizzleY = 1;
+            reg.Register.SwizzleZ = 2;
+            reg.Register.SwizzleW = 3;
+
+            res = bld->bld_base.emit_fetch_funcs[file](&bld->bld_base, &reg, TGSI_TYPE_FLOAT, chan);
+            if (!res) {
+               continue;
+            }
+         } else if (file == TGSI_FILE_INPUT) {
+            res = bld->inputs[index][chan];
+            if (!res) {
+               continue;
+            }
+         } else if (file == TGSI_FILE_TEMPORARY) {
+            reg_ptr = lp_get_temp_ptr_soa(bld, index, chan);
+            assert(reg_ptr);
+            res = LLVMBuildLoad(builder, reg_ptr, "");
+         } else if (file == TGSI_FILE_OUTPUT) {
+            reg_ptr = lp_get_output_ptr(bld, index, chan);
+            assert(reg_ptr);
+            res = LLVMBuildLoad(builder, reg_ptr, "");
+         } else {
+            assert(0);
+         }
+
+         emit_dump_reg(gallivm, file, index, chan, res);
+      }
    }
 }
 
@@ -3171,6 +3296,12 @@ static void emit_prologue(struct lp_build_tgsi_context * bld_base)
       LLVMBuildStore(gallivm->builder, uint_bld->zero,
                      bld->total_emitted_vertices_vec_ptr);
    }
+
+   if (DEBUG_EXECUTION) {
+      lp_build_printf(gallivm, "\n");
+      emit_dump_file(bld, TGSI_FILE_CONSTANT);
+      emit_dump_file(bld, TGSI_FILE_INPUT);
+   }
 }
 
 static void emit_epilogue(struct lp_build_tgsi_context * bld_base)
@@ -3178,9 +3309,13 @@ static void emit_epilogue(struct lp_build_tgsi_context * bld_base)
    struct lp_build_tgsi_soa_context * bld = lp_soa_context(bld_base);
    LLVMBuilderRef builder = bld_base->base.gallivm->builder;
 
-   if (0) {
+   if (DEBUG_EXECUTION) {
       /* for debugging */
-      emit_dump_temps(bld);
+      if (0) {
+         emit_dump_file(bld, TGSI_FILE_TEMPORARY);
+      }
+      emit_dump_file(bld, TGSI_FILE_OUTPUT);
+      lp_build_printf(bld_base->base.gallivm, "\n");
    }
 
    /* If we have indirect addressing in outputs we need to copy our alloca array
@@ -3245,6 +3380,7 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm,
    bld.indirect_files = info->indirect_files;
 
    bld.bld_base.soa = TRUE;
+   bld.bld_base.emit_debug = emit_debug;
    bld.bld_base.emit_fetch_funcs[TGSI_FILE_CONSTANT] = emit_fetch_constant;
    bld.bld_base.emit_fetch_funcs[TGSI_FILE_IMMEDIATE] = emit_fetch_immediate;
    bld.bld_base.emit_fetch_funcs[TGSI_FILE_INPUT] = emit_fetch_input;
index 7f6a3d8ad8f300abe20e54c3913e2a43f238f0fb..77bca6230822e494ee9d03dc17dbaf2d7f6481ab 100644 (file)
@@ -721,3 +721,26 @@ tgsi_dump_str(
 
    tgsi_iterate_shader( tokens, &ctx.base.iter );
 }
+
+void
+tgsi_dump_instruction_str(
+   const struct tgsi_full_instruction *inst,
+   uint instno,
+   char *str,
+   size_t size)
+{
+   struct str_dump_ctx ctx;
+
+   ctx.base.instno = instno;
+   ctx.base.immno = instno;
+   ctx.base.indent = 0;
+   ctx.base.dump_printf = &str_dump_ctx_printf;
+   ctx.base.indentation = 0;
+
+   ctx.str = str;
+   ctx.str[0] = 0;
+   ctx.ptr = str;
+   ctx.left = (int)size;
+
+   iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst );
+}
index adaef9d89feaa3456895edb01c54371dbea1f8fb..9820bb1cacf7cf4f15a1b09a754172d0318a6d4f 100644 (file)
@@ -57,6 +57,13 @@ void
 tgsi_dump_immediate(
    const struct tgsi_full_immediate *imm );
 
+void
+tgsi_dump_instruction_str(
+   const struct tgsi_full_instruction *inst,
+   uint instno,
+   char *str,
+   size_t size);
+
 void
 tgsi_dump_instruction(
    const struct tgsi_full_instruction *inst,