Mesa (master): nvc0: prevent overlap between load address and destination regs

Christoph Bumiller chrisbmr at kemper.freedesktop.org
Fri May 13 09:48:39 PDT 2011


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

Author: Christoph Bumiller <e0425955 at student.tuwien.ac.at>
Date:   Fri May 13 18:43:06 2011 +0200

nvc0: prevent overlap between load address and destination regs

For example, an indirect load like "ld b128 $r0q c0[$r0]" seems to
overwrite the address register before finishing the load, but only
if there are a lot of threads running.

Visible as displaced geoemtry in Unigine Heaven.

---

 src/gallium/drivers/nvc0/nvc0_pc_optimize.c |   44 +++++++++++++++++---------
 1 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/src/gallium/drivers/nvc0/nvc0_pc_optimize.c b/src/gallium/drivers/nvc0/nvc0_pc_optimize.c
index 7f5fbaf..82a8397 100644
--- a/src/gallium/drivers/nvc0/nvc0_pc_optimize.c
+++ b/src/gallium/drivers/nvc0/nvc0_pc_optimize.c
@@ -1293,31 +1293,45 @@ nv_pass_cse(struct nv_pass *ctx, struct nv_basic_block *b)
  * neighbouring registers. CSE might have messed this up.
  * Just generate a MOV for each source to avoid conflicts if they're used in
  * multiple NV_OP_BIND at different positions.
+ *
+ * Add a dummy use of the pointer source of >= 8 byte loads after the load
+ * to prevent it from being assigned a register which overlaps the load's
+ * destination, which would produce random corruptions.
  */
 static int
-nv_pass_fix_bind(struct nv_pass *ctx, struct nv_basic_block *b)
+nv_pass_fixups(struct nv_pass *ctx, struct nv_basic_block *b)
 {
    struct nv_value *val;
-   struct nv_instruction *bnd, *nvi, *next;
+   struct nv_instruction *fix, *nvi, *next;
    int s;
 
-   for (bnd = b->entry; bnd; bnd = next) {
-      next = bnd->next;
-      if (bnd->opcode != NV_OP_BIND)
+   for (fix = b->entry; fix; fix = next) {
+      next = fix->next;
+
+      if (fix->opcode == NV_OP_LD) {
+         if (fix->indirect >= 0 && fix->src[0]->value->reg.size >= 8) {
+            nvi = nv_alloc_instruction(ctx->pc, NV_OP_UNDEF);
+            nv_reference(ctx->pc, nvi, 0, fix->src[fix->indirect]->value);
+
+            nvc0_insn_insert_after(fix, nvi);
+         }
          continue;
-      for (s = 0; s < 4 && bnd->src[s]; ++s) {
-         val = bnd->src[s]->value;
+      } else
+      if (fix->opcode == NV_OP_BIND) {
+         for (s = 0; s < 4 && fix->src[s]; ++s) {
+            val = fix->src[s]->value;
 
-         nvi = nv_alloc_instruction(ctx->pc, NV_OP_MOV);
-         nvi->def[0] = new_value_like(ctx->pc, val);
-         nvi->def[0]->insn = nvi;
-         nv_reference(ctx->pc, nvi, 0, val);
-         nv_reference(ctx->pc, bnd, s, nvi->def[0]);
+            nvi = nv_alloc_instruction(ctx->pc, NV_OP_MOV);
+            nvi->def[0] = new_value_like(ctx->pc, val);
+            nvi->def[0]->insn = nvi;
+            nv_reference(ctx->pc, nvi, 0, val);
+            nv_reference(ctx->pc, fix, s, nvi->def[0]);
 
-         nvc0_insn_insert_before(bnd, nvi);
+            nvc0_insn_insert_before(fix, nvi);
+         }
       }
    }
-   DESCEND_ARBITRARY(s, nv_pass_fix_bind);
+   DESCEND_ARBITRARY(s, nv_pass_fixups);
 
    return 0;
 }
@@ -1403,7 +1417,7 @@ nv_pc_pass0(struct nv_pc *pc, struct nv_basic_block *root)
       return ret;
 
    pc->pass_seq++;
-   ret = nv_pass_fix_bind(&pass, root);
+   ret = nv_pass_fixups(&pass, root);
 
    return ret;
 }



More information about the mesa-commit mailing list