summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2013-09-30 17:07:23 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2013-09-30 17:07:23 +0200
commit296195c61c09e9a2fd37183a779d17b0216c4fe1 (patch)
treef2de0eb05021b8c7b309407ff11d5e3cb4758ba4
parent6d9b47215644b70af3c8b158cfc08a7b8b86ee70 (diff)
driver: generate intermediate temporary if multiple uniforms used in instruction
It is not allowed to use multiple uniforms in one instruction by the Vivante ISA. If this happens anyway, generate an intermediate MOV instruction and a temporary.
-rw-r--r--native/driver/etna_asm.c8
-rw-r--r--native/driver/etna_asm.h3
-rw-r--r--native/driver/etna_compiler.c77
-rw-r--r--native/driver/etna_debug.h5
4 files changed, 77 insertions, 16 deletions
diff --git a/native/driver/etna_asm.c b/native/driver/etna_asm.c
index 65816fc..c4a4802 100644
--- a/native/driver/etna_asm.c
+++ b/native/driver/etna_asm.c
@@ -26,7 +26,7 @@
#include <etnaviv/isa.xml.h>
/* Return whether the rgroup is one of the uniforms */
-static inline int rgroup_is_uniform(unsigned rgroup)
+int etna_rgroup_is_uniform(unsigned rgroup)
{
return rgroup == INST_RGROUP_UNIFORM_0 ||
rgroup == INST_RGROUP_UNIFORM_1;
@@ -41,9 +41,9 @@ static bool check_uniforms(const struct etna_inst *inst)
unsigned uni_rgroup = -1;
unsigned uni_reg = -1;
bool conflict = false;
- for(int src=0; src<3; ++src)
+ for(int src=0; src<ETNA_NUM_SRC; ++src)
{
- if(rgroup_is_uniform(inst->src[src].rgroup))
+ if(etna_rgroup_is_uniform(inst->src[src].rgroup))
{
if(uni_reg == -1) /* first uniform used */
{
@@ -68,7 +68,7 @@ int etna_assemble(uint32_t *out, const struct etna_inst *inst)
if(!check_uniforms(inst))
{
- DBG("warning: generating instruction that accesses two different uniforms");
+ BUG("error: generating instruction that accesses two different uniforms");
}
out[0] = VIV_ISA_WORD_0_OPCODE(inst->opcode) |
diff --git a/native/driver/etna_asm.h b/native/driver/etna_asm.h
index 6d7def6..ad2e075 100644
--- a/native/driver/etna_asm.h
+++ b/native/driver/etna_asm.h
@@ -91,5 +91,8 @@ int etna_assemble(uint32_t *out, const struct etna_inst *inst);
*/
int etna_assemble_set_imm(uint32_t *out, uint32_t imm);
+/* Return whether the rgroup is one of the uniforms */
+int etna_rgroup_is_uniform(unsigned rgroup);
+
#endif
diff --git a/native/driver/etna_compiler.c b/native/driver/etna_compiler.c
index fba7a89..d0a281c 100644
--- a/native/driver/etna_compiler.c
+++ b/native/driver/etna_compiler.c
@@ -153,6 +153,7 @@ struct etna_compile_data
/* Temporary register for use within translated TGSI instruction,
* only allocated when needed.
*/
+ int inner_temps; /* number of inner temps used; only up to one available at this point */
struct etna_native_reg inner_temp;
/* Fields for handling nested conditionals */
@@ -572,10 +573,70 @@ static void etna_compile_pass_optimize_outputs(struct etna_compile_data *cd, con
tgsi_parse_free(&ctx);
}
+/* Get temporary to be used within one TGSI instruction.
+ * The first time that this function is called the temporary will be allocated.
+ * Each call to this function will return the same temporary.
+ */
+static struct etna_native_reg etna_compile_get_inner_temp(struct etna_compile_data *cd)
+{
+ if(cd->inner_temps)
+ BUG("Multiple inner temporaries (%i) requested in one instruction", cd->inner_temps + 1);
+ if(!cd->inner_temp.valid)
+ cd->inner_temp = alloc_new_native_reg(cd);
+ cd->inner_temps += 1;
+ return cd->inner_temp;
+}
+
/* emit instruction and append to program */
-static void emit_inst(struct etna_compile_data *cd, const struct etna_inst *inst)
+static void emit_inst(struct etna_compile_data *cd, struct etna_inst *inst)
{
assert(cd->inst_ptr <= ETNA_MAX_INSTRUCTIONS);
+
+ /* Check for uniform conflicts (each instruction can only access one uniform),
+ * if detected, use an intermediate temporary */
+ unsigned uni_rgroup = -1;
+ unsigned uni_reg = -1;
+
+ for(int src=0; src<ETNA_NUM_SRC; ++src)
+ {
+ if(etna_rgroup_is_uniform(inst->src[src].rgroup))
+ {
+ if(uni_reg == -1) /* first unique uniform used */
+ {
+ uni_rgroup = inst->src[src].rgroup;
+ uni_reg = inst->src[src].reg;
+ } else { /* second or later; check that it is a re-use */
+ if(uni_rgroup != inst->src[src].rgroup ||
+ uni_reg != inst->src[src].reg)
+ {
+ DBG_F(ETNA_DBG_COMPILER_MSGS,
+ "perf warning: instruction that accesses different uniforms, need to generate extra MOV");
+ struct etna_native_reg inner_temp = etna_compile_get_inner_temp(cd);
+
+ /* Generate move instruction to temporary */
+ etna_assemble(&cd->code[cd->inst_ptr*4], &(struct etna_inst) {
+ .opcode = INST_OPCODE_MOV,
+ .dst.use = 1,
+ .dst.comps = INST_COMPS_X | INST_COMPS_Y | INST_COMPS_Z | INST_COMPS_W,
+ .dst.reg = inner_temp.id,
+ .src[2] = inst->src[src]
+ });
+ cd->inst_ptr ++;
+
+ /* Modify instruction to use temp register instead of uniform */
+ inst->src[src].use = 1;
+ inst->src[src].rgroup = INST_RGROUP_TEMP;
+ inst->src[src].reg = inner_temp.id;
+ inst->src[src].swiz = INST_SWIZ_IDENTITY; /* swizzling happens on MOV */
+ inst->src[src].neg = 0; /* negation happens on MOV */
+ inst->src[src].abs = 0; /* abs happens on MOV */
+ inst->src[src].amode = 0; /* amode effects happen on MOV */
+ }
+ }
+ }
+ }
+
+ /* Finally assemble the actual instruction */
etna_assemble(&cd->code[cd->inst_ptr*4], inst);
cd->inst_ptr ++;
}
@@ -672,17 +733,6 @@ static void label_mark_use(struct etna_compile_data *cd, struct etna_compile_lab
cd->lbl_usage[cd->inst_ptr] = label;
}
-/* Get temporary to be used within one TGSI instruction.
- * The first time that this function is called the temporary will be allocated.
- * Each call to this function will return the same temporary.
- */
-static struct etna_native_reg etna_compile_get_inner_temp(struct etna_compile_data *cd)
-{
- if(!cd->inner_temp.valid)
- cd->inner_temp = alloc_new_native_reg(cd);
- return cd->inner_temp;
-}
-
/* Pass -- compile instructions */
static void etna_compile_pass_generate_code(struct etna_compile_data *cd, const struct tgsi_token *tokens)
{
@@ -696,6 +746,9 @@ static void etna_compile_pass_generate_code(struct etna_compile_data *cd, const
{
tgsi_parse_token(&ctx);
const struct tgsi_full_instruction *inst = 0;
+ /* No inner temps used yet for this instruction, clear counter */
+ cd->inner_temps = 0;
+
switch(ctx.FullToken.Token.Type)
{
case TGSI_TOKEN_TYPE_INSTRUCTION:
diff --git a/native/driver/etna_debug.h b/native/driver/etna_debug.h
index 1274ffc..df6f792 100644
--- a/native/driver/etna_debug.h
+++ b/native/driver/etna_debug.h
@@ -27,6 +27,7 @@
#include <stdint.h>
#include <stdlib.h>
+#include <stdio.h>
#include "util/u_debug.h"
/* Logging */
@@ -63,6 +64,10 @@ extern uint32_t etna_mesa_debug; /* set in etna_screen.c from ETNA_DEBUG */
debug_printf("%s:%d: "fmt "\n", \
__FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
+/* A serious bug, show this even in non-debug mode */
+#define BUG(fmt, ...) \
+ do { printf("%s:%d: "fmt "\n", \
+ __FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
#endif