mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-03 11:30:21 +01:00
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 <alyssa@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17794>
This commit is contained in:
parent
0a83748c54
commit
6c5ab777ee
2 changed files with 106 additions and 0 deletions
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Collabora, Ltd.
|
||||
* Copyright (C) 2018-2019 Alyssa Rosenzweig <alyssa@rosenzweig.io>
|
||||
* 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue