1 | /* Floating point range operators. |
2 | Copyright (C) 2022-2023 Free Software Foundation, Inc. |
3 | Contributed by Aldy Hernandez <aldyh@redhat.com>. |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 3, or (at your option) |
10 | any later version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "coretypes.h" |
24 | #include "backend.h" |
25 | #include "insn-codes.h" |
26 | #include "rtl.h" |
27 | #include "tree.h" |
28 | #include "gimple.h" |
29 | #include "cfghooks.h" |
30 | #include "tree-pass.h" |
31 | #include "ssa.h" |
32 | #include "optabs-tree.h" |
33 | #include "gimple-pretty-print.h" |
34 | #include "diagnostic-core.h" |
35 | #include "flags.h" |
36 | #include "fold-const.h" |
37 | #include "stor-layout.h" |
38 | #include "calls.h" |
39 | #include "cfganal.h" |
40 | #include "gimple-iterator.h" |
41 | #include "gimple-fold.h" |
42 | #include "tree-eh.h" |
43 | #include "gimple-walk.h" |
44 | #include "tree-cfg.h" |
45 | #include "wide-int.h" |
46 | #include "value-relation.h" |
47 | #include "range-op.h" |
48 | #include "range-op-mixed.h" |
49 | |
50 | // Default definitions for floating point operators. |
51 | |
52 | bool |
53 | range_operator::fold_range (frange &r, tree type, |
54 | const frange &op1, const frange &op2, |
55 | relation_trio trio) const |
56 | { |
57 | if (empty_range_varying (r, type, op1, op2)) |
58 | return true; |
59 | if (op1.known_isnan () || op2.known_isnan ()) |
60 | { |
61 | r.set_nan (type); |
62 | return true; |
63 | } |
64 | |
65 | rv_fold (r, type, |
66 | lh_lb: op1.lower_bound (), lh_ub: op1.upper_bound (), |
67 | rh_lb: op2.lower_bound (), rh_ub: op2.upper_bound (), trio.op1_op2 ()); |
68 | |
69 | if (r.known_isnan ()) |
70 | return true; |
71 | if (op1.maybe_isnan () || op2.maybe_isnan ()) |
72 | r.update_nan (); |
73 | |
74 | // If the result has overflowed and flag_trapping_math, folding this |
75 | // operation could elide an overflow or division by zero exception. |
76 | // Avoid returning a singleton +-INF, to keep the propagators (DOM |
77 | // and substitute_and_fold_engine) from folding. See PR107608. |
78 | if (flag_trapping_math |
79 | && MODE_HAS_INFINITIES (TYPE_MODE (type)) |
80 | && r.known_isinf () && !op1.known_isinf () && !op2.known_isinf ()) |
81 | { |
82 | REAL_VALUE_TYPE inf = r.lower_bound (); |
83 | if (real_isneg (&inf)) |
84 | { |
85 | REAL_VALUE_TYPE min = real_min_representable (type); |
86 | r.set (type, inf, min); |
87 | } |
88 | else |
89 | { |
90 | REAL_VALUE_TYPE max = real_max_representable (type); |
91 | r.set (type, max, inf); |
92 | } |
93 | } |
94 | |
95 | r.flush_denormals_to_zero (); |
96 | |
97 | return true; |
98 | } |
99 | |
100 | // For a given operation, fold two sets of ranges into [lb, ub]. |
101 | // MAYBE_NAN is set to TRUE if, in addition to any result in LB or |
102 | // UB, the final range has the possibility of a NAN. |
103 | void |
104 | range_operator::rv_fold (frange &r, tree type, |
105 | const REAL_VALUE_TYPE &, |
106 | const REAL_VALUE_TYPE &, |
107 | const REAL_VALUE_TYPE &, |
108 | const REAL_VALUE_TYPE &, relation_kind) const |
109 | { |
110 | r.set (type, dconstninf, dconstinf, nan_state (true)); |
111 | } |
112 | |
113 | bool |
114 | range_operator::fold_range (irange &r ATTRIBUTE_UNUSED, |
115 | tree type ATTRIBUTE_UNUSED, |
116 | const frange &lh ATTRIBUTE_UNUSED, |
117 | const irange &rh ATTRIBUTE_UNUSED, |
118 | relation_trio) const |
119 | { |
120 | return false; |
121 | } |
122 | |
123 | bool |
124 | range_operator::fold_range (irange &r ATTRIBUTE_UNUSED, |
125 | tree type ATTRIBUTE_UNUSED, |
126 | const frange &lh ATTRIBUTE_UNUSED, |
127 | const frange &rh ATTRIBUTE_UNUSED, |
128 | relation_trio) const |
129 | { |
130 | return false; |
131 | } |
132 | |
133 | bool |
134 | range_operator::fold_range (frange &r ATTRIBUTE_UNUSED, |
135 | tree type ATTRIBUTE_UNUSED, |
136 | const irange &lh ATTRIBUTE_UNUSED, |
137 | const irange &rh ATTRIBUTE_UNUSED, |
138 | relation_trio) const |
139 | { |
140 | return false; |
141 | } |
142 | |
143 | bool |
144 | range_operator::op1_range (frange &r ATTRIBUTE_UNUSED, |
145 | tree type ATTRIBUTE_UNUSED, |
146 | const frange &lhs ATTRIBUTE_UNUSED, |
147 | const frange &op2 ATTRIBUTE_UNUSED, |
148 | relation_trio) const |
149 | { |
150 | return false; |
151 | } |
152 | |
153 | bool |
154 | range_operator::op1_range (frange &r ATTRIBUTE_UNUSED, |
155 | tree type ATTRIBUTE_UNUSED, |
156 | const irange &lhs ATTRIBUTE_UNUSED, |
157 | const frange &op2 ATTRIBUTE_UNUSED, |
158 | relation_trio) const |
159 | { |
160 | return false; |
161 | } |
162 | |
163 | bool |
164 | range_operator::op2_range (frange &r ATTRIBUTE_UNUSED, |
165 | tree type ATTRIBUTE_UNUSED, |
166 | const frange &lhs ATTRIBUTE_UNUSED, |
167 | const frange &op1 ATTRIBUTE_UNUSED, |
168 | relation_trio) const |
169 | { |
170 | return false; |
171 | } |
172 | |
173 | bool |
174 | range_operator::op2_range (frange &r ATTRIBUTE_UNUSED, |
175 | tree type ATTRIBUTE_UNUSED, |
176 | const irange &lhs ATTRIBUTE_UNUSED, |
177 | const frange &op1 ATTRIBUTE_UNUSED, |
178 | relation_trio) const |
179 | { |
180 | return false; |
181 | } |
182 | |
183 | relation_kind |
184 | range_operator::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED, |
185 | const frange &op1 ATTRIBUTE_UNUSED, |
186 | const frange &op2 ATTRIBUTE_UNUSED, |
187 | relation_kind) const |
188 | { |
189 | return VREL_VARYING; |
190 | } |
191 | |
192 | relation_kind |
193 | range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED, |
194 | const frange &op1 ATTRIBUTE_UNUSED, |
195 | const frange &op2 ATTRIBUTE_UNUSED, |
196 | relation_kind) const |
197 | { |
198 | return VREL_VARYING; |
199 | } |
200 | |
201 | relation_kind |
202 | range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, |
203 | const frange &op1 ATTRIBUTE_UNUSED, |
204 | const frange &op2 ATTRIBUTE_UNUSED, |
205 | relation_kind) const |
206 | { |
207 | return VREL_VARYING; |
208 | } |
209 | |
210 | relation_kind |
211 | range_operator::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED, |
212 | const frange &op1 ATTRIBUTE_UNUSED, |
213 | const frange &op2 ATTRIBUTE_UNUSED, |
214 | relation_kind) const |
215 | { |
216 | return VREL_VARYING; |
217 | } |
218 | |
219 | relation_kind |
220 | range_operator::op1_op2_relation (const irange &, |
221 | const frange &, |
222 | const frange &) const |
223 | { |
224 | return VREL_VARYING; |
225 | } |
226 | |
227 | |
228 | relation_kind |
229 | range_operator::op1_op2_relation (const frange &, |
230 | const frange &, |
231 | const frange &) const |
232 | { |
233 | return VREL_VARYING; |
234 | } |
235 | |
236 | // Return TRUE if OP1 and OP2 may be a NAN. |
237 | |
238 | static inline bool |
239 | maybe_isnan (const frange &op1, const frange &op2) |
240 | { |
241 | return op1.maybe_isnan () || op2.maybe_isnan (); |
242 | } |
243 | |
244 | // Floating point version of relop_early_resolve that takes NANs into |
245 | // account. |
246 | // |
247 | // For relation opcodes, first try to see if the supplied relation |
248 | // forces a true or false result, and return that. |
249 | // Then check for undefined operands. If none of this applies, |
250 | // return false. |
251 | // |
252 | // TRIO are the relations between operands as they appear in the IL. |
253 | // MY_REL is the relation that corresponds to the operator being |
254 | // folded. For example, when attempting to fold x_3 == y_5, MY_REL is |
255 | // VREL_EQ, and if the statement is dominated by x_3 > y_5, then |
256 | // TRIO.op1_op2() is VREL_GT. |
257 | |
258 | static inline bool |
259 | frelop_early_resolve (irange &r, tree type, |
260 | const frange &op1, const frange &op2, |
261 | relation_trio trio, relation_kind my_rel) |
262 | { |
263 | relation_kind rel = trio.op1_op2 (); |
264 | |
265 | // If known relation is a complete subset of this relation, always |
266 | // return true. However, avoid doing this when NAN is a possibility |
267 | // as we'll incorrectly fold conditions: |
268 | // |
269 | // if (x_3 >= y_5) |
270 | // ; |
271 | // else |
272 | // ;; With NANs the relation here is basically VREL_UNLT, so we |
273 | // ;; can't fold the following: |
274 | // if (x_3 < y_5) |
275 | if (!maybe_isnan (op1, op2) && relation_union (r1: rel, r2: my_rel) == my_rel) |
276 | { |
277 | r = range_true (type); |
278 | return true; |
279 | } |
280 | |
281 | // If known relation has no subset of this relation, always false. |
282 | if (relation_intersect (r1: rel, r2: my_rel) == VREL_UNDEFINED) |
283 | { |
284 | r = range_false (type); |
285 | return true; |
286 | } |
287 | |
288 | // If either operand is undefined, return VARYING. |
289 | if (empty_range_varying (r, type, op1, op2)) |
290 | return true; |
291 | |
292 | return false; |
293 | } |
294 | |
295 | // Set VALUE to its next real value, or INF if the operation overflows. |
296 | |
297 | void |
298 | frange_nextafter (enum machine_mode mode, |
299 | REAL_VALUE_TYPE &value, |
300 | const REAL_VALUE_TYPE &inf) |
301 | { |
302 | if (MODE_COMPOSITE_P (mode) |
303 | && (real_isdenormal (r: &value, mode) || real_iszero (&value))) |
304 | { |
305 | // IBM extended denormals only have DFmode precision. |
306 | REAL_VALUE_TYPE tmp, tmp2; |
307 | real_convert (&tmp2, DFmode, &value); |
308 | real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2, &inf); |
309 | real_convert (&value, mode, &tmp); |
310 | } |
311 | else |
312 | { |
313 | REAL_VALUE_TYPE tmp; |
314 | real_nextafter (&tmp, REAL_MODE_FORMAT (mode), &value, &inf); |
315 | value = tmp; |
316 | } |
317 | } |
318 | |
319 | // Like real_arithmetic, but round the result to INF if the operation |
320 | // produced inexact results. |
321 | // |
322 | // ?? There is still one problematic case, i387. With |
323 | // -fexcess-precision=standard we perform most SF/DFmode arithmetic in |
324 | // XFmode (long_double_type_node), so that case is OK. But without |
325 | // -mfpmath=sse, all the SF/DFmode computations are in XFmode |
326 | // precision (64-bit mantissa) and only occasionally rounded to |
327 | // SF/DFmode (when storing into memory from the 387 stack). Maybe |
328 | // this is ok as well though it is just occasionally more precise. ?? |
329 | |
330 | void |
331 | frange_arithmetic (enum tree_code code, tree type, |
332 | REAL_VALUE_TYPE &result, |
333 | const REAL_VALUE_TYPE &op1, |
334 | const REAL_VALUE_TYPE &op2, |
335 | const REAL_VALUE_TYPE &inf) |
336 | { |
337 | REAL_VALUE_TYPE value; |
338 | enum machine_mode mode = TYPE_MODE (type); |
339 | bool mode_composite = MODE_COMPOSITE_P (mode); |
340 | |
341 | bool inexact = real_arithmetic (&value, code, &op1, &op2); |
342 | real_convert (&result, mode, &value); |
343 | |
344 | /* When rounding towards negative infinity, x + (-x) and |
345 | x - x is -0 rather than +0 real_arithmetic computes. |
346 | So, when we are looking for lower bound (inf is negative), |
347 | use -0 rather than +0. */ |
348 | if (flag_rounding_math |
349 | && (code == PLUS_EXPR || code == MINUS_EXPR) |
350 | && !inexact |
351 | && real_iszero (&result) |
352 | && !real_isneg (&result) |
353 | && real_isneg (&inf)) |
354 | { |
355 | REAL_VALUE_TYPE op2a = op2; |
356 | if (code == PLUS_EXPR) |
357 | op2a.sign ^= 1; |
358 | if (real_isneg (&op1) == real_isneg (&op2a) && real_equal (&op1, &op2a)) |
359 | result.sign = 1; |
360 | } |
361 | |
362 | // Be extra careful if there may be discrepancies between the |
363 | // compile and runtime results. |
364 | bool round = false; |
365 | if (mode_composite) |
366 | round = true; |
367 | else |
368 | { |
369 | bool low = real_isneg (&inf); |
370 | round = (low ? !real_less (&result, &value) |
371 | : !real_less (&value, &result)); |
372 | if (real_isinf (&result, sign: !low) |
373 | && !real_isinf (&value) |
374 | && !flag_rounding_math) |
375 | { |
376 | // Use just [+INF, +INF] rather than [MAX, +INF] |
377 | // even if value is larger than MAX and rounds to |
378 | // nearest to +INF. Similarly just [-INF, -INF] |
379 | // rather than [-INF, +MAX] even if value is smaller |
380 | // than -MAX and rounds to nearest to -INF. |
381 | // Unless INEXACT is true, in that case we need some |
382 | // extra buffer. |
383 | if (!inexact) |
384 | round = false; |
385 | else |
386 | { |
387 | REAL_VALUE_TYPE tmp = result, tmp2; |
388 | frange_nextafter (mode, value&: tmp, inf); |
389 | // TMP is at this point the maximum representable |
390 | // number. |
391 | real_arithmetic (&tmp2, MINUS_EXPR, &value, &tmp); |
392 | if (real_isneg (&tmp2) != low |
393 | && (REAL_EXP (&tmp2) - REAL_EXP (&tmp) |
394 | >= 2 - REAL_MODE_FORMAT (mode)->p)) |
395 | round = false; |
396 | } |
397 | } |
398 | } |
399 | if (round && (inexact || !real_identical (&result, &value))) |
400 | { |
401 | if (mode_composite |
402 | && (real_isdenormal (r: &result, mode) || real_iszero (&result))) |
403 | { |
404 | // IBM extended denormals only have DFmode precision. |
405 | REAL_VALUE_TYPE tmp, tmp2; |
406 | real_convert (&tmp2, DFmode, &value); |
407 | real_nextafter (&tmp, REAL_MODE_FORMAT (DFmode), &tmp2, &inf); |
408 | real_convert (&result, mode, &tmp); |
409 | } |
410 | else |
411 | frange_nextafter (mode, value&: result, inf); |
412 | } |
413 | if (mode_composite) |
414 | switch (code) |
415 | { |
416 | case PLUS_EXPR: |
417 | case MINUS_EXPR: |
418 | // ibm-ldouble-format documents 1ulp for + and -. |
419 | frange_nextafter (mode, value&: result, inf); |
420 | break; |
421 | case MULT_EXPR: |
422 | // ibm-ldouble-format documents 2ulps for *. |
423 | frange_nextafter (mode, value&: result, inf); |
424 | frange_nextafter (mode, value&: result, inf); |
425 | break; |
426 | case RDIV_EXPR: |
427 | // ibm-ldouble-format documents 3ulps for /. |
428 | frange_nextafter (mode, value&: result, inf); |
429 | frange_nextafter (mode, value&: result, inf); |
430 | frange_nextafter (mode, value&: result, inf); |
431 | break; |
432 | default: |
433 | break; |
434 | } |
435 | } |
436 | |
437 | // Crop R to [-INF, MAX] where MAX is the maximum representable number |
438 | // for TYPE. |
439 | |
440 | static inline void |
441 | frange_drop_inf (frange &r, tree type) |
442 | { |
443 | REAL_VALUE_TYPE max = real_max_representable (type); |
444 | frange tmp (type, r.lower_bound (), max); |
445 | r.intersect (tmp); |
446 | } |
447 | |
448 | // Crop R to [MIN, +INF] where MIN is the minimum representable number |
449 | // for TYPE. |
450 | |
451 | static inline void |
452 | frange_drop_ninf (frange &r, tree type) |
453 | { |
454 | REAL_VALUE_TYPE min = real_min_representable (type); |
455 | frange tmp (type, min, r.upper_bound ()); |
456 | r.intersect (tmp); |
457 | } |
458 | |
459 | // Crop R to [MIN, MAX] where MAX is the maximum representable number |
460 | // for TYPE and MIN the minimum representable number for TYPE. |
461 | |
462 | static inline void |
463 | frange_drop_infs (frange &r, tree type) |
464 | { |
465 | REAL_VALUE_TYPE max = real_max_representable (type); |
466 | REAL_VALUE_TYPE min = real_min_representable (type); |
467 | frange tmp (type, min, max); |
468 | r.intersect (tmp); |
469 | } |
470 | |
471 | // If zero is in R, make sure both -0.0 and +0.0 are in the range. |
472 | |
473 | static inline void |
474 | frange_add_zeros (frange &r, tree type) |
475 | { |
476 | if (r.undefined_p () || r.known_isnan ()) |
477 | return; |
478 | |
479 | if (HONOR_SIGNED_ZEROS (type) |
480 | && (real_iszero (&r.lower_bound ()) || real_iszero (&r.upper_bound ()))) |
481 | { |
482 | frange zero; |
483 | zero.set_zero (type); |
484 | r.union_ (zero); |
485 | } |
486 | } |
487 | |
488 | // Build a range that is <= VAL and store it in R. Return TRUE if |
489 | // further changes may be needed for R, or FALSE if R is in its final |
490 | // form. |
491 | |
492 | static bool |
493 | build_le (frange &r, tree type, const frange &val) |
494 | { |
495 | gcc_checking_assert (!val.known_isnan ()); |
496 | |
497 | REAL_VALUE_TYPE ninf = frange_val_min (type); |
498 | r.set (type, ninf, val.upper_bound ()); |
499 | |
500 | // Add both zeros if there's the possibility of zero equality. |
501 | frange_add_zeros (r, type); |
502 | |
503 | return true; |
504 | } |
505 | |
506 | // Build a range that is < VAL and store it in R. Return TRUE if |
507 | // further changes may be needed for R, or FALSE if R is in its final |
508 | // form. |
509 | |
510 | static bool |
511 | build_lt (frange &r, tree type, const frange &val) |
512 | { |
513 | gcc_checking_assert (!val.known_isnan ()); |
514 | |
515 | // < -INF is outside the range. |
516 | if (real_isinf (&val.upper_bound (), sign: 1)) |
517 | { |
518 | if (HONOR_NANS (type)) |
519 | r.set_nan (type); |
520 | else |
521 | r.set_undefined (); |
522 | return false; |
523 | } |
524 | |
525 | REAL_VALUE_TYPE ninf = frange_val_min (type); |
526 | REAL_VALUE_TYPE prev = val.upper_bound (); |
527 | machine_mode mode = TYPE_MODE (type); |
528 | // Default to the conservatively correct closed ranges for |
529 | // MODE_COMPOSITE_P, otherwise use nextafter. Note that for |
530 | // !HONOR_INFINITIES, nextafter will yield -INF, but frange::set() |
531 | // will crop the range appropriately. |
532 | if (!MODE_COMPOSITE_P (mode)) |
533 | frange_nextafter (mode, value&: prev, inf: ninf); |
534 | r.set (type, ninf, prev); |
535 | return true; |
536 | } |
537 | |
538 | // Build a range that is >= VAL and store it in R. Return TRUE if |
539 | // further changes may be needed for R, or FALSE if R is in its final |
540 | // form. |
541 | |
542 | static bool |
543 | build_ge (frange &r, tree type, const frange &val) |
544 | { |
545 | gcc_checking_assert (!val.known_isnan ()); |
546 | |
547 | REAL_VALUE_TYPE inf = frange_val_max (type); |
548 | r.set (type, val.lower_bound (), inf); |
549 | |
550 | // Add both zeros if there's the possibility of zero equality. |
551 | frange_add_zeros (r, type); |
552 | |
553 | return true; |
554 | } |
555 | |
556 | // Build a range that is > VAL and store it in R. Return TRUE if |
557 | // further changes may be needed for R, or FALSE if R is in its final |
558 | // form. |
559 | |
560 | static bool |
561 | build_gt (frange &r, tree type, const frange &val) |
562 | { |
563 | gcc_checking_assert (!val.known_isnan ()); |
564 | |
565 | // > +INF is outside the range. |
566 | if (real_isinf (&val.lower_bound (), sign: 0)) |
567 | { |
568 | if (HONOR_NANS (type)) |
569 | r.set_nan (type); |
570 | else |
571 | r.set_undefined (); |
572 | return false; |
573 | } |
574 | |
575 | REAL_VALUE_TYPE inf = frange_val_max (type); |
576 | REAL_VALUE_TYPE next = val.lower_bound (); |
577 | machine_mode mode = TYPE_MODE (type); |
578 | // Default to the conservatively correct closed ranges for |
579 | // MODE_COMPOSITE_P, otherwise use nextafter. Note that for |
580 | // !HONOR_INFINITIES, nextafter will yield +INF, but frange::set() |
581 | // will crop the range appropriately. |
582 | if (!MODE_COMPOSITE_P (mode)) |
583 | frange_nextafter (mode, value&: next, inf); |
584 | r.set (type, next, inf); |
585 | return true; |
586 | } |
587 | |
588 | |
589 | bool |
590 | operator_identity::fold_range (frange &r, tree, const frange &op1, |
591 | const frange &, relation_trio) const |
592 | { |
593 | r = op1; |
594 | return true; |
595 | } |
596 | |
597 | bool |
598 | operator_identity::op1_range (frange &r, tree, const frange &lhs, |
599 | const frange &, relation_trio) const |
600 | { |
601 | r = lhs; |
602 | return true; |
603 | } |
604 | |
605 | bool |
606 | operator_cst::fold_range (frange &r, tree, const frange &op1, |
607 | const frange &, relation_trio) const |
608 | { |
609 | r = op1; |
610 | return true; |
611 | } |
612 | |
613 | bool |
614 | operator_equal::op2_range (frange &r, tree type, |
615 | const irange &lhs, const frange &op1, |
616 | relation_trio rel) const |
617 | { |
618 | return op1_range (r, type, lhs, op2: op1, rel.swap_op1_op2 ()); |
619 | } |
620 | |
621 | bool |
622 | operator_equal::fold_range (irange &r, tree type, |
623 | const frange &op1, const frange &op2, |
624 | relation_trio rel) const |
625 | { |
626 | if (frelop_early_resolve (r, type, op1, op2, trio: rel, my_rel: VREL_EQ)) |
627 | return true; |
628 | |
629 | if (op1.known_isnan () || op2.known_isnan ()) |
630 | r = range_false (type); |
631 | // We can be sure the values are always equal or not if both ranges |
632 | // consist of a single value, and then compare them. |
633 | else if (op1.singleton_p () && op2.singleton_p ()) |
634 | { |
635 | if (op1 == op2) |
636 | r = range_true (type); |
637 | // If one operand is -0.0 and other 0.0, they are still equal. |
638 | else if (real_iszero (&op1.lower_bound ()) |
639 | && real_iszero (&op2.lower_bound ())) |
640 | r = range_true (type); |
641 | else |
642 | r = range_false (type); |
643 | } |
644 | else if (real_iszero (&op1.lower_bound ()) |
645 | && real_iszero (&op1.upper_bound ()) |
646 | && real_iszero (&op2.lower_bound ()) |
647 | && real_iszero (&op2.upper_bound ()) |
648 | && !maybe_isnan (op1, op2)) |
649 | // [-0.0, 0.0] == [-0.0, 0.0] or similar. |
650 | r = range_true (type); |
651 | else |
652 | { |
653 | // If ranges do not intersect, we know the range is not equal, |
654 | // otherwise we don't know anything for sure. |
655 | frange tmp = op1; |
656 | tmp.intersect (op2); |
657 | if (tmp.undefined_p ()) |
658 | { |
659 | // If one range is [whatever, -0.0] and another |
660 | // [0.0, whatever2], we don't know anything either, |
661 | // because -0.0 == 0.0. |
662 | if ((real_iszero (&op1.upper_bound ()) |
663 | && real_iszero (&op2.lower_bound ())) |
664 | || (real_iszero (&op1.lower_bound ()) |
665 | && real_iszero (&op2.upper_bound ()))) |
666 | r = range_true_and_false (type); |
667 | else |
668 | r = range_false (type); |
669 | } |
670 | else |
671 | r = range_true_and_false (type); |
672 | } |
673 | return true; |
674 | } |
675 | |
676 | bool |
677 | operator_equal::op1_range (frange &r, tree type, |
678 | const irange &lhs, |
679 | const frange &op2, |
680 | relation_trio trio) const |
681 | { |
682 | relation_kind rel = trio.op1_op2 (); |
683 | switch (get_bool_state (r, lhs, val_type: type)) |
684 | { |
685 | case BRS_TRUE: |
686 | // The TRUE side of x == NAN is unreachable. |
687 | if (op2.known_isnan ()) |
688 | r.set_undefined (); |
689 | else |
690 | { |
691 | // If it's true, the result is the same as OP2. |
692 | r = op2; |
693 | // Add both zeros if there's the possibility of zero equality. |
694 | frange_add_zeros (r, type); |
695 | // The TRUE side of op1 == op2 implies op1 is !NAN. |
696 | r.clear_nan (); |
697 | } |
698 | break; |
699 | |
700 | case BRS_FALSE: |
701 | // The FALSE side of op1 == op1 implies op1 is a NAN. |
702 | if (rel == VREL_EQ) |
703 | r.set_nan (type); |
704 | // On the FALSE side of x == NAN, we know nothing about x. |
705 | else if (op2.known_isnan ()) |
706 | r.set_varying (type); |
707 | // If the result is false, the only time we know anything is |
708 | // if OP2 is a constant. |
709 | else if (op2.singleton_p () |
710 | || (!op2.maybe_isnan () && op2.zero_p ())) |
711 | { |
712 | REAL_VALUE_TYPE tmp = op2.lower_bound (); |
713 | r.set (type, tmp, tmp, VR_ANTI_RANGE); |
714 | } |
715 | else |
716 | r.set_varying (type); |
717 | break; |
718 | |
719 | default: |
720 | break; |
721 | } |
722 | return true; |
723 | } |
724 | |
725 | // Check if the LHS range indicates a relation between OP1 and OP2. |
726 | |
727 | relation_kind |
728 | operator_equal::op1_op2_relation (const irange &lhs, const frange &, |
729 | const frange &) const |
730 | { |
731 | if (lhs.undefined_p ()) |
732 | return VREL_UNDEFINED; |
733 | |
734 | // FALSE = op1 == op2 indicates NE_EXPR. |
735 | if (lhs.zero_p ()) |
736 | return VREL_NE; |
737 | |
738 | // TRUE = op1 == op2 indicates EQ_EXPR. |
739 | if (!contains_zero_p (r: lhs)) |
740 | return VREL_EQ; |
741 | return VREL_VARYING; |
742 | } |
743 | |
744 | bool |
745 | operator_not_equal::fold_range (irange &r, tree type, |
746 | const frange &op1, const frange &op2, |
747 | relation_trio trio) const |
748 | { |
749 | relation_kind rel = trio.op1_op2 (); |
750 | |
751 | // VREL_NE & NE_EXPR is always true, even with NANs. |
752 | if (rel == VREL_NE) |
753 | { |
754 | r = range_true (type); |
755 | return true; |
756 | } |
757 | if (rel == VREL_EQ && maybe_isnan (op1, op2)) |
758 | { |
759 | // Avoid frelop_early_resolve() below as it could fold to FALSE |
760 | // without regards to NANs. This would be incorrect if trying |
761 | // to fold x_5 != x_5 without prior knowledge of NANs. |
762 | } |
763 | else if (frelop_early_resolve (r, type, op1, op2, trio, my_rel: VREL_NE)) |
764 | return true; |
765 | |
766 | // x != NAN is always TRUE. |
767 | if (op1.known_isnan () || op2.known_isnan ()) |
768 | r = range_true (type); |
769 | // We can be sure the values are always equal or not if both ranges |
770 | // consist of a single value, and then compare them. |
771 | else if (op1.singleton_p () && op2.singleton_p ()) |
772 | { |
773 | if (op1 == op2) |
774 | r = range_false (type); |
775 | // If one operand is -0.0 and other 0.0, they are still equal. |
776 | else if (real_iszero (&op1.lower_bound ()) |
777 | && real_iszero (&op2.lower_bound ())) |
778 | r = range_false (type); |
779 | else |
780 | r = range_true (type); |
781 | } |
782 | else if (real_iszero (&op1.lower_bound ()) |
783 | && real_iszero (&op1.upper_bound ()) |
784 | && real_iszero (&op2.lower_bound ()) |
785 | && real_iszero (&op2.upper_bound ()) |
786 | && !maybe_isnan (op1, op2)) |
787 | // [-0.0, 0.0] != [-0.0, 0.0] or similar. |
788 | r = range_false (type); |
789 | else |
790 | { |
791 | // If ranges do not intersect, we know the range is not equal, |
792 | // otherwise we don't know anything for sure. |
793 | frange tmp = op1; |
794 | tmp.intersect (op2); |
795 | if (tmp.undefined_p ()) |
796 | { |
797 | // If one range is [whatever, -0.0] and another |
798 | // [0.0, whatever2], we don't know anything either, |
799 | // because -0.0 == 0.0. |
800 | if ((real_iszero (&op1.upper_bound ()) |
801 | && real_iszero (&op2.lower_bound ())) |
802 | || (real_iszero (&op1.lower_bound ()) |
803 | && real_iszero (&op2.upper_bound ()))) |
804 | r = range_true_and_false (type); |
805 | else |
806 | r = range_true (type); |
807 | } |
808 | else |
809 | r = range_true_and_false (type); |
810 | } |
811 | return true; |
812 | } |
813 | |
814 | bool |
815 | operator_not_equal::op1_range (frange &r, tree type, |
816 | const irange &lhs, |
817 | const frange &op2, |
818 | relation_trio trio) const |
819 | { |
820 | relation_kind rel = trio.op1_op2 (); |
821 | switch (get_bool_state (r, lhs, val_type: type)) |
822 | { |
823 | case BRS_TRUE: |
824 | // If the result is true, the only time we know anything is if |
825 | // OP2 is a constant. |
826 | if (op2.singleton_p ()) |
827 | { |
828 | // This is correct even if op1 is NAN, because the following |
829 | // range would be ~[tmp, tmp] with the NAN property set to |
830 | // maybe (VARYING). |
831 | REAL_VALUE_TYPE tmp = op2.lower_bound (); |
832 | r.set (type, tmp, tmp, VR_ANTI_RANGE); |
833 | } |
834 | // The TRUE side of op1 != op1 implies op1 is NAN. |
835 | else if (rel == VREL_EQ) |
836 | r.set_nan (type); |
837 | else |
838 | r.set_varying (type); |
839 | break; |
840 | |
841 | case BRS_FALSE: |
842 | // The FALSE side of x != NAN is impossible. |
843 | if (op2.known_isnan ()) |
844 | r.set_undefined (); |
845 | else |
846 | { |
847 | // If it's false, the result is the same as OP2. |
848 | r = op2; |
849 | // Add both zeros if there's the possibility of zero equality. |
850 | frange_add_zeros (r, type); |
851 | // The FALSE side of op1 != op2 implies op1 is !NAN. |
852 | r.clear_nan (); |
853 | } |
854 | break; |
855 | |
856 | default: |
857 | break; |
858 | } |
859 | return true; |
860 | } |
861 | |
862 | bool |
863 | operator_not_equal::op2_range (frange &r, tree type, |
864 | const irange &lhs, |
865 | const frange &op1, |
866 | relation_trio trio) const |
867 | { |
868 | return op1_range (r, type, lhs, op2: op1, trio); |
869 | } |
870 | |
871 | // Check if the LHS range indicates a relation between OP1 and OP2. |
872 | |
873 | relation_kind |
874 | operator_not_equal::op1_op2_relation (const irange &lhs, const frange &, |
875 | const frange &) const |
876 | { |
877 | if (lhs.undefined_p ()) |
878 | return VREL_UNDEFINED; |
879 | |
880 | // FALSE = op1 != op2 indicates EQ_EXPR. |
881 | if (lhs.zero_p ()) |
882 | return VREL_EQ; |
883 | |
884 | // TRUE = op1 != op2 indicates NE_EXPR. |
885 | if (!contains_zero_p (r: lhs)) |
886 | return VREL_NE; |
887 | return VREL_VARYING; |
888 | } |
889 | |
890 | bool |
891 | operator_lt::fold_range (irange &r, tree type, |
892 | const frange &op1, const frange &op2, |
893 | relation_trio trio) const |
894 | { |
895 | if (frelop_early_resolve (r, type, op1, op2, trio, my_rel: VREL_LT)) |
896 | return true; |
897 | |
898 | if (op1.known_isnan () |
899 | || op2.known_isnan () |
900 | || !real_less (&op1.lower_bound (), &op2.upper_bound ())) |
901 | r = range_false (type); |
902 | else if (!maybe_isnan (op1, op2) |
903 | && real_less (&op1.upper_bound (), &op2.lower_bound ())) |
904 | r = range_true (type); |
905 | else |
906 | r = range_true_and_false (type); |
907 | return true; |
908 | } |
909 | |
910 | bool |
911 | operator_lt::op1_range (frange &r, |
912 | tree type, |
913 | const irange &lhs, |
914 | const frange &op2, |
915 | relation_trio) const |
916 | { |
917 | switch (get_bool_state (r, lhs, val_type: type)) |
918 | { |
919 | case BRS_TRUE: |
920 | // The TRUE side of x < NAN is unreachable. |
921 | if (op2.known_isnan ()) |
922 | r.set_undefined (); |
923 | else if (op2.undefined_p ()) |
924 | return false; |
925 | else if (build_lt (r, type, val: op2)) |
926 | { |
927 | r.clear_nan (); |
928 | // x < y implies x is not +INF. |
929 | frange_drop_inf (r, type); |
930 | } |
931 | break; |
932 | |
933 | case BRS_FALSE: |
934 | // On the FALSE side of x < NAN, we know nothing about x. |
935 | if (op2.maybe_isnan ()) |
936 | r.set_varying (type); |
937 | else |
938 | build_ge (r, type, val: op2); |
939 | break; |
940 | |
941 | default: |
942 | break; |
943 | } |
944 | return true; |
945 | } |
946 | |
947 | bool |
948 | operator_lt::op2_range (frange &r, |
949 | tree type, |
950 | const irange &lhs, |
951 | const frange &op1, |
952 | relation_trio) const |
953 | { |
954 | switch (get_bool_state (r, lhs, val_type: type)) |
955 | { |
956 | case BRS_TRUE: |
957 | // The TRUE side of NAN < x is unreachable. |
958 | if (op1.known_isnan ()) |
959 | r.set_undefined (); |
960 | else if (op1.undefined_p ()) |
961 | return false; |
962 | else if (build_gt (r, type, val: op1)) |
963 | { |
964 | r.clear_nan (); |
965 | // x < y implies y is not -INF. |
966 | frange_drop_ninf (r, type); |
967 | } |
968 | break; |
969 | |
970 | case BRS_FALSE: |
971 | // On the FALSE side of NAN < x, we know nothing about x. |
972 | if (op1.maybe_isnan ()) |
973 | r.set_varying (type); |
974 | else |
975 | build_le (r, type, val: op1); |
976 | break; |
977 | |
978 | default: |
979 | break; |
980 | } |
981 | return true; |
982 | } |
983 | |
984 | |
985 | // Check if the LHS range indicates a relation between OP1 and OP2. |
986 | |
987 | relation_kind |
988 | operator_lt::op1_op2_relation (const irange &lhs, const frange &, |
989 | const frange &) const |
990 | { |
991 | if (lhs.undefined_p ()) |
992 | return VREL_UNDEFINED; |
993 | |
994 | // FALSE = op1 < op2 indicates GE_EXPR. |
995 | if (lhs.zero_p ()) |
996 | return VREL_GE; |
997 | |
998 | // TRUE = op1 < op2 indicates LT_EXPR. |
999 | if (!contains_zero_p (r: lhs)) |
1000 | return VREL_LT; |
1001 | return VREL_VARYING; |
1002 | } |
1003 | |
1004 | bool |
1005 | operator_le::fold_range (irange &r, tree type, |
1006 | const frange &op1, const frange &op2, |
1007 | relation_trio rel) const |
1008 | { |
1009 | if (frelop_early_resolve (r, type, op1, op2, trio: rel, my_rel: VREL_LE)) |
1010 | return true; |
1011 | |
1012 | if (op1.known_isnan () |
1013 | || op2.known_isnan () |
1014 | || !real_compare (LE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) |
1015 | r = range_false (type); |
1016 | else if (!maybe_isnan (op1, op2) |
1017 | && real_compare (LE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) |
1018 | r = range_true (type); |
1019 | else |
1020 | r = range_true_and_false (type); |
1021 | return true; |
1022 | } |
1023 | |
1024 | bool |
1025 | operator_le::op1_range (frange &r, |
1026 | tree type, |
1027 | const irange &lhs, |
1028 | const frange &op2, |
1029 | relation_trio) const |
1030 | { |
1031 | switch (get_bool_state (r, lhs, val_type: type)) |
1032 | { |
1033 | case BRS_TRUE: |
1034 | // The TRUE side of x <= NAN is unreachable. |
1035 | if (op2.known_isnan ()) |
1036 | r.set_undefined (); |
1037 | else if (op2.undefined_p ()) |
1038 | return false; |
1039 | else if (build_le (r, type, val: op2)) |
1040 | r.clear_nan (); |
1041 | break; |
1042 | |
1043 | case BRS_FALSE: |
1044 | // On the FALSE side of x <= NAN, we know nothing about x. |
1045 | if (op2.maybe_isnan ()) |
1046 | r.set_varying (type); |
1047 | else |
1048 | build_gt (r, type, val: op2); |
1049 | break; |
1050 | |
1051 | default: |
1052 | break; |
1053 | } |
1054 | return true; |
1055 | } |
1056 | |
1057 | bool |
1058 | operator_le::op2_range (frange &r, |
1059 | tree type, |
1060 | const irange &lhs, |
1061 | const frange &op1, |
1062 | relation_trio) const |
1063 | { |
1064 | switch (get_bool_state (r, lhs, val_type: type)) |
1065 | { |
1066 | case BRS_TRUE: |
1067 | // The TRUE side of NAN <= x is unreachable. |
1068 | if (op1.known_isnan ()) |
1069 | r.set_undefined (); |
1070 | else if (op1.undefined_p ()) |
1071 | return false; |
1072 | else if (build_ge (r, type, val: op1)) |
1073 | r.clear_nan (); |
1074 | break; |
1075 | |
1076 | case BRS_FALSE: |
1077 | // On the FALSE side of NAN <= x, we know nothing about x. |
1078 | if (op1.maybe_isnan ()) |
1079 | r.set_varying (type); |
1080 | else if (op1.undefined_p ()) |
1081 | return false; |
1082 | else |
1083 | build_lt (r, type, val: op1); |
1084 | break; |
1085 | |
1086 | default: |
1087 | break; |
1088 | } |
1089 | return true; |
1090 | } |
1091 | |
1092 | // Check if the LHS range indicates a relation between OP1 and OP2. |
1093 | |
1094 | relation_kind |
1095 | operator_le::op1_op2_relation (const irange &lhs, const frange &, |
1096 | const frange &) const |
1097 | { |
1098 | if (lhs.undefined_p ()) |
1099 | return VREL_UNDEFINED; |
1100 | |
1101 | // FALSE = op1 <= op2 indicates GT_EXPR. |
1102 | if (lhs.zero_p ()) |
1103 | return VREL_GT; |
1104 | |
1105 | // TRUE = op1 <= op2 indicates LE_EXPR. |
1106 | if (!contains_zero_p (r: lhs)) |
1107 | return VREL_LE; |
1108 | return VREL_VARYING; |
1109 | } |
1110 | |
1111 | bool |
1112 | operator_gt::fold_range (irange &r, tree type, |
1113 | const frange &op1, const frange &op2, |
1114 | relation_trio trio) const |
1115 | { |
1116 | if (frelop_early_resolve (r, type, op1, op2, trio, my_rel: VREL_GT)) |
1117 | return true; |
1118 | |
1119 | if (op1.known_isnan () |
1120 | || op2.known_isnan () |
1121 | || !real_compare (GT_EXPR, &op1.upper_bound (), &op2.lower_bound ())) |
1122 | r = range_false (type); |
1123 | else if (!maybe_isnan (op1, op2) |
1124 | && real_compare (GT_EXPR, &op1.lower_bound (), &op2.upper_bound ())) |
1125 | r = range_true (type); |
1126 | else |
1127 | r = range_true_and_false (type); |
1128 | return true; |
1129 | } |
1130 | |
1131 | bool |
1132 | operator_gt::op1_range (frange &r, |
1133 | tree type, |
1134 | const irange &lhs, |
1135 | const frange &op2, |
1136 | relation_trio) const |
1137 | { |
1138 | switch (get_bool_state (r, lhs, val_type: type)) |
1139 | { |
1140 | case BRS_TRUE: |
1141 | // The TRUE side of x > NAN is unreachable. |
1142 | if (op2.known_isnan ()) |
1143 | r.set_undefined (); |
1144 | else if (op2.undefined_p ()) |
1145 | return false; |
1146 | else if (build_gt (r, type, val: op2)) |
1147 | { |
1148 | r.clear_nan (); |
1149 | // x > y implies x is not -INF. |
1150 | frange_drop_ninf (r, type); |
1151 | } |
1152 | break; |
1153 | |
1154 | case BRS_FALSE: |
1155 | // On the FALSE side of x > NAN, we know nothing about x. |
1156 | if (op2.maybe_isnan ()) |
1157 | r.set_varying (type); |
1158 | else if (op2.undefined_p ()) |
1159 | return false; |
1160 | else |
1161 | build_le (r, type, val: op2); |
1162 | break; |
1163 | |
1164 | default: |
1165 | break; |
1166 | } |
1167 | return true; |
1168 | } |
1169 | |
1170 | bool |
1171 | operator_gt::op2_range (frange &r, |
1172 | tree type, |
1173 | const irange &lhs, |
1174 | const frange &op1, |
1175 | relation_trio) const |
1176 | { |
1177 | switch (get_bool_state (r, lhs, val_type: type)) |
1178 | { |
1179 | case BRS_TRUE: |
1180 | // The TRUE side of NAN > x is unreachable. |
1181 | if (op1.known_isnan ()) |
1182 | r.set_undefined (); |
1183 | else if (op1.undefined_p ()) |
1184 | return false; |
1185 | else if (build_lt (r, type, val: op1)) |
1186 | { |
1187 | r.clear_nan (); |
1188 | // x > y implies y is not +INF. |
1189 | frange_drop_inf (r, type); |
1190 | } |
1191 | break; |
1192 | |
1193 | case BRS_FALSE: |
1194 | // On The FALSE side of NAN > x, we know nothing about x. |
1195 | if (op1.maybe_isnan ()) |
1196 | r.set_varying (type); |
1197 | else if (op1.undefined_p ()) |
1198 | return false; |
1199 | else |
1200 | build_ge (r, type, val: op1); |
1201 | break; |
1202 | |
1203 | default: |
1204 | break; |
1205 | } |
1206 | return true; |
1207 | } |
1208 | |
1209 | // Check if the LHS range indicates a relation between OP1 and OP2. |
1210 | |
1211 | relation_kind |
1212 | operator_gt::op1_op2_relation (const irange &lhs, const frange &, |
1213 | const frange &) const |
1214 | { |
1215 | if (lhs.undefined_p ()) |
1216 | return VREL_UNDEFINED; |
1217 | |
1218 | // FALSE = op1 > op2 indicates LE_EXPR. |
1219 | if (lhs.zero_p ()) |
1220 | return VREL_LE; |
1221 | |
1222 | // TRUE = op1 > op2 indicates GT_EXPR. |
1223 | if (!contains_zero_p (r: lhs)) |
1224 | return VREL_GT; |
1225 | return VREL_VARYING; |
1226 | } |
1227 | |
1228 | bool |
1229 | operator_ge::fold_range (irange &r, tree type, |
1230 | const frange &op1, const frange &op2, |
1231 | relation_trio rel) const |
1232 | { |
1233 | if (frelop_early_resolve (r, type, op1, op2, trio: rel, my_rel: VREL_GE)) |
1234 | return true; |
1235 | |
1236 | if (op1.known_isnan () |
1237 | || op2.known_isnan () |
1238 | || !real_compare (GE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) |
1239 | r = range_false (type); |
1240 | else if (!maybe_isnan (op1, op2) |
1241 | && real_compare (GE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) |
1242 | r = range_true (type); |
1243 | else |
1244 | r = range_true_and_false (type); |
1245 | return true; |
1246 | } |
1247 | |
1248 | bool |
1249 | operator_ge::op1_range (frange &r, |
1250 | tree type, |
1251 | const irange &lhs, |
1252 | const frange &op2, |
1253 | relation_trio) const |
1254 | { |
1255 | switch (get_bool_state (r, lhs, val_type: type)) |
1256 | { |
1257 | case BRS_TRUE: |
1258 | // The TRUE side of x >= NAN is unreachable. |
1259 | if (op2.known_isnan ()) |
1260 | r.set_undefined (); |
1261 | else if (op2.undefined_p ()) |
1262 | return false; |
1263 | else if (build_ge (r, type, val: op2)) |
1264 | r.clear_nan (); |
1265 | break; |
1266 | |
1267 | case BRS_FALSE: |
1268 | // On the FALSE side of x >= NAN, we know nothing about x. |
1269 | if (op2.maybe_isnan ()) |
1270 | r.set_varying (type); |
1271 | else if (op2.undefined_p ()) |
1272 | return false; |
1273 | else |
1274 | build_lt (r, type, val: op2); |
1275 | break; |
1276 | |
1277 | default: |
1278 | break; |
1279 | } |
1280 | return true; |
1281 | } |
1282 | |
1283 | bool |
1284 | operator_ge::op2_range (frange &r, tree type, |
1285 | const irange &lhs, |
1286 | const frange &op1, |
1287 | relation_trio) const |
1288 | { |
1289 | switch (get_bool_state (r, lhs, val_type: type)) |
1290 | { |
1291 | case BRS_TRUE: |
1292 | // The TRUE side of NAN >= x is unreachable. |
1293 | if (op1.known_isnan ()) |
1294 | r.set_undefined (); |
1295 | else if (op1.undefined_p ()) |
1296 | return false; |
1297 | else if (build_le (r, type, val: op1)) |
1298 | r.clear_nan (); |
1299 | break; |
1300 | |
1301 | case BRS_FALSE: |
1302 | // On the FALSE side of NAN >= x, we know nothing about x. |
1303 | if (op1.maybe_isnan ()) |
1304 | r.set_varying (type); |
1305 | else if (op1.undefined_p ()) |
1306 | return false; |
1307 | else |
1308 | build_gt (r, type, val: op1); |
1309 | break; |
1310 | |
1311 | default: |
1312 | break; |
1313 | } |
1314 | return true; |
1315 | } |
1316 | |
1317 | // Check if the LHS range indicates a relation between OP1 and OP2. |
1318 | |
1319 | relation_kind |
1320 | operator_ge::op1_op2_relation (const irange &lhs, const frange &, |
1321 | const frange &) const |
1322 | { |
1323 | if (lhs.undefined_p ()) |
1324 | return VREL_UNDEFINED; |
1325 | |
1326 | // FALSE = op1 >= op2 indicates LT_EXPR. |
1327 | if (lhs.zero_p ()) |
1328 | return VREL_LT; |
1329 | |
1330 | // TRUE = op1 >= op2 indicates GE_EXPR. |
1331 | if (!contains_zero_p (r: lhs)) |
1332 | return VREL_GE; |
1333 | return VREL_VARYING; |
1334 | } |
1335 | |
1336 | // UNORDERED_EXPR comparison. |
1337 | |
1338 | class foperator_unordered : public range_operator |
1339 | { |
1340 | using range_operator::fold_range; |
1341 | using range_operator::op1_range; |
1342 | using range_operator::op2_range; |
1343 | public: |
1344 | bool fold_range (irange &r, tree type, |
1345 | const frange &op1, const frange &op2, |
1346 | relation_trio = TRIO_VARYING) const final override; |
1347 | bool op1_range (frange &r, tree type, |
1348 | const irange &lhs, const frange &op2, |
1349 | relation_trio = TRIO_VARYING) const final override; |
1350 | bool op2_range (frange &r, tree type, |
1351 | const irange &lhs, const frange &op1, |
1352 | relation_trio rel = TRIO_VARYING) const final override |
1353 | { |
1354 | return op1_range (r, type, lhs, op2: op1, rel.swap_op1_op2 ()); |
1355 | } |
1356 | } fop_unordered; |
1357 | |
1358 | bool |
1359 | foperator_unordered::fold_range (irange &r, tree type, |
1360 | const frange &op1, const frange &op2, |
1361 | relation_trio) const |
1362 | { |
1363 | // UNORDERED is TRUE if either operand is a NAN. |
1364 | if (op1.known_isnan () || op2.known_isnan ()) |
1365 | r = range_true (type); |
1366 | // UNORDERED is FALSE if neither operand is a NAN. |
1367 | else if (!op1.maybe_isnan () && !op2.maybe_isnan ()) |
1368 | r = range_false (type); |
1369 | else |
1370 | r = range_true_and_false (type); |
1371 | return true; |
1372 | } |
1373 | |
1374 | bool |
1375 | foperator_unordered::op1_range (frange &r, tree type, |
1376 | const irange &lhs, |
1377 | const frange &op2, |
1378 | relation_trio trio) const |
1379 | { |
1380 | relation_kind rel = trio.op1_op2 (); |
1381 | switch (get_bool_state (r, lhs, val_type: type)) |
1382 | { |
1383 | case BRS_TRUE: |
1384 | // Since at least one operand must be NAN, if one of them is |
1385 | // not, the other must be. |
1386 | if (rel == VREL_EQ || !op2.maybe_isnan ()) |
1387 | r.set_nan (type); |
1388 | else |
1389 | r.set_varying (type); |
1390 | break; |
1391 | |
1392 | case BRS_FALSE: |
1393 | // A false UNORDERED means both operands are !NAN, so it's |
1394 | // impossible for op2 to be a NAN. |
1395 | if (op2.known_isnan ()) |
1396 | r.set_undefined (); |
1397 | else |
1398 | { |
1399 | r.set_varying (type); |
1400 | r.clear_nan (); |
1401 | } |
1402 | break; |
1403 | |
1404 | default: |
1405 | break; |
1406 | } |
1407 | return true; |
1408 | } |
1409 | |
1410 | // ORDERED_EXPR comparison. |
1411 | |
1412 | class foperator_ordered : public range_operator |
1413 | { |
1414 | using range_operator::fold_range; |
1415 | using range_operator::op1_range; |
1416 | using range_operator::op2_range; |
1417 | public: |
1418 | bool fold_range (irange &r, tree type, |
1419 | const frange &op1, const frange &op2, |
1420 | relation_trio = TRIO_VARYING) const final override; |
1421 | bool op1_range (frange &r, tree type, |
1422 | const irange &lhs, const frange &op2, |
1423 | relation_trio = TRIO_VARYING) const final override; |
1424 | bool op2_range (frange &r, tree type, |
1425 | const irange &lhs, const frange &op1, |
1426 | relation_trio rel = TRIO_VARYING) const final override |
1427 | { |
1428 | return op1_range (r, type, lhs, op2: op1, rel.swap_op1_op2 ()); |
1429 | } |
1430 | } fop_ordered; |
1431 | |
1432 | bool |
1433 | foperator_ordered::fold_range (irange &r, tree type, |
1434 | const frange &op1, const frange &op2, |
1435 | relation_trio) const |
1436 | { |
1437 | if (op1.known_isnan () || op2.known_isnan ()) |
1438 | r = range_false (type); |
1439 | else if (!op1.maybe_isnan () && !op2.maybe_isnan ()) |
1440 | r = range_true (type); |
1441 | else |
1442 | r = range_true_and_false (type); |
1443 | return true; |
1444 | } |
1445 | |
1446 | bool |
1447 | foperator_ordered::op1_range (frange &r, tree type, |
1448 | const irange &lhs, |
1449 | const frange &op2, |
1450 | relation_trio trio) const |
1451 | { |
1452 | relation_kind rel = trio.op1_op2 (); |
1453 | switch (get_bool_state (r, lhs, val_type: type)) |
1454 | { |
1455 | case BRS_TRUE: |
1456 | // The TRUE side of ORDERED means both operands are !NAN, so |
1457 | // it's impossible for op2 to be a NAN. |
1458 | if (op2.known_isnan ()) |
1459 | r.set_undefined (); |
1460 | else |
1461 | { |
1462 | r.set_varying (type); |
1463 | r.clear_nan (); |
1464 | } |
1465 | break; |
1466 | |
1467 | case BRS_FALSE: |
1468 | // The FALSE side of op1 ORDERED op1 implies op1 is NAN. |
1469 | if (rel == VREL_EQ) |
1470 | r.set_nan (type); |
1471 | else |
1472 | r.set_varying (type); |
1473 | break; |
1474 | |
1475 | default: |
1476 | break; |
1477 | } |
1478 | return true; |
1479 | } |
1480 | |
1481 | bool |
1482 | operator_negate::fold_range (frange &r, tree type, |
1483 | const frange &op1, const frange &op2, |
1484 | relation_trio) const |
1485 | { |
1486 | if (empty_range_varying (r, type, op1, op2)) |
1487 | return true; |
1488 | if (op1.known_isnan ()) |
1489 | { |
1490 | bool sign; |
1491 | if (op1.nan_signbit_p (signbit&: sign)) |
1492 | r.set_nan (type, sign: !sign); |
1493 | else |
1494 | r.set_nan (type); |
1495 | return true; |
1496 | } |
1497 | |
1498 | REAL_VALUE_TYPE lh_lb = op1.lower_bound (); |
1499 | REAL_VALUE_TYPE lh_ub = op1.upper_bound (); |
1500 | lh_lb = real_value_negate (&lh_lb); |
1501 | lh_ub = real_value_negate (&lh_ub); |
1502 | r.set (type, lh_ub, lh_lb); |
1503 | if (op1.maybe_isnan ()) |
1504 | { |
1505 | bool sign; |
1506 | if (op1.nan_signbit_p (signbit&: sign)) |
1507 | r.update_nan (sign: !sign); |
1508 | else |
1509 | r.update_nan (); |
1510 | } |
1511 | else |
1512 | r.clear_nan (); |
1513 | return true; |
1514 | } |
1515 | |
1516 | bool |
1517 | operator_negate::op1_range (frange &r, tree type, |
1518 | const frange &lhs, const frange &op2, |
1519 | relation_trio rel) const |
1520 | { |
1521 | return fold_range (r, type, op1: lhs, op2, rel); |
1522 | } |
1523 | |
1524 | bool |
1525 | operator_abs::fold_range (frange &r, tree type, |
1526 | const frange &op1, const frange &op2, |
1527 | relation_trio) const |
1528 | { |
1529 | if (empty_range_varying (r, type, op1, op2)) |
1530 | return true; |
1531 | if (op1.known_isnan ()) |
1532 | { |
1533 | r.set_nan (type, /*sign=*/false); |
1534 | return true; |
1535 | } |
1536 | |
1537 | const REAL_VALUE_TYPE lh_lb = op1.lower_bound (); |
1538 | const REAL_VALUE_TYPE lh_ub = op1.upper_bound (); |
1539 | // Handle the easy case where everything is positive. |
1540 | if (real_compare (GE_EXPR, &lh_lb, &dconst0) |
1541 | && !real_iszero (&lh_lb, /*sign=*/true) |
1542 | && !op1.maybe_isnan (/*sign=*/true)) |
1543 | { |
1544 | r = op1; |
1545 | return true; |
1546 | } |
1547 | |
1548 | REAL_VALUE_TYPE min = real_value_abs (&lh_lb); |
1549 | REAL_VALUE_TYPE max = real_value_abs (&lh_ub); |
1550 | // If the range contains zero then we know that the minimum value in the |
1551 | // range will be zero. |
1552 | if (real_compare (LE_EXPR, &lh_lb, &dconst0) |
1553 | && real_compare (GE_EXPR, &lh_ub, &dconst0)) |
1554 | { |
1555 | if (real_compare (GT_EXPR, &min, &max)) |
1556 | max = min; |
1557 | min = dconst0; |
1558 | } |
1559 | else |
1560 | { |
1561 | // If the range was reversed, swap MIN and MAX. |
1562 | if (real_compare (GT_EXPR, &min, &max)) |
1563 | std::swap (a&: min, b&: max); |
1564 | } |
1565 | |
1566 | r.set (type, min, max); |
1567 | if (op1.maybe_isnan ()) |
1568 | r.update_nan (/*sign=*/false); |
1569 | else |
1570 | r.clear_nan (); |
1571 | return true; |
1572 | } |
1573 | |
1574 | bool |
1575 | operator_abs::op1_range (frange &r, tree type, |
1576 | const frange &lhs, const frange &op2, |
1577 | relation_trio) const |
1578 | { |
1579 | if (empty_range_varying (r, type, op1: lhs, op2)) |
1580 | return true; |
1581 | if (lhs.known_isnan ()) |
1582 | { |
1583 | r.set_nan (type); |
1584 | return true; |
1585 | } |
1586 | |
1587 | // Start with the positives because negatives are an impossible result. |
1588 | frange positives (type, dconst0, frange_val_max (type)); |
1589 | positives.update_nan (/*sign=*/false); |
1590 | positives.intersect (lhs); |
1591 | r = positives; |
1592 | // Add -NAN if relevant. |
1593 | if (r.maybe_isnan ()) |
1594 | { |
1595 | frange neg_nan; |
1596 | neg_nan.set_nan (type, sign: true); |
1597 | r.union_ (neg_nan); |
1598 | } |
1599 | if (r.known_isnan () || r.undefined_p ()) |
1600 | return true; |
1601 | // Then add the negative of each pair: |
1602 | // ABS(op1) = [5,20] would yield op1 => [-20,-5][5,20]. |
1603 | frange negatives (type, real_value_negate (&positives.upper_bound ()), |
1604 | real_value_negate (&positives.lower_bound ())); |
1605 | negatives.clear_nan (); |
1606 | r.union_ (negatives); |
1607 | return true; |
1608 | } |
1609 | |
1610 | class foperator_unordered_lt : public range_operator |
1611 | { |
1612 | using range_operator::fold_range; |
1613 | using range_operator::op1_range; |
1614 | using range_operator::op2_range; |
1615 | public: |
1616 | bool fold_range (irange &r, tree type, |
1617 | const frange &op1, const frange &op2, |
1618 | relation_trio trio = TRIO_VARYING) const final override |
1619 | { |
1620 | if (op1.known_isnan () || op2.known_isnan ()) |
1621 | { |
1622 | r = range_true (type); |
1623 | return true; |
1624 | } |
1625 | frange op1_no_nan = op1; |
1626 | frange op2_no_nan = op2; |
1627 | if (op1.maybe_isnan ()) |
1628 | op1_no_nan.clear_nan (); |
1629 | if (op2.maybe_isnan ()) |
1630 | op2_no_nan.clear_nan (); |
1631 | if (!range_op_handler (LT_EXPR).fold_range (r, type, lh: op1_no_nan, |
1632 | rh: op2_no_nan, trio)) |
1633 | return false; |
1634 | // The result is the same as the ordered version when the |
1635 | // comparison is true or when the operands cannot be NANs. |
1636 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
1637 | return true; |
1638 | else |
1639 | { |
1640 | r = range_true_and_false (type); |
1641 | return true; |
1642 | } |
1643 | } |
1644 | bool op1_range (frange &r, tree type, |
1645 | const irange &lhs, |
1646 | const frange &op2, |
1647 | relation_trio trio) const final override; |
1648 | bool op2_range (frange &r, tree type, |
1649 | const irange &lhs, |
1650 | const frange &op1, |
1651 | relation_trio trio) const final override; |
1652 | } fop_unordered_lt; |
1653 | |
1654 | bool |
1655 | foperator_unordered_lt::op1_range (frange &r, tree type, |
1656 | const irange &lhs, |
1657 | const frange &op2, |
1658 | relation_trio) const |
1659 | { |
1660 | switch (get_bool_state (r, lhs, val_type: type)) |
1661 | { |
1662 | case BRS_TRUE: |
1663 | if (op2.maybe_isnan ()) |
1664 | r.set_varying (type); |
1665 | else if (op2.undefined_p ()) |
1666 | return false; |
1667 | else |
1668 | build_lt (r, type, val: op2); |
1669 | break; |
1670 | |
1671 | case BRS_FALSE: |
1672 | // A false UNORDERED_LT means both operands are !NAN, so it's |
1673 | // impossible for op2 to be a NAN. |
1674 | if (op2.known_isnan ()) |
1675 | r.set_undefined (); |
1676 | else if (op2.undefined_p ()) |
1677 | return false; |
1678 | else if (build_ge (r, type, val: op2)) |
1679 | r.clear_nan (); |
1680 | break; |
1681 | |
1682 | default: |
1683 | break; |
1684 | } |
1685 | return true; |
1686 | } |
1687 | |
1688 | bool |
1689 | foperator_unordered_lt::op2_range (frange &r, tree type, |
1690 | const irange &lhs, |
1691 | const frange &op1, |
1692 | relation_trio) const |
1693 | { |
1694 | switch (get_bool_state (r, lhs, val_type: type)) |
1695 | { |
1696 | case BRS_TRUE: |
1697 | if (op1.maybe_isnan ()) |
1698 | r.set_varying (type); |
1699 | else if (op1.undefined_p ()) |
1700 | return false; |
1701 | else |
1702 | build_gt (r, type, val: op1); |
1703 | break; |
1704 | |
1705 | case BRS_FALSE: |
1706 | // A false UNORDERED_LT means both operands are !NAN, so it's |
1707 | // impossible for op1 to be a NAN. |
1708 | if (op1.known_isnan ()) |
1709 | r.set_undefined (); |
1710 | else if (op1.undefined_p ()) |
1711 | return false; |
1712 | else if (build_le (r, type, val: op1)) |
1713 | r.clear_nan (); |
1714 | break; |
1715 | |
1716 | default: |
1717 | break; |
1718 | } |
1719 | return true; |
1720 | } |
1721 | |
1722 | class foperator_unordered_le : public range_operator |
1723 | { |
1724 | using range_operator::fold_range; |
1725 | using range_operator::op1_range; |
1726 | using range_operator::op2_range; |
1727 | public: |
1728 | bool fold_range (irange &r, tree type, |
1729 | const frange &op1, const frange &op2, |
1730 | relation_trio trio = TRIO_VARYING) const final override |
1731 | { |
1732 | if (op1.known_isnan () || op2.known_isnan ()) |
1733 | { |
1734 | r = range_true (type); |
1735 | return true; |
1736 | } |
1737 | frange op1_no_nan = op1; |
1738 | frange op2_no_nan = op2; |
1739 | if (op1.maybe_isnan ()) |
1740 | op1_no_nan.clear_nan (); |
1741 | if (op2.maybe_isnan ()) |
1742 | op2_no_nan.clear_nan (); |
1743 | if (!range_op_handler (LE_EXPR).fold_range (r, type, lh: op1_no_nan, |
1744 | rh: op2_no_nan, trio)) |
1745 | return false; |
1746 | // The result is the same as the ordered version when the |
1747 | // comparison is true or when the operands cannot be NANs. |
1748 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
1749 | return true; |
1750 | else |
1751 | { |
1752 | r = range_true_and_false (type); |
1753 | return true; |
1754 | } |
1755 | } |
1756 | bool op1_range (frange &r, tree type, |
1757 | const irange &lhs, const frange &op2, |
1758 | relation_trio = TRIO_VARYING) const final override; |
1759 | bool op2_range (frange &r, tree type, |
1760 | const irange &lhs, const frange &op1, |
1761 | relation_trio = TRIO_VARYING) const final override; |
1762 | } fop_unordered_le; |
1763 | |
1764 | bool |
1765 | foperator_unordered_le::op1_range (frange &r, tree type, |
1766 | const irange &lhs, const frange &op2, |
1767 | relation_trio) const |
1768 | { |
1769 | switch (get_bool_state (r, lhs, val_type: type)) |
1770 | { |
1771 | case BRS_TRUE: |
1772 | if (op2.maybe_isnan ()) |
1773 | r.set_varying (type); |
1774 | else if (op2.undefined_p ()) |
1775 | return false; |
1776 | else |
1777 | build_le (r, type, val: op2); |
1778 | break; |
1779 | |
1780 | case BRS_FALSE: |
1781 | // A false UNORDERED_LE means both operands are !NAN, so it's |
1782 | // impossible for op2 to be a NAN. |
1783 | if (op2.known_isnan ()) |
1784 | r.set_undefined (); |
1785 | else if (build_gt (r, type, val: op2)) |
1786 | r.clear_nan (); |
1787 | break; |
1788 | |
1789 | default: |
1790 | break; |
1791 | } |
1792 | return true; |
1793 | } |
1794 | |
1795 | bool |
1796 | foperator_unordered_le::op2_range (frange &r, |
1797 | tree type, |
1798 | const irange &lhs, |
1799 | const frange &op1, |
1800 | relation_trio) const |
1801 | { |
1802 | switch (get_bool_state (r, lhs, val_type: type)) |
1803 | { |
1804 | case BRS_TRUE: |
1805 | if (op1.maybe_isnan ()) |
1806 | r.set_varying (type); |
1807 | else if (op1.undefined_p ()) |
1808 | return false; |
1809 | else |
1810 | build_ge (r, type, val: op1); |
1811 | break; |
1812 | |
1813 | case BRS_FALSE: |
1814 | // A false UNORDERED_LE means both operands are !NAN, so it's |
1815 | // impossible for op1 to be a NAN. |
1816 | if (op1.known_isnan ()) |
1817 | r.set_undefined (); |
1818 | else if (op1.undefined_p ()) |
1819 | return false; |
1820 | else if (build_lt (r, type, val: op1)) |
1821 | r.clear_nan (); |
1822 | break; |
1823 | |
1824 | default: |
1825 | break; |
1826 | } |
1827 | return true; |
1828 | } |
1829 | |
1830 | class foperator_unordered_gt : public range_operator |
1831 | { |
1832 | using range_operator::fold_range; |
1833 | using range_operator::op1_range; |
1834 | using range_operator::op2_range; |
1835 | public: |
1836 | bool fold_range (irange &r, tree type, |
1837 | const frange &op1, const frange &op2, |
1838 | relation_trio trio = TRIO_VARYING) const final override |
1839 | { |
1840 | if (op1.known_isnan () || op2.known_isnan ()) |
1841 | { |
1842 | r = range_true (type); |
1843 | return true; |
1844 | } |
1845 | frange op1_no_nan = op1; |
1846 | frange op2_no_nan = op2; |
1847 | if (op1.maybe_isnan ()) |
1848 | op1_no_nan.clear_nan (); |
1849 | if (op2.maybe_isnan ()) |
1850 | op2_no_nan.clear_nan (); |
1851 | if (!range_op_handler (GT_EXPR).fold_range (r, type, lh: op1_no_nan, |
1852 | rh: op2_no_nan, trio)) |
1853 | return false; |
1854 | // The result is the same as the ordered version when the |
1855 | // comparison is true or when the operands cannot be NANs. |
1856 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
1857 | return true; |
1858 | else |
1859 | { |
1860 | r = range_true_and_false (type); |
1861 | return true; |
1862 | } |
1863 | } |
1864 | bool op1_range (frange &r, tree type, |
1865 | const irange &lhs, const frange &op2, |
1866 | relation_trio = TRIO_VARYING) const final override; |
1867 | bool op2_range (frange &r, tree type, |
1868 | const irange &lhs, const frange &op1, |
1869 | relation_trio = TRIO_VARYING) const final override; |
1870 | } fop_unordered_gt; |
1871 | |
1872 | bool |
1873 | foperator_unordered_gt::op1_range (frange &r, |
1874 | tree type, |
1875 | const irange &lhs, |
1876 | const frange &op2, |
1877 | relation_trio) const |
1878 | { |
1879 | switch (get_bool_state (r, lhs, val_type: type)) |
1880 | { |
1881 | case BRS_TRUE: |
1882 | if (op2.maybe_isnan ()) |
1883 | r.set_varying (type); |
1884 | else if (op2.undefined_p ()) |
1885 | return false; |
1886 | else |
1887 | build_gt (r, type, val: op2); |
1888 | break; |
1889 | |
1890 | case BRS_FALSE: |
1891 | // A false UNORDERED_GT means both operands are !NAN, so it's |
1892 | // impossible for op2 to be a NAN. |
1893 | if (op2.known_isnan ()) |
1894 | r.set_undefined (); |
1895 | else if (op2.undefined_p ()) |
1896 | return false; |
1897 | else if (build_le (r, type, val: op2)) |
1898 | r.clear_nan (); |
1899 | break; |
1900 | |
1901 | default: |
1902 | break; |
1903 | } |
1904 | return true; |
1905 | } |
1906 | |
1907 | bool |
1908 | foperator_unordered_gt::op2_range (frange &r, |
1909 | tree type, |
1910 | const irange &lhs, |
1911 | const frange &op1, |
1912 | relation_trio) const |
1913 | { |
1914 | switch (get_bool_state (r, lhs, val_type: type)) |
1915 | { |
1916 | case BRS_TRUE: |
1917 | if (op1.maybe_isnan ()) |
1918 | r.set_varying (type); |
1919 | else if (op1.undefined_p ()) |
1920 | return false; |
1921 | else |
1922 | build_lt (r, type, val: op1); |
1923 | break; |
1924 | |
1925 | case BRS_FALSE: |
1926 | // A false UNORDERED_GT means both operands are !NAN, so it's |
1927 | // impossible for op1 to be a NAN. |
1928 | if (op1.known_isnan ()) |
1929 | r.set_undefined (); |
1930 | else if (op1.undefined_p ()) |
1931 | return false; |
1932 | else if (build_ge (r, type, val: op1)) |
1933 | r.clear_nan (); |
1934 | break; |
1935 | |
1936 | default: |
1937 | break; |
1938 | } |
1939 | return true; |
1940 | } |
1941 | |
1942 | class foperator_unordered_ge : public range_operator |
1943 | { |
1944 | using range_operator::fold_range; |
1945 | using range_operator::op1_range; |
1946 | using range_operator::op2_range; |
1947 | public: |
1948 | bool fold_range (irange &r, tree type, |
1949 | const frange &op1, const frange &op2, |
1950 | relation_trio trio = TRIO_VARYING) const final override |
1951 | { |
1952 | if (op1.known_isnan () || op2.known_isnan ()) |
1953 | { |
1954 | r = range_true (type); |
1955 | return true; |
1956 | } |
1957 | frange op1_no_nan = op1; |
1958 | frange op2_no_nan = op2; |
1959 | if (op1.maybe_isnan ()) |
1960 | op1_no_nan.clear_nan (); |
1961 | if (op2.maybe_isnan ()) |
1962 | op2_no_nan.clear_nan (); |
1963 | if (!range_op_handler (GE_EXPR).fold_range (r, type, lh: op1_no_nan, |
1964 | rh: op2_no_nan, trio)) |
1965 | return false; |
1966 | // The result is the same as the ordered version when the |
1967 | // comparison is true or when the operands cannot be NANs. |
1968 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
1969 | return true; |
1970 | else |
1971 | { |
1972 | r = range_true_and_false (type); |
1973 | return true; |
1974 | } |
1975 | } |
1976 | bool op1_range (frange &r, tree type, |
1977 | const irange &lhs, const frange &op2, |
1978 | relation_trio = TRIO_VARYING) const final override; |
1979 | bool op2_range (frange &r, tree type, |
1980 | const irange &lhs, const frange &op1, |
1981 | relation_trio = TRIO_VARYING) const final override; |
1982 | } fop_unordered_ge; |
1983 | |
1984 | bool |
1985 | foperator_unordered_ge::op1_range (frange &r, |
1986 | tree type, |
1987 | const irange &lhs, |
1988 | const frange &op2, |
1989 | relation_trio) const |
1990 | { |
1991 | switch (get_bool_state (r, lhs, val_type: type)) |
1992 | { |
1993 | case BRS_TRUE: |
1994 | if (op2.maybe_isnan ()) |
1995 | r.set_varying (type); |
1996 | else if (op2.undefined_p ()) |
1997 | return false; |
1998 | else |
1999 | build_ge (r, type, val: op2); |
2000 | break; |
2001 | |
2002 | case BRS_FALSE: |
2003 | // A false UNORDERED_GE means both operands are !NAN, so it's |
2004 | // impossible for op2 to be a NAN. |
2005 | if (op2.known_isnan ()) |
2006 | r.set_undefined (); |
2007 | else if (op2.undefined_p ()) |
2008 | return false; |
2009 | else if (build_lt (r, type, val: op2)) |
2010 | r.clear_nan (); |
2011 | break; |
2012 | |
2013 | default: |
2014 | break; |
2015 | } |
2016 | return true; |
2017 | } |
2018 | |
2019 | bool |
2020 | foperator_unordered_ge::op2_range (frange &r, tree type, |
2021 | const irange &lhs, |
2022 | const frange &op1, |
2023 | relation_trio) const |
2024 | { |
2025 | switch (get_bool_state (r, lhs, val_type: type)) |
2026 | { |
2027 | case BRS_TRUE: |
2028 | if (op1.maybe_isnan ()) |
2029 | r.set_varying (type); |
2030 | else if (op1.undefined_p ()) |
2031 | return false; |
2032 | else |
2033 | build_le (r, type, val: op1); |
2034 | break; |
2035 | |
2036 | case BRS_FALSE: |
2037 | // A false UNORDERED_GE means both operands are !NAN, so it's |
2038 | // impossible for op1 to be a NAN. |
2039 | if (op1.known_isnan ()) |
2040 | r.set_undefined (); |
2041 | else if (op1.undefined_p ()) |
2042 | return false; |
2043 | else if (build_gt (r, type, val: op1)) |
2044 | r.clear_nan (); |
2045 | break; |
2046 | |
2047 | default: |
2048 | break; |
2049 | } |
2050 | return true; |
2051 | } |
2052 | |
2053 | class foperator_unordered_equal : public range_operator |
2054 | { |
2055 | using range_operator::fold_range; |
2056 | using range_operator::op1_range; |
2057 | using range_operator::op2_range; |
2058 | public: |
2059 | bool fold_range (irange &r, tree type, |
2060 | const frange &op1, const frange &op2, |
2061 | relation_trio trio = TRIO_VARYING) const final override |
2062 | { |
2063 | if (op1.known_isnan () || op2.known_isnan ()) |
2064 | { |
2065 | r = range_true (type); |
2066 | return true; |
2067 | } |
2068 | frange op1_no_nan = op1; |
2069 | frange op2_no_nan = op2; |
2070 | if (op1.maybe_isnan ()) |
2071 | op1_no_nan.clear_nan (); |
2072 | if (op2.maybe_isnan ()) |
2073 | op2_no_nan.clear_nan (); |
2074 | if (!range_op_handler (EQ_EXPR).fold_range (r, type, lh: op1_no_nan, |
2075 | rh: op2_no_nan, trio)) |
2076 | return false; |
2077 | // The result is the same as the ordered version when the |
2078 | // comparison is true or when the operands cannot be NANs. |
2079 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
2080 | return true; |
2081 | else |
2082 | { |
2083 | r = range_true_and_false (type); |
2084 | return true; |
2085 | } |
2086 | } |
2087 | bool op1_range (frange &r, tree type, |
2088 | const irange &lhs, const frange &op2, |
2089 | relation_trio = TRIO_VARYING) const final override; |
2090 | bool op2_range (frange &r, tree type, |
2091 | const irange &lhs, const frange &op1, |
2092 | relation_trio rel = TRIO_VARYING) const final override |
2093 | { |
2094 | return op1_range (r, type, lhs, op2: op1, rel.swap_op1_op2 ()); |
2095 | } |
2096 | } fop_unordered_equal; |
2097 | |
2098 | bool |
2099 | foperator_unordered_equal::op1_range (frange &r, tree type, |
2100 | const irange &lhs, |
2101 | const frange &op2, |
2102 | relation_trio) const |
2103 | { |
2104 | switch (get_bool_state (r, lhs, val_type: type)) |
2105 | { |
2106 | case BRS_TRUE: |
2107 | // If it's true, the result is the same as OP2 plus a NAN. |
2108 | r = op2; |
2109 | // Add both zeros if there's the possibility of zero equality. |
2110 | frange_add_zeros (r, type); |
2111 | // Add the possibility of a NAN. |
2112 | r.update_nan (); |
2113 | break; |
2114 | |
2115 | case BRS_FALSE: |
2116 | // A false UNORDERED_EQ means both operands are !NAN, so it's |
2117 | // impossible for op2 to be a NAN. |
2118 | if (op2.known_isnan ()) |
2119 | r.set_undefined (); |
2120 | else |
2121 | { |
2122 | // The false side indicates !NAN and not equal. We can at least |
2123 | // represent !NAN. |
2124 | r.set_varying (type); |
2125 | r.clear_nan (); |
2126 | } |
2127 | break; |
2128 | |
2129 | default: |
2130 | break; |
2131 | } |
2132 | return true; |
2133 | } |
2134 | |
2135 | class foperator_ltgt : public range_operator |
2136 | { |
2137 | using range_operator::fold_range; |
2138 | using range_operator::op1_range; |
2139 | using range_operator::op2_range; |
2140 | public: |
2141 | bool fold_range (irange &r, tree type, |
2142 | const frange &op1, const frange &op2, |
2143 | relation_trio trio = TRIO_VARYING) const final override |
2144 | { |
2145 | if (op1.known_isnan () || op2.known_isnan ()) |
2146 | { |
2147 | r = range_false (type); |
2148 | return true; |
2149 | } |
2150 | frange op1_no_nan = op1; |
2151 | frange op2_no_nan = op2; |
2152 | if (op1.maybe_isnan ()) |
2153 | op1_no_nan.clear_nan (); |
2154 | if (op2.maybe_isnan ()) |
2155 | op2_no_nan.clear_nan (); |
2156 | if (!range_op_handler (NE_EXPR).fold_range (r, type, lh: op1_no_nan, |
2157 | rh: op2_no_nan, trio)) |
2158 | return false; |
2159 | // The result is the same as the ordered version when the |
2160 | // comparison is true or when the operands cannot be NANs. |
2161 | if (!maybe_isnan (op1, op2) || r == range_false (type)) |
2162 | return true; |
2163 | else |
2164 | { |
2165 | r = range_true_and_false (type); |
2166 | return true; |
2167 | } |
2168 | } |
2169 | bool op1_range (frange &r, tree type, |
2170 | const irange &lhs, const frange &op2, |
2171 | relation_trio = TRIO_VARYING) const final override; |
2172 | bool op2_range (frange &r, tree type, |
2173 | const irange &lhs, const frange &op1, |
2174 | relation_trio rel = TRIO_VARYING) const final override |
2175 | { |
2176 | return op1_range (r, type, lhs, op2: op1, rel.swap_op1_op2 ()); |
2177 | } |
2178 | } fop_ltgt; |
2179 | |
2180 | bool |
2181 | foperator_ltgt::op1_range (frange &r, tree type, |
2182 | const irange &lhs, |
2183 | const frange &op2, |
2184 | relation_trio) const |
2185 | { |
2186 | switch (get_bool_state (r, lhs, val_type: type)) |
2187 | { |
2188 | case BRS_TRUE: |
2189 | // A true LTGT means both operands are !NAN, so it's |
2190 | // impossible for op2 to be a NAN. |
2191 | if (op2.known_isnan ()) |
2192 | r.set_undefined (); |
2193 | else |
2194 | { |
2195 | // The true side indicates !NAN and not equal. We can at least |
2196 | // represent !NAN. |
2197 | r.set_varying (type); |
2198 | r.clear_nan (); |
2199 | } |
2200 | break; |
2201 | |
2202 | case BRS_FALSE: |
2203 | // If it's false, the result is the same as OP2 plus a NAN. |
2204 | r = op2; |
2205 | // Add both zeros if there's the possibility of zero equality. |
2206 | frange_add_zeros (r, type); |
2207 | // Add the possibility of a NAN. |
2208 | r.update_nan (); |
2209 | break; |
2210 | |
2211 | default: |
2212 | break; |
2213 | } |
2214 | return true; |
2215 | } |
2216 | |
2217 | // Final tweaks for float binary op op1_range/op2_range. |
2218 | // Return TRUE if the operation is performed and a valid range is available. |
2219 | |
2220 | static bool |
2221 | float_binary_op_range_finish (bool ret, frange &r, tree type, |
2222 | const frange &lhs, bool div_op2 = false) |
2223 | { |
2224 | if (!ret) |
2225 | return false; |
2226 | |
2227 | // If we get a known NAN from reverse op, it means either that |
2228 | // the other operand was known NAN (in that case we know nothing), |
2229 | // or the reverse operation introduced a known NAN. |
2230 | // Say for lhs = op1 * op2 if lhs is [-0, +0] and op2 is too, |
2231 | // 0 / 0 is known NAN. Just punt in that case. |
2232 | // If NANs aren't honored, we get for 0 / 0 UNDEFINED, so punt as well. |
2233 | // Or if lhs is a known NAN, we also don't know anything. |
2234 | if (r.known_isnan () || lhs.known_isnan () || r.undefined_p ()) |
2235 | { |
2236 | r.set_varying (type); |
2237 | return true; |
2238 | } |
2239 | |
2240 | // If lhs isn't NAN, then neither operand could be NAN, |
2241 | // even if the reverse operation does introduce a maybe_nan. |
2242 | if (!lhs.maybe_isnan ()) |
2243 | { |
2244 | r.clear_nan (); |
2245 | if (div_op2 |
2246 | ? !(real_compare (LE_EXPR, &lhs.lower_bound (), &dconst0) |
2247 | && real_compare (GE_EXPR, &lhs.upper_bound (), &dconst0)) |
2248 | : !(real_isinf (&lhs.lower_bound ()) |
2249 | || real_isinf (&lhs.upper_bound ()))) |
2250 | // For reverse + or - or * or op1 of /, if result is finite, then |
2251 | // r must be finite too, as X + INF or X - INF or X * INF or |
2252 | // INF / X is always +-INF or NAN. For op2 of /, if result is |
2253 | // non-zero and not NAN, r must be finite, as X / INF is always |
2254 | // 0 or NAN. |
2255 | frange_drop_infs (r, type); |
2256 | } |
2257 | // If lhs is a maybe or known NAN, the operand could be |
2258 | // NAN. |
2259 | else |
2260 | r.update_nan (); |
2261 | return true; |
2262 | } |
2263 | |
2264 | // True if [lb, ub] is [+-0, +-0]. |
2265 | static bool |
2266 | zero_p (const REAL_VALUE_TYPE &lb, const REAL_VALUE_TYPE &ub) |
2267 | { |
2268 | return real_iszero (&lb) && real_iszero (&ub); |
2269 | } |
2270 | |
2271 | // True if +0 or -0 is in [lb, ub] range. |
2272 | static bool |
2273 | contains_zero_p (const REAL_VALUE_TYPE &lb, const REAL_VALUE_TYPE &ub) |
2274 | { |
2275 | return (real_compare (LE_EXPR, &lb, &dconst0) |
2276 | && real_compare (GE_EXPR, &ub, &dconst0)); |
2277 | } |
2278 | |
2279 | // True if [lb, ub] is [-INF, -INF] or [+INF, +INF]. |
2280 | static bool |
2281 | singleton_inf_p (const REAL_VALUE_TYPE &lb, const REAL_VALUE_TYPE &ub) |
2282 | { |
2283 | return real_isinf (&lb) && real_isinf (&ub, sign: real_isneg (&lb)); |
2284 | } |
2285 | |
2286 | // Return -1 if binary op result must have sign bit set, |
2287 | // 1 if binary op result must have sign bit clear, |
2288 | // 0 otherwise. |
2289 | // Sign bit of binary op result is exclusive or of the |
2290 | // operand's sign bits. |
2291 | static int |
2292 | signbit_known_p (const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
2293 | const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub) |
2294 | { |
2295 | if (real_isneg (&lh_lb) == real_isneg (&lh_ub) |
2296 | && real_isneg (&rh_lb) == real_isneg (&rh_ub)) |
2297 | { |
2298 | if (real_isneg (&lh_lb) == real_isneg (&rh_ub)) |
2299 | return 1; |
2300 | else |
2301 | return -1; |
2302 | } |
2303 | return 0; |
2304 | } |
2305 | |
2306 | // Set [lb, ub] to [-0, -0], [-0, +0] or [+0, +0] depending on |
2307 | // signbit_known. |
2308 | static void |
2309 | zero_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, int signbit_known) |
2310 | { |
2311 | ub = lb = dconst0; |
2312 | if (signbit_known <= 0) |
2313 | lb = dconstm0; |
2314 | if (signbit_known < 0) |
2315 | ub = lb; |
2316 | } |
2317 | |
2318 | // Set [lb, ub] to [-INF, -INF], [-INF, +INF] or [+INF, +INF] depending on |
2319 | // signbit_known. |
2320 | static void |
2321 | inf_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, int signbit_known) |
2322 | { |
2323 | if (signbit_known > 0) |
2324 | ub = lb = dconstinf; |
2325 | else if (signbit_known < 0) |
2326 | ub = lb = dconstninf; |
2327 | else |
2328 | { |
2329 | lb = dconstninf; |
2330 | ub = dconstinf; |
2331 | } |
2332 | } |
2333 | |
2334 | // Set [lb, ub] to [-INF, -0], [-INF, +INF] or [+0, +INF] depending on |
2335 | // signbit_known. |
2336 | static void |
2337 | zero_to_inf_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, int signbit_known) |
2338 | { |
2339 | if (signbit_known > 0) |
2340 | { |
2341 | lb = dconst0; |
2342 | ub = dconstinf; |
2343 | } |
2344 | else if (signbit_known < 0) |
2345 | { |
2346 | lb = dconstninf; |
2347 | ub = dconstm0; |
2348 | } |
2349 | else |
2350 | { |
2351 | lb = dconstninf; |
2352 | ub = dconstinf; |
2353 | } |
2354 | } |
2355 | |
2356 | /* Extend the LHS range by 1ulp in each direction. For op1_range |
2357 | or op2_range of binary operations just computing the inverse |
2358 | operation on ranges isn't sufficient. Consider e.g. |
2359 | [1., 1.] = op1 + [1., 1.]. op1's range is not [0., 0.], but |
2360 | [-0x1.0p-54, 0x1.0p-53] (when not -frounding-math), any value for |
2361 | which adding 1. to it results in 1. after rounding to nearest. |
2362 | So, for op1_range/op2_range extend the lhs range by 1ulp (or 0.5ulp) |
2363 | in each direction. See PR109008 for more details. */ |
2364 | |
2365 | static frange |
2366 | float_widen_lhs_range (tree type, const frange &lhs) |
2367 | { |
2368 | frange ret = lhs; |
2369 | if (lhs.known_isnan ()) |
2370 | return ret; |
2371 | REAL_VALUE_TYPE lb = lhs.lower_bound (); |
2372 | REAL_VALUE_TYPE ub = lhs.upper_bound (); |
2373 | if (real_isfinite (&lb)) |
2374 | { |
2375 | frange_nextafter (TYPE_MODE (type), value&: lb, inf: dconstninf); |
2376 | if (real_isinf (&lb)) |
2377 | { |
2378 | /* For -DBL_MAX, instead of -Inf use |
2379 | nexttoward (-DBL_MAX, -LDBL_MAX) in a hypothetical |
2380 | wider type with the same mantissa precision but larger |
2381 | exponent range; it is outside of range of double values, |
2382 | but makes it clear it is just one ulp larger rather than |
2383 | infinite amount larger. */ |
2384 | lb = dconstm1; |
2385 | SET_REAL_EXP (&lb, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); |
2386 | } |
2387 | if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type))) |
2388 | { |
2389 | /* If not -frounding-math nor IBM double double, actually widen |
2390 | just by 0.5ulp rather than 1ulp. */ |
2391 | REAL_VALUE_TYPE tem; |
2392 | real_arithmetic (&tem, PLUS_EXPR, &lhs.lower_bound (), &lb); |
2393 | real_arithmetic (&lb, RDIV_EXPR, &tem, &dconst2); |
2394 | } |
2395 | } |
2396 | if (real_isfinite (&ub)) |
2397 | { |
2398 | frange_nextafter (TYPE_MODE (type), value&: ub, inf: dconstinf); |
2399 | if (real_isinf (&ub)) |
2400 | { |
2401 | /* For DBL_MAX similarly. */ |
2402 | ub = dconst1; |
2403 | SET_REAL_EXP (&ub, FLOAT_MODE_FORMAT (TYPE_MODE (type))->emax + 1); |
2404 | } |
2405 | if (!flag_rounding_math && !MODE_COMPOSITE_P (TYPE_MODE (type))) |
2406 | { |
2407 | /* If not -frounding-math nor IBM double double, actually widen |
2408 | just by 0.5ulp rather than 1ulp. */ |
2409 | REAL_VALUE_TYPE tem; |
2410 | real_arithmetic (&tem, PLUS_EXPR, &lhs.upper_bound (), &ub); |
2411 | real_arithmetic (&ub, RDIV_EXPR, &tem, &dconst2); |
2412 | } |
2413 | } |
2414 | /* Temporarily disable -ffinite-math-only, so that frange::set doesn't |
2415 | reduce the range back to real_min_representable (type) as lower bound |
2416 | or real_max_representable (type) as upper bound. */ |
2417 | bool save_flag_finite_math_only = flag_finite_math_only; |
2418 | flag_finite_math_only = false; |
2419 | ret.set (type, lb, ub, lhs.get_nan_state ()); |
2420 | flag_finite_math_only = save_flag_finite_math_only; |
2421 | return ret; |
2422 | } |
2423 | |
2424 | bool |
2425 | operator_plus::op1_range (frange &r, tree type, const frange &lhs, |
2426 | const frange &op2, relation_trio) const |
2427 | { |
2428 | if (lhs.undefined_p ()) |
2429 | return false; |
2430 | range_op_handler minus (MINUS_EXPR); |
2431 | if (!minus) |
2432 | return false; |
2433 | frange wlhs = float_widen_lhs_range (type, lhs); |
2434 | return float_binary_op_range_finish (ret: minus.fold_range (r, type, lh: wlhs, rh: op2), |
2435 | r, type, lhs: wlhs); |
2436 | } |
2437 | |
2438 | bool |
2439 | operator_plus::op2_range (frange &r, tree type, |
2440 | const frange &lhs, const frange &op1, |
2441 | relation_trio) const |
2442 | { |
2443 | return op1_range (r, type, lhs, op2: op1); |
2444 | } |
2445 | |
2446 | void |
2447 | operator_plus::rv_fold (frange &r, tree type, |
2448 | const REAL_VALUE_TYPE &lh_lb, |
2449 | const REAL_VALUE_TYPE &lh_ub, |
2450 | const REAL_VALUE_TYPE &rh_lb, |
2451 | const REAL_VALUE_TYPE &rh_ub, |
2452 | relation_kind) const |
2453 | { |
2454 | REAL_VALUE_TYPE lb, ub; |
2455 | bool maybe_nan = false; |
2456 | |
2457 | frange_arithmetic (code: PLUS_EXPR, type, result&: lb, op1: lh_lb, op2: rh_lb, inf: dconstninf); |
2458 | frange_arithmetic (code: PLUS_EXPR, type, result&: ub, op1: lh_ub, op2: rh_ub, inf: dconstinf); |
2459 | |
2460 | // [-INF] + [+INF] = NAN |
2461 | if (real_isinf (&lh_lb, sign: true) && real_isinf (&rh_ub, sign: false)) |
2462 | maybe_nan = true; |
2463 | // [+INF] + [-INF] = NAN |
2464 | else if (real_isinf (&lh_ub, sign: false) && real_isinf (&rh_lb, sign: true)) |
2465 | maybe_nan = true; |
2466 | |
2467 | // Handle possible NANs by saturating to the appropriate INF if only |
2468 | // one end is a NAN. If both ends are a NAN, just return a NAN. |
2469 | bool lb_nan = real_isnan (&lb); |
2470 | bool ub_nan = real_isnan (&ub); |
2471 | if (lb_nan && ub_nan) |
2472 | { |
2473 | r.set_nan (type); |
2474 | return; |
2475 | } |
2476 | if (lb_nan) |
2477 | lb = dconstninf; |
2478 | else if (ub_nan) |
2479 | ub = dconstinf; |
2480 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2481 | } |
2482 | |
2483 | |
2484 | bool |
2485 | operator_minus::op1_range (frange &r, tree type, |
2486 | const frange &lhs, const frange &op2, |
2487 | relation_trio) const |
2488 | { |
2489 | if (lhs.undefined_p ()) |
2490 | return false; |
2491 | frange wlhs = float_widen_lhs_range (type, lhs); |
2492 | return float_binary_op_range_finish ( |
2493 | ret: range_op_handler (PLUS_EXPR).fold_range (r, type, lh: wlhs, rh: op2), |
2494 | r, type, lhs: wlhs); |
2495 | } |
2496 | |
2497 | bool |
2498 | operator_minus::op2_range (frange &r, tree type, |
2499 | const frange &lhs, const frange &op1, |
2500 | relation_trio) const |
2501 | { |
2502 | if (lhs.undefined_p ()) |
2503 | return false; |
2504 | frange wlhs = float_widen_lhs_range (type, lhs); |
2505 | return float_binary_op_range_finish (ret: fold_range (r, type, lh: op1, rh: wlhs), |
2506 | r, type, lhs: wlhs); |
2507 | } |
2508 | |
2509 | void |
2510 | operator_minus::rv_fold (frange &r, tree type, |
2511 | const REAL_VALUE_TYPE &lh_lb, |
2512 | const REAL_VALUE_TYPE &lh_ub, |
2513 | const REAL_VALUE_TYPE &rh_lb, |
2514 | const REAL_VALUE_TYPE &rh_ub, |
2515 | relation_kind) const |
2516 | { |
2517 | REAL_VALUE_TYPE lb, ub; |
2518 | bool maybe_nan = false; |
2519 | |
2520 | frange_arithmetic (code: MINUS_EXPR, type, result&: lb, op1: lh_lb, op2: rh_ub, inf: dconstninf); |
2521 | frange_arithmetic (code: MINUS_EXPR, type, result&: ub, op1: lh_ub, op2: rh_lb, inf: dconstinf); |
2522 | |
2523 | // [+INF] - [+INF] = NAN |
2524 | if (real_isinf (&lh_ub, sign: false) && real_isinf (&rh_ub, sign: false)) |
2525 | maybe_nan = true; |
2526 | // [-INF] - [-INF] = NAN |
2527 | else if (real_isinf (&lh_lb, sign: true) && real_isinf (&rh_lb, sign: true)) |
2528 | maybe_nan = true; |
2529 | |
2530 | // Handle possible NANs by saturating to the appropriate INF if only |
2531 | // one end is a NAN. If both ends are a NAN, just return a NAN. |
2532 | bool lb_nan = real_isnan (&lb); |
2533 | bool ub_nan = real_isnan (&ub); |
2534 | if (lb_nan && ub_nan) |
2535 | { |
2536 | r.set_nan (type); |
2537 | return; |
2538 | } |
2539 | if (lb_nan) |
2540 | lb = dconstninf; |
2541 | else if (ub_nan) |
2542 | ub = dconstinf; |
2543 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2544 | } |
2545 | |
2546 | |
2547 | // Given CP[0] to CP[3] floating point values rounded to -INF, |
2548 | // set LB to the smallest of them (treating -0 as smaller to +0). |
2549 | // Given CP[4] to CP[7] floating point values rounded to +INF, |
2550 | // set UB to the largest of them (treating -0 as smaller to +0). |
2551 | |
2552 | static void |
2553 | find_range (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, |
2554 | const REAL_VALUE_TYPE (&cp)[8]) |
2555 | { |
2556 | lb = cp[0]; |
2557 | ub = cp[4]; |
2558 | for (int i = 1; i < 4; ++i) |
2559 | { |
2560 | if (real_less (&cp[i], &lb) |
2561 | || (real_iszero (&lb) && real_isnegzero (&cp[i]))) |
2562 | lb = cp[i]; |
2563 | if (real_less (&ub, &cp[i + 4]) |
2564 | || (real_isnegzero (&ub) && real_iszero (&cp[i + 4]))) |
2565 | ub = cp[i + 4]; |
2566 | } |
2567 | } |
2568 | |
2569 | |
2570 | bool |
2571 | operator_mult::op1_range (frange &r, tree type, |
2572 | const frange &lhs, const frange &op2, |
2573 | relation_trio) const |
2574 | { |
2575 | if (lhs.undefined_p ()) |
2576 | return false; |
2577 | range_op_handler rdiv (RDIV_EXPR); |
2578 | if (!rdiv) |
2579 | return false; |
2580 | frange wlhs = float_widen_lhs_range (type, lhs); |
2581 | bool ret = rdiv.fold_range (r, type, lh: wlhs, rh: op2); |
2582 | if (ret == false) |
2583 | return false; |
2584 | if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) |
2585 | return float_binary_op_range_finish (ret, r, type, lhs: wlhs); |
2586 | const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); |
2587 | const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); |
2588 | const REAL_VALUE_TYPE &op2_lb = op2.lower_bound (); |
2589 | const REAL_VALUE_TYPE &op2_ub = op2.upper_bound (); |
2590 | if ((contains_zero_p (lb: lhs_lb, ub: lhs_ub) && contains_zero_p (lb: op2_lb, ub: op2_ub)) |
2591 | || ((real_isinf (&lhs_lb) || real_isinf (&lhs_ub)) |
2592 | && (real_isinf (&op2_lb) || real_isinf (&op2_ub)))) |
2593 | { |
2594 | // If both lhs and op2 could be zeros or both could be infinities, |
2595 | // we don't know anything about op1 except maybe for the sign |
2596 | // and perhaps if it can be NAN or not. |
2597 | REAL_VALUE_TYPE lb, ub; |
2598 | int signbit_known = signbit_known_p (lh_lb: lhs_lb, lh_ub: lhs_ub, rh_lb: op2_lb, rh_ub: op2_ub); |
2599 | zero_to_inf_range (lb, ub, signbit_known); |
2600 | r.set (type, lb, ub); |
2601 | } |
2602 | // Otherwise, if op2 is a singleton INF and lhs doesn't include INF, |
2603 | // or if lhs must be zero and op2 doesn't include zero, it would be |
2604 | // UNDEFINED, while rdiv.fold_range computes a zero or singleton INF |
2605 | // range. Those are supersets of UNDEFINED, so let's keep that way. |
2606 | return float_binary_op_range_finish (ret, r, type, lhs: wlhs); |
2607 | } |
2608 | |
2609 | bool |
2610 | operator_mult::op2_range (frange &r, tree type, |
2611 | const frange &lhs, const frange &op1, |
2612 | relation_trio) const |
2613 | { |
2614 | return op1_range (r, type, lhs, op2: op1); |
2615 | } |
2616 | |
2617 | void |
2618 | operator_mult::rv_fold (frange &r, tree type, |
2619 | const REAL_VALUE_TYPE &lh_lb, |
2620 | const REAL_VALUE_TYPE &lh_ub, |
2621 | const REAL_VALUE_TYPE &rh_lb, |
2622 | const REAL_VALUE_TYPE &rh_ub, |
2623 | relation_kind kind) const |
2624 | { |
2625 | bool is_square |
2626 | = (kind == VREL_EQ |
2627 | && real_equal (&lh_lb, &rh_lb) |
2628 | && real_equal (&lh_ub, &rh_ub) |
2629 | && real_isneg (&lh_lb) == real_isneg (&rh_lb) |
2630 | && real_isneg (&lh_ub) == real_isneg (&rh_ub)); |
2631 | REAL_VALUE_TYPE lb, ub; |
2632 | bool maybe_nan = false; |
2633 | // x * x never produces a new NAN and we only multiply the same |
2634 | // values, so the 0 * INF problematic cases never appear there. |
2635 | if (!is_square) |
2636 | { |
2637 | // [+-0, +-0] * [+INF,+INF] (or [-INF,-INF] or swapped is a known NAN. |
2638 | if ((zero_p (lb: lh_lb, ub: lh_ub) && singleton_inf_p (lb: rh_lb, ub: rh_ub)) |
2639 | || (zero_p (lb: rh_lb, ub: rh_ub) && singleton_inf_p (lb: lh_lb, ub: lh_ub))) |
2640 | { |
2641 | r.set_nan (type); |
2642 | return; |
2643 | } |
2644 | |
2645 | // Otherwise, if one range includes zero and the other ends with +-INF, |
2646 | // it is a maybe NAN. |
2647 | if ((contains_zero_p (lb: lh_lb, ub: lh_ub) |
2648 | && (real_isinf (&rh_lb) || real_isinf (&rh_ub))) |
2649 | || (contains_zero_p (lb: rh_lb, ub: rh_ub) |
2650 | && (real_isinf (&lh_lb) || real_isinf (&lh_ub)))) |
2651 | { |
2652 | maybe_nan = true; |
2653 | |
2654 | int signbit_known = signbit_known_p (lh_lb, lh_ub, rh_lb, rh_ub); |
2655 | |
2656 | // If one of the ranges that includes INF is singleton |
2657 | // and the other range includes zero, the resulting |
2658 | // range is INF and NAN, because the 0 * INF boundary |
2659 | // case will be NAN, but already nextafter (0, 1) * INF |
2660 | // is INF. |
2661 | if (singleton_inf_p (lb: lh_lb, ub: lh_ub) |
2662 | || singleton_inf_p (lb: rh_lb, ub: rh_ub)) |
2663 | { |
2664 | inf_range (lb, ub, signbit_known); |
2665 | r.set (type, lb, ub, nan_state (true)); |
2666 | return; |
2667 | } |
2668 | |
2669 | // If one of the multiplicands must be zero, the resulting |
2670 | // range is +-0 and NAN. |
2671 | if (zero_p (lb: lh_lb, ub: lh_ub) || zero_p (lb: rh_lb, ub: rh_ub)) |
2672 | { |
2673 | zero_range (lb, ub, signbit_known); |
2674 | r.set (type, lb, ub, nan_state (true)); |
2675 | return; |
2676 | } |
2677 | |
2678 | // Otherwise one of the multiplicands could be |
2679 | // [0.0, nextafter (0.0, 1.0)] and the [DBL_MAX, INF] |
2680 | // or similarly with different signs. 0.0 * DBL_MAX |
2681 | // is still 0.0, nextafter (0.0, 1.0) * INF is still INF, |
2682 | // so if the signs are always the same or always different, |
2683 | // result is [+0.0, +INF] or [-INF, -0.0], otherwise VARYING. |
2684 | zero_to_inf_range (lb, ub, signbit_known); |
2685 | r.set (type, lb, ub, nan_state (true)); |
2686 | return; |
2687 | } |
2688 | } |
2689 | |
2690 | REAL_VALUE_TYPE cp[8]; |
2691 | // Do a cross-product. At this point none of the multiplications |
2692 | // should produce a NAN. |
2693 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[0], op1: lh_lb, op2: rh_lb, inf: dconstninf); |
2694 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[4], op1: lh_lb, op2: rh_lb, inf: dconstinf); |
2695 | if (is_square) |
2696 | { |
2697 | // For x * x we can just do max (lh_lb * lh_lb, lh_ub * lh_ub) |
2698 | // as maximum and -0.0 as minimum if 0.0 is in the range, |
2699 | // otherwise min (lh_lb * lh_lb, lh_ub * lh_ub). |
2700 | // -0.0 rather than 0.0 because VREL_EQ doesn't prove that |
2701 | // x and y are bitwise equal, just that they compare equal. |
2702 | if (contains_zero_p (lb: lh_lb, ub: lh_ub)) |
2703 | { |
2704 | if (real_isneg (&lh_lb) == real_isneg (&lh_ub)) |
2705 | cp[1] = dconst0; |
2706 | else |
2707 | cp[1] = dconstm0; |
2708 | } |
2709 | else |
2710 | cp[1] = cp[0]; |
2711 | cp[2] = cp[0]; |
2712 | cp[5] = cp[4]; |
2713 | cp[6] = cp[4]; |
2714 | } |
2715 | else |
2716 | { |
2717 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[1], op1: lh_lb, op2: rh_ub, inf: dconstninf); |
2718 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[5], op1: lh_lb, op2: rh_ub, inf: dconstinf); |
2719 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[2], op1: lh_ub, op2: rh_lb, inf: dconstninf); |
2720 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[6], op1: lh_ub, op2: rh_lb, inf: dconstinf); |
2721 | } |
2722 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[3], op1: lh_ub, op2: rh_ub, inf: dconstninf); |
2723 | frange_arithmetic (code: MULT_EXPR, type, result&: cp[7], op1: lh_ub, op2: rh_ub, inf: dconstinf); |
2724 | |
2725 | find_range (lb, ub, cp); |
2726 | |
2727 | gcc_checking_assert (!real_isnan (&lb)); |
2728 | gcc_checking_assert (!real_isnan (&ub)); |
2729 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2730 | } |
2731 | |
2732 | |
2733 | class foperator_div : public range_operator |
2734 | { |
2735 | using range_operator::op1_range; |
2736 | using range_operator::op2_range; |
2737 | public: |
2738 | virtual bool op1_range (frange &r, tree type, |
2739 | const frange &lhs, |
2740 | const frange &op2, |
2741 | relation_trio = TRIO_VARYING) const final override |
2742 | { |
2743 | if (lhs.undefined_p ()) |
2744 | return false; |
2745 | frange wlhs = float_widen_lhs_range (type, lhs); |
2746 | bool ret = range_op_handler (MULT_EXPR).fold_range (r, type, lh: wlhs, rh: op2); |
2747 | if (!ret) |
2748 | return ret; |
2749 | if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) |
2750 | return float_binary_op_range_finish (ret, r, type, lhs: wlhs); |
2751 | const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); |
2752 | const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); |
2753 | const REAL_VALUE_TYPE &op2_lb = op2.lower_bound (); |
2754 | const REAL_VALUE_TYPE &op2_ub = op2.upper_bound (); |
2755 | if ((contains_zero_p (lb: lhs_lb, ub: lhs_ub) |
2756 | && (real_isinf (&op2_lb) || real_isinf (&op2_ub))) |
2757 | || ((contains_zero_p (lb: op2_lb, ub: op2_ub)) |
2758 | && (real_isinf (&lhs_lb) || real_isinf (&lhs_ub)))) |
2759 | { |
2760 | // If both lhs could be zero and op2 infinity or vice versa, |
2761 | // we don't know anything about op1 except maybe for the sign |
2762 | // and perhaps if it can be NAN or not. |
2763 | REAL_VALUE_TYPE lb, ub; |
2764 | int signbit_known = signbit_known_p (lh_lb: lhs_lb, lh_ub: lhs_ub, rh_lb: op2_lb, rh_ub: op2_ub); |
2765 | zero_to_inf_range (lb, ub, signbit_known); |
2766 | r.set (type, lb, ub); |
2767 | } |
2768 | return float_binary_op_range_finish (ret, r, type, lhs: wlhs); |
2769 | } |
2770 | virtual bool op2_range (frange &r, tree type, |
2771 | const frange &lhs, |
2772 | const frange &op1, |
2773 | relation_trio = TRIO_VARYING) const final override |
2774 | { |
2775 | if (lhs.undefined_p ()) |
2776 | return false; |
2777 | frange wlhs = float_widen_lhs_range (type, lhs); |
2778 | bool ret = fold_range (r, type, op1, op2: wlhs); |
2779 | if (!ret) |
2780 | return ret; |
2781 | if (wlhs.known_isnan () || op1.known_isnan () || op1.undefined_p ()) |
2782 | return float_binary_op_range_finish (ret, r, type, lhs: wlhs, div_op2: true); |
2783 | const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); |
2784 | const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); |
2785 | const REAL_VALUE_TYPE &op1_lb = op1.lower_bound (); |
2786 | const REAL_VALUE_TYPE &op1_ub = op1.upper_bound (); |
2787 | if ((contains_zero_p (lb: lhs_lb, ub: lhs_ub) && contains_zero_p (lb: op1_lb, ub: op1_ub)) |
2788 | || ((real_isinf (&lhs_lb) || real_isinf (&lhs_ub)) |
2789 | && (real_isinf (&op1_lb) || real_isinf (&op1_ub)))) |
2790 | { |
2791 | // If both lhs and op1 could be zeros or both could be infinities, |
2792 | // we don't know anything about op2 except maybe for the sign |
2793 | // and perhaps if it can be NAN or not. |
2794 | REAL_VALUE_TYPE lb, ub; |
2795 | int signbit_known = signbit_known_p (lh_lb: lhs_lb, lh_ub: lhs_ub, rh_lb: op1_lb, rh_ub: op1_ub); |
2796 | zero_to_inf_range (lb, ub, signbit_known); |
2797 | r.set (type, lb, ub); |
2798 | } |
2799 | return float_binary_op_range_finish (ret, r, type, lhs: wlhs, div_op2: true); |
2800 | } |
2801 | private: |
2802 | void rv_fold (frange &r, tree type, |
2803 | const REAL_VALUE_TYPE &lh_lb, |
2804 | const REAL_VALUE_TYPE &lh_ub, |
2805 | const REAL_VALUE_TYPE &rh_lb, |
2806 | const REAL_VALUE_TYPE &rh_ub, |
2807 | relation_kind) const final override |
2808 | { |
2809 | // +-0.0 / +-0.0 or +-INF / +-INF is a known NAN. |
2810 | if ((zero_p (lb: lh_lb, ub: lh_ub) && zero_p (lb: rh_lb, ub: rh_ub)) |
2811 | || (singleton_inf_p (lb: lh_lb, ub: lh_ub) && singleton_inf_p (lb: rh_lb, ub: rh_ub))) |
2812 | { |
2813 | r.set_nan (type); |
2814 | return; |
2815 | } |
2816 | |
2817 | REAL_VALUE_TYPE lb, ub; |
2818 | bool maybe_nan = false; |
2819 | // If +-0.0 is in both ranges, it is a maybe NAN. |
2820 | if (contains_zero_p (lb: lh_lb, ub: lh_ub) && contains_zero_p (lb: rh_lb, ub: rh_ub)) |
2821 | maybe_nan = true; |
2822 | // If +-INF is in both ranges, it is a maybe NAN. |
2823 | else if ((real_isinf (&lh_lb) || real_isinf (&lh_ub)) |
2824 | && (real_isinf (&rh_lb) || real_isinf (&rh_ub))) |
2825 | maybe_nan = true; |
2826 | |
2827 | int signbit_known = signbit_known_p (lh_lb, lh_ub, rh_lb, rh_ub); |
2828 | |
2829 | // If dividend must be zero, the range is just +-0 |
2830 | // (including if the divisor is +-INF). |
2831 | // If divisor must be +-INF, the range is just +-0 |
2832 | // (including if the dividend is zero). |
2833 | if (zero_p (lb: lh_lb, ub: lh_ub) || singleton_inf_p (lb: rh_lb, ub: rh_ub)) |
2834 | { |
2835 | zero_range (lb, ub, signbit_known); |
2836 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2837 | return; |
2838 | } |
2839 | |
2840 | // If divisor must be zero, the range is just +-INF |
2841 | // (including if the dividend is +-INF). |
2842 | // If dividend must be +-INF, the range is just +-INF |
2843 | // (including if the dividend is zero). |
2844 | if (zero_p (lb: rh_lb, ub: rh_ub) || singleton_inf_p (lb: lh_lb, ub: lh_ub)) |
2845 | { |
2846 | inf_range (lb, ub, signbit_known); |
2847 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2848 | return; |
2849 | } |
2850 | |
2851 | // Otherwise if both operands may be zero, divisor could be |
2852 | // nextafter(0.0, +-1.0) and dividend +-0.0 |
2853 | // in which case result is going to INF or vice versa and |
2854 | // result +0.0. So, all we can say for that case is if the |
2855 | // signs of divisor and dividend are always the same we have |
2856 | // [+0.0, +INF], if they are always different we have |
2857 | // [-INF, -0.0]. If they vary, VARYING. |
2858 | // If both may be +-INF, divisor could be INF and dividend FLT_MAX, |
2859 | // in which case result is going to INF or vice versa and |
2860 | // result +0.0. So, all we can say for that case is if the |
2861 | // signs of divisor and dividend are always the same we have |
2862 | // [+0.0, +INF], if they are always different we have |
2863 | // [-INF, -0.0]. If they vary, VARYING. |
2864 | if (maybe_nan) |
2865 | { |
2866 | zero_to_inf_range (lb, ub, signbit_known); |
2867 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2868 | return; |
2869 | } |
2870 | |
2871 | REAL_VALUE_TYPE cp[8]; |
2872 | // Do a cross-division. At this point none of the divisions should |
2873 | // produce a NAN. |
2874 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[0], op1: lh_lb, op2: rh_lb, inf: dconstninf); |
2875 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[1], op1: lh_lb, op2: rh_ub, inf: dconstninf); |
2876 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[2], op1: lh_ub, op2: rh_lb, inf: dconstninf); |
2877 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[3], op1: lh_ub, op2: rh_ub, inf: dconstninf); |
2878 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[4], op1: lh_lb, op2: rh_lb, inf: dconstinf); |
2879 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[5], op1: lh_lb, op2: rh_ub, inf: dconstinf); |
2880 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[6], op1: lh_ub, op2: rh_lb, inf: dconstinf); |
2881 | frange_arithmetic (code: RDIV_EXPR, type, result&: cp[7], op1: lh_ub, op2: rh_ub, inf: dconstinf); |
2882 | |
2883 | find_range (lb, ub, cp); |
2884 | |
2885 | // If divisor may be zero (but is not known to be only zero), |
2886 | // and dividend can't be zero, the range can go up to -INF or +INF |
2887 | // depending on the signs. |
2888 | if (contains_zero_p (lb: rh_lb, ub: rh_ub)) |
2889 | { |
2890 | if (signbit_known <= 0) |
2891 | real_inf (&lb, sign: true); |
2892 | if (signbit_known >= 0) |
2893 | real_inf (&ub, sign: false); |
2894 | } |
2895 | |
2896 | gcc_checking_assert (!real_isnan (&lb)); |
2897 | gcc_checking_assert (!real_isnan (&ub)); |
2898 | r.set (type, lb, ub, nan_state (maybe_nan)); |
2899 | } |
2900 | } fop_div; |
2901 | |
2902 | |
2903 | // Initialize any float operators to the primary table |
2904 | |
2905 | void |
2906 | range_op_table::initialize_float_ops () |
2907 | { |
2908 | set (code: UNLE_EXPR, op&: fop_unordered_le); |
2909 | set (code: UNLT_EXPR, op&: fop_unordered_lt); |
2910 | set (code: UNGE_EXPR, op&: fop_unordered_ge); |
2911 | set (code: UNGT_EXPR, op&: fop_unordered_gt); |
2912 | set (code: UNEQ_EXPR, op&: fop_unordered_equal); |
2913 | set (code: ORDERED_EXPR, op&: fop_ordered); |
2914 | set (code: UNORDERED_EXPR, op&: fop_unordered); |
2915 | set (code: LTGT_EXPR, op&: fop_ltgt); |
2916 | set (code: RDIV_EXPR, op&: fop_div); |
2917 | } |
2918 | |
2919 | #if CHECKING_P |
2920 | #include "selftest.h" |
2921 | |
2922 | namespace selftest |
2923 | { |
2924 | |
2925 | // Build an frange from string endpoints. |
2926 | |
2927 | static inline frange |
2928 | frange_float (const char *lb, const char *ub, tree type = float_type_node) |
2929 | { |
2930 | REAL_VALUE_TYPE min, max; |
2931 | gcc_assert (real_from_string (&min, lb) == 0); |
2932 | gcc_assert (real_from_string (&max, ub) == 0); |
2933 | return frange (type, min, max); |
2934 | } |
2935 | |
2936 | void |
2937 | range_op_float_tests () |
2938 | { |
2939 | frange r, r0, r1; |
2940 | frange trange (float_type_node); |
2941 | |
2942 | // negate([-5, +10]) => [-10, 5] |
2943 | r0 = frange_float (lb: "-5" , ub: "10" ); |
2944 | range_op_handler (NEGATE_EXPR).fold_range (r, float_type_node, lh: r0, rh: trange); |
2945 | ASSERT_EQ (r, frange_float ("-10" , "5" )); |
2946 | |
2947 | // negate([0, 1] -NAN) => [-1, -0] +NAN |
2948 | r0 = frange_float (lb: "0" , ub: "1" ); |
2949 | r0.update_nan (sign: true); |
2950 | range_op_handler (NEGATE_EXPR).fold_range (r, float_type_node, lh: r0, rh: trange); |
2951 | r1 = frange_float (lb: "-1" , ub: "-0" ); |
2952 | r1.update_nan (sign: false); |
2953 | ASSERT_EQ (r, r1); |
2954 | |
2955 | // [-INF,+INF] + [-INF,+INF] could be a NAN. |
2956 | range_op_handler plus (PLUS_EXPR); |
2957 | r0.set_varying (float_type_node); |
2958 | r1.set_varying (float_type_node); |
2959 | r0.clear_nan (); |
2960 | r1.clear_nan (); |
2961 | plus.fold_range (r, float_type_node, lh: r0, rh: r1); |
2962 | if (HONOR_NANS (float_type_node)) |
2963 | ASSERT_TRUE (r.maybe_isnan ()); |
2964 | } |
2965 | |
2966 | } // namespace selftest |
2967 | |
2968 | #endif // CHECKING_P |
2969 | |