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