Mesa (master): nvc0: prevent overlap between load address and destination regs
Christoph Bumiller
chrisbmr at kemper.freedesktop.org
Fri May 13 16:48:39 UTC 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