/* branches/flow control */
OPC_META_FLOW = 4,
OPC_META_PHI = 5,
- /* relative addressing */
- OPC_META_DEREF = 6,
-
} opc_t;
* the component is in the low two bits of the reg #, so
* rN.x becomes: (N << 2) | x
*/
- int num;
+ int num;
/* immediate: */
- int iim_val;
- float fim_val;
+ int iim_val;
+ float fim_val;
/* relative: */
- int offset;
- /* for IR3_REG_SSA, src registers contain ptr back to
- * assigning instruction.
- */
- struct ir3_instruction *instr;
+ int offset;
};
+ /* for IR3_REG_SSA, src registers contain ptr back to
+ * assigning instruction.
+ */
+ struct ir3_instruction *instr;
+
union {
/* used for cat5 instructions, but also for internal/IR level
* tracking of what registers are read/written by an instruction.
struct {
struct ir3_block *block;
} inout;
- struct {
- int off; /* offset relative to addr reg */
- } deref;
/* XXX keep this as big as all other union members! */
uint32_t info[3];
struct ir3_instruction *left, *right;
uint16_t left_cnt, right_cnt;
} cp;
+
+ /* an instruction can reference at most one address register amongst
+ * it's src/dst registers. Beyond that, you need to insert mov's.
+ */
+ struct ir3_instruction *address;
+
struct ir3_instruction *next;
#ifdef DEBUG
uint32_t serialno;
return (instr->category == -1);
}
-static inline bool is_addr(struct ir3_instruction *instr)
-{
- return is_meta(instr) && (instr->opc == OPC_META_DEREF);
-}
-
static inline bool writes_addr(struct ir3_instruction *instr)
{
if (instr->regs_count > 0) {
static inline unsigned __ssa_src_cnt(struct ir3_instruction *instr)
{
+ if (instr->address)
+ return instr->regs_count + 1;
return instr->regs_count;
}
static inline struct ir3_instruction * __ssa_src_n(struct ir3_instruction *instr, unsigned n)
{
+ if (n == (instr->regs_count + 0))
+ return instr->address;
return ssa(instr->regs[n]);
}
* we must generate a fanin instruction to collect all possible
* array elements that the instruction could address together:
*/
- unsigned i, j, aid = src_array_id(ctx, src);
+ unsigned aid = src_array_id(ctx, src);
+ unsigned first = ctx->array[aid].first;
+ unsigned last = ctx->array[aid].last;
+ unsigned off = src->Index - first; /* vec4 offset */
+ unsigned i, j;
+
+ reg->size = 4 * (1 + last - first);
+ reg->offset = regid(off, chan);
if (ctx->array[aid].fanin) {
instr = ctx->array[aid].fanin;
} else {
- unsigned first, last;
-
- first = ctx->array[aid].first;
- last = ctx->array[aid].last;
-
instr = ir3_instr_create2(ctx->block, -1, OPC_META_FI,
1 + (4 * (last + 1 - first)));
ir3_reg_create(instr, 0, 0);
{
unsigned flags = 0, num = 0;
struct ir3_register *reg;
- struct ir3_instruction *orig = NULL;
switch (src->File) {
case TGSI_FILE_IMMEDIATE:
/* shouldn't happen, and we can't cope with it below: */
compile_assert(ctx, wrmask == 0x1);
- /* wrap in a meta-deref to track both the src and address: */
- orig = instr;
-
- instr = ir3_instr_create(ctx->block, -1, OPC_META_DEREF);
- ir3_reg_create(instr, 0, 0);
- ir3_reg_create(instr, 0, IR3_REG_SSA)->instr = ctx->block->address;
+ compile_assert(ctx, ctx->block->address);
+ if (instr->address)
+ compile_assert(ctx, ctx->block->address == instr->address);
- if (src->File != TGSI_FILE_CONSTANT) {
- unsigned aid = src_array_id(ctx, src);
- unsigned off = src->Index - ctx->array[aid].first; /* vec4 offset */
- instr->deref.off = regid(off, chan);
- }
+ instr->address = ctx->block->address;
}
reg = ir3_reg_create(instr, regid(num, chan), flags);
-
- if (src->Indirect && (src->File != TGSI_FILE_CONSTANT)) {
- unsigned aid = src_array_id(ctx, src);
- reg->size = 4 * (1 + ctx->array[aid].last - ctx->array[aid].first);
- } else {
- reg->wrmask = wrmask;
- }
+ reg->wrmask = wrmask;
if (wrmask == 0x1) {
/* normal case */
reg->instr = collect;
}
- if (src->Indirect) {
- unsigned size = reg->size;
-
- reg = ir3_reg_create(orig, 0, flags | IR3_REG_SSA);
- reg->instr = instr;
- reg->size = size;
- }
-
return reg;
}
foreach_src(reg, instr)
if (reg->flags & IR3_REG_SSA)
reg->instr = instr_cp(reg->instr);
+
+ if (instr->address)
+ instr->address = instr_cp(instr->address);
}
return instr;
case OPC_META_PHI:
fprintf(ctx->f, "Φ");
break;
- case OPC_META_DEREF:
- fprintf(ctx->f, "(*)");
- break;
default:
/* shouldn't hit here.. just for debugging: */
switch (instr->opc) {
ir3_block_dump(ctx, instr->flow.else_block, "else");
if (reg->flags & IR3_REG_SSA)
dump_instr(ctx, reg->instr);
- } else if ((instr->opc == OPC_META_PHI) ||
- (instr->opc == OPC_META_DEREF)) {
+ } else if (instr->opc == OPC_META_PHI) {
/* treat like a normal instruction: */
ir3_instr_dump(ctx, instr);
}
printdef(ctx, defer, "output%lx:<out%u>:w -> %s",
PTRID(instr->inout.block),
instr->regs[0]->num, target);
- } else if ((instr->opc == OPC_META_PHI) ||
- (instr->opc == OPC_META_DEREF)) {
+ } else if (instr->opc == OPC_META_PHI) {
/* treat like a normal instruction: */
printdef(ctx, defer, "instr%lx:<dst0> -> %s", PTRID(instr), target);
}
dump_reg_name(&ctx, reg, !!i);
}
+ if (instr->address) {
+ fprintf(ctx.f, ", address=_");
+ fprintf(ctx.f, "[");
+ dump_instr_name(&ctx, instr->address);
+ fprintf(ctx.f, "]");
+ }
+
if (is_meta(instr) && (instr->opc == OPC_META_FO))
printf(", off=%d", instr->fo.off);
static void instr_assign_src(struct ir3_ra_ctx *ctx,
struct ir3_instruction *instr, unsigned r, unsigned name)
{
+ struct ir3_register *reg = instr->regs[r];
+
+ if (reg->flags & IR3_REG_RELATIV)
+ name += reg->offset;
+
reg_assign(instr, r, name);
if (is_meta(instr)) {
case OPC_META_FI:
instr_assign(ctx, instr, name - (r - 1));
return;
- case OPC_META_DEREF:
- /* first arg of meta:deref is the addr reg (do not
- * propagate), 2nd is actual src (fanin) which does
- * get propagated)
- */
- if (r == 2)
- instr_assign(ctx, instr, name + instr->deref.off);
- break;
default:
break;
}
struct ir3_instruction *n, *src;
struct ir3_register *reg = instr->regs[0];
+ if ((reg->flags & IR3_REG_RELATIV))
+ name += reg->offset;
+
/* check if already assigned: */
if (!(reg->flags & IR3_REG_SSA)) {
/* ... and if so, sanity check: */
/* allocate register(s): */
if (name >= 0) {
/* already partially assigned, just finish the job */
- } else if (is_addr(instr)) {
- debug_assert(!instr->cp.right);
- name = instr->regs[2]->num + instr->deref.off;
} else if (reg_gpr(dst)) {
int size;
/* number of consecutive registers to assign: */
static bool uses_current_addr(struct ir3_sched_ctx *ctx,
struct ir3_instruction *instr)
{
- struct ir3_instruction *src;
- foreach_ssa_src(src, instr) {
- if (is_addr(src)) {
- struct ir3_instruction *addr =
- src->regs[1]->instr; /* the mova */
- if (ctx->addr == addr)
- return true;
- }
- }
- return false;
+ return instr->address && (ctx->addr == instr->address);
}
static bool uses_current_pred(struct ir3_sched_ctx *ctx,