nvc0: make sure all sources of the BIND op are distinct

They're supposed to be assigned consecutive registers so they can't
contain the same SSA value more than once.
This commit is contained in:
Christoph Bumiller 2011-01-15 14:03:05 +01:00
parent 1ae982adfd
commit 52474d4246
3 changed files with 45 additions and 0 deletions

View File

@ -514,6 +514,13 @@ nvc0_insn_insert_after(struct nv_instruction *at, struct nv_instruction *ni)
ni->prev->next = ni;
}
void
nvc0_insn_insert_before(struct nv_instruction *at, struct nv_instruction *ni)
{
nvc0_insn_insert_after(at, ni);
nvc0_insns_permute(at, ni);
}
void
nvc0_insn_delete(struct nv_instruction *nvi)
{

View File

@ -473,6 +473,7 @@ struct nv_pc {
};
void nvc0_insn_append(struct nv_basic_block *, struct nv_instruction *);
void nvc0_insn_insert_before(struct nv_instruction *, struct nv_instruction *);
void nvc0_insn_insert_after(struct nv_instruction *, struct nv_instruction *);
static INLINE struct nv_instruction *

View File

@ -1101,6 +1101,40 @@ nv_pass_cse(struct nv_pass *ctx, struct nv_basic_block *b)
return 0;
}
/* Make sure all sources of an NV_OP_BIND are distinct, they need to occupy
* neighbouring registers. CSE might have messed this up.
*/
static int
nv_pass_fix_bind(struct nv_pass *ctx, struct nv_basic_block *b)
{
struct nv_value *val;
struct nv_instruction *bnd, *nvi, *next;
int s, t;
for (bnd = b->entry; bnd; bnd = next) {
next = bnd->next;
if (bnd->opcode != NV_OP_BIND)
continue;
for (s = 0; s < 4 && bnd->src[s]; ++s) {
val = bnd->src[s]->value;
for (t = s + 1; t < 4 && bnd->src[t]; ++t) {
if (bnd->src[t]->value != val)
continue;
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);
nvc0_insn_insert_before(bnd, nvi);
nv_reference(ctx->pc, bnd, t, nvi->def[0]);
}
}
}
DESCEND_ARBITRARY(t, nv_pass_fix_bind);
return 0;
}
static int
nv_pc_pass0(struct nv_pc *pc, struct nv_basic_block *root)
{
@ -1177,6 +1211,9 @@ nv_pc_pass0(struct nv_pc *pc, struct nv_basic_block *root)
if (ret)
return ret;
pc->pass_seq++;
ret = nv_pass_fix_bind(&pass, root);
return ret;
}