freedreno/ir3: remove ir3 phi instruction

Now that we convert phi webs to ssa, we can drop all this.

Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
Rob Clark
2018-01-29 16:22:26 -05:00
parent a7b569d60c
commit 242a8a1957
8 changed files with 16 additions and 205 deletions
@@ -202,7 +202,6 @@ typedef enum {
/* 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
-7
View File
@@ -93,7 +93,6 @@ struct ir3_register {
*/
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 {
@@ -261,12 +260,6 @@ struct ir3_instruction {
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;
@@ -2593,64 +2593,6 @@ emit_tex_txs(struct ir3_context *ctx, nir_tex_instr *tex)
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)
{
@@ -2701,12 +2643,13 @@ emit_instr(struct ir3_context *ctx, nir_instr *instr)
}
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);
@@ -3180,10 +3123,6 @@ emit_instructions(struct ir3_context *ctx)
/* 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"
+1 -13
View File
@@ -67,13 +67,7 @@ static bool is_eligible_mov(struct ir3_instruction *instr, bool allow_flags)
/* 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;
@@ -328,12 +322,6 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
{
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];
@@ -133,10 +133,6 @@ restart:
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:
*
+6 -13
View File
@@ -50,20 +50,13 @@ static void print_instr_name(struct ir3_instruction *instr)
printf("(ss)");
if (is_meta(instr)) {
switch(instr->opc) {
case OPC_META_PHI:
printf("&#934;");
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[] = {
+2 -63
View File
@@ -484,41 +484,6 @@ get_definer(struct ir3_ra_ctx *ctx, struct ir3_instruction *instr,
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;
@@ -713,13 +678,7 @@ ra_block_compute_live_ranges(struct ir3_ra_ctx *ctx, struct ir3_block *block)
* 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.
@@ -734,8 +693,6 @@ ra_block_compute_live_ranges(struct ir3_ra_ctx *ctx, struct ir3_block *block)
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);
@@ -780,24 +737,6 @@ ra_block_compute_live_ranges(struct ir3_ra_ctx *ctx, struct ir3_block *block)
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);
}
}
}
}
}
@@ -1064,7 +1003,7 @@ reg_assign(struct ir3_ra_ctx *ctx, struct ir3_register *reg,
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;
+3 -39
View File
@@ -516,12 +516,12 @@ sched_block(struct ir3_sched_ctx *ctx, struct ir3_block *block)
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);
@@ -633,46 +633,10 @@ sched_block(struct ir3_sched_ctx *ctx, struct ir3_block *block)
*/
}
/* 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);