• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Alyssa Rosenzweig
3  * Copyright (C) 2019-2020 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include "agx_compiler.h"
26 #include "util/u_memory.h"
27 #include "util/list.h"
28 #include "util/set.h"
29 
30 /* Liveness analysis is a backwards-may dataflow analysis pass. Within a block,
31  * we compute live_out from live_in. The intrablock pass is linear-time. It
32  * returns whether progress was made. */
33 
34 /* live_in[s] = GEN[s] + (live_out[s] - KILL[s]) */
35 
36 void
agx_liveness_ins_update(BITSET_WORD * live,agx_instr * I)37 agx_liveness_ins_update(BITSET_WORD *live, agx_instr *I)
38 {
39    agx_foreach_dest(I, d) {
40       if (I->dest[d].type == AGX_INDEX_NORMAL)
41          BITSET_CLEAR(live, I->dest[d].value);
42    }
43 
44    agx_foreach_src(I, s) {
45       if (I->src[s].type == AGX_INDEX_NORMAL) {
46          /* If the source is not live after this instruction, but becomes live
47           * at this instruction, this is the use that kills the source */
48          I->src[s].kill = !BITSET_TEST(live, I->src[s].value);
49          BITSET_SET(live, I->src[s].value);
50       }
51    }
52 }
53 
54 /* Globally, liveness analysis uses a fixed-point algorithm based on a
55  * worklist. We initialize a work list with the exit block. We iterate the work
56  * list to compute live_in from live_out for each block on the work list,
57  * adding the predecessors of the block to the work list if we made progress.
58  */
59 
60 void
agx_compute_liveness(agx_context * ctx)61 agx_compute_liveness(agx_context *ctx)
62 {
63    u_worklist worklist;
64    u_worklist_init(&worklist, ctx->num_blocks, NULL);
65 
66    /* Free any previous liveness, and allocate */
67    unsigned words = BITSET_WORDS(ctx->alloc);
68 
69    agx_foreach_block(ctx, block) {
70       if (block->live_in)
71          ralloc_free(block->live_in);
72 
73       if (block->live_out)
74          ralloc_free(block->live_out);
75 
76       block->live_in = rzalloc_array(block, BITSET_WORD, words);
77       block->live_out = rzalloc_array(block, BITSET_WORD, words);
78 
79       agx_worklist_push_head(&worklist, block);
80    }
81 
82    /* Iterate the work list */
83    while(!u_worklist_is_empty(&worklist)) {
84       /* Pop in reverse order since liveness is a backwards pass */
85       agx_block *blk = agx_worklist_pop_head(&worklist);
86 
87       /* Update its liveness information */
88       memcpy(blk->live_in, blk->live_out, words * sizeof(BITSET_WORD));
89 
90       agx_foreach_instr_in_block_rev(blk, I) {
91          /* Phi nodes are handled separately, so we skip them. As phi nodes are at
92           * the beginning and we're iterating backwards, we stop as soon as we hit
93           * a phi node.
94           */
95          if (I->op == AGX_OPCODE_PHI)
96             break;
97 
98          agx_liveness_ins_update(blk->live_in, I);
99       }
100 
101       /* Propagate the live in of the successor (blk) to the live out of
102        * predecessors.
103        *
104        * Phi nodes are logically on the control flow edge and act in parallel. To
105        * handle when propagating, we kill writes from phis and make live the
106        * corresponding sources.
107        */
108       agx_foreach_predecessor(blk, pred) {
109          BITSET_WORD *live = ralloc_array(blk, BITSET_WORD, words);
110          memcpy(live, blk->live_in, words * sizeof(BITSET_WORD));
111 
112          /* Kill write */
113          agx_foreach_instr_in_block(blk, I) {
114             if (I->op != AGX_OPCODE_PHI) break;
115 
116             assert(I->dest[0].type == AGX_INDEX_NORMAL);
117             BITSET_CLEAR(live, I->dest[0].value);
118          }
119 
120          /* Make live the corresponding source */
121          agx_foreach_instr_in_block(blk, I) {
122             if (I->op != AGX_OPCODE_PHI) break;
123 
124             agx_index operand = I->src[agx_predecessor_index(blk, *pred)];
125             assert(operand.type == AGX_INDEX_NORMAL);
126             BITSET_SET(live, operand.value);
127          }
128 
129          bool progress = false;
130 
131          for (unsigned i = 0; i < words; ++i) {
132             progress |= live[i] & ~((*pred)->live_out[i]);
133             (*pred)->live_out[i] |= live[i];
134          }
135 
136          if (progress)
137             agx_worklist_push_tail(&worklist, *pred);
138       }
139    }
140 
141    u_worklist_fini(&worklist);
142 }
143