xref: /aosp_15_r20/external/mesa3d/src/asahi/compiler/agx_spill.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2023-2024 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker  * Copyright 2023-2024 Valve Corporation
4*61046927SAndroid Build Coastguard Worker  * Copyright 2022 Collabora Ltd.
5*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
6*61046927SAndroid Build Coastguard Worker  */
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker #include "util/bitset.h"
9*61046927SAndroid Build Coastguard Worker #include "util/hash_table.h"
10*61046927SAndroid Build Coastguard Worker #include "util/ralloc.h"
11*61046927SAndroid Build Coastguard Worker #include "util/u_dynarray.h"
12*61046927SAndroid Build Coastguard Worker #include "util/u_qsort.h"
13*61046927SAndroid Build Coastguard Worker #include "agx_builder.h"
14*61046927SAndroid Build Coastguard Worker #include "agx_compiler.h"
15*61046927SAndroid Build Coastguard Worker #include "agx_opcodes.h"
16*61046927SAndroid Build Coastguard Worker 
17*61046927SAndroid Build Coastguard Worker /*
18*61046927SAndroid Build Coastguard Worker  * An implementation of "Register Spilling and Live-Range Splitting for SSA-Form
19*61046927SAndroid Build Coastguard Worker  * Programs" by Braun and Hack.
20*61046927SAndroid Build Coastguard Worker  */
21*61046927SAndroid Build Coastguard Worker 
22*61046927SAndroid Build Coastguard Worker /*
23*61046927SAndroid Build Coastguard Worker  * Next-use distances are logically in ℤ ∪ {∞}. Modeled as saturating uint32 and
24*61046927SAndroid Build Coastguard Worker  * referred to as dist_t.
25*61046927SAndroid Build Coastguard Worker  *
26*61046927SAndroid Build Coastguard Worker  * next_uses represents a next-use map. This is a sparse data structure mapping
27*61046927SAndroid Build Coastguard Worker  * variable names to next-use dist_t's. Variables with no later use (infinite
28*61046927SAndroid Build Coastguard Worker  * next-use distance) are not stored explicitly, making the time/space
29*61046927SAndroid Build Coastguard Worker  * requirements O(live variables). This is important for performance and memory
30*61046927SAndroid Build Coastguard Worker  * usage on big shaders with many blocks.
31*61046927SAndroid Build Coastguard Worker  *
32*61046927SAndroid Build Coastguard Worker  * For now, next_uses is backed by a Mesa hash table, but it could be optimized
33*61046927SAndroid Build Coastguard Worker  * to something more specialized in the future.
34*61046927SAndroid Build Coastguard Worker  */
35*61046927SAndroid Build Coastguard Worker #define DIST_INFINITY (UINT32_MAX)
36*61046927SAndroid Build Coastguard Worker typedef uint32_t dist_t;
37*61046927SAndroid Build Coastguard Worker 
38*61046927SAndroid Build Coastguard Worker static dist_t
dist_sum(dist_t A,dist_t B)39*61046927SAndroid Build Coastguard Worker dist_sum(dist_t A, dist_t B)
40*61046927SAndroid Build Coastguard Worker {
41*61046927SAndroid Build Coastguard Worker    return (A + B < A) ? DIST_INFINITY : (A + B);
42*61046927SAndroid Build Coastguard Worker }
43*61046927SAndroid Build Coastguard Worker 
44*61046927SAndroid Build Coastguard Worker struct next_uses {
45*61046927SAndroid Build Coastguard Worker    struct hash_table_u64 *ht;
46*61046927SAndroid Build Coastguard Worker };
47*61046927SAndroid Build Coastguard Worker 
48*61046927SAndroid Build Coastguard Worker static void
init_next_uses(struct next_uses * nu,void * memctx)49*61046927SAndroid Build Coastguard Worker init_next_uses(struct next_uses *nu, void *memctx)
50*61046927SAndroid Build Coastguard Worker {
51*61046927SAndroid Build Coastguard Worker    nu->ht = _mesa_hash_table_u64_create(memctx);
52*61046927SAndroid Build Coastguard Worker }
53*61046927SAndroid Build Coastguard Worker 
54*61046927SAndroid Build Coastguard Worker static void
destroy_next_uses(struct next_uses * nu)55*61046927SAndroid Build Coastguard Worker destroy_next_uses(struct next_uses *nu)
56*61046927SAndroid Build Coastguard Worker {
57*61046927SAndroid Build Coastguard Worker    _mesa_hash_table_u64_destroy(nu->ht);
58*61046927SAndroid Build Coastguard Worker }
59*61046927SAndroid Build Coastguard Worker 
60*61046927SAndroid Build Coastguard Worker static void
clear_next_uses(struct next_uses * nu)61*61046927SAndroid Build Coastguard Worker clear_next_uses(struct next_uses *nu)
62*61046927SAndroid Build Coastguard Worker {
63*61046927SAndroid Build Coastguard Worker    _mesa_hash_table_u64_clear(nu->ht);
64*61046927SAndroid Build Coastguard Worker }
65*61046927SAndroid Build Coastguard Worker 
66*61046927SAndroid Build Coastguard Worker static void
copy_next_uses(struct next_uses * nu,const struct next_uses * from)67*61046927SAndroid Build Coastguard Worker copy_next_uses(struct next_uses *nu, const struct next_uses *from)
68*61046927SAndroid Build Coastguard Worker {
69*61046927SAndroid Build Coastguard Worker    clear_next_uses(nu);
70*61046927SAndroid Build Coastguard Worker 
71*61046927SAndroid Build Coastguard Worker    hash_table_u64_foreach(from->ht, use) {
72*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_u64_insert(nu->ht, use.key, use.data);
73*61046927SAndroid Build Coastguard Worker    }
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker 
76*61046927SAndroid Build Coastguard Worker static void
set_next_use(struct next_uses * nu,unsigned node,dist_t dist)77*61046927SAndroid Build Coastguard Worker set_next_use(struct next_uses *nu, unsigned node, dist_t dist)
78*61046927SAndroid Build Coastguard Worker {
79*61046927SAndroid Build Coastguard Worker    if (dist == DIST_INFINITY) {
80*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_u64_remove(nu->ht, node);
81*61046927SAndroid Build Coastguard Worker    } else {
82*61046927SAndroid Build Coastguard Worker       uintptr_t as_ptr = (uintptr_t)(dist + 1);
83*61046927SAndroid Build Coastguard Worker       assert(as_ptr != 0 && "non-NULL");
84*61046927SAndroid Build Coastguard Worker 
85*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_u64_insert(nu->ht, node, (void *)as_ptr);
86*61046927SAndroid Build Coastguard Worker    }
87*61046927SAndroid Build Coastguard Worker }
88*61046927SAndroid Build Coastguard Worker 
89*61046927SAndroid Build Coastguard Worker static dist_t
search_next_uses(const struct next_uses * nu,unsigned node)90*61046927SAndroid Build Coastguard Worker search_next_uses(const struct next_uses *nu, unsigned node)
91*61046927SAndroid Build Coastguard Worker {
92*61046927SAndroid Build Coastguard Worker    void *ent = _mesa_hash_table_u64_search(nu->ht, node);
93*61046927SAndroid Build Coastguard Worker    if (!ent)
94*61046927SAndroid Build Coastguard Worker       return DIST_INFINITY;
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker    uintptr_t raw = (uintptr_t)ent;
97*61046927SAndroid Build Coastguard Worker    return raw - 1;
98*61046927SAndroid Build Coastguard Worker }
99*61046927SAndroid Build Coastguard Worker 
100*61046927SAndroid Build Coastguard Worker #define foreach_next_use(nu, node, dist)                                       \
101*61046927SAndroid Build Coastguard Worker    hash_table_u64_foreach((nu)->ht, use_)                                      \
102*61046927SAndroid Build Coastguard Worker       for (uint32_t _terminator = 1, node = use_.key,                          \
103*61046927SAndroid Build Coastguard Worker                     UNUSED dist = ((uintptr_t)use_.data) - 1;                  \
104*61046927SAndroid Build Coastguard Worker            _terminator != 0; _terminator = 0)
105*61046927SAndroid Build Coastguard Worker 
106*61046927SAndroid Build Coastguard Worker /*
107*61046927SAndroid Build Coastguard Worker  * Calculate the minimum of two next-use sets. Values absent from one of the
108*61046927SAndroid Build Coastguard Worker  * underlying sets are infinity so do not contribute to the minimum, instead
109*61046927SAndroid Build Coastguard Worker  * acting like a set union.
110*61046927SAndroid Build Coastguard Worker  */
111*61046927SAndroid Build Coastguard Worker static bool
minimum_next_uses(struct next_uses * nu,const struct next_uses * from)112*61046927SAndroid Build Coastguard Worker minimum_next_uses(struct next_uses *nu, const struct next_uses *from)
113*61046927SAndroid Build Coastguard Worker {
114*61046927SAndroid Build Coastguard Worker    bool progress = false;
115*61046927SAndroid Build Coastguard Worker 
116*61046927SAndroid Build Coastguard Worker    foreach_next_use(from, node, from_dist) {
117*61046927SAndroid Build Coastguard Worker       dist_t nu_dist = search_next_uses(nu, node);
118*61046927SAndroid Build Coastguard Worker 
119*61046927SAndroid Build Coastguard Worker       if (from_dist < nu_dist) {
120*61046927SAndroid Build Coastguard Worker          set_next_use(nu, node, from_dist);
121*61046927SAndroid Build Coastguard Worker          progress = true;
122*61046927SAndroid Build Coastguard Worker       }
123*61046927SAndroid Build Coastguard Worker    }
124*61046927SAndroid Build Coastguard Worker 
125*61046927SAndroid Build Coastguard Worker    return progress;
126*61046927SAndroid Build Coastguard Worker }
127*61046927SAndroid Build Coastguard Worker 
128*61046927SAndroid Build Coastguard Worker static uint32_t
instr_cycles(const agx_instr * I)129*61046927SAndroid Build Coastguard Worker instr_cycles(const agx_instr *I)
130*61046927SAndroid Build Coastguard Worker {
131*61046927SAndroid Build Coastguard Worker    return 1;
132*61046927SAndroid Build Coastguard Worker }
133*61046927SAndroid Build Coastguard Worker 
134*61046927SAndroid Build Coastguard Worker struct spill_block {
135*61046927SAndroid Build Coastguard Worker    /* Set of values available in the register file at the end */
136*61046927SAndroid Build Coastguard Worker    unsigned W_exit[AGX_NUM_REGS];
137*61046927SAndroid Build Coastguard Worker    unsigned nW_exit;
138*61046927SAndroid Build Coastguard Worker 
139*61046927SAndroid Build Coastguard Worker    unsigned W_entry[AGX_NUM_REGS];
140*61046927SAndroid Build Coastguard Worker    unsigned nW_entry;
141*61046927SAndroid Build Coastguard Worker 
142*61046927SAndroid Build Coastguard Worker    /* Set of live-out spilled values at the end of the block */
143*61046927SAndroid Build Coastguard Worker    unsigned *S_exit;
144*61046927SAndroid Build Coastguard Worker    unsigned nS_exit;
145*61046927SAndroid Build Coastguard Worker 
146*61046927SAndroid Build Coastguard Worker    unsigned *S_entry;
147*61046927SAndroid Build Coastguard Worker    unsigned nS_entry;
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker    /* Estimate */
150*61046927SAndroid Build Coastguard Worker    uint32_t cycles;
151*61046927SAndroid Build Coastguard Worker 
152*61046927SAndroid Build Coastguard Worker    /* Next-use maps at the start/end of the block */
153*61046927SAndroid Build Coastguard Worker    struct next_uses next_use_in;
154*61046927SAndroid Build Coastguard Worker    struct next_uses next_use_out;
155*61046927SAndroid Build Coastguard Worker };
156*61046927SAndroid Build Coastguard Worker 
157*61046927SAndroid Build Coastguard Worker struct spill_ctx {
158*61046927SAndroid Build Coastguard Worker    void *memctx;
159*61046927SAndroid Build Coastguard Worker    agx_context *shader;
160*61046927SAndroid Build Coastguard Worker    agx_block *block;
161*61046927SAndroid Build Coastguard Worker 
162*61046927SAndroid Build Coastguard Worker    /* Set of values currently available in the register file */
163*61046927SAndroid Build Coastguard Worker    BITSET_WORD *W;
164*61046927SAndroid Build Coastguard Worker 
165*61046927SAndroid Build Coastguard Worker    /* |W| = Current register pressure */
166*61046927SAndroid Build Coastguard Worker    unsigned nW;
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker    /* Local IPs of next-use */
169*61046927SAndroid Build Coastguard Worker    dist_t *next_uses;
170*61046927SAndroid Build Coastguard Worker 
171*61046927SAndroid Build Coastguard Worker    /* Current local IP relative to the start of the block */
172*61046927SAndroid Build Coastguard Worker    uint32_t ip;
173*61046927SAndroid Build Coastguard Worker 
174*61046927SAndroid Build Coastguard Worker    /* Set of live values that have been spilled. Contrary to the paper, this
175*61046927SAndroid Build Coastguard Worker     * is not a subset of W: the definition in the paper is bogus.
176*61046927SAndroid Build Coastguard Worker     */
177*61046927SAndroid Build Coastguard Worker    BITSET_WORD *S;
178*61046927SAndroid Build Coastguard Worker 
179*61046927SAndroid Build Coastguard Worker    /* Widths of vectors */
180*61046927SAndroid Build Coastguard Worker    uint8_t *channels;
181*61046927SAndroid Build Coastguard Worker    enum agx_size *size;
182*61046927SAndroid Build Coastguard Worker 
183*61046927SAndroid Build Coastguard Worker    /* Mapping of rematerializable values to their definitions, or NULL for nodes
184*61046927SAndroid Build Coastguard Worker     * that are not materializable.
185*61046927SAndroid Build Coastguard Worker     */
186*61046927SAndroid Build Coastguard Worker    agx_instr **remat;
187*61046927SAndroid Build Coastguard Worker 
188*61046927SAndroid Build Coastguard Worker    /* Maximum register pressure allowed */
189*61046927SAndroid Build Coastguard Worker    unsigned k;
190*61046927SAndroid Build Coastguard Worker 
191*61046927SAndroid Build Coastguard Worker    /* Number of variables */
192*61046927SAndroid Build Coastguard Worker    unsigned n;
193*61046927SAndroid Build Coastguard Worker 
194*61046927SAndroid Build Coastguard Worker    /* Information on blocks indexed in source order */
195*61046927SAndroid Build Coastguard Worker    struct spill_block *blocks;
196*61046927SAndroid Build Coastguard Worker 
197*61046927SAndroid Build Coastguard Worker    /* Base memory index reserved for spilled indices */
198*61046927SAndroid Build Coastguard Worker    unsigned spill_base;
199*61046927SAndroid Build Coastguard Worker };
200*61046927SAndroid Build Coastguard Worker 
201*61046927SAndroid Build Coastguard Worker static inline struct spill_block *
spill_block(struct spill_ctx * ctx,agx_block * block)202*61046927SAndroid Build Coastguard Worker spill_block(struct spill_ctx *ctx, agx_block *block)
203*61046927SAndroid Build Coastguard Worker {
204*61046927SAndroid Build Coastguard Worker    return &ctx->blocks[block->index];
205*61046927SAndroid Build Coastguard Worker }
206*61046927SAndroid Build Coastguard Worker 
207*61046927SAndroid Build Coastguard Worker /* Calculate the register demand of a node. This is rounded up to a power-of-two
208*61046927SAndroid Build Coastguard Worker  * to match the equivalent calculations in RA.
209*61046927SAndroid Build Coastguard Worker  */
210*61046927SAndroid Build Coastguard Worker static unsigned
node_size(struct spill_ctx * ctx,unsigned node)211*61046927SAndroid Build Coastguard Worker node_size(struct spill_ctx *ctx, unsigned node)
212*61046927SAndroid Build Coastguard Worker {
213*61046927SAndroid Build Coastguard Worker    return util_next_power_of_two(ctx->channels[node]) *
214*61046927SAndroid Build Coastguard Worker           agx_size_align_16(ctx->size[node]);
215*61046927SAndroid Build Coastguard Worker }
216*61046927SAndroid Build Coastguard Worker 
217*61046927SAndroid Build Coastguard Worker /*
218*61046927SAndroid Build Coastguard Worker  * Map a control flow edge to a block. Assumes no critical edges.
219*61046927SAndroid Build Coastguard Worker  */
220*61046927SAndroid Build Coastguard Worker static agx_block *
agx_edge_to_block(agx_block * pred,agx_block * succ)221*61046927SAndroid Build Coastguard Worker agx_edge_to_block(agx_block *pred, agx_block *succ)
222*61046927SAndroid Build Coastguard Worker {
223*61046927SAndroid Build Coastguard Worker    /* End of predecessor is unique if there's a single successor */
224*61046927SAndroid Build Coastguard Worker    if (agx_num_successors(pred) == 1)
225*61046927SAndroid Build Coastguard Worker       return pred;
226*61046927SAndroid Build Coastguard Worker 
227*61046927SAndroid Build Coastguard Worker    /* The predecessor has multiple successors, meaning this is not the only
228*61046927SAndroid Build Coastguard Worker     * edge leaving the predecessor. Therefore, it is the only edge entering
229*61046927SAndroid Build Coastguard Worker     * the successor (otherwise the edge would be critical), so the start of
230*61046927SAndroid Build Coastguard Worker     * the successor is unique.
231*61046927SAndroid Build Coastguard Worker     */
232*61046927SAndroid Build Coastguard Worker    assert(agx_num_predecessors(succ) == 1 && "critical edge detected");
233*61046927SAndroid Build Coastguard Worker    return succ;
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker 
236*61046927SAndroid Build Coastguard Worker /*
237*61046927SAndroid Build Coastguard Worker  * Get a cursor to insert along a control flow edge: either at the start of the
238*61046927SAndroid Build Coastguard Worker  * successor or the end of the predecessor. This relies on the control flow
239*61046927SAndroid Build Coastguard Worker  * graph having no critical edges.
240*61046927SAndroid Build Coastguard Worker  */
241*61046927SAndroid Build Coastguard Worker static agx_cursor
agx_along_edge(agx_block * pred,agx_block * succ)242*61046927SAndroid Build Coastguard Worker agx_along_edge(agx_block *pred, agx_block *succ)
243*61046927SAndroid Build Coastguard Worker {
244*61046927SAndroid Build Coastguard Worker    agx_block *to = agx_edge_to_block(pred, succ);
245*61046927SAndroid Build Coastguard Worker 
246*61046927SAndroid Build Coastguard Worker    if (to == pred)
247*61046927SAndroid Build Coastguard Worker       return agx_after_block_logical(pred);
248*61046927SAndroid Build Coastguard Worker    else
249*61046927SAndroid Build Coastguard Worker       return agx_before_block(succ);
250*61046927SAndroid Build Coastguard Worker }
251*61046927SAndroid Build Coastguard Worker 
252*61046927SAndroid Build Coastguard Worker static inline agx_index
agx_index_as_mem(agx_index idx,unsigned mem_base)253*61046927SAndroid Build Coastguard Worker agx_index_as_mem(agx_index idx, unsigned mem_base)
254*61046927SAndroid Build Coastguard Worker {
255*61046927SAndroid Build Coastguard Worker    assert(idx.type == AGX_INDEX_NORMAL);
256*61046927SAndroid Build Coastguard Worker    assert(!idx.memory);
257*61046927SAndroid Build Coastguard Worker    idx.memory = true;
258*61046927SAndroid Build Coastguard Worker    idx.value = mem_base + idx.value;
259*61046927SAndroid Build Coastguard Worker    return idx;
260*61046927SAndroid Build Coastguard Worker }
261*61046927SAndroid Build Coastguard Worker 
262*61046927SAndroid Build Coastguard Worker static unsigned
chase_mem_index(agx_index ref,unsigned mem_base)263*61046927SAndroid Build Coastguard Worker chase_mem_index(agx_index ref, unsigned mem_base)
264*61046927SAndroid Build Coastguard Worker {
265*61046927SAndroid Build Coastguard Worker    assert(ref.type == AGX_INDEX_NORMAL);
266*61046927SAndroid Build Coastguard Worker    return ref.memory ? (ref.value - mem_base) : ref.value;
267*61046927SAndroid Build Coastguard Worker }
268*61046927SAndroid Build Coastguard Worker 
269*61046927SAndroid Build Coastguard Worker static agx_index
reconstruct_index(struct spill_ctx * ctx,unsigned node)270*61046927SAndroid Build Coastguard Worker reconstruct_index(struct spill_ctx *ctx, unsigned node)
271*61046927SAndroid Build Coastguard Worker {
272*61046927SAndroid Build Coastguard Worker    return agx_get_vec_index(node, ctx->size[node], ctx->channels[node]);
273*61046927SAndroid Build Coastguard Worker }
274*61046927SAndroid Build Coastguard Worker 
275*61046927SAndroid Build Coastguard Worker static bool
can_remat(agx_instr * I)276*61046927SAndroid Build Coastguard Worker can_remat(agx_instr *I)
277*61046927SAndroid Build Coastguard Worker {
278*61046927SAndroid Build Coastguard Worker    switch (I->op) {
279*61046927SAndroid Build Coastguard Worker    case AGX_OPCODE_MOV_IMM:
280*61046927SAndroid Build Coastguard Worker    case AGX_OPCODE_GET_SR:
281*61046927SAndroid Build Coastguard Worker       return true;
282*61046927SAndroid Build Coastguard Worker    default:
283*61046927SAndroid Build Coastguard Worker       return false;
284*61046927SAndroid Build Coastguard Worker    }
285*61046927SAndroid Build Coastguard Worker }
286*61046927SAndroid Build Coastguard Worker 
287*61046927SAndroid Build Coastguard Worker static agx_instr *
remat_to(agx_builder * b,agx_index dst,struct spill_ctx * ctx,unsigned node)288*61046927SAndroid Build Coastguard Worker remat_to(agx_builder *b, agx_index dst, struct spill_ctx *ctx, unsigned node)
289*61046927SAndroid Build Coastguard Worker {
290*61046927SAndroid Build Coastguard Worker    agx_instr *I = ctx->remat[node];
291*61046927SAndroid Build Coastguard Worker    assert(can_remat(I));
292*61046927SAndroid Build Coastguard Worker 
293*61046927SAndroid Build Coastguard Worker    switch (I->op) {
294*61046927SAndroid Build Coastguard Worker    case AGX_OPCODE_MOV_IMM:
295*61046927SAndroid Build Coastguard Worker       return agx_mov_imm_to(b, dst, I->imm);
296*61046927SAndroid Build Coastguard Worker    case AGX_OPCODE_GET_SR:
297*61046927SAndroid Build Coastguard Worker       return agx_get_sr_to(b, dst, I->sr);
298*61046927SAndroid Build Coastguard Worker    default:
299*61046927SAndroid Build Coastguard Worker       unreachable("invalid remat");
300*61046927SAndroid Build Coastguard Worker    }
301*61046927SAndroid Build Coastguard Worker }
302*61046927SAndroid Build Coastguard Worker 
303*61046927SAndroid Build Coastguard Worker static void
insert_spill(agx_builder * b,struct spill_ctx * ctx,unsigned node)304*61046927SAndroid Build Coastguard Worker insert_spill(agx_builder *b, struct spill_ctx *ctx, unsigned node)
305*61046927SAndroid Build Coastguard Worker {
306*61046927SAndroid Build Coastguard Worker    if (!ctx->remat[node]) {
307*61046927SAndroid Build Coastguard Worker       agx_index idx = reconstruct_index(ctx, node);
308*61046927SAndroid Build Coastguard Worker       agx_mov_to(b, agx_index_as_mem(idx, ctx->spill_base), idx);
309*61046927SAndroid Build Coastguard Worker    }
310*61046927SAndroid Build Coastguard Worker }
311*61046927SAndroid Build Coastguard Worker 
312*61046927SAndroid Build Coastguard Worker static void
insert_reload(struct spill_ctx * ctx,agx_block * block,agx_cursor cursor,unsigned node)313*61046927SAndroid Build Coastguard Worker insert_reload(struct spill_ctx *ctx, agx_block *block, agx_cursor cursor,
314*61046927SAndroid Build Coastguard Worker               unsigned node)
315*61046927SAndroid Build Coastguard Worker {
316*61046927SAndroid Build Coastguard Worker    agx_builder b = agx_init_builder(ctx->shader, cursor);
317*61046927SAndroid Build Coastguard Worker    agx_index idx = reconstruct_index(ctx, node);
318*61046927SAndroid Build Coastguard Worker 
319*61046927SAndroid Build Coastguard Worker    /* Reloading breaks SSA, but agx_repair_ssa will repair */
320*61046927SAndroid Build Coastguard Worker    if (ctx->remat[node]) {
321*61046927SAndroid Build Coastguard Worker       remat_to(&b, idx, ctx, node);
322*61046927SAndroid Build Coastguard Worker    } else {
323*61046927SAndroid Build Coastguard Worker       agx_mov_to(&b, idx, agx_index_as_mem(idx, ctx->spill_base));
324*61046927SAndroid Build Coastguard Worker    }
325*61046927SAndroid Build Coastguard Worker }
326*61046927SAndroid Build Coastguard Worker 
327*61046927SAndroid Build Coastguard Worker /* Insert into the register file */
328*61046927SAndroid Build Coastguard Worker static void
insert_W(struct spill_ctx * ctx,unsigned v)329*61046927SAndroid Build Coastguard Worker insert_W(struct spill_ctx *ctx, unsigned v)
330*61046927SAndroid Build Coastguard Worker {
331*61046927SAndroid Build Coastguard Worker    assert(v < ctx->n);
332*61046927SAndroid Build Coastguard Worker    assert(!BITSET_TEST(ctx->W, v));
333*61046927SAndroid Build Coastguard Worker 
334*61046927SAndroid Build Coastguard Worker    BITSET_SET(ctx->W, v);
335*61046927SAndroid Build Coastguard Worker    ctx->nW += node_size(ctx, v);
336*61046927SAndroid Build Coastguard Worker }
337*61046927SAndroid Build Coastguard Worker 
338*61046927SAndroid Build Coastguard Worker /* Remove from the register file */
339*61046927SAndroid Build Coastguard Worker static void
remove_W(struct spill_ctx * ctx,unsigned v)340*61046927SAndroid Build Coastguard Worker remove_W(struct spill_ctx *ctx, unsigned v)
341*61046927SAndroid Build Coastguard Worker {
342*61046927SAndroid Build Coastguard Worker    assert(v < ctx->n);
343*61046927SAndroid Build Coastguard Worker    assert(BITSET_TEST(ctx->W, v));
344*61046927SAndroid Build Coastguard Worker 
345*61046927SAndroid Build Coastguard Worker    BITSET_CLEAR(ctx->W, v);
346*61046927SAndroid Build Coastguard Worker    ctx->nW -= node_size(ctx, v);
347*61046927SAndroid Build Coastguard Worker }
348*61046927SAndroid Build Coastguard Worker 
349*61046927SAndroid Build Coastguard Worker static void
remove_W_if_present(struct spill_ctx * ctx,unsigned v)350*61046927SAndroid Build Coastguard Worker remove_W_if_present(struct spill_ctx *ctx, unsigned v)
351*61046927SAndroid Build Coastguard Worker {
352*61046927SAndroid Build Coastguard Worker    assert(v < ctx->n);
353*61046927SAndroid Build Coastguard Worker 
354*61046927SAndroid Build Coastguard Worker    if (BITSET_TEST(ctx->W, v))
355*61046927SAndroid Build Coastguard Worker       remove_W(ctx, v);
356*61046927SAndroid Build Coastguard Worker }
357*61046927SAndroid Build Coastguard Worker 
358*61046927SAndroid Build Coastguard Worker struct candidate {
359*61046927SAndroid Build Coastguard Worker    unsigned node;
360*61046927SAndroid Build Coastguard Worker    dist_t dist;
361*61046927SAndroid Build Coastguard Worker };
362*61046927SAndroid Build Coastguard Worker 
363*61046927SAndroid Build Coastguard Worker static int
cmp_dist(const void * left_,const void * right_,void * ctx_)364*61046927SAndroid Build Coastguard Worker cmp_dist(const void *left_, const void *right_, void *ctx_)
365*61046927SAndroid Build Coastguard Worker {
366*61046927SAndroid Build Coastguard Worker    struct spill_ctx *ctx = ctx_;
367*61046927SAndroid Build Coastguard Worker    const struct candidate *left = left_;
368*61046927SAndroid Build Coastguard Worker    const struct candidate *right = right_;
369*61046927SAndroid Build Coastguard Worker 
370*61046927SAndroid Build Coastguard Worker    /* We assume that rematerializing - even before every instruction - is
371*61046927SAndroid Build Coastguard Worker     * cheaper than spilling. As long as one of the nodes is rematerializable
372*61046927SAndroid Build Coastguard Worker     * (with distance > 0), we choose it over spilling. Within a class of nodes
373*61046927SAndroid Build Coastguard Worker     * (rematerializable or not), compare by next-use-distance.
374*61046927SAndroid Build Coastguard Worker     */
375*61046927SAndroid Build Coastguard Worker    bool remat_left = ctx->remat[left->node] != NULL && left->dist > 0;
376*61046927SAndroid Build Coastguard Worker    bool remat_right = ctx->remat[right->node] != NULL && right->dist > 0;
377*61046927SAndroid Build Coastguard Worker 
378*61046927SAndroid Build Coastguard Worker    if (remat_left != remat_right)
379*61046927SAndroid Build Coastguard Worker       return remat_left ? 1 : -1;
380*61046927SAndroid Build Coastguard Worker    else
381*61046927SAndroid Build Coastguard Worker       return (left->dist > right->dist) - (left->dist < right->dist);
382*61046927SAndroid Build Coastguard Worker }
383*61046927SAndroid Build Coastguard Worker 
384*61046927SAndroid Build Coastguard Worker /*
385*61046927SAndroid Build Coastguard Worker  * Limit the register file W to maximum size m by evicting registers.
386*61046927SAndroid Build Coastguard Worker  */
387*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
limit(struct spill_ctx * ctx,agx_instr * I,unsigned m)388*61046927SAndroid Build Coastguard Worker limit(struct spill_ctx *ctx, agx_instr *I, unsigned m)
389*61046927SAndroid Build Coastguard Worker {
390*61046927SAndroid Build Coastguard Worker    /* Nothing to do if we're already below the limit */
391*61046927SAndroid Build Coastguard Worker    if (ctx->nW <= m)
392*61046927SAndroid Build Coastguard Worker       return;
393*61046927SAndroid Build Coastguard Worker 
394*61046927SAndroid Build Coastguard Worker    /* Gather candidates for eviction. Note that next_uses gives IPs whereas
395*61046927SAndroid Build Coastguard Worker     * cmp_dist expects relative distances. This requires us to subtract ctx->ip
396*61046927SAndroid Build Coastguard Worker     * to ensure that cmp_dist works properly. Even though logically it shouldn't
397*61046927SAndroid Build Coastguard Worker     * affect the sorted order, practically this matters for correctness with
398*61046927SAndroid Build Coastguard Worker     * rematerialization. See the dist=0 test in cmp_dist.
399*61046927SAndroid Build Coastguard Worker     */
400*61046927SAndroid Build Coastguard Worker    struct candidate *candidates = alloca(ctx->nW * sizeof(struct candidate));
401*61046927SAndroid Build Coastguard Worker    unsigned j = 0;
402*61046927SAndroid Build Coastguard Worker 
403*61046927SAndroid Build Coastguard Worker    int i;
404*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, ctx->W, ctx->n) {
405*61046927SAndroid Build Coastguard Worker       assert(j < ctx->nW);
406*61046927SAndroid Build Coastguard Worker 
407*61046927SAndroid Build Coastguard Worker       candidates[j++] = (struct candidate){
408*61046927SAndroid Build Coastguard Worker          .node = i,
409*61046927SAndroid Build Coastguard Worker          .dist = ctx->next_uses[i] - ctx->ip,
410*61046927SAndroid Build Coastguard Worker       };
411*61046927SAndroid Build Coastguard Worker    }
412*61046927SAndroid Build Coastguard Worker 
413*61046927SAndroid Build Coastguard Worker    /* Sort by next-use distance */
414*61046927SAndroid Build Coastguard Worker    util_qsort_r(candidates, j, sizeof(struct candidate), cmp_dist, ctx);
415*61046927SAndroid Build Coastguard Worker 
416*61046927SAndroid Build Coastguard Worker    /* Evict what doesn't fit */
417*61046927SAndroid Build Coastguard Worker    unsigned new_weight = 0;
418*61046927SAndroid Build Coastguard Worker 
419*61046927SAndroid Build Coastguard Worker    for (i = 0; i < j; ++i) {
420*61046927SAndroid Build Coastguard Worker       unsigned v = candidates[i].node;
421*61046927SAndroid Build Coastguard Worker       unsigned comps = node_size(ctx, v);
422*61046927SAndroid Build Coastguard Worker 
423*61046927SAndroid Build Coastguard Worker       if ((new_weight + comps) <= m) {
424*61046927SAndroid Build Coastguard Worker          new_weight += comps;
425*61046927SAndroid Build Coastguard Worker       } else {
426*61046927SAndroid Build Coastguard Worker          /* Insert a spill if we haven't spilled before and there is
427*61046927SAndroid Build Coastguard Worker           * another use
428*61046927SAndroid Build Coastguard Worker           */
429*61046927SAndroid Build Coastguard Worker          if (!BITSET_TEST(ctx->S, v) && candidates[i].dist < DIST_INFINITY) {
430*61046927SAndroid Build Coastguard Worker             agx_builder b = agx_init_builder(ctx->shader, agx_before_instr(I));
431*61046927SAndroid Build Coastguard Worker             insert_spill(&b, ctx, v);
432*61046927SAndroid Build Coastguard Worker             BITSET_SET(ctx->S, v);
433*61046927SAndroid Build Coastguard Worker          }
434*61046927SAndroid Build Coastguard Worker 
435*61046927SAndroid Build Coastguard Worker          remove_W(ctx, v);
436*61046927SAndroid Build Coastguard Worker 
437*61046927SAndroid Build Coastguard Worker          /* We keep going in case we can pack in a scalar */
438*61046927SAndroid Build Coastguard Worker       }
439*61046927SAndroid Build Coastguard Worker    }
440*61046927SAndroid Build Coastguard Worker }
441*61046927SAndroid Build Coastguard Worker 
442*61046927SAndroid Build Coastguard Worker /*
443*61046927SAndroid Build Coastguard Worker  * Insert coupling code on block boundaries. This must ensure:
444*61046927SAndroid Build Coastguard Worker  *
445*61046927SAndroid Build Coastguard Worker  *    - anything live-in we expect to have spilled is spilled
446*61046927SAndroid Build Coastguard Worker  *    - anything live-in we expect to have filled is filled
447*61046927SAndroid Build Coastguard Worker  *    - phi sources are spilled if the destination is spilled
448*61046927SAndroid Build Coastguard Worker  *    - phi sources are filled if the destination is not spilled
449*61046927SAndroid Build Coastguard Worker  *
450*61046927SAndroid Build Coastguard Worker  * The latter two requirements ensure correct pressure calculations for phis.
451*61046927SAndroid Build Coastguard Worker  */
452*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
insert_coupling_code(struct spill_ctx * ctx,agx_block * pred,agx_block * succ)453*61046927SAndroid Build Coastguard Worker insert_coupling_code(struct spill_ctx *ctx, agx_block *pred, agx_block *succ)
454*61046927SAndroid Build Coastguard Worker {
455*61046927SAndroid Build Coastguard Worker    struct spill_block *sp = spill_block(ctx, pred);
456*61046927SAndroid Build Coastguard Worker    struct spill_block *ss = spill_block(ctx, succ);
457*61046927SAndroid Build Coastguard Worker 
458*61046927SAndroid Build Coastguard Worker    agx_foreach_phi_in_block(succ, I) {
459*61046927SAndroid Build Coastguard Worker       if (!I->dest[0].memory)
460*61046927SAndroid Build Coastguard Worker          continue;
461*61046927SAndroid Build Coastguard Worker 
462*61046927SAndroid Build Coastguard Worker       agx_builder b =
463*61046927SAndroid Build Coastguard Worker          agx_init_builder(ctx->shader, agx_before_function(ctx->shader));
464*61046927SAndroid Build Coastguard Worker 
465*61046927SAndroid Build Coastguard Worker       unsigned s = agx_predecessor_index(succ, pred);
466*61046927SAndroid Build Coastguard Worker 
467*61046927SAndroid Build Coastguard Worker       /* Copy immediate/uniform phi sources to memory variables at the start of
468*61046927SAndroid Build Coastguard Worker        * the program, where pressure is zero and hence the copy is legal.
469*61046927SAndroid Build Coastguard Worker        */
470*61046927SAndroid Build Coastguard Worker       if (I->src[s].type != AGX_INDEX_NORMAL) {
471*61046927SAndroid Build Coastguard Worker          assert(I->src[s].type == AGX_INDEX_IMMEDIATE ||
472*61046927SAndroid Build Coastguard Worker                 I->src[s].type == AGX_INDEX_UNIFORM);
473*61046927SAndroid Build Coastguard Worker 
474*61046927SAndroid Build Coastguard Worker          agx_index mem = agx_temp_like(ctx->shader, I->dest[0]);
475*61046927SAndroid Build Coastguard Worker          assert(mem.memory);
476*61046927SAndroid Build Coastguard Worker 
477*61046927SAndroid Build Coastguard Worker          agx_index gpr = agx_temp_like(ctx->shader, I->dest[0]);
478*61046927SAndroid Build Coastguard Worker          gpr.memory = false;
479*61046927SAndroid Build Coastguard Worker 
480*61046927SAndroid Build Coastguard Worker          if (I->src[s].type == AGX_INDEX_IMMEDIATE)
481*61046927SAndroid Build Coastguard Worker             agx_mov_imm_to(&b, gpr, I->src[s].value);
482*61046927SAndroid Build Coastguard Worker          else
483*61046927SAndroid Build Coastguard Worker             agx_mov_to(&b, gpr, I->src[s]);
484*61046927SAndroid Build Coastguard Worker 
485*61046927SAndroid Build Coastguard Worker          agx_mov_to(&b, mem, gpr);
486*61046927SAndroid Build Coastguard Worker          I->src[s] = mem;
487*61046927SAndroid Build Coastguard Worker          continue;
488*61046927SAndroid Build Coastguard Worker       }
489*61046927SAndroid Build Coastguard Worker 
490*61046927SAndroid Build Coastguard Worker       bool spilled = false;
491*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < sp->nS_exit; ++i) {
492*61046927SAndroid Build Coastguard Worker          if (sp->S_exit[i] == I->src[s].value) {
493*61046927SAndroid Build Coastguard Worker             spilled = true;
494*61046927SAndroid Build Coastguard Worker             break;
495*61046927SAndroid Build Coastguard Worker          }
496*61046927SAndroid Build Coastguard Worker       }
497*61046927SAndroid Build Coastguard Worker 
498*61046927SAndroid Build Coastguard Worker       if (!spilled) {
499*61046927SAndroid Build Coastguard Worker          /* Spill the phi source. TODO: avoid redundant spills here */
500*61046927SAndroid Build Coastguard Worker          agx_builder b =
501*61046927SAndroid Build Coastguard Worker             agx_init_builder(ctx->shader, agx_after_block_logical(pred));
502*61046927SAndroid Build Coastguard Worker 
503*61046927SAndroid Build Coastguard Worker          insert_spill(&b, ctx, I->src[s].value);
504*61046927SAndroid Build Coastguard Worker       }
505*61046927SAndroid Build Coastguard Worker 
506*61046927SAndroid Build Coastguard Worker       if (ctx->remat[I->src[s].value]) {
507*61046927SAndroid Build Coastguard Worker          unsigned node = I->src[s].value;
508*61046927SAndroid Build Coastguard Worker          agx_index idx = reconstruct_index(ctx, node);
509*61046927SAndroid Build Coastguard Worker          agx_index tmp = agx_temp_like(ctx->shader, idx);
510*61046927SAndroid Build Coastguard Worker 
511*61046927SAndroid Build Coastguard Worker          remat_to(&b, tmp, ctx, node);
512*61046927SAndroid Build Coastguard Worker          agx_mov_to(&b, agx_index_as_mem(idx, ctx->spill_base), tmp);
513*61046927SAndroid Build Coastguard Worker       }
514*61046927SAndroid Build Coastguard Worker 
515*61046927SAndroid Build Coastguard Worker       /* Use the spilled version */
516*61046927SAndroid Build Coastguard Worker       I->src[s] = agx_index_as_mem(I->src[s], ctx->spill_base);
517*61046927SAndroid Build Coastguard Worker    }
518*61046927SAndroid Build Coastguard Worker 
519*61046927SAndroid Build Coastguard Worker    /* Anything assumed to be spilled at the start of succ must be spilled along
520*61046927SAndroid Build Coastguard Worker     * all edges.
521*61046927SAndroid Build Coastguard Worker     */
522*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < ss->nS_entry; ++i) {
523*61046927SAndroid Build Coastguard Worker       unsigned v = ss->S_entry[i];
524*61046927SAndroid Build Coastguard Worker 
525*61046927SAndroid Build Coastguard Worker       bool spilled = false;
526*61046927SAndroid Build Coastguard Worker       for (unsigned j = 0; j < sp->nS_exit; ++j) {
527*61046927SAndroid Build Coastguard Worker          if (sp->S_exit[j] == v) {
528*61046927SAndroid Build Coastguard Worker             spilled = true;
529*61046927SAndroid Build Coastguard Worker             break;
530*61046927SAndroid Build Coastguard Worker          }
531*61046927SAndroid Build Coastguard Worker       }
532*61046927SAndroid Build Coastguard Worker 
533*61046927SAndroid Build Coastguard Worker       /* We handle spilling phi destinations separately */
534*61046927SAndroid Build Coastguard Worker       agx_foreach_phi_in_block(succ, phi) {
535*61046927SAndroid Build Coastguard Worker          if (chase_mem_index(phi->dest[0], ctx->spill_base) == v) {
536*61046927SAndroid Build Coastguard Worker             spilled = true;
537*61046927SAndroid Build Coastguard Worker             break;
538*61046927SAndroid Build Coastguard Worker          }
539*61046927SAndroid Build Coastguard Worker       }
540*61046927SAndroid Build Coastguard Worker 
541*61046927SAndroid Build Coastguard Worker       if (spilled)
542*61046927SAndroid Build Coastguard Worker          continue;
543*61046927SAndroid Build Coastguard Worker 
544*61046927SAndroid Build Coastguard Worker       agx_builder b = agx_init_builder(ctx->shader, agx_along_edge(pred, succ));
545*61046927SAndroid Build Coastguard Worker       insert_spill(&b, ctx, v);
546*61046927SAndroid Build Coastguard Worker    }
547*61046927SAndroid Build Coastguard Worker 
548*61046927SAndroid Build Coastguard Worker    /* Variables in W at the start of succ must be defined along the edge. */
549*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < ss->nW_entry; ++i) {
550*61046927SAndroid Build Coastguard Worker       unsigned node = ss->W_entry[i];
551*61046927SAndroid Build Coastguard Worker       bool defined = false;
552*61046927SAndroid Build Coastguard Worker 
553*61046927SAndroid Build Coastguard Worker       /* Variables live at the end of the predecessor are live along the edge */
554*61046927SAndroid Build Coastguard Worker       for (unsigned j = 0; j < sp->nW_exit; ++j) {
555*61046927SAndroid Build Coastguard Worker          if (sp->W_exit[j] == node) {
556*61046927SAndroid Build Coastguard Worker             defined = true;
557*61046927SAndroid Build Coastguard Worker             break;
558*61046927SAndroid Build Coastguard Worker          }
559*61046927SAndroid Build Coastguard Worker       }
560*61046927SAndroid Build Coastguard Worker 
561*61046927SAndroid Build Coastguard Worker       /* Phis are defined along the edge */
562*61046927SAndroid Build Coastguard Worker       agx_foreach_phi_in_block(succ, phi) {
563*61046927SAndroid Build Coastguard Worker          if (phi->dest[0].value == node) {
564*61046927SAndroid Build Coastguard Worker             defined = true;
565*61046927SAndroid Build Coastguard Worker             break;
566*61046927SAndroid Build Coastguard Worker          }
567*61046927SAndroid Build Coastguard Worker       }
568*61046927SAndroid Build Coastguard Worker 
569*61046927SAndroid Build Coastguard Worker       if (defined)
570*61046927SAndroid Build Coastguard Worker          continue;
571*61046927SAndroid Build Coastguard Worker 
572*61046927SAndroid Build Coastguard Worker       /* Otherwise, inserting a reload defines the variable along the edge */
573*61046927SAndroid Build Coastguard Worker       agx_block *reload_block = agx_edge_to_block(pred, succ);
574*61046927SAndroid Build Coastguard Worker       insert_reload(ctx, reload_block, agx_along_edge(pred, succ), node);
575*61046927SAndroid Build Coastguard Worker    }
576*61046927SAndroid Build Coastguard Worker 
577*61046927SAndroid Build Coastguard Worker    agx_foreach_phi_in_block(succ, I) {
578*61046927SAndroid Build Coastguard Worker       if (I->dest[0].memory)
579*61046927SAndroid Build Coastguard Worker          continue;
580*61046927SAndroid Build Coastguard Worker 
581*61046927SAndroid Build Coastguard Worker       unsigned s = agx_predecessor_index(succ, pred);
582*61046927SAndroid Build Coastguard Worker 
583*61046927SAndroid Build Coastguard Worker       /* Treat immediate/uniform phi sources as registers for pressure
584*61046927SAndroid Build Coastguard Worker        * accounting and phi lowering purposes. Parallel copy lowering can handle
585*61046927SAndroid Build Coastguard Worker        * a copy from a immediate/uniform to a register, but not from an
586*61046927SAndroid Build Coastguard Worker        * immediate/uniform directly to memory.
587*61046927SAndroid Build Coastguard Worker        */
588*61046927SAndroid Build Coastguard Worker       if (I->src[s].type != AGX_INDEX_NORMAL) {
589*61046927SAndroid Build Coastguard Worker          assert(I->src[s].type == AGX_INDEX_IMMEDIATE ||
590*61046927SAndroid Build Coastguard Worker                 I->src[s].type == AGX_INDEX_UNIFORM);
591*61046927SAndroid Build Coastguard Worker 
592*61046927SAndroid Build Coastguard Worker          continue;
593*61046927SAndroid Build Coastguard Worker       }
594*61046927SAndroid Build Coastguard Worker 
595*61046927SAndroid Build Coastguard Worker       bool live = false;
596*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < sp->nW_exit; ++i) {
597*61046927SAndroid Build Coastguard Worker          if (sp->W_exit[i] == I->src[s].value) {
598*61046927SAndroid Build Coastguard Worker             live = true;
599*61046927SAndroid Build Coastguard Worker             break;
600*61046927SAndroid Build Coastguard Worker          }
601*61046927SAndroid Build Coastguard Worker       }
602*61046927SAndroid Build Coastguard Worker 
603*61046927SAndroid Build Coastguard Worker       /* Fill the phi source in the predecessor */
604*61046927SAndroid Build Coastguard Worker       if (!live) {
605*61046927SAndroid Build Coastguard Worker          agx_block *reload_block = agx_edge_to_block(pred, succ);
606*61046927SAndroid Build Coastguard Worker          insert_reload(ctx, reload_block, agx_along_edge(pred, succ),
607*61046927SAndroid Build Coastguard Worker                        I->src[s].value);
608*61046927SAndroid Build Coastguard Worker       }
609*61046927SAndroid Build Coastguard Worker 
610*61046927SAndroid Build Coastguard Worker       /* Leave as-is for the GPR version */
611*61046927SAndroid Build Coastguard Worker       assert(!I->src[s].memory);
612*61046927SAndroid Build Coastguard Worker    }
613*61046927SAndroid Build Coastguard Worker }
614*61046927SAndroid Build Coastguard Worker 
615*61046927SAndroid Build Coastguard Worker /*
616*61046927SAndroid Build Coastguard Worker  * Produce an array of next-use IPs relative to the start of the block. This is
617*61046927SAndroid Build Coastguard Worker  * an array of dist_t scalars, representing the next-use IP of each SSA dest
618*61046927SAndroid Build Coastguard Worker  * (right-to-left) and SSA source (left-to-right) of each instruction in the
619*61046927SAndroid Build Coastguard Worker  * block (bottom-to-top). Its size equals the # of SSA sources in the block.
620*61046927SAndroid Build Coastguard Worker  */
621*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
calculate_local_next_use(struct spill_ctx * ctx,struct util_dynarray * out)622*61046927SAndroid Build Coastguard Worker calculate_local_next_use(struct spill_ctx *ctx, struct util_dynarray *out)
623*61046927SAndroid Build Coastguard Worker {
624*61046927SAndroid Build Coastguard Worker    struct spill_block *sb = spill_block(ctx, ctx->block);
625*61046927SAndroid Build Coastguard Worker    unsigned ip = sb->cycles;
626*61046927SAndroid Build Coastguard Worker 
627*61046927SAndroid Build Coastguard Worker    util_dynarray_init(out, NULL);
628*61046927SAndroid Build Coastguard Worker 
629*61046927SAndroid Build Coastguard Worker    struct next_uses nu;
630*61046927SAndroid Build Coastguard Worker    init_next_uses(&nu, NULL);
631*61046927SAndroid Build Coastguard Worker 
632*61046927SAndroid Build Coastguard Worker    foreach_next_use(&sb->next_use_out, i, dist) {
633*61046927SAndroid Build Coastguard Worker       set_next_use(&nu, i, dist_sum(ip, dist));
634*61046927SAndroid Build Coastguard Worker    }
635*61046927SAndroid Build Coastguard Worker 
636*61046927SAndroid Build Coastguard Worker    agx_foreach_instr_in_block_rev(ctx->block, I) {
637*61046927SAndroid Build Coastguard Worker       ip -= instr_cycles(I);
638*61046927SAndroid Build Coastguard Worker 
639*61046927SAndroid Build Coastguard Worker       if (I->op != AGX_OPCODE_PHI) {
640*61046927SAndroid Build Coastguard Worker          agx_foreach_ssa_dest_rev(I, d) {
641*61046927SAndroid Build Coastguard Worker             unsigned v = I->dest[d].value;
642*61046927SAndroid Build Coastguard Worker 
643*61046927SAndroid Build Coastguard Worker             util_dynarray_append(out, dist_t, search_next_uses(&nu, v));
644*61046927SAndroid Build Coastguard Worker          }
645*61046927SAndroid Build Coastguard Worker 
646*61046927SAndroid Build Coastguard Worker          agx_foreach_ssa_src(I, s) {
647*61046927SAndroid Build Coastguard Worker             unsigned v = I->src[s].value;
648*61046927SAndroid Build Coastguard Worker 
649*61046927SAndroid Build Coastguard Worker             util_dynarray_append(out, dist_t, search_next_uses(&nu, v));
650*61046927SAndroid Build Coastguard Worker             set_next_use(&nu, v, ip);
651*61046927SAndroid Build Coastguard Worker          }
652*61046927SAndroid Build Coastguard Worker       }
653*61046927SAndroid Build Coastguard Worker    }
654*61046927SAndroid Build Coastguard Worker 
655*61046927SAndroid Build Coastguard Worker    assert(ip == 0 && "cycle counting is consistent");
656*61046927SAndroid Build Coastguard Worker    destroy_next_uses(&nu);
657*61046927SAndroid Build Coastguard Worker }
658*61046927SAndroid Build Coastguard Worker 
659*61046927SAndroid Build Coastguard Worker /*
660*61046927SAndroid Build Coastguard Worker  * Insert spills/fills for a single basic block, following Belady's algorithm.
661*61046927SAndroid Build Coastguard Worker  * Corresponds to minAlgorithm from the paper.
662*61046927SAndroid Build Coastguard Worker  */
663*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
min_algorithm(struct spill_ctx * ctx)664*61046927SAndroid Build Coastguard Worker min_algorithm(struct spill_ctx *ctx)
665*61046927SAndroid Build Coastguard Worker {
666*61046927SAndroid Build Coastguard Worker    struct spill_block *sblock = spill_block(ctx, ctx->block);
667*61046927SAndroid Build Coastguard Worker    struct util_dynarray local_next_ip;
668*61046927SAndroid Build Coastguard Worker    calculate_local_next_use(ctx, &local_next_ip);
669*61046927SAndroid Build Coastguard Worker 
670*61046927SAndroid Build Coastguard Worker    /* next_uses gives the distance from the start of the block, so prepopulate
671*61046927SAndroid Build Coastguard Worker     * with next_use_in.
672*61046927SAndroid Build Coastguard Worker     */
673*61046927SAndroid Build Coastguard Worker    foreach_next_use(&sblock->next_use_in, key, dist) {
674*61046927SAndroid Build Coastguard Worker       assert(key < ctx->n);
675*61046927SAndroid Build Coastguard Worker       ctx->next_uses[key] = dist;
676*61046927SAndroid Build Coastguard Worker    }
677*61046927SAndroid Build Coastguard Worker 
678*61046927SAndroid Build Coastguard Worker    dist_t *next_ips = util_dynarray_element(&local_next_ip, dist_t, 0);
679*61046927SAndroid Build Coastguard Worker    unsigned next_use_cursor =
680*61046927SAndroid Build Coastguard Worker       util_dynarray_num_elements(&local_next_ip, dist_t);
681*61046927SAndroid Build Coastguard Worker 
682*61046927SAndroid Build Coastguard Worker    /* Iterate each instruction in forward order */
683*61046927SAndroid Build Coastguard Worker    agx_foreach_instr_in_block(ctx->block, I) {
684*61046927SAndroid Build Coastguard Worker       assert(ctx->nW <= ctx->k && "invariant");
685*61046927SAndroid Build Coastguard Worker 
686*61046927SAndroid Build Coastguard Worker       /* Phis are special since they happen along the edge. When we initialized
687*61046927SAndroid Build Coastguard Worker        * W and S, we implicitly chose which phis are spilled. So, here we just
688*61046927SAndroid Build Coastguard Worker        * need to rewrite the phis to write into memory.
689*61046927SAndroid Build Coastguard Worker        *
690*61046927SAndroid Build Coastguard Worker        * Phi sources are handled later.
691*61046927SAndroid Build Coastguard Worker        */
692*61046927SAndroid Build Coastguard Worker       if (I->op == AGX_OPCODE_PHI) {
693*61046927SAndroid Build Coastguard Worker          if (!BITSET_TEST(ctx->W, I->dest[0].value)) {
694*61046927SAndroid Build Coastguard Worker             I->dest[0] = agx_index_as_mem(I->dest[0], ctx->spill_base);
695*61046927SAndroid Build Coastguard Worker          }
696*61046927SAndroid Build Coastguard Worker 
697*61046927SAndroid Build Coastguard Worker          ctx->ip += instr_cycles(I);
698*61046927SAndroid Build Coastguard Worker          continue;
699*61046927SAndroid Build Coastguard Worker       }
700*61046927SAndroid Build Coastguard Worker 
701*61046927SAndroid Build Coastguard Worker       /* Any source that is not in W needs to be reloaded. Gather the set R of
702*61046927SAndroid Build Coastguard Worker        * such values.
703*61046927SAndroid Build Coastguard Worker        */
704*61046927SAndroid Build Coastguard Worker       unsigned R[AGX_MAX_NORMAL_SOURCES];
705*61046927SAndroid Build Coastguard Worker       unsigned nR = 0;
706*61046927SAndroid Build Coastguard Worker 
707*61046927SAndroid Build Coastguard Worker       agx_foreach_ssa_src(I, s) {
708*61046927SAndroid Build Coastguard Worker          unsigned node = I->src[s].value;
709*61046927SAndroid Build Coastguard Worker          if (BITSET_TEST(ctx->W, node))
710*61046927SAndroid Build Coastguard Worker             continue;
711*61046927SAndroid Build Coastguard Worker 
712*61046927SAndroid Build Coastguard Worker          /* Mark this variable as needing a reload. */
713*61046927SAndroid Build Coastguard Worker          assert(node < ctx->n);
714*61046927SAndroid Build Coastguard Worker          assert(BITSET_TEST(ctx->S, node) && "must have been spilled");
715*61046927SAndroid Build Coastguard Worker          assert(nR < ARRAY_SIZE(R) && "maximum source count");
716*61046927SAndroid Build Coastguard Worker          R[nR++] = node;
717*61046927SAndroid Build Coastguard Worker 
718*61046927SAndroid Build Coastguard Worker          /* The inserted reload will add the value to the register file. */
719*61046927SAndroid Build Coastguard Worker          insert_W(ctx, node);
720*61046927SAndroid Build Coastguard Worker       }
721*61046927SAndroid Build Coastguard Worker 
722*61046927SAndroid Build Coastguard Worker       /* Limit W to make space for the sources we just added */
723*61046927SAndroid Build Coastguard Worker       limit(ctx, I, ctx->k);
724*61046927SAndroid Build Coastguard Worker 
725*61046927SAndroid Build Coastguard Worker       /* Update next-use distances for this instruction. Unlike the paper, we
726*61046927SAndroid Build Coastguard Worker        * prune dead values from W as we go. This doesn't affect correctness, but
727*61046927SAndroid Build Coastguard Worker        * it speeds up limit() on average.
728*61046927SAndroid Build Coastguard Worker        */
729*61046927SAndroid Build Coastguard Worker       agx_foreach_ssa_src_rev(I, s) {
730*61046927SAndroid Build Coastguard Worker          assert(next_use_cursor >= 1);
731*61046927SAndroid Build Coastguard Worker 
732*61046927SAndroid Build Coastguard Worker          unsigned next_ip = next_ips[--next_use_cursor];
733*61046927SAndroid Build Coastguard Worker          assert((next_ip == DIST_INFINITY) == I->src[s].kill);
734*61046927SAndroid Build Coastguard Worker 
735*61046927SAndroid Build Coastguard Worker          if (next_ip == DIST_INFINITY)
736*61046927SAndroid Build Coastguard Worker             remove_W_if_present(ctx, I->src[s].value);
737*61046927SAndroid Build Coastguard Worker          else
738*61046927SAndroid Build Coastguard Worker             ctx->next_uses[I->src[s].value] = next_ip;
739*61046927SAndroid Build Coastguard Worker       }
740*61046927SAndroid Build Coastguard Worker 
741*61046927SAndroid Build Coastguard Worker       agx_foreach_ssa_dest(I, d) {
742*61046927SAndroid Build Coastguard Worker          assert(next_use_cursor >= 1);
743*61046927SAndroid Build Coastguard Worker          unsigned next_ip = next_ips[--next_use_cursor];
744*61046927SAndroid Build Coastguard Worker 
745*61046927SAndroid Build Coastguard Worker          if (next_ip == DIST_INFINITY)
746*61046927SAndroid Build Coastguard Worker             remove_W_if_present(ctx, I->dest[d].value);
747*61046927SAndroid Build Coastguard Worker          else
748*61046927SAndroid Build Coastguard Worker             ctx->next_uses[I->dest[d].value] = next_ip;
749*61046927SAndroid Build Coastguard Worker       }
750*61046927SAndroid Build Coastguard Worker 
751*61046927SAndroid Build Coastguard Worker       /* Count how many registers we need for destinations. Because of
752*61046927SAndroid Build Coastguard Worker        * SSA form, destinations are unique.
753*61046927SAndroid Build Coastguard Worker        */
754*61046927SAndroid Build Coastguard Worker       unsigned dest_size = 0;
755*61046927SAndroid Build Coastguard Worker       agx_foreach_ssa_dest(I, d) {
756*61046927SAndroid Build Coastguard Worker          dest_size += node_size(ctx, I->dest[d].value);
757*61046927SAndroid Build Coastguard Worker       }
758*61046927SAndroid Build Coastguard Worker 
759*61046927SAndroid Build Coastguard Worker       /* Limit W to make space for the destinations. */
760*61046927SAndroid Build Coastguard Worker       limit(ctx, I, ctx->k - dest_size);
761*61046927SAndroid Build Coastguard Worker 
762*61046927SAndroid Build Coastguard Worker       /* Destinations are now in the register file */
763*61046927SAndroid Build Coastguard Worker       agx_foreach_ssa_dest(I, d) {
764*61046927SAndroid Build Coastguard Worker          insert_W(ctx, I->dest[d].value);
765*61046927SAndroid Build Coastguard Worker       }
766*61046927SAndroid Build Coastguard Worker 
767*61046927SAndroid Build Coastguard Worker       /* Add reloads for the sources in front of the instruction */
768*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < nR; ++i) {
769*61046927SAndroid Build Coastguard Worker          insert_reload(ctx, ctx->block, agx_before_instr(I), R[i]);
770*61046927SAndroid Build Coastguard Worker       }
771*61046927SAndroid Build Coastguard Worker 
772*61046927SAndroid Build Coastguard Worker       ctx->ip += instr_cycles(I);
773*61046927SAndroid Build Coastguard Worker    }
774*61046927SAndroid Build Coastguard Worker 
775*61046927SAndroid Build Coastguard Worker    assert(next_use_cursor == 0 && "exactly sized");
776*61046927SAndroid Build Coastguard Worker 
777*61046927SAndroid Build Coastguard Worker    int i;
778*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, ctx->W, ctx->n)
779*61046927SAndroid Build Coastguard Worker       sblock->W_exit[sblock->nW_exit++] = i;
780*61046927SAndroid Build Coastguard Worker 
781*61046927SAndroid Build Coastguard Worker    unsigned nS = __bitset_count(ctx->S, BITSET_WORDS(ctx->n));
782*61046927SAndroid Build Coastguard Worker    sblock->S_exit = ralloc_array(ctx->memctx, unsigned, nS);
783*61046927SAndroid Build Coastguard Worker 
784*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, ctx->S, ctx->n)
785*61046927SAndroid Build Coastguard Worker       sblock->S_exit[sblock->nS_exit++] = i;
786*61046927SAndroid Build Coastguard Worker 
787*61046927SAndroid Build Coastguard Worker    assert(nS == sblock->nS_exit);
788*61046927SAndroid Build Coastguard Worker    util_dynarray_fini(&local_next_ip);
789*61046927SAndroid Build Coastguard Worker }
790*61046927SAndroid Build Coastguard Worker 
791*61046927SAndroid Build Coastguard Worker /*
792*61046927SAndroid Build Coastguard Worker  * TODO: Implement section 4.2 of the paper.
793*61046927SAndroid Build Coastguard Worker  *
794*61046927SAndroid Build Coastguard Worker  * For now, we implement the simpler heuristic in Hack's thesis: sort
795*61046927SAndroid Build Coastguard Worker  * the live-in set (+ destinations of phis) by next-use distance.
796*61046927SAndroid Build Coastguard Worker  */
797*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
compute_w_entry_loop_header(struct spill_ctx * ctx)798*61046927SAndroid Build Coastguard Worker compute_w_entry_loop_header(struct spill_ctx *ctx)
799*61046927SAndroid Build Coastguard Worker {
800*61046927SAndroid Build Coastguard Worker    agx_block *block = ctx->block;
801*61046927SAndroid Build Coastguard Worker    struct spill_block *sb = spill_block(ctx, block);
802*61046927SAndroid Build Coastguard Worker 
803*61046927SAndroid Build Coastguard Worker    unsigned nP = __bitset_count(block->live_in, BITSET_WORDS(ctx->n));
804*61046927SAndroid Build Coastguard Worker    struct candidate *candidates = calloc(nP, sizeof(struct candidate));
805*61046927SAndroid Build Coastguard Worker    unsigned j = 0;
806*61046927SAndroid Build Coastguard Worker 
807*61046927SAndroid Build Coastguard Worker    foreach_next_use(&sb->next_use_in, i, dist) {
808*61046927SAndroid Build Coastguard Worker       assert(j < nP);
809*61046927SAndroid Build Coastguard Worker       candidates[j++] = (struct candidate){.node = i, .dist = dist};
810*61046927SAndroid Build Coastguard Worker    }
811*61046927SAndroid Build Coastguard Worker 
812*61046927SAndroid Build Coastguard Worker    assert(j == nP);
813*61046927SAndroid Build Coastguard Worker 
814*61046927SAndroid Build Coastguard Worker    /* Sort by next-use distance */
815*61046927SAndroid Build Coastguard Worker    util_qsort_r(candidates, j, sizeof(struct candidate), cmp_dist, ctx);
816*61046927SAndroid Build Coastguard Worker 
817*61046927SAndroid Build Coastguard Worker    /* Take as much as we can */
818*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < j; ++i) {
819*61046927SAndroid Build Coastguard Worker       unsigned node = candidates[i].node;
820*61046927SAndroid Build Coastguard Worker       unsigned comps = node_size(ctx, node);
821*61046927SAndroid Build Coastguard Worker 
822*61046927SAndroid Build Coastguard Worker       if ((ctx->nW + comps) <= ctx->k) {
823*61046927SAndroid Build Coastguard Worker          insert_W(ctx, node);
824*61046927SAndroid Build Coastguard Worker          sb->W_entry[sb->nW_entry++] = node;
825*61046927SAndroid Build Coastguard Worker       }
826*61046927SAndroid Build Coastguard Worker    }
827*61046927SAndroid Build Coastguard Worker 
828*61046927SAndroid Build Coastguard Worker    assert(ctx->nW <= ctx->k);
829*61046927SAndroid Build Coastguard Worker    free(candidates);
830*61046927SAndroid Build Coastguard Worker }
831*61046927SAndroid Build Coastguard Worker 
832*61046927SAndroid Build Coastguard Worker /*
833*61046927SAndroid Build Coastguard Worker  * Compute W_entry for a block. Section 4.2 in the paper.
834*61046927SAndroid Build Coastguard Worker  */
835*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
compute_w_entry(struct spill_ctx * ctx)836*61046927SAndroid Build Coastguard Worker compute_w_entry(struct spill_ctx *ctx)
837*61046927SAndroid Build Coastguard Worker {
838*61046927SAndroid Build Coastguard Worker    agx_block *block = ctx->block;
839*61046927SAndroid Build Coastguard Worker    struct spill_block *sb = spill_block(ctx, block);
840*61046927SAndroid Build Coastguard Worker 
841*61046927SAndroid Build Coastguard Worker    /* Nothing to do for start blocks */
842*61046927SAndroid Build Coastguard Worker    if (agx_num_predecessors(block) == 0)
843*61046927SAndroid Build Coastguard Worker       return;
844*61046927SAndroid Build Coastguard Worker 
845*61046927SAndroid Build Coastguard Worker    /* Loop headers have a different heuristic */
846*61046927SAndroid Build Coastguard Worker    if (block->loop_header) {
847*61046927SAndroid Build Coastguard Worker       compute_w_entry_loop_header(ctx);
848*61046927SAndroid Build Coastguard Worker       return;
849*61046927SAndroid Build Coastguard Worker    }
850*61046927SAndroid Build Coastguard Worker 
851*61046927SAndroid Build Coastguard Worker    /* Usual blocks follow */
852*61046927SAndroid Build Coastguard Worker    unsigned *freq = calloc(ctx->n, sizeof(unsigned));
853*61046927SAndroid Build Coastguard Worker 
854*61046927SAndroid Build Coastguard Worker    /* Record what's written at the end of each predecessor */
855*61046927SAndroid Build Coastguard Worker    agx_foreach_predecessor(ctx->block, P) {
856*61046927SAndroid Build Coastguard Worker       struct spill_block *sp = spill_block(ctx, *P);
857*61046927SAndroid Build Coastguard Worker 
858*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < sp->nW_exit; ++i) {
859*61046927SAndroid Build Coastguard Worker          unsigned v = sp->W_exit[i];
860*61046927SAndroid Build Coastguard Worker          freq[v]++;
861*61046927SAndroid Build Coastguard Worker       }
862*61046927SAndroid Build Coastguard Worker    }
863*61046927SAndroid Build Coastguard Worker 
864*61046927SAndroid Build Coastguard Worker    struct candidate *candidates = calloc(ctx->n, sizeof(struct candidate));
865*61046927SAndroid Build Coastguard Worker    unsigned j = 0;
866*61046927SAndroid Build Coastguard Worker 
867*61046927SAndroid Build Coastguard Worker    /* Variables that are in all predecessors are assumed in W_entry. Phis and
868*61046927SAndroid Build Coastguard Worker     * variables in some predecessors are scored by next-use.
869*61046927SAndroid Build Coastguard Worker     */
870*61046927SAndroid Build Coastguard Worker    foreach_next_use(&sb->next_use_in, i, dist) {
871*61046927SAndroid Build Coastguard Worker       if (freq[i] == agx_num_predecessors(ctx->block)) {
872*61046927SAndroid Build Coastguard Worker          insert_W(ctx, i);
873*61046927SAndroid Build Coastguard Worker       } else if (freq[i]) {
874*61046927SAndroid Build Coastguard Worker          candidates[j++] = (struct candidate){.node = i, .dist = dist};
875*61046927SAndroid Build Coastguard Worker       }
876*61046927SAndroid Build Coastguard Worker    }
877*61046927SAndroid Build Coastguard Worker 
878*61046927SAndroid Build Coastguard Worker    agx_foreach_phi_in_block(ctx->block, I) {
879*61046927SAndroid Build Coastguard Worker       bool all_found = true;
880*61046927SAndroid Build Coastguard Worker 
881*61046927SAndroid Build Coastguard Worker       agx_foreach_predecessor(ctx->block, pred) {
882*61046927SAndroid Build Coastguard Worker          struct spill_block *sp = spill_block(ctx, *pred);
883*61046927SAndroid Build Coastguard Worker          bool found = false;
884*61046927SAndroid Build Coastguard Worker 
885*61046927SAndroid Build Coastguard Worker          agx_index src = I->src[agx_predecessor_index(ctx->block, *pred)];
886*61046927SAndroid Build Coastguard Worker          if (src.type != AGX_INDEX_NORMAL)
887*61046927SAndroid Build Coastguard Worker             continue;
888*61046927SAndroid Build Coastguard Worker 
889*61046927SAndroid Build Coastguard Worker          unsigned v = src.value;
890*61046927SAndroid Build Coastguard Worker          for (unsigned i = 0; i < sp->nW_exit; ++i) {
891*61046927SAndroid Build Coastguard Worker             if (sp->W_exit[i] == v) {
892*61046927SAndroid Build Coastguard Worker                found = true;
893*61046927SAndroid Build Coastguard Worker                break;
894*61046927SAndroid Build Coastguard Worker             }
895*61046927SAndroid Build Coastguard Worker          }
896*61046927SAndroid Build Coastguard Worker 
897*61046927SAndroid Build Coastguard Worker          all_found &= found;
898*61046927SAndroid Build Coastguard Worker       }
899*61046927SAndroid Build Coastguard Worker 
900*61046927SAndroid Build Coastguard Worker       /* Heuristic: if any phi source is spilled, spill the whole phi. This is
901*61046927SAndroid Build Coastguard Worker        * suboptimal, but it massively reduces pointless fill/spill chains with
902*61046927SAndroid Build Coastguard Worker        * massive phi webs.
903*61046927SAndroid Build Coastguard Worker        */
904*61046927SAndroid Build Coastguard Worker       if (!all_found)
905*61046927SAndroid Build Coastguard Worker          continue;
906*61046927SAndroid Build Coastguard Worker 
907*61046927SAndroid Build Coastguard Worker       candidates[j++] = (struct candidate){
908*61046927SAndroid Build Coastguard Worker          .node = I->dest[0].value,
909*61046927SAndroid Build Coastguard Worker          .dist = search_next_uses(&sb->next_use_in, I->dest[0].value),
910*61046927SAndroid Build Coastguard Worker       };
911*61046927SAndroid Build Coastguard Worker    }
912*61046927SAndroid Build Coastguard Worker 
913*61046927SAndroid Build Coastguard Worker    /* Sort by next-use distance */
914*61046927SAndroid Build Coastguard Worker    util_qsort_r(candidates, j, sizeof(struct candidate), cmp_dist, ctx);
915*61046927SAndroid Build Coastguard Worker 
916*61046927SAndroid Build Coastguard Worker    /* Take as much as we can */
917*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < j; ++i) {
918*61046927SAndroid Build Coastguard Worker       unsigned node = candidates[i].node;
919*61046927SAndroid Build Coastguard Worker       unsigned comps = node_size(ctx, node);
920*61046927SAndroid Build Coastguard Worker 
921*61046927SAndroid Build Coastguard Worker       if ((ctx->nW + comps) <= ctx->k) {
922*61046927SAndroid Build Coastguard Worker          insert_W(ctx, node);
923*61046927SAndroid Build Coastguard Worker          sb->W_entry[sb->nW_entry++] = node;
924*61046927SAndroid Build Coastguard Worker       }
925*61046927SAndroid Build Coastguard Worker    }
926*61046927SAndroid Build Coastguard Worker 
927*61046927SAndroid Build Coastguard Worker    assert(ctx->nW <= ctx->k && "invariant");
928*61046927SAndroid Build Coastguard Worker 
929*61046927SAndroid Build Coastguard Worker    free(freq);
930*61046927SAndroid Build Coastguard Worker    free(candidates);
931*61046927SAndroid Build Coastguard Worker }
932*61046927SAndroid Build Coastguard Worker 
933*61046927SAndroid Build Coastguard Worker /*
934*61046927SAndroid Build Coastguard Worker  * We initialize S with the union of S at the exit of (forward edge)
935*61046927SAndroid Build Coastguard Worker  * predecessors and the complement of W, intersected with the live-in set. The
936*61046927SAndroid Build Coastguard Worker  * former propagates S forward. The latter ensures we spill along the edge when
937*61046927SAndroid Build Coastguard Worker  * a live value is not selected for the entry W.
938*61046927SAndroid Build Coastguard Worker  */
939*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
compute_s_entry(struct spill_ctx * ctx)940*61046927SAndroid Build Coastguard Worker compute_s_entry(struct spill_ctx *ctx)
941*61046927SAndroid Build Coastguard Worker {
942*61046927SAndroid Build Coastguard Worker    unsigned v;
943*61046927SAndroid Build Coastguard Worker 
944*61046927SAndroid Build Coastguard Worker    agx_foreach_predecessor(ctx->block, pred) {
945*61046927SAndroid Build Coastguard Worker       struct spill_block *sp = spill_block(ctx, *pred);
946*61046927SAndroid Build Coastguard Worker 
947*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < sp->nS_exit; ++i) {
948*61046927SAndroid Build Coastguard Worker          v = sp->S_exit[i];
949*61046927SAndroid Build Coastguard Worker 
950*61046927SAndroid Build Coastguard Worker          if (BITSET_TEST(ctx->block->live_in, v))
951*61046927SAndroid Build Coastguard Worker             BITSET_SET(ctx->S, v);
952*61046927SAndroid Build Coastguard Worker       }
953*61046927SAndroid Build Coastguard Worker    }
954*61046927SAndroid Build Coastguard Worker 
955*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(v, ctx->block->live_in, ctx->n) {
956*61046927SAndroid Build Coastguard Worker       if (!BITSET_TEST(ctx->W, v))
957*61046927SAndroid Build Coastguard Worker          BITSET_SET(ctx->S, v);
958*61046927SAndroid Build Coastguard Worker    }
959*61046927SAndroid Build Coastguard Worker 
960*61046927SAndroid Build Coastguard Worker    /* Copy ctx->S to S_entry for later look-ups with coupling code */
961*61046927SAndroid Build Coastguard Worker    struct spill_block *sb = spill_block(ctx, ctx->block);
962*61046927SAndroid Build Coastguard Worker    unsigned nS = __bitset_count(ctx->S, BITSET_WORDS(ctx->n));
963*61046927SAndroid Build Coastguard Worker    sb->S_entry = ralloc_array(ctx->memctx, unsigned, nS);
964*61046927SAndroid Build Coastguard Worker 
965*61046927SAndroid Build Coastguard Worker    int i;
966*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, ctx->S, ctx->n)
967*61046927SAndroid Build Coastguard Worker       sb->S_entry[sb->nS_entry++] = i;
968*61046927SAndroid Build Coastguard Worker 
969*61046927SAndroid Build Coastguard Worker    assert(sb->nS_entry == nS);
970*61046927SAndroid Build Coastguard Worker }
971*61046927SAndroid Build Coastguard Worker 
972*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
global_next_use_distances(agx_context * ctx,void * memctx,struct spill_block * blocks)973*61046927SAndroid Build Coastguard Worker global_next_use_distances(agx_context *ctx, void *memctx,
974*61046927SAndroid Build Coastguard Worker                           struct spill_block *blocks)
975*61046927SAndroid Build Coastguard Worker {
976*61046927SAndroid Build Coastguard Worker    u_worklist worklist;
977*61046927SAndroid Build Coastguard Worker    u_worklist_init(&worklist, ctx->num_blocks, NULL);
978*61046927SAndroid Build Coastguard Worker 
979*61046927SAndroid Build Coastguard Worker    agx_foreach_block(ctx, block) {
980*61046927SAndroid Build Coastguard Worker       struct spill_block *sb = &blocks[block->index];
981*61046927SAndroid Build Coastguard Worker 
982*61046927SAndroid Build Coastguard Worker       init_next_uses(&sb->next_use_in, memctx);
983*61046927SAndroid Build Coastguard Worker       init_next_uses(&sb->next_use_out, memctx);
984*61046927SAndroid Build Coastguard Worker 
985*61046927SAndroid Build Coastguard Worker       agx_foreach_instr_in_block(block, I) {
986*61046927SAndroid Build Coastguard Worker          sb->cycles += instr_cycles(I);
987*61046927SAndroid Build Coastguard Worker       }
988*61046927SAndroid Build Coastguard Worker 
989*61046927SAndroid Build Coastguard Worker       agx_worklist_push_head(&worklist, block);
990*61046927SAndroid Build Coastguard Worker    }
991*61046927SAndroid Build Coastguard Worker 
992*61046927SAndroid Build Coastguard Worker    /* Definitions that have been seen */
993*61046927SAndroid Build Coastguard Worker    BITSET_WORD *defined =
994*61046927SAndroid Build Coastguard Worker       malloc(BITSET_WORDS(ctx->alloc) * sizeof(BITSET_WORD));
995*61046927SAndroid Build Coastguard Worker 
996*61046927SAndroid Build Coastguard Worker    struct next_uses dists;
997*61046927SAndroid Build Coastguard Worker    init_next_uses(&dists, NULL);
998*61046927SAndroid Build Coastguard Worker 
999*61046927SAndroid Build Coastguard Worker    /* Iterate the work list in reverse order since liveness is backwards */
1000*61046927SAndroid Build Coastguard Worker    while (!u_worklist_is_empty(&worklist)) {
1001*61046927SAndroid Build Coastguard Worker       agx_block *blk = agx_worklist_pop_head(&worklist);
1002*61046927SAndroid Build Coastguard Worker       struct spill_block *sb = &blocks[blk->index];
1003*61046927SAndroid Build Coastguard Worker 
1004*61046927SAndroid Build Coastguard Worker       /* Definitions that have been seen */
1005*61046927SAndroid Build Coastguard Worker       memset(defined, 0, BITSET_WORDS(ctx->alloc) * sizeof(BITSET_WORD));
1006*61046927SAndroid Build Coastguard Worker 
1007*61046927SAndroid Build Coastguard Worker       /* Initialize all distances to infinity */
1008*61046927SAndroid Build Coastguard Worker       clear_next_uses(&dists);
1009*61046927SAndroid Build Coastguard Worker 
1010*61046927SAndroid Build Coastguard Worker       uint32_t cycle = 0;
1011*61046927SAndroid Build Coastguard Worker 
1012*61046927SAndroid Build Coastguard Worker       /* Calculate dists. Phis are handled separately. */
1013*61046927SAndroid Build Coastguard Worker       agx_foreach_instr_in_block(blk, I) {
1014*61046927SAndroid Build Coastguard Worker          if (I->op == AGX_OPCODE_PHI) {
1015*61046927SAndroid Build Coastguard Worker             cycle++;
1016*61046927SAndroid Build Coastguard Worker             continue;
1017*61046927SAndroid Build Coastguard Worker          }
1018*61046927SAndroid Build Coastguard Worker 
1019*61046927SAndroid Build Coastguard Worker          /* Record first use before def. Phi sources are handled
1020*61046927SAndroid Build Coastguard Worker           * above, because they logically happen in the
1021*61046927SAndroid Build Coastguard Worker           * predecessor.
1022*61046927SAndroid Build Coastguard Worker           */
1023*61046927SAndroid Build Coastguard Worker          agx_foreach_ssa_src(I, s) {
1024*61046927SAndroid Build Coastguard Worker             if (BITSET_TEST(defined, I->src[s].value))
1025*61046927SAndroid Build Coastguard Worker                continue;
1026*61046927SAndroid Build Coastguard Worker             if (search_next_uses(&dists, I->src[s].value) < DIST_INFINITY)
1027*61046927SAndroid Build Coastguard Worker                continue;
1028*61046927SAndroid Build Coastguard Worker 
1029*61046927SAndroid Build Coastguard Worker             assert(I->src[s].value < ctx->alloc);
1030*61046927SAndroid Build Coastguard Worker             set_next_use(&dists, I->src[s].value, cycle);
1031*61046927SAndroid Build Coastguard Worker          }
1032*61046927SAndroid Build Coastguard Worker 
1033*61046927SAndroid Build Coastguard Worker          /* Record defs */
1034*61046927SAndroid Build Coastguard Worker          agx_foreach_ssa_dest(I, d) {
1035*61046927SAndroid Build Coastguard Worker             assert(I->dest[d].value < ctx->alloc);
1036*61046927SAndroid Build Coastguard Worker             BITSET_SET(defined, I->dest[d].value);
1037*61046927SAndroid Build Coastguard Worker          }
1038*61046927SAndroid Build Coastguard Worker 
1039*61046927SAndroid Build Coastguard Worker          cycle += instr_cycles(I);
1040*61046927SAndroid Build Coastguard Worker       }
1041*61046927SAndroid Build Coastguard Worker 
1042*61046927SAndroid Build Coastguard Worker       /* Apply transfer function to get our entry state. */
1043*61046927SAndroid Build Coastguard Worker       foreach_next_use(&sb->next_use_out, node, dist) {
1044*61046927SAndroid Build Coastguard Worker          set_next_use(&sb->next_use_in, node, dist_sum(dist, sb->cycles));
1045*61046927SAndroid Build Coastguard Worker       }
1046*61046927SAndroid Build Coastguard Worker 
1047*61046927SAndroid Build Coastguard Worker       foreach_next_use(&dists, node, dist) {
1048*61046927SAndroid Build Coastguard Worker          set_next_use(&sb->next_use_in, node, dist);
1049*61046927SAndroid Build Coastguard Worker       }
1050*61046927SAndroid Build Coastguard Worker 
1051*61046927SAndroid Build Coastguard Worker       int i;
1052*61046927SAndroid Build Coastguard Worker       BITSET_FOREACH_SET(i, defined, ctx->alloc) {
1053*61046927SAndroid Build Coastguard Worker          set_next_use(&sb->next_use_in, i, DIST_INFINITY);
1054*61046927SAndroid Build Coastguard Worker       }
1055*61046927SAndroid Build Coastguard Worker 
1056*61046927SAndroid Build Coastguard Worker       /* Propagate the live in of the successor (blk) to the live out of
1057*61046927SAndroid Build Coastguard Worker        * predecessors.
1058*61046927SAndroid Build Coastguard Worker        *
1059*61046927SAndroid Build Coastguard Worker        * Phi nodes are logically on the control flow edge and act in parallel.
1060*61046927SAndroid Build Coastguard Worker        * To handle when propagating, we kill writes from phis and make live the
1061*61046927SAndroid Build Coastguard Worker        * corresponding sources.
1062*61046927SAndroid Build Coastguard Worker        */
1063*61046927SAndroid Build Coastguard Worker       agx_foreach_predecessor(blk, pred) {
1064*61046927SAndroid Build Coastguard Worker          struct spill_block *sp = &blocks[(*pred)->index];
1065*61046927SAndroid Build Coastguard Worker          copy_next_uses(&dists, &sb->next_use_in);
1066*61046927SAndroid Build Coastguard Worker 
1067*61046927SAndroid Build Coastguard Worker          /* Kill write */
1068*61046927SAndroid Build Coastguard Worker          agx_foreach_phi_in_block(blk, I) {
1069*61046927SAndroid Build Coastguard Worker             assert(I->dest[0].type == AGX_INDEX_NORMAL);
1070*61046927SAndroid Build Coastguard Worker             set_next_use(&dists, I->dest[0].value, DIST_INFINITY);
1071*61046927SAndroid Build Coastguard Worker          }
1072*61046927SAndroid Build Coastguard Worker 
1073*61046927SAndroid Build Coastguard Worker          /* Make live the corresponding source */
1074*61046927SAndroid Build Coastguard Worker          agx_foreach_phi_in_block(blk, I) {
1075*61046927SAndroid Build Coastguard Worker             agx_index operand = I->src[agx_predecessor_index(blk, *pred)];
1076*61046927SAndroid Build Coastguard Worker             if (operand.type == AGX_INDEX_NORMAL)
1077*61046927SAndroid Build Coastguard Worker                set_next_use(&dists, operand.value, 0);
1078*61046927SAndroid Build Coastguard Worker          }
1079*61046927SAndroid Build Coastguard Worker 
1080*61046927SAndroid Build Coastguard Worker          /* Join by taking minimum */
1081*61046927SAndroid Build Coastguard Worker          if (minimum_next_uses(&sp->next_use_out, &dists))
1082*61046927SAndroid Build Coastguard Worker             agx_worklist_push_tail(&worklist, *pred);
1083*61046927SAndroid Build Coastguard Worker       }
1084*61046927SAndroid Build Coastguard Worker    }
1085*61046927SAndroid Build Coastguard Worker 
1086*61046927SAndroid Build Coastguard Worker    free(defined);
1087*61046927SAndroid Build Coastguard Worker    u_worklist_fini(&worklist);
1088*61046927SAndroid Build Coastguard Worker    destroy_next_uses(&dists);
1089*61046927SAndroid Build Coastguard Worker }
1090*61046927SAndroid Build Coastguard Worker 
1091*61046927SAndroid Build Coastguard Worker static ATTRIBUTE_NOINLINE void
validate_next_use_info(UNUSED agx_context * ctx,UNUSED struct spill_block * blocks)1092*61046927SAndroid Build Coastguard Worker validate_next_use_info(UNUSED agx_context *ctx,
1093*61046927SAndroid Build Coastguard Worker                        UNUSED struct spill_block *blocks)
1094*61046927SAndroid Build Coastguard Worker {
1095*61046927SAndroid Build Coastguard Worker #ifndef NDEBUG
1096*61046927SAndroid Build Coastguard Worker    int i;
1097*61046927SAndroid Build Coastguard Worker 
1098*61046927SAndroid Build Coastguard Worker    agx_foreach_block(ctx, blk) {
1099*61046927SAndroid Build Coastguard Worker       struct spill_block *sb = &blocks[blk->index];
1100*61046927SAndroid Build Coastguard Worker 
1101*61046927SAndroid Build Coastguard Worker       /* Invariant: next-use distance is finite iff the node is live */
1102*61046927SAndroid Build Coastguard Worker       BITSET_FOREACH_SET(i, blk->live_in, ctx->alloc)
1103*61046927SAndroid Build Coastguard Worker          assert(search_next_uses(&sb->next_use_in, i) < DIST_INFINITY);
1104*61046927SAndroid Build Coastguard Worker 
1105*61046927SAndroid Build Coastguard Worker       BITSET_FOREACH_SET(i, blk->live_out, ctx->alloc)
1106*61046927SAndroid Build Coastguard Worker          assert(search_next_uses(&sb->next_use_out, i) < DIST_INFINITY);
1107*61046927SAndroid Build Coastguard Worker 
1108*61046927SAndroid Build Coastguard Worker       foreach_next_use(&sb->next_use_in, i, _)
1109*61046927SAndroid Build Coastguard Worker          assert(BITSET_TEST(blk->live_in, i));
1110*61046927SAndroid Build Coastguard Worker 
1111*61046927SAndroid Build Coastguard Worker       foreach_next_use(&sb->next_use_out, i, _)
1112*61046927SAndroid Build Coastguard Worker          assert(BITSET_TEST(blk->live_out, i));
1113*61046927SAndroid Build Coastguard Worker    }
1114*61046927SAndroid Build Coastguard Worker #endif
1115*61046927SAndroid Build Coastguard Worker }
1116*61046927SAndroid Build Coastguard Worker 
1117*61046927SAndroid Build Coastguard Worker void
agx_spill(agx_context * ctx,unsigned k)1118*61046927SAndroid Build Coastguard Worker agx_spill(agx_context *ctx, unsigned k)
1119*61046927SAndroid Build Coastguard Worker {
1120*61046927SAndroid Build Coastguard Worker    void *memctx = ralloc_context(NULL);
1121*61046927SAndroid Build Coastguard Worker 
1122*61046927SAndroid Build Coastguard Worker    /* Reserve the bottom registers as temporaries for memory-memory swaps */
1123*61046927SAndroid Build Coastguard Worker    ctx->has_spill_pcopy_reserved = true;
1124*61046927SAndroid Build Coastguard Worker    k -= 8;
1125*61046927SAndroid Build Coastguard Worker 
1126*61046927SAndroid Build Coastguard Worker    uint8_t *channels = rzalloc_array(memctx, uint8_t, ctx->alloc);
1127*61046927SAndroid Build Coastguard Worker    dist_t *next_uses = rzalloc_array(memctx, dist_t, ctx->alloc);
1128*61046927SAndroid Build Coastguard Worker    enum agx_size *sizes = rzalloc_array(memctx, enum agx_size, ctx->alloc);
1129*61046927SAndroid Build Coastguard Worker    agx_instr **remat = rzalloc_array(memctx, agx_instr *, ctx->alloc);
1130*61046927SAndroid Build Coastguard Worker 
1131*61046927SAndroid Build Coastguard Worker    agx_foreach_instr_global(ctx, I) {
1132*61046927SAndroid Build Coastguard Worker       if (can_remat(I))
1133*61046927SAndroid Build Coastguard Worker          remat[I->dest[0].value] = I;
1134*61046927SAndroid Build Coastguard Worker 
1135*61046927SAndroid Build Coastguard Worker       /* Measure vectors */
1136*61046927SAndroid Build Coastguard Worker       agx_foreach_ssa_dest(I, d) {
1137*61046927SAndroid Build Coastguard Worker          assert(sizes[I->dest[d].value] == 0 && "broken SSA");
1138*61046927SAndroid Build Coastguard Worker          assert(channels[I->dest[d].value] == 0 && "broken SSA");
1139*61046927SAndroid Build Coastguard Worker 
1140*61046927SAndroid Build Coastguard Worker          sizes[I->dest[d].value] = I->dest[d].size;
1141*61046927SAndroid Build Coastguard Worker          channels[I->dest[d].value] = agx_channels(I->dest[d]);
1142*61046927SAndroid Build Coastguard Worker       }
1143*61046927SAndroid Build Coastguard Worker    }
1144*61046927SAndroid Build Coastguard Worker 
1145*61046927SAndroid Build Coastguard Worker    struct spill_block *blocks =
1146*61046927SAndroid Build Coastguard Worker       rzalloc_array(memctx, struct spill_block, ctx->num_blocks);
1147*61046927SAndroid Build Coastguard Worker 
1148*61046927SAndroid Build Coastguard Worker    /* Step 1. Compute global next-use distances */
1149*61046927SAndroid Build Coastguard Worker    global_next_use_distances(ctx, memctx, blocks);
1150*61046927SAndroid Build Coastguard Worker    validate_next_use_info(ctx, blocks);
1151*61046927SAndroid Build Coastguard Worker 
1152*61046927SAndroid Build Coastguard Worker    /* Reserve a memory variable for every regular variable */
1153*61046927SAndroid Build Coastguard Worker    unsigned n = ctx->alloc;
1154*61046927SAndroid Build Coastguard Worker    ctx->alloc *= 2;
1155*61046927SAndroid Build Coastguard Worker 
1156*61046927SAndroid Build Coastguard Worker    BITSET_WORD *W = ralloc_array(memctx, BITSET_WORD, BITSET_WORDS(n));
1157*61046927SAndroid Build Coastguard Worker    BITSET_WORD *S = ralloc_array(memctx, BITSET_WORD, BITSET_WORDS(n));
1158*61046927SAndroid Build Coastguard Worker 
1159*61046927SAndroid Build Coastguard Worker    agx_foreach_block(ctx, block) {
1160*61046927SAndroid Build Coastguard Worker       memset(W, 0, BITSET_WORDS(n) * sizeof(BITSET_WORD));
1161*61046927SAndroid Build Coastguard Worker       memset(S, 0, BITSET_WORDS(n) * sizeof(BITSET_WORD));
1162*61046927SAndroid Build Coastguard Worker 
1163*61046927SAndroid Build Coastguard Worker       struct spill_ctx sctx = {
1164*61046927SAndroid Build Coastguard Worker          .memctx = memctx,
1165*61046927SAndroid Build Coastguard Worker          .shader = ctx,
1166*61046927SAndroid Build Coastguard Worker          .n = n,
1167*61046927SAndroid Build Coastguard Worker          .channels = channels,
1168*61046927SAndroid Build Coastguard Worker          .size = sizes,
1169*61046927SAndroid Build Coastguard Worker          .remat = remat,
1170*61046927SAndroid Build Coastguard Worker          .next_uses = next_uses,
1171*61046927SAndroid Build Coastguard Worker          .block = block,
1172*61046927SAndroid Build Coastguard Worker          .blocks = blocks,
1173*61046927SAndroid Build Coastguard Worker          .k = k,
1174*61046927SAndroid Build Coastguard Worker          .W = W,
1175*61046927SAndroid Build Coastguard Worker          .S = S,
1176*61046927SAndroid Build Coastguard Worker          .spill_base = n,
1177*61046927SAndroid Build Coastguard Worker       };
1178*61046927SAndroid Build Coastguard Worker 
1179*61046927SAndroid Build Coastguard Worker       compute_w_entry(&sctx);
1180*61046927SAndroid Build Coastguard Worker       compute_s_entry(&sctx);
1181*61046927SAndroid Build Coastguard Worker       min_algorithm(&sctx);
1182*61046927SAndroid Build Coastguard Worker    }
1183*61046927SAndroid Build Coastguard Worker 
1184*61046927SAndroid Build Coastguard Worker    /* Now that all blocks are processed separately, stitch it together */
1185*61046927SAndroid Build Coastguard Worker    agx_foreach_block(ctx, block) {
1186*61046927SAndroid Build Coastguard Worker       struct spill_ctx sctx = {
1187*61046927SAndroid Build Coastguard Worker          .memctx = memctx,
1188*61046927SAndroid Build Coastguard Worker          .shader = ctx,
1189*61046927SAndroid Build Coastguard Worker          .n = n,
1190*61046927SAndroid Build Coastguard Worker          .channels = channels,
1191*61046927SAndroid Build Coastguard Worker          .size = sizes,
1192*61046927SAndroid Build Coastguard Worker          .remat = remat,
1193*61046927SAndroid Build Coastguard Worker          .block = block,
1194*61046927SAndroid Build Coastguard Worker          .blocks = blocks,
1195*61046927SAndroid Build Coastguard Worker          .k = k,
1196*61046927SAndroid Build Coastguard Worker          .W = W,
1197*61046927SAndroid Build Coastguard Worker          .S = S,
1198*61046927SAndroid Build Coastguard Worker          .spill_base = n,
1199*61046927SAndroid Build Coastguard Worker       };
1200*61046927SAndroid Build Coastguard Worker 
1201*61046927SAndroid Build Coastguard Worker       agx_foreach_predecessor(block, pred) {
1202*61046927SAndroid Build Coastguard Worker          /* After spilling phi sources, insert coupling code */
1203*61046927SAndroid Build Coastguard Worker          insert_coupling_code(&sctx, *pred, block);
1204*61046927SAndroid Build Coastguard Worker       }
1205*61046927SAndroid Build Coastguard Worker    }
1206*61046927SAndroid Build Coastguard Worker 
1207*61046927SAndroid Build Coastguard Worker    ralloc_free(memctx);
1208*61046927SAndroid Build Coastguard Worker 
1209*61046927SAndroid Build Coastguard Worker    /* Spilling breaks SSA, so we need to repair before validating */
1210*61046927SAndroid Build Coastguard Worker    agx_repair_ssa(ctx);
1211*61046927SAndroid Build Coastguard Worker    agx_validate(ctx, "Spilling");
1212*61046927SAndroid Build Coastguard Worker 
1213*61046927SAndroid Build Coastguard Worker    /* Remat can introduce dead code */
1214*61046927SAndroid Build Coastguard Worker    agx_dce(ctx, false);
1215*61046927SAndroid Build Coastguard Worker }
1216