xref: /aosp_15_r20/external/mesa3d/src/compiler/nir/nir_schedule.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2019 Broadcom
3*61046927SAndroid Build Coastguard Worker  *
4*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker  *
11*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker  * Software.
14*61046927SAndroid Build Coastguard Worker  *
15*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker  * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker  */
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker #include "nir_schedule.h"
25*61046927SAndroid Build Coastguard Worker #include "util/dag.h"
26*61046927SAndroid Build Coastguard Worker #include "util/u_dynarray.h"
27*61046927SAndroid Build Coastguard Worker 
28*61046927SAndroid Build Coastguard Worker /** @file
29*61046927SAndroid Build Coastguard Worker  *
30*61046927SAndroid Build Coastguard Worker  * Implements basic-block-level prepass instruction scheduling in NIR to
31*61046927SAndroid Build Coastguard Worker  * manage register pressure.
32*61046927SAndroid Build Coastguard Worker  *
33*61046927SAndroid Build Coastguard Worker  * This is based on the Goodman/Hsu paper (1988, cached copy at
34*61046927SAndroid Build Coastguard Worker  * https://people.freedesktop.org/~anholt/scheduling-goodman-hsu.pdf).  We
35*61046927SAndroid Build Coastguard Worker  * make up the DDG for NIR (which can be mostly done using the NIR def/use
36*61046927SAndroid Build Coastguard Worker  * chains for SSA instructions, plus some edges for ordering register writes
37*61046927SAndroid Build Coastguard Worker  * vs reads, and some more for ordering intrinsics).  Then we pick heads off
38*61046927SAndroid Build Coastguard Worker  * of the DDG using their heuristic to emit the NIR instructions back into the
39*61046927SAndroid Build Coastguard Worker  * block in their new order.
40*61046927SAndroid Build Coastguard Worker  *
41*61046927SAndroid Build Coastguard Worker  * The hard case for prepass scheduling on GPUs seems to always be consuming
42*61046927SAndroid Build Coastguard Worker  * texture/ubo results.  The register pressure heuristic doesn't want to pick
43*61046927SAndroid Build Coastguard Worker  * an instr that starts consuming texture results because it usually won't be
44*61046927SAndroid Build Coastguard Worker  * the only usage, so that instruction will increase pressure.
45*61046927SAndroid Build Coastguard Worker  *
46*61046927SAndroid Build Coastguard Worker  * If you try to force consumption of tex results always, then in a case where
47*61046927SAndroid Build Coastguard Worker  * single sample is used for many outputs, you'll end up picking every other
48*61046927SAndroid Build Coastguard Worker  * user and expanding register pressure.  The partially_evaluated_path flag
49*61046927SAndroid Build Coastguard Worker  * helps tremendously, in that if you happen for whatever reason to pick a
50*61046927SAndroid Build Coastguard Worker  * texture sample's output, then you'll try to finish off that sample.  Future
51*61046927SAndroid Build Coastguard Worker  * work may include doing some local search before locking in a choice, to try
52*61046927SAndroid Build Coastguard Worker  * to more reliably find the case where just a few choices going against the
53*61046927SAndroid Build Coastguard Worker  * heuristic can manage to free the whole vector.
54*61046927SAndroid Build Coastguard Worker  */
55*61046927SAndroid Build Coastguard Worker 
56*61046927SAndroid Build Coastguard Worker static bool debug;
57*61046927SAndroid Build Coastguard Worker 
58*61046927SAndroid Build Coastguard Worker /**
59*61046927SAndroid Build Coastguard Worker  * Represents a node in the DDG for a NIR instruction.
60*61046927SAndroid Build Coastguard Worker  */
61*61046927SAndroid Build Coastguard Worker typedef struct {
62*61046927SAndroid Build Coastguard Worker    struct dag_node dag; /* must be first for our u_dynarray_foreach */
63*61046927SAndroid Build Coastguard Worker    nir_instr *instr;
64*61046927SAndroid Build Coastguard Worker    bool partially_evaluated_path;
65*61046927SAndroid Build Coastguard Worker 
66*61046927SAndroid Build Coastguard Worker    /* Approximate estimate of the delay between starting this instruction and
67*61046927SAndroid Build Coastguard Worker     * its results being available.
68*61046927SAndroid Build Coastguard Worker     *
69*61046927SAndroid Build Coastguard Worker     * Accuracy is not too important, given that we're prepass scheduling here
70*61046927SAndroid Build Coastguard Worker     * and just trying to reduce excess dependencies introduced by a register
71*61046927SAndroid Build Coastguard Worker     * allocator by stretching out the live intervals of expensive
72*61046927SAndroid Build Coastguard Worker     * instructions.
73*61046927SAndroid Build Coastguard Worker     */
74*61046927SAndroid Build Coastguard Worker    uint32_t delay;
75*61046927SAndroid Build Coastguard Worker 
76*61046927SAndroid Build Coastguard Worker    /* Cost of the maximum-delay path from this node to the leaves. */
77*61046927SAndroid Build Coastguard Worker    uint32_t max_delay;
78*61046927SAndroid Build Coastguard Worker 
79*61046927SAndroid Build Coastguard Worker    /* scoreboard->time value when this instruction can be scheduled without
80*61046927SAndroid Build Coastguard Worker     * any stalls expected.
81*61046927SAndroid Build Coastguard Worker     */
82*61046927SAndroid Build Coastguard Worker    uint32_t ready_time;
83*61046927SAndroid Build Coastguard Worker } nir_schedule_node;
84*61046927SAndroid Build Coastguard Worker 
85*61046927SAndroid Build Coastguard Worker typedef struct {
86*61046927SAndroid Build Coastguard Worker    struct dag *dag;
87*61046927SAndroid Build Coastguard Worker 
88*61046927SAndroid Build Coastguard Worker    nir_shader *shader;
89*61046927SAndroid Build Coastguard Worker 
90*61046927SAndroid Build Coastguard Worker    /* Mapping from nir_def * to a struct set of
91*61046927SAndroid Build Coastguard Worker     * instructions remaining to be scheduled using the register.
92*61046927SAndroid Build Coastguard Worker     */
93*61046927SAndroid Build Coastguard Worker    struct hash_table *remaining_uses;
94*61046927SAndroid Build Coastguard Worker 
95*61046927SAndroid Build Coastguard Worker    /* Map from nir_instr to nir_schedule_node * */
96*61046927SAndroid Build Coastguard Worker    struct hash_table *instr_map;
97*61046927SAndroid Build Coastguard Worker 
98*61046927SAndroid Build Coastguard Worker    /* Set of nir_def * that have had any instruction scheduled on them. */
99*61046927SAndroid Build Coastguard Worker    struct set *live_values;
100*61046927SAndroid Build Coastguard Worker 
101*61046927SAndroid Build Coastguard Worker    /* An abstract approximation of the number of nir_scheduler_node->delay
102*61046927SAndroid Build Coastguard Worker     * units since the start of the shader.
103*61046927SAndroid Build Coastguard Worker     */
104*61046927SAndroid Build Coastguard Worker    uint32_t time;
105*61046927SAndroid Build Coastguard Worker 
106*61046927SAndroid Build Coastguard Worker    /* Number of channels currently used by the NIR instructions that have been
107*61046927SAndroid Build Coastguard Worker     * scheduled.
108*61046927SAndroid Build Coastguard Worker     */
109*61046927SAndroid Build Coastguard Worker    int pressure;
110*61046927SAndroid Build Coastguard Worker 
111*61046927SAndroid Build Coastguard Worker    /* Options specified by the backend */
112*61046927SAndroid Build Coastguard Worker    const nir_schedule_options *options;
113*61046927SAndroid Build Coastguard Worker } nir_schedule_scoreboard;
114*61046927SAndroid Build Coastguard Worker 
115*61046927SAndroid Build Coastguard Worker /* When walking the instructions in reverse, we use this flag to swap
116*61046927SAndroid Build Coastguard Worker  * before/after in add_dep().
117*61046927SAndroid Build Coastguard Worker  */
118*61046927SAndroid Build Coastguard Worker enum direction { F,
119*61046927SAndroid Build Coastguard Worker                  R };
120*61046927SAndroid Build Coastguard Worker 
121*61046927SAndroid Build Coastguard Worker struct nir_schedule_class_dep {
122*61046927SAndroid Build Coastguard Worker    int klass;
123*61046927SAndroid Build Coastguard Worker    nir_schedule_node *node;
124*61046927SAndroid Build Coastguard Worker    struct nir_schedule_class_dep *next;
125*61046927SAndroid Build Coastguard Worker };
126*61046927SAndroid Build Coastguard Worker 
127*61046927SAndroid Build Coastguard Worker typedef struct {
128*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard;
129*61046927SAndroid Build Coastguard Worker 
130*61046927SAndroid Build Coastguard Worker    /* Map from registers to nir_schedule_node * */
131*61046927SAndroid Build Coastguard Worker    struct hash_table *reg_map;
132*61046927SAndroid Build Coastguard Worker 
133*61046927SAndroid Build Coastguard Worker    /* Scheduler nodes for last instruction involved in some class of dependency.
134*61046927SAndroid Build Coastguard Worker     */
135*61046927SAndroid Build Coastguard Worker    nir_schedule_node *load_input;
136*61046927SAndroid Build Coastguard Worker    nir_schedule_node *store_shared;
137*61046927SAndroid Build Coastguard Worker    nir_schedule_node *unknown_intrinsic;
138*61046927SAndroid Build Coastguard Worker    nir_schedule_node *discard;
139*61046927SAndroid Build Coastguard Worker    nir_schedule_node *jump;
140*61046927SAndroid Build Coastguard Worker 
141*61046927SAndroid Build Coastguard Worker    struct nir_schedule_class_dep *class_deps;
142*61046927SAndroid Build Coastguard Worker 
143*61046927SAndroid Build Coastguard Worker    enum direction dir;
144*61046927SAndroid Build Coastguard Worker } nir_deps_state;
145*61046927SAndroid Build Coastguard Worker 
146*61046927SAndroid Build Coastguard Worker static void *
_mesa_hash_table_search_data(struct hash_table * ht,void * key)147*61046927SAndroid Build Coastguard Worker _mesa_hash_table_search_data(struct hash_table *ht, void *key)
148*61046927SAndroid Build Coastguard Worker {
149*61046927SAndroid Build Coastguard Worker    struct hash_entry *entry = _mesa_hash_table_search(ht, key);
150*61046927SAndroid Build Coastguard Worker    if (!entry)
151*61046927SAndroid Build Coastguard Worker       return NULL;
152*61046927SAndroid Build Coastguard Worker    return entry->data;
153*61046927SAndroid Build Coastguard Worker }
154*61046927SAndroid Build Coastguard Worker 
155*61046927SAndroid Build Coastguard Worker static nir_schedule_node *
nir_schedule_get_node(struct hash_table * instr_map,nir_instr * instr)156*61046927SAndroid Build Coastguard Worker nir_schedule_get_node(struct hash_table *instr_map, nir_instr *instr)
157*61046927SAndroid Build Coastguard Worker {
158*61046927SAndroid Build Coastguard Worker    return _mesa_hash_table_search_data(instr_map, instr);
159*61046927SAndroid Build Coastguard Worker }
160*61046927SAndroid Build Coastguard Worker 
161*61046927SAndroid Build Coastguard Worker static struct set *
nir_schedule_scoreboard_get_reg(nir_schedule_scoreboard * scoreboard,nir_def * reg)162*61046927SAndroid Build Coastguard Worker nir_schedule_scoreboard_get_reg(nir_schedule_scoreboard *scoreboard,
163*61046927SAndroid Build Coastguard Worker                                 nir_def *reg)
164*61046927SAndroid Build Coastguard Worker {
165*61046927SAndroid Build Coastguard Worker    return _mesa_hash_table_search_data(scoreboard->remaining_uses, reg);
166*61046927SAndroid Build Coastguard Worker }
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker static struct set *
nir_schedule_scoreboard_get_src(nir_schedule_scoreboard * scoreboard,nir_src * src)169*61046927SAndroid Build Coastguard Worker nir_schedule_scoreboard_get_src(nir_schedule_scoreboard *scoreboard, nir_src *src)
170*61046927SAndroid Build Coastguard Worker {
171*61046927SAndroid Build Coastguard Worker    return _mesa_hash_table_search_data(scoreboard->remaining_uses, src->ssa);
172*61046927SAndroid Build Coastguard Worker }
173*61046927SAndroid Build Coastguard Worker 
174*61046927SAndroid Build Coastguard Worker static int
nir_schedule_reg_pressure(nir_def * reg)175*61046927SAndroid Build Coastguard Worker nir_schedule_reg_pressure(nir_def *reg)
176*61046927SAndroid Build Coastguard Worker {
177*61046927SAndroid Build Coastguard Worker    nir_intrinsic_instr *decl = nir_reg_get_decl(reg);
178*61046927SAndroid Build Coastguard Worker    return nir_intrinsic_num_components(decl);
179*61046927SAndroid Build Coastguard Worker }
180*61046927SAndroid Build Coastguard Worker 
181*61046927SAndroid Build Coastguard Worker static int
nir_schedule_def_pressure(nir_def * def)182*61046927SAndroid Build Coastguard Worker nir_schedule_def_pressure(nir_def *def)
183*61046927SAndroid Build Coastguard Worker {
184*61046927SAndroid Build Coastguard Worker    return def->num_components;
185*61046927SAndroid Build Coastguard Worker }
186*61046927SAndroid Build Coastguard Worker 
187*61046927SAndroid Build Coastguard Worker static int
nir_schedule_src_pressure(nir_src * src)188*61046927SAndroid Build Coastguard Worker nir_schedule_src_pressure(nir_src *src)
189*61046927SAndroid Build Coastguard Worker {
190*61046927SAndroid Build Coastguard Worker    return nir_schedule_def_pressure(src->ssa);
191*61046927SAndroid Build Coastguard Worker }
192*61046927SAndroid Build Coastguard Worker 
193*61046927SAndroid Build Coastguard Worker /**
194*61046927SAndroid Build Coastguard Worker  * Adds a dependency such that @after must appear in the final program after
195*61046927SAndroid Build Coastguard Worker  * @before.
196*61046927SAndroid Build Coastguard Worker  *
197*61046927SAndroid Build Coastguard Worker  * We add @before as a child of @after, so that DAG heads are the outputs of
198*61046927SAndroid Build Coastguard Worker  * the program and we make our scheduling decisions bottom to top.
199*61046927SAndroid Build Coastguard Worker  */
200*61046927SAndroid Build Coastguard Worker static void
add_dep(nir_deps_state * state,nir_schedule_node * before,nir_schedule_node * after)201*61046927SAndroid Build Coastguard Worker add_dep(nir_deps_state *state,
202*61046927SAndroid Build Coastguard Worker         nir_schedule_node *before,
203*61046927SAndroid Build Coastguard Worker         nir_schedule_node *after)
204*61046927SAndroid Build Coastguard Worker {
205*61046927SAndroid Build Coastguard Worker    if (!before || !after)
206*61046927SAndroid Build Coastguard Worker       return;
207*61046927SAndroid Build Coastguard Worker 
208*61046927SAndroid Build Coastguard Worker    assert(before != after);
209*61046927SAndroid Build Coastguard Worker 
210*61046927SAndroid Build Coastguard Worker    if (state->dir == F)
211*61046927SAndroid Build Coastguard Worker       dag_add_edge(&before->dag, &after->dag, 0);
212*61046927SAndroid Build Coastguard Worker    else
213*61046927SAndroid Build Coastguard Worker       dag_add_edge(&after->dag, &before->dag, 0);
214*61046927SAndroid Build Coastguard Worker }
215*61046927SAndroid Build Coastguard Worker 
216*61046927SAndroid Build Coastguard Worker static void
add_read_dep(nir_deps_state * state,nir_schedule_node * before,nir_schedule_node * after)217*61046927SAndroid Build Coastguard Worker add_read_dep(nir_deps_state *state,
218*61046927SAndroid Build Coastguard Worker              nir_schedule_node *before,
219*61046927SAndroid Build Coastguard Worker              nir_schedule_node *after)
220*61046927SAndroid Build Coastguard Worker {
221*61046927SAndroid Build Coastguard Worker    add_dep(state, before, after);
222*61046927SAndroid Build Coastguard Worker }
223*61046927SAndroid Build Coastguard Worker 
224*61046927SAndroid Build Coastguard Worker static void
add_write_dep(nir_deps_state * state,nir_schedule_node ** before,nir_schedule_node * after)225*61046927SAndroid Build Coastguard Worker add_write_dep(nir_deps_state *state,
226*61046927SAndroid Build Coastguard Worker               nir_schedule_node **before,
227*61046927SAndroid Build Coastguard Worker               nir_schedule_node *after)
228*61046927SAndroid Build Coastguard Worker {
229*61046927SAndroid Build Coastguard Worker    add_dep(state, *before, after);
230*61046927SAndroid Build Coastguard Worker    *before = after;
231*61046927SAndroid Build Coastguard Worker }
232*61046927SAndroid Build Coastguard Worker 
233*61046927SAndroid Build Coastguard Worker static void
nir_schedule_load_reg_deps(nir_intrinsic_instr * load,nir_deps_state * state)234*61046927SAndroid Build Coastguard Worker nir_schedule_load_reg_deps(nir_intrinsic_instr *load,
235*61046927SAndroid Build Coastguard Worker                            nir_deps_state *state)
236*61046927SAndroid Build Coastguard Worker {
237*61046927SAndroid Build Coastguard Worker    nir_def *reg = load->src[0].ssa;
238*61046927SAndroid Build Coastguard Worker    (void)nir_reg_get_decl(reg);
239*61046927SAndroid Build Coastguard Worker 
240*61046927SAndroid Build Coastguard Worker    struct hash_entry *entry = _mesa_hash_table_search(state->reg_map, reg);
241*61046927SAndroid Build Coastguard Worker    if (!entry)
242*61046927SAndroid Build Coastguard Worker       return;
243*61046927SAndroid Build Coastguard Worker    nir_schedule_node *dst_n = entry->data;
244*61046927SAndroid Build Coastguard Worker 
245*61046927SAndroid Build Coastguard Worker    nir_schedule_node *src_n =
246*61046927SAndroid Build Coastguard Worker       nir_schedule_get_node(state->scoreboard->instr_map, &load->instr);
247*61046927SAndroid Build Coastguard Worker 
248*61046927SAndroid Build Coastguard Worker    add_dep(state, dst_n, src_n);
249*61046927SAndroid Build Coastguard Worker }
250*61046927SAndroid Build Coastguard Worker 
251*61046927SAndroid Build Coastguard Worker static void
nir_schedule_store_reg_deps(nir_intrinsic_instr * store,nir_deps_state * state)252*61046927SAndroid Build Coastguard Worker nir_schedule_store_reg_deps(nir_intrinsic_instr *store,
253*61046927SAndroid Build Coastguard Worker                             nir_deps_state *state)
254*61046927SAndroid Build Coastguard Worker {
255*61046927SAndroid Build Coastguard Worker    nir_def *reg = store->src[1].ssa;
256*61046927SAndroid Build Coastguard Worker    (void)nir_reg_get_decl(reg);
257*61046927SAndroid Build Coastguard Worker 
258*61046927SAndroid Build Coastguard Worker    nir_schedule_node *dest_n =
259*61046927SAndroid Build Coastguard Worker       nir_schedule_get_node(state->scoreboard->instr_map, &store->instr);
260*61046927SAndroid Build Coastguard Worker 
261*61046927SAndroid Build Coastguard Worker    struct hash_entry *entry = _mesa_hash_table_search(state->reg_map, reg);
262*61046927SAndroid Build Coastguard Worker    if (!entry) {
263*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_insert(state->reg_map, reg, dest_n);
264*61046927SAndroid Build Coastguard Worker       return;
265*61046927SAndroid Build Coastguard Worker    }
266*61046927SAndroid Build Coastguard Worker    nir_schedule_node **before = (nir_schedule_node **)&entry->data;
267*61046927SAndroid Build Coastguard Worker 
268*61046927SAndroid Build Coastguard Worker    add_write_dep(state, before, dest_n);
269*61046927SAndroid Build Coastguard Worker }
270*61046927SAndroid Build Coastguard Worker 
271*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_ssa_deps(nir_def * def,void * in_state)272*61046927SAndroid Build Coastguard Worker nir_schedule_ssa_deps(nir_def *def, void *in_state)
273*61046927SAndroid Build Coastguard Worker {
274*61046927SAndroid Build Coastguard Worker    nir_deps_state *state = in_state;
275*61046927SAndroid Build Coastguard Worker    struct hash_table *instr_map = state->scoreboard->instr_map;
276*61046927SAndroid Build Coastguard Worker    nir_schedule_node *def_n = nir_schedule_get_node(instr_map, def->parent_instr);
277*61046927SAndroid Build Coastguard Worker 
278*61046927SAndroid Build Coastguard Worker    nir_foreach_use(src, def) {
279*61046927SAndroid Build Coastguard Worker       nir_schedule_node *use_n = nir_schedule_get_node(instr_map,
280*61046927SAndroid Build Coastguard Worker                                                        nir_src_parent_instr(src));
281*61046927SAndroid Build Coastguard Worker 
282*61046927SAndroid Build Coastguard Worker       add_read_dep(state, def_n, use_n);
283*61046927SAndroid Build Coastguard Worker    }
284*61046927SAndroid Build Coastguard Worker 
285*61046927SAndroid Build Coastguard Worker    return true;
286*61046927SAndroid Build Coastguard Worker }
287*61046927SAndroid Build Coastguard Worker 
288*61046927SAndroid Build Coastguard Worker static struct nir_schedule_class_dep *
nir_schedule_get_class_dep(nir_deps_state * state,int klass)289*61046927SAndroid Build Coastguard Worker nir_schedule_get_class_dep(nir_deps_state *state,
290*61046927SAndroid Build Coastguard Worker                            int klass)
291*61046927SAndroid Build Coastguard Worker {
292*61046927SAndroid Build Coastguard Worker    for (struct nir_schedule_class_dep *class_dep = state->class_deps;
293*61046927SAndroid Build Coastguard Worker         class_dep != NULL;
294*61046927SAndroid Build Coastguard Worker         class_dep = class_dep->next) {
295*61046927SAndroid Build Coastguard Worker       if (class_dep->klass == klass)
296*61046927SAndroid Build Coastguard Worker          return class_dep;
297*61046927SAndroid Build Coastguard Worker    }
298*61046927SAndroid Build Coastguard Worker 
299*61046927SAndroid Build Coastguard Worker    struct nir_schedule_class_dep *class_dep =
300*61046927SAndroid Build Coastguard Worker       ralloc(state->reg_map, struct nir_schedule_class_dep);
301*61046927SAndroid Build Coastguard Worker 
302*61046927SAndroid Build Coastguard Worker    class_dep->klass = klass;
303*61046927SAndroid Build Coastguard Worker    class_dep->node = NULL;
304*61046927SAndroid Build Coastguard Worker    class_dep->next = state->class_deps;
305*61046927SAndroid Build Coastguard Worker 
306*61046927SAndroid Build Coastguard Worker    state->class_deps = class_dep;
307*61046927SAndroid Build Coastguard Worker 
308*61046927SAndroid Build Coastguard Worker    return class_dep;
309*61046927SAndroid Build Coastguard Worker }
310*61046927SAndroid Build Coastguard Worker 
311*61046927SAndroid Build Coastguard Worker static void
nir_schedule_intrinsic_deps(nir_deps_state * state,nir_intrinsic_instr * instr)312*61046927SAndroid Build Coastguard Worker nir_schedule_intrinsic_deps(nir_deps_state *state,
313*61046927SAndroid Build Coastguard Worker                             nir_intrinsic_instr *instr)
314*61046927SAndroid Build Coastguard Worker {
315*61046927SAndroid Build Coastguard Worker    nir_schedule_node *n = nir_schedule_get_node(state->scoreboard->instr_map,
316*61046927SAndroid Build Coastguard Worker                                                 &instr->instr);
317*61046927SAndroid Build Coastguard Worker    const nir_schedule_options *options = state->scoreboard->options;
318*61046927SAndroid Build Coastguard Worker    nir_schedule_dependency dep;
319*61046927SAndroid Build Coastguard Worker 
320*61046927SAndroid Build Coastguard Worker    if (options->intrinsic_cb &&
321*61046927SAndroid Build Coastguard Worker        options->intrinsic_cb(instr, &dep, options->intrinsic_cb_data)) {
322*61046927SAndroid Build Coastguard Worker       struct nir_schedule_class_dep *class_dep =
323*61046927SAndroid Build Coastguard Worker          nir_schedule_get_class_dep(state, dep.klass);
324*61046927SAndroid Build Coastguard Worker 
325*61046927SAndroid Build Coastguard Worker       switch (dep.type) {
326*61046927SAndroid Build Coastguard Worker       case NIR_SCHEDULE_READ_DEPENDENCY:
327*61046927SAndroid Build Coastguard Worker          add_read_dep(state, class_dep->node, n);
328*61046927SAndroid Build Coastguard Worker          break;
329*61046927SAndroid Build Coastguard Worker       case NIR_SCHEDULE_WRITE_DEPENDENCY:
330*61046927SAndroid Build Coastguard Worker          add_write_dep(state, &class_dep->node, n);
331*61046927SAndroid Build Coastguard Worker          break;
332*61046927SAndroid Build Coastguard Worker       }
333*61046927SAndroid Build Coastguard Worker    }
334*61046927SAndroid Build Coastguard Worker 
335*61046927SAndroid Build Coastguard Worker    switch (instr->intrinsic) {
336*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_decl_reg:
337*61046927SAndroid Build Coastguard Worker       break; /* Nothing to do */
338*61046927SAndroid Build Coastguard Worker 
339*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_reg:
340*61046927SAndroid Build Coastguard Worker       nir_schedule_load_reg_deps(instr, state);
341*61046927SAndroid Build Coastguard Worker       break;
342*61046927SAndroid Build Coastguard Worker 
343*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_reg:
344*61046927SAndroid Build Coastguard Worker       nir_schedule_store_reg_deps(instr, state);
345*61046927SAndroid Build Coastguard Worker       break;
346*61046927SAndroid Build Coastguard Worker 
347*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_uniform:
348*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_ubo:
349*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_front_face:
350*61046927SAndroid Build Coastguard Worker       break;
351*61046927SAndroid Build Coastguard Worker 
352*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_demote:
353*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_demote_if:
354*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_terminate:
355*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_terminate_if:
356*61046927SAndroid Build Coastguard Worker       /* We are adding two dependencies:
357*61046927SAndroid Build Coastguard Worker        *
358*61046927SAndroid Build Coastguard Worker        * * A individual one that we could use to add a read_dep while handling
359*61046927SAndroid Build Coastguard Worker        *   nir_instr_type_tex
360*61046927SAndroid Build Coastguard Worker        *
361*61046927SAndroid Build Coastguard Worker        * * Include it on the unknown intrinsic set, as we want discard to be
362*61046927SAndroid Build Coastguard Worker        *   serialized in in the same order relative to intervening stores or
363*61046927SAndroid Build Coastguard Worker        *   atomic accesses to SSBOs and images
364*61046927SAndroid Build Coastguard Worker        */
365*61046927SAndroid Build Coastguard Worker       add_write_dep(state, &state->discard, n);
366*61046927SAndroid Build Coastguard Worker       add_write_dep(state, &state->unknown_intrinsic, n);
367*61046927SAndroid Build Coastguard Worker       break;
368*61046927SAndroid Build Coastguard Worker 
369*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_output:
370*61046927SAndroid Build Coastguard Worker       /* For some hardware and stages, output stores affect the same shared
371*61046927SAndroid Build Coastguard Worker        * memory as input loads.
372*61046927SAndroid Build Coastguard Worker        */
373*61046927SAndroid Build Coastguard Worker       if ((state->scoreboard->options->stages_with_shared_io_memory &
374*61046927SAndroid Build Coastguard Worker            (1 << state->scoreboard->shader->info.stage)))
375*61046927SAndroid Build Coastguard Worker          add_write_dep(state, &state->load_input, n);
376*61046927SAndroid Build Coastguard Worker 
377*61046927SAndroid Build Coastguard Worker       /* Make sure that preceding discards stay before the store_output */
378*61046927SAndroid Build Coastguard Worker       add_read_dep(state, state->discard, n);
379*61046927SAndroid Build Coastguard Worker 
380*61046927SAndroid Build Coastguard Worker       break;
381*61046927SAndroid Build Coastguard Worker 
382*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_input:
383*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_per_primitive_input:
384*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_per_vertex_input:
385*61046927SAndroid Build Coastguard Worker       add_read_dep(state, state->load_input, n);
386*61046927SAndroid Build Coastguard Worker       break;
387*61046927SAndroid Build Coastguard Worker 
388*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_shared:
389*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_shared2_amd:
390*61046927SAndroid Build Coastguard Worker       /* Don't move load_shared beyond a following store_shared, as it could
391*61046927SAndroid Build Coastguard Worker        * change their value
392*61046927SAndroid Build Coastguard Worker        */
393*61046927SAndroid Build Coastguard Worker       add_read_dep(state, state->store_shared, n);
394*61046927SAndroid Build Coastguard Worker       break;
395*61046927SAndroid Build Coastguard Worker 
396*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_shared_atomic:
397*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_shared_atomic_swap:
398*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_shared_append_amd:
399*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_shared_consume_amd:
400*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_shared:
401*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_shared2_amd:
402*61046927SAndroid Build Coastguard Worker       add_write_dep(state, &state->store_shared, n);
403*61046927SAndroid Build Coastguard Worker       break;
404*61046927SAndroid Build Coastguard Worker 
405*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_barrier: {
406*61046927SAndroid Build Coastguard Worker       const nir_variable_mode modes = nir_intrinsic_memory_modes(instr);
407*61046927SAndroid Build Coastguard Worker 
408*61046927SAndroid Build Coastguard Worker       if (modes & nir_var_mem_shared)
409*61046927SAndroid Build Coastguard Worker          add_write_dep(state, &state->store_shared, n);
410*61046927SAndroid Build Coastguard Worker 
411*61046927SAndroid Build Coastguard Worker       /* Serialize against other categories. */
412*61046927SAndroid Build Coastguard Worker       add_write_dep(state, &state->unknown_intrinsic, n);
413*61046927SAndroid Build Coastguard Worker 
414*61046927SAndroid Build Coastguard Worker       break;
415*61046927SAndroid Build Coastguard Worker    }
416*61046927SAndroid Build Coastguard Worker 
417*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_ddx:
418*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_ddx_fine:
419*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_ddx_coarse:
420*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_ddy:
421*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_ddy_fine:
422*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_ddy_coarse:
423*61046927SAndroid Build Coastguard Worker       /* Match the old behaviour. TODO: Is this correct with discards? */
424*61046927SAndroid Build Coastguard Worker       break;
425*61046927SAndroid Build Coastguard Worker 
426*61046927SAndroid Build Coastguard Worker    default:
427*61046927SAndroid Build Coastguard Worker       /* Attempt to handle other intrinsics that we haven't individually
428*61046927SAndroid Build Coastguard Worker        * categorized by serializing them in the same order relative to each
429*61046927SAndroid Build Coastguard Worker        * other.
430*61046927SAndroid Build Coastguard Worker        */
431*61046927SAndroid Build Coastguard Worker       add_write_dep(state, &state->unknown_intrinsic, n);
432*61046927SAndroid Build Coastguard Worker       break;
433*61046927SAndroid Build Coastguard Worker    }
434*61046927SAndroid Build Coastguard Worker }
435*61046927SAndroid Build Coastguard Worker 
436*61046927SAndroid Build Coastguard Worker /**
437*61046927SAndroid Build Coastguard Worker  * Common code for dependencies that need to be tracked both forward and
438*61046927SAndroid Build Coastguard Worker  * backward.
439*61046927SAndroid Build Coastguard Worker  *
440*61046927SAndroid Build Coastguard Worker  * This is for things like "all reads of r4 have to happen between the r4
441*61046927SAndroid Build Coastguard Worker  * writes that surround them".
442*61046927SAndroid Build Coastguard Worker  */
443*61046927SAndroid Build Coastguard Worker static void
nir_schedule_calculate_deps(nir_deps_state * state,nir_schedule_node * n)444*61046927SAndroid Build Coastguard Worker nir_schedule_calculate_deps(nir_deps_state *state, nir_schedule_node *n)
445*61046927SAndroid Build Coastguard Worker {
446*61046927SAndroid Build Coastguard Worker    nir_instr *instr = n->instr;
447*61046927SAndroid Build Coastguard Worker 
448*61046927SAndroid Build Coastguard Worker    /* For NIR SSA defs, we only need to do a single pass of making the uses
449*61046927SAndroid Build Coastguard Worker     * depend on the def.
450*61046927SAndroid Build Coastguard Worker     */
451*61046927SAndroid Build Coastguard Worker    if (state->dir == F)
452*61046927SAndroid Build Coastguard Worker       nir_foreach_def(instr, nir_schedule_ssa_deps, state);
453*61046927SAndroid Build Coastguard Worker 
454*61046927SAndroid Build Coastguard Worker    /* Make sure any other instructions keep their positions relative to
455*61046927SAndroid Build Coastguard Worker     * jumps.
456*61046927SAndroid Build Coastguard Worker     */
457*61046927SAndroid Build Coastguard Worker    if (instr->type != nir_instr_type_jump)
458*61046927SAndroid Build Coastguard Worker       add_read_dep(state, state->jump, n);
459*61046927SAndroid Build Coastguard Worker 
460*61046927SAndroid Build Coastguard Worker    switch (instr->type) {
461*61046927SAndroid Build Coastguard Worker    case nir_instr_type_undef:
462*61046927SAndroid Build Coastguard Worker    case nir_instr_type_load_const:
463*61046927SAndroid Build Coastguard Worker    case nir_instr_type_alu:
464*61046927SAndroid Build Coastguard Worker    case nir_instr_type_deref:
465*61046927SAndroid Build Coastguard Worker    case nir_instr_type_debug_info:
466*61046927SAndroid Build Coastguard Worker       break;
467*61046927SAndroid Build Coastguard Worker 
468*61046927SAndroid Build Coastguard Worker    case nir_instr_type_tex:
469*61046927SAndroid Build Coastguard Worker       /* Don't move texture ops before a discard, as that could increase
470*61046927SAndroid Build Coastguard Worker        * memory bandwidth for reading the discarded samples.
471*61046927SAndroid Build Coastguard Worker        */
472*61046927SAndroid Build Coastguard Worker       add_read_dep(state, state->discard, n);
473*61046927SAndroid Build Coastguard Worker       break;
474*61046927SAndroid Build Coastguard Worker 
475*61046927SAndroid Build Coastguard Worker    case nir_instr_type_jump:
476*61046927SAndroid Build Coastguard Worker       add_write_dep(state, &state->jump, n);
477*61046927SAndroid Build Coastguard Worker       break;
478*61046927SAndroid Build Coastguard Worker 
479*61046927SAndroid Build Coastguard Worker    case nir_instr_type_call:
480*61046927SAndroid Build Coastguard Worker       unreachable("Calls should have been lowered");
481*61046927SAndroid Build Coastguard Worker       break;
482*61046927SAndroid Build Coastguard Worker 
483*61046927SAndroid Build Coastguard Worker    case nir_instr_type_parallel_copy:
484*61046927SAndroid Build Coastguard Worker       unreachable("Parallel copies should have been lowered");
485*61046927SAndroid Build Coastguard Worker       break;
486*61046927SAndroid Build Coastguard Worker 
487*61046927SAndroid Build Coastguard Worker    case nir_instr_type_phi:
488*61046927SAndroid Build Coastguard Worker       unreachable("nir_schedule() should be called after lowering from SSA");
489*61046927SAndroid Build Coastguard Worker       break;
490*61046927SAndroid Build Coastguard Worker 
491*61046927SAndroid Build Coastguard Worker    case nir_instr_type_intrinsic:
492*61046927SAndroid Build Coastguard Worker       nir_schedule_intrinsic_deps(state, nir_instr_as_intrinsic(instr));
493*61046927SAndroid Build Coastguard Worker       break;
494*61046927SAndroid Build Coastguard Worker    }
495*61046927SAndroid Build Coastguard Worker }
496*61046927SAndroid Build Coastguard Worker 
497*61046927SAndroid Build Coastguard Worker static void
calculate_forward_deps(nir_schedule_scoreboard * scoreboard,nir_block * block)498*61046927SAndroid Build Coastguard Worker calculate_forward_deps(nir_schedule_scoreboard *scoreboard, nir_block *block)
499*61046927SAndroid Build Coastguard Worker {
500*61046927SAndroid Build Coastguard Worker    nir_deps_state state = {
501*61046927SAndroid Build Coastguard Worker       .scoreboard = scoreboard,
502*61046927SAndroid Build Coastguard Worker       .dir = F,
503*61046927SAndroid Build Coastguard Worker       .reg_map = _mesa_pointer_hash_table_create(NULL),
504*61046927SAndroid Build Coastguard Worker    };
505*61046927SAndroid Build Coastguard Worker 
506*61046927SAndroid Build Coastguard Worker    nir_foreach_instr(instr, block) {
507*61046927SAndroid Build Coastguard Worker       nir_schedule_node *node = nir_schedule_get_node(scoreboard->instr_map,
508*61046927SAndroid Build Coastguard Worker                                                       instr);
509*61046927SAndroid Build Coastguard Worker       nir_schedule_calculate_deps(&state, node);
510*61046927SAndroid Build Coastguard Worker    }
511*61046927SAndroid Build Coastguard Worker 
512*61046927SAndroid Build Coastguard Worker    ralloc_free(state.reg_map);
513*61046927SAndroid Build Coastguard Worker }
514*61046927SAndroid Build Coastguard Worker 
515*61046927SAndroid Build Coastguard Worker static void
calculate_reverse_deps(nir_schedule_scoreboard * scoreboard,nir_block * block)516*61046927SAndroid Build Coastguard Worker calculate_reverse_deps(nir_schedule_scoreboard *scoreboard, nir_block *block)
517*61046927SAndroid Build Coastguard Worker {
518*61046927SAndroid Build Coastguard Worker    nir_deps_state state = {
519*61046927SAndroid Build Coastguard Worker       .scoreboard = scoreboard,
520*61046927SAndroid Build Coastguard Worker       .dir = R,
521*61046927SAndroid Build Coastguard Worker       .reg_map = _mesa_pointer_hash_table_create(NULL),
522*61046927SAndroid Build Coastguard Worker    };
523*61046927SAndroid Build Coastguard Worker 
524*61046927SAndroid Build Coastguard Worker    nir_foreach_instr_reverse(instr, block) {
525*61046927SAndroid Build Coastguard Worker       nir_schedule_node *node = nir_schedule_get_node(scoreboard->instr_map,
526*61046927SAndroid Build Coastguard Worker                                                       instr);
527*61046927SAndroid Build Coastguard Worker       nir_schedule_calculate_deps(&state, node);
528*61046927SAndroid Build Coastguard Worker    }
529*61046927SAndroid Build Coastguard Worker 
530*61046927SAndroid Build Coastguard Worker    ralloc_free(state.reg_map);
531*61046927SAndroid Build Coastguard Worker }
532*61046927SAndroid Build Coastguard Worker 
533*61046927SAndroid Build Coastguard Worker typedef struct {
534*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard;
535*61046927SAndroid Build Coastguard Worker    int regs_freed;
536*61046927SAndroid Build Coastguard Worker } nir_schedule_regs_freed_state;
537*61046927SAndroid Build Coastguard Worker 
538*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_regs_freed_src_cb(nir_src * src,void * in_state)539*61046927SAndroid Build Coastguard Worker nir_schedule_regs_freed_src_cb(nir_src *src, void *in_state)
540*61046927SAndroid Build Coastguard Worker {
541*61046927SAndroid Build Coastguard Worker    nir_schedule_regs_freed_state *state = in_state;
542*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = state->scoreboard;
543*61046927SAndroid Build Coastguard Worker    struct set *remaining_uses = nir_schedule_scoreboard_get_src(scoreboard, src);
544*61046927SAndroid Build Coastguard Worker 
545*61046927SAndroid Build Coastguard Worker    if (remaining_uses->entries == 1 &&
546*61046927SAndroid Build Coastguard Worker        _mesa_set_search(remaining_uses, nir_src_parent_instr(src))) {
547*61046927SAndroid Build Coastguard Worker       state->regs_freed += nir_schedule_src_pressure(src);
548*61046927SAndroid Build Coastguard Worker    }
549*61046927SAndroid Build Coastguard Worker 
550*61046927SAndroid Build Coastguard Worker    return true;
551*61046927SAndroid Build Coastguard Worker }
552*61046927SAndroid Build Coastguard Worker 
553*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_regs_freed_def_cb(nir_def * def,void * in_state)554*61046927SAndroid Build Coastguard Worker nir_schedule_regs_freed_def_cb(nir_def *def, void *in_state)
555*61046927SAndroid Build Coastguard Worker {
556*61046927SAndroid Build Coastguard Worker    nir_schedule_regs_freed_state *state = in_state;
557*61046927SAndroid Build Coastguard Worker 
558*61046927SAndroid Build Coastguard Worker    state->regs_freed -= nir_schedule_def_pressure(def);
559*61046927SAndroid Build Coastguard Worker 
560*61046927SAndroid Build Coastguard Worker    return true;
561*61046927SAndroid Build Coastguard Worker }
562*61046927SAndroid Build Coastguard Worker 
563*61046927SAndroid Build Coastguard Worker static void
nir_schedule_regs_freed_load_reg(nir_intrinsic_instr * load,nir_schedule_regs_freed_state * state)564*61046927SAndroid Build Coastguard Worker nir_schedule_regs_freed_load_reg(nir_intrinsic_instr *load,
565*61046927SAndroid Build Coastguard Worker                                  nir_schedule_regs_freed_state *state)
566*61046927SAndroid Build Coastguard Worker {
567*61046927SAndroid Build Coastguard Worker    assert(nir_is_load_reg(load));
568*61046927SAndroid Build Coastguard Worker 
569*61046927SAndroid Build Coastguard Worker    if (load->intrinsic == nir_intrinsic_load_reg_indirect)
570*61046927SAndroid Build Coastguard Worker       nir_schedule_regs_freed_src_cb(&load->src[1], state);
571*61046927SAndroid Build Coastguard Worker 
572*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = state->scoreboard;
573*61046927SAndroid Build Coastguard Worker    nir_def *reg = load->src[0].ssa;
574*61046927SAndroid Build Coastguard Worker    struct set *remaining_uses = nir_schedule_scoreboard_get_reg(scoreboard, reg);
575*61046927SAndroid Build Coastguard Worker 
576*61046927SAndroid Build Coastguard Worker    if (remaining_uses->entries == 1 &&
577*61046927SAndroid Build Coastguard Worker        _mesa_set_search(remaining_uses, &load->instr)) {
578*61046927SAndroid Build Coastguard Worker       state->regs_freed += nir_schedule_reg_pressure(reg);
579*61046927SAndroid Build Coastguard Worker    }
580*61046927SAndroid Build Coastguard Worker 
581*61046927SAndroid Build Coastguard Worker    nir_schedule_regs_freed_def_cb(&load->def, state);
582*61046927SAndroid Build Coastguard Worker }
583*61046927SAndroid Build Coastguard Worker 
584*61046927SAndroid Build Coastguard Worker static void
nir_schedule_regs_freed_store_reg(nir_intrinsic_instr * store,nir_schedule_regs_freed_state * state)585*61046927SAndroid Build Coastguard Worker nir_schedule_regs_freed_store_reg(nir_intrinsic_instr *store,
586*61046927SAndroid Build Coastguard Worker                                   nir_schedule_regs_freed_state *state)
587*61046927SAndroid Build Coastguard Worker {
588*61046927SAndroid Build Coastguard Worker    assert(nir_is_store_reg(store));
589*61046927SAndroid Build Coastguard Worker 
590*61046927SAndroid Build Coastguard Worker    nir_schedule_regs_freed_src_cb(&store->src[0], state);
591*61046927SAndroid Build Coastguard Worker    if (store->intrinsic == nir_intrinsic_store_reg_indirect)
592*61046927SAndroid Build Coastguard Worker       nir_schedule_regs_freed_src_cb(&store->src[2], state);
593*61046927SAndroid Build Coastguard Worker 
594*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = state->scoreboard;
595*61046927SAndroid Build Coastguard Worker    nir_def *reg = store->src[1].ssa;
596*61046927SAndroid Build Coastguard Worker 
597*61046927SAndroid Build Coastguard Worker    /* Only the first def of a reg counts against register pressure. */
598*61046927SAndroid Build Coastguard Worker    if (!_mesa_set_search(scoreboard->live_values, reg))
599*61046927SAndroid Build Coastguard Worker       state->regs_freed -= nir_schedule_reg_pressure(reg);
600*61046927SAndroid Build Coastguard Worker }
601*61046927SAndroid Build Coastguard Worker 
602*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_regs_freed_reg_intrin(nir_instr * instr,nir_schedule_regs_freed_state * state)603*61046927SAndroid Build Coastguard Worker nir_schedule_regs_freed_reg_intrin(nir_instr *instr,
604*61046927SAndroid Build Coastguard Worker                                    nir_schedule_regs_freed_state *state)
605*61046927SAndroid Build Coastguard Worker {
606*61046927SAndroid Build Coastguard Worker    if (instr->type != nir_instr_type_intrinsic)
607*61046927SAndroid Build Coastguard Worker       return false;
608*61046927SAndroid Build Coastguard Worker 
609*61046927SAndroid Build Coastguard Worker    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
610*61046927SAndroid Build Coastguard Worker    switch (intrin->intrinsic) {
611*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_decl_reg:
612*61046927SAndroid Build Coastguard Worker       return true; /* Handled but nothing to do */
613*61046927SAndroid Build Coastguard Worker 
614*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_reg:
615*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_reg_indirect:
616*61046927SAndroid Build Coastguard Worker       nir_schedule_regs_freed_load_reg(intrin, state);
617*61046927SAndroid Build Coastguard Worker       return true;
618*61046927SAndroid Build Coastguard Worker 
619*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_reg:
620*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_reg_indirect:
621*61046927SAndroid Build Coastguard Worker       nir_schedule_regs_freed_store_reg(intrin, state);
622*61046927SAndroid Build Coastguard Worker       return true;
623*61046927SAndroid Build Coastguard Worker 
624*61046927SAndroid Build Coastguard Worker    default:
625*61046927SAndroid Build Coastguard Worker       return false;
626*61046927SAndroid Build Coastguard Worker    }
627*61046927SAndroid Build Coastguard Worker }
628*61046927SAndroid Build Coastguard Worker 
629*61046927SAndroid Build Coastguard Worker static int
nir_schedule_regs_freed(nir_schedule_scoreboard * scoreboard,nir_schedule_node * n)630*61046927SAndroid Build Coastguard Worker nir_schedule_regs_freed(nir_schedule_scoreboard *scoreboard, nir_schedule_node *n)
631*61046927SAndroid Build Coastguard Worker {
632*61046927SAndroid Build Coastguard Worker    nir_schedule_regs_freed_state state = {
633*61046927SAndroid Build Coastguard Worker       .scoreboard = scoreboard,
634*61046927SAndroid Build Coastguard Worker    };
635*61046927SAndroid Build Coastguard Worker 
636*61046927SAndroid Build Coastguard Worker    if (!nir_schedule_regs_freed_reg_intrin(n->instr, &state)) {
637*61046927SAndroid Build Coastguard Worker       nir_foreach_src(n->instr, nir_schedule_regs_freed_src_cb, &state);
638*61046927SAndroid Build Coastguard Worker       nir_foreach_def(n->instr, nir_schedule_regs_freed_def_cb, &state);
639*61046927SAndroid Build Coastguard Worker    }
640*61046927SAndroid Build Coastguard Worker 
641*61046927SAndroid Build Coastguard Worker    return state.regs_freed;
642*61046927SAndroid Build Coastguard Worker }
643*61046927SAndroid Build Coastguard Worker 
644*61046927SAndroid Build Coastguard Worker /**
645*61046927SAndroid Build Coastguard Worker  * Chooses an instruction that will minimise the register pressure as much as
646*61046927SAndroid Build Coastguard Worker  * possible. This should only be used as a fallback when the regular scheduling
647*61046927SAndroid Build Coastguard Worker  * generates a shader whose register allocation fails.
648*61046927SAndroid Build Coastguard Worker  */
649*61046927SAndroid Build Coastguard Worker static nir_schedule_node *
nir_schedule_choose_instruction_fallback(nir_schedule_scoreboard * scoreboard)650*61046927SAndroid Build Coastguard Worker nir_schedule_choose_instruction_fallback(nir_schedule_scoreboard *scoreboard)
651*61046927SAndroid Build Coastguard Worker {
652*61046927SAndroid Build Coastguard Worker    nir_schedule_node *chosen = NULL;
653*61046927SAndroid Build Coastguard Worker 
654*61046927SAndroid Build Coastguard Worker    /* Find the leader in the ready (shouldn't-stall) set with the mininum
655*61046927SAndroid Build Coastguard Worker     * cost.
656*61046927SAndroid Build Coastguard Worker     */
657*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
658*61046927SAndroid Build Coastguard Worker       if (scoreboard->time < n->ready_time)
659*61046927SAndroid Build Coastguard Worker          continue;
660*61046927SAndroid Build Coastguard Worker 
661*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay > n->max_delay)
662*61046927SAndroid Build Coastguard Worker          chosen = n;
663*61046927SAndroid Build Coastguard Worker    }
664*61046927SAndroid Build Coastguard Worker    if (chosen) {
665*61046927SAndroid Build Coastguard Worker       if (debug) {
666*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (ready fallback):          ");
667*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
668*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
669*61046927SAndroid Build Coastguard Worker       }
670*61046927SAndroid Build Coastguard Worker 
671*61046927SAndroid Build Coastguard Worker       return chosen;
672*61046927SAndroid Build Coastguard Worker    }
673*61046927SAndroid Build Coastguard Worker 
674*61046927SAndroid Build Coastguard Worker    /* Otherwise, choose the leader with the minimum cost. */
675*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
676*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay > n->max_delay)
677*61046927SAndroid Build Coastguard Worker          chosen = n;
678*61046927SAndroid Build Coastguard Worker    }
679*61046927SAndroid Build Coastguard Worker    if (debug) {
680*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "chose (leader fallback):         ");
681*61046927SAndroid Build Coastguard Worker       nir_print_instr(chosen->instr, stderr);
682*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "\n");
683*61046927SAndroid Build Coastguard Worker    }
684*61046927SAndroid Build Coastguard Worker 
685*61046927SAndroid Build Coastguard Worker    return chosen;
686*61046927SAndroid Build Coastguard Worker }
687*61046927SAndroid Build Coastguard Worker 
688*61046927SAndroid Build Coastguard Worker /**
689*61046927SAndroid Build Coastguard Worker  * Chooses an instruction to schedule using the Goodman/Hsu (1988) CSP (Code
690*61046927SAndroid Build Coastguard Worker  * Scheduling for Parallelism) heuristic.
691*61046927SAndroid Build Coastguard Worker  *
692*61046927SAndroid Build Coastguard Worker  * Picks an instruction on the critical that's ready to execute without
693*61046927SAndroid Build Coastguard Worker  * stalls, if possible, otherwise picks the instruction on the critical path.
694*61046927SAndroid Build Coastguard Worker  */
695*61046927SAndroid Build Coastguard Worker static nir_schedule_node *
nir_schedule_choose_instruction_csp(nir_schedule_scoreboard * scoreboard)696*61046927SAndroid Build Coastguard Worker nir_schedule_choose_instruction_csp(nir_schedule_scoreboard *scoreboard)
697*61046927SAndroid Build Coastguard Worker {
698*61046927SAndroid Build Coastguard Worker    nir_schedule_node *chosen = NULL;
699*61046927SAndroid Build Coastguard Worker 
700*61046927SAndroid Build Coastguard Worker    /* Find the leader in the ready (shouldn't-stall) set with the maximum
701*61046927SAndroid Build Coastguard Worker     * cost.
702*61046927SAndroid Build Coastguard Worker     */
703*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
704*61046927SAndroid Build Coastguard Worker       if (scoreboard->time < n->ready_time)
705*61046927SAndroid Build Coastguard Worker          continue;
706*61046927SAndroid Build Coastguard Worker 
707*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay < n->max_delay)
708*61046927SAndroid Build Coastguard Worker          chosen = n;
709*61046927SAndroid Build Coastguard Worker    }
710*61046927SAndroid Build Coastguard Worker    if (chosen) {
711*61046927SAndroid Build Coastguard Worker       if (debug) {
712*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (ready):          ");
713*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
714*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
715*61046927SAndroid Build Coastguard Worker       }
716*61046927SAndroid Build Coastguard Worker 
717*61046927SAndroid Build Coastguard Worker       return chosen;
718*61046927SAndroid Build Coastguard Worker    }
719*61046927SAndroid Build Coastguard Worker 
720*61046927SAndroid Build Coastguard Worker    /* Otherwise, choose the leader with the maximum cost. */
721*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
722*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay < n->max_delay)
723*61046927SAndroid Build Coastguard Worker          chosen = n;
724*61046927SAndroid Build Coastguard Worker    }
725*61046927SAndroid Build Coastguard Worker    if (debug) {
726*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "chose (leader):         ");
727*61046927SAndroid Build Coastguard Worker       nir_print_instr(chosen->instr, stderr);
728*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "\n");
729*61046927SAndroid Build Coastguard Worker    }
730*61046927SAndroid Build Coastguard Worker 
731*61046927SAndroid Build Coastguard Worker    return chosen;
732*61046927SAndroid Build Coastguard Worker }
733*61046927SAndroid Build Coastguard Worker 
734*61046927SAndroid Build Coastguard Worker /**
735*61046927SAndroid Build Coastguard Worker  * Chooses an instruction to schedule using the Goodman/Hsu (1988) CSR (Code
736*61046927SAndroid Build Coastguard Worker  * Scheduling for Register pressure) heuristic.
737*61046927SAndroid Build Coastguard Worker  */
738*61046927SAndroid Build Coastguard Worker static nir_schedule_node *
nir_schedule_choose_instruction_csr(nir_schedule_scoreboard * scoreboard)739*61046927SAndroid Build Coastguard Worker nir_schedule_choose_instruction_csr(nir_schedule_scoreboard *scoreboard)
740*61046927SAndroid Build Coastguard Worker {
741*61046927SAndroid Build Coastguard Worker    nir_schedule_node *chosen = NULL;
742*61046927SAndroid Build Coastguard Worker 
743*61046927SAndroid Build Coastguard Worker    /* Find a ready inst with regs freed and pick the one with max cost. */
744*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
745*61046927SAndroid Build Coastguard Worker       if (n->ready_time > scoreboard->time)
746*61046927SAndroid Build Coastguard Worker          continue;
747*61046927SAndroid Build Coastguard Worker 
748*61046927SAndroid Build Coastguard Worker       int regs_freed = nir_schedule_regs_freed(scoreboard, n);
749*61046927SAndroid Build Coastguard Worker 
750*61046927SAndroid Build Coastguard Worker       if (regs_freed > 0 && (!chosen || chosen->max_delay < n->max_delay)) {
751*61046927SAndroid Build Coastguard Worker          chosen = n;
752*61046927SAndroid Build Coastguard Worker       }
753*61046927SAndroid Build Coastguard Worker    }
754*61046927SAndroid Build Coastguard Worker    if (chosen) {
755*61046927SAndroid Build Coastguard Worker       if (debug) {
756*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (freed+ready):    ");
757*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
758*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
759*61046927SAndroid Build Coastguard Worker       }
760*61046927SAndroid Build Coastguard Worker 
761*61046927SAndroid Build Coastguard Worker       return chosen;
762*61046927SAndroid Build Coastguard Worker    }
763*61046927SAndroid Build Coastguard Worker 
764*61046927SAndroid Build Coastguard Worker    /* Find a leader with regs freed and pick the one with max cost. */
765*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
766*61046927SAndroid Build Coastguard Worker       int regs_freed = nir_schedule_regs_freed(scoreboard, n);
767*61046927SAndroid Build Coastguard Worker 
768*61046927SAndroid Build Coastguard Worker       if (regs_freed > 0 && (!chosen || chosen->max_delay < n->max_delay)) {
769*61046927SAndroid Build Coastguard Worker          chosen = n;
770*61046927SAndroid Build Coastguard Worker       }
771*61046927SAndroid Build Coastguard Worker    }
772*61046927SAndroid Build Coastguard Worker    if (chosen) {
773*61046927SAndroid Build Coastguard Worker       if (debug) {
774*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (regs freed):     ");
775*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
776*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
777*61046927SAndroid Build Coastguard Worker       }
778*61046927SAndroid Build Coastguard Worker 
779*61046927SAndroid Build Coastguard Worker       return chosen;
780*61046927SAndroid Build Coastguard Worker    }
781*61046927SAndroid Build Coastguard Worker 
782*61046927SAndroid Build Coastguard Worker    /* Find a partially evaluated path and try to finish it off */
783*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
784*61046927SAndroid Build Coastguard Worker       if (n->partially_evaluated_path &&
785*61046927SAndroid Build Coastguard Worker           (!chosen || chosen->max_delay < n->max_delay)) {
786*61046927SAndroid Build Coastguard Worker          chosen = n;
787*61046927SAndroid Build Coastguard Worker       }
788*61046927SAndroid Build Coastguard Worker    }
789*61046927SAndroid Build Coastguard Worker    if (chosen) {
790*61046927SAndroid Build Coastguard Worker       if (debug) {
791*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (partial path):   ");
792*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
793*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
794*61046927SAndroid Build Coastguard Worker       }
795*61046927SAndroid Build Coastguard Worker 
796*61046927SAndroid Build Coastguard Worker       return chosen;
797*61046927SAndroid Build Coastguard Worker    }
798*61046927SAndroid Build Coastguard Worker 
799*61046927SAndroid Build Coastguard Worker    /* Contra the paper, pick a leader with no effect on used regs.  This may
800*61046927SAndroid Build Coastguard Worker     * open up new opportunities, as otherwise a single-operand instr consuming
801*61046927SAndroid Build Coastguard Worker     * a value will tend to block finding freeing that value.  This had a
802*61046927SAndroid Build Coastguard Worker     * massive effect on reducing spilling on V3D.
803*61046927SAndroid Build Coastguard Worker     *
804*61046927SAndroid Build Coastguard Worker     * XXX: Should this prioritize ready?
805*61046927SAndroid Build Coastguard Worker     */
806*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
807*61046927SAndroid Build Coastguard Worker       if (nir_schedule_regs_freed(scoreboard, n) != 0)
808*61046927SAndroid Build Coastguard Worker          continue;
809*61046927SAndroid Build Coastguard Worker 
810*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay < n->max_delay)
811*61046927SAndroid Build Coastguard Worker          chosen = n;
812*61046927SAndroid Build Coastguard Worker    }
813*61046927SAndroid Build Coastguard Worker    if (chosen) {
814*61046927SAndroid Build Coastguard Worker       if (debug) {
815*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (regs no-op):     ");
816*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
817*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
818*61046927SAndroid Build Coastguard Worker       }
819*61046927SAndroid Build Coastguard Worker 
820*61046927SAndroid Build Coastguard Worker       return chosen;
821*61046927SAndroid Build Coastguard Worker    }
822*61046927SAndroid Build Coastguard Worker 
823*61046927SAndroid Build Coastguard Worker    /* Pick the max delay of the remaining ready set. */
824*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
825*61046927SAndroid Build Coastguard Worker       if (n->ready_time > scoreboard->time)
826*61046927SAndroid Build Coastguard Worker          continue;
827*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay < n->max_delay)
828*61046927SAndroid Build Coastguard Worker          chosen = n;
829*61046927SAndroid Build Coastguard Worker    }
830*61046927SAndroid Build Coastguard Worker    if (chosen) {
831*61046927SAndroid Build Coastguard Worker       if (debug) {
832*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "chose (ready max delay):   ");
833*61046927SAndroid Build Coastguard Worker          nir_print_instr(chosen->instr, stderr);
834*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
835*61046927SAndroid Build Coastguard Worker       }
836*61046927SAndroid Build Coastguard Worker       return chosen;
837*61046927SAndroid Build Coastguard Worker    }
838*61046927SAndroid Build Coastguard Worker 
839*61046927SAndroid Build Coastguard Worker    /* Pick the max delay of the remaining leaders. */
840*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
841*61046927SAndroid Build Coastguard Worker       if (!chosen || chosen->max_delay < n->max_delay)
842*61046927SAndroid Build Coastguard Worker          chosen = n;
843*61046927SAndroid Build Coastguard Worker    }
844*61046927SAndroid Build Coastguard Worker 
845*61046927SAndroid Build Coastguard Worker    if (debug) {
846*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "chose (max delay):         ");
847*61046927SAndroid Build Coastguard Worker       nir_print_instr(chosen->instr, stderr);
848*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "\n");
849*61046927SAndroid Build Coastguard Worker    }
850*61046927SAndroid Build Coastguard Worker 
851*61046927SAndroid Build Coastguard Worker    return chosen;
852*61046927SAndroid Build Coastguard Worker }
853*61046927SAndroid Build Coastguard Worker 
854*61046927SAndroid Build Coastguard Worker static void
dump_state(nir_schedule_scoreboard * scoreboard)855*61046927SAndroid Build Coastguard Worker dump_state(nir_schedule_scoreboard *scoreboard)
856*61046927SAndroid Build Coastguard Worker {
857*61046927SAndroid Build Coastguard Worker    list_for_each_entry(nir_schedule_node, n, &scoreboard->dag->heads, dag.link) {
858*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "maxdel %5d ", n->max_delay);
859*61046927SAndroid Build Coastguard Worker       nir_print_instr(n->instr, stderr);
860*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "\n");
861*61046927SAndroid Build Coastguard Worker 
862*61046927SAndroid Build Coastguard Worker       util_dynarray_foreach(&n->dag.edges, struct dag_edge, edge) {
863*61046927SAndroid Build Coastguard Worker          nir_schedule_node *child = (nir_schedule_node *)edge->child;
864*61046927SAndroid Build Coastguard Worker 
865*61046927SAndroid Build Coastguard Worker          fprintf(stderr, " -> (%d parents) ", child->dag.parent_count);
866*61046927SAndroid Build Coastguard Worker          nir_print_instr(child->instr, stderr);
867*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
868*61046927SAndroid Build Coastguard Worker       }
869*61046927SAndroid Build Coastguard Worker    }
870*61046927SAndroid Build Coastguard Worker }
871*61046927SAndroid Build Coastguard Worker 
872*61046927SAndroid Build Coastguard Worker static void
nir_schedule_mark_use(nir_schedule_scoreboard * scoreboard,void * reg_or_def,nir_instr * reg_or_def_parent,int pressure)873*61046927SAndroid Build Coastguard Worker nir_schedule_mark_use(nir_schedule_scoreboard *scoreboard,
874*61046927SAndroid Build Coastguard Worker                       void *reg_or_def,
875*61046927SAndroid Build Coastguard Worker                       nir_instr *reg_or_def_parent,
876*61046927SAndroid Build Coastguard Worker                       int pressure)
877*61046927SAndroid Build Coastguard Worker {
878*61046927SAndroid Build Coastguard Worker    /* Make the value live if it's the first time it's been used. */
879*61046927SAndroid Build Coastguard Worker    if (!_mesa_set_search(scoreboard->live_values, reg_or_def)) {
880*61046927SAndroid Build Coastguard Worker       _mesa_set_add(scoreboard->live_values, reg_or_def);
881*61046927SAndroid Build Coastguard Worker       scoreboard->pressure += pressure;
882*61046927SAndroid Build Coastguard Worker    }
883*61046927SAndroid Build Coastguard Worker 
884*61046927SAndroid Build Coastguard Worker    /* Make the value dead if it's the last remaining use.  Be careful when one
885*61046927SAndroid Build Coastguard Worker     * instruction uses a value twice to not decrement pressure twice.
886*61046927SAndroid Build Coastguard Worker     */
887*61046927SAndroid Build Coastguard Worker    struct set *remaining_uses =
888*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_search_data(scoreboard->remaining_uses, reg_or_def);
889*61046927SAndroid Build Coastguard Worker    struct set_entry *entry = _mesa_set_search(remaining_uses, reg_or_def_parent);
890*61046927SAndroid Build Coastguard Worker    if (entry) {
891*61046927SAndroid Build Coastguard Worker       _mesa_set_remove(remaining_uses, entry);
892*61046927SAndroid Build Coastguard Worker 
893*61046927SAndroid Build Coastguard Worker       if (remaining_uses->entries == 0)
894*61046927SAndroid Build Coastguard Worker          scoreboard->pressure -= pressure;
895*61046927SAndroid Build Coastguard Worker    }
896*61046927SAndroid Build Coastguard Worker }
897*61046927SAndroid Build Coastguard Worker 
898*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_mark_src_scheduled(nir_src * src,void * state)899*61046927SAndroid Build Coastguard Worker nir_schedule_mark_src_scheduled(nir_src *src, void *state)
900*61046927SAndroid Build Coastguard Worker {
901*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = state;
902*61046927SAndroid Build Coastguard Worker    struct set *remaining_uses = nir_schedule_scoreboard_get_src(scoreboard, src);
903*61046927SAndroid Build Coastguard Worker 
904*61046927SAndroid Build Coastguard Worker    struct set_entry *entry = _mesa_set_search(remaining_uses,
905*61046927SAndroid Build Coastguard Worker                                               nir_src_parent_instr(src));
906*61046927SAndroid Build Coastguard Worker    if (entry) {
907*61046927SAndroid Build Coastguard Worker       /* Once we've used an SSA value in one instruction, bump the priority of
908*61046927SAndroid Build Coastguard Worker        * the other uses so the SSA value can get fully consumed.
909*61046927SAndroid Build Coastguard Worker        *
910*61046927SAndroid Build Coastguard Worker        * We don't do this for registers, and it's would be a hassle and it's
911*61046927SAndroid Build Coastguard Worker        * unclear if that would help or not.  Also, skip it for constants, as
912*61046927SAndroid Build Coastguard Worker        * they're often folded as immediates into backend instructions and have
913*61046927SAndroid Build Coastguard Worker        * many unrelated instructions all referencing the same value (0).
914*61046927SAndroid Build Coastguard Worker        */
915*61046927SAndroid Build Coastguard Worker       if (src->ssa->parent_instr->type != nir_instr_type_load_const) {
916*61046927SAndroid Build Coastguard Worker          nir_foreach_use(other_src, src->ssa) {
917*61046927SAndroid Build Coastguard Worker             if (nir_src_parent_instr(other_src) == nir_src_parent_instr(src))
918*61046927SAndroid Build Coastguard Worker                continue;
919*61046927SAndroid Build Coastguard Worker 
920*61046927SAndroid Build Coastguard Worker             nir_schedule_node *n =
921*61046927SAndroid Build Coastguard Worker                nir_schedule_get_node(scoreboard->instr_map,
922*61046927SAndroid Build Coastguard Worker                                      nir_src_parent_instr(other_src));
923*61046927SAndroid Build Coastguard Worker 
924*61046927SAndroid Build Coastguard Worker             if (n && !n->partially_evaluated_path) {
925*61046927SAndroid Build Coastguard Worker                if (debug) {
926*61046927SAndroid Build Coastguard Worker                   fprintf(stderr, "  New partially evaluated path: ");
927*61046927SAndroid Build Coastguard Worker                   nir_print_instr(n->instr, stderr);
928*61046927SAndroid Build Coastguard Worker                   fprintf(stderr, "\n");
929*61046927SAndroid Build Coastguard Worker                }
930*61046927SAndroid Build Coastguard Worker 
931*61046927SAndroid Build Coastguard Worker                n->partially_evaluated_path = true;
932*61046927SAndroid Build Coastguard Worker             }
933*61046927SAndroid Build Coastguard Worker          }
934*61046927SAndroid Build Coastguard Worker       }
935*61046927SAndroid Build Coastguard Worker    }
936*61046927SAndroid Build Coastguard Worker 
937*61046927SAndroid Build Coastguard Worker    nir_schedule_mark_use(scoreboard,
938*61046927SAndroid Build Coastguard Worker                          (void *)src->ssa,
939*61046927SAndroid Build Coastguard Worker                          nir_src_parent_instr(src),
940*61046927SAndroid Build Coastguard Worker                          nir_schedule_src_pressure(src));
941*61046927SAndroid Build Coastguard Worker 
942*61046927SAndroid Build Coastguard Worker    return true;
943*61046927SAndroid Build Coastguard Worker }
944*61046927SAndroid Build Coastguard Worker 
945*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_mark_def_scheduled(nir_def * def,void * state)946*61046927SAndroid Build Coastguard Worker nir_schedule_mark_def_scheduled(nir_def *def, void *state)
947*61046927SAndroid Build Coastguard Worker {
948*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = state;
949*61046927SAndroid Build Coastguard Worker 
950*61046927SAndroid Build Coastguard Worker    nir_schedule_mark_use(scoreboard, def, def->parent_instr,
951*61046927SAndroid Build Coastguard Worker                          nir_schedule_def_pressure(def));
952*61046927SAndroid Build Coastguard Worker 
953*61046927SAndroid Build Coastguard Worker    return true;
954*61046927SAndroid Build Coastguard Worker }
955*61046927SAndroid Build Coastguard Worker 
956*61046927SAndroid Build Coastguard Worker static void
nir_schedule_mark_load_reg_scheduled(nir_intrinsic_instr * load,nir_schedule_scoreboard * scoreboard)957*61046927SAndroid Build Coastguard Worker nir_schedule_mark_load_reg_scheduled(nir_intrinsic_instr *load,
958*61046927SAndroid Build Coastguard Worker                                      nir_schedule_scoreboard *scoreboard)
959*61046927SAndroid Build Coastguard Worker {
960*61046927SAndroid Build Coastguard Worker    assert(nir_is_load_reg(load));
961*61046927SAndroid Build Coastguard Worker    nir_def *reg = load->src[0].ssa;
962*61046927SAndroid Build Coastguard Worker 
963*61046927SAndroid Build Coastguard Worker    if (load->intrinsic == nir_intrinsic_load_reg_indirect)
964*61046927SAndroid Build Coastguard Worker       nir_schedule_mark_src_scheduled(&load->src[1], scoreboard);
965*61046927SAndroid Build Coastguard Worker 
966*61046927SAndroid Build Coastguard Worker    nir_schedule_mark_use(scoreboard, reg, &load->instr,
967*61046927SAndroid Build Coastguard Worker                          nir_schedule_reg_pressure(reg));
968*61046927SAndroid Build Coastguard Worker 
969*61046927SAndroid Build Coastguard Worker    nir_schedule_mark_def_scheduled(&load->def, scoreboard);
970*61046927SAndroid Build Coastguard Worker }
971*61046927SAndroid Build Coastguard Worker 
972*61046927SAndroid Build Coastguard Worker static void
nir_schedule_mark_store_reg_scheduled(nir_intrinsic_instr * store,nir_schedule_scoreboard * scoreboard)973*61046927SAndroid Build Coastguard Worker nir_schedule_mark_store_reg_scheduled(nir_intrinsic_instr *store,
974*61046927SAndroid Build Coastguard Worker                                       nir_schedule_scoreboard *scoreboard)
975*61046927SAndroid Build Coastguard Worker {
976*61046927SAndroid Build Coastguard Worker    assert(nir_is_store_reg(store));
977*61046927SAndroid Build Coastguard Worker    nir_def *reg = store->src[1].ssa;
978*61046927SAndroid Build Coastguard Worker 
979*61046927SAndroid Build Coastguard Worker    nir_schedule_mark_src_scheduled(&store->src[0], scoreboard);
980*61046927SAndroid Build Coastguard Worker    if (store->intrinsic == nir_intrinsic_store_reg_indirect)
981*61046927SAndroid Build Coastguard Worker       nir_schedule_mark_src_scheduled(&store->src[2], scoreboard);
982*61046927SAndroid Build Coastguard Worker 
983*61046927SAndroid Build Coastguard Worker    /* XXX: This is not actually accurate for regs -- the last use of a reg may
984*61046927SAndroid Build Coastguard Worker     * have a live interval that extends across control flow.  We should
985*61046927SAndroid Build Coastguard Worker     * calculate the live ranges of regs, and have scheduler nodes for the CF
986*61046927SAndroid Build Coastguard Worker     * nodes that also "use" the reg.
987*61046927SAndroid Build Coastguard Worker     */
988*61046927SAndroid Build Coastguard Worker    nir_schedule_mark_use(scoreboard, reg, &store->instr,
989*61046927SAndroid Build Coastguard Worker                          nir_schedule_reg_pressure(reg));
990*61046927SAndroid Build Coastguard Worker }
991*61046927SAndroid Build Coastguard Worker 
992*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_mark_reg_intrin_scheduled(nir_instr * instr,nir_schedule_scoreboard * scoreboard)993*61046927SAndroid Build Coastguard Worker nir_schedule_mark_reg_intrin_scheduled(nir_instr *instr,
994*61046927SAndroid Build Coastguard Worker                                        nir_schedule_scoreboard *scoreboard)
995*61046927SAndroid Build Coastguard Worker {
996*61046927SAndroid Build Coastguard Worker    if (instr->type != nir_instr_type_intrinsic)
997*61046927SAndroid Build Coastguard Worker       return false;
998*61046927SAndroid Build Coastguard Worker 
999*61046927SAndroid Build Coastguard Worker    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
1000*61046927SAndroid Build Coastguard Worker    switch (intrin->intrinsic) {
1001*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_decl_reg:
1002*61046927SAndroid Build Coastguard Worker       return true; /* Handled but nothing to do */
1003*61046927SAndroid Build Coastguard Worker 
1004*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_reg:
1005*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_load_reg_indirect:
1006*61046927SAndroid Build Coastguard Worker       nir_schedule_mark_load_reg_scheduled(intrin, scoreboard);
1007*61046927SAndroid Build Coastguard Worker       return true;
1008*61046927SAndroid Build Coastguard Worker 
1009*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_reg:
1010*61046927SAndroid Build Coastguard Worker    case nir_intrinsic_store_reg_indirect:
1011*61046927SAndroid Build Coastguard Worker       nir_schedule_mark_store_reg_scheduled(intrin, scoreboard);
1012*61046927SAndroid Build Coastguard Worker       return true;
1013*61046927SAndroid Build Coastguard Worker 
1014*61046927SAndroid Build Coastguard Worker    default:
1015*61046927SAndroid Build Coastguard Worker       return false;
1016*61046927SAndroid Build Coastguard Worker    }
1017*61046927SAndroid Build Coastguard Worker }
1018*61046927SAndroid Build Coastguard Worker 
1019*61046927SAndroid Build Coastguard Worker static void
nir_schedule_mark_node_scheduled(nir_schedule_scoreboard * scoreboard,nir_schedule_node * n)1020*61046927SAndroid Build Coastguard Worker nir_schedule_mark_node_scheduled(nir_schedule_scoreboard *scoreboard,
1021*61046927SAndroid Build Coastguard Worker                                  nir_schedule_node *n)
1022*61046927SAndroid Build Coastguard Worker {
1023*61046927SAndroid Build Coastguard Worker    if (!nir_schedule_mark_reg_intrin_scheduled(n->instr, scoreboard)) {
1024*61046927SAndroid Build Coastguard Worker       nir_foreach_src(n->instr, nir_schedule_mark_src_scheduled, scoreboard);
1025*61046927SAndroid Build Coastguard Worker       nir_foreach_def(n->instr, nir_schedule_mark_def_scheduled, scoreboard);
1026*61046927SAndroid Build Coastguard Worker    }
1027*61046927SAndroid Build Coastguard Worker 
1028*61046927SAndroid Build Coastguard Worker    util_dynarray_foreach(&n->dag.edges, struct dag_edge, edge) {
1029*61046927SAndroid Build Coastguard Worker       nir_schedule_node *child = (nir_schedule_node *)edge->child;
1030*61046927SAndroid Build Coastguard Worker 
1031*61046927SAndroid Build Coastguard Worker       child->ready_time = MAX2(child->ready_time,
1032*61046927SAndroid Build Coastguard Worker                                scoreboard->time + n->delay);
1033*61046927SAndroid Build Coastguard Worker 
1034*61046927SAndroid Build Coastguard Worker       if (child->dag.parent_count == 1) {
1035*61046927SAndroid Build Coastguard Worker          if (debug) {
1036*61046927SAndroid Build Coastguard Worker             fprintf(stderr, "  New DAG head: ");
1037*61046927SAndroid Build Coastguard Worker             nir_print_instr(child->instr, stderr);
1038*61046927SAndroid Build Coastguard Worker             fprintf(stderr, "\n");
1039*61046927SAndroid Build Coastguard Worker          }
1040*61046927SAndroid Build Coastguard Worker       }
1041*61046927SAndroid Build Coastguard Worker    }
1042*61046927SAndroid Build Coastguard Worker 
1043*61046927SAndroid Build Coastguard Worker    dag_prune_head(scoreboard->dag, &n->dag);
1044*61046927SAndroid Build Coastguard Worker 
1045*61046927SAndroid Build Coastguard Worker    scoreboard->time = MAX2(n->ready_time, scoreboard->time);
1046*61046927SAndroid Build Coastguard Worker    scoreboard->time++;
1047*61046927SAndroid Build Coastguard Worker }
1048*61046927SAndroid Build Coastguard Worker 
1049*61046927SAndroid Build Coastguard Worker static void
nir_schedule_instructions(nir_schedule_scoreboard * scoreboard,nir_block * block)1050*61046927SAndroid Build Coastguard Worker nir_schedule_instructions(nir_schedule_scoreboard *scoreboard, nir_block *block)
1051*61046927SAndroid Build Coastguard Worker {
1052*61046927SAndroid Build Coastguard Worker    while (!list_is_empty(&scoreboard->dag->heads)) {
1053*61046927SAndroid Build Coastguard Worker       if (debug) {
1054*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "current list:\n");
1055*61046927SAndroid Build Coastguard Worker          dump_state(scoreboard);
1056*61046927SAndroid Build Coastguard Worker       }
1057*61046927SAndroid Build Coastguard Worker 
1058*61046927SAndroid Build Coastguard Worker       nir_schedule_node *chosen;
1059*61046927SAndroid Build Coastguard Worker       if (scoreboard->options->fallback)
1060*61046927SAndroid Build Coastguard Worker          chosen = nir_schedule_choose_instruction_fallback(scoreboard);
1061*61046927SAndroid Build Coastguard Worker       else if (scoreboard->pressure < scoreboard->options->threshold)
1062*61046927SAndroid Build Coastguard Worker          chosen = nir_schedule_choose_instruction_csp(scoreboard);
1063*61046927SAndroid Build Coastguard Worker       else
1064*61046927SAndroid Build Coastguard Worker          chosen = nir_schedule_choose_instruction_csr(scoreboard);
1065*61046927SAndroid Build Coastguard Worker 
1066*61046927SAndroid Build Coastguard Worker       /* Now that we've scheduled a new instruction, some of its children may
1067*61046927SAndroid Build Coastguard Worker        * be promoted to the list of instructions ready to be scheduled.
1068*61046927SAndroid Build Coastguard Worker        */
1069*61046927SAndroid Build Coastguard Worker       nir_schedule_mark_node_scheduled(scoreboard, chosen);
1070*61046927SAndroid Build Coastguard Worker 
1071*61046927SAndroid Build Coastguard Worker       /* Move the instruction to the end (so our first chosen instructions are
1072*61046927SAndroid Build Coastguard Worker        * the start of the program).
1073*61046927SAndroid Build Coastguard Worker        */
1074*61046927SAndroid Build Coastguard Worker       exec_node_remove(&chosen->instr->node);
1075*61046927SAndroid Build Coastguard Worker       exec_list_push_tail(&block->instr_list, &chosen->instr->node);
1076*61046927SAndroid Build Coastguard Worker 
1077*61046927SAndroid Build Coastguard Worker       if (debug)
1078*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
1079*61046927SAndroid Build Coastguard Worker    }
1080*61046927SAndroid Build Coastguard Worker }
1081*61046927SAndroid Build Coastguard Worker 
1082*61046927SAndroid Build Coastguard Worker static uint32_t
nir_schedule_get_delay(nir_schedule_scoreboard * scoreboard,nir_instr * instr)1083*61046927SAndroid Build Coastguard Worker nir_schedule_get_delay(nir_schedule_scoreboard *scoreboard, nir_instr *instr)
1084*61046927SAndroid Build Coastguard Worker {
1085*61046927SAndroid Build Coastguard Worker    if (scoreboard->options->instr_delay_cb) {
1086*61046927SAndroid Build Coastguard Worker       void *cb_data = scoreboard->options->instr_delay_cb_data;
1087*61046927SAndroid Build Coastguard Worker       return scoreboard->options->instr_delay_cb(instr, cb_data);
1088*61046927SAndroid Build Coastguard Worker    }
1089*61046927SAndroid Build Coastguard Worker 
1090*61046927SAndroid Build Coastguard Worker    switch (instr->type) {
1091*61046927SAndroid Build Coastguard Worker    case nir_instr_type_undef:
1092*61046927SAndroid Build Coastguard Worker    case nir_instr_type_load_const:
1093*61046927SAndroid Build Coastguard Worker    case nir_instr_type_alu:
1094*61046927SAndroid Build Coastguard Worker    case nir_instr_type_deref:
1095*61046927SAndroid Build Coastguard Worker    case nir_instr_type_jump:
1096*61046927SAndroid Build Coastguard Worker    case nir_instr_type_parallel_copy:
1097*61046927SAndroid Build Coastguard Worker    case nir_instr_type_call:
1098*61046927SAndroid Build Coastguard Worker    case nir_instr_type_phi:
1099*61046927SAndroid Build Coastguard Worker    case nir_instr_type_debug_info:
1100*61046927SAndroid Build Coastguard Worker       return 1;
1101*61046927SAndroid Build Coastguard Worker 
1102*61046927SAndroid Build Coastguard Worker    case nir_instr_type_intrinsic:
1103*61046927SAndroid Build Coastguard Worker       switch (nir_instr_as_intrinsic(instr)->intrinsic) {
1104*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_decl_reg:
1105*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_load_reg:
1106*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_store_reg:
1107*61046927SAndroid Build Coastguard Worker          return 0;
1108*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_load_ubo:
1109*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_load_ssbo:
1110*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_load_scratch:
1111*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_load_shared:
1112*61046927SAndroid Build Coastguard Worker       case nir_intrinsic_image_load:
1113*61046927SAndroid Build Coastguard Worker          return 50;
1114*61046927SAndroid Build Coastguard Worker       default:
1115*61046927SAndroid Build Coastguard Worker          return 1;
1116*61046927SAndroid Build Coastguard Worker       }
1117*61046927SAndroid Build Coastguard Worker       break;
1118*61046927SAndroid Build Coastguard Worker 
1119*61046927SAndroid Build Coastguard Worker    case nir_instr_type_tex:
1120*61046927SAndroid Build Coastguard Worker       /* Pick some large number to try to fetch textures early and sample them
1121*61046927SAndroid Build Coastguard Worker        * late.
1122*61046927SAndroid Build Coastguard Worker        */
1123*61046927SAndroid Build Coastguard Worker       return 100;
1124*61046927SAndroid Build Coastguard Worker    }
1125*61046927SAndroid Build Coastguard Worker 
1126*61046927SAndroid Build Coastguard Worker    return 0;
1127*61046927SAndroid Build Coastguard Worker }
1128*61046927SAndroid Build Coastguard Worker 
1129*61046927SAndroid Build Coastguard Worker static void
nir_schedule_dag_max_delay_cb(struct dag_node * node,void * state)1130*61046927SAndroid Build Coastguard Worker nir_schedule_dag_max_delay_cb(struct dag_node *node, void *state)
1131*61046927SAndroid Build Coastguard Worker {
1132*61046927SAndroid Build Coastguard Worker    nir_schedule_node *n = (nir_schedule_node *)node;
1133*61046927SAndroid Build Coastguard Worker    uint32_t max_delay = 0;
1134*61046927SAndroid Build Coastguard Worker 
1135*61046927SAndroid Build Coastguard Worker    util_dynarray_foreach(&n->dag.edges, struct dag_edge, edge) {
1136*61046927SAndroid Build Coastguard Worker       nir_schedule_node *child = (nir_schedule_node *)edge->child;
1137*61046927SAndroid Build Coastguard Worker       max_delay = MAX2(child->max_delay, max_delay);
1138*61046927SAndroid Build Coastguard Worker    }
1139*61046927SAndroid Build Coastguard Worker 
1140*61046927SAndroid Build Coastguard Worker    n->max_delay = MAX2(n->max_delay, max_delay + n->delay);
1141*61046927SAndroid Build Coastguard Worker }
1142*61046927SAndroid Build Coastguard Worker 
1143*61046927SAndroid Build Coastguard Worker static void
nir_schedule_block(nir_schedule_scoreboard * scoreboard,nir_block * block)1144*61046927SAndroid Build Coastguard Worker nir_schedule_block(nir_schedule_scoreboard *scoreboard, nir_block *block)
1145*61046927SAndroid Build Coastguard Worker {
1146*61046927SAndroid Build Coastguard Worker    void *mem_ctx = ralloc_context(NULL);
1147*61046927SAndroid Build Coastguard Worker    scoreboard->instr_map = _mesa_pointer_hash_table_create(mem_ctx);
1148*61046927SAndroid Build Coastguard Worker 
1149*61046927SAndroid Build Coastguard Worker    scoreboard->dag = dag_create(mem_ctx);
1150*61046927SAndroid Build Coastguard Worker 
1151*61046927SAndroid Build Coastguard Worker    nir_foreach_instr(instr, block) {
1152*61046927SAndroid Build Coastguard Worker       nir_schedule_node *n =
1153*61046927SAndroid Build Coastguard Worker          rzalloc(mem_ctx, nir_schedule_node);
1154*61046927SAndroid Build Coastguard Worker 
1155*61046927SAndroid Build Coastguard Worker       n->instr = instr;
1156*61046927SAndroid Build Coastguard Worker       n->delay = nir_schedule_get_delay(scoreboard, instr);
1157*61046927SAndroid Build Coastguard Worker       dag_init_node(scoreboard->dag, &n->dag);
1158*61046927SAndroid Build Coastguard Worker 
1159*61046927SAndroid Build Coastguard Worker       _mesa_hash_table_insert(scoreboard->instr_map, instr, n);
1160*61046927SAndroid Build Coastguard Worker    }
1161*61046927SAndroid Build Coastguard Worker 
1162*61046927SAndroid Build Coastguard Worker    calculate_forward_deps(scoreboard, block);
1163*61046927SAndroid Build Coastguard Worker    calculate_reverse_deps(scoreboard, block);
1164*61046927SAndroid Build Coastguard Worker 
1165*61046927SAndroid Build Coastguard Worker    dag_traverse_bottom_up(scoreboard->dag, nir_schedule_dag_max_delay_cb, NULL);
1166*61046927SAndroid Build Coastguard Worker 
1167*61046927SAndroid Build Coastguard Worker    nir_schedule_instructions(scoreboard, block);
1168*61046927SAndroid Build Coastguard Worker 
1169*61046927SAndroid Build Coastguard Worker    ralloc_free(mem_ctx);
1170*61046927SAndroid Build Coastguard Worker    scoreboard->instr_map = NULL;
1171*61046927SAndroid Build Coastguard Worker }
1172*61046927SAndroid Build Coastguard Worker 
1173*61046927SAndroid Build Coastguard Worker static bool
is_decl_reg(nir_instr * instr)1174*61046927SAndroid Build Coastguard Worker is_decl_reg(nir_instr *instr)
1175*61046927SAndroid Build Coastguard Worker {
1176*61046927SAndroid Build Coastguard Worker    if (instr->type != nir_instr_type_intrinsic)
1177*61046927SAndroid Build Coastguard Worker       return false;
1178*61046927SAndroid Build Coastguard Worker 
1179*61046927SAndroid Build Coastguard Worker    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
1180*61046927SAndroid Build Coastguard Worker    return intrin->intrinsic == nir_intrinsic_decl_reg;
1181*61046927SAndroid Build Coastguard Worker }
1182*61046927SAndroid Build Coastguard Worker 
1183*61046927SAndroid Build Coastguard Worker static bool
nir_schedule_ssa_def_init_scoreboard(nir_def * def,void * state)1184*61046927SAndroid Build Coastguard Worker nir_schedule_ssa_def_init_scoreboard(nir_def *def, void *state)
1185*61046927SAndroid Build Coastguard Worker {
1186*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = state;
1187*61046927SAndroid Build Coastguard Worker    struct set *def_uses = _mesa_pointer_set_create(scoreboard);
1188*61046927SAndroid Build Coastguard Worker 
1189*61046927SAndroid Build Coastguard Worker    _mesa_hash_table_insert(scoreboard->remaining_uses, def, def_uses);
1190*61046927SAndroid Build Coastguard Worker 
1191*61046927SAndroid Build Coastguard Worker    /* We don't consider decl_reg to be a use to avoid extending register live
1192*61046927SAndroid Build Coastguard Worker     * ranges any further than needed.
1193*61046927SAndroid Build Coastguard Worker     */
1194*61046927SAndroid Build Coastguard Worker    if (!is_decl_reg(def->parent_instr))
1195*61046927SAndroid Build Coastguard Worker       _mesa_set_add(def_uses, def->parent_instr);
1196*61046927SAndroid Build Coastguard Worker 
1197*61046927SAndroid Build Coastguard Worker    nir_foreach_use(src, def) {
1198*61046927SAndroid Build Coastguard Worker       _mesa_set_add(def_uses, nir_src_parent_instr(src));
1199*61046927SAndroid Build Coastguard Worker    }
1200*61046927SAndroid Build Coastguard Worker 
1201*61046927SAndroid Build Coastguard Worker    /* XXX: Handle if uses */
1202*61046927SAndroid Build Coastguard Worker 
1203*61046927SAndroid Build Coastguard Worker    return true;
1204*61046927SAndroid Build Coastguard Worker }
1205*61046927SAndroid Build Coastguard Worker 
1206*61046927SAndroid Build Coastguard Worker static nir_schedule_scoreboard *
nir_schedule_get_scoreboard(nir_shader * shader,const nir_schedule_options * options)1207*61046927SAndroid Build Coastguard Worker nir_schedule_get_scoreboard(nir_shader *shader,
1208*61046927SAndroid Build Coastguard Worker                             const nir_schedule_options *options)
1209*61046927SAndroid Build Coastguard Worker {
1210*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = rzalloc(NULL, nir_schedule_scoreboard);
1211*61046927SAndroid Build Coastguard Worker 
1212*61046927SAndroid Build Coastguard Worker    scoreboard->shader = shader;
1213*61046927SAndroid Build Coastguard Worker    scoreboard->live_values = _mesa_pointer_set_create(scoreboard);
1214*61046927SAndroid Build Coastguard Worker    scoreboard->remaining_uses = _mesa_pointer_hash_table_create(scoreboard);
1215*61046927SAndroid Build Coastguard Worker    scoreboard->options = options;
1216*61046927SAndroid Build Coastguard Worker    scoreboard->pressure = 0;
1217*61046927SAndroid Build Coastguard Worker 
1218*61046927SAndroid Build Coastguard Worker    nir_foreach_function_impl(impl, shader) {
1219*61046927SAndroid Build Coastguard Worker       nir_foreach_block(block, impl) {
1220*61046927SAndroid Build Coastguard Worker          nir_foreach_instr(instr, block) {
1221*61046927SAndroid Build Coastguard Worker             nir_foreach_def(instr, nir_schedule_ssa_def_init_scoreboard,
1222*61046927SAndroid Build Coastguard Worker                             scoreboard);
1223*61046927SAndroid Build Coastguard Worker          }
1224*61046927SAndroid Build Coastguard Worker 
1225*61046927SAndroid Build Coastguard Worker          /* XXX: We're ignoring if uses, which may prioritize scheduling other
1226*61046927SAndroid Build Coastguard Worker           * uses of the if src even when it doesn't help.  That's not many
1227*61046927SAndroid Build Coastguard Worker           * values, though, so meh.
1228*61046927SAndroid Build Coastguard Worker           */
1229*61046927SAndroid Build Coastguard Worker       }
1230*61046927SAndroid Build Coastguard Worker    }
1231*61046927SAndroid Build Coastguard Worker 
1232*61046927SAndroid Build Coastguard Worker    return scoreboard;
1233*61046927SAndroid Build Coastguard Worker }
1234*61046927SAndroid Build Coastguard Worker 
1235*61046927SAndroid Build Coastguard Worker static void
nir_schedule_validate_uses(nir_schedule_scoreboard * scoreboard)1236*61046927SAndroid Build Coastguard Worker nir_schedule_validate_uses(nir_schedule_scoreboard *scoreboard)
1237*61046927SAndroid Build Coastguard Worker {
1238*61046927SAndroid Build Coastguard Worker #ifdef NDEBUG
1239*61046927SAndroid Build Coastguard Worker    return;
1240*61046927SAndroid Build Coastguard Worker #endif
1241*61046927SAndroid Build Coastguard Worker 
1242*61046927SAndroid Build Coastguard Worker    bool any_uses = false;
1243*61046927SAndroid Build Coastguard Worker 
1244*61046927SAndroid Build Coastguard Worker    hash_table_foreach(scoreboard->remaining_uses, entry) {
1245*61046927SAndroid Build Coastguard Worker       struct set *remaining_uses = entry->data;
1246*61046927SAndroid Build Coastguard Worker 
1247*61046927SAndroid Build Coastguard Worker       set_foreach(remaining_uses, instr_entry) {
1248*61046927SAndroid Build Coastguard Worker          if (!any_uses) {
1249*61046927SAndroid Build Coastguard Worker             fprintf(stderr, "Tracked uses remain after scheduling.  "
1250*61046927SAndroid Build Coastguard Worker                             "Affected instructions: \n");
1251*61046927SAndroid Build Coastguard Worker             any_uses = true;
1252*61046927SAndroid Build Coastguard Worker          }
1253*61046927SAndroid Build Coastguard Worker          nir_print_instr(instr_entry->key, stderr);
1254*61046927SAndroid Build Coastguard Worker          fprintf(stderr, "\n");
1255*61046927SAndroid Build Coastguard Worker       }
1256*61046927SAndroid Build Coastguard Worker    }
1257*61046927SAndroid Build Coastguard Worker 
1258*61046927SAndroid Build Coastguard Worker    assert(!any_uses);
1259*61046927SAndroid Build Coastguard Worker }
1260*61046927SAndroid Build Coastguard Worker 
1261*61046927SAndroid Build Coastguard Worker /**
1262*61046927SAndroid Build Coastguard Worker  * Schedules the NIR instructions to try to decrease stalls (for example,
1263*61046927SAndroid Build Coastguard Worker  * delaying texture reads) while managing register pressure.
1264*61046927SAndroid Build Coastguard Worker  *
1265*61046927SAndroid Build Coastguard Worker  * The threshold represents "number of NIR register/SSA def channels live
1266*61046927SAndroid Build Coastguard Worker  * before switching the scheduling heuristic to reduce register pressure",
1267*61046927SAndroid Build Coastguard Worker  * since most of our GPU architectures are scalar (extending to vector with a
1268*61046927SAndroid Build Coastguard Worker  * flag wouldn't be hard).  This number should be a bit below the number of
1269*61046927SAndroid Build Coastguard Worker  * registers available (counting any that may be occupied by system value
1270*61046927SAndroid Build Coastguard Worker  * payload values, for example), since the heuristic may not always be able to
1271*61046927SAndroid Build Coastguard Worker  * free a register immediately.  The amount below the limit is up to you to
1272*61046927SAndroid Build Coastguard Worker  * tune.
1273*61046927SAndroid Build Coastguard Worker  */
1274*61046927SAndroid Build Coastguard Worker void
nir_schedule(nir_shader * shader,const nir_schedule_options * options)1275*61046927SAndroid Build Coastguard Worker nir_schedule(nir_shader *shader,
1276*61046927SAndroid Build Coastguard Worker              const nir_schedule_options *options)
1277*61046927SAndroid Build Coastguard Worker {
1278*61046927SAndroid Build Coastguard Worker    nir_schedule_scoreboard *scoreboard = nir_schedule_get_scoreboard(shader,
1279*61046927SAndroid Build Coastguard Worker                                                                      options);
1280*61046927SAndroid Build Coastguard Worker 
1281*61046927SAndroid Build Coastguard Worker    if (debug) {
1282*61046927SAndroid Build Coastguard Worker       fprintf(stderr, "NIR shader before scheduling:\n");
1283*61046927SAndroid Build Coastguard Worker       nir_print_shader(shader, stderr);
1284*61046927SAndroid Build Coastguard Worker    }
1285*61046927SAndroid Build Coastguard Worker 
1286*61046927SAndroid Build Coastguard Worker    nir_foreach_function_impl(impl, shader) {
1287*61046927SAndroid Build Coastguard Worker       nir_foreach_block(block, impl) {
1288*61046927SAndroid Build Coastguard Worker          nir_schedule_block(scoreboard, block);
1289*61046927SAndroid Build Coastguard Worker       }
1290*61046927SAndroid Build Coastguard Worker    }
1291*61046927SAndroid Build Coastguard Worker 
1292*61046927SAndroid Build Coastguard Worker    nir_schedule_validate_uses(scoreboard);
1293*61046927SAndroid Build Coastguard Worker 
1294*61046927SAndroid Build Coastguard Worker    ralloc_free(scoreboard);
1295*61046927SAndroid Build Coastguard Worker }
1296