pan/bi: Implement bi_spill_register

Given a node to spill, insert the appropriate loads and stores to spill
it.

Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7206>
diff --git a/src/panfrost/bifrost/bi_ra.c b/src/panfrost/bifrost/bi_ra.c
index 072540c..82ecb3c 100644
--- a/src/panfrost/bifrost/bi_ra.c
+++ b/src/panfrost/bifrost/bi_ra.c
@@ -287,6 +287,60 @@
         return lcra_get_best_spill_node(l);
 }
 
+/* Once we've chosen a spill node, spill it. Precondition: node is a valid
+ * SSA node in the non-optimized scheduled IR that was not already
+ * spilled (enforced by bi_choose_spill_node). Returns bytes spilled */
+
+static unsigned
+bi_spill_register(bi_context *ctx, unsigned node, unsigned offset)
+{
+        assert(!(node & PAN_IS_REG));
+
+        unsigned channels = 1;
+
+        /* Spill after every store */
+        bi_foreach_block(ctx, _block) {
+                bi_block *block = (bi_block *) _block;
+                bi_foreach_clause_in_block_safe(block, clause) {
+                        bi_instruction *ins = bi_unwrap_singleton(clause);
+
+                        if (ins->dest != node) continue;
+
+                        ins->dest = bi_make_temp(ctx);
+                        ins->no_spill = true;
+                        channels = MAX2(channels, ins->vector_channels);
+
+                        bi_instruction st = bi_spill(ins->dest, offset, channels);
+                        bi_insert_singleton(ctx, clause, block, st, false);
+                        ctx->spills++;
+                }
+        }
+
+        /* Fill before every use */
+        bi_foreach_block(ctx, _block) {
+                bi_block *block = (bi_block *) _block;
+                bi_foreach_clause_in_block_safe(block, clause) {
+                        bi_instruction *ins = bi_unwrap_singleton(clause);
+                        if (!bi_has_arg(ins, node)) continue;
+
+                        /* Don't rewrite spills themselves */
+                        if (ins->segment == BI_SEGMENT_TLS) continue;
+
+                        unsigned index = bi_make_temp(ctx);
+
+                        bi_instruction ld = bi_fill(index, offset, channels);
+                        ld.no_spill = true;
+                        bi_insert_singleton(ctx, clause, block, ld, true);
+
+                        /* Rewrite to use */
+                        bi_rewrite_index_src_single(ins, node, index);
+                        ctx->fills++;
+                }
+        }
+
+        return (channels * 4);
+}
+
 void
 bi_register_allocate(bi_context *ctx)
 {