From: Alyssa Rosenzweig Date: Mon, 25 Jul 2022 15:25:24 +0000 (-0400) Subject: pan/bi: Add SSA-based liveness pass X-Git-Tag: upstream/22.3.5~3642 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6c5ab777eeaaeb2b535e7a67dd5976d3e342f136;p=platform%2Fupstream%2Fmesa.git pan/bi: Add SSA-based liveness pass Adapted from NIR's liveness analysis. This is different from our non-SSA liveness pass for a few reasons: 1. It must handle phi nodes. This implies significant changes to the worklist algorithm. 2. It only handles SSA. It doesn't need funny labelling schemes for handling nir_registers in parallel with SSA defs. 3. It is scalar-only. The vector liveness information isn't interesting when vectors are handled via COLLECT and SPLIT. This means it uses a bitset (uses 8x less memory to store livenss information, should be easier on the caches too). Eventually, this will become our only pre-RA liveness pass. For now, both passes are maintained in parallel: the SSA pass used before out-of-SSA, the non-SSA pass used after out-of-SSA and before RA, and the post-RA pass used after RA. Signed-off-by: Alyssa Rosenzweig Part-of: --- diff --git a/src/panfrost/bifrost/bi_liveness.c b/src/panfrost/bifrost/bi_liveness.c index 4d6c97a..5d237a7 100644 --- a/src/panfrost/bifrost/bi_liveness.c +++ b/src/panfrost/bifrost/bi_liveness.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2020 Collabora, Ltd. * Copyright (C) 2018-2019 Alyssa Rosenzweig + * Copyright © 2014 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -124,3 +125,101 @@ bi_compute_liveness(bi_context *ctx) u_worklist_fini(&worklist); } + +void +bi_liveness_ins_update_ssa(BITSET_WORD *live, const bi_instr *I) +{ + bi_foreach_dest(I, d) { + assert(I->dest[d].type == BI_INDEX_NORMAL); + BITSET_CLEAR(live, I->dest[d].value); + } + + bi_foreach_src(I, s) { + if (I->src[s].type == BI_INDEX_NORMAL) + BITSET_SET(live, I->src[s].value); + } +} + +void +bi_compute_liveness_ssa(bi_context *ctx) +{ + u_worklist worklist; + u_worklist_init(&worklist, ctx->num_blocks, NULL); + + /* Free any previous liveness, and allocate */ + unsigned words = BITSET_WORDS(ctx->ssa_alloc); + + bi_foreach_block(ctx, block) { + if (block->ssa_live_in) + ralloc_free(block->ssa_live_in); + + if (block->ssa_live_out) + ralloc_free(block->ssa_live_out); + + block->ssa_live_in = rzalloc_array(block, BITSET_WORD, words); + block->ssa_live_out = rzalloc_array(block, BITSET_WORD, words); + + bi_worklist_push_head(&worklist, block); + } + + /* Iterate the work list */ + while(!u_worklist_is_empty(&worklist)) { + /* Pop in reverse order since liveness is a backwards pass */ + bi_block *blk = bi_worklist_pop_head(&worklist); + + /* Update its liveness information */ + memcpy(blk->ssa_live_in, blk->ssa_live_out, words * sizeof(BITSET_WORD)); + + bi_foreach_instr_in_block_rev(blk, I) { + /* Phi nodes are handled separately, so we skip them. As phi nodes are + * at the beginning and we're iterating backwards, we stop as soon as + * we hit a phi node. + */ + if (I->op == BI_OPCODE_PHI) + break; + + bi_liveness_ins_update_ssa(blk->ssa_live_in, I); + } + + /* Propagate the live in of the successor (blk) to the live out of + * predecessors. + * + * Phi nodes are logically on the control flow edge and act in parallel. + * To handle when propagating, we kill writes from phis and make live the + * corresponding sources. + */ + bi_foreach_predecessor(blk, pred) { + BITSET_WORD *live = ralloc_array(blk, BITSET_WORD, words); + memcpy(live, blk->ssa_live_in, words * sizeof(BITSET_WORD)); + + /* Kill write */ + bi_foreach_instr_in_block(blk, I) { + if (I->op != BI_OPCODE_PHI) break; + + assert(I->dest[0].type == BI_INDEX_NORMAL); + BITSET_CLEAR(live, I->dest[0].value); + } + + /* Make live the corresponding source */ + bi_foreach_instr_in_block(blk, I) { + if (I->op != BI_OPCODE_PHI) break; + + bi_index operand = I->src[bi_predecessor_index(blk, *pred)]; + if (operand.type == BI_INDEX_NORMAL) + BITSET_SET(live, operand.value); + } + + BITSET_WORD progress = 0; + + for (unsigned i = 0; i < words; ++i) { + progress |= live[i] & ~((*pred)->ssa_live_out[i]); + (*pred)->ssa_live_out[i] |= live[i]; + } + + if (progress != 0) + bi_worklist_push_tail(&worklist, *pred); + } + } + + u_worklist_fini(&worklist); +} diff --git a/src/panfrost/bifrost/compiler.h b/src/panfrost/bifrost/compiler.h index 9ca858e..e4b5759 100644 --- a/src/panfrost/bifrost/compiler.h +++ b/src/panfrost/bifrost/compiler.h @@ -706,6 +706,10 @@ typedef struct bi_block { uint8_t *live_in; uint8_t *live_out; + /* Scalar liveness indexed by SSA index */ + BITSET_WORD *ssa_live_in; + BITSET_WORD *ssa_live_out; + /* If true, uses clauses; if false, uses instructions */ bool scheduled; struct list_head clauses; /* list of bi_clause */ @@ -1180,6 +1184,9 @@ bool bi_opt_constant_fold(bi_context *ctx); void bi_compute_liveness(bi_context *ctx); void bi_liveness_ins_update(uint8_t *live, bi_instr *ins, unsigned max); +void bi_compute_liveness_ssa(bi_context *ctx); +void bi_liveness_ins_update_ssa(BITSET_WORD *live, const bi_instr *ins); + void bi_postra_liveness(bi_context *ctx); uint64_t MUST_CHECK bi_postra_liveness_ins(uint64_t live, bi_instr *ins);