1 /*
2 * Copyright © 2016 Red Hat
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Rob Clark <robclark@freedesktop.org>
25 */
26
27 #ifndef _NIR_SEARCH_HELPERS_
28 #define _NIR_SEARCH_HELPERS_
29
30 #include "nir.h"
31 #include "util/bitscan.h"
32 #include "nir_range_analysis.h"
33 #include <math.h>
34
35 static inline bool
is_pos_power_of_two(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)36 is_pos_power_of_two(UNUSED struct hash_table *ht, nir_alu_instr *instr,
37 unsigned src, unsigned num_components,
38 const uint8_t *swizzle)
39 {
40 /* only constant srcs: */
41 if (!nir_src_is_const(instr->src[src].src))
42 return false;
43
44 for (unsigned i = 0; i < num_components; i++) {
45 nir_alu_type type = nir_op_infos[instr->op].input_types[src];
46 switch (nir_alu_type_get_base_type(type)) {
47 case nir_type_int: {
48 int64_t val = nir_src_comp_as_int(instr->src[src].src, swizzle[i]);
49 if (val <= 0 || !util_is_power_of_two_or_zero64(val))
50 return false;
51 break;
52 }
53 case nir_type_uint: {
54 uint64_t val = nir_src_comp_as_uint(instr->src[src].src, swizzle[i]);
55 if (val == 0 || !util_is_power_of_two_or_zero64(val))
56 return false;
57 break;
58 }
59 default:
60 return false;
61 }
62 }
63
64 return true;
65 }
66
67 static inline bool
is_neg_power_of_two(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)68 is_neg_power_of_two(UNUSED struct hash_table *ht, nir_alu_instr *instr,
69 unsigned src, unsigned num_components,
70 const uint8_t *swizzle)
71 {
72 /* only constant srcs: */
73 if (!nir_src_is_const(instr->src[src].src))
74 return false;
75
76 for (unsigned i = 0; i < num_components; i++) {
77 nir_alu_type type = nir_op_infos[instr->op].input_types[src];
78 switch (nir_alu_type_get_base_type(type)) {
79 case nir_type_int: {
80 int64_t val = nir_src_comp_as_int(instr->src[src].src, swizzle[i]);
81 if (val >= 0 || !util_is_power_of_two_or_zero64(-val))
82 return false;
83 break;
84 }
85 default:
86 return false;
87 }
88 }
89
90 return true;
91 }
92
93 #define MULTIPLE(test) \
94 static inline bool \
95 is_unsigned_multiple_of_ ## test(UNUSED struct hash_table *ht, nir_alu_instr *instr, \
96 unsigned src, unsigned num_components, \
97 const uint8_t *swizzle) \
98 { \
99 /* only constant srcs: */ \
100 if (!nir_src_is_const(instr->src[src].src)) \
101 return false; \
102 \
103 for (unsigned i = 0; i < num_components; i++) { \
104 uint64_t val = nir_src_comp_as_uint(instr->src[src].src, swizzle[i]); \
105 if (val % test != 0) \
106 return false; \
107 } \
108 \
109 return true; \
110 }
111
112 MULTIPLE(2)
113 MULTIPLE(4)
114 MULTIPLE(8)
115 MULTIPLE(16)
116 MULTIPLE(32)
117 MULTIPLE(64)
118
119 static inline bool
is_zero_to_one(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)120 is_zero_to_one(UNUSED struct hash_table *ht, nir_alu_instr *instr, unsigned src,
121 unsigned num_components,
122 const uint8_t *swizzle)
123 {
124 /* only constant srcs: */
125 if (!nir_src_is_const(instr->src[src].src))
126 return false;
127
128 for (unsigned i = 0; i < num_components; i++) {
129 switch (nir_op_infos[instr->op].input_types[src]) {
130 case nir_type_float: {
131 double val = nir_src_comp_as_float(instr->src[src].src, swizzle[i]);
132 if (isnan(val) || val < 0.0f || val > 1.0f)
133 return false;
134 break;
135 }
136 default:
137 return false;
138 }
139 }
140
141 return true;
142 }
143
144 /**
145 * Exclusive compare with (0, 1).
146 *
147 * This differs from \c is_zero_to_one because that function tests 0 <= src <=
148 * 1 while this function tests 0 < src < 1.
149 */
150 static inline bool
is_gt_0_and_lt_1(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)151 is_gt_0_and_lt_1(UNUSED struct hash_table *ht, nir_alu_instr *instr,
152 unsigned src, unsigned num_components,
153 const uint8_t *swizzle)
154 {
155 /* only constant srcs: */
156 if (!nir_src_is_const(instr->src[src].src))
157 return false;
158
159 for (unsigned i = 0; i < num_components; i++) {
160 switch (nir_op_infos[instr->op].input_types[src]) {
161 case nir_type_float: {
162 double val = nir_src_comp_as_float(instr->src[src].src, swizzle[i]);
163 if (isnan(val) || val <= 0.0f || val >= 1.0f)
164 return false;
165 break;
166 }
167 default:
168 return false;
169 }
170 }
171
172 return true;
173 }
174
175 static inline bool
is_not_const_zero(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)176 is_not_const_zero(UNUSED struct hash_table *ht, nir_alu_instr *instr,
177 unsigned src, unsigned num_components,
178 const uint8_t *swizzle)
179 {
180 if (nir_src_as_const_value(instr->src[src].src) == NULL)
181 return true;
182
183 for (unsigned i = 0; i < num_components; i++) {
184 nir_alu_type type = nir_op_infos[instr->op].input_types[src];
185 switch (nir_alu_type_get_base_type(type)) {
186 case nir_type_float:
187 if (nir_src_comp_as_float(instr->src[src].src, swizzle[i]) == 0.0)
188 return false;
189 break;
190 case nir_type_bool:
191 case nir_type_int:
192 case nir_type_uint:
193 if (nir_src_comp_as_uint(instr->src[src].src, swizzle[i]) == 0)
194 return false;
195 break;
196 default:
197 return false;
198 }
199 }
200
201 return true;
202 }
203
204 static inline bool
is_not_const(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)205 is_not_const(UNUSED struct hash_table *ht, nir_alu_instr *instr, unsigned src,
206 UNUSED unsigned num_components,
207 UNUSED const uint8_t *swizzle)
208 {
209 return !nir_src_is_const(instr->src[src].src);
210 }
211
212 static inline bool
is_not_fmul(struct hash_table * ht,nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)213 is_not_fmul(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
214 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
215 {
216 nir_alu_instr *src_alu =
217 nir_src_as_alu_instr(instr->src[src].src);
218
219 if (src_alu == NULL)
220 return true;
221
222 if (src_alu->op == nir_op_fneg)
223 return is_not_fmul(ht, src_alu, 0, 0, NULL);
224
225 return src_alu->op != nir_op_fmul;
226 }
227
228 static inline bool
is_fmul(struct hash_table * ht,nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)229 is_fmul(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
230 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
231 {
232 nir_alu_instr *src_alu =
233 nir_src_as_alu_instr(instr->src[src].src);
234
235 if (src_alu == NULL)
236 return false;
237
238 if (src_alu->op == nir_op_fneg)
239 return is_fmul(ht, src_alu, 0, 0, NULL);
240
241 return src_alu->op == nir_op_fmul;
242 }
243
244 static inline bool
is_fsign(nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)245 is_fsign(nir_alu_instr *instr, unsigned src,
246 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
247 {
248 nir_alu_instr *src_alu =
249 nir_src_as_alu_instr(instr->src[src].src);
250
251 if (src_alu == NULL)
252 return false;
253
254 if (src_alu->op == nir_op_fneg)
255 src_alu = nir_src_as_alu_instr(src_alu->src[0].src);
256
257 return src_alu != NULL && src_alu->op == nir_op_fsign;
258 }
259
260 static inline bool
is_not_const_and_not_fsign(struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)261 is_not_const_and_not_fsign(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
262 unsigned num_components, const uint8_t *swizzle)
263 {
264 return is_not_const(ht, instr, src, num_components, swizzle) &&
265 !is_fsign(instr, src, num_components, swizzle);
266 }
267
268 static inline bool
is_used_once(nir_alu_instr * instr)269 is_used_once(nir_alu_instr *instr)
270 {
271 bool zero_if_use = list_is_empty(&instr->dest.dest.ssa.if_uses);
272 bool zero_use = list_is_empty(&instr->dest.dest.ssa.uses);
273
274 if (zero_if_use && zero_use)
275 return false;
276
277 if (!zero_if_use && list_is_singular(&instr->dest.dest.ssa.uses))
278 return false;
279
280 if (!zero_use && list_is_singular(&instr->dest.dest.ssa.if_uses))
281 return false;
282
283 if (!list_is_singular(&instr->dest.dest.ssa.if_uses) &&
284 !list_is_singular(&instr->dest.dest.ssa.uses))
285 return false;
286
287 return true;
288 }
289
290 static inline bool
is_used_by_if(nir_alu_instr * instr)291 is_used_by_if(nir_alu_instr *instr)
292 {
293 return !list_is_empty(&instr->dest.dest.ssa.if_uses);
294 }
295
296 static inline bool
is_not_used_by_if(nir_alu_instr * instr)297 is_not_used_by_if(nir_alu_instr *instr)
298 {
299 return list_is_empty(&instr->dest.dest.ssa.if_uses);
300 }
301
302 static inline bool
is_used_by_non_fsat(nir_alu_instr * instr)303 is_used_by_non_fsat(nir_alu_instr *instr)
304 {
305 nir_foreach_use(src, &instr->dest.dest.ssa) {
306 const nir_instr *const user_instr = src->parent_instr;
307
308 if (user_instr->type != nir_instr_type_alu)
309 return true;
310
311 const nir_alu_instr *const user_alu = nir_instr_as_alu(user_instr);
312
313 assert(instr != user_alu);
314 if (user_alu->op != nir_op_fsat)
315 return true;
316 }
317
318 return false;
319 }
320
321 /**
322 * Returns true if a NIR ALU src represents a constant integer
323 * of either 32 or 64 bits, and the higher word (bit-size / 2)
324 * of all its components is zero.
325 */
326 static inline bool
is_upper_half_zero(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)327 is_upper_half_zero(UNUSED struct hash_table *ht,
328 nir_alu_instr *instr, unsigned src,
329 unsigned num_components, const uint8_t *swizzle)
330 {
331 if (nir_src_as_const_value(instr->src[src].src) == NULL)
332 return false;
333
334 for (unsigned i = 0; i < num_components; i++) {
335 unsigned half_bit_size = nir_src_bit_size(instr->src[src].src) / 2;
336 uint32_t high_bits = ((1 << half_bit_size) - 1) << half_bit_size;
337 if ((nir_src_comp_as_uint(instr->src[src].src,
338 swizzle[i]) & high_bits) != 0) {
339 return false;
340 }
341 }
342
343 return true;
344 }
345
346 /**
347 * Returns true if a NIR ALU src represents a constant integer
348 * of either 32 or 64 bits, and the lower word (bit-size / 2)
349 * of all its components is zero.
350 */
351 static inline bool
is_lower_half_zero(UNUSED struct hash_table * ht,nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)352 is_lower_half_zero(UNUSED struct hash_table *ht,
353 nir_alu_instr *instr, unsigned src,
354 unsigned num_components, const uint8_t *swizzle)
355 {
356 if (nir_src_as_const_value(instr->src[src].src) == NULL)
357 return false;
358
359 for (unsigned i = 0; i < num_components; i++) {
360 uint32_t low_bits =
361 (1 << (nir_src_bit_size(instr->src[src].src) / 2)) - 1;
362 if ((nir_src_comp_as_int(instr->src[src].src, swizzle[i]) & low_bits) != 0)
363 return false;
364 }
365
366 return true;
367 }
368
369 static inline bool
no_signed_wrap(nir_alu_instr * instr)370 no_signed_wrap(nir_alu_instr *instr)
371 {
372 return instr->no_signed_wrap;
373 }
374
375 static inline bool
no_unsigned_wrap(nir_alu_instr * instr)376 no_unsigned_wrap(nir_alu_instr *instr)
377 {
378 return instr->no_unsigned_wrap;
379 }
380
381 static inline bool
is_integral(struct hash_table * ht,nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)382 is_integral(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
383 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
384 {
385 const struct ssa_result_range r = nir_analyze_range(ht, instr, src);
386
387 return r.is_integral;
388 }
389
390 #define RELATION(r) \
391 static inline bool \
392 is_ ## r (struct hash_table *ht, nir_alu_instr *instr, unsigned src, \
393 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle) \
394 { \
395 const struct ssa_result_range v = nir_analyze_range(ht, instr, src); \
396 return v.range == r; \
397 }
398
399 RELATION(lt_zero)
RELATION(le_zero)400 RELATION(le_zero)
401 RELATION(gt_zero)
402 RELATION(ge_zero)
403 RELATION(ne_zero)
404
405 static inline bool
406 is_not_negative(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
407 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
408 {
409 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
410 return v.range == ge_zero || v.range == gt_zero || v.range == eq_zero;
411 }
412
413 static inline bool
is_not_positive(struct hash_table * ht,nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)414 is_not_positive(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
415 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
416 {
417 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
418 return v.range == le_zero || v.range == lt_zero || v.range == eq_zero;
419 }
420
421 static inline bool
is_not_zero(struct hash_table * ht,nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)422 is_not_zero(struct hash_table *ht, nir_alu_instr *instr, unsigned src,
423 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
424 {
425 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
426 return v.range == lt_zero || v.range == gt_zero || v.range == ne_zero;
427 }
428
429 #endif /* _NIR_SEARCH_ */
430