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
35static inline bool
36is_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
67static inline bool
68is_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)                                                  \
97static inline bool                                                      \
98is_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
116MULTIPLE(2)
117MULTIPLE(4)
118MULTIPLE(8)
119MULTIPLE(16)
120MULTIPLE(32)
121MULTIPLE(64)
122
123static inline bool
124is_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 */
154static inline bool
155is_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
179static inline bool
180is_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? */
209static inline bool
210is_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
229static inline bool
230is_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
237static inline bool
238is_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
253static inline bool
254is_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
269static inline bool
270is_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
285static inline bool
286is_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
294static inline bool
295is_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
316static inline bool
317is_used_by_if(nir_alu_instr *instr)
318{
319   return !list_is_empty(&instr->dest.dest.ssa.if_uses);
320}
321
322static inline bool
323is_not_used_by_if(nir_alu_instr *instr)
324{
325   return list_is_empty(&instr->dest.dest.ssa.if_uses);
326}
327
328static inline bool
329is_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
347static inline bool
348is_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
366static inline bool
367only_lower_8_bits_used(nir_alu_instr *instr)
368{
369   return (nir_ssa_def_bits_used(&instr->dest.dest.ssa) & ~0xffull) == 0;
370}
371
372static inline bool
373only_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 */
383static inline bool
384is_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 */
408static inline bool
409is_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
426static inline bool
427no_signed_wrap(nir_alu_instr *instr)
428{
429   return instr->no_signed_wrap;
430}
431
432static inline bool
433no_unsigned_wrap(nir_alu_instr *instr)
434{
435   return instr->no_unsigned_wrap;
436}
437
438static inline bool
439is_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 */
450static inline bool
451is_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)                                                     \
462static inline bool                                                      \
463is_ ## 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                                                                        \
471static inline bool                                                      \
472is_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
480RELATION(lt_zero)
481RELATION(le_zero)
482RELATION(gt_zero)
483RELATION(ge_zero)
484RELATION(ne_zero)
485
486static inline bool
487is_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
494static inline bool
495is_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
505static inline bool
506is_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
513static inline bool
514is_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
523static inline bool
524is_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
531static inline bool
532is_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
541static inline bool
542is_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