xref: /aosp_15_r20/external/mesa3d/src/asahi/compiler/agx_liveness.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2021 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker  * Copyright 2019-2020 Collabora, Ltd.
4*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker  */
6*61046927SAndroid Build Coastguard Worker 
7*61046927SAndroid Build Coastguard Worker #include "util/list.h"
8*61046927SAndroid Build Coastguard Worker #include "util/set.h"
9*61046927SAndroid Build Coastguard Worker #include "util/u_memory.h"
10*61046927SAndroid Build Coastguard Worker #include "agx_compiler.h"
11*61046927SAndroid Build Coastguard Worker 
12*61046927SAndroid Build Coastguard Worker /* Liveness analysis is a backwards-may dataflow analysis pass. Within a block,
13*61046927SAndroid Build Coastguard Worker  * we compute live_out from live_in. The intrablock pass is linear-time. It
14*61046927SAndroid Build Coastguard Worker  * returns whether progress was made. */
15*61046927SAndroid Build Coastguard Worker 
16*61046927SAndroid Build Coastguard Worker /* live_in[s] = GEN[s] + (live_out[s] - KILL[s]) */
17*61046927SAndroid Build Coastguard Worker 
18*61046927SAndroid Build Coastguard Worker void
agx_liveness_ins_update(BITSET_WORD * live,agx_instr * I)19*61046927SAndroid Build Coastguard Worker agx_liveness_ins_update(BITSET_WORD *live, agx_instr *I)
20*61046927SAndroid Build Coastguard Worker {
21*61046927SAndroid Build Coastguard Worker    agx_foreach_ssa_dest(I, d)
22*61046927SAndroid Build Coastguard Worker       BITSET_CLEAR(live, I->dest[d].value);
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker    agx_foreach_ssa_src(I, s) {
25*61046927SAndroid Build Coastguard Worker       /* If the source is not live after this instruction, but becomes live
26*61046927SAndroid Build Coastguard Worker        * at this instruction, this is the use that kills the source
27*61046927SAndroid Build Coastguard Worker        */
28*61046927SAndroid Build Coastguard Worker       I->src[s].kill = !BITSET_TEST(live, I->src[s].value);
29*61046927SAndroid Build Coastguard Worker       BITSET_SET(live, I->src[s].value);
30*61046927SAndroid Build Coastguard Worker    }
31*61046927SAndroid Build Coastguard Worker }
32*61046927SAndroid Build Coastguard Worker 
33*61046927SAndroid Build Coastguard Worker /* Globally, liveness analysis uses a fixed-point algorithm based on a
34*61046927SAndroid Build Coastguard Worker  * worklist. We initialize a work list with the exit block. We iterate the work
35*61046927SAndroid Build Coastguard Worker  * list to compute live_in from live_out for each block on the work list,
36*61046927SAndroid Build Coastguard Worker  * adding the predecessors of the block to the work list if we made progress.
37*61046927SAndroid Build Coastguard Worker  */
38*61046927SAndroid Build Coastguard Worker 
39*61046927SAndroid Build Coastguard Worker void
agx_compute_liveness(agx_context * ctx)40*61046927SAndroid Build Coastguard Worker agx_compute_liveness(agx_context *ctx)
41*61046927SAndroid Build Coastguard Worker {
42*61046927SAndroid Build Coastguard Worker    u_worklist worklist;
43*61046927SAndroid Build Coastguard Worker    u_worklist_init(&worklist, ctx->num_blocks, NULL);
44*61046927SAndroid Build Coastguard Worker 
45*61046927SAndroid Build Coastguard Worker    /* Free any previous liveness, and allocate */
46*61046927SAndroid Build Coastguard Worker    unsigned words = BITSET_WORDS(ctx->alloc);
47*61046927SAndroid Build Coastguard Worker 
48*61046927SAndroid Build Coastguard Worker    agx_foreach_block(ctx, block) {
49*61046927SAndroid Build Coastguard Worker       if (block->live_in)
50*61046927SAndroid Build Coastguard Worker          ralloc_free(block->live_in);
51*61046927SAndroid Build Coastguard Worker 
52*61046927SAndroid Build Coastguard Worker       if (block->live_out)
53*61046927SAndroid Build Coastguard Worker          ralloc_free(block->live_out);
54*61046927SAndroid Build Coastguard Worker 
55*61046927SAndroid Build Coastguard Worker       block->live_in = rzalloc_array(block, BITSET_WORD, words);
56*61046927SAndroid Build Coastguard Worker       block->live_out = rzalloc_array(block, BITSET_WORD, words);
57*61046927SAndroid Build Coastguard Worker 
58*61046927SAndroid Build Coastguard Worker       agx_worklist_push_head(&worklist, block);
59*61046927SAndroid Build Coastguard Worker    }
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker    /* Iterate the work list */
62*61046927SAndroid Build Coastguard Worker    while (!u_worklist_is_empty(&worklist)) {
63*61046927SAndroid Build Coastguard Worker       /* Pop in reverse order since liveness is a backwards pass */
64*61046927SAndroid Build Coastguard Worker       agx_block *blk = agx_worklist_pop_head(&worklist);
65*61046927SAndroid Build Coastguard Worker 
66*61046927SAndroid Build Coastguard Worker       /* Update its liveness information */
67*61046927SAndroid Build Coastguard Worker       memcpy(blk->live_in, blk->live_out, words * sizeof(BITSET_WORD));
68*61046927SAndroid Build Coastguard Worker 
69*61046927SAndroid Build Coastguard Worker       agx_foreach_instr_in_block_rev(blk, I) {
70*61046927SAndroid Build Coastguard Worker          if (I->op != AGX_OPCODE_PHI)
71*61046927SAndroid Build Coastguard Worker             agx_liveness_ins_update(blk->live_in, I);
72*61046927SAndroid Build Coastguard Worker       }
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker       /* Propagate the live in of the successor (blk) to the live out of
75*61046927SAndroid Build Coastguard Worker        * predecessors.
76*61046927SAndroid Build Coastguard Worker        *
77*61046927SAndroid Build Coastguard Worker        * Phi nodes are logically on the control flow edge and act in parallel.
78*61046927SAndroid Build Coastguard Worker        * To handle when propagating, we kill writes from phis and make live the
79*61046927SAndroid Build Coastguard Worker        * corresponding sources.
80*61046927SAndroid Build Coastguard Worker        */
81*61046927SAndroid Build Coastguard Worker       agx_foreach_predecessor(blk, pred) {
82*61046927SAndroid Build Coastguard Worker          BITSET_WORD *live = ralloc_array(blk, BITSET_WORD, words);
83*61046927SAndroid Build Coastguard Worker          memcpy(live, blk->live_in, words * sizeof(BITSET_WORD));
84*61046927SAndroid Build Coastguard Worker 
85*61046927SAndroid Build Coastguard Worker          /* Kill write */
86*61046927SAndroid Build Coastguard Worker          agx_foreach_phi_in_block(blk, phi) {
87*61046927SAndroid Build Coastguard Worker             assert(phi->dest[0].type == AGX_INDEX_NORMAL);
88*61046927SAndroid Build Coastguard Worker             BITSET_CLEAR(live, phi->dest[0].value);
89*61046927SAndroid Build Coastguard Worker          }
90*61046927SAndroid Build Coastguard Worker 
91*61046927SAndroid Build Coastguard Worker          /* Make live the corresponding source */
92*61046927SAndroid Build Coastguard Worker          agx_foreach_phi_in_block(blk, phi) {
93*61046927SAndroid Build Coastguard Worker             agx_index operand = phi->src[agx_predecessor_index(blk, *pred)];
94*61046927SAndroid Build Coastguard Worker             if (operand.type == AGX_INDEX_NORMAL)
95*61046927SAndroid Build Coastguard Worker                BITSET_SET(live, operand.value);
96*61046927SAndroid Build Coastguard Worker          }
97*61046927SAndroid Build Coastguard Worker 
98*61046927SAndroid Build Coastguard Worker          bool progress = false;
99*61046927SAndroid Build Coastguard Worker 
100*61046927SAndroid Build Coastguard Worker          for (unsigned i = 0; i < words; ++i) {
101*61046927SAndroid Build Coastguard Worker             progress |= live[i] & ~((*pred)->live_out[i]);
102*61046927SAndroid Build Coastguard Worker             (*pred)->live_out[i] |= live[i];
103*61046927SAndroid Build Coastguard Worker          }
104*61046927SAndroid Build Coastguard Worker 
105*61046927SAndroid Build Coastguard Worker          if (progress)
106*61046927SAndroid Build Coastguard Worker             agx_worklist_push_tail(&worklist, *pred);
107*61046927SAndroid Build Coastguard Worker       }
108*61046927SAndroid Build Coastguard Worker    }
109*61046927SAndroid Build Coastguard Worker 
110*61046927SAndroid Build Coastguard Worker    u_worklist_fini(&worklist);
111*61046927SAndroid Build Coastguard Worker }
112