diff --git a/src/gallium/drivers/lima/ir/pp/liveness.c b/src/gallium/drivers/lima/ir/pp/liveness.c index 02faa423b87..74a1c9cc038 100644 --- a/src/gallium/drivers/lima/ir/pp/liveness.c +++ b/src/gallium/drivers/lima/ir/pp/liveness.c @@ -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 diff --git a/src/gallium/drivers/lima/ir/pp/regalloc.c b/src/gallium/drivers/lima/ir/pp/regalloc.c index e80d468313b..151f94c8666 100644 --- a/src/gallium/drivers/lima/ir/pp/regalloc.c +++ b/src/gallium/drivers/lima/ir/pp/regalloc.c @@ -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); + } + } + } } }