Now that we convert phi webs to ssa, we can drop all this.
Signed-off-by: Rob Clark <robdclark@gmail.com>
/* meta instructions (category -1): */
/* placeholder instr to mark shader inputs: */
OPC_META_INPUT = _OPC(-1, 0),
- OPC_META_PHI = _OPC(-1, 1),
/* The "fan-in" and "fan-out" instructions are used for keeping
* track of instructions that write to multiple dst registers
* (fan-out) like texture sample instructions, or read multiple
*/
IR3_REG_SSA = 0x4000, /* 'instr' is ptr to assigning instr */
IR3_REG_ARRAY = 0x8000,
- IR3_REG_PHI_SRC= 0x10000, /* phi src, regs[0]->instr points to phi */
} flags;
union {
struct {
int off; /* component/offset */
} fo;
- struct {
- /* used to temporarily hold reference to nir_phi_instr
- * until we resolve the phi srcs
- */
- void *nphi;
- } phi;
struct {
struct ir3_block *block;
} inout;
put_dst(ctx, &tex->dest);
}
-static void
-emit_phi(struct ir3_context *ctx, nir_phi_instr *nphi)
-{
- struct ir3_instruction *phi, **dst;
-
- /* NOTE: phi's should be lowered to scalar at this point */
- compile_assert(ctx, nphi->dest.ssa.num_components == 1);
-
- dst = get_dst(ctx, &nphi->dest, 1);
-
- phi = ir3_instr_create2(ctx->block, OPC_META_PHI,
- 1 + exec_list_length(&nphi->srcs));
- ir3_reg_create(phi, 0, 0); /* dst */
- phi->phi.nphi = nphi;
-
- dst[0] = phi;
-
- put_dst(ctx, &nphi->dest);
-}
-
-/* phi instructions are left partially constructed. We don't resolve
- * their srcs until the end of the block, since (eg. loops) one of
- * the phi's srcs might be defined after the phi due to back edges in
- * the CFG.
- */
-static void
-resolve_phis(struct ir3_context *ctx, struct ir3_block *block)
-{
- list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node) {
- nir_phi_instr *nphi;
-
- /* phi's only come at start of block: */
- if (instr->opc != OPC_META_PHI)
- break;
-
- if (!instr->phi.nphi)
- break;
-
- nphi = instr->phi.nphi;
- instr->phi.nphi = NULL;
-
- foreach_list_typed(nir_phi_src, nsrc, node, &nphi->srcs) {
- struct ir3_instruction *src = get_src(ctx, &nsrc->src)[0];
-
- /* NOTE: src might not be in the same block as it comes from
- * according to the phi.. but in the end the backend assumes
- * it will be able to assign the same register to each (which
- * only works if it is assigned in the src block), so insert
- * an extra mov to make sure the phi src is assigned in the
- * block it comes from:
- */
- src = ir3_MOV(get_block(ctx, nsrc->pred), src, TYPE_U32);
-
- ir3_reg_create(instr, 0, IR3_REG_SSA)->instr = src;
- }
- }
-}
-
static void
emit_jump(struct ir3_context *ctx, nir_jump_instr *jump)
{
}
break;
}
- case nir_instr_type_phi:
- emit_phi(ctx, nir_instr_as_phi(instr));
- break;
case nir_instr_type_jump:
emit_jump(ctx, nir_instr_as_jump(instr));
break;
+ case nir_instr_type_phi:
+ /* we have converted phi webs to regs in NIR by now */
+ compile_error(ctx, "Unexpected NIR instruction type: %d\n", instr->type);
+ break;
case nir_instr_type_call:
case nir_instr_type_parallel_copy:
compile_error(ctx, "Unhandled NIR instruction type: %d\n", instr->type);
/* And emit the body: */
ctx->impl = fxn;
emit_function(ctx, fxn);
-
- list_for_each_entry (struct ir3_block, block, &ctx->ir->block_list, node) {
- resolve_phis(ctx, block);
- }
}
/* from NIR perspective, we actually have inputs. But most of the "inputs"
/* TODO: remove this hack: */
if (src_instr->opc == OPC_META_FO)
return false;
- /* TODO: we currently don't handle left/right neighbors
- * very well when inserting parallel-copies into phi..
- * to avoid problems don't eliminate a mov coming out
- * of phi..
- */
- if (src_instr->opc == OPC_META_PHI)
- return false;
+
return true;
}
return false;
{
struct ir3_instruction *src = ssa(reg);
- /* don't propagate copies into a PHI, since we don't know if the
- * src block executed:
- */
- if (instr->opc == OPC_META_PHI)
- return;
-
if (is_eligible_mov(src, true)) {
/* simple case, no immed/const/relativ, only mov's w/ ssa src: */
struct ir3_register *src_reg = src->regs[1];
conflict = conflicts(instr->cp.left, left) ||
conflicts(instr->cp.right, right);
- /* RA can't yet deal very well w/ group'd phi's: */
- if (instr->opc == OPC_META_PHI)
- conflict = true;
-
/* Mixing array elements and higher register classes
* (ie. groups) doesn't really work out in RA. See:
*
printf("(ss)");
if (is_meta(instr)) {
- switch(instr->opc) {
- case OPC_META_PHI:
- printf("Φ");
- break;
- default:
- /* shouldn't hit here.. just for debugging: */
- switch (instr->opc) {
- case OPC_META_INPUT: printf("_meta:in"); break;
- case OPC_META_FO: printf("_meta:fo"); break;
- case OPC_META_FI: printf("_meta:fi"); break;
+ switch (instr->opc) {
+ case OPC_META_INPUT: printf("_meta:in"); break;
+ case OPC_META_FO: printf("_meta:fo"); break;
+ case OPC_META_FI: printf("_meta:fi"); break;
- default: printf("_meta:%d", instr->opc); break;
- }
- break;
+ /* shouldn't hit here.. just for debugging: */
+ default: printf("_meta:%d", instr->opc); break;
}
} else if (instr->opc == OPC_MOV) {
static const char *type[] = {
d = instr;
}
- if (d->regs[0]->flags & IR3_REG_PHI_SRC) {
- struct ir3_instruction *phi = d->regs[0]->instr;
- struct ir3_instruction *dd;
- int dsz, doff;
-
- dd = get_definer(ctx, phi, &dsz, &doff);
-
- *sz = MAX2(*sz, dsz);
- *off = doff;
-
- if (instr_before(dd, d)) {
- d = dd;
- }
- }
-
- if (d->opc == OPC_META_PHI) {
- /* we have already inserted parallel-copies into
- * the phi, so we don't need to chase definers
- */
- struct ir3_register *src;
- struct ir3_instruction *dd = d;
-
- /* note: don't use foreach_ssa_src as this gets called once
- * while assigning regs (which clears SSA flag)
- */
- foreach_src(src, d) {
- if (!src->instr)
- continue;
- if (instr_before(src->instr, dd))
- dd = src->instr;
- }
-
- d = dd;
- }
-
if (d->opc == OPC_META_FO) {
struct ir3_instruction *dd;
int dsz, doff;
* to texture sample instructions; We consider these to be
* defined at the earliest fanin source.
*
- * phi: used to merge values from different flow control paths
- * to the same reg. Consider defined at earliest phi src,
- * and update all the other phi src's (which may come later
- * in the program) as users to extend the var's live range.
- *
- * Most of this, other than phi, is completely handled in the
- * get_definer() helper.
+ * Most of this is handled in the get_definer() helper.
*
* In either case, we trace the instruction back to the original
* definer and consider that as the def/use ip.
ir3_lookup_array(ctx->ir, dst->array.id);
unsigned i;
- debug_assert(!(dst->flags & IR3_REG_PHI_SRC));
-
arr->start_ip = MIN2(arr->start_ip, instr->ip);
arr->end_ip = MAX2(arr->end_ip, instr->ip);
ra_set_node_class(ctx->g, name,
ctx->set->classes[id->cls]);
}
-
- /* extend the live range for phi srcs, which may come
- * from the bottom of the loop
- */
- if (id->defn->regs[0]->flags & IR3_REG_PHI_SRC) {
- struct ir3_instruction *phi = id->defn->regs[0]->instr;
- foreach_ssa_src(src, phi) {
- /* if src is after phi, then we need to extend
- * the liverange to the end of src's block:
- */
- if (src->ip > phi->ip) {
- struct ir3_instruction *last =
- list_last_entry(&src->block->instr_list,
- struct ir3_instruction, node);
- ctx->use[name] = MAX2(ctx->use[name], last->ip);
- }
- }
- }
}
}
num += FIRST_HIGH_REG;
reg->num = num;
- reg->flags &= ~(IR3_REG_SSA | IR3_REG_PHI_SRC);
+ reg->flags &= ~IR3_REG_SSA;
if (is_half(id->defn))
reg->flags |= IR3_REG_HALF;
list_inithead(&block->instr_list);
list_inithead(&ctx->depth_list);
- /* first a pre-pass to schedule all meta:input/phi instructions
+ /* first a pre-pass to schedule all meta:input instructions
* (which need to appear first so that RA knows the register is
* occupied), and move remaining to depth sorted list:
*/
list_for_each_entry_safe (struct ir3_instruction, instr, &unscheduled_list, node) {
- if ((instr->opc == OPC_META_INPUT) || (instr->opc == OPC_META_PHI)) {
+ if (instr->opc == OPC_META_INPUT) {
schedule(ctx, instr);
} else {
ir3_insert_by_depth(instr, &ctx->depth_list);
*/
}
-/* this is needed to ensure later RA stage succeeds: */
-static void
-sched_insert_parallel_copies(struct ir3_block *block)
-{
- list_for_each_entry (struct ir3_instruction, instr, &block->instr_list, node) {
- if (instr->opc == OPC_META_PHI) {
- struct ir3_register *reg, *reg2;
- foreach_src(reg, instr) {
- struct ir3_instruction *src = reg->instr;
- struct ir3_instruction *mov = NULL;
-
- /* after CP we could end up w/ duplicate phi srcs: */
- foreach_src(reg2, instr) {
- if (reg == reg2)
- break;
- /* reg2 is before reg1 so already an inserted mov: */
- else if (reg2->instr->regs[1]->instr == src) {
- mov = reg2->instr;
- break;
- }
- }
-
- if (!mov) {
- mov = ir3_MOV(src->block, src, TYPE_U32);
- mov->regs[0]->flags |= IR3_REG_PHI_SRC;
- mov->regs[0]->instr = instr;
- }
-
- reg->instr = mov;
- }
- }
- }
-}
-
int ir3_sched(struct ir3 *ir)
{
struct ir3_sched_ctx ctx = {0};
- list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
- sched_insert_parallel_copies(block);
- }
+
ir3_clear_mark(ir);
list_for_each_entry (struct ir3_block, block, &ir->block_list, node) {
sched_block(&ctx, block);