1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2021 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker * Copyright 2019-2020 Collabora, Ltd.
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include "util/list.h"
8*61046927SAndroid Build Coastguard Worker #include "util/set.h"
9*61046927SAndroid Build Coastguard Worker #include "util/u_memory.h"
10*61046927SAndroid Build Coastguard Worker #include "agx_compiler.h"
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker /* Liveness analysis is a backwards-may dataflow analysis pass. Within a block,
13*61046927SAndroid Build Coastguard Worker * we compute live_out from live_in. The intrablock pass is linear-time. It
14*61046927SAndroid Build Coastguard Worker * returns whether progress was made. */
15*61046927SAndroid Build Coastguard Worker
16*61046927SAndroid Build Coastguard Worker /* live_in[s] = GEN[s] + (live_out[s] - KILL[s]) */
17*61046927SAndroid Build Coastguard Worker
18*61046927SAndroid Build Coastguard Worker void
agx_liveness_ins_update(BITSET_WORD * live,agx_instr * I)19*61046927SAndroid Build Coastguard Worker agx_liveness_ins_update(BITSET_WORD *live, agx_instr *I)
20*61046927SAndroid Build Coastguard Worker {
21*61046927SAndroid Build Coastguard Worker agx_foreach_ssa_dest(I, d)
22*61046927SAndroid Build Coastguard Worker BITSET_CLEAR(live, I->dest[d].value);
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker agx_foreach_ssa_src(I, s) {
25*61046927SAndroid Build Coastguard Worker /* If the source is not live after this instruction, but becomes live
26*61046927SAndroid Build Coastguard Worker * at this instruction, this is the use that kills the source
27*61046927SAndroid Build Coastguard Worker */
28*61046927SAndroid Build Coastguard Worker I->src[s].kill = !BITSET_TEST(live, I->src[s].value);
29*61046927SAndroid Build Coastguard Worker BITSET_SET(live, I->src[s].value);
30*61046927SAndroid Build Coastguard Worker }
31*61046927SAndroid Build Coastguard Worker }
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker /* Globally, liveness analysis uses a fixed-point algorithm based on a
34*61046927SAndroid Build Coastguard Worker * worklist. We initialize a work list with the exit block. We iterate the work
35*61046927SAndroid Build Coastguard Worker * list to compute live_in from live_out for each block on the work list,
36*61046927SAndroid Build Coastguard Worker * adding the predecessors of the block to the work list if we made progress.
37*61046927SAndroid Build Coastguard Worker */
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker void
agx_compute_liveness(agx_context * ctx)40*61046927SAndroid Build Coastguard Worker agx_compute_liveness(agx_context *ctx)
41*61046927SAndroid Build Coastguard Worker {
42*61046927SAndroid Build Coastguard Worker u_worklist worklist;
43*61046927SAndroid Build Coastguard Worker u_worklist_init(&worklist, ctx->num_blocks, NULL);
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker /* Free any previous liveness, and allocate */
46*61046927SAndroid Build Coastguard Worker unsigned words = BITSET_WORDS(ctx->alloc);
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker agx_foreach_block(ctx, block) {
49*61046927SAndroid Build Coastguard Worker if (block->live_in)
50*61046927SAndroid Build Coastguard Worker ralloc_free(block->live_in);
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker if (block->live_out)
53*61046927SAndroid Build Coastguard Worker ralloc_free(block->live_out);
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker block->live_in = rzalloc_array(block, BITSET_WORD, words);
56*61046927SAndroid Build Coastguard Worker block->live_out = rzalloc_array(block, BITSET_WORD, words);
57*61046927SAndroid Build Coastguard Worker
58*61046927SAndroid Build Coastguard Worker agx_worklist_push_head(&worklist, block);
59*61046927SAndroid Build Coastguard Worker }
60*61046927SAndroid Build Coastguard Worker
61*61046927SAndroid Build Coastguard Worker /* Iterate the work list */
62*61046927SAndroid Build Coastguard Worker while (!u_worklist_is_empty(&worklist)) {
63*61046927SAndroid Build Coastguard Worker /* Pop in reverse order since liveness is a backwards pass */
64*61046927SAndroid Build Coastguard Worker agx_block *blk = agx_worklist_pop_head(&worklist);
65*61046927SAndroid Build Coastguard Worker
66*61046927SAndroid Build Coastguard Worker /* Update its liveness information */
67*61046927SAndroid Build Coastguard Worker memcpy(blk->live_in, blk->live_out, words * sizeof(BITSET_WORD));
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Worker agx_foreach_instr_in_block_rev(blk, I) {
70*61046927SAndroid Build Coastguard Worker if (I->op != AGX_OPCODE_PHI)
71*61046927SAndroid Build Coastguard Worker agx_liveness_ins_update(blk->live_in, I);
72*61046927SAndroid Build Coastguard Worker }
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker /* Propagate the live in of the successor (blk) to the live out of
75*61046927SAndroid Build Coastguard Worker * predecessors.
76*61046927SAndroid Build Coastguard Worker *
77*61046927SAndroid Build Coastguard Worker * Phi nodes are logically on the control flow edge and act in parallel.
78*61046927SAndroid Build Coastguard Worker * To handle when propagating, we kill writes from phis and make live the
79*61046927SAndroid Build Coastguard Worker * corresponding sources.
80*61046927SAndroid Build Coastguard Worker */
81*61046927SAndroid Build Coastguard Worker agx_foreach_predecessor(blk, pred) {
82*61046927SAndroid Build Coastguard Worker BITSET_WORD *live = ralloc_array(blk, BITSET_WORD, words);
83*61046927SAndroid Build Coastguard Worker memcpy(live, blk->live_in, words * sizeof(BITSET_WORD));
84*61046927SAndroid Build Coastguard Worker
85*61046927SAndroid Build Coastguard Worker /* Kill write */
86*61046927SAndroid Build Coastguard Worker agx_foreach_phi_in_block(blk, phi) {
87*61046927SAndroid Build Coastguard Worker assert(phi->dest[0].type == AGX_INDEX_NORMAL);
88*61046927SAndroid Build Coastguard Worker BITSET_CLEAR(live, phi->dest[0].value);
89*61046927SAndroid Build Coastguard Worker }
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker /* Make live the corresponding source */
92*61046927SAndroid Build Coastguard Worker agx_foreach_phi_in_block(blk, phi) {
93*61046927SAndroid Build Coastguard Worker agx_index operand = phi->src[agx_predecessor_index(blk, *pred)];
94*61046927SAndroid Build Coastguard Worker if (operand.type == AGX_INDEX_NORMAL)
95*61046927SAndroid Build Coastguard Worker BITSET_SET(live, operand.value);
96*61046927SAndroid Build Coastguard Worker }
97*61046927SAndroid Build Coastguard Worker
98*61046927SAndroid Build Coastguard Worker bool progress = false;
99*61046927SAndroid Build Coastguard Worker
100*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < words; ++i) {
101*61046927SAndroid Build Coastguard Worker progress |= live[i] & ~((*pred)->live_out[i]);
102*61046927SAndroid Build Coastguard Worker (*pred)->live_out[i] |= live[i];
103*61046927SAndroid Build Coastguard Worker }
104*61046927SAndroid Build Coastguard Worker
105*61046927SAndroid Build Coastguard Worker if (progress)
106*61046927SAndroid Build Coastguard Worker agx_worklist_push_tail(&worklist, *pred);
107*61046927SAndroid Build Coastguard Worker }
108*61046927SAndroid Build Coastguard Worker }
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker u_worklist_fini(&worklist);
111*61046927SAndroid Build Coastguard Worker }
112