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,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)36 is_pos_power_of_two(UNUSED struct hash_table *ht, const 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,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)68 is_neg_power_of_two(UNUSED struct hash_table *ht, const 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 int64_t int_min = u_intN_min(instr->src[src].src.ssa->bit_size);
77
78 for (unsigned i = 0; i < num_components; i++) {
79 nir_alu_type type = nir_op_infos[instr->op].input_types[src];
80 switch (nir_alu_type_get_base_type(type)) {
81 case nir_type_int: {
82 int64_t val = nir_src_comp_as_int(instr->src[src].src, swizzle[i]);
83 /* "int_min" is a power-of-two, but negation can cause overflow. */
84 if (val == int_min || val >= 0 || !util_is_power_of_two_or_zero64(-val))
85 return false;
86 break;
87 }
88 default:
89 return false;
90 }
91 }
92
93 return true;
94 }
95
96 #define MULTIPLE(test) \
97 static inline bool \
98 is_unsigned_multiple_of_ ## test(UNUSED struct hash_table *ht, \
99 const nir_alu_instr *instr, \
100 unsigned src, unsigned num_components, \
101 const uint8_t *swizzle) \
102 { \
103 /* only constant srcs: */ \
104 if (!nir_src_is_const(instr->src[src].src)) \
105 return false; \
106 \
107 for (unsigned i = 0; i < num_components; i++) { \
108 uint64_t val = nir_src_comp_as_uint(instr->src[src].src, swizzle[i]); \
109 if (val % test != 0) \
110 return false; \
111 } \
112 \
113 return true; \
114 }
115
116 MULTIPLE(2)
117 MULTIPLE(4)
118 MULTIPLE(8)
119 MULTIPLE(16)
120 MULTIPLE(32)
121 MULTIPLE(64)
122
123 static inline bool
is_zero_to_one(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)124 is_zero_to_one(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
125 unsigned src, unsigned num_components,
126 const uint8_t *swizzle)
127 {
128 /* only constant srcs: */
129 if (!nir_src_is_const(instr->src[src].src))
130 return false;
131
132 for (unsigned i = 0; i < num_components; i++) {
133 switch (nir_op_infos[instr->op].input_types[src]) {
134 case nir_type_float: {
135 double val = nir_src_comp_as_float(instr->src[src].src, swizzle[i]);
136 if (isnan(val) || val < 0.0f || val > 1.0f)
137 return false;
138 break;
139 }
140 default:
141 return false;
142 }
143 }
144
145 return true;
146 }
147
148 /**
149 * Exclusive compare with (0, 1).
150 *
151 * This differs from \c is_zero_to_one because that function tests 0 <= src <=
152 * 1 while this function tests 0 < src < 1.
153 */
154 static inline bool
is_gt_0_and_lt_1(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)155 is_gt_0_and_lt_1(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
156 unsigned src, unsigned num_components,
157 const uint8_t *swizzle)
158 {
159 /* only constant srcs: */
160 if (!nir_src_is_const(instr->src[src].src))
161 return false;
162
163 for (unsigned i = 0; i < num_components; i++) {
164 switch (nir_op_infos[instr->op].input_types[src]) {
165 case nir_type_float: {
166 double val = nir_src_comp_as_float(instr->src[src].src, swizzle[i]);
167 if (isnan(val) || val <= 0.0f || val >= 1.0f)
168 return false;
169 break;
170 }
171 default:
172 return false;
173 }
174 }
175
176 return true;
177 }
178
179 static inline bool
is_not_const_zero(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)180 is_not_const_zero(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
181 unsigned src, unsigned num_components,
182 const uint8_t *swizzle)
183 {
184 if (nir_src_as_const_value(instr->src[src].src) == NULL)
185 return true;
186
187 for (unsigned i = 0; i < num_components; i++) {
188 nir_alu_type type = nir_op_infos[instr->op].input_types[src];
189 switch (nir_alu_type_get_base_type(type)) {
190 case nir_type_float:
191 if (nir_src_comp_as_float(instr->src[src].src, swizzle[i]) == 0.0)
192 return false;
193 break;
194 case nir_type_bool:
195 case nir_type_int:
196 case nir_type_uint:
197 if (nir_src_comp_as_uint(instr->src[src].src, swizzle[i]) == 0)
198 return false;
199 break;
200 default:
201 return false;
202 }
203 }
204
205 return true;
206 }
207
208 /** Is value unsigned less than 0xfffc07fc? */
209 static inline bool
is_ult_0xfffc07fc(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)210 is_ult_0xfffc07fc(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
211 unsigned src, unsigned num_components,
212 const uint8_t *swizzle)
213 {
214 /* only constant srcs: */
215 if (!nir_src_is_const(instr->src[src].src))
216 return false;
217
218 for (unsigned i = 0; i < num_components; i++) {
219 const unsigned val =
220 nir_src_comp_as_uint(instr->src[src].src, swizzle[i]);
221
222 if (val >= 0xfffc07fcU)
223 return false;
224 }
225
226 return true;
227 }
228
229 static inline bool
is_not_const(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)230 is_not_const(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
231 unsigned src, UNUSED unsigned num_components,
232 UNUSED const uint8_t *swizzle)
233 {
234 return !nir_src_is_const(instr->src[src].src);
235 }
236
237 static inline bool
is_not_fmul(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)238 is_not_fmul(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
239 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
240 {
241 nir_alu_instr *src_alu =
242 nir_src_as_alu_instr(instr->src[src].src);
243
244 if (src_alu == NULL)
245 return true;
246
247 if (src_alu->op == nir_op_fneg)
248 return is_not_fmul(ht, src_alu, 0, 0, NULL);
249
250 return src_alu->op != nir_op_fmul;
251 }
252
253 static inline bool
is_fmul(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)254 is_fmul(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
255 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
256 {
257 nir_alu_instr *src_alu =
258 nir_src_as_alu_instr(instr->src[src].src);
259
260 if (src_alu == NULL)
261 return false;
262
263 if (src_alu->op == nir_op_fneg)
264 return is_fmul(ht, src_alu, 0, 0, NULL);
265
266 return src_alu->op == nir_op_fmul;
267 }
268
269 static inline bool
is_fsign(const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)270 is_fsign(const nir_alu_instr *instr, unsigned src,
271 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
272 {
273 nir_alu_instr *src_alu =
274 nir_src_as_alu_instr(instr->src[src].src);
275
276 if (src_alu == NULL)
277 return false;
278
279 if (src_alu->op == nir_op_fneg)
280 src_alu = nir_src_as_alu_instr(src_alu->src[0].src);
281
282 return src_alu != NULL && src_alu->op == nir_op_fsign;
283 }
284
285 static inline bool
is_not_const_and_not_fsign(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)286 is_not_const_and_not_fsign(struct hash_table *ht, const nir_alu_instr *instr,
287 unsigned src, unsigned num_components,
288 const uint8_t *swizzle)
289 {
290 return is_not_const(ht, instr, src, num_components, swizzle) &&
291 !is_fsign(instr, src, num_components, swizzle);
292 }
293
294 static inline bool
is_used_once(nir_alu_instr * instr)295 is_used_once(nir_alu_instr *instr)
296 {
297 bool zero_if_use = list_is_empty(&instr->dest.dest.ssa.if_uses);
298 bool zero_use = list_is_empty(&instr->dest.dest.ssa.uses);
299
300 if (zero_if_use && zero_use)
301 return false;
302
303 if (!zero_if_use && list_is_singular(&instr->dest.dest.ssa.uses))
304 return false;
305
306 if (!zero_use && list_is_singular(&instr->dest.dest.ssa.if_uses))
307 return false;
308
309 if (!list_is_singular(&instr->dest.dest.ssa.if_uses) &&
310 !list_is_singular(&instr->dest.dest.ssa.uses))
311 return false;
312
313 return true;
314 }
315
316 static inline bool
is_used_by_if(nir_alu_instr * instr)317 is_used_by_if(nir_alu_instr *instr)
318 {
319 return !list_is_empty(&instr->dest.dest.ssa.if_uses);
320 }
321
322 static inline bool
is_not_used_by_if(nir_alu_instr * instr)323 is_not_used_by_if(nir_alu_instr *instr)
324 {
325 return list_is_empty(&instr->dest.dest.ssa.if_uses);
326 }
327
328 static inline bool
is_used_by_non_fsat(nir_alu_instr * instr)329 is_used_by_non_fsat(nir_alu_instr *instr)
330 {
331 nir_foreach_use(src, &instr->dest.dest.ssa) {
332 const nir_instr *const user_instr = src->parent_instr;
333
334 if (user_instr->type != nir_instr_type_alu)
335 return true;
336
337 const nir_alu_instr *const user_alu = nir_instr_as_alu(user_instr);
338
339 assert(instr != user_alu);
340 if (user_alu->op != nir_op_fsat)
341 return true;
342 }
343
344 return false;
345 }
346
347 static inline bool
is_only_used_as_float(nir_alu_instr * instr)348 is_only_used_as_float(nir_alu_instr *instr)
349 {
350 nir_foreach_use(src, &instr->dest.dest.ssa) {
351 const nir_instr *const user_instr = src->parent_instr;
352 if (user_instr->type != nir_instr_type_alu)
353 return false;
354
355 const nir_alu_instr *const user_alu = nir_instr_as_alu(user_instr);
356 assert(instr != user_alu);
357
358 unsigned index = (nir_alu_src*)container_of(src, nir_alu_src, src) - user_alu->src;
359 if (nir_op_infos[user_alu->op].input_types[index] != nir_type_float)
360 return false;
361 }
362
363 return true;
364 }
365
366 static inline bool
only_lower_8_bits_used(nir_alu_instr * instr)367 only_lower_8_bits_used(nir_alu_instr *instr)
368 {
369 return (nir_ssa_def_bits_used(&instr->dest.dest.ssa) & ~0xffull) == 0;
370 }
371
372 static inline bool
only_lower_16_bits_used(nir_alu_instr * instr)373 only_lower_16_bits_used(nir_alu_instr *instr)
374 {
375 return (nir_ssa_def_bits_used(&instr->dest.dest.ssa) & ~0xffffull) == 0;
376 }
377
378 /**
379 * Returns true if a NIR ALU src represents a constant integer
380 * of either 32 or 64 bits, and the higher word (bit-size / 2)
381 * of all its components is zero.
382 */
383 static inline bool
is_upper_half_zero(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)384 is_upper_half_zero(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
385 unsigned src, unsigned num_components,
386 const uint8_t *swizzle)
387 {
388 if (nir_src_as_const_value(instr->src[src].src) == NULL)
389 return false;
390
391 for (unsigned i = 0; i < num_components; i++) {
392 unsigned half_bit_size = nir_src_bit_size(instr->src[src].src) / 2;
393 uint32_t high_bits = ((1 << half_bit_size) - 1) << half_bit_size;
394 if ((nir_src_comp_as_uint(instr->src[src].src,
395 swizzle[i]) & high_bits) != 0) {
396 return false;
397 }
398 }
399
400 return true;
401 }
402
403 /**
404 * Returns true if a NIR ALU src represents a constant integer
405 * of either 32 or 64 bits, and the lower word (bit-size / 2)
406 * of all its components is zero.
407 */
408 static inline bool
is_lower_half_zero(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,unsigned num_components,const uint8_t * swizzle)409 is_lower_half_zero(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
410 unsigned src, unsigned num_components,
411 const uint8_t *swizzle)
412 {
413 if (nir_src_as_const_value(instr->src[src].src) == NULL)
414 return false;
415
416 for (unsigned i = 0; i < num_components; i++) {
417 uint32_t low_bits =
418 (1 << (nir_src_bit_size(instr->src[src].src) / 2)) - 1;
419 if ((nir_src_comp_as_int(instr->src[src].src, swizzle[i]) & low_bits) != 0)
420 return false;
421 }
422
423 return true;
424 }
425
426 static inline bool
no_signed_wrap(nir_alu_instr * instr)427 no_signed_wrap(nir_alu_instr *instr)
428 {
429 return instr->no_signed_wrap;
430 }
431
432 static inline bool
no_unsigned_wrap(nir_alu_instr * instr)433 no_unsigned_wrap(nir_alu_instr *instr)
434 {
435 return instr->no_unsigned_wrap;
436 }
437
438 static inline bool
is_integral(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)439 is_integral(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
440 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
441 {
442 const struct ssa_result_range r = nir_analyze_range(ht, instr, src);
443
444 return r.is_integral;
445 }
446
447 /**
448 * Is the value finite?
449 */
450 static inline bool
is_finite(UNUSED struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)451 is_finite(UNUSED struct hash_table *ht, const nir_alu_instr *instr,
452 unsigned src, UNUSED unsigned num_components,
453 UNUSED const uint8_t *swizzle)
454 {
455 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
456
457 return v.is_finite;
458 }
459
460
461 #define RELATION(r) \
462 static inline bool \
463 is_ ## r (struct hash_table *ht, const nir_alu_instr *instr, \
464 unsigned src, UNUSED unsigned num_components, \
465 UNUSED const uint8_t *swizzle) \
466 { \
467 const struct ssa_result_range v = nir_analyze_range(ht, instr, src); \
468 return v.range == r; \
469 } \
470 \
471 static inline bool \
472 is_a_number_ ## r (struct hash_table *ht, const nir_alu_instr *instr, \
473 unsigned src, UNUSED unsigned num_components, \
474 UNUSED const uint8_t *swizzle) \
475 { \
476 const struct ssa_result_range v = nir_analyze_range(ht, instr, src); \
477 return v.is_a_number && v.range == r; \
478 }
479
480 RELATION(lt_zero)
RELATION(le_zero)481 RELATION(le_zero)
482 RELATION(gt_zero)
483 RELATION(ge_zero)
484 RELATION(ne_zero)
485
486 static inline bool
487 is_not_negative(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
488 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
489 {
490 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
491 return v.range == ge_zero || v.range == gt_zero || v.range == eq_zero;
492 }
493
494 static inline bool
is_a_number_not_negative(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)495 is_a_number_not_negative(struct hash_table *ht, const nir_alu_instr *instr,
496 unsigned src, UNUSED unsigned num_components,
497 UNUSED const uint8_t *swizzle)
498 {
499 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
500 return v.is_a_number &&
501 (v.range == ge_zero || v.range == gt_zero || v.range == eq_zero);
502 }
503
504
505 static inline bool
is_not_positive(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)506 is_not_positive(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
507 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
508 {
509 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
510 return v.range == le_zero || v.range == lt_zero || v.range == eq_zero;
511 }
512
513 static inline bool
is_a_number_not_positive(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)514 is_a_number_not_positive(struct hash_table *ht, const nir_alu_instr *instr,
515 unsigned src, UNUSED unsigned num_components,
516 UNUSED const uint8_t *swizzle)
517 {
518 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
519 return v.is_a_number &&
520 (v.range == le_zero || v.range == lt_zero || v.range == eq_zero);
521 }
522
523 static inline bool
is_not_zero(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)524 is_not_zero(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
525 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
526 {
527 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
528 return v.range == lt_zero || v.range == gt_zero || v.range == ne_zero;
529 }
530
531 static inline bool
is_a_number_not_zero(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)532 is_a_number_not_zero(struct hash_table *ht, const nir_alu_instr *instr,
533 unsigned src, UNUSED unsigned num_components,
534 UNUSED const uint8_t *swizzle)
535 {
536 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
537 return v.is_a_number &&
538 (v.range == lt_zero || v.range == gt_zero || v.range == ne_zero);
539 }
540
541 static inline bool
is_a_number(struct hash_table * ht,const nir_alu_instr * instr,unsigned src,UNUSED unsigned num_components,UNUSED const uint8_t * swizzle)542 is_a_number(struct hash_table *ht, const nir_alu_instr *instr, unsigned src,
543 UNUSED unsigned num_components, UNUSED const uint8_t *swizzle)
544 {
545 const struct ssa_result_range v = nir_analyze_range(ht, instr, src);
546 return v.is_a_number;
547 }
548
549 #endif /* _NIR_SEARCH_ */
550