summaryrefslogtreecommitdiff
path: root/src/gallium/auxiliary/gallivm
diff options
context:
space:
mode:
authorJosé Fonseca <jfonseca@vmware.com>2013-11-14 14:02:24 +0000
committerJosé Fonseca <jfonseca@vmware.com>2013-11-14 14:04:28 +0000
commita29e40a42382630c2d9d95d3a1e03a7b3db87add (patch)
treeb6101e3c368e80f6f1b1f02d2c05d33b2118c533 /src/gallium/auxiliary/gallivm
parent673d5391a2f4084525de6c5cebf322ddb0e2acf1 (diff)
gallivm: Compile flag to debug TGSI execution through printfs.
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
Diffstat (limited to 'src/gallium/auxiliary/gallivm')
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi.c4
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi.h5
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c230
3 files changed, 192 insertions, 47 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
index 5a9e8d0a1a2..7ffeaaf99e2 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.c
@@ -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) {
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
index 8bcdbc8f7bd..881cd5ba829 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
@@ -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 *,
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
index 5fc47ed155b..3e0fd1cf991 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
@@ -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"
@@ -67,6 +68,37 @@
#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;