diff --git a/src/freedreno/ir3/ir3_ra.c b/src/freedreno/ir3/ir3_ra.c index 97e4815318c..1a6377dd821 100644 --- a/src/freedreno/ir3/ir3_ra.c +++ b/src/freedreno/ir3/ir3_ra.c @@ -2293,9 +2293,22 @@ handle_block(struct ra_ctx *ctx, struct ir3_block *block) handle_live_in(ctx, reg); } + /* Handle phis in two groups: first those which already have a preferred reg + * set and then those without. The second group should be rare but by + * handling them last, they don't accidentally occupy a preferred reg of + * another phi, preventing excessive copying in some cases. + */ + bool skipped_phi = false; + foreach_instr (instr, &block->instr_list) { if (instr->opc == OPC_META_PHI) { - handle_phi(ctx, instr->dsts[0]); + struct ir3_register *dst = instr->dsts[0]; + + if (dst->merge_set && dst->merge_set->preferred_reg != (physreg_t)~0) { + handle_phi(ctx, dst); + } else { + skipped_phi = true; + } } else if (instr->opc == OPC_META_INPUT || instr->opc == OPC_META_TEX_PREFETCH) { handle_input(ctx, instr); @@ -2304,6 +2317,20 @@ handle_block(struct ra_ctx *ctx, struct ir3_block *block) } } + if (skipped_phi) { + foreach_instr (instr, &block->instr_list) { + if (instr->opc == OPC_META_PHI) { + struct ir3_register *dst = instr->dsts[0]; + + if (!ctx->intervals[dst->name].interval.inserted) { + handle_phi(ctx, dst); + } + } else { + break; + } + } + } + /* After this point, every live-in/phi/input has an interval assigned to * it. We delay actually assigning values until everything has been * allocated, so we can simply ignore any parallel copy entries created