xref: /aosp_15_r20/external/mesa3d/src/freedreno/ir3/ir3_liveness.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2021 Valve Corporation
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #include "ir3_ra.h"
7*61046927SAndroid Build Coastguard Worker #include "ir3_shader.h"
8*61046927SAndroid Build Coastguard Worker #include "util/ralloc.h"
9*61046927SAndroid Build Coastguard Worker 
10*61046927SAndroid Build Coastguard Worker /* A note on how phi node uses are handled:
11*61046927SAndroid Build Coastguard Worker  *
12*61046927SAndroid Build Coastguard Worker  * - Phi node sources are considered to happen after the end of the
13*61046927SAndroid Build Coastguard Worker  *   predecessor block, so the live_out for that block contains phi sources.
14*61046927SAndroid Build Coastguard Worker  * - On the other hand, phi destinations are considered to happen at the start
15*61046927SAndroid Build Coastguard Worker  *   of the block, so that live_in does *not* contain phi destinations. This
16*61046927SAndroid Build Coastguard Worker  *   is mainly because phi destinations and live-through values have to be
17*61046927SAndroid Build Coastguard Worker  *   treated very differently by RA at the beginning of a block.
18*61046927SAndroid Build Coastguard Worker  */
19*61046927SAndroid Build Coastguard Worker 
20*61046927SAndroid Build Coastguard Worker static bool
compute_block_liveness(struct ir3_liveness * live,struct ir3_block * block,BITSET_WORD * tmp_live,unsigned bitset_words,reg_filter_cb filter_src,reg_filter_cb filter_dst)21*61046927SAndroid Build Coastguard Worker compute_block_liveness(struct ir3_liveness *live, struct ir3_block *block,
22*61046927SAndroid Build Coastguard Worker                        BITSET_WORD *tmp_live, unsigned bitset_words,
23*61046927SAndroid Build Coastguard Worker                        reg_filter_cb filter_src, reg_filter_cb filter_dst)
24*61046927SAndroid Build Coastguard Worker {
25*61046927SAndroid Build Coastguard Worker    memcpy(tmp_live, live->live_out[block->index],
26*61046927SAndroid Build Coastguard Worker           bitset_words * sizeof(BITSET_WORD));
27*61046927SAndroid Build Coastguard Worker 
28*61046927SAndroid Build Coastguard Worker    /* Process instructions */
29*61046927SAndroid Build Coastguard Worker    foreach_instr_rev (instr, &block->instr_list) {
30*61046927SAndroid Build Coastguard Worker       foreach_dst_if (dst, instr, filter_dst) {
31*61046927SAndroid Build Coastguard Worker          if (BITSET_TEST(tmp_live, dst->name))
32*61046927SAndroid Build Coastguard Worker             dst->flags &= ~IR3_REG_UNUSED;
33*61046927SAndroid Build Coastguard Worker          else
34*61046927SAndroid Build Coastguard Worker             dst->flags |= IR3_REG_UNUSED;
35*61046927SAndroid Build Coastguard Worker          BITSET_CLEAR(tmp_live, dst->name);
36*61046927SAndroid Build Coastguard Worker       }
37*61046927SAndroid Build Coastguard Worker 
38*61046927SAndroid Build Coastguard Worker       /* Phi node uses occur after the predecessor block */
39*61046927SAndroid Build Coastguard Worker       if (instr->opc != OPC_META_PHI) {
40*61046927SAndroid Build Coastguard Worker          foreach_src_if (src, instr, filter_src) {
41*61046927SAndroid Build Coastguard Worker             if (BITSET_TEST(tmp_live, src->def->name))
42*61046927SAndroid Build Coastguard Worker                src->flags &= ~IR3_REG_KILL;
43*61046927SAndroid Build Coastguard Worker             else
44*61046927SAndroid Build Coastguard Worker                src->flags |= IR3_REG_KILL;
45*61046927SAndroid Build Coastguard Worker          }
46*61046927SAndroid Build Coastguard Worker 
47*61046927SAndroid Build Coastguard Worker          foreach_src_if (src, instr, filter_src) {
48*61046927SAndroid Build Coastguard Worker             if (BITSET_TEST(tmp_live, src->def->name))
49*61046927SAndroid Build Coastguard Worker                src->flags &= ~IR3_REG_FIRST_KILL;
50*61046927SAndroid Build Coastguard Worker             else
51*61046927SAndroid Build Coastguard Worker                src->flags |= IR3_REG_FIRST_KILL;
52*61046927SAndroid Build Coastguard Worker             assert(src->def->name != 0);
53*61046927SAndroid Build Coastguard Worker             BITSET_SET(tmp_live, src->def->name);
54*61046927SAndroid Build Coastguard Worker          }
55*61046927SAndroid Build Coastguard Worker       }
56*61046927SAndroid Build Coastguard Worker    }
57*61046927SAndroid Build Coastguard Worker 
58*61046927SAndroid Build Coastguard Worker    memcpy(live->live_in[block->index], tmp_live,
59*61046927SAndroid Build Coastguard Worker           bitset_words * sizeof(BITSET_WORD));
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker    bool progress = false;
62*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < block->predecessors_count; i++) {
63*61046927SAndroid Build Coastguard Worker       const struct ir3_block *pred = block->predecessors[i];
64*61046927SAndroid Build Coastguard Worker       for (unsigned j = 0; j < bitset_words; j++) {
65*61046927SAndroid Build Coastguard Worker          if (tmp_live[j] & ~live->live_out[pred->index][j])
66*61046927SAndroid Build Coastguard Worker             progress = true;
67*61046927SAndroid Build Coastguard Worker          live->live_out[pred->index][j] |= tmp_live[j];
68*61046927SAndroid Build Coastguard Worker       }
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker       /* Process phi sources. */
71*61046927SAndroid Build Coastguard Worker       foreach_instr (phi, &block->instr_list) {
72*61046927SAndroid Build Coastguard Worker          if (phi->opc != OPC_META_PHI)
73*61046927SAndroid Build Coastguard Worker             break;
74*61046927SAndroid Build Coastguard Worker          if (!phi->srcs[i]->def)
75*61046927SAndroid Build Coastguard Worker             continue;
76*61046927SAndroid Build Coastguard Worker          if (!filter_dst(phi->srcs[i]))
77*61046927SAndroid Build Coastguard Worker             continue;
78*61046927SAndroid Build Coastguard Worker          unsigned name = phi->srcs[i]->def->name;
79*61046927SAndroid Build Coastguard Worker          if (!BITSET_TEST(live->live_out[pred->index], name)) {
80*61046927SAndroid Build Coastguard Worker             progress = true;
81*61046927SAndroid Build Coastguard Worker             BITSET_SET(live->live_out[pred->index], name);
82*61046927SAndroid Build Coastguard Worker          }
83*61046927SAndroid Build Coastguard Worker       }
84*61046927SAndroid Build Coastguard Worker    }
85*61046927SAndroid Build Coastguard Worker 
86*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < block->physical_predecessors_count; i++) {
87*61046927SAndroid Build Coastguard Worker       const struct ir3_block *pred = block->physical_predecessors[i];
88*61046927SAndroid Build Coastguard Worker       unsigned name;
89*61046927SAndroid Build Coastguard Worker       BITSET_FOREACH_SET (name, tmp_live, live->definitions_count) {
90*61046927SAndroid Build Coastguard Worker          struct ir3_register *reg = live->definitions[name];
91*61046927SAndroid Build Coastguard Worker          if (!(reg->flags & IR3_REG_SHARED))
92*61046927SAndroid Build Coastguard Worker             continue;
93*61046927SAndroid Build Coastguard Worker          if (!BITSET_TEST(live->live_out[pred->index], name)) {
94*61046927SAndroid Build Coastguard Worker             progress = true;
95*61046927SAndroid Build Coastguard Worker             BITSET_SET(live->live_out[pred->index], name);
96*61046927SAndroid Build Coastguard Worker          }
97*61046927SAndroid Build Coastguard Worker       }
98*61046927SAndroid Build Coastguard Worker    }
99*61046927SAndroid Build Coastguard Worker 
100*61046927SAndroid Build Coastguard Worker    return progress;
101*61046927SAndroid Build Coastguard Worker }
102*61046927SAndroid Build Coastguard Worker 
103*61046927SAndroid Build Coastguard Worker struct ir3_liveness *
ir3_calc_liveness_for(void * mem_ctx,struct ir3 * ir,reg_filter_cb filter_src,reg_filter_cb filter_dst)104*61046927SAndroid Build Coastguard Worker ir3_calc_liveness_for(void *mem_ctx, struct ir3 *ir, reg_filter_cb filter_src,
105*61046927SAndroid Build Coastguard Worker                       reg_filter_cb filter_dst)
106*61046927SAndroid Build Coastguard Worker {
107*61046927SAndroid Build Coastguard Worker    struct ir3_liveness *live = rzalloc(mem_ctx, struct ir3_liveness);
108*61046927SAndroid Build Coastguard Worker 
109*61046927SAndroid Build Coastguard Worker    /* Reserve name 0 to mean "doesn't have a name yet" to make the debug
110*61046927SAndroid Build Coastguard Worker     * output nicer.
111*61046927SAndroid Build Coastguard Worker     */
112*61046927SAndroid Build Coastguard Worker    array_insert(live, live->definitions, NULL);
113*61046927SAndroid Build Coastguard Worker 
114*61046927SAndroid Build Coastguard Worker    /* Build definition <-> name mapping */
115*61046927SAndroid Build Coastguard Worker    unsigned block_count = 0;
116*61046927SAndroid Build Coastguard Worker    foreach_block (block, &ir->block_list) {
117*61046927SAndroid Build Coastguard Worker       block->index = block_count++;
118*61046927SAndroid Build Coastguard Worker       foreach_instr (instr, &block->instr_list) {
119*61046927SAndroid Build Coastguard Worker          foreach_dst_if (dst, instr, filter_dst) {
120*61046927SAndroid Build Coastguard Worker             dst->name = live->definitions_count;
121*61046927SAndroid Build Coastguard Worker             array_insert(live, live->definitions, dst);
122*61046927SAndroid Build Coastguard Worker          }
123*61046927SAndroid Build Coastguard Worker       }
124*61046927SAndroid Build Coastguard Worker    }
125*61046927SAndroid Build Coastguard Worker 
126*61046927SAndroid Build Coastguard Worker    live->block_count = block_count;
127*61046927SAndroid Build Coastguard Worker 
128*61046927SAndroid Build Coastguard Worker    unsigned bitset_words = BITSET_WORDS(live->definitions_count);
129*61046927SAndroid Build Coastguard Worker    BITSET_WORD *tmp_live = ralloc_array(live, BITSET_WORD, bitset_words);
130*61046927SAndroid Build Coastguard Worker    live->live_in = ralloc_array(live, BITSET_WORD *, block_count);
131*61046927SAndroid Build Coastguard Worker    live->live_out = ralloc_array(live, BITSET_WORD *, block_count);
132*61046927SAndroid Build Coastguard Worker    unsigned i = 0;
133*61046927SAndroid Build Coastguard Worker    foreach_block (block, &ir->block_list) {
134*61046927SAndroid Build Coastguard Worker       block->index = i++;
135*61046927SAndroid Build Coastguard Worker       live->live_in[block->index] =
136*61046927SAndroid Build Coastguard Worker          rzalloc_array(live, BITSET_WORD, bitset_words);
137*61046927SAndroid Build Coastguard Worker       live->live_out[block->index] =
138*61046927SAndroid Build Coastguard Worker          rzalloc_array(live, BITSET_WORD, bitset_words);
139*61046927SAndroid Build Coastguard Worker    }
140*61046927SAndroid Build Coastguard Worker 
141*61046927SAndroid Build Coastguard Worker    bool progress = true;
142*61046927SAndroid Build Coastguard Worker    while (progress) {
143*61046927SAndroid Build Coastguard Worker       progress = false;
144*61046927SAndroid Build Coastguard Worker       foreach_block_rev (block, &ir->block_list) {
145*61046927SAndroid Build Coastguard Worker          progress |= compute_block_liveness(live, block, tmp_live, bitset_words,
146*61046927SAndroid Build Coastguard Worker                                             filter_src, filter_dst);
147*61046927SAndroid Build Coastguard Worker       }
148*61046927SAndroid Build Coastguard Worker    }
149*61046927SAndroid Build Coastguard Worker 
150*61046927SAndroid Build Coastguard Worker    return live;
151*61046927SAndroid Build Coastguard Worker }
152*61046927SAndroid Build Coastguard Worker 
153*61046927SAndroid Build Coastguard Worker /* Return true if "def" is live after "instr". It's assumed that "def"
154*61046927SAndroid Build Coastguard Worker  * dominates "instr".
155*61046927SAndroid Build Coastguard Worker  */
156*61046927SAndroid Build Coastguard Worker bool
ir3_def_live_after(struct ir3_liveness * live,struct ir3_register * def,struct ir3_instruction * instr)157*61046927SAndroid Build Coastguard Worker ir3_def_live_after(struct ir3_liveness *live, struct ir3_register *def,
158*61046927SAndroid Build Coastguard Worker                    struct ir3_instruction *instr)
159*61046927SAndroid Build Coastguard Worker {
160*61046927SAndroid Build Coastguard Worker    /* If it's live out then it's definitely live at the instruction. */
161*61046927SAndroid Build Coastguard Worker    if (BITSET_TEST(live->live_out[instr->block->index], def->name))
162*61046927SAndroid Build Coastguard Worker       return true;
163*61046927SAndroid Build Coastguard Worker 
164*61046927SAndroid Build Coastguard Worker    /* If it's not live in and not defined in the same block then the live
165*61046927SAndroid Build Coastguard Worker     * range can't extend to the instruction.
166*61046927SAndroid Build Coastguard Worker     */
167*61046927SAndroid Build Coastguard Worker    if (def->instr->block != instr->block &&
168*61046927SAndroid Build Coastguard Worker        !BITSET_TEST(live->live_in[instr->block->index], def->name))
169*61046927SAndroid Build Coastguard Worker       return false;
170*61046927SAndroid Build Coastguard Worker 
171*61046927SAndroid Build Coastguard Worker    /* Ok, now comes the tricky case, where "def" is killed somewhere in
172*61046927SAndroid Build Coastguard Worker     * "instr"'s block and we have to check if it's before or after.
173*61046927SAndroid Build Coastguard Worker     */
174*61046927SAndroid Build Coastguard Worker    foreach_instr_rev (test_instr, &instr->block->instr_list) {
175*61046927SAndroid Build Coastguard Worker       if (test_instr == instr)
176*61046927SAndroid Build Coastguard Worker          break;
177*61046927SAndroid Build Coastguard Worker 
178*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < test_instr->srcs_count; i++) {
179*61046927SAndroid Build Coastguard Worker          if (test_instr->srcs[i]->def == def)
180*61046927SAndroid Build Coastguard Worker             return true;
181*61046927SAndroid Build Coastguard Worker       }
182*61046927SAndroid Build Coastguard Worker    }
183*61046927SAndroid Build Coastguard Worker 
184*61046927SAndroid Build Coastguard Worker    return false;
185*61046927SAndroid Build Coastguard Worker }
186