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