ir3: refactor ir3_spill.c to use the ir3_cursor/ir3_builder API

There were a few places that used an instruction pointer to decide where
new instructions should be created. NULL was used to add them at the end
of the block. While fixing a spilling bug, a new option was needed to
add instructions at the beginning of the block. This will be much easier
to implement using cursors.

Fixes: 613eaac7b5 ("ir3: Initial support for spilling non-shared registers")
Signed-off-by: Job Noorman <jnoorman@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29497>
(cherry picked from commit 18cd803cef)
This commit is contained in:
Job Noorman 2024-06-17 11:34:26 +02:00 committed by Eric Engestrom
parent 6f0d595bb5
commit 0c8177d28e
2 changed files with 54 additions and 73 deletions

View file

@ -124,7 +124,7 @@
"description": "ir3: refactor ir3_spill.c to use the ir3_cursor/ir3_builder API",
"nominated": true,
"nomination_type": 1,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": "613eaac7b53bfbfcd6ef536412be6c9c63cdea4f",
"notes": null

View file

@ -346,13 +346,12 @@ can_rematerialize(struct ir3_register *reg)
}
static struct ir3_register *
rematerialize(struct ir3_register *reg, struct ir3_instruction *after,
struct ir3_block *block)
rematerialize(struct ir3_register *reg, struct ir3_cursor cursor)
{
d("rematerializing ssa_%u:%u", reg->instr->serialno, reg->name);
struct ir3_instruction *remat =
ir3_instr_create(block, reg->instr->opc, 1, reg->instr->srcs_count);
ir3_instr_create_at(cursor, reg->instr->opc, 1, reg->instr->srcs_count);
struct ir3_register *dst = __ssa_dst(remat);
dst->flags |= reg->flags & (IR3_REG_HALF | IR3_REG_ARRAY);
for (unsigned i = 0; i < reg->instr->srcs_count; i++) {
@ -367,10 +366,6 @@ rematerialize(struct ir3_register *reg, struct ir3_instruction *after,
dst->merge_set_offset = reg->merge_set_offset;
dst->interval_start = reg->interval_start;
dst->interval_end = reg->interval_end;
if (after)
ir3_instr_move_before(remat, after);
return dst;
}
@ -718,33 +713,30 @@ set_src_val(struct ir3_register *src, const struct reg_or_immed *val)
static struct ir3_register *
materialize_pcopy_src(const struct reg_or_immed *src,
struct ir3_instruction *instr,
struct ir3_block *block)
struct ir3_builder *builder)
{
struct ir3_instruction *mov = ir3_instr_create(block, OPC_MOV, 1, 1);
struct ir3_instruction *mov = ir3_build_instr(builder, OPC_MOV, 1, 1);
struct ir3_register *dst = __ssa_dst(mov);
dst->flags |= src->flags & IR3_REG_HALF;
struct ir3_register *mov_src = ir3_src_create(mov, INVALID_REG, src->flags);
set_src_val(mov_src, src);
mov->cat1.src_type = mov->cat1.dst_type =
(src->flags & IR3_REG_HALF) ? TYPE_U16 : TYPE_U32;
if (instr)
ir3_instr_move_before(mov, instr);
return dst;
}
static void
spill(struct ra_spill_ctx *ctx, const struct reg_or_immed *val,
unsigned spill_slot, struct ir3_instruction *instr, struct ir3_block *block)
unsigned spill_slot, struct ir3_cursor cursor)
{
struct ir3_register *reg;
struct ir3_builder builder = ir3_builder_at(cursor);
/* If spilling an immed/const pcopy src, we need to actually materialize it
* first with a mov.
*/
if (val->flags & (IR3_REG_CONST | IR3_REG_IMMED)) {
reg = materialize_pcopy_src(val, instr, block);
reg = materialize_pcopy_src(val, &builder);
} else {
reg = val->def;
reg->instr->flags &= ~IR3_INSTR_UNUSED;
@ -755,7 +747,7 @@ spill(struct ra_spill_ctx *ctx, const struct reg_or_immed *val,
unsigned elems = reg_elems(reg);
struct ir3_instruction *spill =
ir3_instr_create(block, OPC_SPILL_MACRO, 0, 3);
ir3_build_instr(&builder, OPC_SPILL_MACRO, 0, 3);
ir3_src_create(spill, INVALID_REG, ctx->base_reg->flags)->def = ctx->base_reg;
unsigned src_flags = reg->flags & (IR3_REG_HALF | IR3_REG_IMMED |
IR3_REG_CONST | IR3_REG_SSA |
@ -773,25 +765,22 @@ spill(struct ra_spill_ctx *ctx, const struct reg_or_immed *val,
} else {
src->wrmask = reg->wrmask;
}
if (instr)
ir3_instr_move_before(spill, instr);
}
static void
spill_interval(struct ra_spill_ctx *ctx, struct ra_spill_interval *interval,
struct ir3_instruction *instr, struct ir3_block *block)
struct ir3_cursor cursor)
{
if (interval->can_rematerialize && !interval->interval.reg->merge_set)
return;
spill(ctx, &interval->dst, get_spill_slot(ctx, interval->interval.reg),
instr, block);
cursor);
}
/* This is similar to "limit" in the paper. */
static void
limit(struct ra_spill_ctx *ctx, struct ir3_instruction *instr)
limit(struct ra_spill_ctx *ctx, struct ir3_cursor cursor)
{
if (ctx->cur_pressure.half > ctx->limit_pressure.half) {
d("cur half pressure %u exceeds %u", ctx->cur_pressure.half,
@ -802,7 +791,7 @@ limit(struct ra_spill_ctx *ctx, struct ir3_instruction *instr)
interval->interval.reg->name);
if (!interval->cant_spill) {
if (!interval->already_spilled)
spill_interval(ctx, interval, instr, instr->block);
spill_interval(ctx, interval, cursor);
ir3_reg_interval_remove_all(&ctx->reg_ctx, &interval->interval);
if (ctx->cur_pressure.half <= ctx->limit_pressure.half)
break;
@ -821,7 +810,7 @@ limit(struct ra_spill_ctx *ctx, struct ir3_instruction *instr)
interval->interval.reg->name);
if (!interval->cant_spill) {
if (!interval->already_spilled)
spill_interval(ctx, interval, instr, instr->block);
spill_interval(ctx, interval, cursor);
ir3_reg_interval_remove_all(&ctx->reg_ctx, &interval->interval);
if (ctx->cur_pressure.full <= ctx->limit_pressure.full)
break;
@ -856,8 +845,7 @@ add_to_merge_set(struct ir3_merge_set *set, struct ir3_register *def,
}
static struct ir3_register *
split(struct ir3_register *def, unsigned offset,
struct ir3_instruction *after, struct ir3_block *block)
split(struct ir3_register *def, unsigned offset, struct ir3_builder *builder)
{
if (reg_elems(def) == 1) {
assert(offset == 0);
@ -867,7 +855,7 @@ split(struct ir3_register *def, unsigned offset,
assert(!(def->flags & IR3_REG_ARRAY));
assert(def->merge_set);
struct ir3_instruction *split =
ir3_instr_create(block, OPC_META_SPLIT, 1, 1);
ir3_build_instr(builder, OPC_META_SPLIT, 1, 1);
split->split.off = offset;
struct ir3_register *dst = __ssa_dst(split);
dst->flags |= def->flags & IR3_REG_HALF;
@ -876,25 +864,24 @@ split(struct ir3_register *def, unsigned offset,
src->def = def;
add_to_merge_set(def->merge_set, dst,
def->merge_set_offset + offset * reg_elem_size(def));
if (after)
ir3_instr_move_before(split, after);
return dst;
}
static struct ir3_register *
extract(struct ir3_register *parent_def, unsigned offset, unsigned elems,
struct ir3_instruction *after, struct ir3_block *block)
struct ir3_cursor cursor)
{
if (offset == 0 && elems == reg_elems(parent_def))
return parent_def;
struct ir3_builder builder = ir3_builder_at(cursor);
struct ir3_register *srcs[elems];
for (unsigned i = 0; i < elems; i++) {
srcs[i] = split(parent_def, offset + i, after, block);
srcs[i] = split(parent_def, offset + i, &builder);
}
struct ir3_instruction *collect =
ir3_instr_create(block, OPC_META_COLLECT, 1, elems);
ir3_build_instr(&builder, OPC_META_COLLECT, 1, elems);
struct ir3_register *dst = __ssa_dst(collect);
dst->flags |= parent_def->flags & IR3_REG_HALF;
dst->wrmask = MASK(elems);
@ -904,14 +891,12 @@ extract(struct ir3_register *parent_def, unsigned offset, unsigned elems,
ir3_src_create(collect, INVALID_REG, parent_def->flags)->def = srcs[i];
}
if (after)
ir3_instr_move_before(collect, after);
return dst;
}
static struct ir3_register *
reload(struct ra_spill_ctx *ctx, struct ir3_register *reg,
struct ir3_instruction *after, struct ir3_block *block)
struct ir3_cursor cursor)
{
unsigned spill_slot = get_spill_slot(ctx, reg);
@ -920,7 +905,7 @@ reload(struct ra_spill_ctx *ctx, struct ir3_register *reg,
unsigned elems = reg_elems(reg);
struct ir3_instruction *reload =
ir3_instr_create(block, OPC_RELOAD_MACRO, 1, 3);
ir3_instr_create_at(cursor, OPC_RELOAD_MACRO, 1, 3);
struct ir3_register *dst = __ssa_dst(reload);
dst->flags |= reg->flags & (IR3_REG_HALF | IR3_REG_ARRAY);
/* The reload may be split into multiple pieces, and if the destination
@ -950,10 +935,6 @@ reload(struct ra_spill_ctx *ctx, struct ir3_register *reg,
dst->merge_set_offset = reg->merge_set_offset;
dst->interval_start = reg->interval_start;
dst->interval_end = reg->interval_end;
if (after)
ir3_instr_move_before(reload, after);
return dst;
}
@ -961,8 +942,7 @@ static void
rewrite_src_interval(struct ra_spill_ctx *ctx,
struct ra_spill_interval *interval,
struct ir3_register *def,
struct ir3_instruction *instr,
struct ir3_block *block)
struct ir3_cursor cursor)
{
interval->dst.flags = def->flags;
interval->dst.def = def;
@ -974,14 +954,14 @@ rewrite_src_interval(struct ra_spill_ctx *ctx,
struct ir3_register *child_def =
extract(def, (child_reg->interval_start -
interval->interval.reg->interval_start) / reg_elem_size(def),
reg_elems(child_reg), instr, block);
rewrite_src_interval(ctx, child, child_def, instr, block);
reg_elems(child_reg), cursor);
rewrite_src_interval(ctx, child, child_def, cursor);
}
}
static void
reload_def(struct ra_spill_ctx *ctx, struct ir3_register *def,
struct ir3_instruction *instr, struct ir3_block *block)
struct ir3_cursor cursor)
{
unsigned elems = reg_elems(def);
struct ra_spill_interval *interval = ctx->intervals[def->name];
@ -995,28 +975,28 @@ reload_def(struct ra_spill_ctx *ctx, struct ir3_register *def,
interval->dst.flags = def->flags;
interval->dst.def = extract(
parent->dst.def, (def->interval_start - parent->dst.def->interval_start) /
reg_elem_size(def), elems, instr, block);
reg_elem_size(def), elems, cursor);
return;
}
}
struct ir3_register *dst;
if (interval->can_rematerialize)
dst = rematerialize(def, instr, block);
dst = rematerialize(def, cursor);
else
dst = reload(ctx, def, instr, block);
dst = reload(ctx, def, cursor);
rewrite_src_interval(ctx, interval, dst, instr, block);
rewrite_src_interval(ctx, interval, dst, cursor);
}
static void
reload_src(struct ra_spill_ctx *ctx, struct ir3_instruction *instr,
reload_src(struct ra_spill_ctx *ctx, struct ir3_cursor cursor,
struct ir3_register *src)
{
struct ra_spill_interval *interval = ctx->intervals[src->def->name];
if (interval->needs_reload) {
reload_def(ctx, src->def, instr, instr->block);
reload_def(ctx, src->def, cursor);
}
ra_spill_interval_root(interval)->cant_spill = false;
@ -1074,13 +1054,13 @@ handle_instr(struct ra_spill_ctx *ctx, struct ir3_instruction *instr)
}
if (ctx->spilling)
limit(ctx, instr);
limit(ctx, ir3_before_instr(instr));
else
update_max_pressure(ctx);
if (ctx->spilling) {
ra_foreach_src (src, instr) {
reload_src(ctx, instr, src);
reload_src(ctx, ir3_before_instr(instr), src);
update_src_next_use(ctx, src);
}
}
@ -1095,7 +1075,7 @@ handle_instr(struct ra_spill_ctx *ctx, struct ir3_instruction *instr)
}
if (ctx->spilling)
limit(ctx, instr);
limit(ctx, ir3_before_instr(instr));
else
update_max_pressure(ctx);
@ -1234,7 +1214,7 @@ handle_pcopy(struct ra_spill_ctx *ctx, struct ir3_instruction *pcopy)
ra_spill_ctx_remove(ctx, src_interval);
dst_interval->cant_spill = true;
ra_spill_ctx_insert(ctx, dst_interval);
limit(ctx, pcopy);
limit(ctx, ir3_before_instr(pcopy));
dst_interval->cant_spill = false;
dst_interval->dst = src_interval->dst;
}
@ -1245,8 +1225,8 @@ handle_pcopy(struct ra_spill_ctx *ctx, struct ir3_instruction *pcopy)
temp_interval->next_use_distance = src->next_use;
insert_src(ctx, src);
limit(ctx, pcopy);
reload_src(ctx, pcopy, src);
limit(ctx, ir3_before_instr(pcopy));
reload_src(ctx, ir3_before_instr(pcopy), src);
update_src_next_use(ctx, src);
if (is_last_pcopy_src(pcopy, i))
remove_src(ctx, pcopy, src);
@ -1256,7 +1236,7 @@ handle_pcopy(struct ra_spill_ctx *ctx, struct ir3_instruction *pcopy)
temp_interval->cant_spill = true;
ra_spill_ctx_insert(ctx, temp_interval);
limit(ctx, pcopy);
limit(ctx, ir3_before_instr(pcopy));
temp_interval->cant_spill = false;
src->flags = temp->flags;
@ -1281,7 +1261,7 @@ handle_pcopy(struct ra_spill_ctx *ctx, struct ir3_instruction *pcopy)
if (!(src->flags & IR3_REG_SSA)) {
dst_interval->cant_spill = true;
ra_spill_ctx_insert(ctx, dst_interval);
limit(ctx, pcopy);
limit(ctx, ir3_before_instr(pcopy));
dst_interval->cant_spill = false;
assert(src->flags & (IR3_REG_CONST | IR3_REG_IMMED));
@ -1296,8 +1276,8 @@ handle_pcopy(struct ra_spill_ctx *ctx, struct ir3_instruction *pcopy)
struct ra_spill_interval *temp_interval = ctx->intervals[src->def->name];
insert_src(ctx, src);
limit(ctx, pcopy);
reload_src(ctx, pcopy, src);
limit(ctx, ir3_before_instr(pcopy));
reload_src(ctx, ir3_before_instr(pcopy), src);
remove_src(ctx, pcopy, src);
dst_interval->dst = temp_interval->dst;
@ -1425,7 +1405,8 @@ spill_live_in(struct ra_spill_ctx *ctx, struct ir3_register *def,
struct reg_or_immed *pred_def = read_live_in(ctx, def, block, i);
if (pred_def) {
spill(ctx, pred_def, get_spill_slot(ctx, def), NULL, pred);
spill(ctx, pred_def, get_spill_slot(ctx, def),
ir3_before_terminator(pred));
}
}
}
@ -1504,7 +1485,7 @@ live_in_rewrite(struct ra_spill_ctx *ctx,
extract(new_val->def,
(child->interval.reg->interval_start - def->interval_start) /
reg_elem_size(def), reg_elems(child->interval.reg),
NULL, pred);
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;
@ -1531,9 +1512,9 @@ reload_live_in(struct ra_spill_ctx *ctx, struct ir3_register *def,
if (!new_val) {
new_val = ralloc(ctx, struct reg_or_immed);
if (interval->can_rematerialize)
new_val->def = rematerialize(def, NULL, pred);
new_val->def = rematerialize(def, ir3_before_terminator(pred));
else
new_val->def = reload(ctx, def, NULL, pred);
new_val->def = reload(ctx, def, ir3_before_terminator(pred));
new_val->flags = new_val->def->flags;
}
live_in_rewrite(ctx, interval, new_val, block, i);
@ -1587,8 +1568,8 @@ add_live_in_phi(struct ra_spill_ctx *ctx, struct ir3_register *def,
return;
}
struct ir3_instruction *phi =
ir3_instr_create(block, OPC_META_PHI, 1, block->predecessors_count);
struct ir3_instruction *phi = ir3_instr_create_at(
ir3_before_block(block), OPC_META_PHI, 1, block->predecessors_count);
struct ir3_register *dst = __ssa_dst(phi);
dst->flags |= def->flags & (IR3_REG_HALF | IR3_REG_ARRAY);
dst->size = def->size;
@ -1619,8 +1600,6 @@ add_live_in_phi(struct ra_spill_ctx *ctx, struct ir3_register *def,
interval->dst.def = dst;
interval->dst.flags = dst->flags;
ir3_instr_move_before_block(phi, block);
}
/* When spilling a block with a single predecessors, the pred may have other
@ -1684,8 +1663,10 @@ spill_live_out(struct ra_spill_ctx *ctx, struct ra_spill_interval *interval,
struct ir3_register *def = interval->interval.reg;
if (interval->interval.reg->merge_set ||
!interval->can_rematerialize)
spill(ctx, &interval->dst, get_spill_slot(ctx, def), NULL, block);
!interval->can_rematerialize) {
spill(ctx, &interval->dst, get_spill_slot(ctx, def),
ir3_before_terminator(block));
}
ir3_reg_interval_remove_all(&ctx->reg_ctx, &interval->interval);
}
@ -1708,7 +1689,7 @@ reload_live_out(struct ra_spill_ctx *ctx, struct ir3_register *def,
struct ra_spill_interval *interval = ctx->intervals[def->name];
ir3_reg_interval_insert(&ctx->reg_ctx, &interval->interval);
reload_def(ctx, def, NULL, block);
reload_def(ctx, def, ir3_before_terminator(block));
}
static void