diff --git a/.pick_status.json b/.pick_status.json index 5db7017427a..dc3e24c831b 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -114,7 +114,7 @@ "description": "ir3: only add live-in phis for top-level intervals while spilling", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "613eaac7b53bfbfcd6ef536412be6c9c63cdea4f", "notes": null diff --git a/src/freedreno/ir3/ir3_spill.c b/src/freedreno/ir3/ir3_spill.c index 77b8201c580..8381ca7f443 100644 --- a/src/freedreno/ir3/ir3_spill.c +++ b/src/freedreno/ir3/ir3_spill.c @@ -1031,6 +1031,17 @@ static void handle_instr(struct ra_spill_ctx *ctx, struct ir3_instruction *instr) { ra_foreach_dst (dst, instr) { + /* No need to handle instructions inserted while spilling. Most are + * ignored automatically by virtue of being inserted before the current + * instruction. However, for live-ins, we may insert extracts after the + * phis. Trying to handle them ends badly as they don't have intervals + * allocated. + * Note: since liveness is calculated before spilling, original + * instruction have a name while new ones don't. + */ + if (!dst->name) + return; + init_dst(ctx, dst); } @@ -1477,20 +1488,6 @@ live_in_rewrite(struct ra_spill_ctx *ctx, if (def) _mesa_hash_table_insert(state->remap, def, new_val); - - rb_tree_foreach (struct ra_spill_interval, child, - &interval->interval.children, interval.node) { - assert(new_val->flags & IR3_REG_SSA); - struct ir3_register *child_def = - extract(new_val->def, - (child->interval.reg->interval_start - def->interval_start) / - reg_elem_size(def), reg_elems(child->interval.reg), - ir3_before_terminator(pred)); - struct reg_or_immed *child_val = ralloc(ctx, struct reg_or_immed); - child_val->def = child_def; - child_val->flags = child_def->flags; - live_in_rewrite(ctx, child, child_val, block, pred_idx); - } } static void @@ -1532,7 +1529,7 @@ reload_live_ins(struct ra_spill_ctx *ctx, struct ir3_block *block) static void add_live_in_phi(struct ra_spill_ctx *ctx, struct ir3_register *def, - struct ir3_block *block) + struct ir3_register *parent_def, struct ir3_block *block) { struct ra_spill_interval *interval = ctx->intervals[def->name]; if (!interval->interval.inserted) @@ -1565,6 +1562,26 @@ add_live_in_phi(struct ra_spill_ctx *ctx, struct ir3_register *def, if (!needs_phi) { interval->dst.def = cur_def; interval->dst.flags = cur_def->flags; + + rb_tree_foreach (struct ra_spill_interval, child, + &interval->interval.children, interval.node) { + add_live_in_phi(ctx, child->interval.reg, cur_def, block); + } + + return; + } + + if (parent_def) { + /* We have a child interval that needs a phi but whose parent does not + * need one (otherwise parent_def would be NULL). Just extract the child + * from the parent without creating a phi for the child. + */ + unsigned offset = (def->interval_start - parent_def->interval_start) / + reg_elem_size(def); + struct ir3_register *extracted = + extract(parent_def, offset, reg_elems(def), ir3_after_phis(block)); + rewrite_src_interval(ctx, interval, extracted, + ir3_after_instr(extracted->instr)); return; } @@ -1600,6 +1617,19 @@ add_live_in_phi(struct ra_spill_ctx *ctx, struct ir3_register *def, interval->dst.def = dst; interval->dst.flags = dst->flags; + rewrite_src_interval(ctx, interval, dst, ir3_after_phis(block)); +} + +static void +add_live_in_phis(struct ra_spill_ctx *ctx, struct ir3_block *block) +{ + rb_tree_foreach (struct ra_spill_interval, interval, &ctx->reg_ctx.intervals, + interval.node) { + if (BITSET_TEST(ctx->live->live_in[block->index], + interval->interval.reg->name)) { + add_live_in_phi(ctx, interval->interval.reg, NULL, block); + } + } } /* When spilling a block with a single predecessors, the pred may have other @@ -1831,11 +1861,7 @@ handle_block(struct ra_spill_ctx *ctx, struct ir3_block *block) break; rewrite_phi(ctx, instr, block); } - BITSET_FOREACH_SET (name, ctx->live->live_in[block->index], - ctx->live->definitions_count) { - struct ir3_register *reg = ctx->live->definitions[name]; - add_live_in_phi(ctx, reg, block); - } + add_live_in_phis(ctx, block); } } else { update_max_pressure(ctx);