1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2014 Intel Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #include "nir_search.h"
25*61046927SAndroid Build Coastguard Worker #include <inttypes.h>
26*61046927SAndroid Build Coastguard Worker #include "util/half_float.h"
27*61046927SAndroid Build Coastguard Worker #include "nir_builder.h"
28*61046927SAndroid Build Coastguard Worker #include "nir_worklist.h"
29*61046927SAndroid Build Coastguard Worker
30*61046927SAndroid Build Coastguard Worker /* This should be the same as nir_search_max_comm_ops in nir_algebraic.py. */
31*61046927SAndroid Build Coastguard Worker #define NIR_SEARCH_MAX_COMM_OPS 8
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker struct match_state {
34*61046927SAndroid Build Coastguard Worker bool inexact_match;
35*61046927SAndroid Build Coastguard Worker bool has_exact_alu;
36*61046927SAndroid Build Coastguard Worker uint8_t comm_op_direction;
37*61046927SAndroid Build Coastguard Worker unsigned variables_seen;
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker /* Used for running the automaton on newly-constructed instructions. */
40*61046927SAndroid Build Coastguard Worker struct util_dynarray *states;
41*61046927SAndroid Build Coastguard Worker const struct per_op_table *pass_op_table;
42*61046927SAndroid Build Coastguard Worker const nir_algebraic_table *table;
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker nir_alu_src variables[NIR_SEARCH_MAX_VARIABLES];
45*61046927SAndroid Build Coastguard Worker struct hash_table *range_ht;
46*61046927SAndroid Build Coastguard Worker };
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker static bool
49*61046927SAndroid Build Coastguard Worker match_expression(const nir_algebraic_table *table, const nir_search_expression *expr, nir_alu_instr *instr,
50*61046927SAndroid Build Coastguard Worker unsigned num_components, const uint8_t *swizzle,
51*61046927SAndroid Build Coastguard Worker struct match_state *state);
52*61046927SAndroid Build Coastguard Worker static bool
53*61046927SAndroid Build Coastguard Worker nir_algebraic_automaton(nir_instr *instr, struct util_dynarray *states,
54*61046927SAndroid Build Coastguard Worker const struct per_op_table *pass_op_table);
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker static const uint8_t identity_swizzle[NIR_MAX_VEC_COMPONENTS] = {
57*61046927SAndroid Build Coastguard Worker 0,
58*61046927SAndroid Build Coastguard Worker 1,
59*61046927SAndroid Build Coastguard Worker 2,
60*61046927SAndroid Build Coastguard Worker 3,
61*61046927SAndroid Build Coastguard Worker 4,
62*61046927SAndroid Build Coastguard Worker 5,
63*61046927SAndroid Build Coastguard Worker 6,
64*61046927SAndroid Build Coastguard Worker 7,
65*61046927SAndroid Build Coastguard Worker 8,
66*61046927SAndroid Build Coastguard Worker 9,
67*61046927SAndroid Build Coastguard Worker 10,
68*61046927SAndroid Build Coastguard Worker 11,
69*61046927SAndroid Build Coastguard Worker 12,
70*61046927SAndroid Build Coastguard Worker 13,
71*61046927SAndroid Build Coastguard Worker 14,
72*61046927SAndroid Build Coastguard Worker 15,
73*61046927SAndroid Build Coastguard Worker };
74*61046927SAndroid Build Coastguard Worker
75*61046927SAndroid Build Coastguard Worker /**
76*61046927SAndroid Build Coastguard Worker * Check if a source produces a value of the given type.
77*61046927SAndroid Build Coastguard Worker *
78*61046927SAndroid Build Coastguard Worker * Used for satisfying 'a@type' constraints.
79*61046927SAndroid Build Coastguard Worker */
80*61046927SAndroid Build Coastguard Worker static bool
src_is_type(nir_src src,nir_alu_type type)81*61046927SAndroid Build Coastguard Worker src_is_type(nir_src src, nir_alu_type type)
82*61046927SAndroid Build Coastguard Worker {
83*61046927SAndroid Build Coastguard Worker assert(type != nir_type_invalid);
84*61046927SAndroid Build Coastguard Worker
85*61046927SAndroid Build Coastguard Worker if (src.ssa->parent_instr->type == nir_instr_type_alu) {
86*61046927SAndroid Build Coastguard Worker nir_alu_instr *src_alu = nir_instr_as_alu(src.ssa->parent_instr);
87*61046927SAndroid Build Coastguard Worker nir_alu_type output_type = nir_op_infos[src_alu->op].output_type;
88*61046927SAndroid Build Coastguard Worker
89*61046927SAndroid Build Coastguard Worker if (type == nir_type_bool) {
90*61046927SAndroid Build Coastguard Worker switch (src_alu->op) {
91*61046927SAndroid Build Coastguard Worker case nir_op_iand:
92*61046927SAndroid Build Coastguard Worker case nir_op_ior:
93*61046927SAndroid Build Coastguard Worker case nir_op_ixor:
94*61046927SAndroid Build Coastguard Worker return src_is_type(src_alu->src[0].src, nir_type_bool) &&
95*61046927SAndroid Build Coastguard Worker src_is_type(src_alu->src[1].src, nir_type_bool);
96*61046927SAndroid Build Coastguard Worker case nir_op_inot:
97*61046927SAndroid Build Coastguard Worker return src_is_type(src_alu->src[0].src, nir_type_bool);
98*61046927SAndroid Build Coastguard Worker default:
99*61046927SAndroid Build Coastguard Worker break;
100*61046927SAndroid Build Coastguard Worker }
101*61046927SAndroid Build Coastguard Worker }
102*61046927SAndroid Build Coastguard Worker
103*61046927SAndroid Build Coastguard Worker return nir_alu_type_get_base_type(output_type) == type;
104*61046927SAndroid Build Coastguard Worker } else if (src.ssa->parent_instr->type == nir_instr_type_intrinsic) {
105*61046927SAndroid Build Coastguard Worker nir_intrinsic_instr *intr = nir_instr_as_intrinsic(src.ssa->parent_instr);
106*61046927SAndroid Build Coastguard Worker
107*61046927SAndroid Build Coastguard Worker if (type == nir_type_bool) {
108*61046927SAndroid Build Coastguard Worker return intr->intrinsic == nir_intrinsic_load_front_face ||
109*61046927SAndroid Build Coastguard Worker intr->intrinsic == nir_intrinsic_load_helper_invocation;
110*61046927SAndroid Build Coastguard Worker }
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker
113*61046927SAndroid Build Coastguard Worker /* don't know */
114*61046927SAndroid Build Coastguard Worker return false;
115*61046927SAndroid Build Coastguard Worker }
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker static bool
nir_op_matches_search_op(nir_op nop,uint16_t sop)118*61046927SAndroid Build Coastguard Worker nir_op_matches_search_op(nir_op nop, uint16_t sop)
119*61046927SAndroid Build Coastguard Worker {
120*61046927SAndroid Build Coastguard Worker if (sop <= nir_last_opcode)
121*61046927SAndroid Build Coastguard Worker return nop == sop;
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker #define MATCH_FCONV_CASE(op) \
124*61046927SAndroid Build Coastguard Worker case nir_search_op_##op: \
125*61046927SAndroid Build Coastguard Worker return nop == nir_op_##op##16 || \
126*61046927SAndroid Build Coastguard Worker nop == nir_op_##op##32 || \
127*61046927SAndroid Build Coastguard Worker nop == nir_op_##op##64;
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker #define MATCH_ICONV_CASE(op) \
130*61046927SAndroid Build Coastguard Worker case nir_search_op_##op: \
131*61046927SAndroid Build Coastguard Worker return nop == nir_op_##op##8 || \
132*61046927SAndroid Build Coastguard Worker nop == nir_op_##op##16 || \
133*61046927SAndroid Build Coastguard Worker nop == nir_op_##op##32 || \
134*61046927SAndroid Build Coastguard Worker nop == nir_op_##op##64;
135*61046927SAndroid Build Coastguard Worker
136*61046927SAndroid Build Coastguard Worker switch (sop) {
137*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(i2f)
138*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(u2f)
139*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(f2f)
140*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(f2u)
141*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(f2i)
142*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(u2u)
143*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(i2i)
144*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(b2f)
145*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(b2i)
146*61046927SAndroid Build Coastguard Worker default:
147*61046927SAndroid Build Coastguard Worker unreachable("Invalid nir_search_op");
148*61046927SAndroid Build Coastguard Worker }
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Worker #undef MATCH_FCONV_CASE
151*61046927SAndroid Build Coastguard Worker #undef MATCH_ICONV_CASE
152*61046927SAndroid Build Coastguard Worker }
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker uint16_t
nir_search_op_for_nir_op(nir_op nop)155*61046927SAndroid Build Coastguard Worker nir_search_op_for_nir_op(nir_op nop)
156*61046927SAndroid Build Coastguard Worker {
157*61046927SAndroid Build Coastguard Worker #define MATCH_FCONV_CASE(op) \
158*61046927SAndroid Build Coastguard Worker case nir_op_##op##16: \
159*61046927SAndroid Build Coastguard Worker case nir_op_##op##32: \
160*61046927SAndroid Build Coastguard Worker case nir_op_##op##64: \
161*61046927SAndroid Build Coastguard Worker return nir_search_op_##op;
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker #define MATCH_ICONV_CASE(op) \
164*61046927SAndroid Build Coastguard Worker case nir_op_##op##8: \
165*61046927SAndroid Build Coastguard Worker case nir_op_##op##16: \
166*61046927SAndroid Build Coastguard Worker case nir_op_##op##32: \
167*61046927SAndroid Build Coastguard Worker case nir_op_##op##64: \
168*61046927SAndroid Build Coastguard Worker return nir_search_op_##op;
169*61046927SAndroid Build Coastguard Worker
170*61046927SAndroid Build Coastguard Worker switch (nop) {
171*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(i2f)
172*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(u2f)
173*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(f2f)
174*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(f2u)
175*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(f2i)
176*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(u2u)
177*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(i2i)
178*61046927SAndroid Build Coastguard Worker MATCH_FCONV_CASE(b2f)
179*61046927SAndroid Build Coastguard Worker MATCH_ICONV_CASE(b2i)
180*61046927SAndroid Build Coastguard Worker default:
181*61046927SAndroid Build Coastguard Worker return nop;
182*61046927SAndroid Build Coastguard Worker }
183*61046927SAndroid Build Coastguard Worker
184*61046927SAndroid Build Coastguard Worker #undef MATCH_FCONV_CASE
185*61046927SAndroid Build Coastguard Worker #undef MATCH_ICONV_CASE
186*61046927SAndroid Build Coastguard Worker }
187*61046927SAndroid Build Coastguard Worker
188*61046927SAndroid Build Coastguard Worker static nir_op
nir_op_for_search_op(uint16_t sop,unsigned bit_size)189*61046927SAndroid Build Coastguard Worker nir_op_for_search_op(uint16_t sop, unsigned bit_size)
190*61046927SAndroid Build Coastguard Worker {
191*61046927SAndroid Build Coastguard Worker if (sop <= nir_last_opcode)
192*61046927SAndroid Build Coastguard Worker return sop;
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker #define RET_FCONV_CASE(op) \
195*61046927SAndroid Build Coastguard Worker case nir_search_op_##op: \
196*61046927SAndroid Build Coastguard Worker switch (bit_size) { \
197*61046927SAndroid Build Coastguard Worker case 16: \
198*61046927SAndroid Build Coastguard Worker return nir_op_##op##16; \
199*61046927SAndroid Build Coastguard Worker case 32: \
200*61046927SAndroid Build Coastguard Worker return nir_op_##op##32; \
201*61046927SAndroid Build Coastguard Worker case 64: \
202*61046927SAndroid Build Coastguard Worker return nir_op_##op##64; \
203*61046927SAndroid Build Coastguard Worker default: \
204*61046927SAndroid Build Coastguard Worker unreachable("Invalid bit size"); \
205*61046927SAndroid Build Coastguard Worker }
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker #define RET_ICONV_CASE(op) \
208*61046927SAndroid Build Coastguard Worker case nir_search_op_##op: \
209*61046927SAndroid Build Coastguard Worker switch (bit_size) { \
210*61046927SAndroid Build Coastguard Worker case 8: \
211*61046927SAndroid Build Coastguard Worker return nir_op_##op##8; \
212*61046927SAndroid Build Coastguard Worker case 16: \
213*61046927SAndroid Build Coastguard Worker return nir_op_##op##16; \
214*61046927SAndroid Build Coastguard Worker case 32: \
215*61046927SAndroid Build Coastguard Worker return nir_op_##op##32; \
216*61046927SAndroid Build Coastguard Worker case 64: \
217*61046927SAndroid Build Coastguard Worker return nir_op_##op##64; \
218*61046927SAndroid Build Coastguard Worker default: \
219*61046927SAndroid Build Coastguard Worker unreachable("Invalid bit size"); \
220*61046927SAndroid Build Coastguard Worker }
221*61046927SAndroid Build Coastguard Worker
222*61046927SAndroid Build Coastguard Worker switch (sop) {
223*61046927SAndroid Build Coastguard Worker RET_FCONV_CASE(i2f)
224*61046927SAndroid Build Coastguard Worker RET_FCONV_CASE(u2f)
225*61046927SAndroid Build Coastguard Worker RET_FCONV_CASE(f2f)
226*61046927SAndroid Build Coastguard Worker RET_ICONV_CASE(f2u)
227*61046927SAndroid Build Coastguard Worker RET_ICONV_CASE(f2i)
228*61046927SAndroid Build Coastguard Worker RET_ICONV_CASE(u2u)
229*61046927SAndroid Build Coastguard Worker RET_ICONV_CASE(i2i)
230*61046927SAndroid Build Coastguard Worker RET_FCONV_CASE(b2f)
231*61046927SAndroid Build Coastguard Worker RET_ICONV_CASE(b2i)
232*61046927SAndroid Build Coastguard Worker default:
233*61046927SAndroid Build Coastguard Worker unreachable("Invalid nir_search_op");
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker #undef RET_FCONV_CASE
237*61046927SAndroid Build Coastguard Worker #undef RET_ICONV_CASE
238*61046927SAndroid Build Coastguard Worker }
239*61046927SAndroid Build Coastguard Worker
240*61046927SAndroid Build Coastguard Worker static bool
match_value(const nir_algebraic_table * table,const nir_search_value * value,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle,struct match_state * state)241*61046927SAndroid Build Coastguard Worker match_value(const nir_algebraic_table *table,
242*61046927SAndroid Build Coastguard Worker const nir_search_value *value, nir_alu_instr *instr, unsigned src,
243*61046927SAndroid Build Coastguard Worker unsigned num_components, const uint8_t *swizzle,
244*61046927SAndroid Build Coastguard Worker struct match_state *state)
245*61046927SAndroid Build Coastguard Worker {
246*61046927SAndroid Build Coastguard Worker uint8_t new_swizzle[NIR_MAX_VEC_COMPONENTS];
247*61046927SAndroid Build Coastguard Worker
248*61046927SAndroid Build Coastguard Worker /* If the source is an explicitly sized source, then we need to reset
249*61046927SAndroid Build Coastguard Worker * both the number of components and the swizzle.
250*61046927SAndroid Build Coastguard Worker */
251*61046927SAndroid Build Coastguard Worker if (nir_op_infos[instr->op].input_sizes[src] != 0) {
252*61046927SAndroid Build Coastguard Worker num_components = nir_op_infos[instr->op].input_sizes[src];
253*61046927SAndroid Build Coastguard Worker swizzle = identity_swizzle;
254*61046927SAndroid Build Coastguard Worker }
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_components; ++i)
257*61046927SAndroid Build Coastguard Worker new_swizzle[i] = instr->src[src].swizzle[swizzle[i]];
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker /* If the value has a specific bit size and it doesn't match, bail */
260*61046927SAndroid Build Coastguard Worker if (value->bit_size > 0 &&
261*61046927SAndroid Build Coastguard Worker nir_src_bit_size(instr->src[src].src) != value->bit_size)
262*61046927SAndroid Build Coastguard Worker return false;
263*61046927SAndroid Build Coastguard Worker
264*61046927SAndroid Build Coastguard Worker switch (value->type) {
265*61046927SAndroid Build Coastguard Worker case nir_search_value_expression:
266*61046927SAndroid Build Coastguard Worker if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_alu)
267*61046927SAndroid Build Coastguard Worker return false;
268*61046927SAndroid Build Coastguard Worker
269*61046927SAndroid Build Coastguard Worker return match_expression(table, nir_search_value_as_expression(value),
270*61046927SAndroid Build Coastguard Worker nir_instr_as_alu(instr->src[src].src.ssa->parent_instr),
271*61046927SAndroid Build Coastguard Worker num_components, new_swizzle, state);
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker case nir_search_value_variable: {
274*61046927SAndroid Build Coastguard Worker nir_search_variable *var = nir_search_value_as_variable(value);
275*61046927SAndroid Build Coastguard Worker assert(var->variable < NIR_SEARCH_MAX_VARIABLES);
276*61046927SAndroid Build Coastguard Worker
277*61046927SAndroid Build Coastguard Worker if (state->variables_seen & (1 << var->variable)) {
278*61046927SAndroid Build Coastguard Worker if (state->variables[var->variable].src.ssa != instr->src[src].src.ssa)
279*61046927SAndroid Build Coastguard Worker return false;
280*61046927SAndroid Build Coastguard Worker
281*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_components; ++i) {
282*61046927SAndroid Build Coastguard Worker if (state->variables[var->variable].swizzle[i] != new_swizzle[i])
283*61046927SAndroid Build Coastguard Worker return false;
284*61046927SAndroid Build Coastguard Worker }
285*61046927SAndroid Build Coastguard Worker
286*61046927SAndroid Build Coastguard Worker return true;
287*61046927SAndroid Build Coastguard Worker } else {
288*61046927SAndroid Build Coastguard Worker if (var->is_constant &&
289*61046927SAndroid Build Coastguard Worker instr->src[src].src.ssa->parent_instr->type != nir_instr_type_load_const)
290*61046927SAndroid Build Coastguard Worker return false;
291*61046927SAndroid Build Coastguard Worker
292*61046927SAndroid Build Coastguard Worker if (var->cond_index != -1 && !table->variable_cond[var->cond_index](state->range_ht, instr,
293*61046927SAndroid Build Coastguard Worker src, num_components, new_swizzle))
294*61046927SAndroid Build Coastguard Worker return false;
295*61046927SAndroid Build Coastguard Worker
296*61046927SAndroid Build Coastguard Worker if (var->type != nir_type_invalid &&
297*61046927SAndroid Build Coastguard Worker !src_is_type(instr->src[src].src, var->type))
298*61046927SAndroid Build Coastguard Worker return false;
299*61046927SAndroid Build Coastguard Worker
300*61046927SAndroid Build Coastguard Worker state->variables_seen |= (1 << var->variable);
301*61046927SAndroid Build Coastguard Worker state->variables[var->variable].src = instr->src[src].src;
302*61046927SAndroid Build Coastguard Worker
303*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; ++i) {
304*61046927SAndroid Build Coastguard Worker if (i < num_components)
305*61046927SAndroid Build Coastguard Worker state->variables[var->variable].swizzle[i] = new_swizzle[i];
306*61046927SAndroid Build Coastguard Worker else
307*61046927SAndroid Build Coastguard Worker state->variables[var->variable].swizzle[i] = 0;
308*61046927SAndroid Build Coastguard Worker }
309*61046927SAndroid Build Coastguard Worker
310*61046927SAndroid Build Coastguard Worker return true;
311*61046927SAndroid Build Coastguard Worker }
312*61046927SAndroid Build Coastguard Worker }
313*61046927SAndroid Build Coastguard Worker
314*61046927SAndroid Build Coastguard Worker case nir_search_value_constant: {
315*61046927SAndroid Build Coastguard Worker nir_search_constant *const_val = nir_search_value_as_constant(value);
316*61046927SAndroid Build Coastguard Worker
317*61046927SAndroid Build Coastguard Worker if (!nir_src_is_const(instr->src[src].src))
318*61046927SAndroid Build Coastguard Worker return false;
319*61046927SAndroid Build Coastguard Worker
320*61046927SAndroid Build Coastguard Worker switch (const_val->type) {
321*61046927SAndroid Build Coastguard Worker case nir_type_float: {
322*61046927SAndroid Build Coastguard Worker nir_load_const_instr *const load =
323*61046927SAndroid Build Coastguard Worker nir_instr_as_load_const(instr->src[src].src.ssa->parent_instr);
324*61046927SAndroid Build Coastguard Worker
325*61046927SAndroid Build Coastguard Worker /* There are 8-bit and 1-bit integer types, but there are no 8-bit or
326*61046927SAndroid Build Coastguard Worker * 1-bit float types. This prevents potential assertion failures in
327*61046927SAndroid Build Coastguard Worker * nir_src_comp_as_float.
328*61046927SAndroid Build Coastguard Worker */
329*61046927SAndroid Build Coastguard Worker if (load->def.bit_size < 16)
330*61046927SAndroid Build Coastguard Worker return false;
331*61046927SAndroid Build Coastguard Worker
332*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_components; ++i) {
333*61046927SAndroid Build Coastguard Worker double val = nir_src_comp_as_float(instr->src[src].src,
334*61046927SAndroid Build Coastguard Worker new_swizzle[i]);
335*61046927SAndroid Build Coastguard Worker if (val != const_val->data.d)
336*61046927SAndroid Build Coastguard Worker return false;
337*61046927SAndroid Build Coastguard Worker }
338*61046927SAndroid Build Coastguard Worker return true;
339*61046927SAndroid Build Coastguard Worker }
340*61046927SAndroid Build Coastguard Worker
341*61046927SAndroid Build Coastguard Worker case nir_type_int:
342*61046927SAndroid Build Coastguard Worker case nir_type_uint:
343*61046927SAndroid Build Coastguard Worker case nir_type_bool: {
344*61046927SAndroid Build Coastguard Worker unsigned bit_size = nir_src_bit_size(instr->src[src].src);
345*61046927SAndroid Build Coastguard Worker uint64_t mask = u_uintN_max(bit_size);
346*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_components; ++i) {
347*61046927SAndroid Build Coastguard Worker uint64_t val = nir_src_comp_as_uint(instr->src[src].src,
348*61046927SAndroid Build Coastguard Worker new_swizzle[i]);
349*61046927SAndroid Build Coastguard Worker if ((val & mask) != (const_val->data.u & mask))
350*61046927SAndroid Build Coastguard Worker return false;
351*61046927SAndroid Build Coastguard Worker }
352*61046927SAndroid Build Coastguard Worker return true;
353*61046927SAndroid Build Coastguard Worker }
354*61046927SAndroid Build Coastguard Worker
355*61046927SAndroid Build Coastguard Worker default:
356*61046927SAndroid Build Coastguard Worker unreachable("Invalid alu source type");
357*61046927SAndroid Build Coastguard Worker }
358*61046927SAndroid Build Coastguard Worker }
359*61046927SAndroid Build Coastguard Worker
360*61046927SAndroid Build Coastguard Worker default:
361*61046927SAndroid Build Coastguard Worker unreachable("Invalid search value type");
362*61046927SAndroid Build Coastguard Worker }
363*61046927SAndroid Build Coastguard Worker }
364*61046927SAndroid Build Coastguard Worker
365*61046927SAndroid Build Coastguard Worker static bool
match_expression(const nir_algebraic_table * table,const nir_search_expression * expr,nir_alu_instr * instr,unsigned num_components,const uint8_t * swizzle,struct match_state * state)366*61046927SAndroid Build Coastguard Worker match_expression(const nir_algebraic_table *table, const nir_search_expression *expr, nir_alu_instr *instr,
367*61046927SAndroid Build Coastguard Worker unsigned num_components, const uint8_t *swizzle,
368*61046927SAndroid Build Coastguard Worker struct match_state *state)
369*61046927SAndroid Build Coastguard Worker {
370*61046927SAndroid Build Coastguard Worker if (expr->cond_index != -1 && !table->expression_cond[expr->cond_index](instr))
371*61046927SAndroid Build Coastguard Worker return false;
372*61046927SAndroid Build Coastguard Worker
373*61046927SAndroid Build Coastguard Worker if (expr->nsz && nir_alu_instr_is_signed_zero_preserve(instr))
374*61046927SAndroid Build Coastguard Worker return false;
375*61046927SAndroid Build Coastguard Worker
376*61046927SAndroid Build Coastguard Worker if (expr->nnan && nir_alu_instr_is_nan_preserve(instr))
377*61046927SAndroid Build Coastguard Worker return false;
378*61046927SAndroid Build Coastguard Worker
379*61046927SAndroid Build Coastguard Worker if (expr->ninf && nir_alu_instr_is_inf_preserve(instr))
380*61046927SAndroid Build Coastguard Worker return false;
381*61046927SAndroid Build Coastguard Worker
382*61046927SAndroid Build Coastguard Worker if (!nir_op_matches_search_op(instr->op, expr->opcode))
383*61046927SAndroid Build Coastguard Worker return false;
384*61046927SAndroid Build Coastguard Worker
385*61046927SAndroid Build Coastguard Worker if (expr->value.bit_size > 0 &&
386*61046927SAndroid Build Coastguard Worker instr->def.bit_size != expr->value.bit_size)
387*61046927SAndroid Build Coastguard Worker return false;
388*61046927SAndroid Build Coastguard Worker
389*61046927SAndroid Build Coastguard Worker state->inexact_match = expr->inexact || state->inexact_match;
390*61046927SAndroid Build Coastguard Worker state->has_exact_alu = (instr->exact && !expr->ignore_exact) || state->has_exact_alu;
391*61046927SAndroid Build Coastguard Worker if (state->inexact_match && state->has_exact_alu)
392*61046927SAndroid Build Coastguard Worker return false;
393*61046927SAndroid Build Coastguard Worker
394*61046927SAndroid Build Coastguard Worker assert(nir_op_infos[instr->op].num_inputs > 0);
395*61046927SAndroid Build Coastguard Worker
396*61046927SAndroid Build Coastguard Worker /* If we have an explicitly sized destination, we can only handle the
397*61046927SAndroid Build Coastguard Worker * identity swizzle. While dot(vec3(a, b, c).zxy) is a valid
398*61046927SAndroid Build Coastguard Worker * expression, we don't have the information right now to propagate that
399*61046927SAndroid Build Coastguard Worker * swizzle through. We can only properly propagate swizzles if the
400*61046927SAndroid Build Coastguard Worker * instruction is vectorized.
401*61046927SAndroid Build Coastguard Worker */
402*61046927SAndroid Build Coastguard Worker if (nir_op_infos[instr->op].output_size != 0) {
403*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_components; i++) {
404*61046927SAndroid Build Coastguard Worker if (swizzle[i] != i)
405*61046927SAndroid Build Coastguard Worker return false;
406*61046927SAndroid Build Coastguard Worker }
407*61046927SAndroid Build Coastguard Worker }
408*61046927SAndroid Build Coastguard Worker
409*61046927SAndroid Build Coastguard Worker /* If this is a commutative expression and it's one of the first few, look
410*61046927SAndroid Build Coastguard Worker * up its direction for the current search operation. We'll use that value
411*61046927SAndroid Build Coastguard Worker * to possibly flip the sources for the match.
412*61046927SAndroid Build Coastguard Worker */
413*61046927SAndroid Build Coastguard Worker unsigned comm_op_flip =
414*61046927SAndroid Build Coastguard Worker (expr->comm_expr_idx >= 0 &&
415*61046927SAndroid Build Coastguard Worker expr->comm_expr_idx < NIR_SEARCH_MAX_COMM_OPS)
416*61046927SAndroid Build Coastguard Worker ? ((state->comm_op_direction >> expr->comm_expr_idx) & 1)
417*61046927SAndroid Build Coastguard Worker : 0;
418*61046927SAndroid Build Coastguard Worker
419*61046927SAndroid Build Coastguard Worker bool matched = true;
420*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) {
421*61046927SAndroid Build Coastguard Worker /* 2src_commutative instructions that have 3 sources are only commutative
422*61046927SAndroid Build Coastguard Worker * in the first two sources. Source 2 is always source 2.
423*61046927SAndroid Build Coastguard Worker */
424*61046927SAndroid Build Coastguard Worker if (!match_value(table, &state->table->values[expr->srcs[i]].value, instr,
425*61046927SAndroid Build Coastguard Worker i < 2 ? i ^ comm_op_flip : i,
426*61046927SAndroid Build Coastguard Worker num_components, swizzle, state)) {
427*61046927SAndroid Build Coastguard Worker matched = false;
428*61046927SAndroid Build Coastguard Worker break;
429*61046927SAndroid Build Coastguard Worker }
430*61046927SAndroid Build Coastguard Worker }
431*61046927SAndroid Build Coastguard Worker
432*61046927SAndroid Build Coastguard Worker return matched;
433*61046927SAndroid Build Coastguard Worker }
434*61046927SAndroid Build Coastguard Worker
435*61046927SAndroid Build Coastguard Worker static unsigned
replace_bitsize(const nir_search_value * value,unsigned search_bitsize,struct match_state * state)436*61046927SAndroid Build Coastguard Worker replace_bitsize(const nir_search_value *value, unsigned search_bitsize,
437*61046927SAndroid Build Coastguard Worker struct match_state *state)
438*61046927SAndroid Build Coastguard Worker {
439*61046927SAndroid Build Coastguard Worker if (value->bit_size > 0)
440*61046927SAndroid Build Coastguard Worker return value->bit_size;
441*61046927SAndroid Build Coastguard Worker if (value->bit_size < 0)
442*61046927SAndroid Build Coastguard Worker return nir_src_bit_size(state->variables[-value->bit_size - 1].src);
443*61046927SAndroid Build Coastguard Worker return search_bitsize;
444*61046927SAndroid Build Coastguard Worker }
445*61046927SAndroid Build Coastguard Worker
446*61046927SAndroid Build Coastguard Worker static nir_alu_src
construct_value(nir_builder * build,const nir_search_value * value,unsigned num_components,unsigned search_bitsize,struct match_state * state,nir_instr * instr)447*61046927SAndroid Build Coastguard Worker construct_value(nir_builder *build,
448*61046927SAndroid Build Coastguard Worker const nir_search_value *value,
449*61046927SAndroid Build Coastguard Worker unsigned num_components, unsigned search_bitsize,
450*61046927SAndroid Build Coastguard Worker struct match_state *state,
451*61046927SAndroid Build Coastguard Worker nir_instr *instr)
452*61046927SAndroid Build Coastguard Worker {
453*61046927SAndroid Build Coastguard Worker switch (value->type) {
454*61046927SAndroid Build Coastguard Worker case nir_search_value_expression: {
455*61046927SAndroid Build Coastguard Worker const nir_search_expression *expr = nir_search_value_as_expression(value);
456*61046927SAndroid Build Coastguard Worker unsigned dst_bit_size = replace_bitsize(value, search_bitsize, state);
457*61046927SAndroid Build Coastguard Worker nir_op op = nir_op_for_search_op(expr->opcode, dst_bit_size);
458*61046927SAndroid Build Coastguard Worker
459*61046927SAndroid Build Coastguard Worker if (nir_op_infos[op].output_size != 0)
460*61046927SAndroid Build Coastguard Worker num_components = nir_op_infos[op].output_size;
461*61046927SAndroid Build Coastguard Worker
462*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_alu_instr_create(build->shader, op);
463*61046927SAndroid Build Coastguard Worker nir_def_init(&alu->instr, &alu->def, num_components,
464*61046927SAndroid Build Coastguard Worker dst_bit_size);
465*61046927SAndroid Build Coastguard Worker
466*61046927SAndroid Build Coastguard Worker /* We have no way of knowing what values in a given search expression
467*61046927SAndroid Build Coastguard Worker * map to a particular replacement value. Therefore, if the
468*61046927SAndroid Build Coastguard Worker * expression we are replacing has any exact values, the entire
469*61046927SAndroid Build Coastguard Worker * replacement should be exact.
470*61046927SAndroid Build Coastguard Worker */
471*61046927SAndroid Build Coastguard Worker alu->exact = state->has_exact_alu || expr->exact;
472*61046927SAndroid Build Coastguard Worker alu->fp_fast_math = nir_instr_as_alu(instr)->fp_fast_math;
473*61046927SAndroid Build Coastguard Worker
474*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) {
475*61046927SAndroid Build Coastguard Worker /* If the source is an explicitly sized source, then we need to reset
476*61046927SAndroid Build Coastguard Worker * the number of components to match.
477*61046927SAndroid Build Coastguard Worker */
478*61046927SAndroid Build Coastguard Worker if (nir_op_infos[alu->op].input_sizes[i] != 0)
479*61046927SAndroid Build Coastguard Worker num_components = nir_op_infos[alu->op].input_sizes[i];
480*61046927SAndroid Build Coastguard Worker
481*61046927SAndroid Build Coastguard Worker alu->src[i] = construct_value(build, &state->table->values[expr->srcs[i]].value,
482*61046927SAndroid Build Coastguard Worker num_components, search_bitsize,
483*61046927SAndroid Build Coastguard Worker state, instr);
484*61046927SAndroid Build Coastguard Worker }
485*61046927SAndroid Build Coastguard Worker
486*61046927SAndroid Build Coastguard Worker nir_builder_instr_insert(build, &alu->instr);
487*61046927SAndroid Build Coastguard Worker
488*61046927SAndroid Build Coastguard Worker assert(alu->def.index ==
489*61046927SAndroid Build Coastguard Worker util_dynarray_num_elements(state->states, uint16_t));
490*61046927SAndroid Build Coastguard Worker util_dynarray_append(state->states, uint16_t, 0);
491*61046927SAndroid Build Coastguard Worker nir_algebraic_automaton(&alu->instr, state->states, state->pass_op_table);
492*61046927SAndroid Build Coastguard Worker
493*61046927SAndroid Build Coastguard Worker nir_alu_src val;
494*61046927SAndroid Build Coastguard Worker val.src = nir_src_for_ssa(&alu->def);
495*61046927SAndroid Build Coastguard Worker memcpy(val.swizzle, identity_swizzle, sizeof val.swizzle);
496*61046927SAndroid Build Coastguard Worker
497*61046927SAndroid Build Coastguard Worker return val;
498*61046927SAndroid Build Coastguard Worker }
499*61046927SAndroid Build Coastguard Worker
500*61046927SAndroid Build Coastguard Worker case nir_search_value_variable: {
501*61046927SAndroid Build Coastguard Worker const nir_search_variable *var = nir_search_value_as_variable(value);
502*61046927SAndroid Build Coastguard Worker assert(state->variables_seen & (1 << var->variable));
503*61046927SAndroid Build Coastguard Worker
504*61046927SAndroid Build Coastguard Worker nir_alu_src val = { NIR_SRC_INIT };
505*61046927SAndroid Build Coastguard Worker nir_alu_src_copy(&val, &state->variables[var->variable]);
506*61046927SAndroid Build Coastguard Worker assert(!var->is_constant);
507*61046927SAndroid Build Coastguard Worker
508*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++)
509*61046927SAndroid Build Coastguard Worker val.swizzle[i] = state->variables[var->variable].swizzle[var->swizzle[i]];
510*61046927SAndroid Build Coastguard Worker
511*61046927SAndroid Build Coastguard Worker return val;
512*61046927SAndroid Build Coastguard Worker }
513*61046927SAndroid Build Coastguard Worker
514*61046927SAndroid Build Coastguard Worker case nir_search_value_constant: {
515*61046927SAndroid Build Coastguard Worker const nir_search_constant *c = nir_search_value_as_constant(value);
516*61046927SAndroid Build Coastguard Worker unsigned bit_size = replace_bitsize(value, search_bitsize, state);
517*61046927SAndroid Build Coastguard Worker
518*61046927SAndroid Build Coastguard Worker nir_def *cval;
519*61046927SAndroid Build Coastguard Worker switch (c->type) {
520*61046927SAndroid Build Coastguard Worker case nir_type_float:
521*61046927SAndroid Build Coastguard Worker cval = nir_imm_floatN_t(build, c->data.d, bit_size);
522*61046927SAndroid Build Coastguard Worker break;
523*61046927SAndroid Build Coastguard Worker
524*61046927SAndroid Build Coastguard Worker case nir_type_int:
525*61046927SAndroid Build Coastguard Worker case nir_type_uint:
526*61046927SAndroid Build Coastguard Worker cval = nir_imm_intN_t(build, c->data.i, bit_size);
527*61046927SAndroid Build Coastguard Worker break;
528*61046927SAndroid Build Coastguard Worker
529*61046927SAndroid Build Coastguard Worker case nir_type_bool:
530*61046927SAndroid Build Coastguard Worker cval = nir_imm_boolN_t(build, c->data.u, bit_size);
531*61046927SAndroid Build Coastguard Worker break;
532*61046927SAndroid Build Coastguard Worker
533*61046927SAndroid Build Coastguard Worker default:
534*61046927SAndroid Build Coastguard Worker unreachable("Invalid alu source type");
535*61046927SAndroid Build Coastguard Worker }
536*61046927SAndroid Build Coastguard Worker
537*61046927SAndroid Build Coastguard Worker assert(cval->index ==
538*61046927SAndroid Build Coastguard Worker util_dynarray_num_elements(state->states, uint16_t));
539*61046927SAndroid Build Coastguard Worker util_dynarray_append(state->states, uint16_t, 0);
540*61046927SAndroid Build Coastguard Worker nir_algebraic_automaton(cval->parent_instr, state->states,
541*61046927SAndroid Build Coastguard Worker state->pass_op_table);
542*61046927SAndroid Build Coastguard Worker
543*61046927SAndroid Build Coastguard Worker nir_alu_src val;
544*61046927SAndroid Build Coastguard Worker val.src = nir_src_for_ssa(cval);
545*61046927SAndroid Build Coastguard Worker memset(val.swizzle, 0, sizeof val.swizzle);
546*61046927SAndroid Build Coastguard Worker
547*61046927SAndroid Build Coastguard Worker return val;
548*61046927SAndroid Build Coastguard Worker }
549*61046927SAndroid Build Coastguard Worker
550*61046927SAndroid Build Coastguard Worker default:
551*61046927SAndroid Build Coastguard Worker unreachable("Invalid search value type");
552*61046927SAndroid Build Coastguard Worker }
553*61046927SAndroid Build Coastguard Worker }
554*61046927SAndroid Build Coastguard Worker
555*61046927SAndroid Build Coastguard Worker UNUSED static void
dump_value(const nir_algebraic_table * table,const nir_search_value * val)556*61046927SAndroid Build Coastguard Worker dump_value(const nir_algebraic_table *table, const nir_search_value *val)
557*61046927SAndroid Build Coastguard Worker {
558*61046927SAndroid Build Coastguard Worker switch (val->type) {
559*61046927SAndroid Build Coastguard Worker case nir_search_value_constant: {
560*61046927SAndroid Build Coastguard Worker const nir_search_constant *sconst = nir_search_value_as_constant(val);
561*61046927SAndroid Build Coastguard Worker switch (sconst->type) {
562*61046927SAndroid Build Coastguard Worker case nir_type_float:
563*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%f", sconst->data.d);
564*61046927SAndroid Build Coastguard Worker break;
565*61046927SAndroid Build Coastguard Worker case nir_type_int:
566*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%" PRId64, sconst->data.i);
567*61046927SAndroid Build Coastguard Worker break;
568*61046927SAndroid Build Coastguard Worker case nir_type_uint:
569*61046927SAndroid Build Coastguard Worker fprintf(stderr, "0x%" PRIx64, sconst->data.u);
570*61046927SAndroid Build Coastguard Worker break;
571*61046927SAndroid Build Coastguard Worker case nir_type_bool:
572*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s", sconst->data.u != 0 ? "True" : "False");
573*61046927SAndroid Build Coastguard Worker break;
574*61046927SAndroid Build Coastguard Worker default:
575*61046927SAndroid Build Coastguard Worker unreachable("bad const type");
576*61046927SAndroid Build Coastguard Worker }
577*61046927SAndroid Build Coastguard Worker break;
578*61046927SAndroid Build Coastguard Worker }
579*61046927SAndroid Build Coastguard Worker
580*61046927SAndroid Build Coastguard Worker case nir_search_value_variable: {
581*61046927SAndroid Build Coastguard Worker const nir_search_variable *var = nir_search_value_as_variable(val);
582*61046927SAndroid Build Coastguard Worker if (var->is_constant)
583*61046927SAndroid Build Coastguard Worker fprintf(stderr, "#");
584*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%c", var->variable + 'a');
585*61046927SAndroid Build Coastguard Worker break;
586*61046927SAndroid Build Coastguard Worker }
587*61046927SAndroid Build Coastguard Worker
588*61046927SAndroid Build Coastguard Worker case nir_search_value_expression: {
589*61046927SAndroid Build Coastguard Worker const nir_search_expression *expr = nir_search_value_as_expression(val);
590*61046927SAndroid Build Coastguard Worker fprintf(stderr, "(");
591*61046927SAndroid Build Coastguard Worker if (expr->inexact)
592*61046927SAndroid Build Coastguard Worker fprintf(stderr, "~");
593*61046927SAndroid Build Coastguard Worker switch (expr->opcode) {
594*61046927SAndroid Build Coastguard Worker #define CASE(n) \
595*61046927SAndroid Build Coastguard Worker case nir_search_op_##n: \
596*61046927SAndroid Build Coastguard Worker fprintf(stderr, #n); \
597*61046927SAndroid Build Coastguard Worker break;
598*61046927SAndroid Build Coastguard Worker CASE(b2f)
599*61046927SAndroid Build Coastguard Worker CASE(b2i)
600*61046927SAndroid Build Coastguard Worker CASE(i2i)
601*61046927SAndroid Build Coastguard Worker CASE(f2i)
602*61046927SAndroid Build Coastguard Worker CASE(i2f)
603*61046927SAndroid Build Coastguard Worker #undef CASE
604*61046927SAndroid Build Coastguard Worker default:
605*61046927SAndroid Build Coastguard Worker fprintf(stderr, "%s", nir_op_infos[expr->opcode].name);
606*61046927SAndroid Build Coastguard Worker }
607*61046927SAndroid Build Coastguard Worker
608*61046927SAndroid Build Coastguard Worker unsigned num_srcs = 1;
609*61046927SAndroid Build Coastguard Worker if (expr->opcode <= nir_last_opcode)
610*61046927SAndroid Build Coastguard Worker num_srcs = nir_op_infos[expr->opcode].num_inputs;
611*61046927SAndroid Build Coastguard Worker
612*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_srcs; i++) {
613*61046927SAndroid Build Coastguard Worker fprintf(stderr, " ");
614*61046927SAndroid Build Coastguard Worker dump_value(table, &table->values[expr->srcs[i]].value);
615*61046927SAndroid Build Coastguard Worker }
616*61046927SAndroid Build Coastguard Worker
617*61046927SAndroid Build Coastguard Worker fprintf(stderr, ")");
618*61046927SAndroid Build Coastguard Worker break;
619*61046927SAndroid Build Coastguard Worker }
620*61046927SAndroid Build Coastguard Worker }
621*61046927SAndroid Build Coastguard Worker
622*61046927SAndroid Build Coastguard Worker if (val->bit_size > 0)
623*61046927SAndroid Build Coastguard Worker fprintf(stderr, "@%d", val->bit_size);
624*61046927SAndroid Build Coastguard Worker }
625*61046927SAndroid Build Coastguard Worker
626*61046927SAndroid Build Coastguard Worker static void
add_uses_to_worklist(nir_instr * instr,nir_instr_worklist * worklist,struct util_dynarray * states,const struct per_op_table * pass_op_table)627*61046927SAndroid Build Coastguard Worker add_uses_to_worklist(nir_instr *instr,
628*61046927SAndroid Build Coastguard Worker nir_instr_worklist *worklist,
629*61046927SAndroid Build Coastguard Worker struct util_dynarray *states,
630*61046927SAndroid Build Coastguard Worker const struct per_op_table *pass_op_table)
631*61046927SAndroid Build Coastguard Worker {
632*61046927SAndroid Build Coastguard Worker nir_def *def = nir_instr_def(instr);
633*61046927SAndroid Build Coastguard Worker
634*61046927SAndroid Build Coastguard Worker nir_foreach_use_safe(use_src, def) {
635*61046927SAndroid Build Coastguard Worker if (nir_algebraic_automaton(nir_src_parent_instr(use_src), states, pass_op_table))
636*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(worklist, nir_src_parent_instr(use_src));
637*61046927SAndroid Build Coastguard Worker }
638*61046927SAndroid Build Coastguard Worker }
639*61046927SAndroid Build Coastguard Worker
640*61046927SAndroid Build Coastguard Worker static void
nir_algebraic_update_automaton(nir_instr * new_instr,nir_instr_worklist * algebraic_worklist,struct util_dynarray * states,const struct per_op_table * pass_op_table)641*61046927SAndroid Build Coastguard Worker nir_algebraic_update_automaton(nir_instr *new_instr,
642*61046927SAndroid Build Coastguard Worker nir_instr_worklist *algebraic_worklist,
643*61046927SAndroid Build Coastguard Worker struct util_dynarray *states,
644*61046927SAndroid Build Coastguard Worker const struct per_op_table *pass_op_table)
645*61046927SAndroid Build Coastguard Worker {
646*61046927SAndroid Build Coastguard Worker
647*61046927SAndroid Build Coastguard Worker nir_instr_worklist *automaton_worklist = nir_instr_worklist_create();
648*61046927SAndroid Build Coastguard Worker
649*61046927SAndroid Build Coastguard Worker /* Walk through the tree of uses of our new instruction's SSA value,
650*61046927SAndroid Build Coastguard Worker * recursively updating the automaton state until it stabilizes.
651*61046927SAndroid Build Coastguard Worker */
652*61046927SAndroid Build Coastguard Worker add_uses_to_worklist(new_instr, automaton_worklist, states, pass_op_table);
653*61046927SAndroid Build Coastguard Worker
654*61046927SAndroid Build Coastguard Worker nir_instr *instr;
655*61046927SAndroid Build Coastguard Worker while ((instr = nir_instr_worklist_pop_head(automaton_worklist))) {
656*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(algebraic_worklist, instr);
657*61046927SAndroid Build Coastguard Worker add_uses_to_worklist(instr, automaton_worklist, states, pass_op_table);
658*61046927SAndroid Build Coastguard Worker }
659*61046927SAndroid Build Coastguard Worker
660*61046927SAndroid Build Coastguard Worker nir_instr_worklist_destroy(automaton_worklist);
661*61046927SAndroid Build Coastguard Worker }
662*61046927SAndroid Build Coastguard Worker
663*61046927SAndroid Build Coastguard Worker static nir_def *
nir_replace_instr(nir_builder * build,nir_alu_instr * instr,struct hash_table * range_ht,struct util_dynarray * states,const nir_algebraic_table * table,const nir_search_expression * search,const nir_search_value * replace,nir_instr_worklist * algebraic_worklist,struct exec_list * dead_instrs)664*61046927SAndroid Build Coastguard Worker nir_replace_instr(nir_builder *build, nir_alu_instr *instr,
665*61046927SAndroid Build Coastguard Worker struct hash_table *range_ht,
666*61046927SAndroid Build Coastguard Worker struct util_dynarray *states,
667*61046927SAndroid Build Coastguard Worker const nir_algebraic_table *table,
668*61046927SAndroid Build Coastguard Worker const nir_search_expression *search,
669*61046927SAndroid Build Coastguard Worker const nir_search_value *replace,
670*61046927SAndroid Build Coastguard Worker nir_instr_worklist *algebraic_worklist,
671*61046927SAndroid Build Coastguard Worker struct exec_list *dead_instrs)
672*61046927SAndroid Build Coastguard Worker {
673*61046927SAndroid Build Coastguard Worker uint8_t swizzle[NIR_MAX_VEC_COMPONENTS] = { 0 };
674*61046927SAndroid Build Coastguard Worker
675*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < instr->def.num_components; ++i)
676*61046927SAndroid Build Coastguard Worker swizzle[i] = i;
677*61046927SAndroid Build Coastguard Worker
678*61046927SAndroid Build Coastguard Worker struct match_state state;
679*61046927SAndroid Build Coastguard Worker state.inexact_match = false;
680*61046927SAndroid Build Coastguard Worker state.has_exact_alu = false;
681*61046927SAndroid Build Coastguard Worker state.range_ht = range_ht;
682*61046927SAndroid Build Coastguard Worker state.pass_op_table = table->pass_op_table;
683*61046927SAndroid Build Coastguard Worker state.table = table;
684*61046927SAndroid Build Coastguard Worker
685*61046927SAndroid Build Coastguard Worker STATIC_ASSERT(sizeof(state.comm_op_direction) * 8 >= NIR_SEARCH_MAX_COMM_OPS);
686*61046927SAndroid Build Coastguard Worker
687*61046927SAndroid Build Coastguard Worker unsigned comm_expr_combinations =
688*61046927SAndroid Build Coastguard Worker 1 << MIN2(search->comm_exprs, NIR_SEARCH_MAX_COMM_OPS);
689*61046927SAndroid Build Coastguard Worker
690*61046927SAndroid Build Coastguard Worker bool found = false;
691*61046927SAndroid Build Coastguard Worker for (unsigned comb = 0; comb < comm_expr_combinations; comb++) {
692*61046927SAndroid Build Coastguard Worker /* The bitfield of directions is just the current iteration. Hooray for
693*61046927SAndroid Build Coastguard Worker * binary.
694*61046927SAndroid Build Coastguard Worker */
695*61046927SAndroid Build Coastguard Worker state.comm_op_direction = comb;
696*61046927SAndroid Build Coastguard Worker state.variables_seen = 0;
697*61046927SAndroid Build Coastguard Worker
698*61046927SAndroid Build Coastguard Worker if (match_expression(table, search, instr,
699*61046927SAndroid Build Coastguard Worker instr->def.num_components,
700*61046927SAndroid Build Coastguard Worker swizzle, &state)) {
701*61046927SAndroid Build Coastguard Worker found = true;
702*61046927SAndroid Build Coastguard Worker break;
703*61046927SAndroid Build Coastguard Worker }
704*61046927SAndroid Build Coastguard Worker }
705*61046927SAndroid Build Coastguard Worker if (!found)
706*61046927SAndroid Build Coastguard Worker return NULL;
707*61046927SAndroid Build Coastguard Worker
708*61046927SAndroid Build Coastguard Worker #if 0
709*61046927SAndroid Build Coastguard Worker fprintf(stderr, "matched: ");
710*61046927SAndroid Build Coastguard Worker dump_value(table, &search->value);
711*61046927SAndroid Build Coastguard Worker fprintf(stderr, " -> ");
712*61046927SAndroid Build Coastguard Worker dump_value(table, replace);
713*61046927SAndroid Build Coastguard Worker fprintf(stderr, " ssa_%d\n", instr->def.index);
714*61046927SAndroid Build Coastguard Worker #endif
715*61046927SAndroid Build Coastguard Worker
716*61046927SAndroid Build Coastguard Worker /* If the instruction at the root of the expression tree being replaced is
717*61046927SAndroid Build Coastguard Worker * a unary operation, insert the replacement instructions at the location
718*61046927SAndroid Build Coastguard Worker * of the source of the unary operation. Otherwise, insert the replacement
719*61046927SAndroid Build Coastguard Worker * instructions at the location of the expression tree root.
720*61046927SAndroid Build Coastguard Worker *
721*61046927SAndroid Build Coastguard Worker * For the unary operation case, this is done to prevent some spurious code
722*61046927SAndroid Build Coastguard Worker * motion that can dramatically extend live ranges. Imagine an expression
723*61046927SAndroid Build Coastguard Worker * like -(A+B) where the addtion and the negation are separated by flow
724*61046927SAndroid Build Coastguard Worker * control and thousands of instructions. If this expression is replaced
725*61046927SAndroid Build Coastguard Worker * with -A+-B, inserting the new instructions at the site of the negation
726*61046927SAndroid Build Coastguard Worker * could extend the live range of A and B dramtically. This could increase
727*61046927SAndroid Build Coastguard Worker * register pressure and cause spilling.
728*61046927SAndroid Build Coastguard Worker *
729*61046927SAndroid Build Coastguard Worker * It may well be that moving instructions around is a good thing, but
730*61046927SAndroid Build Coastguard Worker * keeping algebraic optimizations and code motion optimizations separate
731*61046927SAndroid Build Coastguard Worker * seems safest.
732*61046927SAndroid Build Coastguard Worker */
733*61046927SAndroid Build Coastguard Worker nir_alu_instr *const src_instr = nir_src_as_alu_instr(instr->src[0].src);
734*61046927SAndroid Build Coastguard Worker if (src_instr != NULL &&
735*61046927SAndroid Build Coastguard Worker (instr->op == nir_op_fneg || instr->op == nir_op_fabs ||
736*61046927SAndroid Build Coastguard Worker instr->op == nir_op_ineg || instr->op == nir_op_iabs ||
737*61046927SAndroid Build Coastguard Worker instr->op == nir_op_inot)) {
738*61046927SAndroid Build Coastguard Worker /* Insert new instructions *after*. Otherwise a hypothetical
739*61046927SAndroid Build Coastguard Worker * replacement fneg(X) -> fabs(X) would insert the fabs() instruction
740*61046927SAndroid Build Coastguard Worker * before X! This can also occur for things like fneg(X.wzyx) -> X.wzyx
741*61046927SAndroid Build Coastguard Worker * in vector mode. A move instruction to handle the swizzle will get
742*61046927SAndroid Build Coastguard Worker * inserted before X.
743*61046927SAndroid Build Coastguard Worker *
744*61046927SAndroid Build Coastguard Worker * This manifested in a single OpenGL ES 2.0 CTS vertex shader test on
745*61046927SAndroid Build Coastguard Worker * older Intel GPU that use vector-mode vertex processing.
746*61046927SAndroid Build Coastguard Worker */
747*61046927SAndroid Build Coastguard Worker build->cursor = nir_after_instr(&src_instr->instr);
748*61046927SAndroid Build Coastguard Worker } else {
749*61046927SAndroid Build Coastguard Worker build->cursor = nir_before_instr(&instr->instr);
750*61046927SAndroid Build Coastguard Worker }
751*61046927SAndroid Build Coastguard Worker
752*61046927SAndroid Build Coastguard Worker state.states = states;
753*61046927SAndroid Build Coastguard Worker
754*61046927SAndroid Build Coastguard Worker nir_alu_src val = construct_value(build, replace,
755*61046927SAndroid Build Coastguard Worker instr->def.num_components,
756*61046927SAndroid Build Coastguard Worker instr->def.bit_size,
757*61046927SAndroid Build Coastguard Worker &state, &instr->instr);
758*61046927SAndroid Build Coastguard Worker
759*61046927SAndroid Build Coastguard Worker /* Note that NIR builder will elide the MOV if it's a no-op, which may
760*61046927SAndroid Build Coastguard Worker * allow more work to be done in a single pass through algebraic.
761*61046927SAndroid Build Coastguard Worker */
762*61046927SAndroid Build Coastguard Worker nir_def *ssa_val =
763*61046927SAndroid Build Coastguard Worker nir_mov_alu(build, val, instr->def.num_components);
764*61046927SAndroid Build Coastguard Worker if (ssa_val->index == util_dynarray_num_elements(states, uint16_t)) {
765*61046927SAndroid Build Coastguard Worker util_dynarray_append(states, uint16_t, 0);
766*61046927SAndroid Build Coastguard Worker nir_algebraic_automaton(ssa_val->parent_instr, states, table->pass_op_table);
767*61046927SAndroid Build Coastguard Worker }
768*61046927SAndroid Build Coastguard Worker
769*61046927SAndroid Build Coastguard Worker /* Rewrite the uses of the old SSA value to the new one, and recurse
770*61046927SAndroid Build Coastguard Worker * through the uses updating the automaton's state.
771*61046927SAndroid Build Coastguard Worker */
772*61046927SAndroid Build Coastguard Worker nir_def_rewrite_uses(&instr->def, ssa_val);
773*61046927SAndroid Build Coastguard Worker nir_algebraic_update_automaton(ssa_val->parent_instr, algebraic_worklist,
774*61046927SAndroid Build Coastguard Worker states, table->pass_op_table);
775*61046927SAndroid Build Coastguard Worker
776*61046927SAndroid Build Coastguard Worker /* Nothing uses the instr any more, so drop it out of the program. Note
777*61046927SAndroid Build Coastguard Worker * that the instr may be in the worklist still, so we can't free it
778*61046927SAndroid Build Coastguard Worker * directly.
779*61046927SAndroid Build Coastguard Worker */
780*61046927SAndroid Build Coastguard Worker assert(instr->instr.pass_flags == 0);
781*61046927SAndroid Build Coastguard Worker instr->instr.pass_flags = 1;
782*61046927SAndroid Build Coastguard Worker nir_instr_remove(&instr->instr);
783*61046927SAndroid Build Coastguard Worker exec_list_push_tail(dead_instrs, &instr->instr.node);
784*61046927SAndroid Build Coastguard Worker
785*61046927SAndroid Build Coastguard Worker return ssa_val;
786*61046927SAndroid Build Coastguard Worker }
787*61046927SAndroid Build Coastguard Worker
788*61046927SAndroid Build Coastguard Worker static bool
nir_algebraic_automaton(nir_instr * instr,struct util_dynarray * states,const struct per_op_table * pass_op_table)789*61046927SAndroid Build Coastguard Worker nir_algebraic_automaton(nir_instr *instr, struct util_dynarray *states,
790*61046927SAndroid Build Coastguard Worker const struct per_op_table *pass_op_table)
791*61046927SAndroid Build Coastguard Worker {
792*61046927SAndroid Build Coastguard Worker switch (instr->type) {
793*61046927SAndroid Build Coastguard Worker case nir_instr_type_alu: {
794*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(instr);
795*61046927SAndroid Build Coastguard Worker nir_op op = alu->op;
796*61046927SAndroid Build Coastguard Worker uint16_t search_op = nir_search_op_for_nir_op(op);
797*61046927SAndroid Build Coastguard Worker const struct per_op_table *tbl = &pass_op_table[search_op];
798*61046927SAndroid Build Coastguard Worker if (tbl->num_filtered_states == 0)
799*61046927SAndroid Build Coastguard Worker return false;
800*61046927SAndroid Build Coastguard Worker
801*61046927SAndroid Build Coastguard Worker /* Calculate the index into the transition table. Note the index
802*61046927SAndroid Build Coastguard Worker * calculated must match the iteration order of Python's
803*61046927SAndroid Build Coastguard Worker * itertools.product(), which was used to emit the transition
804*61046927SAndroid Build Coastguard Worker * table.
805*61046927SAndroid Build Coastguard Worker */
806*61046927SAndroid Build Coastguard Worker unsigned index = 0;
807*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) {
808*61046927SAndroid Build Coastguard Worker index *= tbl->num_filtered_states;
809*61046927SAndroid Build Coastguard Worker if (tbl->filter)
810*61046927SAndroid Build Coastguard Worker index += tbl->filter[*util_dynarray_element(states, uint16_t,
811*61046927SAndroid Build Coastguard Worker alu->src[i].src.ssa->index)];
812*61046927SAndroid Build Coastguard Worker }
813*61046927SAndroid Build Coastguard Worker
814*61046927SAndroid Build Coastguard Worker uint16_t *state = util_dynarray_element(states, uint16_t,
815*61046927SAndroid Build Coastguard Worker alu->def.index);
816*61046927SAndroid Build Coastguard Worker if (*state != tbl->table[index]) {
817*61046927SAndroid Build Coastguard Worker *state = tbl->table[index];
818*61046927SAndroid Build Coastguard Worker return true;
819*61046927SAndroid Build Coastguard Worker }
820*61046927SAndroid Build Coastguard Worker return false;
821*61046927SAndroid Build Coastguard Worker }
822*61046927SAndroid Build Coastguard Worker
823*61046927SAndroid Build Coastguard Worker case nir_instr_type_load_const: {
824*61046927SAndroid Build Coastguard Worker nir_load_const_instr *load_const = nir_instr_as_load_const(instr);
825*61046927SAndroid Build Coastguard Worker uint16_t *state = util_dynarray_element(states, uint16_t,
826*61046927SAndroid Build Coastguard Worker load_const->def.index);
827*61046927SAndroid Build Coastguard Worker if (*state != CONST_STATE) {
828*61046927SAndroid Build Coastguard Worker *state = CONST_STATE;
829*61046927SAndroid Build Coastguard Worker return true;
830*61046927SAndroid Build Coastguard Worker }
831*61046927SAndroid Build Coastguard Worker return false;
832*61046927SAndroid Build Coastguard Worker }
833*61046927SAndroid Build Coastguard Worker
834*61046927SAndroid Build Coastguard Worker default:
835*61046927SAndroid Build Coastguard Worker return false;
836*61046927SAndroid Build Coastguard Worker }
837*61046927SAndroid Build Coastguard Worker }
838*61046927SAndroid Build Coastguard Worker
839*61046927SAndroid Build Coastguard Worker static bool
nir_algebraic_instr(nir_builder * build,nir_instr * instr,struct hash_table * range_ht,const bool * condition_flags,const nir_algebraic_table * table,struct util_dynarray * states,nir_instr_worklist * worklist,struct exec_list * dead_instrs)840*61046927SAndroid Build Coastguard Worker nir_algebraic_instr(nir_builder *build, nir_instr *instr,
841*61046927SAndroid Build Coastguard Worker struct hash_table *range_ht,
842*61046927SAndroid Build Coastguard Worker const bool *condition_flags,
843*61046927SAndroid Build Coastguard Worker const nir_algebraic_table *table,
844*61046927SAndroid Build Coastguard Worker struct util_dynarray *states,
845*61046927SAndroid Build Coastguard Worker nir_instr_worklist *worklist,
846*61046927SAndroid Build Coastguard Worker struct exec_list *dead_instrs)
847*61046927SAndroid Build Coastguard Worker {
848*61046927SAndroid Build Coastguard Worker
849*61046927SAndroid Build Coastguard Worker if (instr->type != nir_instr_type_alu)
850*61046927SAndroid Build Coastguard Worker return false;
851*61046927SAndroid Build Coastguard Worker
852*61046927SAndroid Build Coastguard Worker nir_alu_instr *alu = nir_instr_as_alu(instr);
853*61046927SAndroid Build Coastguard Worker
854*61046927SAndroid Build Coastguard Worker unsigned bit_size = alu->def.bit_size;
855*61046927SAndroid Build Coastguard Worker const unsigned execution_mode =
856*61046927SAndroid Build Coastguard Worker build->shader->info.float_controls_execution_mode;
857*61046927SAndroid Build Coastguard Worker const bool ignore_inexact =
858*61046927SAndroid Build Coastguard Worker nir_alu_instr_is_signed_zero_inf_nan_preserve(alu) ||
859*61046927SAndroid Build Coastguard Worker nir_is_denorm_flush_to_zero(execution_mode, bit_size);
860*61046927SAndroid Build Coastguard Worker
861*61046927SAndroid Build Coastguard Worker int xform_idx = *util_dynarray_element(states, uint16_t,
862*61046927SAndroid Build Coastguard Worker alu->def.index);
863*61046927SAndroid Build Coastguard Worker for (const struct transform *xform = &table->transforms[table->transform_offsets[xform_idx]];
864*61046927SAndroid Build Coastguard Worker xform->condition_offset != ~0;
865*61046927SAndroid Build Coastguard Worker xform++) {
866*61046927SAndroid Build Coastguard Worker if (condition_flags[xform->condition_offset] &&
867*61046927SAndroid Build Coastguard Worker !(table->values[xform->search].expression.inexact && ignore_inexact) &&
868*61046927SAndroid Build Coastguard Worker nir_replace_instr(build, alu, range_ht, states, table,
869*61046927SAndroid Build Coastguard Worker &table->values[xform->search].expression,
870*61046927SAndroid Build Coastguard Worker &table->values[xform->replace].value, worklist, dead_instrs)) {
871*61046927SAndroid Build Coastguard Worker _mesa_hash_table_clear(range_ht, NULL);
872*61046927SAndroid Build Coastguard Worker return true;
873*61046927SAndroid Build Coastguard Worker }
874*61046927SAndroid Build Coastguard Worker }
875*61046927SAndroid Build Coastguard Worker
876*61046927SAndroid Build Coastguard Worker return false;
877*61046927SAndroid Build Coastguard Worker }
878*61046927SAndroid Build Coastguard Worker
879*61046927SAndroid Build Coastguard Worker bool
nir_algebraic_impl(nir_function_impl * impl,const bool * condition_flags,const nir_algebraic_table * table)880*61046927SAndroid Build Coastguard Worker nir_algebraic_impl(nir_function_impl *impl,
881*61046927SAndroid Build Coastguard Worker const bool *condition_flags,
882*61046927SAndroid Build Coastguard Worker const nir_algebraic_table *table)
883*61046927SAndroid Build Coastguard Worker {
884*61046927SAndroid Build Coastguard Worker bool progress = false;
885*61046927SAndroid Build Coastguard Worker
886*61046927SAndroid Build Coastguard Worker nir_builder build = nir_builder_create(impl);
887*61046927SAndroid Build Coastguard Worker
888*61046927SAndroid Build Coastguard Worker /* Note: it's important here that we're allocating a zeroed array, since
889*61046927SAndroid Build Coastguard Worker * state 0 is the default state, which means we don't have to visit
890*61046927SAndroid Build Coastguard Worker * anything other than constants and ALU instructions.
891*61046927SAndroid Build Coastguard Worker */
892*61046927SAndroid Build Coastguard Worker struct util_dynarray states = { 0 };
893*61046927SAndroid Build Coastguard Worker if (!util_dynarray_resize(&states, uint16_t, impl->ssa_alloc)) {
894*61046927SAndroid Build Coastguard Worker nir_metadata_preserve(impl, nir_metadata_all);
895*61046927SAndroid Build Coastguard Worker return false;
896*61046927SAndroid Build Coastguard Worker }
897*61046927SAndroid Build Coastguard Worker memset(states.data, 0, states.size);
898*61046927SAndroid Build Coastguard Worker
899*61046927SAndroid Build Coastguard Worker struct hash_table *range_ht = _mesa_pointer_hash_table_create(NULL);
900*61046927SAndroid Build Coastguard Worker
901*61046927SAndroid Build Coastguard Worker nir_instr_worklist *worklist = nir_instr_worklist_create();
902*61046927SAndroid Build Coastguard Worker
903*61046927SAndroid Build Coastguard Worker /* Walk top-to-bottom setting up the automaton state. */
904*61046927SAndroid Build Coastguard Worker nir_foreach_block(block, impl) {
905*61046927SAndroid Build Coastguard Worker nir_foreach_instr(instr, block) {
906*61046927SAndroid Build Coastguard Worker nir_algebraic_automaton(instr, &states, table->pass_op_table);
907*61046927SAndroid Build Coastguard Worker }
908*61046927SAndroid Build Coastguard Worker }
909*61046927SAndroid Build Coastguard Worker
910*61046927SAndroid Build Coastguard Worker /* Put our instrs in the worklist such that we're popping the last instr
911*61046927SAndroid Build Coastguard Worker * first. This will encourage us to match the biggest source patterns when
912*61046927SAndroid Build Coastguard Worker * possible.
913*61046927SAndroid Build Coastguard Worker */
914*61046927SAndroid Build Coastguard Worker nir_foreach_block_reverse(block, impl) {
915*61046927SAndroid Build Coastguard Worker nir_foreach_instr_reverse(instr, block) {
916*61046927SAndroid Build Coastguard Worker instr->pass_flags = 0;
917*61046927SAndroid Build Coastguard Worker if (instr->type == nir_instr_type_alu)
918*61046927SAndroid Build Coastguard Worker nir_instr_worklist_push_tail(worklist, instr);
919*61046927SAndroid Build Coastguard Worker }
920*61046927SAndroid Build Coastguard Worker }
921*61046927SAndroid Build Coastguard Worker
922*61046927SAndroid Build Coastguard Worker struct exec_list dead_instrs;
923*61046927SAndroid Build Coastguard Worker exec_list_make_empty(&dead_instrs);
924*61046927SAndroid Build Coastguard Worker
925*61046927SAndroid Build Coastguard Worker nir_instr *instr;
926*61046927SAndroid Build Coastguard Worker while ((instr = nir_instr_worklist_pop_head(worklist))) {
927*61046927SAndroid Build Coastguard Worker /* The worklist can have an instr pushed to it multiple times if it was
928*61046927SAndroid Build Coastguard Worker * the src of multiple instrs that also got optimized, so make sure that
929*61046927SAndroid Build Coastguard Worker * we don't try to re-optimize an instr we already handled.
930*61046927SAndroid Build Coastguard Worker */
931*61046927SAndroid Build Coastguard Worker if (instr->pass_flags)
932*61046927SAndroid Build Coastguard Worker continue;
933*61046927SAndroid Build Coastguard Worker
934*61046927SAndroid Build Coastguard Worker progress |= nir_algebraic_instr(&build, instr,
935*61046927SAndroid Build Coastguard Worker range_ht, condition_flags,
936*61046927SAndroid Build Coastguard Worker table, &states, worklist, &dead_instrs);
937*61046927SAndroid Build Coastguard Worker }
938*61046927SAndroid Build Coastguard Worker
939*61046927SAndroid Build Coastguard Worker nir_instr_free_list(&dead_instrs);
940*61046927SAndroid Build Coastguard Worker
941*61046927SAndroid Build Coastguard Worker nir_instr_worklist_destroy(worklist);
942*61046927SAndroid Build Coastguard Worker ralloc_free(range_ht);
943*61046927SAndroid Build Coastguard Worker util_dynarray_fini(&states);
944*61046927SAndroid Build Coastguard Worker
945*61046927SAndroid Build Coastguard Worker if (progress) {
946*61046927SAndroid Build Coastguard Worker nir_metadata_preserve(impl, nir_metadata_control_flow);
947*61046927SAndroid Build Coastguard Worker } else {
948*61046927SAndroid Build Coastguard Worker nir_metadata_preserve(impl, nir_metadata_all);
949*61046927SAndroid Build Coastguard Worker }
950*61046927SAndroid Build Coastguard Worker
951*61046927SAndroid Build Coastguard Worker return progress;
952*61046927SAndroid Build Coastguard Worker }
953