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