/**
* BIND forces source operand i into the same register as destination operand i,
- * and the operands will be assigned consecutive registers (needed for TEX)
+ * and the operands will be assigned consecutive registers (needed for TEX).
+ * Beware conflicts !
* SELECT forces its multiple source operands and its destination operand into
* one and the same register.
*/
/* Make sure all sources of an NV_OP_BIND are distinct, they need to occupy
* 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.
*/
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;
+ int s;
for (bnd = b->entry; bnd; bnd = next) {
next = bnd->next;
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]);
- }
+ 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]);
+
+ nvc0_insn_insert_before(bnd, nvi);
}
}
- DESCEND_ARBITRARY(t, nv_pass_fix_bind);
+ DESCEND_ARBITRARY(s, nv_pass_fix_bind);
return 0;
}
break;
case NV_OP_MOV:
if ((iter == 2) && i->src[0]->value->insn &&
- !nv_is_texture_op(i->src[0]->value->join->insn->opcode))
+ !nv_is_vector_op(i->src[0]->value->join->insn->opcode))
try_join_values(ctx, i->def[0], i->src[0]->value);
break;
case NV_OP_SELECT:
do_join_values(ctx, i->def[0], i->src[c]->value);
}
break;
- case NV_OP_TEX:
- case NV_OP_TXB:
- case NV_OP_TXL:
- case NV_OP_TXQ:
- /* on nvc0, TEX src and dst can differ */
- break;
case NV_OP_BIND:
if (iter)
break;
- for (c = 0; c < 6 && i->src[c]; ++c)
+ for (c = 0; c < 4 && i->src[c]; ++c)
do_join_values(ctx, i->def[c], i->src[c]->value);
break;
+ case NV_OP_TEX:
+ case NV_OP_TXB:
+ case NV_OP_TXL:
+ case NV_OP_TXQ: /* on nvc0, TEX src and dst can differ */
default:
break;
}
set->pc = pc;
}
+/* We allocate registers for all defs of a vector instruction at once.
+ * Since we'll encounter all of them in the allocation loop, do the allocation
+ * when we're at the one with the live range that starts latest.
+ */
+static boolean
+is_best_representative(struct nv_value *val)
+{
+ struct nv_instruction *nvi = val->insn;
+ int i;
+ for (i = 0; i < 4 && val->insn->def[i]; ++i)
+ if (nvi->def[i]->livei && nvi->def[i]->livei->bgn > val->livei->bgn)
+ return FALSE;
+ return TRUE;
+}
+
static void
insert_ordered_tail(struct nv_value *list, struct nv_value *nval)
{
boolean mem = FALSE;
int v = nvi_vector_size(cur->insn);
- if (v > 1)
- mem = !reg_assign(&f, &cur->insn->def[0], v);
- else
+ if (v > 1) {
+ if (is_best_representative(cur))
+ mem = !reg_assign(&f, &cur->insn->def[0], v);
+ } else {
if (iter)
mem = !reg_assign(&f, &cur, 1);
+ }
if (mem) {
NOUVEAU_ERR("out of registers\n");
if (array)
arg[dim] = bld_cvt(bld, NV_TYPE_U32, NV_TYPE_F32, arg[dim]);
- /* ensure that all inputs reside in a GPR */
- for (c = 0; c < dim + array + cube + shadow; ++c)
- (src[c] = bld_insn_1(bld, NV_OP_MOV, arg[c]))->insn->fixed = 1;
-
/* bind { layer x y z } and { lod/bias shadow } to adjacent regs */
bnd = new_instruction(bld->pc, NV_OP_BIND);
}
for (c = 0; c < 4; ++c)
- if ((mask & (1 << c)) &&
- ((dst0[c]->reg.file == NV_FILE_IMM) ||
- (dst0[c]->reg.id == 63 && dst0[c]->reg.file == NV_FILE_GPR)))
- dst0[c] = bld_insn_1(bld, NV_OP_MOV, dst0[c]);
+ if (mask & (1 << c))
+ if ((dst0[c]->reg.file == NV_FILE_IMM) ||
+ (dst0[c]->reg.file == NV_FILE_GPR && dst0[c]->reg.id == 63))
+ dst0[c] = bld_insn_1(bld, NV_OP_MOV, dst0[c]);
c = 0;
if ((mask & 0x3) == 0x3) {