xref: /aosp_15_r20/external/mesa3d/src/panfrost/midgard/midgard_schedule.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2018-2019 Alyssa Rosenzweig <[email protected]>
3*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2019-2020 Collabora, Ltd.
4*61046927SAndroid Build Coastguard Worker  *
5*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
6*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
7*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
8*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
10*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
11*61046927SAndroid Build Coastguard Worker  *
12*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
13*61046927SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
14*61046927SAndroid Build Coastguard Worker  * Software.
15*61046927SAndroid Build Coastguard Worker  *
16*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*61046927SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*61046927SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*61046927SAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*61046927SAndroid Build Coastguard Worker  * SOFTWARE.
23*61046927SAndroid Build Coastguard Worker  */
24*61046927SAndroid Build Coastguard Worker 
25*61046927SAndroid Build Coastguard Worker #include "util/half_float.h"
26*61046927SAndroid Build Coastguard Worker #include "util/u_math.h"
27*61046927SAndroid Build Coastguard Worker #include "util/u_memory.h"
28*61046927SAndroid Build Coastguard Worker #include "compiler.h"
29*61046927SAndroid Build Coastguard Worker #include "midgard_ops.h"
30*61046927SAndroid Build Coastguard Worker #include "midgard_quirks.h"
31*61046927SAndroid Build Coastguard Worker 
32*61046927SAndroid Build Coastguard Worker /* Scheduling for Midgard is complicated, to say the least. ALU instructions
33*61046927SAndroid Build Coastguard Worker  * must be grouped into VLIW bundles according to following model:
34*61046927SAndroid Build Coastguard Worker  *
35*61046927SAndroid Build Coastguard Worker  * [VMUL] [SADD]
36*61046927SAndroid Build Coastguard Worker  * [VADD] [SMUL] [VLUT]
37*61046927SAndroid Build Coastguard Worker  *
38*61046927SAndroid Build Coastguard Worker  * A given instruction can execute on some subset of the units (or a few can
39*61046927SAndroid Build Coastguard Worker  * execute on all). Instructions can be either vector or scalar; only scalar
40*61046927SAndroid Build Coastguard Worker  * instructions can execute on SADD/SMUL units. Units on a given line execute
41*61046927SAndroid Build Coastguard Worker  * in parallel. Subsequent lines execute separately and can pass results
42*61046927SAndroid Build Coastguard Worker  * directly via pipeline registers r24/r25, bypassing the register file.
43*61046927SAndroid Build Coastguard Worker  *
44*61046927SAndroid Build Coastguard Worker  * A bundle can optionally have 128-bits of embedded constants, shared across
45*61046927SAndroid Build Coastguard Worker  * all of the instructions within a bundle.
46*61046927SAndroid Build Coastguard Worker  *
47*61046927SAndroid Build Coastguard Worker  * Instructions consuming conditionals (branches and conditional selects)
48*61046927SAndroid Build Coastguard Worker  * require their condition to be written into the conditional register (r31)
49*61046927SAndroid Build Coastguard Worker  * within the same bundle they are consumed.
50*61046927SAndroid Build Coastguard Worker  *
51*61046927SAndroid Build Coastguard Worker  * Fragment writeout requires its argument to be written in full within the
52*61046927SAndroid Build Coastguard Worker  * same bundle as the branch, with no hanging dependencies.
53*61046927SAndroid Build Coastguard Worker  *
54*61046927SAndroid Build Coastguard Worker  * Load/store instructions are also in bundles of simply two instructions, and
55*61046927SAndroid Build Coastguard Worker  * texture instructions have no bundling.
56*61046927SAndroid Build Coastguard Worker  *
57*61046927SAndroid Build Coastguard Worker  * -------------------------------------------------------------------------
58*61046927SAndroid Build Coastguard Worker  *
59*61046927SAndroid Build Coastguard Worker  */
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker /* We create the dependency graph with per-byte granularity */
62*61046927SAndroid Build Coastguard Worker 
63*61046927SAndroid Build Coastguard Worker #define BYTE_COUNT 16
64*61046927SAndroid Build Coastguard Worker 
65*61046927SAndroid Build Coastguard Worker static void
add_dependency(struct util_dynarray * table,unsigned index,uint16_t mask,midgard_instruction ** instructions,unsigned child)66*61046927SAndroid Build Coastguard Worker add_dependency(struct util_dynarray *table, unsigned index, uint16_t mask,
67*61046927SAndroid Build Coastguard Worker                midgard_instruction **instructions, unsigned child)
68*61046927SAndroid Build Coastguard Worker {
69*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < BYTE_COUNT; ++i) {
70*61046927SAndroid Build Coastguard Worker       if (!(mask & (1 << i)))
71*61046927SAndroid Build Coastguard Worker          continue;
72*61046927SAndroid Build Coastguard Worker 
73*61046927SAndroid Build Coastguard Worker       struct util_dynarray *parents = &table[(BYTE_COUNT * index) + i];
74*61046927SAndroid Build Coastguard Worker 
75*61046927SAndroid Build Coastguard Worker       util_dynarray_foreach(parents, unsigned, parent) {
76*61046927SAndroid Build Coastguard Worker          BITSET_WORD *dependents = instructions[*parent]->dependents;
77*61046927SAndroid Build Coastguard Worker 
78*61046927SAndroid Build Coastguard Worker          /* Already have the dependency */
79*61046927SAndroid Build Coastguard Worker          if (BITSET_TEST(dependents, child))
80*61046927SAndroid Build Coastguard Worker             continue;
81*61046927SAndroid Build Coastguard Worker 
82*61046927SAndroid Build Coastguard Worker          BITSET_SET(dependents, child);
83*61046927SAndroid Build Coastguard Worker          instructions[child]->nr_dependencies++;
84*61046927SAndroid Build Coastguard Worker       }
85*61046927SAndroid Build Coastguard Worker    }
86*61046927SAndroid Build Coastguard Worker }
87*61046927SAndroid Build Coastguard Worker 
88*61046927SAndroid Build Coastguard Worker static void
mark_access(struct util_dynarray * table,unsigned index,uint16_t mask,unsigned parent)89*61046927SAndroid Build Coastguard Worker mark_access(struct util_dynarray *table, unsigned index, uint16_t mask,
90*61046927SAndroid Build Coastguard Worker             unsigned parent)
91*61046927SAndroid Build Coastguard Worker {
92*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < BYTE_COUNT; ++i) {
93*61046927SAndroid Build Coastguard Worker       if (!(mask & (1 << i)))
94*61046927SAndroid Build Coastguard Worker          continue;
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker       util_dynarray_append(&table[(BYTE_COUNT * index) + i], unsigned, parent);
97*61046927SAndroid Build Coastguard Worker    }
98*61046927SAndroid Build Coastguard Worker }
99*61046927SAndroid Build Coastguard Worker 
100*61046927SAndroid Build Coastguard Worker static void
mir_create_dependency_graph(midgard_instruction ** instructions,unsigned count,unsigned node_count)101*61046927SAndroid Build Coastguard Worker mir_create_dependency_graph(midgard_instruction **instructions, unsigned count,
102*61046927SAndroid Build Coastguard Worker                             unsigned node_count)
103*61046927SAndroid Build Coastguard Worker {
104*61046927SAndroid Build Coastguard Worker    size_t sz = node_count * BYTE_COUNT;
105*61046927SAndroid Build Coastguard Worker 
106*61046927SAndroid Build Coastguard Worker    struct util_dynarray *last_read = calloc(sizeof(struct util_dynarray), sz);
107*61046927SAndroid Build Coastguard Worker    struct util_dynarray *last_write = calloc(sizeof(struct util_dynarray), sz);
108*61046927SAndroid Build Coastguard Worker 
109*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < sz; ++i) {
110*61046927SAndroid Build Coastguard Worker       util_dynarray_init(&last_read[i], NULL);
111*61046927SAndroid Build Coastguard Worker       util_dynarray_init(&last_write[i], NULL);
112*61046927SAndroid Build Coastguard Worker    }
113*61046927SAndroid Build Coastguard Worker 
114*61046927SAndroid Build Coastguard Worker    /* Initialize dependency graph */
115*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < count; ++i) {
116*61046927SAndroid Build Coastguard Worker       instructions[i]->dependents =
117*61046927SAndroid Build Coastguard Worker          calloc(BITSET_WORDS(count), sizeof(BITSET_WORD));
118*61046927SAndroid Build Coastguard Worker 
119*61046927SAndroid Build Coastguard Worker       instructions[i]->nr_dependencies = 0;
120*61046927SAndroid Build Coastguard Worker    }
121*61046927SAndroid Build Coastguard Worker 
122*61046927SAndroid Build Coastguard Worker    unsigned prev_ldst[3] = {~0, ~0, ~0};
123*61046927SAndroid Build Coastguard Worker 
124*61046927SAndroid Build Coastguard Worker    /* Populate dependency graph */
125*61046927SAndroid Build Coastguard Worker    for (signed i = count - 1; i >= 0; --i) {
126*61046927SAndroid Build Coastguard Worker       if (instructions[i]->compact_branch)
127*61046927SAndroid Build Coastguard Worker          continue;
128*61046927SAndroid Build Coastguard Worker 
129*61046927SAndroid Build Coastguard Worker       unsigned dest = instructions[i]->dest;
130*61046927SAndroid Build Coastguard Worker       unsigned mask = mir_bytemask(instructions[i]);
131*61046927SAndroid Build Coastguard Worker 
132*61046927SAndroid Build Coastguard Worker       mir_foreach_src((*instructions), s) {
133*61046927SAndroid Build Coastguard Worker          unsigned src = instructions[i]->src[s];
134*61046927SAndroid Build Coastguard Worker 
135*61046927SAndroid Build Coastguard Worker          if (src < node_count) {
136*61046927SAndroid Build Coastguard Worker             unsigned readmask =
137*61046927SAndroid Build Coastguard Worker                mir_bytemask_of_read_components(instructions[i], src);
138*61046927SAndroid Build Coastguard Worker             add_dependency(last_write, src, readmask, instructions, i);
139*61046927SAndroid Build Coastguard Worker          }
140*61046927SAndroid Build Coastguard Worker       }
141*61046927SAndroid Build Coastguard Worker 
142*61046927SAndroid Build Coastguard Worker       /* Create a list of dependencies for each type of load/store
143*61046927SAndroid Build Coastguard Worker        * instruction to prevent reordering. */
144*61046927SAndroid Build Coastguard Worker       if (instructions[i]->type == TAG_LOAD_STORE_4 &&
145*61046927SAndroid Build Coastguard Worker           load_store_opcode_props[instructions[i]->op].props & LDST_ADDRESS) {
146*61046927SAndroid Build Coastguard Worker 
147*61046927SAndroid Build Coastguard Worker          unsigned type = instructions[i]->load_store.arg_reg |
148*61046927SAndroid Build Coastguard Worker                          instructions[i]->load_store.arg_comp;
149*61046927SAndroid Build Coastguard Worker 
150*61046927SAndroid Build Coastguard Worker          unsigned idx;
151*61046927SAndroid Build Coastguard Worker          switch (type) {
152*61046927SAndroid Build Coastguard Worker          case LDST_SHARED:
153*61046927SAndroid Build Coastguard Worker             idx = 0;
154*61046927SAndroid Build Coastguard Worker             break;
155*61046927SAndroid Build Coastguard Worker          case LDST_SCRATCH:
156*61046927SAndroid Build Coastguard Worker             idx = 1;
157*61046927SAndroid Build Coastguard Worker             break;
158*61046927SAndroid Build Coastguard Worker          default:
159*61046927SAndroid Build Coastguard Worker             idx = 2;
160*61046927SAndroid Build Coastguard Worker             break;
161*61046927SAndroid Build Coastguard Worker          }
162*61046927SAndroid Build Coastguard Worker 
163*61046927SAndroid Build Coastguard Worker          unsigned prev = prev_ldst[idx];
164*61046927SAndroid Build Coastguard Worker 
165*61046927SAndroid Build Coastguard Worker          if (prev != ~0) {
166*61046927SAndroid Build Coastguard Worker             BITSET_WORD *dependents = instructions[prev]->dependents;
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker             /* Already have the dependency */
169*61046927SAndroid Build Coastguard Worker             if (BITSET_TEST(dependents, i))
170*61046927SAndroid Build Coastguard Worker                continue;
171*61046927SAndroid Build Coastguard Worker 
172*61046927SAndroid Build Coastguard Worker             BITSET_SET(dependents, i);
173*61046927SAndroid Build Coastguard Worker             instructions[i]->nr_dependencies++;
174*61046927SAndroid Build Coastguard Worker          }
175*61046927SAndroid Build Coastguard Worker 
176*61046927SAndroid Build Coastguard Worker          prev_ldst[idx] = i;
177*61046927SAndroid Build Coastguard Worker       }
178*61046927SAndroid Build Coastguard Worker 
179*61046927SAndroid Build Coastguard Worker       if (dest < node_count) {
180*61046927SAndroid Build Coastguard Worker          add_dependency(last_read, dest, mask, instructions, i);
181*61046927SAndroid Build Coastguard Worker          add_dependency(last_write, dest, mask, instructions, i);
182*61046927SAndroid Build Coastguard Worker          mark_access(last_write, dest, mask, i);
183*61046927SAndroid Build Coastguard Worker       }
184*61046927SAndroid Build Coastguard Worker 
185*61046927SAndroid Build Coastguard Worker       mir_foreach_src((*instructions), s) {
186*61046927SAndroid Build Coastguard Worker          unsigned src = instructions[i]->src[s];
187*61046927SAndroid Build Coastguard Worker 
188*61046927SAndroid Build Coastguard Worker          if (src < node_count) {
189*61046927SAndroid Build Coastguard Worker             unsigned readmask =
190*61046927SAndroid Build Coastguard Worker                mir_bytemask_of_read_components(instructions[i], src);
191*61046927SAndroid Build Coastguard Worker             mark_access(last_read, src, readmask, i);
192*61046927SAndroid Build Coastguard Worker          }
193*61046927SAndroid Build Coastguard Worker       }
194*61046927SAndroid Build Coastguard Worker    }
195*61046927SAndroid Build Coastguard Worker 
196*61046927SAndroid Build Coastguard Worker    /* If there is a branch, all instructions depend on it, as interblock
197*61046927SAndroid Build Coastguard Worker     * execution must be purely in-order */
198*61046927SAndroid Build Coastguard Worker 
199*61046927SAndroid Build Coastguard Worker    if (instructions[count - 1]->compact_branch) {
200*61046927SAndroid Build Coastguard Worker       BITSET_WORD *dependents = instructions[count - 1]->dependents;
201*61046927SAndroid Build Coastguard Worker 
202*61046927SAndroid Build Coastguard Worker       for (signed i = count - 2; i >= 0; --i) {
203*61046927SAndroid Build Coastguard Worker          if (BITSET_TEST(dependents, i))
204*61046927SAndroid Build Coastguard Worker             continue;
205*61046927SAndroid Build Coastguard Worker 
206*61046927SAndroid Build Coastguard Worker          BITSET_SET(dependents, i);
207*61046927SAndroid Build Coastguard Worker          instructions[i]->nr_dependencies++;
208*61046927SAndroid Build Coastguard Worker       }
209*61046927SAndroid Build Coastguard Worker    }
210*61046927SAndroid Build Coastguard Worker 
211*61046927SAndroid Build Coastguard Worker    /* Free the intermediate structures */
212*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < sz; ++i) {
213*61046927SAndroid Build Coastguard Worker       util_dynarray_fini(&last_read[i]);
214*61046927SAndroid Build Coastguard Worker       util_dynarray_fini(&last_write[i]);
215*61046927SAndroid Build Coastguard Worker    }
216*61046927SAndroid Build Coastguard Worker 
217*61046927SAndroid Build Coastguard Worker    free(last_read);
218*61046927SAndroid Build Coastguard Worker    free(last_write);
219*61046927SAndroid Build Coastguard Worker }
220*61046927SAndroid Build Coastguard Worker 
221*61046927SAndroid Build Coastguard Worker /* Does the mask cover more than a scalar? */
222*61046927SAndroid Build Coastguard Worker 
223*61046927SAndroid Build Coastguard Worker static bool
is_single_component_mask(unsigned mask)224*61046927SAndroid Build Coastguard Worker is_single_component_mask(unsigned mask)
225*61046927SAndroid Build Coastguard Worker {
226*61046927SAndroid Build Coastguard Worker    int components = 0;
227*61046927SAndroid Build Coastguard Worker 
228*61046927SAndroid Build Coastguard Worker    for (int c = 0; c < 8; ++c) {
229*61046927SAndroid Build Coastguard Worker       if (mask & (1 << c))
230*61046927SAndroid Build Coastguard Worker          components++;
231*61046927SAndroid Build Coastguard Worker    }
232*61046927SAndroid Build Coastguard Worker 
233*61046927SAndroid Build Coastguard Worker    return components == 1;
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker 
236*61046927SAndroid Build Coastguard Worker /* Helpers for scheudling */
237*61046927SAndroid Build Coastguard Worker 
238*61046927SAndroid Build Coastguard Worker static bool
mir_is_scalar(midgard_instruction * ains)239*61046927SAndroid Build Coastguard Worker mir_is_scalar(midgard_instruction *ains)
240*61046927SAndroid Build Coastguard Worker {
241*61046927SAndroid Build Coastguard Worker    /* Do we try to use it as a vector op? */
242*61046927SAndroid Build Coastguard Worker    if (!is_single_component_mask(ains->mask))
243*61046927SAndroid Build Coastguard Worker       return false;
244*61046927SAndroid Build Coastguard Worker 
245*61046927SAndroid Build Coastguard Worker    /* Otherwise, check mode hazards */
246*61046927SAndroid Build Coastguard Worker    bool could_scalar = true;
247*61046927SAndroid Build Coastguard Worker    unsigned szd = nir_alu_type_get_type_size(ains->dest_type);
248*61046927SAndroid Build Coastguard Worker    unsigned sz0 = nir_alu_type_get_type_size(ains->src_types[0]);
249*61046927SAndroid Build Coastguard Worker    unsigned sz1 = nir_alu_type_get_type_size(ains->src_types[1]);
250*61046927SAndroid Build Coastguard Worker 
251*61046927SAndroid Build Coastguard Worker    /* Only 16/32-bit can run on a scalar unit */
252*61046927SAndroid Build Coastguard Worker    could_scalar &= (szd == 16) || (szd == 32);
253*61046927SAndroid Build Coastguard Worker 
254*61046927SAndroid Build Coastguard Worker    if (ains->src[0] != ~0)
255*61046927SAndroid Build Coastguard Worker       could_scalar &= (sz0 == 16) || (sz0 == 32);
256*61046927SAndroid Build Coastguard Worker 
257*61046927SAndroid Build Coastguard Worker    if (ains->src[1] != ~0)
258*61046927SAndroid Build Coastguard Worker       could_scalar &= (sz1 == 16) || (sz1 == 32);
259*61046927SAndroid Build Coastguard Worker 
260*61046927SAndroid Build Coastguard Worker    if (midgard_is_integer_out_op(ains->op) &&
261*61046927SAndroid Build Coastguard Worker        ains->outmod != midgard_outmod_keeplo)
262*61046927SAndroid Build Coastguard Worker       return false;
263*61046927SAndroid Build Coastguard Worker 
264*61046927SAndroid Build Coastguard Worker    return could_scalar;
265*61046927SAndroid Build Coastguard Worker }
266*61046927SAndroid Build Coastguard Worker 
267*61046927SAndroid Build Coastguard Worker /* How many bytes does this ALU instruction add to the bundle? */
268*61046927SAndroid Build Coastguard Worker 
269*61046927SAndroid Build Coastguard Worker static unsigned
bytes_for_instruction(midgard_instruction * ains)270*61046927SAndroid Build Coastguard Worker bytes_for_instruction(midgard_instruction *ains)
271*61046927SAndroid Build Coastguard Worker {
272*61046927SAndroid Build Coastguard Worker    if (ains->unit & UNITS_ANY_VECTOR)
273*61046927SAndroid Build Coastguard Worker       return sizeof(midgard_reg_info) + sizeof(midgard_vector_alu);
274*61046927SAndroid Build Coastguard Worker    else if (ains->unit == ALU_ENAB_BRANCH)
275*61046927SAndroid Build Coastguard Worker       return sizeof(midgard_branch_extended);
276*61046927SAndroid Build Coastguard Worker    else if (ains->compact_branch)
277*61046927SAndroid Build Coastguard Worker       return sizeof(uint16_t);
278*61046927SAndroid Build Coastguard Worker    else
279*61046927SAndroid Build Coastguard Worker       return sizeof(midgard_reg_info) + sizeof(midgard_scalar_alu);
280*61046927SAndroid Build Coastguard Worker }
281*61046927SAndroid Build Coastguard Worker 
282*61046927SAndroid Build Coastguard Worker /* We would like to flatten the linked list of midgard_instructions in a bundle
283*61046927SAndroid Build Coastguard Worker  * to an array of pointers on the heap for easy indexing */
284*61046927SAndroid Build Coastguard Worker 
285*61046927SAndroid Build Coastguard Worker static midgard_instruction **
flatten_mir(midgard_block * block,unsigned * len)286*61046927SAndroid Build Coastguard Worker flatten_mir(midgard_block *block, unsigned *len)
287*61046927SAndroid Build Coastguard Worker {
288*61046927SAndroid Build Coastguard Worker    *len = list_length(&block->base.instructions);
289*61046927SAndroid Build Coastguard Worker 
290*61046927SAndroid Build Coastguard Worker    if (!(*len))
291*61046927SAndroid Build Coastguard Worker       return NULL;
292*61046927SAndroid Build Coastguard Worker 
293*61046927SAndroid Build Coastguard Worker    midgard_instruction **instructions =
294*61046927SAndroid Build Coastguard Worker       calloc(sizeof(midgard_instruction *), *len);
295*61046927SAndroid Build Coastguard Worker 
296*61046927SAndroid Build Coastguard Worker    unsigned i = 0;
297*61046927SAndroid Build Coastguard Worker 
298*61046927SAndroid Build Coastguard Worker    mir_foreach_instr_in_block(block, ins)
299*61046927SAndroid Build Coastguard Worker       instructions[i++] = ins;
300*61046927SAndroid Build Coastguard Worker 
301*61046927SAndroid Build Coastguard Worker    return instructions;
302*61046927SAndroid Build Coastguard Worker }
303*61046927SAndroid Build Coastguard Worker 
304*61046927SAndroid Build Coastguard Worker /* The worklist is the set of instructions that can be scheduled now; that is,
305*61046927SAndroid Build Coastguard Worker  * the set of instructions with no remaining dependencies */
306*61046927SAndroid Build Coastguard Worker 
307*61046927SAndroid Build Coastguard Worker static void
mir_initialize_worklist(BITSET_WORD * worklist,midgard_instruction ** instructions,unsigned count)308*61046927SAndroid Build Coastguard Worker mir_initialize_worklist(BITSET_WORD *worklist,
309*61046927SAndroid Build Coastguard Worker                         midgard_instruction **instructions, unsigned count)
310*61046927SAndroid Build Coastguard Worker {
311*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < count; ++i) {
312*61046927SAndroid Build Coastguard Worker       if (instructions[i]->nr_dependencies == 0)
313*61046927SAndroid Build Coastguard Worker          BITSET_SET(worklist, i);
314*61046927SAndroid Build Coastguard Worker    }
315*61046927SAndroid Build Coastguard Worker }
316*61046927SAndroid Build Coastguard Worker 
317*61046927SAndroid Build Coastguard Worker /* Update the worklist after an instruction terminates. Remove its edges from
318*61046927SAndroid Build Coastguard Worker  * the graph and if that causes any node to have no dependencies, add it to the
319*61046927SAndroid Build Coastguard Worker  * worklist */
320*61046927SAndroid Build Coastguard Worker 
321*61046927SAndroid Build Coastguard Worker static void
mir_update_worklist(BITSET_WORD * worklist,unsigned count,midgard_instruction ** instructions,midgard_instruction * done)322*61046927SAndroid Build Coastguard Worker mir_update_worklist(BITSET_WORD *worklist, unsigned count,
323*61046927SAndroid Build Coastguard Worker                     midgard_instruction **instructions,
324*61046927SAndroid Build Coastguard Worker                     midgard_instruction *done)
325*61046927SAndroid Build Coastguard Worker {
326*61046927SAndroid Build Coastguard Worker    /* Sanity check: if no instruction terminated, there is nothing to do.
327*61046927SAndroid Build Coastguard Worker     * If the instruction that terminated had dependencies, that makes no
328*61046927SAndroid Build Coastguard Worker     * sense and means we messed up the worklist. Finally, as the purpose
329*61046927SAndroid Build Coastguard Worker     * of this routine is to update dependents, we abort early if there are
330*61046927SAndroid Build Coastguard Worker     * no dependents defined. */
331*61046927SAndroid Build Coastguard Worker 
332*61046927SAndroid Build Coastguard Worker    if (!done)
333*61046927SAndroid Build Coastguard Worker       return;
334*61046927SAndroid Build Coastguard Worker 
335*61046927SAndroid Build Coastguard Worker    assert(done->nr_dependencies == 0);
336*61046927SAndroid Build Coastguard Worker 
337*61046927SAndroid Build Coastguard Worker    if (!done->dependents)
338*61046927SAndroid Build Coastguard Worker       return;
339*61046927SAndroid Build Coastguard Worker 
340*61046927SAndroid Build Coastguard Worker    /* We have an instruction with dependents. Iterate each dependent to
341*61046927SAndroid Build Coastguard Worker     * remove one dependency (`done`), adding dependents to the worklist
342*61046927SAndroid Build Coastguard Worker     * where possible. */
343*61046927SAndroid Build Coastguard Worker 
344*61046927SAndroid Build Coastguard Worker    unsigned i;
345*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, done->dependents, count) {
346*61046927SAndroid Build Coastguard Worker       assert(instructions[i]->nr_dependencies);
347*61046927SAndroid Build Coastguard Worker 
348*61046927SAndroid Build Coastguard Worker       if (!(--instructions[i]->nr_dependencies))
349*61046927SAndroid Build Coastguard Worker          BITSET_SET(worklist, i);
350*61046927SAndroid Build Coastguard Worker    }
351*61046927SAndroid Build Coastguard Worker 
352*61046927SAndroid Build Coastguard Worker    free(done->dependents);
353*61046927SAndroid Build Coastguard Worker }
354*61046927SAndroid Build Coastguard Worker 
355*61046927SAndroid Build Coastguard Worker /* While scheduling, we need to choose instructions satisfying certain
356*61046927SAndroid Build Coastguard Worker  * criteria. As we schedule backwards, we choose the *last* instruction in the
357*61046927SAndroid Build Coastguard Worker  * worklist to simulate in-order scheduling. Chosen instructions must satisfy a
358*61046927SAndroid Build Coastguard Worker  * given predicate. */
359*61046927SAndroid Build Coastguard Worker 
360*61046927SAndroid Build Coastguard Worker struct midgard_predicate {
361*61046927SAndroid Build Coastguard Worker    /* TAG or ~0 for dont-care */
362*61046927SAndroid Build Coastguard Worker    unsigned tag;
363*61046927SAndroid Build Coastguard Worker 
364*61046927SAndroid Build Coastguard Worker    /* True if we want to pop off the chosen instruction */
365*61046927SAndroid Build Coastguard Worker    bool destructive;
366*61046927SAndroid Build Coastguard Worker 
367*61046927SAndroid Build Coastguard Worker    /* For ALU, choose only this unit */
368*61046927SAndroid Build Coastguard Worker    unsigned unit;
369*61046927SAndroid Build Coastguard Worker 
370*61046927SAndroid Build Coastguard Worker    /* State for bundle constants. constants is the actual constants
371*61046927SAndroid Build Coastguard Worker     * for the bundle. constant_count is the number of bytes (up to
372*61046927SAndroid Build Coastguard Worker     * 16) currently in use for constants. When picking in destructive
373*61046927SAndroid Build Coastguard Worker     * mode, the constants array will be updated, and the instruction
374*61046927SAndroid Build Coastguard Worker     * will be adjusted to index into the constants array */
375*61046927SAndroid Build Coastguard Worker 
376*61046927SAndroid Build Coastguard Worker    midgard_constants *constants;
377*61046927SAndroid Build Coastguard Worker    unsigned constant_mask;
378*61046927SAndroid Build Coastguard Worker 
379*61046927SAndroid Build Coastguard Worker    /* Exclude this destination (if not ~0) */
380*61046927SAndroid Build Coastguard Worker    unsigned exclude;
381*61046927SAndroid Build Coastguard Worker 
382*61046927SAndroid Build Coastguard Worker    /* Don't schedule instructions consuming conditionals (since we already
383*61046927SAndroid Build Coastguard Worker     * scheduled one). Excludes conditional branches and csel */
384*61046927SAndroid Build Coastguard Worker    bool no_cond;
385*61046927SAndroid Build Coastguard Worker 
386*61046927SAndroid Build Coastguard Worker    /* Require (or reject) a minimal mask and (if nonzero) given
387*61046927SAndroid Build Coastguard Worker     * destination. Used for writeout optimizations */
388*61046927SAndroid Build Coastguard Worker 
389*61046927SAndroid Build Coastguard Worker    unsigned mask;
390*61046927SAndroid Build Coastguard Worker    unsigned no_mask;
391*61046927SAndroid Build Coastguard Worker    unsigned dest;
392*61046927SAndroid Build Coastguard Worker 
393*61046927SAndroid Build Coastguard Worker    /* Whether to not-care/only/never schedule imov/fmov instructions This
394*61046927SAndroid Build Coastguard Worker     * allows non-move instructions to get priority on each unit */
395*61046927SAndroid Build Coastguard Worker    unsigned move_mode;
396*61046927SAndroid Build Coastguard Worker 
397*61046927SAndroid Build Coastguard Worker    /* For load/store: how many pipeline registers are in use? The two
398*61046927SAndroid Build Coastguard Worker     * scheduled instructions cannot use more than the 256-bits of pipeline
399*61046927SAndroid Build Coastguard Worker     * space available or RA will fail (as it would run out of pipeline
400*61046927SAndroid Build Coastguard Worker     * registers and fail to spill without breaking the schedule) */
401*61046927SAndroid Build Coastguard Worker 
402*61046927SAndroid Build Coastguard Worker    unsigned pipeline_count;
403*61046927SAndroid Build Coastguard Worker 
404*61046927SAndroid Build Coastguard Worker    /* For load/store: is a ST_VARY.a32 instruction scheduled into the
405*61046927SAndroid Build Coastguard Worker     * bundle? is a non-ST_VARY.a32 instruction scheduled? Potential
406*61046927SAndroid Build Coastguard Worker     * hardware issue, unknown cause.
407*61046927SAndroid Build Coastguard Worker     */
408*61046927SAndroid Build Coastguard Worker    bool any_st_vary_a32, any_non_st_vary_a32;
409*61046927SAndroid Build Coastguard Worker };
410*61046927SAndroid Build Coastguard Worker 
411*61046927SAndroid Build Coastguard Worker static bool
mir_adjust_constant(midgard_instruction * ins,unsigned src,unsigned * bundle_constant_mask,unsigned * comp_mapping,uint8_t * bundle_constants,bool upper)412*61046927SAndroid Build Coastguard Worker mir_adjust_constant(midgard_instruction *ins, unsigned src,
413*61046927SAndroid Build Coastguard Worker                     unsigned *bundle_constant_mask, unsigned *comp_mapping,
414*61046927SAndroid Build Coastguard Worker                     uint8_t *bundle_constants, bool upper)
415*61046927SAndroid Build Coastguard Worker {
416*61046927SAndroid Build Coastguard Worker    unsigned type_size = nir_alu_type_get_type_size(ins->src_types[src]) / 8;
417*61046927SAndroid Build Coastguard Worker    unsigned type_shift = util_logbase2(type_size);
418*61046927SAndroid Build Coastguard Worker    unsigned max_comp = mir_components_for_type(ins->src_types[src]);
419*61046927SAndroid Build Coastguard Worker    unsigned comp_mask = mir_from_bytemask(
420*61046927SAndroid Build Coastguard Worker       mir_round_bytemask_up(mir_bytemask_of_read_components_index(ins, src),
421*61046927SAndroid Build Coastguard Worker                             type_size * 8),
422*61046927SAndroid Build Coastguard Worker       type_size * 8);
423*61046927SAndroid Build Coastguard Worker    unsigned type_mask = (1 << type_size) - 1;
424*61046927SAndroid Build Coastguard Worker 
425*61046927SAndroid Build Coastguard Worker    /* Upper only makes sense for 16-bit */
426*61046927SAndroid Build Coastguard Worker    if (type_size != 16 && upper)
427*61046927SAndroid Build Coastguard Worker       return false;
428*61046927SAndroid Build Coastguard Worker 
429*61046927SAndroid Build Coastguard Worker    /* For 16-bit, we need to stay on either upper or lower halves to avoid
430*61046927SAndroid Build Coastguard Worker     * disrupting the swizzle */
431*61046927SAndroid Build Coastguard Worker    unsigned start = upper ? 8 : 0;
432*61046927SAndroid Build Coastguard Worker    unsigned length = (type_size == 2) ? 8 : 16;
433*61046927SAndroid Build Coastguard Worker 
434*61046927SAndroid Build Coastguard Worker    for (unsigned comp = 0; comp < max_comp; comp++) {
435*61046927SAndroid Build Coastguard Worker       if (!(comp_mask & (1 << comp)))
436*61046927SAndroid Build Coastguard Worker          continue;
437*61046927SAndroid Build Coastguard Worker 
438*61046927SAndroid Build Coastguard Worker       uint8_t *constantp = ins->constants.u8 + (type_size * comp);
439*61046927SAndroid Build Coastguard Worker       unsigned best_reuse_bytes = 0;
440*61046927SAndroid Build Coastguard Worker       signed best_place = -1;
441*61046927SAndroid Build Coastguard Worker       unsigned i, j;
442*61046927SAndroid Build Coastguard Worker 
443*61046927SAndroid Build Coastguard Worker       for (i = start; i < (start + length); i += type_size) {
444*61046927SAndroid Build Coastguard Worker          unsigned reuse_bytes = 0;
445*61046927SAndroid Build Coastguard Worker 
446*61046927SAndroid Build Coastguard Worker          for (j = 0; j < type_size; j++) {
447*61046927SAndroid Build Coastguard Worker             if (!(*bundle_constant_mask & (1 << (i + j))))
448*61046927SAndroid Build Coastguard Worker                continue;
449*61046927SAndroid Build Coastguard Worker             if (constantp[j] != bundle_constants[i + j])
450*61046927SAndroid Build Coastguard Worker                break;
451*61046927SAndroid Build Coastguard Worker             if ((i + j) > (start + length))
452*61046927SAndroid Build Coastguard Worker                break;
453*61046927SAndroid Build Coastguard Worker 
454*61046927SAndroid Build Coastguard Worker             reuse_bytes++;
455*61046927SAndroid Build Coastguard Worker          }
456*61046927SAndroid Build Coastguard Worker 
457*61046927SAndroid Build Coastguard Worker          /* Select the place where existing bytes can be
458*61046927SAndroid Build Coastguard Worker           * reused so we leave empty slots to others
459*61046927SAndroid Build Coastguard Worker           */
460*61046927SAndroid Build Coastguard Worker          if (j == type_size &&
461*61046927SAndroid Build Coastguard Worker              (reuse_bytes > best_reuse_bytes || best_place < 0)) {
462*61046927SAndroid Build Coastguard Worker             best_reuse_bytes = reuse_bytes;
463*61046927SAndroid Build Coastguard Worker             best_place = i;
464*61046927SAndroid Build Coastguard Worker             break;
465*61046927SAndroid Build Coastguard Worker          }
466*61046927SAndroid Build Coastguard Worker       }
467*61046927SAndroid Build Coastguard Worker 
468*61046927SAndroid Build Coastguard Worker       /* This component couldn't fit in the remaining constant slot,
469*61046927SAndroid Build Coastguard Worker        * no need check the remaining components, bail out now
470*61046927SAndroid Build Coastguard Worker        */
471*61046927SAndroid Build Coastguard Worker       if (best_place < 0)
472*61046927SAndroid Build Coastguard Worker          return false;
473*61046927SAndroid Build Coastguard Worker 
474*61046927SAndroid Build Coastguard Worker       memcpy(&bundle_constants[i], constantp, type_size);
475*61046927SAndroid Build Coastguard Worker       *bundle_constant_mask |= type_mask << best_place;
476*61046927SAndroid Build Coastguard Worker       comp_mapping[comp] = best_place >> type_shift;
477*61046927SAndroid Build Coastguard Worker    }
478*61046927SAndroid Build Coastguard Worker 
479*61046927SAndroid Build Coastguard Worker    return true;
480*61046927SAndroid Build Coastguard Worker }
481*61046927SAndroid Build Coastguard Worker 
482*61046927SAndroid Build Coastguard Worker /* For an instruction that can fit, adjust it to fit and update the constants
483*61046927SAndroid Build Coastguard Worker  * array, in destructive mode. Returns whether the fitting was successful. */
484*61046927SAndroid Build Coastguard Worker 
485*61046927SAndroid Build Coastguard Worker static bool
mir_adjust_constants(midgard_instruction * ins,struct midgard_predicate * pred,bool destructive)486*61046927SAndroid Build Coastguard Worker mir_adjust_constants(midgard_instruction *ins, struct midgard_predicate *pred,
487*61046927SAndroid Build Coastguard Worker                      bool destructive)
488*61046927SAndroid Build Coastguard Worker {
489*61046927SAndroid Build Coastguard Worker    /* No constant, nothing to adjust */
490*61046927SAndroid Build Coastguard Worker    if (!ins->has_constants)
491*61046927SAndroid Build Coastguard Worker       return true;
492*61046927SAndroid Build Coastguard Worker 
493*61046927SAndroid Build Coastguard Worker    unsigned r_constant = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
494*61046927SAndroid Build Coastguard Worker    unsigned bundle_constant_mask = pred->constant_mask;
495*61046927SAndroid Build Coastguard Worker    unsigned comp_mapping[2][16] = {};
496*61046927SAndroid Build Coastguard Worker    uint8_t bundle_constants[16];
497*61046927SAndroid Build Coastguard Worker 
498*61046927SAndroid Build Coastguard Worker    memcpy(bundle_constants, pred->constants, 16);
499*61046927SAndroid Build Coastguard Worker 
500*61046927SAndroid Build Coastguard Worker    /* Let's try to find a place for each active component of the constant
501*61046927SAndroid Build Coastguard Worker     * register.
502*61046927SAndroid Build Coastguard Worker     */
503*61046927SAndroid Build Coastguard Worker    for (unsigned src = 0; src < 2; ++src) {
504*61046927SAndroid Build Coastguard Worker       if (ins->src[src] != SSA_FIXED_REGISTER(REGISTER_CONSTANT))
505*61046927SAndroid Build Coastguard Worker          continue;
506*61046927SAndroid Build Coastguard Worker 
507*61046927SAndroid Build Coastguard Worker       /* First, try lower half (or whole for !16) */
508*61046927SAndroid Build Coastguard Worker       if (mir_adjust_constant(ins, src, &bundle_constant_mask,
509*61046927SAndroid Build Coastguard Worker                               comp_mapping[src], bundle_constants, false))
510*61046927SAndroid Build Coastguard Worker          continue;
511*61046927SAndroid Build Coastguard Worker 
512*61046927SAndroid Build Coastguard Worker       /* Next, try upper half */
513*61046927SAndroid Build Coastguard Worker       if (mir_adjust_constant(ins, src, &bundle_constant_mask,
514*61046927SAndroid Build Coastguard Worker                               comp_mapping[src], bundle_constants, true))
515*61046927SAndroid Build Coastguard Worker          continue;
516*61046927SAndroid Build Coastguard Worker 
517*61046927SAndroid Build Coastguard Worker       /* Otherwise bail */
518*61046927SAndroid Build Coastguard Worker       return false;
519*61046927SAndroid Build Coastguard Worker    }
520*61046927SAndroid Build Coastguard Worker 
521*61046927SAndroid Build Coastguard Worker    /* If non-destructive, we're done */
522*61046927SAndroid Build Coastguard Worker    if (!destructive)
523*61046927SAndroid Build Coastguard Worker       return true;
524*61046927SAndroid Build Coastguard Worker 
525*61046927SAndroid Build Coastguard Worker    /* Otherwise update the constant_mask and constant values */
526*61046927SAndroid Build Coastguard Worker    pred->constant_mask = bundle_constant_mask;
527*61046927SAndroid Build Coastguard Worker    memcpy(pred->constants, bundle_constants, 16);
528*61046927SAndroid Build Coastguard Worker 
529*61046927SAndroid Build Coastguard Worker    /* Use comp_mapping as a swizzle */
530*61046927SAndroid Build Coastguard Worker    mir_foreach_src(ins, s) {
531*61046927SAndroid Build Coastguard Worker       if (ins->src[s] == r_constant)
532*61046927SAndroid Build Coastguard Worker          mir_compose_swizzle(ins->swizzle[s], comp_mapping[s], ins->swizzle[s]);
533*61046927SAndroid Build Coastguard Worker    }
534*61046927SAndroid Build Coastguard Worker 
535*61046927SAndroid Build Coastguard Worker    return true;
536*61046927SAndroid Build Coastguard Worker }
537*61046927SAndroid Build Coastguard Worker 
538*61046927SAndroid Build Coastguard Worker /* Conservative estimate of the pipeline registers required for load/store */
539*61046927SAndroid Build Coastguard Worker 
540*61046927SAndroid Build Coastguard Worker static unsigned
mir_pipeline_count(midgard_instruction * ins)541*61046927SAndroid Build Coastguard Worker mir_pipeline_count(midgard_instruction *ins)
542*61046927SAndroid Build Coastguard Worker {
543*61046927SAndroid Build Coastguard Worker    unsigned bytecount = 0;
544*61046927SAndroid Build Coastguard Worker 
545*61046927SAndroid Build Coastguard Worker    mir_foreach_src(ins, i) {
546*61046927SAndroid Build Coastguard Worker       /* Skip empty source  */
547*61046927SAndroid Build Coastguard Worker       if (ins->src[i] == ~0)
548*61046927SAndroid Build Coastguard Worker          continue;
549*61046927SAndroid Build Coastguard Worker 
550*61046927SAndroid Build Coastguard Worker       if (i == 0) {
551*61046927SAndroid Build Coastguard Worker          /* First source is a vector, worst-case the mask */
552*61046927SAndroid Build Coastguard Worker          unsigned bytemask = mir_bytemask_of_read_components_index(ins, i);
553*61046927SAndroid Build Coastguard Worker          unsigned max = util_logbase2(bytemask) + 1;
554*61046927SAndroid Build Coastguard Worker          bytecount += max;
555*61046927SAndroid Build Coastguard Worker       } else {
556*61046927SAndroid Build Coastguard Worker          /* Sources 1 on are scalars */
557*61046927SAndroid Build Coastguard Worker          bytecount += 4;
558*61046927SAndroid Build Coastguard Worker       }
559*61046927SAndroid Build Coastguard Worker    }
560*61046927SAndroid Build Coastguard Worker 
561*61046927SAndroid Build Coastguard Worker    unsigned dwords = DIV_ROUND_UP(bytecount, 16);
562*61046927SAndroid Build Coastguard Worker    assert(dwords <= 2);
563*61046927SAndroid Build Coastguard Worker 
564*61046927SAndroid Build Coastguard Worker    return dwords;
565*61046927SAndroid Build Coastguard Worker }
566*61046927SAndroid Build Coastguard Worker 
567*61046927SAndroid Build Coastguard Worker /* Matches FADD x, x with modifiers compatible. Since x + x = x * 2, for
568*61046927SAndroid Build Coastguard Worker  * any x including of the form f(y) for some swizzle/abs/neg function f */
569*61046927SAndroid Build Coastguard Worker 
570*61046927SAndroid Build Coastguard Worker static bool
mir_is_add_2(midgard_instruction * ins)571*61046927SAndroid Build Coastguard Worker mir_is_add_2(midgard_instruction *ins)
572*61046927SAndroid Build Coastguard Worker {
573*61046927SAndroid Build Coastguard Worker    if (ins->op != midgard_alu_op_fadd)
574*61046927SAndroid Build Coastguard Worker       return false;
575*61046927SAndroid Build Coastguard Worker 
576*61046927SAndroid Build Coastguard Worker    if (ins->src[0] != ins->src[1])
577*61046927SAndroid Build Coastguard Worker       return false;
578*61046927SAndroid Build Coastguard Worker 
579*61046927SAndroid Build Coastguard Worker    if (ins->src_types[0] != ins->src_types[1])
580*61046927SAndroid Build Coastguard Worker       return false;
581*61046927SAndroid Build Coastguard Worker 
582*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < MIR_VEC_COMPONENTS; ++i) {
583*61046927SAndroid Build Coastguard Worker       if (ins->swizzle[0][i] != ins->swizzle[1][i])
584*61046927SAndroid Build Coastguard Worker          return false;
585*61046927SAndroid Build Coastguard Worker    }
586*61046927SAndroid Build Coastguard Worker 
587*61046927SAndroid Build Coastguard Worker    if (ins->src_abs[0] != ins->src_abs[1])
588*61046927SAndroid Build Coastguard Worker       return false;
589*61046927SAndroid Build Coastguard Worker 
590*61046927SAndroid Build Coastguard Worker    if (ins->src_neg[0] != ins->src_neg[1])
591*61046927SAndroid Build Coastguard Worker       return false;
592*61046927SAndroid Build Coastguard Worker 
593*61046927SAndroid Build Coastguard Worker    return true;
594*61046927SAndroid Build Coastguard Worker }
595*61046927SAndroid Build Coastguard Worker 
596*61046927SAndroid Build Coastguard Worker static void
mir_adjust_unit(midgard_instruction * ins,unsigned unit)597*61046927SAndroid Build Coastguard Worker mir_adjust_unit(midgard_instruction *ins, unsigned unit)
598*61046927SAndroid Build Coastguard Worker {
599*61046927SAndroid Build Coastguard Worker    /* FADD x, x = FMUL x, #2 */
600*61046927SAndroid Build Coastguard Worker    if (mir_is_add_2(ins) && (unit & (UNITS_MUL | UNIT_VLUT))) {
601*61046927SAndroid Build Coastguard Worker       ins->op = midgard_alu_op_fmul;
602*61046927SAndroid Build Coastguard Worker 
603*61046927SAndroid Build Coastguard Worker       ins->src[1] = ~0;
604*61046927SAndroid Build Coastguard Worker       ins->src_abs[1] = false;
605*61046927SAndroid Build Coastguard Worker       ins->src_neg[1] = false;
606*61046927SAndroid Build Coastguard Worker 
607*61046927SAndroid Build Coastguard Worker       ins->has_inline_constant = true;
608*61046927SAndroid Build Coastguard Worker       ins->inline_constant = _mesa_float_to_half(2.0);
609*61046927SAndroid Build Coastguard Worker    }
610*61046927SAndroid Build Coastguard Worker }
611*61046927SAndroid Build Coastguard Worker 
612*61046927SAndroid Build Coastguard Worker static unsigned
mir_has_unit(midgard_instruction * ins,unsigned unit)613*61046927SAndroid Build Coastguard Worker mir_has_unit(midgard_instruction *ins, unsigned unit)
614*61046927SAndroid Build Coastguard Worker {
615*61046927SAndroid Build Coastguard Worker    if (alu_opcode_props[ins->op].props & unit)
616*61046927SAndroid Build Coastguard Worker       return true;
617*61046927SAndroid Build Coastguard Worker 
618*61046927SAndroid Build Coastguard Worker    /* FADD x, x can run on any adder or any multiplier */
619*61046927SAndroid Build Coastguard Worker    if (mir_is_add_2(ins))
620*61046927SAndroid Build Coastguard Worker       return true;
621*61046927SAndroid Build Coastguard Worker 
622*61046927SAndroid Build Coastguard Worker    return false;
623*61046927SAndroid Build Coastguard Worker }
624*61046927SAndroid Build Coastguard Worker 
625*61046927SAndroid Build Coastguard Worker /* Net change in liveness if an instruction were scheduled. Loosely based on
626*61046927SAndroid Build Coastguard Worker  * ir3's scheduler. */
627*61046927SAndroid Build Coastguard Worker 
628*61046927SAndroid Build Coastguard Worker static int
mir_live_effect(uint16_t * liveness,midgard_instruction * ins,bool destructive)629*61046927SAndroid Build Coastguard Worker mir_live_effect(uint16_t *liveness, midgard_instruction *ins, bool destructive)
630*61046927SAndroid Build Coastguard Worker {
631*61046927SAndroid Build Coastguard Worker    /* TODO: what if dest is used multiple times? */
632*61046927SAndroid Build Coastguard Worker    int free_live = 0;
633*61046927SAndroid Build Coastguard Worker 
634*61046927SAndroid Build Coastguard Worker    if (ins->dest < SSA_FIXED_MINIMUM) {
635*61046927SAndroid Build Coastguard Worker       unsigned bytemask = mir_bytemask(ins);
636*61046927SAndroid Build Coastguard Worker       bytemask = util_next_power_of_two(bytemask + 1) - 1;
637*61046927SAndroid Build Coastguard Worker       free_live += util_bitcount(liveness[ins->dest] & bytemask);
638*61046927SAndroid Build Coastguard Worker 
639*61046927SAndroid Build Coastguard Worker       if (destructive)
640*61046927SAndroid Build Coastguard Worker          liveness[ins->dest] &= ~bytemask;
641*61046927SAndroid Build Coastguard Worker    }
642*61046927SAndroid Build Coastguard Worker 
643*61046927SAndroid Build Coastguard Worker    int new_live = 0;
644*61046927SAndroid Build Coastguard Worker 
645*61046927SAndroid Build Coastguard Worker    mir_foreach_src(ins, s) {
646*61046927SAndroid Build Coastguard Worker       unsigned S = ins->src[s];
647*61046927SAndroid Build Coastguard Worker 
648*61046927SAndroid Build Coastguard Worker       bool dupe = false;
649*61046927SAndroid Build Coastguard Worker 
650*61046927SAndroid Build Coastguard Worker       for (unsigned q = 0; q < s; ++q)
651*61046927SAndroid Build Coastguard Worker          dupe |= (ins->src[q] == S);
652*61046927SAndroid Build Coastguard Worker 
653*61046927SAndroid Build Coastguard Worker       if (dupe)
654*61046927SAndroid Build Coastguard Worker          continue;
655*61046927SAndroid Build Coastguard Worker 
656*61046927SAndroid Build Coastguard Worker       if (S < SSA_FIXED_MINIMUM) {
657*61046927SAndroid Build Coastguard Worker          unsigned bytemask = mir_bytemask_of_read_components(ins, S);
658*61046927SAndroid Build Coastguard Worker          bytemask = util_next_power_of_two(bytemask + 1) - 1;
659*61046927SAndroid Build Coastguard Worker 
660*61046927SAndroid Build Coastguard Worker          /* Count only the new components */
661*61046927SAndroid Build Coastguard Worker          new_live += util_bitcount(bytemask & ~(liveness[S]));
662*61046927SAndroid Build Coastguard Worker 
663*61046927SAndroid Build Coastguard Worker          if (destructive)
664*61046927SAndroid Build Coastguard Worker             liveness[S] |= bytemask;
665*61046927SAndroid Build Coastguard Worker       }
666*61046927SAndroid Build Coastguard Worker    }
667*61046927SAndroid Build Coastguard Worker 
668*61046927SAndroid Build Coastguard Worker    return new_live - free_live;
669*61046927SAndroid Build Coastguard Worker }
670*61046927SAndroid Build Coastguard Worker 
671*61046927SAndroid Build Coastguard Worker static midgard_instruction *
mir_choose_instruction(midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned count,struct midgard_predicate * predicate)672*61046927SAndroid Build Coastguard Worker mir_choose_instruction(midgard_instruction **instructions, uint16_t *liveness,
673*61046927SAndroid Build Coastguard Worker                        BITSET_WORD *worklist, unsigned count,
674*61046927SAndroid Build Coastguard Worker                        struct midgard_predicate *predicate)
675*61046927SAndroid Build Coastguard Worker {
676*61046927SAndroid Build Coastguard Worker    /* Parse the predicate */
677*61046927SAndroid Build Coastguard Worker    unsigned tag = predicate->tag;
678*61046927SAndroid Build Coastguard Worker    unsigned unit = predicate->unit;
679*61046927SAndroid Build Coastguard Worker    bool scalar = (unit != ~0) && (unit & UNITS_SCALAR);
680*61046927SAndroid Build Coastguard Worker    bool no_cond = predicate->no_cond;
681*61046927SAndroid Build Coastguard Worker 
682*61046927SAndroid Build Coastguard Worker    unsigned mask = predicate->mask;
683*61046927SAndroid Build Coastguard Worker    unsigned dest = predicate->dest;
684*61046927SAndroid Build Coastguard Worker    bool needs_dest = mask & 0xF;
685*61046927SAndroid Build Coastguard Worker 
686*61046927SAndroid Build Coastguard Worker    /* Iterate to find the best instruction satisfying the predicate */
687*61046927SAndroid Build Coastguard Worker    unsigned i;
688*61046927SAndroid Build Coastguard Worker 
689*61046927SAndroid Build Coastguard Worker    signed best_index = -1;
690*61046927SAndroid Build Coastguard Worker    signed best_effect = INT_MAX;
691*61046927SAndroid Build Coastguard Worker    bool best_conditional = false;
692*61046927SAndroid Build Coastguard Worker 
693*61046927SAndroid Build Coastguard Worker    /* Enforce a simple metric limiting distance to keep down register
694*61046927SAndroid Build Coastguard Worker     * pressure. TOOD: replace with liveness tracking for much better
695*61046927SAndroid Build Coastguard Worker     * results */
696*61046927SAndroid Build Coastguard Worker 
697*61046927SAndroid Build Coastguard Worker    unsigned max_active = 0;
698*61046927SAndroid Build Coastguard Worker    unsigned max_distance = 36;
699*61046927SAndroid Build Coastguard Worker 
700*61046927SAndroid Build Coastguard Worker #ifndef NDEBUG
701*61046927SAndroid Build Coastguard Worker    /* Force in-order scheduling */
702*61046927SAndroid Build Coastguard Worker    if (midgard_debug & MIDGARD_DBG_INORDER)
703*61046927SAndroid Build Coastguard Worker       max_distance = 1;
704*61046927SAndroid Build Coastguard Worker #endif
705*61046927SAndroid Build Coastguard Worker 
706*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, worklist, count) {
707*61046927SAndroid Build Coastguard Worker       max_active = MAX2(max_active, i);
708*61046927SAndroid Build Coastguard Worker    }
709*61046927SAndroid Build Coastguard Worker 
710*61046927SAndroid Build Coastguard Worker    BITSET_FOREACH_SET(i, worklist, count) {
711*61046927SAndroid Build Coastguard Worker       if ((max_active - i) >= max_distance)
712*61046927SAndroid Build Coastguard Worker          continue;
713*61046927SAndroid Build Coastguard Worker 
714*61046927SAndroid Build Coastguard Worker       if (tag != ~0 && instructions[i]->type != tag)
715*61046927SAndroid Build Coastguard Worker          continue;
716*61046927SAndroid Build Coastguard Worker 
717*61046927SAndroid Build Coastguard Worker       bool alu = (instructions[i]->type == TAG_ALU_4);
718*61046927SAndroid Build Coastguard Worker       bool ldst = (instructions[i]->type == TAG_LOAD_STORE_4);
719*61046927SAndroid Build Coastguard Worker 
720*61046927SAndroid Build Coastguard Worker       bool branch = alu && (unit == ALU_ENAB_BR_COMPACT);
721*61046927SAndroid Build Coastguard Worker       bool is_move = alu && (instructions[i]->op == midgard_alu_op_imov ||
722*61046927SAndroid Build Coastguard Worker                              instructions[i]->op == midgard_alu_op_fmov);
723*61046927SAndroid Build Coastguard Worker 
724*61046927SAndroid Build Coastguard Worker       if (predicate->exclude != ~0 &&
725*61046927SAndroid Build Coastguard Worker           instructions[i]->dest == predicate->exclude)
726*61046927SAndroid Build Coastguard Worker          continue;
727*61046927SAndroid Build Coastguard Worker 
728*61046927SAndroid Build Coastguard Worker       if (alu && !branch && unit != ~0 &&
729*61046927SAndroid Build Coastguard Worker           !(mir_has_unit(instructions[i], unit)))
730*61046927SAndroid Build Coastguard Worker          continue;
731*61046927SAndroid Build Coastguard Worker 
732*61046927SAndroid Build Coastguard Worker       /* 0: don't care, 1: no moves, 2: only moves */
733*61046927SAndroid Build Coastguard Worker       if (predicate->move_mode && ((predicate->move_mode - 1) != is_move))
734*61046927SAndroid Build Coastguard Worker          continue;
735*61046927SAndroid Build Coastguard Worker 
736*61046927SAndroid Build Coastguard Worker       if (branch && !instructions[i]->compact_branch)
737*61046927SAndroid Build Coastguard Worker          continue;
738*61046927SAndroid Build Coastguard Worker 
739*61046927SAndroid Build Coastguard Worker       if (alu && scalar && !mir_is_scalar(instructions[i]))
740*61046927SAndroid Build Coastguard Worker          continue;
741*61046927SAndroid Build Coastguard Worker 
742*61046927SAndroid Build Coastguard Worker       if (alu && predicate->constants &&
743*61046927SAndroid Build Coastguard Worker           !mir_adjust_constants(instructions[i], predicate, false))
744*61046927SAndroid Build Coastguard Worker          continue;
745*61046927SAndroid Build Coastguard Worker 
746*61046927SAndroid Build Coastguard Worker       if (needs_dest && instructions[i]->dest != dest)
747*61046927SAndroid Build Coastguard Worker          continue;
748*61046927SAndroid Build Coastguard Worker 
749*61046927SAndroid Build Coastguard Worker       if (mask && ((~instructions[i]->mask) & mask))
750*61046927SAndroid Build Coastguard Worker          continue;
751*61046927SAndroid Build Coastguard Worker 
752*61046927SAndroid Build Coastguard Worker       if (instructions[i]->mask & predicate->no_mask)
753*61046927SAndroid Build Coastguard Worker          continue;
754*61046927SAndroid Build Coastguard Worker 
755*61046927SAndroid Build Coastguard Worker       if (ldst &&
756*61046927SAndroid Build Coastguard Worker           mir_pipeline_count(instructions[i]) + predicate->pipeline_count > 2)
757*61046927SAndroid Build Coastguard Worker          continue;
758*61046927SAndroid Build Coastguard Worker 
759*61046927SAndroid Build Coastguard Worker       bool st_vary_a32 = (instructions[i]->op == midgard_op_st_vary_32);
760*61046927SAndroid Build Coastguard Worker 
761*61046927SAndroid Build Coastguard Worker       if (ldst && predicate->any_non_st_vary_a32 && st_vary_a32)
762*61046927SAndroid Build Coastguard Worker          continue;
763*61046927SAndroid Build Coastguard Worker 
764*61046927SAndroid Build Coastguard Worker       if (ldst && predicate->any_st_vary_a32 && !st_vary_a32)
765*61046927SAndroid Build Coastguard Worker          continue;
766*61046927SAndroid Build Coastguard Worker 
767*61046927SAndroid Build Coastguard Worker       bool conditional = alu && !branch && OP_IS_CSEL(instructions[i]->op);
768*61046927SAndroid Build Coastguard Worker       conditional |= (branch && instructions[i]->branch.conditional);
769*61046927SAndroid Build Coastguard Worker 
770*61046927SAndroid Build Coastguard Worker       if (conditional && no_cond)
771*61046927SAndroid Build Coastguard Worker          continue;
772*61046927SAndroid Build Coastguard Worker 
773*61046927SAndroid Build Coastguard Worker       int effect = mir_live_effect(liveness, instructions[i], false);
774*61046927SAndroid Build Coastguard Worker 
775*61046927SAndroid Build Coastguard Worker       if (effect > best_effect)
776*61046927SAndroid Build Coastguard Worker          continue;
777*61046927SAndroid Build Coastguard Worker 
778*61046927SAndroid Build Coastguard Worker       if (effect == best_effect && (signed)i < best_index)
779*61046927SAndroid Build Coastguard Worker          continue;
780*61046927SAndroid Build Coastguard Worker 
781*61046927SAndroid Build Coastguard Worker       best_effect = effect;
782*61046927SAndroid Build Coastguard Worker       best_index = i;
783*61046927SAndroid Build Coastguard Worker       best_conditional = conditional;
784*61046927SAndroid Build Coastguard Worker    }
785*61046927SAndroid Build Coastguard Worker 
786*61046927SAndroid Build Coastguard Worker    /* Did we find anything?  */
787*61046927SAndroid Build Coastguard Worker 
788*61046927SAndroid Build Coastguard Worker    if (best_index < 0)
789*61046927SAndroid Build Coastguard Worker       return NULL;
790*61046927SAndroid Build Coastguard Worker 
791*61046927SAndroid Build Coastguard Worker    /* If we found something, remove it from the worklist */
792*61046927SAndroid Build Coastguard Worker    assert(best_index < count);
793*61046927SAndroid Build Coastguard Worker    midgard_instruction *I = instructions[best_index];
794*61046927SAndroid Build Coastguard Worker 
795*61046927SAndroid Build Coastguard Worker    if (predicate->destructive) {
796*61046927SAndroid Build Coastguard Worker       BITSET_CLEAR(worklist, best_index);
797*61046927SAndroid Build Coastguard Worker 
798*61046927SAndroid Build Coastguard Worker       if (I->type == TAG_ALU_4)
799*61046927SAndroid Build Coastguard Worker          mir_adjust_constants(instructions[best_index], predicate, true);
800*61046927SAndroid Build Coastguard Worker 
801*61046927SAndroid Build Coastguard Worker       if (I->type == TAG_LOAD_STORE_4) {
802*61046927SAndroid Build Coastguard Worker          predicate->pipeline_count +=
803*61046927SAndroid Build Coastguard Worker             mir_pipeline_count(instructions[best_index]);
804*61046927SAndroid Build Coastguard Worker 
805*61046927SAndroid Build Coastguard Worker          if (instructions[best_index]->op == midgard_op_st_vary_32)
806*61046927SAndroid Build Coastguard Worker             predicate->any_st_vary_a32 = true;
807*61046927SAndroid Build Coastguard Worker          else
808*61046927SAndroid Build Coastguard Worker             predicate->any_non_st_vary_a32 = true;
809*61046927SAndroid Build Coastguard Worker       }
810*61046927SAndroid Build Coastguard Worker 
811*61046927SAndroid Build Coastguard Worker       if (I->type == TAG_ALU_4)
812*61046927SAndroid Build Coastguard Worker          mir_adjust_unit(instructions[best_index], unit);
813*61046927SAndroid Build Coastguard Worker 
814*61046927SAndroid Build Coastguard Worker       /* Once we schedule a conditional, we can't again */
815*61046927SAndroid Build Coastguard Worker       predicate->no_cond |= best_conditional;
816*61046927SAndroid Build Coastguard Worker       mir_live_effect(liveness, instructions[best_index], true);
817*61046927SAndroid Build Coastguard Worker    }
818*61046927SAndroid Build Coastguard Worker 
819*61046927SAndroid Build Coastguard Worker    return I;
820*61046927SAndroid Build Coastguard Worker }
821*61046927SAndroid Build Coastguard Worker 
822*61046927SAndroid Build Coastguard Worker /* Still, we don't choose instructions in a vacuum. We need a way to choose the
823*61046927SAndroid Build Coastguard Worker  * best bundle type (ALU, load/store, texture). Nondestructive. */
824*61046927SAndroid Build Coastguard Worker 
825*61046927SAndroid Build Coastguard Worker static unsigned
mir_choose_bundle(midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned count,unsigned num_ldst)826*61046927SAndroid Build Coastguard Worker mir_choose_bundle(midgard_instruction **instructions, uint16_t *liveness,
827*61046927SAndroid Build Coastguard Worker                   BITSET_WORD *worklist, unsigned count, unsigned num_ldst)
828*61046927SAndroid Build Coastguard Worker {
829*61046927SAndroid Build Coastguard Worker    /* At the moment, our algorithm is very simple - use the bundle of the
830*61046927SAndroid Build Coastguard Worker     * best instruction, regardless of what else could be scheduled
831*61046927SAndroid Build Coastguard Worker     * alongside it. This is not optimal but it works okay for in-order */
832*61046927SAndroid Build Coastguard Worker 
833*61046927SAndroid Build Coastguard Worker    struct midgard_predicate predicate = {
834*61046927SAndroid Build Coastguard Worker       .tag = ~0,
835*61046927SAndroid Build Coastguard Worker       .unit = ~0,
836*61046927SAndroid Build Coastguard Worker       .destructive = false,
837*61046927SAndroid Build Coastguard Worker       .exclude = ~0,
838*61046927SAndroid Build Coastguard Worker    };
839*61046927SAndroid Build Coastguard Worker 
840*61046927SAndroid Build Coastguard Worker    midgard_instruction *chosen = mir_choose_instruction(
841*61046927SAndroid Build Coastguard Worker       instructions, liveness, worklist, count, &predicate);
842*61046927SAndroid Build Coastguard Worker 
843*61046927SAndroid Build Coastguard Worker    if (chosen && chosen->type == TAG_LOAD_STORE_4 && !(num_ldst % 2)) {
844*61046927SAndroid Build Coastguard Worker       /* Try to schedule load/store ops in pairs */
845*61046927SAndroid Build Coastguard Worker 
846*61046927SAndroid Build Coastguard Worker       predicate.exclude = chosen->dest;
847*61046927SAndroid Build Coastguard Worker       predicate.tag = TAG_LOAD_STORE_4;
848*61046927SAndroid Build Coastguard Worker 
849*61046927SAndroid Build Coastguard Worker       chosen = mir_choose_instruction(instructions, liveness, worklist, count,
850*61046927SAndroid Build Coastguard Worker                                       &predicate);
851*61046927SAndroid Build Coastguard Worker       if (chosen)
852*61046927SAndroid Build Coastguard Worker          return TAG_LOAD_STORE_4;
853*61046927SAndroid Build Coastguard Worker 
854*61046927SAndroid Build Coastguard Worker       predicate.tag = ~0;
855*61046927SAndroid Build Coastguard Worker 
856*61046927SAndroid Build Coastguard Worker       chosen = mir_choose_instruction(instructions, liveness, worklist, count,
857*61046927SAndroid Build Coastguard Worker                                       &predicate);
858*61046927SAndroid Build Coastguard Worker       assert(chosen == NULL || chosen->type != TAG_LOAD_STORE_4);
859*61046927SAndroid Build Coastguard Worker 
860*61046927SAndroid Build Coastguard Worker       if (chosen)
861*61046927SAndroid Build Coastguard Worker          return chosen->type;
862*61046927SAndroid Build Coastguard Worker       else
863*61046927SAndroid Build Coastguard Worker          return TAG_LOAD_STORE_4;
864*61046927SAndroid Build Coastguard Worker    }
865*61046927SAndroid Build Coastguard Worker 
866*61046927SAndroid Build Coastguard Worker    if (chosen)
867*61046927SAndroid Build Coastguard Worker       return chosen->type;
868*61046927SAndroid Build Coastguard Worker    else
869*61046927SAndroid Build Coastguard Worker       return ~0;
870*61046927SAndroid Build Coastguard Worker }
871*61046927SAndroid Build Coastguard Worker 
872*61046927SAndroid Build Coastguard Worker /* We want to choose an ALU instruction filling a given unit */
873*61046927SAndroid Build Coastguard Worker static void
mir_choose_alu(midgard_instruction ** slot,midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned len,struct midgard_predicate * predicate,unsigned unit)874*61046927SAndroid Build Coastguard Worker mir_choose_alu(midgard_instruction **slot, midgard_instruction **instructions,
875*61046927SAndroid Build Coastguard Worker                uint16_t *liveness, BITSET_WORD *worklist, unsigned len,
876*61046927SAndroid Build Coastguard Worker                struct midgard_predicate *predicate, unsigned unit)
877*61046927SAndroid Build Coastguard Worker {
878*61046927SAndroid Build Coastguard Worker    /* Did we already schedule to this slot? */
879*61046927SAndroid Build Coastguard Worker    if ((*slot) != NULL)
880*61046927SAndroid Build Coastguard Worker       return;
881*61046927SAndroid Build Coastguard Worker 
882*61046927SAndroid Build Coastguard Worker    /* Try to schedule something, if not */
883*61046927SAndroid Build Coastguard Worker    predicate->unit = unit;
884*61046927SAndroid Build Coastguard Worker    *slot =
885*61046927SAndroid Build Coastguard Worker       mir_choose_instruction(instructions, liveness, worklist, len, predicate);
886*61046927SAndroid Build Coastguard Worker 
887*61046927SAndroid Build Coastguard Worker    /* Store unit upon scheduling */
888*61046927SAndroid Build Coastguard Worker    if (*slot && !((*slot)->compact_branch))
889*61046927SAndroid Build Coastguard Worker       (*slot)->unit = unit;
890*61046927SAndroid Build Coastguard Worker }
891*61046927SAndroid Build Coastguard Worker 
892*61046927SAndroid Build Coastguard Worker /* When we are scheduling a branch/csel, we need the consumed condition in the
893*61046927SAndroid Build Coastguard Worker  * same block as a pipeline register. There are two options to enable this:
894*61046927SAndroid Build Coastguard Worker  *
895*61046927SAndroid Build Coastguard Worker  *  - Move the conditional into the bundle. Preferred, but only works if the
896*61046927SAndroid Build Coastguard Worker  *    conditional is used only once and is from this block.
897*61046927SAndroid Build Coastguard Worker  *  - Copy the conditional.
898*61046927SAndroid Build Coastguard Worker  *
899*61046927SAndroid Build Coastguard Worker  * We search for the conditional. If it's in this block, single-use, and
900*61046927SAndroid Build Coastguard Worker  * without embedded constants, we schedule it immediately. Otherwise, we
901*61046927SAndroid Build Coastguard Worker  * schedule a move for it.
902*61046927SAndroid Build Coastguard Worker  *
903*61046927SAndroid Build Coastguard Worker  * mir_comparison_mobile is a helper to find the moveable condition.
904*61046927SAndroid Build Coastguard Worker  */
905*61046927SAndroid Build Coastguard Worker 
906*61046927SAndroid Build Coastguard Worker static unsigned
mir_comparison_mobile(compiler_context * ctx,midgard_instruction ** instructions,struct midgard_predicate * predicate,unsigned count,unsigned cond)907*61046927SAndroid Build Coastguard Worker mir_comparison_mobile(compiler_context *ctx, midgard_instruction **instructions,
908*61046927SAndroid Build Coastguard Worker                       struct midgard_predicate *predicate, unsigned count,
909*61046927SAndroid Build Coastguard Worker                       unsigned cond)
910*61046927SAndroid Build Coastguard Worker {
911*61046927SAndroid Build Coastguard Worker    if (!mir_single_use(ctx, cond))
912*61046927SAndroid Build Coastguard Worker       return ~0;
913*61046927SAndroid Build Coastguard Worker 
914*61046927SAndroid Build Coastguard Worker    unsigned ret = ~0;
915*61046927SAndroid Build Coastguard Worker 
916*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < count; ++i) {
917*61046927SAndroid Build Coastguard Worker       if (instructions[i]->dest != cond)
918*61046927SAndroid Build Coastguard Worker          continue;
919*61046927SAndroid Build Coastguard Worker 
920*61046927SAndroid Build Coastguard Worker       /* Must fit in an ALU bundle */
921*61046927SAndroid Build Coastguard Worker       if (instructions[i]->type != TAG_ALU_4)
922*61046927SAndroid Build Coastguard Worker          return ~0;
923*61046927SAndroid Build Coastguard Worker 
924*61046927SAndroid Build Coastguard Worker       /* If it would itself require a condition, that's recursive */
925*61046927SAndroid Build Coastguard Worker       if (OP_IS_CSEL(instructions[i]->op))
926*61046927SAndroid Build Coastguard Worker          return ~0;
927*61046927SAndroid Build Coastguard Worker 
928*61046927SAndroid Build Coastguard Worker       /* We'll need to rewrite to .w but that doesn't work for vector
929*61046927SAndroid Build Coastguard Worker        * ops that don't replicate (ball/bany), so bail there */
930*61046927SAndroid Build Coastguard Worker 
931*61046927SAndroid Build Coastguard Worker       if (GET_CHANNEL_COUNT(alu_opcode_props[instructions[i]->op].props))
932*61046927SAndroid Build Coastguard Worker          return ~0;
933*61046927SAndroid Build Coastguard Worker 
934*61046927SAndroid Build Coastguard Worker       /* Ensure it will fit with constants */
935*61046927SAndroid Build Coastguard Worker 
936*61046927SAndroid Build Coastguard Worker       if (!mir_adjust_constants(instructions[i], predicate, false))
937*61046927SAndroid Build Coastguard Worker          return ~0;
938*61046927SAndroid Build Coastguard Worker 
939*61046927SAndroid Build Coastguard Worker       /* Ensure it is written only once */
940*61046927SAndroid Build Coastguard Worker 
941*61046927SAndroid Build Coastguard Worker       if (ret != ~0)
942*61046927SAndroid Build Coastguard Worker          return ~0;
943*61046927SAndroid Build Coastguard Worker       else
944*61046927SAndroid Build Coastguard Worker          ret = i;
945*61046927SAndroid Build Coastguard Worker    }
946*61046927SAndroid Build Coastguard Worker 
947*61046927SAndroid Build Coastguard Worker    /* Inject constants now that we are sure we want to */
948*61046927SAndroid Build Coastguard Worker    if (ret != ~0)
949*61046927SAndroid Build Coastguard Worker       mir_adjust_constants(instructions[ret], predicate, true);
950*61046927SAndroid Build Coastguard Worker 
951*61046927SAndroid Build Coastguard Worker    return ret;
952*61046927SAndroid Build Coastguard Worker }
953*61046927SAndroid Build Coastguard Worker 
954*61046927SAndroid Build Coastguard Worker /* Using the information about the moveable conditional itself, we either pop
955*61046927SAndroid Build Coastguard Worker  * that condition off the worklist for use now, or create a move to
956*61046927SAndroid Build Coastguard Worker  * artificially schedule instead as a fallback */
957*61046927SAndroid Build Coastguard Worker 
958*61046927SAndroid Build Coastguard Worker static midgard_instruction *
mir_schedule_comparison(compiler_context * ctx,midgard_instruction ** instructions,struct midgard_predicate * predicate,BITSET_WORD * worklist,unsigned count,unsigned cond,bool vector,unsigned * swizzle,midgard_instruction * user)959*61046927SAndroid Build Coastguard Worker mir_schedule_comparison(compiler_context *ctx,
960*61046927SAndroid Build Coastguard Worker                         midgard_instruction **instructions,
961*61046927SAndroid Build Coastguard Worker                         struct midgard_predicate *predicate,
962*61046927SAndroid Build Coastguard Worker                         BITSET_WORD *worklist, unsigned count, unsigned cond,
963*61046927SAndroid Build Coastguard Worker                         bool vector, unsigned *swizzle,
964*61046927SAndroid Build Coastguard Worker                         midgard_instruction *user)
965*61046927SAndroid Build Coastguard Worker {
966*61046927SAndroid Build Coastguard Worker    /* TODO: swizzle when scheduling */
967*61046927SAndroid Build Coastguard Worker    unsigned comp_i =
968*61046927SAndroid Build Coastguard Worker       (!vector && (swizzle[0] == 0))
969*61046927SAndroid Build Coastguard Worker          ? mir_comparison_mobile(ctx, instructions, predicate, count, cond)
970*61046927SAndroid Build Coastguard Worker          : ~0;
971*61046927SAndroid Build Coastguard Worker 
972*61046927SAndroid Build Coastguard Worker    /* If we can, schedule the condition immediately */
973*61046927SAndroid Build Coastguard Worker    if ((comp_i != ~0) && BITSET_TEST(worklist, comp_i)) {
974*61046927SAndroid Build Coastguard Worker       assert(comp_i < count);
975*61046927SAndroid Build Coastguard Worker       BITSET_CLEAR(worklist, comp_i);
976*61046927SAndroid Build Coastguard Worker       return instructions[comp_i];
977*61046927SAndroid Build Coastguard Worker    }
978*61046927SAndroid Build Coastguard Worker 
979*61046927SAndroid Build Coastguard Worker    /* Otherwise, we insert a move */
980*61046927SAndroid Build Coastguard Worker 
981*61046927SAndroid Build Coastguard Worker    midgard_instruction mov = v_mov(cond, cond);
982*61046927SAndroid Build Coastguard Worker    mov.mask = vector ? 0xF : 0x1;
983*61046927SAndroid Build Coastguard Worker    memcpy(mov.swizzle[1], swizzle, sizeof(mov.swizzle[1]));
984*61046927SAndroid Build Coastguard Worker 
985*61046927SAndroid Build Coastguard Worker    return mir_insert_instruction_before(ctx, user, mov);
986*61046927SAndroid Build Coastguard Worker }
987*61046927SAndroid Build Coastguard Worker 
988*61046927SAndroid Build Coastguard Worker /* Most generally, we need instructions writing to r31 in the appropriate
989*61046927SAndroid Build Coastguard Worker  * components */
990*61046927SAndroid Build Coastguard Worker 
991*61046927SAndroid Build Coastguard Worker static midgard_instruction *
mir_schedule_condition(compiler_context * ctx,struct midgard_predicate * predicate,BITSET_WORD * worklist,unsigned count,midgard_instruction ** instructions,midgard_instruction * last)992*61046927SAndroid Build Coastguard Worker mir_schedule_condition(compiler_context *ctx,
993*61046927SAndroid Build Coastguard Worker                        struct midgard_predicate *predicate,
994*61046927SAndroid Build Coastguard Worker                        BITSET_WORD *worklist, unsigned count,
995*61046927SAndroid Build Coastguard Worker                        midgard_instruction **instructions,
996*61046927SAndroid Build Coastguard Worker                        midgard_instruction *last)
997*61046927SAndroid Build Coastguard Worker {
998*61046927SAndroid Build Coastguard Worker    /* For a branch, the condition is the only argument; for csel, third */
999*61046927SAndroid Build Coastguard Worker    bool branch = last->compact_branch;
1000*61046927SAndroid Build Coastguard Worker    unsigned condition_index = branch ? 0 : 2;
1001*61046927SAndroid Build Coastguard Worker 
1002*61046927SAndroid Build Coastguard Worker    /* csel_v is vector; otherwise, conditions are scalar */
1003*61046927SAndroid Build Coastguard Worker    bool vector = !branch && OP_IS_CSEL_V(last->op);
1004*61046927SAndroid Build Coastguard Worker 
1005*61046927SAndroid Build Coastguard Worker    /* Grab the conditional instruction */
1006*61046927SAndroid Build Coastguard Worker 
1007*61046927SAndroid Build Coastguard Worker    midgard_instruction *cond = mir_schedule_comparison(
1008*61046927SAndroid Build Coastguard Worker       ctx, instructions, predicate, worklist, count, last->src[condition_index],
1009*61046927SAndroid Build Coastguard Worker       vector, last->swizzle[condition_index], last);
1010*61046927SAndroid Build Coastguard Worker 
1011*61046927SAndroid Build Coastguard Worker    /* We have exclusive reign over this (possibly move) conditional
1012*61046927SAndroid Build Coastguard Worker     * instruction. We can rewrite into a pipeline conditional register */
1013*61046927SAndroid Build Coastguard Worker 
1014*61046927SAndroid Build Coastguard Worker    predicate->exclude = cond->dest;
1015*61046927SAndroid Build Coastguard Worker    cond->dest = SSA_FIXED_REGISTER(31);
1016*61046927SAndroid Build Coastguard Worker    last->src[condition_index] = cond->dest;
1017*61046927SAndroid Build Coastguard Worker 
1018*61046927SAndroid Build Coastguard Worker    if (!vector) {
1019*61046927SAndroid Build Coastguard Worker       cond->mask = (1 << COMPONENT_W);
1020*61046927SAndroid Build Coastguard Worker 
1021*61046927SAndroid Build Coastguard Worker       mir_foreach_src(cond, s) {
1022*61046927SAndroid Build Coastguard Worker          if (cond->src[s] == ~0)
1023*61046927SAndroid Build Coastguard Worker             continue;
1024*61046927SAndroid Build Coastguard Worker 
1025*61046927SAndroid Build Coastguard Worker          for (unsigned q = 0; q < 4; ++q)
1026*61046927SAndroid Build Coastguard Worker             cond->swizzle[s][q + COMPONENT_W] = cond->swizzle[s][q];
1027*61046927SAndroid Build Coastguard Worker       }
1028*61046927SAndroid Build Coastguard Worker 
1029*61046927SAndroid Build Coastguard Worker       last->swizzle[condition_index][0] = COMPONENT_W;
1030*61046927SAndroid Build Coastguard Worker    }
1031*61046927SAndroid Build Coastguard Worker 
1032*61046927SAndroid Build Coastguard Worker    /* Schedule the unit: csel is always in the latter pipeline, so a csel
1033*61046927SAndroid Build Coastguard Worker     * condition must be in the former pipeline stage (vmul/sadd),
1034*61046927SAndroid Build Coastguard Worker     * depending on scalar/vector of the instruction itself. A branch must
1035*61046927SAndroid Build Coastguard Worker     * be written from the latter pipeline stage and a branch condition is
1036*61046927SAndroid Build Coastguard Worker     * always scalar, so it is always in smul (exception: ball/bany, which
1037*61046927SAndroid Build Coastguard Worker     * will be vadd) */
1038*61046927SAndroid Build Coastguard Worker 
1039*61046927SAndroid Build Coastguard Worker    if (branch)
1040*61046927SAndroid Build Coastguard Worker       cond->unit = UNIT_SMUL;
1041*61046927SAndroid Build Coastguard Worker    else
1042*61046927SAndroid Build Coastguard Worker       cond->unit = vector ? UNIT_VMUL : UNIT_SADD;
1043*61046927SAndroid Build Coastguard Worker 
1044*61046927SAndroid Build Coastguard Worker    return cond;
1045*61046927SAndroid Build Coastguard Worker }
1046*61046927SAndroid Build Coastguard Worker 
1047*61046927SAndroid Build Coastguard Worker /* Schedules a single bundle of the given type */
1048*61046927SAndroid Build Coastguard Worker 
1049*61046927SAndroid Build Coastguard Worker static midgard_bundle
mir_schedule_texture(midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned len,bool is_vertex)1050*61046927SAndroid Build Coastguard Worker mir_schedule_texture(midgard_instruction **instructions, uint16_t *liveness,
1051*61046927SAndroid Build Coastguard Worker                      BITSET_WORD *worklist, unsigned len, bool is_vertex)
1052*61046927SAndroid Build Coastguard Worker {
1053*61046927SAndroid Build Coastguard Worker    struct midgard_predicate predicate = {
1054*61046927SAndroid Build Coastguard Worker       .tag = TAG_TEXTURE_4,
1055*61046927SAndroid Build Coastguard Worker       .destructive = true,
1056*61046927SAndroid Build Coastguard Worker       .exclude = ~0,
1057*61046927SAndroid Build Coastguard Worker    };
1058*61046927SAndroid Build Coastguard Worker 
1059*61046927SAndroid Build Coastguard Worker    midgard_instruction *ins =
1060*61046927SAndroid Build Coastguard Worker       mir_choose_instruction(instructions, liveness, worklist, len, &predicate);
1061*61046927SAndroid Build Coastguard Worker 
1062*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, ins);
1063*61046927SAndroid Build Coastguard Worker 
1064*61046927SAndroid Build Coastguard Worker    struct midgard_bundle out = {
1065*61046927SAndroid Build Coastguard Worker       .tag = ins->op == midgard_tex_op_barrier ? TAG_TEXTURE_4_BARRIER
1066*61046927SAndroid Build Coastguard Worker              : (ins->op == midgard_tex_op_fetch) || is_vertex
1067*61046927SAndroid Build Coastguard Worker                 ? TAG_TEXTURE_4_VTX
1068*61046927SAndroid Build Coastguard Worker                 : TAG_TEXTURE_4,
1069*61046927SAndroid Build Coastguard Worker       .instruction_count = 1,
1070*61046927SAndroid Build Coastguard Worker       .instructions = {ins},
1071*61046927SAndroid Build Coastguard Worker    };
1072*61046927SAndroid Build Coastguard Worker 
1073*61046927SAndroid Build Coastguard Worker    return out;
1074*61046927SAndroid Build Coastguard Worker }
1075*61046927SAndroid Build Coastguard Worker 
1076*61046927SAndroid Build Coastguard Worker static midgard_bundle
mir_schedule_ldst(midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned len,unsigned * num_ldst)1077*61046927SAndroid Build Coastguard Worker mir_schedule_ldst(midgard_instruction **instructions, uint16_t *liveness,
1078*61046927SAndroid Build Coastguard Worker                   BITSET_WORD *worklist, unsigned len, unsigned *num_ldst)
1079*61046927SAndroid Build Coastguard Worker {
1080*61046927SAndroid Build Coastguard Worker    struct midgard_predicate predicate = {
1081*61046927SAndroid Build Coastguard Worker       .tag = TAG_LOAD_STORE_4,
1082*61046927SAndroid Build Coastguard Worker       .destructive = true,
1083*61046927SAndroid Build Coastguard Worker       .exclude = ~0,
1084*61046927SAndroid Build Coastguard Worker    };
1085*61046927SAndroid Build Coastguard Worker 
1086*61046927SAndroid Build Coastguard Worker    /* Try to pick two load/store ops. Second not gauranteed to exist */
1087*61046927SAndroid Build Coastguard Worker 
1088*61046927SAndroid Build Coastguard Worker    midgard_instruction *ins =
1089*61046927SAndroid Build Coastguard Worker       mir_choose_instruction(instructions, liveness, worklist, len, &predicate);
1090*61046927SAndroid Build Coastguard Worker 
1091*61046927SAndroid Build Coastguard Worker    midgard_instruction *pair =
1092*61046927SAndroid Build Coastguard Worker       mir_choose_instruction(instructions, liveness, worklist, len, &predicate);
1093*61046927SAndroid Build Coastguard Worker 
1094*61046927SAndroid Build Coastguard Worker    assert(ins != NULL);
1095*61046927SAndroid Build Coastguard Worker 
1096*61046927SAndroid Build Coastguard Worker    struct midgard_bundle out = {
1097*61046927SAndroid Build Coastguard Worker       .tag = TAG_LOAD_STORE_4,
1098*61046927SAndroid Build Coastguard Worker       .instruction_count = pair ? 2 : 1,
1099*61046927SAndroid Build Coastguard Worker       .instructions = {ins, pair},
1100*61046927SAndroid Build Coastguard Worker    };
1101*61046927SAndroid Build Coastguard Worker 
1102*61046927SAndroid Build Coastguard Worker    *num_ldst -= out.instruction_count;
1103*61046927SAndroid Build Coastguard Worker 
1104*61046927SAndroid Build Coastguard Worker    /* We have to update the worklist atomically, since the two
1105*61046927SAndroid Build Coastguard Worker     * instructions run concurrently (TODO: verify it's not pipelined) */
1106*61046927SAndroid Build Coastguard Worker 
1107*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, ins);
1108*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, pair);
1109*61046927SAndroid Build Coastguard Worker 
1110*61046927SAndroid Build Coastguard Worker    return out;
1111*61046927SAndroid Build Coastguard Worker }
1112*61046927SAndroid Build Coastguard Worker 
1113*61046927SAndroid Build Coastguard Worker static void
mir_schedule_zs_write(compiler_context * ctx,struct midgard_predicate * predicate,midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned len,midgard_instruction * branch,midgard_instruction ** smul,midgard_instruction ** vadd,midgard_instruction ** vlut,bool stencil)1114*61046927SAndroid Build Coastguard Worker mir_schedule_zs_write(compiler_context *ctx,
1115*61046927SAndroid Build Coastguard Worker                       struct midgard_predicate *predicate,
1116*61046927SAndroid Build Coastguard Worker                       midgard_instruction **instructions, uint16_t *liveness,
1117*61046927SAndroid Build Coastguard Worker                       BITSET_WORD *worklist, unsigned len,
1118*61046927SAndroid Build Coastguard Worker                       midgard_instruction *branch, midgard_instruction **smul,
1119*61046927SAndroid Build Coastguard Worker                       midgard_instruction **vadd, midgard_instruction **vlut,
1120*61046927SAndroid Build Coastguard Worker                       bool stencil)
1121*61046927SAndroid Build Coastguard Worker {
1122*61046927SAndroid Build Coastguard Worker    bool success = false;
1123*61046927SAndroid Build Coastguard Worker    unsigned idx = stencil ? 3 : 2;
1124*61046927SAndroid Build Coastguard Worker    unsigned src =
1125*61046927SAndroid Build Coastguard Worker       (branch->src[0] == ~0) ? SSA_FIXED_REGISTER(1) : branch->src[idx];
1126*61046927SAndroid Build Coastguard Worker 
1127*61046927SAndroid Build Coastguard Worker    predicate->dest = src;
1128*61046927SAndroid Build Coastguard Worker    predicate->mask = 0x1;
1129*61046927SAndroid Build Coastguard Worker 
1130*61046927SAndroid Build Coastguard Worker    midgard_instruction **units[] = {smul, vadd, vlut};
1131*61046927SAndroid Build Coastguard Worker    unsigned unit_names[] = {UNIT_SMUL, UNIT_VADD, UNIT_VLUT};
1132*61046927SAndroid Build Coastguard Worker 
1133*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < 3; ++i) {
1134*61046927SAndroid Build Coastguard Worker       if (*(units[i]))
1135*61046927SAndroid Build Coastguard Worker          continue;
1136*61046927SAndroid Build Coastguard Worker 
1137*61046927SAndroid Build Coastguard Worker       predicate->unit = unit_names[i];
1138*61046927SAndroid Build Coastguard Worker       midgard_instruction *ins = mir_choose_instruction(
1139*61046927SAndroid Build Coastguard Worker          instructions, liveness, worklist, len, predicate);
1140*61046927SAndroid Build Coastguard Worker 
1141*61046927SAndroid Build Coastguard Worker       if (ins) {
1142*61046927SAndroid Build Coastguard Worker          ins->unit = unit_names[i];
1143*61046927SAndroid Build Coastguard Worker          *(units[i]) = ins;
1144*61046927SAndroid Build Coastguard Worker          success |= true;
1145*61046927SAndroid Build Coastguard Worker          break;
1146*61046927SAndroid Build Coastguard Worker       }
1147*61046927SAndroid Build Coastguard Worker    }
1148*61046927SAndroid Build Coastguard Worker 
1149*61046927SAndroid Build Coastguard Worker    predicate->dest = predicate->mask = 0;
1150*61046927SAndroid Build Coastguard Worker 
1151*61046927SAndroid Build Coastguard Worker    if (success)
1152*61046927SAndroid Build Coastguard Worker       return;
1153*61046927SAndroid Build Coastguard Worker 
1154*61046927SAndroid Build Coastguard Worker    midgard_instruction *mov = ralloc(ctx, midgard_instruction);
1155*61046927SAndroid Build Coastguard Worker    *mov = v_mov(src, make_compiler_temp(ctx));
1156*61046927SAndroid Build Coastguard Worker    mov->mask = 0x1;
1157*61046927SAndroid Build Coastguard Worker 
1158*61046927SAndroid Build Coastguard Worker    branch->src[idx] = mov->dest;
1159*61046927SAndroid Build Coastguard Worker 
1160*61046927SAndroid Build Coastguard Worker    if (stencil) {
1161*61046927SAndroid Build Coastguard Worker       unsigned swizzle = (branch->src[0] == ~0) ? COMPONENT_Y : COMPONENT_X;
1162*61046927SAndroid Build Coastguard Worker 
1163*61046927SAndroid Build Coastguard Worker       for (unsigned c = 0; c < 16; ++c)
1164*61046927SAndroid Build Coastguard Worker          mov->swizzle[1][c] = swizzle;
1165*61046927SAndroid Build Coastguard Worker    }
1166*61046927SAndroid Build Coastguard Worker 
1167*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < 3; ++i) {
1168*61046927SAndroid Build Coastguard Worker       if (!(*(units[i]))) {
1169*61046927SAndroid Build Coastguard Worker          *(units[i]) = mov;
1170*61046927SAndroid Build Coastguard Worker          mov->unit = unit_names[i];
1171*61046927SAndroid Build Coastguard Worker          return;
1172*61046927SAndroid Build Coastguard Worker       }
1173*61046927SAndroid Build Coastguard Worker    }
1174*61046927SAndroid Build Coastguard Worker 
1175*61046927SAndroid Build Coastguard Worker    unreachable("Could not schedule Z/S move to any unit");
1176*61046927SAndroid Build Coastguard Worker }
1177*61046927SAndroid Build Coastguard Worker 
1178*61046927SAndroid Build Coastguard Worker static midgard_bundle
mir_schedule_alu(compiler_context * ctx,midgard_instruction ** instructions,uint16_t * liveness,BITSET_WORD * worklist,unsigned len)1179*61046927SAndroid Build Coastguard Worker mir_schedule_alu(compiler_context *ctx, midgard_instruction **instructions,
1180*61046927SAndroid Build Coastguard Worker                  uint16_t *liveness, BITSET_WORD *worklist, unsigned len)
1181*61046927SAndroid Build Coastguard Worker {
1182*61046927SAndroid Build Coastguard Worker    struct midgard_bundle bundle = {};
1183*61046927SAndroid Build Coastguard Worker 
1184*61046927SAndroid Build Coastguard Worker    unsigned bytes_emitted = sizeof(bundle.control);
1185*61046927SAndroid Build Coastguard Worker 
1186*61046927SAndroid Build Coastguard Worker    struct midgard_predicate predicate = {
1187*61046927SAndroid Build Coastguard Worker       .tag = TAG_ALU_4,
1188*61046927SAndroid Build Coastguard Worker       .destructive = true,
1189*61046927SAndroid Build Coastguard Worker       .exclude = ~0,
1190*61046927SAndroid Build Coastguard Worker       .constants = &bundle.constants,
1191*61046927SAndroid Build Coastguard Worker    };
1192*61046927SAndroid Build Coastguard Worker 
1193*61046927SAndroid Build Coastguard Worker    midgard_instruction *vmul = NULL;
1194*61046927SAndroid Build Coastguard Worker    midgard_instruction *vadd = NULL;
1195*61046927SAndroid Build Coastguard Worker    midgard_instruction *vlut = NULL;
1196*61046927SAndroid Build Coastguard Worker    midgard_instruction *smul = NULL;
1197*61046927SAndroid Build Coastguard Worker    midgard_instruction *sadd = NULL;
1198*61046927SAndroid Build Coastguard Worker    midgard_instruction *branch = NULL;
1199*61046927SAndroid Build Coastguard Worker 
1200*61046927SAndroid Build Coastguard Worker    mir_choose_alu(&branch, instructions, liveness, worklist, len, &predicate,
1201*61046927SAndroid Build Coastguard Worker                   ALU_ENAB_BR_COMPACT);
1202*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, branch);
1203*61046927SAndroid Build Coastguard Worker    unsigned writeout = branch ? branch->writeout : 0;
1204*61046927SAndroid Build Coastguard Worker 
1205*61046927SAndroid Build Coastguard Worker    if (branch && branch->branch.conditional) {
1206*61046927SAndroid Build Coastguard Worker       midgard_instruction *cond = mir_schedule_condition(
1207*61046927SAndroid Build Coastguard Worker          ctx, &predicate, worklist, len, instructions, branch);
1208*61046927SAndroid Build Coastguard Worker 
1209*61046927SAndroid Build Coastguard Worker       if (cond->unit == UNIT_VADD)
1210*61046927SAndroid Build Coastguard Worker          vadd = cond;
1211*61046927SAndroid Build Coastguard Worker       else if (cond->unit == UNIT_SMUL)
1212*61046927SAndroid Build Coastguard Worker          smul = cond;
1213*61046927SAndroid Build Coastguard Worker       else
1214*61046927SAndroid Build Coastguard Worker          unreachable("Bad condition");
1215*61046927SAndroid Build Coastguard Worker    }
1216*61046927SAndroid Build Coastguard Worker 
1217*61046927SAndroid Build Coastguard Worker    /* If we have a render target reference, schedule a move for it. Since
1218*61046927SAndroid Build Coastguard Worker     * this will be in sadd, we boost this to prevent scheduling csel into
1219*61046927SAndroid Build Coastguard Worker     * smul */
1220*61046927SAndroid Build Coastguard Worker 
1221*61046927SAndroid Build Coastguard Worker    if (writeout && (branch->constants.u32[0] || ctx->inputs->is_blend)) {
1222*61046927SAndroid Build Coastguard Worker       sadd = ralloc(ctx, midgard_instruction);
1223*61046927SAndroid Build Coastguard Worker       *sadd = v_mov(~0, make_compiler_temp(ctx));
1224*61046927SAndroid Build Coastguard Worker       sadd->unit = UNIT_SADD;
1225*61046927SAndroid Build Coastguard Worker       sadd->mask = 0x1;
1226*61046927SAndroid Build Coastguard Worker       sadd->has_inline_constant = true;
1227*61046927SAndroid Build Coastguard Worker       sadd->inline_constant = branch->constants.u32[0];
1228*61046927SAndroid Build Coastguard Worker       branch->src[1] = sadd->dest;
1229*61046927SAndroid Build Coastguard Worker       branch->src_types[1] = sadd->dest_type;
1230*61046927SAndroid Build Coastguard Worker    }
1231*61046927SAndroid Build Coastguard Worker 
1232*61046927SAndroid Build Coastguard Worker    if (writeout) {
1233*61046927SAndroid Build Coastguard Worker       /* Propagate up */
1234*61046927SAndroid Build Coastguard Worker       bundle.last_writeout = branch->last_writeout;
1235*61046927SAndroid Build Coastguard Worker 
1236*61046927SAndroid Build Coastguard Worker       /* Mask off any conditionals.
1237*61046927SAndroid Build Coastguard Worker        * This prevents csel and csel_v being scheduled into smul
1238*61046927SAndroid Build Coastguard Worker        * since we might not have room for a conditional in vmul/sadd.
1239*61046927SAndroid Build Coastguard Worker        * This is important because both writeout and csel have same-bundle
1240*61046927SAndroid Build Coastguard Worker        * requirements on their dependencies. */
1241*61046927SAndroid Build Coastguard Worker       predicate.no_cond = true;
1242*61046927SAndroid Build Coastguard Worker    }
1243*61046927SAndroid Build Coastguard Worker 
1244*61046927SAndroid Build Coastguard Worker    /* Set r1.w to the return address so we can return from blend shaders */
1245*61046927SAndroid Build Coastguard Worker    if (writeout) {
1246*61046927SAndroid Build Coastguard Worker       vadd = ralloc(ctx, midgard_instruction);
1247*61046927SAndroid Build Coastguard Worker       *vadd = v_mov(~0, make_compiler_temp(ctx));
1248*61046927SAndroid Build Coastguard Worker 
1249*61046927SAndroid Build Coastguard Worker       if (!ctx->inputs->is_blend) {
1250*61046927SAndroid Build Coastguard Worker          vadd->op = midgard_alu_op_iadd;
1251*61046927SAndroid Build Coastguard Worker          vadd->src[0] = SSA_FIXED_REGISTER(31);
1252*61046927SAndroid Build Coastguard Worker          vadd->src_types[0] = nir_type_uint32;
1253*61046927SAndroid Build Coastguard Worker 
1254*61046927SAndroid Build Coastguard Worker          for (unsigned c = 0; c < 16; ++c)
1255*61046927SAndroid Build Coastguard Worker             vadd->swizzle[0][c] = COMPONENT_X;
1256*61046927SAndroid Build Coastguard Worker 
1257*61046927SAndroid Build Coastguard Worker          vadd->has_inline_constant = true;
1258*61046927SAndroid Build Coastguard Worker          vadd->inline_constant = 0;
1259*61046927SAndroid Build Coastguard Worker       } else {
1260*61046927SAndroid Build Coastguard Worker          vadd->src[1] = SSA_FIXED_REGISTER(1);
1261*61046927SAndroid Build Coastguard Worker          vadd->src_types[0] = nir_type_uint32;
1262*61046927SAndroid Build Coastguard Worker 
1263*61046927SAndroid Build Coastguard Worker          for (unsigned c = 0; c < 16; ++c)
1264*61046927SAndroid Build Coastguard Worker             vadd->swizzle[1][c] = COMPONENT_W;
1265*61046927SAndroid Build Coastguard Worker       }
1266*61046927SAndroid Build Coastguard Worker 
1267*61046927SAndroid Build Coastguard Worker       vadd->unit = UNIT_VADD;
1268*61046927SAndroid Build Coastguard Worker       vadd->mask = 0x1;
1269*61046927SAndroid Build Coastguard Worker       branch->dest = vadd->dest;
1270*61046927SAndroid Build Coastguard Worker       branch->dest_type = vadd->dest_type;
1271*61046927SAndroid Build Coastguard Worker    }
1272*61046927SAndroid Build Coastguard Worker 
1273*61046927SAndroid Build Coastguard Worker    if (writeout & PAN_WRITEOUT_Z)
1274*61046927SAndroid Build Coastguard Worker       mir_schedule_zs_write(ctx, &predicate, instructions, liveness, worklist,
1275*61046927SAndroid Build Coastguard Worker                             len, branch, &smul, &vadd, &vlut, false);
1276*61046927SAndroid Build Coastguard Worker 
1277*61046927SAndroid Build Coastguard Worker    if (writeout & PAN_WRITEOUT_S)
1278*61046927SAndroid Build Coastguard Worker       mir_schedule_zs_write(ctx, &predicate, instructions, liveness, worklist,
1279*61046927SAndroid Build Coastguard Worker                             len, branch, &smul, &vadd, &vlut, true);
1280*61046927SAndroid Build Coastguard Worker 
1281*61046927SAndroid Build Coastguard Worker    mir_choose_alu(&smul, instructions, liveness, worklist, len, &predicate,
1282*61046927SAndroid Build Coastguard Worker                   UNIT_SMUL);
1283*61046927SAndroid Build Coastguard Worker 
1284*61046927SAndroid Build Coastguard Worker    for (unsigned mode = 1; mode < 3; ++mode) {
1285*61046927SAndroid Build Coastguard Worker       predicate.move_mode = mode;
1286*61046927SAndroid Build Coastguard Worker       predicate.no_mask = writeout ? (1 << 3) : 0;
1287*61046927SAndroid Build Coastguard Worker       mir_choose_alu(&vlut, instructions, liveness, worklist, len, &predicate,
1288*61046927SAndroid Build Coastguard Worker                      UNIT_VLUT);
1289*61046927SAndroid Build Coastguard Worker       predicate.no_mask = 0;
1290*61046927SAndroid Build Coastguard Worker       mir_choose_alu(&vadd, instructions, liveness, worklist, len, &predicate,
1291*61046927SAndroid Build Coastguard Worker                      UNIT_VADD);
1292*61046927SAndroid Build Coastguard Worker    }
1293*61046927SAndroid Build Coastguard Worker 
1294*61046927SAndroid Build Coastguard Worker    /* Reset */
1295*61046927SAndroid Build Coastguard Worker    predicate.move_mode = 0;
1296*61046927SAndroid Build Coastguard Worker    predicate.exclude = ~0;
1297*61046927SAndroid Build Coastguard Worker 
1298*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, vlut);
1299*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, vadd);
1300*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, smul);
1301*61046927SAndroid Build Coastguard Worker 
1302*61046927SAndroid Build Coastguard Worker    bool vadd_csel = vadd && OP_IS_CSEL(vadd->op);
1303*61046927SAndroid Build Coastguard Worker    bool smul_csel = smul && OP_IS_CSEL(smul->op);
1304*61046927SAndroid Build Coastguard Worker 
1305*61046927SAndroid Build Coastguard Worker    if (vadd_csel || smul_csel) {
1306*61046927SAndroid Build Coastguard Worker       midgard_instruction *ins = vadd_csel ? vadd : smul;
1307*61046927SAndroid Build Coastguard Worker       midgard_instruction *cond = mir_schedule_condition(
1308*61046927SAndroid Build Coastguard Worker          ctx, &predicate, worklist, len, instructions, ins);
1309*61046927SAndroid Build Coastguard Worker 
1310*61046927SAndroid Build Coastguard Worker       if (cond->unit == UNIT_VMUL)
1311*61046927SAndroid Build Coastguard Worker          vmul = cond;
1312*61046927SAndroid Build Coastguard Worker       else if (cond->unit == UNIT_SADD)
1313*61046927SAndroid Build Coastguard Worker          sadd = cond;
1314*61046927SAndroid Build Coastguard Worker       else
1315*61046927SAndroid Build Coastguard Worker          unreachable("Bad condition");
1316*61046927SAndroid Build Coastguard Worker    }
1317*61046927SAndroid Build Coastguard Worker 
1318*61046927SAndroid Build Coastguard Worker    /* Stage 2, let's schedule sadd before vmul for writeout */
1319*61046927SAndroid Build Coastguard Worker    mir_choose_alu(&sadd, instructions, liveness, worklist, len, &predicate,
1320*61046927SAndroid Build Coastguard Worker                   UNIT_SADD);
1321*61046927SAndroid Build Coastguard Worker 
1322*61046927SAndroid Build Coastguard Worker    /* Check if writeout reads its own register */
1323*61046927SAndroid Build Coastguard Worker 
1324*61046927SAndroid Build Coastguard Worker    if (writeout) {
1325*61046927SAndroid Build Coastguard Worker       midgard_instruction *stages[] = {sadd, vadd, smul, vlut};
1326*61046927SAndroid Build Coastguard Worker       unsigned src =
1327*61046927SAndroid Build Coastguard Worker          (branch->src[0] == ~0) ? SSA_FIXED_REGISTER(0) : branch->src[0];
1328*61046927SAndroid Build Coastguard Worker       unsigned writeout_mask = 0x0;
1329*61046927SAndroid Build Coastguard Worker       bool bad_writeout = false;
1330*61046927SAndroid Build Coastguard Worker 
1331*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < ARRAY_SIZE(stages); ++i) {
1332*61046927SAndroid Build Coastguard Worker          if (!stages[i])
1333*61046927SAndroid Build Coastguard Worker             continue;
1334*61046927SAndroid Build Coastguard Worker 
1335*61046927SAndroid Build Coastguard Worker          if (stages[i]->dest != src)
1336*61046927SAndroid Build Coastguard Worker             continue;
1337*61046927SAndroid Build Coastguard Worker 
1338*61046927SAndroid Build Coastguard Worker          writeout_mask |= stages[i]->mask;
1339*61046927SAndroid Build Coastguard Worker          bad_writeout |= mir_has_arg(stages[i], branch->src[0]);
1340*61046927SAndroid Build Coastguard Worker       }
1341*61046927SAndroid Build Coastguard Worker 
1342*61046927SAndroid Build Coastguard Worker       /* It's possible we'll be able to schedule something into vmul
1343*61046927SAndroid Build Coastguard Worker        * to fill r0. Let's peak into the future, trying to schedule
1344*61046927SAndroid Build Coastguard Worker        * vmul specially that way. */
1345*61046927SAndroid Build Coastguard Worker 
1346*61046927SAndroid Build Coastguard Worker       unsigned full_mask = 0xF;
1347*61046927SAndroid Build Coastguard Worker 
1348*61046927SAndroid Build Coastguard Worker       if (!bad_writeout && writeout_mask != full_mask) {
1349*61046927SAndroid Build Coastguard Worker          predicate.unit = UNIT_VMUL;
1350*61046927SAndroid Build Coastguard Worker          predicate.dest = src;
1351*61046927SAndroid Build Coastguard Worker          predicate.mask = writeout_mask ^ full_mask;
1352*61046927SAndroid Build Coastguard Worker 
1353*61046927SAndroid Build Coastguard Worker          struct midgard_instruction *peaked = mir_choose_instruction(
1354*61046927SAndroid Build Coastguard Worker             instructions, liveness, worklist, len, &predicate);
1355*61046927SAndroid Build Coastguard Worker 
1356*61046927SAndroid Build Coastguard Worker          if (peaked) {
1357*61046927SAndroid Build Coastguard Worker             vmul = peaked;
1358*61046927SAndroid Build Coastguard Worker             vmul->unit = UNIT_VMUL;
1359*61046927SAndroid Build Coastguard Worker             writeout_mask |= predicate.mask;
1360*61046927SAndroid Build Coastguard Worker             assert(writeout_mask == full_mask);
1361*61046927SAndroid Build Coastguard Worker          }
1362*61046927SAndroid Build Coastguard Worker 
1363*61046927SAndroid Build Coastguard Worker          /* Cleanup */
1364*61046927SAndroid Build Coastguard Worker          predicate.dest = predicate.mask = 0;
1365*61046927SAndroid Build Coastguard Worker       }
1366*61046927SAndroid Build Coastguard Worker 
1367*61046927SAndroid Build Coastguard Worker       /* Finally, add a move if necessary */
1368*61046927SAndroid Build Coastguard Worker       if (bad_writeout || writeout_mask != full_mask) {
1369*61046927SAndroid Build Coastguard Worker          unsigned temp = (branch->src[0] == ~0) ? SSA_FIXED_REGISTER(0)
1370*61046927SAndroid Build Coastguard Worker                                                 : make_compiler_temp(ctx);
1371*61046927SAndroid Build Coastguard Worker 
1372*61046927SAndroid Build Coastguard Worker          vmul = ralloc(ctx, midgard_instruction);
1373*61046927SAndroid Build Coastguard Worker          *vmul = v_mov(src, temp);
1374*61046927SAndroid Build Coastguard Worker          vmul->unit = UNIT_VMUL;
1375*61046927SAndroid Build Coastguard Worker          vmul->mask = full_mask ^ writeout_mask;
1376*61046927SAndroid Build Coastguard Worker 
1377*61046927SAndroid Build Coastguard Worker          /* Rewrite to use our temp */
1378*61046927SAndroid Build Coastguard Worker 
1379*61046927SAndroid Build Coastguard Worker          for (unsigned i = 0; i < ARRAY_SIZE(stages); ++i) {
1380*61046927SAndroid Build Coastguard Worker             if (stages[i]) {
1381*61046927SAndroid Build Coastguard Worker                mir_rewrite_index_dst_single(stages[i], src, temp);
1382*61046927SAndroid Build Coastguard Worker                mir_rewrite_index_src_single(stages[i], src, temp);
1383*61046927SAndroid Build Coastguard Worker             }
1384*61046927SAndroid Build Coastguard Worker          }
1385*61046927SAndroid Build Coastguard Worker 
1386*61046927SAndroid Build Coastguard Worker          mir_rewrite_index_src_single(branch, src, temp);
1387*61046927SAndroid Build Coastguard Worker       }
1388*61046927SAndroid Build Coastguard Worker    }
1389*61046927SAndroid Build Coastguard Worker 
1390*61046927SAndroid Build Coastguard Worker    mir_choose_alu(&vmul, instructions, liveness, worklist, len, &predicate,
1391*61046927SAndroid Build Coastguard Worker                   UNIT_VMUL);
1392*61046927SAndroid Build Coastguard Worker 
1393*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, vmul);
1394*61046927SAndroid Build Coastguard Worker    mir_update_worklist(worklist, len, instructions, sadd);
1395*61046927SAndroid Build Coastguard Worker 
1396*61046927SAndroid Build Coastguard Worker    bundle.has_embedded_constants = predicate.constant_mask != 0;
1397*61046927SAndroid Build Coastguard Worker 
1398*61046927SAndroid Build Coastguard Worker    unsigned padding = 0;
1399*61046927SAndroid Build Coastguard Worker 
1400*61046927SAndroid Build Coastguard Worker    /* Now that we have finished scheduling, build up the bundle */
1401*61046927SAndroid Build Coastguard Worker    midgard_instruction *stages[] = {vmul, sadd, vadd, smul, vlut, branch};
1402*61046927SAndroid Build Coastguard Worker 
1403*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < ARRAY_SIZE(stages); ++i) {
1404*61046927SAndroid Build Coastguard Worker       if (stages[i]) {
1405*61046927SAndroid Build Coastguard Worker          bundle.control |= stages[i]->unit;
1406*61046927SAndroid Build Coastguard Worker          bytes_emitted += bytes_for_instruction(stages[i]);
1407*61046927SAndroid Build Coastguard Worker          bundle.instructions[bundle.instruction_count++] = stages[i];
1408*61046927SAndroid Build Coastguard Worker 
1409*61046927SAndroid Build Coastguard Worker          /* If we branch, we can't spill to TLS since the store
1410*61046927SAndroid Build Coastguard Worker           * instruction will never get executed. We could try to
1411*61046927SAndroid Build Coastguard Worker           * break the bundle but this is probably easier for
1412*61046927SAndroid Build Coastguard Worker           * now. */
1413*61046927SAndroid Build Coastguard Worker 
1414*61046927SAndroid Build Coastguard Worker          if (branch)
1415*61046927SAndroid Build Coastguard Worker             stages[i]->no_spill |= (1 << REG_CLASS_WORK);
1416*61046927SAndroid Build Coastguard Worker       }
1417*61046927SAndroid Build Coastguard Worker    }
1418*61046927SAndroid Build Coastguard Worker 
1419*61046927SAndroid Build Coastguard Worker    /* Pad ALU op to nearest word */
1420*61046927SAndroid Build Coastguard Worker 
1421*61046927SAndroid Build Coastguard Worker    if (bytes_emitted & 15) {
1422*61046927SAndroid Build Coastguard Worker       padding = 16 - (bytes_emitted & 15);
1423*61046927SAndroid Build Coastguard Worker       bytes_emitted += padding;
1424*61046927SAndroid Build Coastguard Worker    }
1425*61046927SAndroid Build Coastguard Worker 
1426*61046927SAndroid Build Coastguard Worker    /* Constants must always be quadwords */
1427*61046927SAndroid Build Coastguard Worker    if (bundle.has_embedded_constants)
1428*61046927SAndroid Build Coastguard Worker       bytes_emitted += 16;
1429*61046927SAndroid Build Coastguard Worker 
1430*61046927SAndroid Build Coastguard Worker    /* Size ALU instruction for tag */
1431*61046927SAndroid Build Coastguard Worker    bundle.tag = (TAG_ALU_4) + (bytes_emitted / 16) - 1;
1432*61046927SAndroid Build Coastguard Worker 
1433*61046927SAndroid Build Coastguard Worker    bool tilebuf_wait = branch && branch->compact_branch &&
1434*61046927SAndroid Build Coastguard Worker                        branch->branch.target_type == TARGET_TILEBUF_WAIT;
1435*61046927SAndroid Build Coastguard Worker 
1436*61046927SAndroid Build Coastguard Worker    /* MRT capable GPUs use a special writeout procedure */
1437*61046927SAndroid Build Coastguard Worker    if ((writeout || tilebuf_wait) && !(ctx->quirks & MIDGARD_NO_UPPER_ALU))
1438*61046927SAndroid Build Coastguard Worker       bundle.tag += 4;
1439*61046927SAndroid Build Coastguard Worker 
1440*61046927SAndroid Build Coastguard Worker    bundle.padding = padding;
1441*61046927SAndroid Build Coastguard Worker    bundle.control |= bundle.tag;
1442*61046927SAndroid Build Coastguard Worker 
1443*61046927SAndroid Build Coastguard Worker    return bundle;
1444*61046927SAndroid Build Coastguard Worker }
1445*61046927SAndroid Build Coastguard Worker 
1446*61046927SAndroid Build Coastguard Worker /* Schedule a single block by iterating its instruction to create bundles.
1447*61046927SAndroid Build Coastguard Worker  * While we go, tally about the bundle sizes to compute the block size. */
1448*61046927SAndroid Build Coastguard Worker 
1449*61046927SAndroid Build Coastguard Worker static void
schedule_block(compiler_context * ctx,midgard_block * block)1450*61046927SAndroid Build Coastguard Worker schedule_block(compiler_context *ctx, midgard_block *block)
1451*61046927SAndroid Build Coastguard Worker {
1452*61046927SAndroid Build Coastguard Worker    /* Copy list to dynamic array */
1453*61046927SAndroid Build Coastguard Worker    unsigned len = 0;
1454*61046927SAndroid Build Coastguard Worker    midgard_instruction **instructions = flatten_mir(block, &len);
1455*61046927SAndroid Build Coastguard Worker 
1456*61046927SAndroid Build Coastguard Worker    if (!len)
1457*61046927SAndroid Build Coastguard Worker       return;
1458*61046927SAndroid Build Coastguard Worker 
1459*61046927SAndroid Build Coastguard Worker    /* Calculate dependencies and initial worklist */
1460*61046927SAndroid Build Coastguard Worker    unsigned node_count = ctx->temp_count + 1;
1461*61046927SAndroid Build Coastguard Worker    mir_create_dependency_graph(instructions, len, node_count);
1462*61046927SAndroid Build Coastguard Worker 
1463*61046927SAndroid Build Coastguard Worker    /* Allocate the worklist */
1464*61046927SAndroid Build Coastguard Worker    size_t sz = BITSET_WORDS(len) * sizeof(BITSET_WORD);
1465*61046927SAndroid Build Coastguard Worker    BITSET_WORD *worklist = calloc(sz, 1);
1466*61046927SAndroid Build Coastguard Worker    uint16_t *liveness = calloc(node_count, 2);
1467*61046927SAndroid Build Coastguard Worker    mir_initialize_worklist(worklist, instructions, len);
1468*61046927SAndroid Build Coastguard Worker 
1469*61046927SAndroid Build Coastguard Worker    /* Count the number of load/store instructions so we know when it's
1470*61046927SAndroid Build Coastguard Worker     * worth trying to schedule them in pairs. */
1471*61046927SAndroid Build Coastguard Worker    unsigned num_ldst = 0;
1472*61046927SAndroid Build Coastguard Worker    for (unsigned i = 0; i < len; ++i) {
1473*61046927SAndroid Build Coastguard Worker       if (instructions[i]->type == TAG_LOAD_STORE_4)
1474*61046927SAndroid Build Coastguard Worker          ++num_ldst;
1475*61046927SAndroid Build Coastguard Worker    }
1476*61046927SAndroid Build Coastguard Worker 
1477*61046927SAndroid Build Coastguard Worker    struct util_dynarray bundles;
1478*61046927SAndroid Build Coastguard Worker    util_dynarray_init(&bundles, NULL);
1479*61046927SAndroid Build Coastguard Worker 
1480*61046927SAndroid Build Coastguard Worker    block->quadword_count = 0;
1481*61046927SAndroid Build Coastguard Worker 
1482*61046927SAndroid Build Coastguard Worker    for (;;) {
1483*61046927SAndroid Build Coastguard Worker       unsigned tag =
1484*61046927SAndroid Build Coastguard Worker          mir_choose_bundle(instructions, liveness, worklist, len, num_ldst);
1485*61046927SAndroid Build Coastguard Worker       midgard_bundle bundle;
1486*61046927SAndroid Build Coastguard Worker 
1487*61046927SAndroid Build Coastguard Worker       if (tag == TAG_TEXTURE_4)
1488*61046927SAndroid Build Coastguard Worker          bundle = mir_schedule_texture(instructions, liveness, worklist, len,
1489*61046927SAndroid Build Coastguard Worker                                        ctx->stage != MESA_SHADER_FRAGMENT);
1490*61046927SAndroid Build Coastguard Worker       else if (tag == TAG_LOAD_STORE_4)
1491*61046927SAndroid Build Coastguard Worker          bundle =
1492*61046927SAndroid Build Coastguard Worker             mir_schedule_ldst(instructions, liveness, worklist, len, &num_ldst);
1493*61046927SAndroid Build Coastguard Worker       else if (tag == TAG_ALU_4)
1494*61046927SAndroid Build Coastguard Worker          bundle = mir_schedule_alu(ctx, instructions, liveness, worklist, len);
1495*61046927SAndroid Build Coastguard Worker       else
1496*61046927SAndroid Build Coastguard Worker          break;
1497*61046927SAndroid Build Coastguard Worker 
1498*61046927SAndroid Build Coastguard Worker       for (unsigned i = 0; i < bundle.instruction_count; ++i)
1499*61046927SAndroid Build Coastguard Worker          bundle.instructions[i]->bundle_id =
1500*61046927SAndroid Build Coastguard Worker             ctx->quadword_count + block->quadword_count;
1501*61046927SAndroid Build Coastguard Worker 
1502*61046927SAndroid Build Coastguard Worker       util_dynarray_append(&bundles, midgard_bundle, bundle);
1503*61046927SAndroid Build Coastguard Worker       block->quadword_count += midgard_tag_props[bundle.tag].size;
1504*61046927SAndroid Build Coastguard Worker    }
1505*61046927SAndroid Build Coastguard Worker 
1506*61046927SAndroid Build Coastguard Worker    assert(num_ldst == 0);
1507*61046927SAndroid Build Coastguard Worker 
1508*61046927SAndroid Build Coastguard Worker    /* We emitted bundles backwards; copy into the block in reverse-order */
1509*61046927SAndroid Build Coastguard Worker 
1510*61046927SAndroid Build Coastguard Worker    util_dynarray_init(&block->bundles, block);
1511*61046927SAndroid Build Coastguard Worker    util_dynarray_foreach_reverse(&bundles, midgard_bundle, bundle) {
1512*61046927SAndroid Build Coastguard Worker       util_dynarray_append(&block->bundles, midgard_bundle, *bundle);
1513*61046927SAndroid Build Coastguard Worker    }
1514*61046927SAndroid Build Coastguard Worker    util_dynarray_fini(&bundles);
1515*61046927SAndroid Build Coastguard Worker 
1516*61046927SAndroid Build Coastguard Worker    block->scheduled = true;
1517*61046927SAndroid Build Coastguard Worker    ctx->quadword_count += block->quadword_count;
1518*61046927SAndroid Build Coastguard Worker 
1519*61046927SAndroid Build Coastguard Worker    /* Reorder instructions to match bundled. First remove existing
1520*61046927SAndroid Build Coastguard Worker     * instructions and then recreate the list */
1521*61046927SAndroid Build Coastguard Worker 
1522*61046927SAndroid Build Coastguard Worker    mir_foreach_instr_in_block_safe(block, ins) {
1523*61046927SAndroid Build Coastguard Worker       list_del(&ins->link);
1524*61046927SAndroid Build Coastguard Worker    }
1525*61046927SAndroid Build Coastguard Worker 
1526*61046927SAndroid Build Coastguard Worker    mir_foreach_instr_in_block_scheduled_rev(block, ins) {
1527*61046927SAndroid Build Coastguard Worker       list_add(&ins->link, &block->base.instructions);
1528*61046927SAndroid Build Coastguard Worker    }
1529*61046927SAndroid Build Coastguard Worker 
1530*61046927SAndroid Build Coastguard Worker    free(instructions); /* Allocated by flatten_mir() */
1531*61046927SAndroid Build Coastguard Worker    free(worklist);
1532*61046927SAndroid Build Coastguard Worker    free(liveness);
1533*61046927SAndroid Build Coastguard Worker }
1534*61046927SAndroid Build Coastguard Worker 
1535*61046927SAndroid Build Coastguard Worker /* Insert moves to ensure we can register allocate load/store registers */
1536*61046927SAndroid Build Coastguard Worker static void
mir_lower_ldst(compiler_context * ctx)1537*61046927SAndroid Build Coastguard Worker mir_lower_ldst(compiler_context *ctx)
1538*61046927SAndroid Build Coastguard Worker {
1539*61046927SAndroid Build Coastguard Worker    mir_foreach_instr_global_safe(ctx, I) {
1540*61046927SAndroid Build Coastguard Worker       if (I->type != TAG_LOAD_STORE_4)
1541*61046927SAndroid Build Coastguard Worker          continue;
1542*61046927SAndroid Build Coastguard Worker 
1543*61046927SAndroid Build Coastguard Worker       mir_foreach_src(I, s) {
1544*61046927SAndroid Build Coastguard Worker          if (s == 0)
1545*61046927SAndroid Build Coastguard Worker             continue;
1546*61046927SAndroid Build Coastguard Worker          if (I->src[s] == ~0)
1547*61046927SAndroid Build Coastguard Worker             continue;
1548*61046927SAndroid Build Coastguard Worker          if (I->swizzle[s][0] == 0)
1549*61046927SAndroid Build Coastguard Worker             continue;
1550*61046927SAndroid Build Coastguard Worker 
1551*61046927SAndroid Build Coastguard Worker          unsigned temp = make_compiler_temp(ctx);
1552*61046927SAndroid Build Coastguard Worker          midgard_instruction mov = v_mov(I->src[s], temp);
1553*61046927SAndroid Build Coastguard Worker          mov.mask = 0x1;
1554*61046927SAndroid Build Coastguard Worker          mov.dest_type = I->src_types[s];
1555*61046927SAndroid Build Coastguard Worker          for (unsigned c = 0; c < NIR_MAX_VEC_COMPONENTS; ++c)
1556*61046927SAndroid Build Coastguard Worker             mov.swizzle[1][c] = I->swizzle[s][0];
1557*61046927SAndroid Build Coastguard Worker 
1558*61046927SAndroid Build Coastguard Worker          mir_insert_instruction_before(ctx, I, mov);
1559*61046927SAndroid Build Coastguard Worker          I->src[s] = mov.dest;
1560*61046927SAndroid Build Coastguard Worker          I->swizzle[s][0] = 0;
1561*61046927SAndroid Build Coastguard Worker       }
1562*61046927SAndroid Build Coastguard Worker    }
1563*61046927SAndroid Build Coastguard Worker }
1564*61046927SAndroid Build Coastguard Worker 
1565*61046927SAndroid Build Coastguard Worker /* Insert moves to ensure we can register allocate blend writeout */
1566*61046927SAndroid Build Coastguard Worker static void
mir_lower_blend_input(compiler_context * ctx)1567*61046927SAndroid Build Coastguard Worker mir_lower_blend_input(compiler_context *ctx)
1568*61046927SAndroid Build Coastguard Worker {
1569*61046927SAndroid Build Coastguard Worker    mir_foreach_block(ctx, _blk) {
1570*61046927SAndroid Build Coastguard Worker       midgard_block *blk = (midgard_block *)_blk;
1571*61046927SAndroid Build Coastguard Worker 
1572*61046927SAndroid Build Coastguard Worker       if (list_is_empty(&blk->base.instructions))
1573*61046927SAndroid Build Coastguard Worker          continue;
1574*61046927SAndroid Build Coastguard Worker 
1575*61046927SAndroid Build Coastguard Worker       midgard_instruction *I = mir_last_in_block(blk);
1576*61046927SAndroid Build Coastguard Worker 
1577*61046927SAndroid Build Coastguard Worker       if (!I || I->type != TAG_ALU_4 || !I->writeout)
1578*61046927SAndroid Build Coastguard Worker          continue;
1579*61046927SAndroid Build Coastguard Worker 
1580*61046927SAndroid Build Coastguard Worker       mir_foreach_src(I, s) {
1581*61046927SAndroid Build Coastguard Worker          unsigned src = I->src[s];
1582*61046927SAndroid Build Coastguard Worker 
1583*61046927SAndroid Build Coastguard Worker          if (src >= ctx->temp_count)
1584*61046927SAndroid Build Coastguard Worker             continue;
1585*61046927SAndroid Build Coastguard Worker 
1586*61046927SAndroid Build Coastguard Worker          if (!_blk->live_out[src])
1587*61046927SAndroid Build Coastguard Worker             continue;
1588*61046927SAndroid Build Coastguard Worker 
1589*61046927SAndroid Build Coastguard Worker          unsigned temp = make_compiler_temp(ctx);
1590*61046927SAndroid Build Coastguard Worker          midgard_instruction mov = v_mov(src, temp);
1591*61046927SAndroid Build Coastguard Worker          mov.mask = 0xF;
1592*61046927SAndroid Build Coastguard Worker          mov.dest_type = nir_type_uint32;
1593*61046927SAndroid Build Coastguard Worker          mir_insert_instruction_before(ctx, I, mov);
1594*61046927SAndroid Build Coastguard Worker          I->src[s] = mov.dest;
1595*61046927SAndroid Build Coastguard Worker       }
1596*61046927SAndroid Build Coastguard Worker    }
1597*61046927SAndroid Build Coastguard Worker }
1598*61046927SAndroid Build Coastguard Worker 
1599*61046927SAndroid Build Coastguard Worker void
midgard_schedule_program(compiler_context * ctx)1600*61046927SAndroid Build Coastguard Worker midgard_schedule_program(compiler_context *ctx)
1601*61046927SAndroid Build Coastguard Worker {
1602*61046927SAndroid Build Coastguard Worker    mir_lower_ldst(ctx);
1603*61046927SAndroid Build Coastguard Worker    midgard_promote_uniforms(ctx);
1604*61046927SAndroid Build Coastguard Worker 
1605*61046927SAndroid Build Coastguard Worker    /* Must be lowered right before scheduling */
1606*61046927SAndroid Build Coastguard Worker    mir_lower_special_reads(ctx);
1607*61046927SAndroid Build Coastguard Worker    mir_squeeze_index(ctx);
1608*61046927SAndroid Build Coastguard Worker 
1609*61046927SAndroid Build Coastguard Worker    if (ctx->stage == MESA_SHADER_FRAGMENT) {
1610*61046927SAndroid Build Coastguard Worker       mir_invalidate_liveness(ctx);
1611*61046927SAndroid Build Coastguard Worker       mir_compute_liveness(ctx);
1612*61046927SAndroid Build Coastguard Worker       mir_lower_blend_input(ctx);
1613*61046927SAndroid Build Coastguard Worker    }
1614*61046927SAndroid Build Coastguard Worker 
1615*61046927SAndroid Build Coastguard Worker    mir_squeeze_index(ctx);
1616*61046927SAndroid Build Coastguard Worker 
1617*61046927SAndroid Build Coastguard Worker    /* Lowering can introduce some dead moves */
1618*61046927SAndroid Build Coastguard Worker 
1619*61046927SAndroid Build Coastguard Worker    mir_foreach_block(ctx, _block) {
1620*61046927SAndroid Build Coastguard Worker       midgard_block *block = (midgard_block *)_block;
1621*61046927SAndroid Build Coastguard Worker       midgard_opt_dead_move_eliminate(ctx, block);
1622*61046927SAndroid Build Coastguard Worker       schedule_block(ctx, block);
1623*61046927SAndroid Build Coastguard Worker    }
1624*61046927SAndroid Build Coastguard Worker }
1625