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