mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-08 06:58:05 +02:00
lima: ppir: fix regalloc bugs
Currently regalloc doesn't mark write destinations in the single instructions as conflicting, as a result regalloc may assign the same register to a multiple write destinations. Before we started scheduling multiple root nodes into a single instruction it was pretty much hidden. Fix it by marking destination registers as conflicting if instruction has multiple writes. Also stop handling a special case for output registers in regalloc and just mark them as live in the last instruction of "stop" block(s) Reviewed-by: Erico Nunes <nunes.erico@gmail.com> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33636>
This commit is contained in:
parent
c58655b999
commit
8905ee3a03
2 changed files with 47 additions and 11 deletions
|
|
@ -123,6 +123,7 @@ ppir_liveness_instr_srcs(ppir_compiler *comp, ppir_instr *instr)
|
|||
static void
|
||||
ppir_liveness_instr_dest(ppir_compiler *comp, ppir_instr *instr, ppir_instr *last)
|
||||
{
|
||||
int dest_count = 0;
|
||||
for (int i = PPIR_INSTR_SLOT_NUM-1; i >= 0; i--) {
|
||||
ppir_node *node = instr->slots[i];
|
||||
if (!node)
|
||||
|
|
@ -143,21 +144,14 @@ ppir_liveness_instr_dest(ppir_compiler *comp, ppir_instr *instr, ppir_instr *las
|
|||
if (!reg || reg->undef)
|
||||
continue;
|
||||
|
||||
dest_count++;
|
||||
unsigned int index = reg->regalloc_index;
|
||||
bool live = BITSET_TEST(instr->live_set, index);
|
||||
|
||||
/* If it's an out reg, it's alive till the end of the block, so add it
|
||||
* to live_set of the last instruction */
|
||||
if (!live && reg->out_reg && (instr != last)) {
|
||||
BITSET_SET(last->live_set, index);
|
||||
BITSET_CLEAR(instr->live_set, index);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If a register is written but wasn't read in a later instruction, it is
|
||||
* either an output register in last instruction, dead code or a bug.
|
||||
* For now, assign an interference to it to ensure it doesn't get assigned
|
||||
* a live register and overwrites it. */
|
||||
* likely consumed in the current instruction, dead code (which should have
|
||||
* been eliminated by DCE pass) or a bug. Assign an interference to it to
|
||||
* ensure it doesn't get assigned a live register and overwrites it. */
|
||||
if (!live) {
|
||||
BITSET_SET(instr->live_internal, index);
|
||||
continue;
|
||||
|
|
@ -182,6 +176,35 @@ ppir_liveness_instr_dest(ppir_compiler *comp, ppir_instr *instr, ppir_instr *las
|
|||
}
|
||||
}
|
||||
}
|
||||
if (dest_count < 2)
|
||||
return;
|
||||
|
||||
/* If we have more than one write, mark all write dests as conflicting,
|
||||
* otherwise regalloc may assign the same register to them
|
||||
*/
|
||||
for (int i = PPIR_INSTR_SLOT_NUM-1; i >= 0; i--) {
|
||||
ppir_node *node = instr->slots[i];
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
switch(node->op) {
|
||||
case ppir_op_const:
|
||||
case ppir_op_undef:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ppir_dest *dest = ppir_node_get_dest(node);
|
||||
if (!dest || dest->type == ppir_target_pipeline)
|
||||
continue;
|
||||
ppir_reg *reg = ppir_dest_get_reg(dest);
|
||||
if (!reg || reg->undef)
|
||||
continue;
|
||||
|
||||
unsigned int index = reg->regalloc_index;
|
||||
BITSET_SET(instr->live_internal, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* Main loop, iterate blocks/instructions/ops backwards, propagate
|
||||
|
|
|
|||
|
|
@ -500,6 +500,8 @@ static void ppir_regalloc_reset_liveness_info(ppir_compiler *comp)
|
|||
}
|
||||
|
||||
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
|
||||
if (list_is_empty(&block->instr_list))
|
||||
continue;
|
||||
list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
|
||||
|
||||
if (instr->live_mask)
|
||||
|
|
@ -515,6 +517,17 @@ static void ppir_regalloc_reset_liveness_info(ppir_compiler *comp)
|
|||
ralloc_free(instr->live_internal);
|
||||
instr->live_internal = rzalloc_array(comp, BITSET_WORD, comp->reg_num);
|
||||
}
|
||||
|
||||
/* Mark out regs as live for the last instruction of stop block */
|
||||
if (block->stop) {
|
||||
ppir_instr *last = list_last_entry(&block->instr_list, ppir_instr, list);
|
||||
list_for_each_entry(ppir_reg, reg, &comp->reg_list, list) {
|
||||
if (reg->out_reg) {
|
||||
BITSET_SET(last->live_set, reg->regalloc_index);
|
||||
set_reg_mask(last->live_mask, reg->regalloc_index, 0xf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue