xref: /aosp_15_r20/external/mesa3d/src/panfrost/compiler/bi_liveness.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (C) 2020 Collabora, Ltd.
3  * Copyright (C) 2018-2019 Alyssa Rosenzweig <[email protected]>
4  * Copyright © 2014 Intel Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "util/u_memory.h"
27 #include "compiler.h"
28 
29 void
bi_liveness_ins_update_ssa(BITSET_WORD * live,const bi_instr * I)30 bi_liveness_ins_update_ssa(BITSET_WORD *live, const bi_instr *I)
31 {
32    bi_foreach_dest(I, d)
33       BITSET_CLEAR(live, I->dest[d].value);
34 
35    bi_foreach_ssa_src(I, s)
36       BITSET_SET(live, I->src[s].value);
37 }
38 
39 void
bi_compute_liveness_ssa(bi_context * ctx)40 bi_compute_liveness_ssa(bi_context *ctx)
41 {
42    u_worklist worklist;
43    u_worklist_init(&worklist, ctx->num_blocks, NULL);
44 
45    /* Free any previous liveness, and allocate */
46    unsigned words = BITSET_WORDS(ctx->ssa_alloc);
47 
48    bi_foreach_block(ctx, block) {
49       if (block->ssa_live_in)
50          ralloc_free(block->ssa_live_in);
51 
52       if (block->ssa_live_out)
53          ralloc_free(block->ssa_live_out);
54 
55       block->ssa_live_in = rzalloc_array(block, BITSET_WORD, words);
56       block->ssa_live_out = rzalloc_array(block, BITSET_WORD, words);
57 
58       bi_worklist_push_head(&worklist, block);
59    }
60 
61    /* Iterate the work list */
62    while (!u_worklist_is_empty(&worklist)) {
63       /* Pop in reverse order since liveness is a backwards pass */
64       bi_block *blk = bi_worklist_pop_head(&worklist);
65 
66       /* Update its liveness information */
67       memcpy(blk->ssa_live_in, blk->ssa_live_out, words * sizeof(BITSET_WORD));
68 
69       bi_foreach_instr_in_block_rev(blk, I) {
70          /* Phi nodes are handled separately, so we skip them. As phi nodes are
71           * at the beginning and we're iterating backwards, we stop as soon as
72           * we hit a phi node.
73           */
74          if (I->op == BI_OPCODE_PHI)
75             break;
76 
77          bi_liveness_ins_update_ssa(blk->ssa_live_in, I);
78       }
79 
80       /* Propagate the live in of the successor (blk) to the live out of
81        * predecessors.
82        *
83        * Phi nodes are logically on the control flow edge and act in parallel.
84        * To handle when propagating, we kill writes from phis and make live the
85        * corresponding sources.
86        */
87       bi_foreach_predecessor(blk, pred) {
88          BITSET_WORD *live = ralloc_array(blk, BITSET_WORD, words);
89          memcpy(live, blk->ssa_live_in, words * sizeof(BITSET_WORD));
90 
91          /* Kill write */
92          bi_foreach_instr_in_block(blk, I) {
93             if (I->op != BI_OPCODE_PHI)
94                break;
95 
96             BITSET_CLEAR(live, I->dest[0].value);
97          }
98 
99          /* Make live the corresponding source */
100          bi_foreach_instr_in_block(blk, I) {
101             if (I->op != BI_OPCODE_PHI)
102                break;
103 
104             bi_index operand = I->src[bi_predecessor_index(blk, *pred)];
105             if (bi_is_ssa(operand))
106                BITSET_SET(live, operand.value);
107          }
108 
109          BITSET_WORD progress = 0;
110 
111          for (unsigned i = 0; i < words; ++i) {
112             progress |= live[i] & ~((*pred)->ssa_live_out[i]);
113             (*pred)->ssa_live_out[i] |= live[i];
114          }
115 
116          if (progress != 0)
117             bi_worklist_push_tail(&worklist, *pred);
118       }
119    }
120 
121    u_worklist_fini(&worklist);
122 }
123