pan/bi: Preserve SSA form from NIR
authorAlyssa Rosenzweig <alyssa@collabora.com>
Wed, 18 May 2022 15:24:32 +0000 (11:24 -0400)
committerMarge Bot <emma+marge@anholt.net>
Fri, 2 Sep 2022 16:03:23 +0000 (16:03 +0000)
Don't call nir_convert_from_ssa, preserve the SSA from NIR. This gets us real
SSA for all frontend passes. The RA becomes a black box that takes SSA in and
outputs register allocated code out. The "broken" SSA form never escapes RA,
which means we can clean up special cases in the rest of the compiler. It also
gets us ready for exploiting SSA form in the RA itself.

Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17794>

src/panfrost/bifrost/bi_opt_dce.c
src/panfrost/bifrost/bi_pressure_schedule.c
src/panfrost/bifrost/bi_validate.c
src/panfrost/bifrost/bifrost_compile.c

index 84ea988..aa20f14 100644 (file)
 #include "compiler.h"
 #include "util/u_memory.h"
 
-/* A simple liveness-based dead code elimination pass. */
+/* A simple SSA-based mark-and-sweep dead code elimination pass. */
 
 void
 bi_opt_dead_code_eliminate(bi_context *ctx)
 {
-        unsigned temp_count = bi_max_temp(ctx);
+        /* Mark live values */
+        BITSET_WORD *mark = calloc(sizeof(BITSET_WORD), BITSET_WORDS(ctx->ssa_alloc));
 
-        bi_compute_liveness(ctx);
+        u_worklist worklist;
+        u_worklist_init(&worklist, ctx->num_blocks, NULL);
 
-        bi_foreach_block_rev(ctx, block) {
-                uint8_t *live = rzalloc_array(block, uint8_t, temp_count);
+        bi_foreach_block(ctx, block) {
+                bi_worklist_push_head(&worklist, block);
+        }
 
-                bi_foreach_successor(block, succ) {
-                        for (unsigned i = 0; i < temp_count; ++i)
-                                live[i] |= succ->live_in[i];
-                }
+        while(!u_worklist_is_empty(&worklist)) {
+                /* Pop in reverse order for backwards pass */
+                bi_block *blk = bi_worklist_pop_head(&worklist);
 
-                bi_foreach_instr_in_block_safe_rev(block, ins) {
-                        bool all_null = true;
+                bool progress = false;
 
-                        bi_foreach_dest(ins, d) {
-                                /* Destination required */
-                                if (ins->op == BI_OPCODE_AXCHG_I32 ||
-                                    ins->op == BI_OPCODE_ACMPXCHG_I32 ||
-                                    ins->op == BI_OPCODE_ATOM_RETURN_I32 ||
-                                    ins->op == BI_OPCODE_ATOM1_RETURN_I32 ||
-                                    ins->op == BI_OPCODE_BLEND ||
-                                    ins->op == BI_OPCODE_ATEST ||
-                                    ins->op == BI_OPCODE_ZS_EMIT)
-                                        continue;
+                bi_foreach_instr_in_block_rev(blk, I) {
+                        bool needed = bi_side_effects(I);
+
+                        bi_foreach_dest(I, d)
+                                needed |= BITSET_TEST(mark, I->dest[d].value);
 
-                                unsigned index = bi_get_node(ins->dest[d]);
+                        if (!needed)
+                                continue;
 
-                                if (index >= temp_count)
-                                        all_null = false;
-                                else if (live[index] & bi_writemask(ins, d))
-                                        all_null = false;
+                        bi_foreach_src(I, s) {
+                                if (bi_is_ssa(I->src[s])) {
+                                        progress |= !BITSET_TEST(mark, I->src[s].value);
+                                        BITSET_SET(mark, I->src[s].value);
+                                }
                         }
+                }
 
-                        if (all_null && !bi_side_effects(ins))
-                                bi_remove_instruction(ins);
-                        else
-                                bi_liveness_ins_update(live, ins, temp_count);
+                /* XXX: slow */
+                if (progress) {
+                        bi_foreach_block(ctx, block)
+                                bi_worklist_push_head(&worklist, block);
                 }
+        }
+
+        u_worklist_fini(&worklist);
 
-                ralloc_free(block->live_in);
-                block->live_in = live;
+        /* Sweep */
+        bi_foreach_instr_global_safe(ctx, I) {
+                bool needed = bi_side_effects(I);
+
+                bi_foreach_dest(I, d)
+                        needed |= BITSET_TEST(mark, I->dest[d].value);
+
+                if (!needed)
+                        bi_remove_instruction(I);
         }
+
+        free(mark);
 }
 
 /* Post-RA liveness-based dead code analysis to clean up results of bundling */
index ff8a2ae..3735a39 100644 (file)
@@ -34,10 +34,7 @@ struct sched_ctx {
         struct dag *dag;
 
         /* Live set */
-        uint8_t *live;
-
-        /* Size of the live set */
-        unsigned max;
+        BITSET_WORD *live;
 };
 
 struct sched_node {
@@ -227,35 +224,33 @@ create_dag(bi_context *ctx, bi_block *block, void *memctx)
  *      live_in = (live_out - KILL) + GEN
  */
 static signed
-calculate_pressure_delta(bi_instr *I, uint8_t *live, unsigned max)
+calculate_pressure_delta(bi_instr *I, BITSET_WORD *live)
 {
         signed delta = 0;
 
         /* Destinations must be unique */
         bi_foreach_dest(I, d) {
-                unsigned node = bi_get_node(I->dest[d]);
-                assert(node < max);
+                assert(I->dest[d].type == BI_INDEX_NORMAL);
 
-                if (live[node])
+                if (BITSET_TEST(live, I->dest[d].value))
                         delta -= bi_count_write_registers(I, d);
         }
 
         bi_foreach_src(I, src) {
-                unsigned node = bi_get_node(I->src[src]);
-                if (node >= max)
+                if (I->src[src].type != BI_INDEX_NORMAL)
                         continue;
 
                 /* Filter duplicates */
                 bool dupe = false;
 
                 for (unsigned i = 0; i < src; ++i) {
-                        if (bi_get_node(I->src[i]) == node) {
+                        if (bi_is_equiv(I->src[i], I->src[src])) {
                                 dupe = true;
                                 break;
                         }
                 }
 
-                if (!dupe && !live[node])
+                if (!dupe && !BITSET_TEST(live, I->src[src].value))
                         delta += bi_count_read_registers(I, src);
         }
 
@@ -273,7 +268,7 @@ choose_instr(struct sched_ctx *s)
         struct sched_node *best = NULL;
 
         list_for_each_entry(struct sched_node, n, &s->dag->heads, dag.link) {
-                int32_t delta = calculate_pressure_delta(n->instr, s->live, s->max);
+                int32_t delta = calculate_pressure_delta(n->instr, s->live);
 
                 if (delta < min_delta) {
                         best = n;
@@ -292,16 +287,16 @@ pressure_schedule_block(bi_context *ctx, bi_block *block, struct sched_ctx *s)
         signed orig_max_pressure = 0;
         unsigned nr_ins = 0;
 
-        memcpy(s->live, block->live_out, s->max);
+        memcpy(s->live, block->ssa_live_out, BITSET_WORDS(ctx->ssa_alloc) * sizeof(BITSET_WORD));
 
         bi_foreach_instr_in_block_rev(block, I) {
-                pressure += calculate_pressure_delta(I, s->live, s->max);
+                pressure += calculate_pressure_delta(I, s->live);
                 orig_max_pressure = MAX2(pressure, orig_max_pressure);
-                bi_liveness_ins_update(s->live, I, s->max);
+                bi_liveness_ins_update_ssa(s->live, I);
                 nr_ins++;
         }
 
-        memcpy(s->live, block->live_out, s->max);
+        memcpy(s->live, block->ssa_live_out, BITSET_WORDS(ctx->ssa_alloc) * sizeof(BITSET_WORD));
 
         /* off by a constant, that's ok */
         signed max_pressure = 0;
@@ -312,12 +307,12 @@ pressure_schedule_block(bi_context *ctx, bi_block *block, struct sched_ctx *s)
 
         while (!list_is_empty(&s->dag->heads)) {
                 struct sched_node *node = choose_instr(s);
-                pressure += calculate_pressure_delta(node->instr, s->live, s->max);
+                pressure += calculate_pressure_delta(node->instr, s->live);
                 max_pressure = MAX2(pressure, max_pressure);
                 dag_prune_head(s->dag, &node->dag);
 
                 schedule[nr_ins++] = node;
-                bi_liveness_ins_update(s->live, node->instr, s->max);
+                bi_liveness_ins_update_ssa(s->live, node->instr);
         }
 
         /* Bail if it looks like it's worse */
@@ -338,15 +333,13 @@ pressure_schedule_block(bi_context *ctx, bi_block *block, struct sched_ctx *s)
 void
 bi_pressure_schedule(bi_context *ctx)
 {
-        bi_compute_liveness(ctx);
-        unsigned temp_count = bi_max_temp(ctx);
+        bi_compute_liveness_ssa(ctx);
         void *memctx = ralloc_context(ctx);
-        uint8_t *live = ralloc_array(memctx, uint8_t, temp_count);
+        BITSET_WORD *live = ralloc_array(memctx, BITSET_WORD, BITSET_WORDS(ctx->ssa_alloc));
 
         bi_foreach_block(ctx, block) {
                 struct sched_ctx sctx = {
                         .dag = create_dag(ctx, block, memctx),
-                        .max = temp_count,
                         .live = live
                 };
 
index 3a2c51d..7d10ff1 100644 (file)
@@ -39,15 +39,14 @@ bi_validate_initialization(bi_context *ctx)
 
         /* Calculate the live set */
         bi_block *entry = bi_entry_block(ctx);
-        unsigned temp_count = bi_max_temp(ctx);
-        bi_compute_liveness(ctx);
+        bi_compute_liveness_ssa(ctx);
 
         /* Validate that the live set is indeed empty */
-        for (unsigned i = 0; i < temp_count; ++i) {
-                if (entry->live_in[i] == 0) continue;
-
-                fprintf(stderr, "%s%u\n", (i & PAN_IS_REG) ? "r" : "", i >> 1);
-                success = false;
+        for (unsigned i = 0; i < ctx->ssa_alloc; ++i) {
+                if (BITSET_TEST(entry->ssa_live_in, i)) {
+                        fprintf(stderr, "%u\n", i);
+                        success = false;
+                }
         }
 
         return success;
index c9e8e90..fd35dd7 100644 (file)
@@ -5021,11 +5021,6 @@ bi_compile_variant_nir(nir_shader *nir,
                 }
         }
 
-        /* We can only go out-of-SSA after speciailizing IDVS, as opt_dead_cf
-         * doesn't know how to deal with nir_register.
-         */
-        NIR_PASS_V(nir, nir_convert_from_ssa, true);
-
         /* If nothing is pushed, all UBOs need to be uploaded */
         ctx->ubo_mask = ~0;