nir/range-analysis: Fail gracefully on non-SSA sources
[mesa.git] / src / compiler / nir / nir_range_analysis.c
1 /*
2 * Copyright © 2018 Intel Corporation
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 #include <math.h>
24 #include <float.h>
25 #include "nir.h"
26 #include "nir_range_analysis.h"
27 #include "util/hash_table.h"
28
29 /**
30 * Analyzes a sequence of operations to determine some aspects of the range of
31 * the result.
32 */
33
34 static bool
35 is_not_zero(enum ssa_ranges r)
36 {
37 return r == gt_zero || r == lt_zero || r == ne_zero;
38 }
39
40 static void *
41 pack_data(const struct ssa_result_range r)
42 {
43 return (void *)(uintptr_t)(r.range | r.is_integral << 8);
44 }
45
46 static struct ssa_result_range
47 unpack_data(const void *p)
48 {
49 const uintptr_t v = (uintptr_t) p;
50
51 return (struct ssa_result_range){v & 0xff, (v & 0x0ff00) != 0};
52 }
53
54 static struct ssa_result_range
55 analyze_constant(const struct nir_alu_instr *instr, unsigned src)
56 {
57 uint8_t swizzle[4] = { 0, 1, 2, 3 };
58
59 /* If the source is an explicitly sized source, then we need to reset
60 * both the number of components and the swizzle.
61 */
62 const unsigned num_components = nir_ssa_alu_instr_src_components(instr, src);
63
64 for (unsigned i = 0; i < num_components; ++i)
65 swizzle[i] = instr->src[src].swizzle[i];
66
67 const nir_load_const_instr *const load =
68 nir_instr_as_load_const(instr->src[src].src.ssa->parent_instr);
69
70 struct ssa_result_range r = { unknown, false };
71
72 switch (nir_op_infos[instr->op].input_types[src]) {
73 case nir_type_float: {
74 double min_value = DBL_MAX;
75 double max_value = -DBL_MAX;
76 bool any_zero = false;
77 bool all_zero = true;
78
79 r.is_integral = true;
80
81 for (unsigned i = 0; i < num_components; ++i) {
82 const double v = nir_const_value_as_float(load->value[swizzle[i]],
83 load->def.bit_size);
84
85 if (floor(v) != v)
86 r.is_integral = false;
87
88 any_zero = any_zero || (v == 0.0);
89 all_zero = all_zero && (v == 0.0);
90 min_value = MIN2(min_value, v);
91 max_value = MAX2(max_value, v);
92 }
93
94 assert(any_zero >= all_zero);
95 assert(isnan(max_value) || max_value >= min_value);
96
97 if (all_zero)
98 r.range = eq_zero;
99 else if (min_value > 0.0)
100 r.range = gt_zero;
101 else if (min_value == 0.0)
102 r.range = ge_zero;
103 else if (max_value < 0.0)
104 r.range = lt_zero;
105 else if (max_value == 0.0)
106 r.range = le_zero;
107 else if (!any_zero)
108 r.range = ne_zero;
109 else
110 r.range = unknown;
111
112 return r;
113 }
114
115 case nir_type_int:
116 case nir_type_bool: {
117 int64_t min_value = INT_MAX;
118 int64_t max_value = INT_MIN;
119 bool any_zero = false;
120 bool all_zero = true;
121
122 for (unsigned i = 0; i < num_components; ++i) {
123 const int64_t v = nir_const_value_as_int(load->value[swizzle[i]],
124 load->def.bit_size);
125
126 any_zero = any_zero || (v == 0);
127 all_zero = all_zero && (v == 0);
128 min_value = MIN2(min_value, v);
129 max_value = MAX2(max_value, v);
130 }
131
132 assert(any_zero >= all_zero);
133 assert(max_value >= min_value);
134
135 if (all_zero)
136 r.range = eq_zero;
137 else if (min_value > 0)
138 r.range = gt_zero;
139 else if (min_value == 0)
140 r.range = ge_zero;
141 else if (max_value < 0)
142 r.range = lt_zero;
143 else if (max_value == 0)
144 r.range = le_zero;
145 else if (!any_zero)
146 r.range = ne_zero;
147 else
148 r.range = unknown;
149
150 return r;
151 }
152
153 case nir_type_uint: {
154 bool any_zero = false;
155 bool all_zero = true;
156
157 for (unsigned i = 0; i < num_components; ++i) {
158 const uint64_t v = nir_const_value_as_uint(load->value[swizzle[i]],
159 load->def.bit_size);
160
161 any_zero = any_zero || (v == 0);
162 all_zero = all_zero && (v == 0);
163 }
164
165 assert(any_zero >= all_zero);
166
167 if (all_zero)
168 r.range = eq_zero;
169 else if (any_zero)
170 r.range = ge_zero;
171 else
172 r.range = gt_zero;
173
174 return r;
175 }
176
177 default:
178 unreachable("Invalid alu source type");
179 }
180 }
181
182 #ifndef NDEBUG
183 #define ASSERT_TABLE_IS_COMMUTATIVE(t) \
184 do { \
185 for (unsigned r = 0; r < ARRAY_SIZE(t); r++) { \
186 for (unsigned c = 0; c < ARRAY_SIZE(t[0]); c++) \
187 assert(t[r][c] == t[c][r]); \
188 } \
189 } while (false)
190
191 #define ASSERT_TABLE_IS_DIAGONAL(t) \
192 do { \
193 for (unsigned r = 0; r < ARRAY_SIZE(t); r++) \
194 assert(t[r][r] == r); \
195 } while (false)
196 #else
197 #define ASSERT_TABLE_IS_COMMUTATIVE(t)
198 #define ASSERT_TABLE_IS_DIAGONAL(t)
199 #endif
200
201 /**
202 * Short-hand name for use in the tables in analyze_expression. If this name
203 * becomes a problem on some compiler, we can change it to _.
204 */
205 #define _______ unknown
206
207 /**
208 * Analyze an expression to determine the range of its result
209 *
210 * The end result of this analysis is a token that communicates something
211 * about the range of values. There's an implicit grammar that produces
212 * tokens from sequences of literal values, other tokens, and operations.
213 * This function implements this grammar as a recursive-descent parser. Some
214 * (but not all) of the grammar is listed in-line in the function.
215 */
216 static struct ssa_result_range
217 analyze_expression(const nir_alu_instr *instr, unsigned src,
218 struct hash_table *ht)
219 {
220 if (!instr->src[src].src.is_ssa)
221 return (struct ssa_result_range){unknown, false};
222
223 if (nir_src_is_const(instr->src[src].src))
224 return analyze_constant(instr, src);
225
226 if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_alu)
227 return (struct ssa_result_range){unknown, false};
228
229 const struct nir_alu_instr *const alu =
230 nir_instr_as_alu(instr->src[src].src.ssa->parent_instr);
231
232 struct hash_entry *he = _mesa_hash_table_search(ht, alu);
233 if (he != NULL)
234 return unpack_data(he->data);
235
236 struct ssa_result_range r = {unknown, false};
237
238 /* ge_zero: ge_zero + ge_zero
239 *
240 * gt_zero: gt_zero + eq_zero
241 * | gt_zero + ge_zero
242 * | eq_zero + gt_zero # Addition is commutative
243 * | ge_zero + gt_zero # Addition is commutative
244 * | gt_zero + gt_zero
245 * ;
246 *
247 * le_zero: le_zero + le_zero
248 *
249 * lt_zero: lt_zero + eq_zero
250 * | lt_zero + le_zero
251 * | eq_zero + lt_zero # Addition is commutative
252 * | le_zero + lt_zero # Addition is commutative
253 * | lt_zero + lt_zero
254 * ;
255 *
256 * eq_zero: eq_zero + eq_zero
257 *
258 * All other cases are 'unknown'.
259 */
260 static const enum ssa_ranges fadd_table[last_range + 1][last_range + 1] = {
261 /* left\right unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */
262 /* unknown */ { _______, _______, _______, _______, _______, _______, _______ },
263 /* lt_zero */ { _______, lt_zero, lt_zero, _______, _______, _______, lt_zero },
264 /* le_zero */ { _______, lt_zero, le_zero, _______, _______, _______, le_zero },
265 /* gt_zero */ { _______, _______, _______, gt_zero, gt_zero, _______, gt_zero },
266 /* ge_zero */ { _______, _______, _______, gt_zero, ge_zero, _______, ge_zero },
267 /* ne_zero */ { _______, _______, _______, _______, _______, ne_zero, ne_zero },
268 /* eq_zero */ { _______, lt_zero, le_zero, gt_zero, ge_zero, ne_zero, eq_zero },
269 };
270
271 ASSERT_TABLE_IS_COMMUTATIVE(fadd_table);
272 ASSERT_TABLE_IS_DIAGONAL(fadd_table);
273
274 /* ge_zero: ge_zero * ge_zero
275 * | ge_zero * gt_zero
276 * | ge_zero * eq_zero
277 * | le_zero * lt_zero
278 * | lt_zero * le_zero # Multiplication is commutative
279 * | le_zero * le_zero
280 * | gt_zero * ge_zero # Multiplication is commutative
281 * | eq_zero * ge_zero # Multiplication is commutative
282 * | a * a # Left source == right source
283 * ;
284 *
285 * gt_zero: gt_zero * gt_zero
286 * | lt_zero * lt_zero
287 * ;
288 *
289 * le_zero: ge_zero * le_zero
290 * | ge_zero * lt_zero
291 * | lt_zero * ge_zero # Multiplication is commutative
292 * | le_zero * ge_zero # Multiplication is commutative
293 * | le_zero * gt_zero
294 * ;
295 *
296 * lt_zero: lt_zero * gt_zero
297 * | gt_zero * lt_zero # Multiplication is commutative
298 * ;
299 *
300 * ne_zero: ne_zero * gt_zero
301 * | ne_zero * lt_zero
302 * | gt_zero * ne_zero # Multiplication is commutative
303 * | lt_zero * ne_zero # Multiplication is commutative
304 * | ne_zero * ne_zero
305 * ;
306 *
307 * eq_zero: eq_zero * <any>
308 * <any> * eq_zero # Multiplication is commutative
309 *
310 * All other cases are 'unknown'.
311 */
312 static const enum ssa_ranges fmul_table[last_range + 1][last_range + 1] = {
313 /* left\right unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */
314 /* unknown */ { _______, _______, _______, _______, _______, _______, eq_zero },
315 /* lt_zero */ { _______, gt_zero, ge_zero, lt_zero, le_zero, ne_zero, eq_zero },
316 /* le_zero */ { _______, ge_zero, ge_zero, le_zero, le_zero, _______, eq_zero },
317 /* gt_zero */ { _______, lt_zero, le_zero, gt_zero, ge_zero, ne_zero, eq_zero },
318 /* ge_zero */ { _______, le_zero, le_zero, ge_zero, ge_zero, _______, eq_zero },
319 /* ne_zero */ { _______, ne_zero, _______, ne_zero, _______, ne_zero, eq_zero },
320 /* eq_zero */ { eq_zero, eq_zero, eq_zero, eq_zero, eq_zero, eq_zero, eq_zero }
321 };
322
323 ASSERT_TABLE_IS_COMMUTATIVE(fmul_table);
324
325 static const enum ssa_ranges fneg_table[last_range + 1] = {
326 /* unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */
327 _______, gt_zero, ge_zero, lt_zero, le_zero, ne_zero, eq_zero
328 };
329
330
331 switch (alu->op) {
332 case nir_op_b2f32:
333 case nir_op_b2i32:
334 r = (struct ssa_result_range){ge_zero, alu->op == nir_op_b2f32};
335 break;
336
337 case nir_op_bcsel: {
338 const struct ssa_result_range left = analyze_expression(alu, 1, ht);
339 const struct ssa_result_range right = analyze_expression(alu, 2, ht);
340
341 /* If either source is a constant load that is not zero, punt. The type
342 * will always be uint regardless of the actual type. We can't even
343 * decide if the value is non-zero because -0.0 is 0x80000000, and that
344 * will (possibly incorrectly) be considered non-zero.
345 */
346 /* FINISHME: We could do better, but it would require having the expected
347 * FINISHME: type passed in.
348 */
349 if ((nir_src_is_const(alu->src[1].src) && left.range != eq_zero) ||
350 (nir_src_is_const(alu->src[2].src) && right.range != eq_zero)) {
351 return (struct ssa_result_range){unknown, false};
352 }
353
354 r.is_integral = left.is_integral && right.is_integral;
355
356 /* le_zero: bcsel(<any>, le_zero, lt_zero)
357 * | bcsel(<any>, eq_zero, lt_zero)
358 * | bcsel(<any>, le_zero, eq_zero)
359 * | bcsel(<any>, lt_zero, le_zero)
360 * | bcsel(<any>, lt_zero, eq_zero)
361 * | bcsel(<any>, eq_zero, le_zero)
362 * | bcsel(<any>, le_zero, le_zero)
363 * ;
364 *
365 * lt_zero: bcsel(<any>, lt_zero, lt_zero)
366 * ;
367 *
368 * ge_zero: bcsel(<any>, ge_zero, ge_zero)
369 * | bcsel(<any>, ge_zero, gt_zero)
370 * | bcsel(<any>, ge_zero, eq_zero)
371 * | bcsel(<any>, gt_zero, ge_zero)
372 * | bcsel(<any>, eq_zero, ge_zero)
373 * ;
374 *
375 * gt_zero: bcsel(<any>, gt_zero, gt_zero)
376 * ;
377 *
378 * ne_zero: bcsel(<any>, ne_zero, gt_zero)
379 * | bcsel(<any>, ne_zero, lt_zero)
380 * | bcsel(<any>, gt_zero, lt_zero)
381 * | bcsel(<any>, gt_zero, ne_zero)
382 * | bcsel(<any>, lt_zero, ne_zero)
383 * | bcsel(<any>, lt_zero, gt_zero)
384 * | bcsel(<any>, ne_zero, ne_zero)
385 * ;
386 *
387 * eq_zero: bcsel(<any>, eq_zero, eq_zero)
388 * ;
389 *
390 * All other cases are 'unknown'.
391 *
392 * The ranges could be tightened if the range of the first source is
393 * known. However, opt_algebraic will (eventually) elminiate the bcsel
394 * if the condition is known.
395 */
396 static const enum ssa_ranges table[last_range + 1][last_range + 1] = {
397 /* left\right unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */
398 /* unknown */ { _______, _______, _______, _______, _______, _______, _______ },
399 /* lt_zero */ { _______, lt_zero, le_zero, ne_zero, _______, ne_zero, le_zero },
400 /* le_zero */ { _______, le_zero, le_zero, _______, _______, _______, le_zero },
401 /* gt_zero */ { _______, ne_zero, _______, gt_zero, ge_zero, ne_zero, ge_zero },
402 /* ge_zero */ { _______, _______, _______, ge_zero, ge_zero, _______, ge_zero },
403 /* ne_zero */ { _______, ne_zero, _______, ne_zero, _______, ne_zero, _______ },
404 /* eq_zero */ { _______, le_zero, le_zero, ge_zero, ge_zero, _______, eq_zero },
405 };
406
407 ASSERT_TABLE_IS_COMMUTATIVE(table);
408 ASSERT_TABLE_IS_DIAGONAL(table);
409
410 r.range = table[left.range][right.range];
411 break;
412 }
413
414 case nir_op_i2f32:
415 case nir_op_u2f32:
416 r = analyze_expression(alu, 0, ht);
417
418 r.is_integral = true;
419
420 if (r.range == unknown && alu->op == nir_op_u2f32)
421 r.range = ge_zero;
422
423 break;
424
425 case nir_op_fabs:
426 r = analyze_expression(alu, 0, ht);
427
428 switch (r.range) {
429 case unknown:
430 case le_zero:
431 case ge_zero:
432 r.range = ge_zero;
433 break;
434
435 case lt_zero:
436 case gt_zero:
437 case ne_zero:
438 r.range = gt_zero;
439 break;
440
441 case eq_zero:
442 break;
443 }
444
445 break;
446
447 case nir_op_fadd: {
448 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
449 const struct ssa_result_range right = analyze_expression(alu, 1, ht);
450
451 r.is_integral = left.is_integral && right.is_integral;
452 r.range = fadd_table[left.range][right.range];
453 break;
454 }
455
456 case nir_op_fexp2:
457 r = (struct ssa_result_range){gt_zero, analyze_expression(alu, 0, ht).is_integral};
458 break;
459
460 case nir_op_fmax: {
461 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
462 const struct ssa_result_range right = analyze_expression(alu, 1, ht);
463
464 r.is_integral = left.is_integral && right.is_integral;
465
466 /* gt_zero: fmax(gt_zero, *)
467 * | fmax(*, gt_zero) # Treat fmax as commutative
468 * ;
469 *
470 * ge_zero: fmax(ge_zero, ne_zero)
471 * | fmax(ge_zero, lt_zero)
472 * | fmax(ge_zero, le_zero)
473 * | fmax(ge_zero, eq_zero)
474 * | fmax(ne_zero, ge_zero) # Treat fmax as commutative
475 * | fmax(lt_zero, ge_zero) # Treat fmax as commutative
476 * | fmax(le_zero, ge_zero) # Treat fmax as commutative
477 * | fmax(eq_zero, ge_zero) # Treat fmax as commutative
478 * | fmax(ge_zero, ge_zero)
479 * ;
480 *
481 * le_zero: fmax(le_zero, lt_zero)
482 * | fmax(lt_zero, le_zero) # Treat fmax as commutative
483 * | fmax(le_zero, le_zero)
484 * ;
485 *
486 * lt_zero: fmax(lt_zero, lt_zero)
487 * ;
488 *
489 * ne_zero: fmax(ne_zero, lt_zero)
490 * | fmax(lt_zero, ne_zero) # Treat fmax as commutative
491 * | fmax(ne_zero, ne_zero)
492 * ;
493 *
494 * eq_zero: fmax(eq_zero, le_zero)
495 * | fmax(eq_zero, lt_zero)
496 * | fmax(le_zero, eq_zero) # Treat fmax as commutative
497 * | fmax(lt_zero, eq_zero) # Treat fmax as commutative
498 * | fmax(eq_zero, eq_zero)
499 * ;
500 *
501 * All other cases are 'unknown'.
502 */
503 static const enum ssa_ranges table[last_range + 1][last_range + 1] = {
504 /* left\right unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */
505 /* unknown */ { _______, _______, _______, gt_zero, ge_zero, _______, _______ },
506 /* lt_zero */ { _______, lt_zero, le_zero, gt_zero, ge_zero, ne_zero, eq_zero },
507 /* le_zero */ { _______, le_zero, le_zero, gt_zero, ge_zero, _______, eq_zero },
508 /* gt_zero */ { gt_zero, gt_zero, gt_zero, gt_zero, gt_zero, gt_zero, gt_zero },
509 /* ge_zero */ { ge_zero, ge_zero, ge_zero, gt_zero, ge_zero, ge_zero, ge_zero },
510 /* ne_zero */ { _______, ne_zero, _______, gt_zero, ge_zero, ne_zero, _______ },
511 /* eq_zero */ { _______, eq_zero, eq_zero, gt_zero, ge_zero, _______, eq_zero }
512 };
513
514 /* Treat fmax as commutative. */
515 ASSERT_TABLE_IS_COMMUTATIVE(table);
516 ASSERT_TABLE_IS_DIAGONAL(table);
517
518 r.range = table[left.range][right.range];
519 break;
520 }
521
522 case nir_op_fmin: {
523 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
524 const struct ssa_result_range right = analyze_expression(alu, 1, ht);
525
526 r.is_integral = left.is_integral && right.is_integral;
527
528 /* lt_zero: fmin(lt_zero, *)
529 * | fmin(*, lt_zero) # Treat fmin as commutative
530 * ;
531 *
532 * le_zero: fmin(le_zero, ne_zero)
533 * | fmin(le_zero, gt_zero)
534 * | fmin(le_zero, ge_zero)
535 * | fmin(le_zero, eq_zero)
536 * | fmin(ne_zero, le_zero) # Treat fmin as commutative
537 * | fmin(gt_zero, le_zero) # Treat fmin as commutative
538 * | fmin(ge_zero, le_zero) # Treat fmin as commutative
539 * | fmin(eq_zero, le_zero) # Treat fmin as commutative
540 * | fmin(le_zero, le_zero)
541 * ;
542 *
543 * ge_zero: fmin(ge_zero, gt_zero)
544 * | fmin(gt_zero, ge_zero) # Treat fmin as commutative
545 * | fmin(ge_zero, ge_zero)
546 * ;
547 *
548 * gt_zero: fmin(gt_zero, gt_zero)
549 * ;
550 *
551 * ne_zero: fmin(ne_zero, gt_zero)
552 * | fmin(gt_zero, ne_zero) # Treat fmin as commutative
553 * | fmin(ne_zero, ne_zero)
554 * ;
555 *
556 * eq_zero: fmin(eq_zero, ge_zero)
557 * | fmin(eq_zero, gt_zero)
558 * | fmin(ge_zero, eq_zero) # Treat fmin as commutative
559 * | fmin(gt_zero, eq_zero) # Treat fmin as commutative
560 * | fmin(eq_zero, eq_zero)
561 * ;
562 *
563 * All other cases are 'unknown'.
564 */
565 static const enum ssa_ranges table[last_range + 1][last_range + 1] = {
566 /* left\right unknown lt_zero le_zero gt_zero ge_zero ne_zero eq_zero */
567 /* unknown */ { _______, lt_zero, le_zero, _______, _______, _______, _______ },
568 /* lt_zero */ { lt_zero, lt_zero, lt_zero, lt_zero, lt_zero, lt_zero, lt_zero },
569 /* le_zero */ { le_zero, lt_zero, le_zero, le_zero, le_zero, le_zero, le_zero },
570 /* gt_zero */ { _______, lt_zero, le_zero, gt_zero, ge_zero, ne_zero, eq_zero },
571 /* ge_zero */ { _______, lt_zero, le_zero, ge_zero, ge_zero, _______, eq_zero },
572 /* ne_zero */ { _______, lt_zero, le_zero, ne_zero, _______, ne_zero, _______ },
573 /* eq_zero */ { _______, lt_zero, le_zero, eq_zero, eq_zero, _______, eq_zero }
574 };
575
576 /* Treat fmin as commutative. */
577 ASSERT_TABLE_IS_COMMUTATIVE(table);
578 ASSERT_TABLE_IS_DIAGONAL(table);
579
580 r.range = table[left.range][right.range];
581 break;
582 }
583
584 case nir_op_fmul: {
585 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
586 const struct ssa_result_range right = analyze_expression(alu, 1, ht);
587
588 r.is_integral = left.is_integral && right.is_integral;
589
590 /* x * x => ge_zero */
591 if (left.range != eq_zero && nir_alu_srcs_equal(alu, alu, 0, 1)) {
592 /* x * x => ge_zero or gt_zero depending on the range of x. */
593 r.range = is_not_zero(left.range) ? gt_zero : ge_zero;
594 } else if (left.range != eq_zero && nir_alu_srcs_negative_equal(alu, alu, 0, 1)) {
595 /* -x * x => le_zero or lt_zero depending on the range of x. */
596 r.range = is_not_zero(left.range) ? lt_zero : le_zero;
597 } else
598 r.range = fmul_table[left.range][right.range];
599
600 break;
601 }
602
603 case nir_op_frcp:
604 r = (struct ssa_result_range){analyze_expression(alu, 0, ht).range, false};
605 break;
606
607 case nir_op_mov:
608 r = analyze_expression(alu, 0, ht);
609 break;
610
611 case nir_op_fneg:
612 r = analyze_expression(alu, 0, ht);
613
614 r.range = fneg_table[r.range];
615 break;
616
617 case nir_op_fsat:
618 r = analyze_expression(alu, 0, ht);
619
620 switch (r.range) {
621 case le_zero:
622 case lt_zero:
623 r.range = eq_zero;
624 r.is_integral = true;
625 break;
626
627 case eq_zero:
628 assert(r.is_integral);
629 case gt_zero:
630 case ge_zero:
631 /* The fsat doesn't add any information in these cases. */
632 break;
633
634 case ne_zero:
635 case unknown:
636 /* Since the result must be in [0, 1], the value must be >= 0. */
637 r.range = ge_zero;
638 break;
639 }
640 break;
641
642 case nir_op_fsign:
643 r = (struct ssa_result_range){analyze_expression(alu, 0, ht).range, true};
644 break;
645
646 case nir_op_fsqrt:
647 case nir_op_frsq:
648 r = (struct ssa_result_range){ge_zero, false};
649 break;
650
651 case nir_op_ffloor: {
652 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
653
654 r.is_integral = true;
655
656 if (left.is_integral || left.range == le_zero || left.range == lt_zero)
657 r.range = left.range;
658 else if (left.range == ge_zero || left.range == gt_zero)
659 r.range = ge_zero;
660 else if (left.range == ne_zero)
661 r.range = unknown;
662
663 break;
664 }
665
666 case nir_op_fceil: {
667 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
668
669 r.is_integral = true;
670
671 if (left.is_integral || left.range == ge_zero || left.range == gt_zero)
672 r.range = left.range;
673 else if (left.range == le_zero || left.range == lt_zero)
674 r.range = le_zero;
675 else if (left.range == ne_zero)
676 r.range = unknown;
677
678 break;
679 }
680
681 case nir_op_ftrunc: {
682 const struct ssa_result_range left = analyze_expression(alu, 0, ht);
683
684 r.is_integral = true;
685
686 if (left.is_integral)
687 r.range = left.range;
688 else if (left.range == ge_zero || left.range == gt_zero)
689 r.range = ge_zero;
690 else if (left.range == le_zero || left.range == lt_zero)
691 r.range = le_zero;
692 else if (left.range == ne_zero)
693 r.range = unknown;
694
695 break;
696 }
697
698 case nir_op_flt:
699 case nir_op_fge:
700 case nir_op_feq:
701 case nir_op_fne:
702 case nir_op_ilt:
703 case nir_op_ige:
704 case nir_op_ieq:
705 case nir_op_ine:
706 case nir_op_ult:
707 case nir_op_uge:
708 /* Boolean results are 0 or -1. */
709 r = (struct ssa_result_range){le_zero, false};
710 break;
711
712 case nir_op_ffma: {
713 const struct ssa_result_range first = analyze_expression(alu, 0, ht);
714 const struct ssa_result_range second = analyze_expression(alu, 1, ht);
715 const struct ssa_result_range third = analyze_expression(alu, 2, ht);
716
717 r.is_integral = first.is_integral && second.is_integral &&
718 third.is_integral;
719
720 enum ssa_ranges fmul_range;
721
722 if (first.range != eq_zero && nir_alu_srcs_equal(alu, alu, 0, 1)) {
723 /* x * x => ge_zero or gt_zero depending on the range of x. */
724 fmul_range = is_not_zero(first.range) ? gt_zero : ge_zero;
725 } else if (first.range != eq_zero && nir_alu_srcs_negative_equal(alu, alu, 0, 1)) {
726 /* -x * x => le_zero or lt_zero depending on the range of x. */
727 fmul_range = is_not_zero(first.range) ? lt_zero : le_zero;
728 } else
729 fmul_range = fmul_table[first.range][second.range];
730
731 r.range = fadd_table[fmul_range][third.range];
732 break;
733 }
734
735 case nir_op_flrp: {
736 const struct ssa_result_range first = analyze_expression(alu, 0, ht);
737 const struct ssa_result_range second = analyze_expression(alu, 1, ht);
738 const struct ssa_result_range third = analyze_expression(alu, 2, ht);
739
740 r.is_integral = first.is_integral && second.is_integral &&
741 third.is_integral;
742
743 /* Decompose the flrp to first + third * (second + -first) */
744 const enum ssa_ranges inner_fadd_range =
745 fadd_table[second.range][fneg_table[first.range]];
746
747 const enum ssa_ranges fmul_range =
748 fmul_table[third.range][inner_fadd_range];
749
750 r.range = fadd_table[first.range][fmul_range];
751 break;
752 }
753
754 default:
755 r = (struct ssa_result_range){unknown, false};
756 break;
757 }
758
759 if (r.range == eq_zero)
760 r.is_integral = true;
761
762 _mesa_hash_table_insert(ht, alu, pack_data(r));
763 return r;
764 }
765
766 #undef _______
767
768 struct ssa_result_range
769 nir_analyze_range(const nir_alu_instr *instr, unsigned src)
770 {
771 struct hash_table *ht = _mesa_pointer_hash_table_create(NULL);
772
773 const struct ssa_result_range r = analyze_expression(instr, src, ht);
774
775 _mesa_hash_table_destroy(ht, NULL);
776
777 return r;
778 }