diff --git a/src/panfrost/bifrost/bi_opt_copy_prop.c b/src/panfrost/bifrost/bi_opt_copy_prop.c index 0ded862bc5a..901b58950dd 100644 --- a/src/panfrost/bifrost/bi_opt_copy_prop.c +++ b/src/panfrost/bifrost/bi_opt_copy_prop.c @@ -23,6 +23,7 @@ */ #include "compiler.h" +#include "bi_builder.h" /* A simple scalar-only SSA-based copy-propagation pass. TODO: vectors */ @@ -48,6 +49,43 @@ bi_reads_fau(bi_instr *ins) void bi_opt_copy_prop(bi_context *ctx) { + /* Chase SPLIT of COLLECT. Instruction selection usually avoids this + * pattern (due to the split cache), but it is inevitably generated by + * the UBO pushing pass. + */ + bi_instr **collects = calloc(sizeof(bi_instr *), ctx->ssa_alloc); + bi_foreach_instr_global_safe(ctx, I) { + if (I->op == BI_OPCODE_COLLECT_I32) { + /* Rewrite trivial collects while we're at it */ + if (I->nr_srcs == 1) + I->op = BI_OPCODE_MOV_I32; + + if (bi_is_ssa(I->dest[0])) + collects[I->dest[0].value] = I; + } else if (I->op == BI_OPCODE_SPLIT_I32) { + /* Rewrite trivial splits while we're at it */ + if (I->nr_dests == 1) + I->op = BI_OPCODE_MOV_I32; + + if (!bi_is_ssa(I->src[0])) + continue; + + bi_instr *collect = collects[I->src[0].value]; + if (!collect) + continue; + + /* Lower the split to moves, copyprop cleans up */ + bi_builder b = bi_init_builder(ctx, bi_before_instr(I)); + + for (unsigned d = 0; d < I->nr_dests; ++d) + bi_mov_i32_to(&b, I->dest[d], collect->src[d]); + + bi_remove_instruction(I); + } + } + + free(collects); + bi_index *replacement = calloc(sizeof(bi_index), ctx->ssa_alloc); bi_foreach_instr_global_safe(ctx, ins) {