xref: /aosp_15_r20/external/mesa3d/src/panfrost/util/pan_liveness.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2019-2020 Collabora, Ltd.
3*61046927SAndroid Build Coastguard Worker  *
4*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker  *
11*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker  * Software.
14*61046927SAndroid Build Coastguard Worker  *
15*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*61046927SAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*61046927SAndroid Build Coastguard Worker  * SOFTWARE.
22*61046927SAndroid Build Coastguard Worker  */
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker #include "util/list.h"
25*61046927SAndroid Build Coastguard Worker #include "util/set.h"
26*61046927SAndroid Build Coastguard Worker #include "util/u_memory.h"
27*61046927SAndroid Build Coastguard Worker #include "pan_ir.h"
28*61046927SAndroid Build Coastguard Worker 
29*61046927SAndroid Build Coastguard Worker /* Routines for liveness analysis. Liveness is tracked per byte per node. Per
30*61046927SAndroid Build Coastguard Worker  * byte granularity is necessary for proper handling of int8 */
31*61046927SAndroid Build Coastguard Worker 
32*61046927SAndroid Build Coastguard Worker void
pan_liveness_gen(uint16_t * live,unsigned node,unsigned max,uint16_t mask)33*61046927SAndroid Build Coastguard Worker pan_liveness_gen(uint16_t *live, unsigned node, unsigned max, uint16_t mask)
34*61046927SAndroid Build Coastguard Worker {
35*61046927SAndroid Build Coastguard Worker    if (node >= max)
36*61046927SAndroid Build Coastguard Worker       return;
37*61046927SAndroid Build Coastguard Worker 
38*61046927SAndroid Build Coastguard Worker    live[node] |= mask;
39*61046927SAndroid Build Coastguard Worker }
40*61046927SAndroid Build Coastguard Worker 
41*61046927SAndroid Build Coastguard Worker void
pan_liveness_kill(uint16_t * live,unsigned node,unsigned max,uint16_t mask)42*61046927SAndroid Build Coastguard Worker pan_liveness_kill(uint16_t *live, unsigned node, unsigned max, uint16_t mask)
43*61046927SAndroid Build Coastguard Worker {
44*61046927SAndroid Build Coastguard Worker    if (node >= max)
45*61046927SAndroid Build Coastguard Worker       return;
46*61046927SAndroid Build Coastguard Worker 
47*61046927SAndroid Build Coastguard Worker    live[node] &= ~mask;
48*61046927SAndroid Build Coastguard Worker }
49*61046927SAndroid Build Coastguard Worker 
50*61046927SAndroid Build Coastguard Worker bool
pan_liveness_get(uint16_t * live,unsigned node,uint16_t max)51*61046927SAndroid Build Coastguard Worker pan_liveness_get(uint16_t *live, unsigned node, uint16_t max)
52*61046927SAndroid Build Coastguard Worker {
53*61046927SAndroid Build Coastguard Worker    if (node >= max)
54*61046927SAndroid Build Coastguard Worker       return false;
55*61046927SAndroid Build Coastguard Worker 
56*61046927SAndroid Build Coastguard Worker    return live[node];
57*61046927SAndroid Build Coastguard Worker }
58*61046927SAndroid Build Coastguard Worker 
59*61046927SAndroid Build Coastguard Worker /* live_out[s] = sum { p in succ[s] } ( live_in[p] ) */
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker static void
liveness_block_live_out(pan_block * blk,unsigned temp_count)62*61046927SAndroid Build Coastguard Worker liveness_block_live_out(pan_block *blk, unsigned temp_count)
63*61046927SAndroid Build Coastguard Worker {
64*61046927SAndroid Build Coastguard Worker    pan_foreach_successor(blk, succ) {
65*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < temp_count; ++i)
66*61046927SAndroid Build Coastguard Worker          blk->live_out[i] |= succ->live_in[i];
67*61046927SAndroid Build Coastguard Worker    }
68*61046927SAndroid Build Coastguard Worker }
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker /* Liveness analysis is a backwards-may dataflow analysis pass. Within a block,
71*61046927SAndroid Build Coastguard Worker  * we compute live_out from live_in. The intrablock pass is linear-time. It
72*61046927SAndroid Build Coastguard Worker  * returns whether progress was made. */
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker static bool
liveness_block_update(pan_block * blk,unsigned temp_count,pan_liveness_update callback)75*61046927SAndroid Build Coastguard Worker liveness_block_update(pan_block *blk, unsigned temp_count,
76*61046927SAndroid Build Coastguard Worker                       pan_liveness_update callback)
77*61046927SAndroid Build Coastguard Worker {
78*61046927SAndroid Build Coastguard Worker    bool progress = false;
79*61046927SAndroid Build Coastguard Worker 
80*61046927SAndroid Build Coastguard Worker    liveness_block_live_out(blk, temp_count);
81*61046927SAndroid Build Coastguard Worker 
82*61046927SAndroid Build Coastguard Worker    uint16_t *live = ralloc_array(blk, uint16_t, temp_count);
83*61046927SAndroid Build Coastguard Worker    memcpy(live, blk->live_out, temp_count * sizeof(uint16_t));
84*61046927SAndroid Build Coastguard Worker 
85*61046927SAndroid Build Coastguard Worker    pan_foreach_instr_in_block_rev(blk, ins)
86*61046927SAndroid Build Coastguard Worker       callback(live, (void *)ins, temp_count);
87*61046927SAndroid Build Coastguard Worker 
88*61046927SAndroid Build Coastguard Worker    /* To figure out progress, diff live_in */
89*61046927SAndroid Build Coastguard Worker 
90*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; (i < temp_count) && !progress; ++i)
91*61046927SAndroid Build Coastguard Worker       progress |= (blk->live_in[i] != live[i]);
92*61046927SAndroid Build Coastguard Worker 
93*61046927SAndroid Build Coastguard Worker    ralloc_free(blk->live_in);
94*61046927SAndroid Build Coastguard Worker    blk->live_in = live;
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker    return progress;
97*61046927SAndroid Build Coastguard Worker }
98*61046927SAndroid Build Coastguard Worker 
99*61046927SAndroid Build Coastguard Worker /* Globally, liveness analysis uses a fixed-point algorithm based on a
100*61046927SAndroid Build Coastguard Worker  * worklist. We initialize a work list with the exit block. We iterate the work
101*61046927SAndroid Build Coastguard Worker  * list to compute live_in from live_out for each block on the work list,
102*61046927SAndroid Build Coastguard Worker  * adding the predecessors of the block to the work list if we made progress.
103*61046927SAndroid Build Coastguard Worker  */
104*61046927SAndroid Build Coastguard Worker 
105*61046927SAndroid Build Coastguard Worker void
pan_compute_liveness(struct list_head * blocks,unsigned temp_count,pan_liveness_update callback)106*61046927SAndroid Build Coastguard Worker pan_compute_liveness(struct list_head *blocks, unsigned temp_count,
107*61046927SAndroid Build Coastguard Worker                      pan_liveness_update callback)
108*61046927SAndroid Build Coastguard Worker {
109*61046927SAndroid Build Coastguard Worker 
110*61046927SAndroid Build Coastguard Worker    /* Set of pan_block */
111*61046927SAndroid Build Coastguard Worker    struct set *work_list =
112*61046927SAndroid Build Coastguard Worker       _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal);
113*61046927SAndroid Build Coastguard Worker 
114*61046927SAndroid Build Coastguard Worker    struct set *visited =
115*61046927SAndroid Build Coastguard Worker       _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal);
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker    /* Free any previous liveness, and allocate */
118*61046927SAndroid Build Coastguard Worker 
119*61046927SAndroid Build Coastguard Worker    pan_free_liveness(blocks);
120*61046927SAndroid Build Coastguard Worker 
121*61046927SAndroid Build Coastguard Worker    list_for_each_entry(pan_block, block, blocks, link) {
122*61046927SAndroid Build Coastguard Worker       block->live_in = rzalloc_array(block, uint16_t, temp_count);
123*61046927SAndroid Build Coastguard Worker       block->live_out = rzalloc_array(block, uint16_t, temp_count);
124*61046927SAndroid Build Coastguard Worker    }
125*61046927SAndroid Build Coastguard Worker 
126*61046927SAndroid Build Coastguard Worker    /* Initialize the work list with the exit block */
127*61046927SAndroid Build Coastguard Worker    struct set_entry *cur;
128*61046927SAndroid Build Coastguard Worker 
129*61046927SAndroid Build Coastguard Worker    cur = _mesa_set_add(work_list, pan_exit_block(blocks));
130*61046927SAndroid Build Coastguard Worker 
131*61046927SAndroid Build Coastguard Worker    /* Iterate the work list */
132*61046927SAndroid Build Coastguard Worker 
133*61046927SAndroid Build Coastguard Worker    do {
134*61046927SAndroid Build Coastguard Worker       /* Pop off a block */
135*61046927SAndroid Build Coastguard Worker       pan_block *blk = (struct pan_block *)cur->key;
136*61046927SAndroid Build Coastguard Worker       _mesa_set_remove(work_list, cur);
137*61046927SAndroid Build Coastguard Worker 
138*61046927SAndroid Build Coastguard Worker       /* Update its liveness information */
139*61046927SAndroid Build Coastguard Worker       bool progress = liveness_block_update(blk, temp_count, callback);
140*61046927SAndroid Build Coastguard Worker 
141*61046927SAndroid Build Coastguard Worker       /* If we made progress, we need to process the predecessors */
142*61046927SAndroid Build Coastguard Worker 
143*61046927SAndroid Build Coastguard Worker       if (progress || !_mesa_set_search(visited, blk)) {
144*61046927SAndroid Build Coastguard Worker          pan_foreach_predecessor(blk, pred)
145*61046927SAndroid Build Coastguard Worker             _mesa_set_add(work_list, pred);
146*61046927SAndroid Build Coastguard Worker       }
147*61046927SAndroid Build Coastguard Worker 
148*61046927SAndroid Build Coastguard Worker       _mesa_set_add(visited, blk);
149*61046927SAndroid Build Coastguard Worker    } while ((cur = _mesa_set_next_entry(work_list, NULL)) != NULL);
150*61046927SAndroid Build Coastguard Worker 
151*61046927SAndroid Build Coastguard Worker    _mesa_set_destroy(visited, NULL);
152*61046927SAndroid Build Coastguard Worker    _mesa_set_destroy(work_list, NULL);
153*61046927SAndroid Build Coastguard Worker }
154*61046927SAndroid Build Coastguard Worker 
155*61046927SAndroid Build Coastguard Worker void
pan_free_liveness(struct list_head * blocks)156*61046927SAndroid Build Coastguard Worker pan_free_liveness(struct list_head *blocks)
157*61046927SAndroid Build Coastguard Worker {
158*61046927SAndroid Build Coastguard Worker    list_for_each_entry(pan_block, block, blocks, link) {
159*61046927SAndroid Build Coastguard Worker       if (block->live_in)
160*61046927SAndroid Build Coastguard Worker          ralloc_free(block->live_in);
161*61046927SAndroid Build Coastguard Worker 
162*61046927SAndroid Build Coastguard Worker       if (block->live_out)
163*61046927SAndroid Build Coastguard Worker          ralloc_free(block->live_out);
164*61046927SAndroid Build Coastguard Worker 
165*61046927SAndroid Build Coastguard Worker       block->live_in = NULL;
166*61046927SAndroid Build Coastguard Worker       block->live_out = NULL;
167*61046927SAndroid Build Coastguard Worker    }
168*61046927SAndroid Build Coastguard Worker }
169