]>
Commit | Line | Data |
---|---|---|
a6efab5f | 1 | /* Floating point range operators. |
a945c346 | 2 | Copyright (C) 2022-2024 Free Software Foundation, Inc. |
a6efab5f AH |
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" | |
07767389 | 48 | #include "range-op-mixed.h" |
a6efab5f AH |
49 | |
50 | // Default definitions for floating point operators. | |
51 | ||
52 | bool | |
9c0fed50 | 53 | range_operator::fold_range (frange &r, tree type, |
0ef5649e | 54 | const frange &op1, const frange &op2, |
2f7f9edd | 55 | relation_trio trio) const |
a6efab5f | 56 | { |
0ef5649e AH |
57 | if (empty_range_varying (r, type, op1, op2)) |
58 | return true; | |
59 | if (op1.known_isnan () || op2.known_isnan ()) | |
60 | { | |
ce81740c | 61 | r.set_nan (type); |
0ef5649e AH |
62 | return true; |
63 | } | |
64 | ||
848b5f3a | 65 | rv_fold (r, type, |
0ef5649e | 66 | op1.lower_bound (), op1.upper_bound (), |
2f7f9edd | 67 | op2.lower_bound (), op2.upper_bound (), trio.op1_op2 ()); |
0ef5649e | 68 | |
848b5f3a AH |
69 | if (r.known_isnan ()) |
70 | return true; | |
24e97ac4 | 71 | if (op1.maybe_isnan () || op2.maybe_isnan ()) |
848b5f3a | 72 | r.update_nan (); |
24e97ac4 | 73 | |
844190af AH |
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 | ||
ce3974e5 JJ |
95 | r.flush_denormals_to_zero (); |
96 | ||
0ef5649e AH |
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 | |
c46b5b0a | 102 | // UB, the final range has the possibility of a NAN. |
0ef5649e | 103 | void |
24e97ac4 | 104 | range_operator::rv_fold (frange &r, tree type, |
24e97ac4 AH |
105 | const REAL_VALUE_TYPE &, |
106 | const REAL_VALUE_TYPE &, | |
107 | const REAL_VALUE_TYPE &, | |
108 | const REAL_VALUE_TYPE &, relation_kind) const | |
0ef5649e | 109 | { |
24e97ac4 | 110 | r.set (type, dconstninf, dconstinf, nan_state (true)); |
a6efab5f AH |
111 | } |
112 | ||
be2a25ad | 113 | bool |
9c0fed50 | 114 | range_operator::fold_range (irange &r ATTRIBUTE_UNUSED, |
be2a25ad AM |
115 | tree type ATTRIBUTE_UNUSED, |
116 | const frange &lh ATTRIBUTE_UNUSED, | |
117 | const irange &rh ATTRIBUTE_UNUSED, | |
b565ac19 | 118 | relation_trio) const |
be2a25ad AM |
119 | { |
120 | return false; | |
121 | } | |
122 | ||
a6efab5f | 123 | bool |
9c0fed50 | 124 | range_operator::fold_range (irange &r ATTRIBUTE_UNUSED, |
a6efab5f AH |
125 | tree type ATTRIBUTE_UNUSED, |
126 | const frange &lh ATTRIBUTE_UNUSED, | |
127 | const frange &rh ATTRIBUTE_UNUSED, | |
b565ac19 | 128 | relation_trio) const |
a6efab5f AH |
129 | { |
130 | return false; | |
131 | } | |
132 | ||
0ddc8c78 AM |
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 | ||
a6efab5f | 143 | bool |
9c0fed50 | 144 | range_operator::op1_range (frange &r ATTRIBUTE_UNUSED, |
a6efab5f AH |
145 | tree type ATTRIBUTE_UNUSED, |
146 | const frange &lhs ATTRIBUTE_UNUSED, | |
147 | const frange &op2 ATTRIBUTE_UNUSED, | |
b565ac19 | 148 | relation_trio) const |
a6efab5f AH |
149 | { |
150 | return false; | |
151 | } | |
152 | ||
153 | bool | |
9c0fed50 | 154 | range_operator::op1_range (frange &r ATTRIBUTE_UNUSED, |
a6efab5f AH |
155 | tree type ATTRIBUTE_UNUSED, |
156 | const irange &lhs ATTRIBUTE_UNUSED, | |
157 | const frange &op2 ATTRIBUTE_UNUSED, | |
b565ac19 | 158 | relation_trio) const |
a6efab5f AH |
159 | { |
160 | return false; | |
161 | } | |
162 | ||
163 | bool | |
9c0fed50 | 164 | range_operator::op2_range (frange &r ATTRIBUTE_UNUSED, |
a6efab5f AH |
165 | tree type ATTRIBUTE_UNUSED, |
166 | const frange &lhs ATTRIBUTE_UNUSED, | |
167 | const frange &op1 ATTRIBUTE_UNUSED, | |
b565ac19 | 168 | relation_trio) const |
a6efab5f AH |
169 | { |
170 | return false; | |
171 | } | |
172 | ||
173 | bool | |
9c0fed50 | 174 | range_operator::op2_range (frange &r ATTRIBUTE_UNUSED, |
a6efab5f AH |
175 | tree type ATTRIBUTE_UNUSED, |
176 | const irange &lhs ATTRIBUTE_UNUSED, | |
177 | const frange &op1 ATTRIBUTE_UNUSED, | |
b565ac19 | 178 | relation_trio) const |
a6efab5f AH |
179 | { |
180 | return false; | |
181 | } | |
182 | ||
183 | relation_kind | |
9c0fed50 | 184 | range_operator::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED, |
a6efab5f AH |
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 | |
9c0fed50 | 193 | range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED, |
a6efab5f AH |
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 | |
9c0fed50 | 202 | range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, |
a6efab5f AH |
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 | |
9c0fed50 | 211 | range_operator::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED, |
a6efab5f AH |
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 | |
9fedc3c0 AM |
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 | |
5364b425 AH |
232 | { |
233 | return VREL_VARYING; | |
234 | } | |
235 | ||
be43d5d3 | 236 | // Return TRUE if OP1 and OP2 may be a NAN. |
4fbe3e6a AH |
237 | |
238 | static inline bool | |
be43d5d3 | 239 | maybe_isnan (const frange &op1, const frange &op2) |
4fbe3e6a | 240 | { |
be43d5d3 | 241 | return op1.maybe_isnan () || op2.maybe_isnan (); |
24012539 AH |
242 | } |
243 | ||
66be6ed8 AH |
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. | |
24012539 | 257 | |
d438b67e | 258 | static inline bool |
24012539 AH |
259 | frelop_early_resolve (irange &r, tree type, |
260 | const frange &op1, const frange &op2, | |
66be6ed8 | 261 | relation_trio trio, relation_kind my_rel) |
24012539 | 262 | { |
66be6ed8 AH |
263 | relation_kind rel = trio.op1_op2 (); |
264 | ||
66be6ed8 AH |
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) | |
7a4e57ff | 275 | if (!maybe_isnan (op1, op2) && relation_union (rel, my_rel) == my_rel) |
66be6ed8 AH |
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 (rel, my_rel) == VREL_UNDEFINED) | |
283 | { | |
284 | r = range_false (type); | |
285 | return true; | |
286 | } | |
287 | ||
24012539 AH |
288 | // If either operand is undefined, return VARYING. |
289 | if (empty_range_varying (r, type, op1, op2)) | |
290 | return true; | |
291 | ||
66be6ed8 | 292 | return false; |
24012539 AH |
293 | } |
294 | ||
9d96a286 AH |
295 | // Set VALUE to its next real value, or INF if the operation overflows. |
296 | ||
d438b67e | 297 | void |
9d96a286 AH |
298 | frange_nextafter (enum machine_mode mode, |
299 | REAL_VALUE_TYPE &value, | |
300 | const REAL_VALUE_TYPE &inf) | |
301 | { | |
716c2d08 JJ |
302 | if (MODE_COMPOSITE_P (mode) |
303 | && (real_isdenormal (&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 | } | |
9d96a286 AH |
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 | |
c46b5b0a | 326 | // precision (64-bit mantissa) and only occasionally rounded to |
9d96a286 | 327 | // SF/DFmode (when storing into memory from the 387 stack). Maybe |
c46b5b0a | 328 | // this is ok as well though it is just occasionally more precise. ?? |
9d96a286 | 329 | |
82aef047 | 330 | void |
9d96a286 AH |
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 | ||
21da32d9 JJ |
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 | ||
9d96a286 AH |
362 | // Be extra careful if there may be discrepancies between the |
363 | // compile and runtime results. | |
2f187e98 JJ |
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, !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, 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))) | |
9d96a286 | 400 | { |
716c2d08 JJ |
401 | if (mode_composite |
402 | && (real_isdenormal (&result, mode) || real_iszero (&result))) | |
9d96a286 | 403 | { |
716c2d08 JJ |
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); | |
9d96a286 | 409 | } |
716c2d08 JJ |
410 | else |
411 | frange_nextafter (mode, result, inf); | |
9d96a286 | 412 | } |
716c2d08 JJ |
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, result, inf); | |
420 | break; | |
421 | case MULT_EXPR: | |
422 | // ibm-ldouble-format documents 2ulps for *. | |
423 | frange_nextafter (mode, result, inf); | |
424 | frange_nextafter (mode, result, inf); | |
425 | break; | |
426 | case RDIV_EXPR: | |
427 | // ibm-ldouble-format documents 3ulps for /. | |
428 | frange_nextafter (mode, result, inf); | |
429 | frange_nextafter (mode, result, inf); | |
430 | frange_nextafter (mode, result, inf); | |
431 | break; | |
432 | default: | |
433 | break; | |
434 | } | |
9d96a286 AH |
435 | } |
436 | ||
8bb1df03 AH |
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 | { | |
b7fd7fb5 | 443 | REAL_VALUE_TYPE max = real_max_representable (type); |
8bb1df03 AH |
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 | { | |
b7fd7fb5 | 454 | REAL_VALUE_TYPE min = real_min_representable (type); |
8bb1df03 AH |
455 | frange tmp (type, min, r.upper_bound ()); |
456 | r.intersect (tmp); | |
457 | } | |
458 | ||
a0ee2e52 JJ |
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 | ||
3c85c118 AH |
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 | { | |
91746147 | 476 | if (r.undefined_p () || r.known_isnan ()) |
3c85c118 AH |
477 | return; |
478 | ||
479 | if (HONOR_SIGNED_ZEROS (type) | |
480 | && (real_iszero (&r.lower_bound ()) || real_iszero (&r.upper_bound ()))) | |
91746147 AH |
481 | { |
482 | frange zero; | |
483 | zero.set_zero (type); | |
484 | r.union_ (zero); | |
485 | } | |
3c85c118 AH |
486 | } |
487 | ||
f0068278 AH |
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. | |
4fbe3e6a | 491 | |
f5dc9da0 | 492 | static bool |
7d647a8d | 493 | build_le (frange &r, tree type, const frange &val) |
4fbe3e6a | 494 | { |
d2278da1 AH |
495 | gcc_checking_assert (!val.known_isnan ()); |
496 | ||
b7fd7fb5 AH |
497 | REAL_VALUE_TYPE ninf = frange_val_min (type); |
498 | r.set (type, ninf, val.upper_bound ()); | |
3c85c118 AH |
499 | |
500 | // Add both zeros if there's the possibility of zero equality. | |
501 | frange_add_zeros (r, type); | |
502 | ||
f5dc9da0 | 503 | return true; |
4fbe3e6a AH |
504 | } |
505 | ||
f0068278 AH |
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. | |
4fbe3e6a | 509 | |
f5dc9da0 | 510 | static bool |
7d647a8d | 511 | build_lt (frange &r, tree type, const frange &val) |
4fbe3e6a | 512 | { |
d2278da1 AH |
513 | gcc_checking_assert (!val.known_isnan ()); |
514 | ||
f5dc9da0 | 515 | // < -INF is outside the range. |
7d647a8d | 516 | if (real_isinf (&val.upper_bound (), 1)) |
f5dc9da0 AH |
517 | { |
518 | if (HONOR_NANS (type)) | |
9c4c4186 | 519 | r.set_nan (type); |
f5dc9da0 AH |
520 | else |
521 | r.set_undefined (); | |
522 | return false; | |
523 | } | |
4c57e57b | 524 | |
b7fd7fb5 | 525 | REAL_VALUE_TYPE ninf = frange_val_min (type); |
4c57e57b AH |
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, prev, ninf); | |
534 | r.set (type, ninf, prev); | |
f5dc9da0 | 535 | return true; |
4fbe3e6a AH |
536 | } |
537 | ||
f0068278 AH |
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. | |
4fbe3e6a | 541 | |
f5dc9da0 | 542 | static bool |
7d647a8d | 543 | build_ge (frange &r, tree type, const frange &val) |
4fbe3e6a | 544 | { |
d2278da1 AH |
545 | gcc_checking_assert (!val.known_isnan ()); |
546 | ||
b7fd7fb5 AH |
547 | REAL_VALUE_TYPE inf = frange_val_max (type); |
548 | r.set (type, val.lower_bound (), inf); | |
3c85c118 AH |
549 | |
550 | // Add both zeros if there's the possibility of zero equality. | |
551 | frange_add_zeros (r, type); | |
552 | ||
f5dc9da0 | 553 | return true; |
4fbe3e6a AH |
554 | } |
555 | ||
f0068278 AH |
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. | |
4fbe3e6a | 559 | |
f5dc9da0 | 560 | static bool |
7d647a8d | 561 | build_gt (frange &r, tree type, const frange &val) |
4fbe3e6a | 562 | { |
d2278da1 AH |
563 | gcc_checking_assert (!val.known_isnan ()); |
564 | ||
f5dc9da0 | 565 | // > +INF is outside the range. |
7d647a8d | 566 | if (real_isinf (&val.lower_bound (), 0)) |
f5dc9da0 AH |
567 | { |
568 | if (HONOR_NANS (type)) | |
9c4c4186 | 569 | r.set_nan (type); |
f5dc9da0 AH |
570 | else |
571 | r.set_undefined (); | |
572 | return false; | |
573 | } | |
574 | ||
b7fd7fb5 | 575 | REAL_VALUE_TYPE inf = frange_val_max (type); |
4c57e57b AH |
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, next, inf); | |
584 | r.set (type, next, inf); | |
f5dc9da0 | 585 | return true; |
4fbe3e6a AH |
586 | } |
587 | ||
588 | ||
b073d8af AM |
589 | bool |
590 | operator_identity::fold_range (frange &r, tree, const frange &op1, | |
591 | const frange &, relation_trio) const | |
a6efab5f | 592 | { |
b073d8af AM |
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 | ||
4f0ac5a5 AM |
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 | } | |
a6efab5f | 612 | |
2dbf1e61 AM |
613 | bool |
614 | operator_equal::op2_range (frange &r, tree type, | |
615 | const irange &lhs, const frange &op1, | |
616 | relation_trio rel) const | |
24012539 | 617 | { |
2dbf1e61 AM |
618 | return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); |
619 | } | |
24012539 | 620 | |
4fbe3e6a | 621 | bool |
2dbf1e61 AM |
622 | operator_equal::fold_range (irange &r, tree type, |
623 | const frange &op1, const frange &op2, | |
624 | relation_trio rel) const | |
4fbe3e6a AH |
625 | { |
626 | if (frelop_early_resolve (r, type, op1, op2, rel, VREL_EQ)) | |
627 | return true; | |
628 | ||
d2278da1 AH |
629 | if (op1.known_isnan () || op2.known_isnan ()) |
630 | r = range_false (type); | |
4fbe3e6a AH |
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. | |
d2278da1 | 633 | else if (op1.singleton_p () && op2.singleton_p ()) |
4fbe3e6a AH |
634 | { |
635 | if (op1 == op2) | |
636 | r = range_true (type); | |
09176201 JJ |
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); | |
4fbe3e6a AH |
641 | else |
642 | r = range_false (type); | |
643 | } | |
69044e11 JJ |
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); | |
5fe05ffe | 651 | else |
4fbe3e6a AH |
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 ()) | |
09176201 JJ |
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 | } | |
4fbe3e6a AH |
670 | else |
671 | r = range_true_and_false (type); | |
672 | } | |
4fbe3e6a AH |
673 | return true; |
674 | } | |
675 | ||
24012539 | 676 | bool |
2dbf1e61 | 677 | operator_equal::op1_range (frange &r, tree type, |
24012539 | 678 | const irange &lhs, |
d2278da1 | 679 | const frange &op2, |
b565ac19 | 680 | relation_trio trio) const |
24012539 | 681 | { |
b565ac19 | 682 | relation_kind rel = trio.op1_op2 (); |
24012539 AH |
683 | switch (get_bool_state (r, lhs, type)) |
684 | { | |
685 | case BRS_TRUE: | |
d2278da1 AH |
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 | } | |
24012539 AH |
698 | break; |
699 | ||
700 | case BRS_FALSE: | |
24012539 AH |
701 | // The FALSE side of op1 == op1 implies op1 is a NAN. |
702 | if (rel == VREL_EQ) | |
9c4c4186 | 703 | r.set_nan (type); |
d2278da1 AH |
704 | // On the FALSE side of x == NAN, we know nothing about x. |
705 | else if (op2.known_isnan ()) | |
706 | r.set_varying (type); | |
4fbe3e6a AH |
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 () | |
be43d5d3 | 710 | || (!op2.maybe_isnan () && op2.zero_p ())) |
4fbe3e6a AH |
711 | { |
712 | REAL_VALUE_TYPE tmp = op2.lower_bound (); | |
713 | r.set (type, tmp, tmp, VR_ANTI_RANGE); | |
714 | } | |
d2278da1 AH |
715 | else |
716 | r.set_varying (type); | |
24012539 AH |
717 | break; |
718 | ||
719 | default: | |
720 | break; | |
721 | } | |
722 | return true; | |
723 | } | |
724 | ||
9fedc3c0 AM |
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. | |
7ece864a | 739 | if (!contains_zero_p (lhs)) |
9fedc3c0 AM |
740 | return VREL_EQ; |
741 | return VREL_VARYING; | |
742 | } | |
743 | ||
4fbe3e6a | 744 | bool |
eb29c3e1 AM |
745 | operator_not_equal::fold_range (irange &r, tree type, |
746 | const frange &op1, const frange &op2, | |
66be6ed8 | 747 | relation_trio trio) const |
4fbe3e6a | 748 | { |
66be6ed8 AH |
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 | } | |
7a4e57ff AH |
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, VREL_NE)) | |
4fbe3e6a AH |
764 | return true; |
765 | ||
d2278da1 AH |
766 | // x != NAN is always TRUE. |
767 | if (op1.known_isnan () || op2.known_isnan ()) | |
768 | r = range_true (type); | |
4fbe3e6a AH |
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. | |
d2278da1 | 771 | else if (op1.singleton_p () && op2.singleton_p ()) |
4fbe3e6a | 772 | { |
09176201 | 773 | if (op1 == op2) |
4fbe3e6a | 774 | r = range_false (type); |
09176201 JJ |
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); | |
4fbe3e6a | 781 | } |
69044e11 JJ |
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); | |
5fe05ffe | 789 | else |
4fbe3e6a AH |
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 ()) | |
09176201 JJ |
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 | } | |
4fbe3e6a AH |
808 | else |
809 | r = range_true_and_false (type); | |
810 | } | |
4fbe3e6a AH |
811 | return true; |
812 | } | |
813 | ||
24012539 | 814 | bool |
eb29c3e1 AM |
815 | operator_not_equal::op1_range (frange &r, tree type, |
816 | const irange &lhs, | |
817 | const frange &op2, | |
818 | relation_trio trio) const | |
24012539 | 819 | { |
b565ac19 | 820 | relation_kind rel = trio.op1_op2 (); |
24012539 AH |
821 | switch (get_bool_state (r, lhs, type)) |
822 | { | |
823 | case BRS_TRUE: | |
4fbe3e6a AH |
824 | // If the result is true, the only time we know anything is if |
825 | // OP2 is a constant. | |
04874fed | 826 | if (op2.singleton_p ()) |
4fbe3e6a AH |
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 | } | |
04874fed AM |
834 | // The TRUE side of op1 != op1 implies op1 is NAN. |
835 | else if (rel == VREL_EQ) | |
836 | r.set_nan (type); | |
4fbe3e6a AH |
837 | else |
838 | r.set_varying (type); | |
24012539 AH |
839 | break; |
840 | ||
841 | case BRS_FALSE: | |
d2278da1 AH |
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 | } | |
24012539 AH |
854 | break; |
855 | ||
856 | default: | |
857 | break; | |
858 | } | |
859 | return true; | |
860 | } | |
861 | ||
9c739c98 AH |
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, op1, trio); | |
869 | } | |
9fedc3c0 AM |
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. | |
7ece864a | 885 | if (!contains_zero_p (lhs)) |
9fedc3c0 AM |
886 | return VREL_NE; |
887 | return VREL_VARYING; | |
888 | } | |
889 | ||
4fbe3e6a | 890 | bool |
5b079541 AM |
891 | operator_lt::fold_range (irange &r, tree type, |
892 | const frange &op1, const frange &op2, | |
66be6ed8 | 893 | relation_trio trio) const |
4fbe3e6a | 894 | { |
66be6ed8 | 895 | if (frelop_early_resolve (r, type, op1, op2, trio, VREL_LT)) |
4fbe3e6a AH |
896 | return true; |
897 | ||
5fe05ffe JJ |
898 | if (op1.known_isnan () |
899 | || op2.known_isnan () | |
900 | || !real_less (&op1.lower_bound (), &op2.upper_bound ())) | |
d2278da1 | 901 | r = range_false (type); |
5fe05ffe JJ |
902 | else if (!maybe_isnan (op1, op2) |
903 | && real_less (&op1.upper_bound (), &op2.lower_bound ())) | |
904 | r = range_true (type); | |
4fbe3e6a AH |
905 | else |
906 | r = range_true_and_false (type); | |
907 | return true; | |
908 | } | |
909 | ||
24012539 | 910 | bool |
5b079541 AM |
911 | operator_lt::op1_range (frange &r, |
912 | tree type, | |
913 | const irange &lhs, | |
914 | const frange &op2, | |
915 | relation_trio) const | |
24012539 AH |
916 | { |
917 | switch (get_bool_state (r, lhs, type)) | |
918 | { | |
919 | case BRS_TRUE: | |
d2278da1 AH |
920 | // The TRUE side of x < NAN is unreachable. |
921 | if (op2.known_isnan ()) | |
922 | r.set_undefined (); | |
10bd26d6 AH |
923 | else if (op2.undefined_p ()) |
924 | return false; | |
d2278da1 | 925 | else if (build_lt (r, type, op2)) |
f5dc9da0 | 926 | { |
9c4c4186 | 927 | r.clear_nan (); |
f5dc9da0 AH |
928 | // x < y implies x is not +INF. |
929 | frange_drop_inf (r, type); | |
930 | } | |
24012539 AH |
931 | break; |
932 | ||
933 | case BRS_FALSE: | |
d2278da1 | 934 | // On the FALSE side of x < NAN, we know nothing about x. |
36eec799 | 935 | if (op2.maybe_isnan ()) |
d2278da1 AH |
936 | r.set_varying (type); |
937 | else | |
938 | build_ge (r, type, op2); | |
24012539 AH |
939 | break; |
940 | ||
941 | default: | |
942 | break; | |
943 | } | |
944 | return true; | |
945 | } | |
946 | ||
947 | bool | |
5b079541 AM |
948 | operator_lt::op2_range (frange &r, |
949 | tree type, | |
950 | const irange &lhs, | |
951 | const frange &op1, | |
952 | relation_trio) const | |
24012539 AH |
953 | { |
954 | switch (get_bool_state (r, lhs, type)) | |
955 | { | |
956 | case BRS_TRUE: | |
d2278da1 AH |
957 | // The TRUE side of NAN < x is unreachable. |
958 | if (op1.known_isnan ()) | |
959 | r.set_undefined (); | |
10bd26d6 AH |
960 | else if (op1.undefined_p ()) |
961 | return false; | |
d2278da1 | 962 | else if (build_gt (r, type, op1)) |
f5dc9da0 | 963 | { |
9c4c4186 | 964 | r.clear_nan (); |
f5dc9da0 AH |
965 | // x < y implies y is not -INF. |
966 | frange_drop_ninf (r, type); | |
967 | } | |
24012539 AH |
968 | break; |
969 | ||
970 | case BRS_FALSE: | |
d2278da1 | 971 | // On the FALSE side of NAN < x, we know nothing about x. |
36eec799 | 972 | if (op1.maybe_isnan ()) |
d2278da1 AH |
973 | r.set_varying (type); |
974 | else | |
975 | build_le (r, type, op1); | |
24012539 AH |
976 | break; |
977 | ||
978 | default: | |
979 | break; | |
980 | } | |
981 | return true; | |
982 | } | |
983 | ||
9fedc3c0 AM |
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. | |
7ece864a | 999 | if (!contains_zero_p (lhs)) |
9fedc3c0 AM |
1000 | return VREL_LT; |
1001 | return VREL_VARYING; | |
1002 | } | |
1003 | ||
4fbe3e6a | 1004 | bool |
d251d14c AM |
1005 | operator_le::fold_range (irange &r, tree type, |
1006 | const frange &op1, const frange &op2, | |
1007 | relation_trio rel) const | |
4fbe3e6a AH |
1008 | { |
1009 | if (frelop_early_resolve (r, type, op1, op2, rel, VREL_LE)) | |
1010 | return true; | |
1011 | ||
5fe05ffe JJ |
1012 | if (op1.known_isnan () |
1013 | || op2.known_isnan () | |
1014 | || !real_compare (LE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) | |
d2278da1 | 1015 | r = range_false (type); |
5fe05ffe JJ |
1016 | else if (!maybe_isnan (op1, op2) |
1017 | && real_compare (LE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) | |
1018 | r = range_true (type); | |
4fbe3e6a AH |
1019 | else |
1020 | r = range_true_and_false (type); | |
1021 | return true; | |
1022 | } | |
1023 | ||
24012539 | 1024 | bool |
d251d14c AM |
1025 | operator_le::op1_range (frange &r, |
1026 | tree type, | |
1027 | const irange &lhs, | |
1028 | const frange &op2, | |
1029 | relation_trio) const | |
24012539 AH |
1030 | { |
1031 | switch (get_bool_state (r, lhs, type)) | |
1032 | { | |
1033 | case BRS_TRUE: | |
d2278da1 AH |
1034 | // The TRUE side of x <= NAN is unreachable. |
1035 | if (op2.known_isnan ()) | |
1036 | r.set_undefined (); | |
10bd26d6 AH |
1037 | else if (op2.undefined_p ()) |
1038 | return false; | |
d2278da1 | 1039 | else if (build_le (r, type, op2)) |
9c4c4186 | 1040 | r.clear_nan (); |
24012539 AH |
1041 | break; |
1042 | ||
1043 | case BRS_FALSE: | |
d2278da1 | 1044 | // On the FALSE side of x <= NAN, we know nothing about x. |
36eec799 | 1045 | if (op2.maybe_isnan ()) |
d2278da1 AH |
1046 | r.set_varying (type); |
1047 | else | |
1048 | build_gt (r, type, op2); | |
4fbe3e6a AH |
1049 | break; |
1050 | ||
1051 | default: | |
1052 | break; | |
1053 | } | |
1054 | return true; | |
1055 | } | |
1056 | ||
1057 | bool | |
d251d14c AM |
1058 | operator_le::op2_range (frange &r, |
1059 | tree type, | |
1060 | const irange &lhs, | |
1061 | const frange &op1, | |
1062 | relation_trio) const | |
4fbe3e6a AH |
1063 | { |
1064 | switch (get_bool_state (r, lhs, type)) | |
1065 | { | |
1066 | case BRS_TRUE: | |
d2278da1 AH |
1067 | // The TRUE side of NAN <= x is unreachable. |
1068 | if (op1.known_isnan ()) | |
1069 | r.set_undefined (); | |
10bd26d6 AH |
1070 | else if (op1.undefined_p ()) |
1071 | return false; | |
d2278da1 | 1072 | else if (build_ge (r, type, op1)) |
9c4c4186 | 1073 | r.clear_nan (); |
4fbe3e6a AH |
1074 | break; |
1075 | ||
1076 | case BRS_FALSE: | |
d2278da1 | 1077 | // On the FALSE side of NAN <= x, we know nothing about x. |
36eec799 | 1078 | if (op1.maybe_isnan ()) |
d2278da1 | 1079 | r.set_varying (type); |
10bd26d6 AH |
1080 | else if (op1.undefined_p ()) |
1081 | return false; | |
d2278da1 AH |
1082 | else |
1083 | build_lt (r, type, op1); | |
24012539 AH |
1084 | break; |
1085 | ||
1086 | default: | |
1087 | break; | |
1088 | } | |
1089 | return true; | |
1090 | } | |
1091 | ||
9fedc3c0 AM |
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. | |
7ece864a | 1106 | if (!contains_zero_p (lhs)) |
9fedc3c0 AM |
1107 | return VREL_LE; |
1108 | return VREL_VARYING; | |
1109 | } | |
1110 | ||
4fbe3e6a | 1111 | bool |
f544e7e8 AM |
1112 | operator_gt::fold_range (irange &r, tree type, |
1113 | const frange &op1, const frange &op2, | |
66be6ed8 | 1114 | relation_trio trio) const |
4fbe3e6a | 1115 | { |
66be6ed8 | 1116 | if (frelop_early_resolve (r, type, op1, op2, trio, VREL_GT)) |
4fbe3e6a AH |
1117 | return true; |
1118 | ||
5fe05ffe JJ |
1119 | if (op1.known_isnan () |
1120 | || op2.known_isnan () | |
1121 | || !real_compare (GT_EXPR, &op1.upper_bound (), &op2.lower_bound ())) | |
d2278da1 | 1122 | r = range_false (type); |
5fe05ffe JJ |
1123 | else if (!maybe_isnan (op1, op2) |
1124 | && real_compare (GT_EXPR, &op1.lower_bound (), &op2.upper_bound ())) | |
1125 | r = range_true (type); | |
4fbe3e6a AH |
1126 | else |
1127 | r = range_true_and_false (type); | |
1128 | return true; | |
1129 | } | |
1130 | ||
24012539 | 1131 | bool |
f544e7e8 AM |
1132 | operator_gt::op1_range (frange &r, |
1133 | tree type, | |
1134 | const irange &lhs, | |
1135 | const frange &op2, | |
1136 | relation_trio) const | |
24012539 AH |
1137 | { |
1138 | switch (get_bool_state (r, lhs, type)) | |
1139 | { | |
1140 | case BRS_TRUE: | |
d2278da1 AH |
1141 | // The TRUE side of x > NAN is unreachable. |
1142 | if (op2.known_isnan ()) | |
1143 | r.set_undefined (); | |
10bd26d6 AH |
1144 | else if (op2.undefined_p ()) |
1145 | return false; | |
d2278da1 | 1146 | else if (build_gt (r, type, op2)) |
f5dc9da0 | 1147 | { |
9c4c4186 | 1148 | r.clear_nan (); |
f5dc9da0 AH |
1149 | // x > y implies x is not -INF. |
1150 | frange_drop_ninf (r, type); | |
1151 | } | |
24012539 AH |
1152 | break; |
1153 | ||
1154 | case BRS_FALSE: | |
d2278da1 | 1155 | // On the FALSE side of x > NAN, we know nothing about x. |
36eec799 | 1156 | if (op2.maybe_isnan ()) |
d2278da1 | 1157 | r.set_varying (type); |
10bd26d6 AH |
1158 | else if (op2.undefined_p ()) |
1159 | return false; | |
d2278da1 AH |
1160 | else |
1161 | build_le (r, type, op2); | |
24012539 AH |
1162 | break; |
1163 | ||
1164 | default: | |
1165 | break; | |
1166 | } | |
1167 | return true; | |
1168 | } | |
1169 | ||
1170 | bool | |
f544e7e8 AM |
1171 | operator_gt::op2_range (frange &r, |
1172 | tree type, | |
1173 | const irange &lhs, | |
1174 | const frange &op1, | |
1175 | relation_trio) const | |
24012539 AH |
1176 | { |
1177 | switch (get_bool_state (r, lhs, type)) | |
1178 | { | |
1179 | case BRS_TRUE: | |
d2278da1 AH |
1180 | // The TRUE side of NAN > x is unreachable. |
1181 | if (op1.known_isnan ()) | |
1182 | r.set_undefined (); | |
10bd26d6 AH |
1183 | else if (op1.undefined_p ()) |
1184 | return false; | |
d2278da1 | 1185 | else if (build_lt (r, type, op1)) |
f5dc9da0 | 1186 | { |
9c4c4186 | 1187 | r.clear_nan (); |
f5dc9da0 AH |
1188 | // x > y implies y is not +INF. |
1189 | frange_drop_inf (r, type); | |
1190 | } | |
24012539 AH |
1191 | break; |
1192 | ||
1193 | case BRS_FALSE: | |
d2278da1 | 1194 | // On The FALSE side of NAN > x, we know nothing about x. |
36eec799 | 1195 | if (op1.maybe_isnan ()) |
d2278da1 | 1196 | r.set_varying (type); |
10bd26d6 AH |
1197 | else if (op1.undefined_p ()) |
1198 | return false; | |
d2278da1 AH |
1199 | else |
1200 | build_ge (r, type, op1); | |
24012539 AH |
1201 | break; |
1202 | ||
1203 | default: | |
1204 | break; | |
1205 | } | |
1206 | return true; | |
1207 | } | |
1208 | ||
9fedc3c0 AM |
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 (lhs)) | |
1224 | return VREL_GT; | |
1225 | return VREL_VARYING; | |
1226 | } | |
1227 | ||
4fbe3e6a | 1228 | bool |
a0a8f1c7 AM |
1229 | operator_ge::fold_range (irange &r, tree type, |
1230 | const frange &op1, const frange &op2, | |
1231 | relation_trio rel) const | |
4fbe3e6a AH |
1232 | { |
1233 | if (frelop_early_resolve (r, type, op1, op2, rel, VREL_GE)) | |
1234 | return true; | |
1235 | ||
5fe05ffe JJ |
1236 | if (op1.known_isnan () |
1237 | || op2.known_isnan () | |
1238 | || !real_compare (GE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) | |
d2278da1 | 1239 | r = range_false (type); |
5fe05ffe JJ |
1240 | else if (!maybe_isnan (op1, op2) |
1241 | && real_compare (GE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) | |
1242 | r = range_true (type); | |
4fbe3e6a AH |
1243 | else |
1244 | r = range_true_and_false (type); | |
1245 | return true; | |
1246 | } | |
1247 | ||
24012539 | 1248 | bool |
a0a8f1c7 AM |
1249 | operator_ge::op1_range (frange &r, |
1250 | tree type, | |
1251 | const irange &lhs, | |
1252 | const frange &op2, | |
1253 | relation_trio) const | |
24012539 AH |
1254 | { |
1255 | switch (get_bool_state (r, lhs, type)) | |
1256 | { | |
1257 | case BRS_TRUE: | |
d2278da1 AH |
1258 | // The TRUE side of x >= NAN is unreachable. |
1259 | if (op2.known_isnan ()) | |
1260 | r.set_undefined (); | |
10bd26d6 AH |
1261 | else if (op2.undefined_p ()) |
1262 | return false; | |
d2278da1 AH |
1263 | else if (build_ge (r, type, op2)) |
1264 | r.clear_nan (); | |
24012539 AH |
1265 | break; |
1266 | ||
1267 | case BRS_FALSE: | |
d2278da1 | 1268 | // On the FALSE side of x >= NAN, we know nothing about x. |
36eec799 | 1269 | if (op2.maybe_isnan ()) |
d2278da1 | 1270 | r.set_varying (type); |
10bd26d6 AH |
1271 | else if (op2.undefined_p ()) |
1272 | return false; | |
d2278da1 AH |
1273 | else |
1274 | build_lt (r, type, op2); | |
4fbe3e6a AH |
1275 | break; |
1276 | ||
1277 | default: | |
1278 | break; | |
1279 | } | |
1280 | return true; | |
1281 | } | |
1282 | ||
1283 | bool | |
a0a8f1c7 AM |
1284 | operator_ge::op2_range (frange &r, tree type, |
1285 | const irange &lhs, | |
1286 | const frange &op1, | |
1287 | relation_trio) const | |
4fbe3e6a AH |
1288 | { |
1289 | switch (get_bool_state (r, lhs, type)) | |
1290 | { | |
d2278da1 AH |
1291 | case BRS_TRUE: |
1292 | // The TRUE side of NAN >= x is unreachable. | |
1293 | if (op1.known_isnan ()) | |
1294 | r.set_undefined (); | |
10bd26d6 AH |
1295 | else if (op1.undefined_p ()) |
1296 | return false; | |
f0068278 AH |
1297 | else if (build_le (r, type, op1)) |
1298 | r.clear_nan (); | |
4fbe3e6a AH |
1299 | break; |
1300 | ||
d2278da1 AH |
1301 | case BRS_FALSE: |
1302 | // On the FALSE side of NAN >= x, we know nothing about x. | |
36eec799 | 1303 | if (op1.maybe_isnan ()) |
d2278da1 | 1304 | r.set_varying (type); |
10bd26d6 AH |
1305 | else if (op1.undefined_p ()) |
1306 | return false; | |
d2278da1 AH |
1307 | else |
1308 | build_gt (r, type, op1); | |
24012539 AH |
1309 | break; |
1310 | ||
1311 | default: | |
1312 | break; | |
1313 | } | |
1314 | return true; | |
1315 | } | |
1316 | ||
9fedc3c0 AM |
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 (lhs)) | |
1332 | return VREL_GE; | |
1333 | return VREL_VARYING; | |
1334 | } | |
1335 | ||
24012539 AH |
1336 | // UNORDERED_EXPR comparison. |
1337 | ||
9c0fed50 | 1338 | class foperator_unordered : public range_operator |
24012539 | 1339 | { |
9c0fed50 AM |
1340 | using range_operator::fold_range; |
1341 | using range_operator::op1_range; | |
1342 | using range_operator::op2_range; | |
24012539 AH |
1343 | public: |
1344 | bool fold_range (irange &r, tree type, | |
1345 | const frange &op1, const frange &op2, | |
b565ac19 | 1346 | relation_trio = TRIO_VARYING) const final override; |
24012539 AH |
1347 | bool op1_range (frange &r, tree type, |
1348 | const irange &lhs, const frange &op2, | |
b565ac19 | 1349 | relation_trio = TRIO_VARYING) const final override; |
24012539 AH |
1350 | bool op2_range (frange &r, tree type, |
1351 | const irange &lhs, const frange &op1, | |
b565ac19 | 1352 | relation_trio rel = TRIO_VARYING) const final override |
24012539 | 1353 | { |
b565ac19 | 1354 | return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); |
24012539 AH |
1355 | } |
1356 | } fop_unordered; | |
1357 | ||
1358 | bool | |
1359 | foperator_unordered::fold_range (irange &r, tree type, | |
1360 | const frange &op1, const frange &op2, | |
b565ac19 | 1361 | relation_trio) const |
24012539 AH |
1362 | { |
1363 | // UNORDERED is TRUE if either operand is a NAN. | |
91746147 | 1364 | if (op1.known_isnan () || op2.known_isnan ()) |
24012539 AH |
1365 | r = range_true (type); |
1366 | // UNORDERED is FALSE if neither operand is a NAN. | |
91746147 | 1367 | else if (!op1.maybe_isnan () && !op2.maybe_isnan ()) |
24012539 AH |
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, | |
d2278da1 | 1377 | const frange &op2, |
b565ac19 | 1378 | relation_trio trio) const |
24012539 | 1379 | { |
b565ac19 | 1380 | relation_kind rel = trio.op1_op2 (); |
24012539 AH |
1381 | switch (get_bool_state (r, lhs, type)) |
1382 | { | |
1383 | case BRS_TRUE: | |
24012539 AH |
1384 | // Since at least one operand must be NAN, if one of them is |
1385 | // not, the other must be. | |
04874fed | 1386 | if (rel == VREL_EQ || !op2.maybe_isnan ()) |
9c4c4186 | 1387 | r.set_nan (type); |
d2278da1 AH |
1388 | else |
1389 | r.set_varying (type); | |
24012539 AH |
1390 | break; |
1391 | ||
1392 | case BRS_FALSE: | |
d2278da1 AH |
1393 | // A false UNORDERED means both operands are !NAN, so it's |
1394 | // impossible for op2 to be a NAN. | |
04874fed | 1395 | if (op2.known_isnan ()) |
d2278da1 AH |
1396 | r.set_undefined (); |
1397 | else | |
1398 | { | |
1399 | r.set_varying (type); | |
1400 | r.clear_nan (); | |
1401 | } | |
24012539 AH |
1402 | break; |
1403 | ||
1404 | default: | |
1405 | break; | |
1406 | } | |
1407 | return true; | |
1408 | } | |
1409 | ||
1410 | // ORDERED_EXPR comparison. | |
1411 | ||
9c0fed50 | 1412 | class foperator_ordered : public range_operator |
24012539 | 1413 | { |
9c0fed50 AM |
1414 | using range_operator::fold_range; |
1415 | using range_operator::op1_range; | |
1416 | using range_operator::op2_range; | |
24012539 AH |
1417 | public: |
1418 | bool fold_range (irange &r, tree type, | |
1419 | const frange &op1, const frange &op2, | |
b565ac19 | 1420 | relation_trio = TRIO_VARYING) const final override; |
24012539 AH |
1421 | bool op1_range (frange &r, tree type, |
1422 | const irange &lhs, const frange &op2, | |
b565ac19 | 1423 | relation_trio = TRIO_VARYING) const final override; |
24012539 AH |
1424 | bool op2_range (frange &r, tree type, |
1425 | const irange &lhs, const frange &op1, | |
b565ac19 | 1426 | relation_trio rel = TRIO_VARYING) const final override |
24012539 | 1427 | { |
b565ac19 | 1428 | return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); |
24012539 AH |
1429 | } |
1430 | } fop_ordered; | |
1431 | ||
1432 | bool | |
1433 | foperator_ordered::fold_range (irange &r, tree type, | |
1434 | const frange &op1, const frange &op2, | |
b565ac19 | 1435 | relation_trio) const |
24012539 | 1436 | { |
d2278da1 | 1437 | if (op1.known_isnan () || op2.known_isnan ()) |
24012539 | 1438 | r = range_false (type); |
d2278da1 AH |
1439 | else if (!op1.maybe_isnan () && !op2.maybe_isnan ()) |
1440 | r = range_true (type); | |
24012539 AH |
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, | |
d2278da1 | 1449 | const frange &op2, |
b565ac19 | 1450 | relation_trio trio) const |
24012539 | 1451 | { |
b565ac19 | 1452 | relation_kind rel = trio.op1_op2 (); |
24012539 AH |
1453 | switch (get_bool_state (r, lhs, type)) |
1454 | { | |
1455 | case BRS_TRUE: | |
d2278da1 AH |
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 | } | |
24012539 AH |
1465 | break; |
1466 | ||
1467 | case BRS_FALSE: | |
04874fed | 1468 | // The FALSE side of op1 ORDERED op1 implies op1 is NAN. |
24012539 | 1469 | if (rel == VREL_EQ) |
04874fed AM |
1470 | r.set_nan (type); |
1471 | else | |
1472 | r.set_varying (type); | |
24012539 AH |
1473 | break; |
1474 | ||
1475 | default: | |
1476 | break; | |
1477 | } | |
1478 | return true; | |
1479 | } | |
1480 | ||
56518bef AM |
1481 | bool |
1482 | operator_negate::fold_range (frange &r, tree type, | |
1483 | const frange &op1, const frange &op2, | |
1484 | relation_trio) const | |
a0c1a059 | 1485 | { |
56518bef AM |
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 (sign)) | |
1492 | r.set_nan (type, !sign); | |
1493 | else | |
1494 | r.set_nan (type); | |
a0c1a059 | 1495 | return true; |
56518bef | 1496 | } |
a0c1a059 | 1497 | |
56518bef AM |
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 (sign)) | |
1507 | r.update_nan (!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, lhs, op2, rel); | |
1522 | } | |
a0c1a059 | 1523 | |
706d8583 | 1524 | bool |
a1aaaff3 AM |
1525 | operator_abs::fold_range (frange &r, tree type, |
1526 | const frange &op1, const frange &op2, | |
1527 | relation_trio) const | |
706d8583 AH |
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 (min, 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 | |
a1aaaff3 AM |
1575 | operator_abs::op1_range (frange &r, tree type, |
1576 | const frange &lhs, const frange &op2, | |
1577 | relation_trio) const | |
706d8583 AH |
1578 | { |
1579 | if (empty_range_varying (r, type, 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; | |
5bcd92d0 AH |
1592 | // Add -NAN if relevant. |
1593 | if (r.maybe_isnan ()) | |
1594 | { | |
1595 | frange neg_nan; | |
1596 | neg_nan.set_nan (type, true); | |
1597 | r.union_ (neg_nan); | |
1598 | } | |
4e306222 | 1599 | if (r.known_isnan () || r.undefined_p ()) |
5bcd92d0 | 1600 | return true; |
706d8583 AH |
1601 | // Then add the negative of each pair: |
1602 | // ABS(op1) = [5,20] would yield op1 => [-20,-5][5,20]. | |
d943927f JJ |
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); | |
706d8583 AH |
1607 | return true; |
1608 | } | |
1609 | ||
9c0fed50 | 1610 | class foperator_unordered_lt : public range_operator |
4cbc312a | 1611 | { |
9c0fed50 AM |
1612 | using range_operator::fold_range; |
1613 | using range_operator::op1_range; | |
1614 | using range_operator::op2_range; | |
4cbc312a AH |
1615 | public: |
1616 | bool fold_range (irange &r, tree type, | |
1617 | const frange &op1, const frange &op2, | |
66be6ed8 | 1618 | relation_trio trio = TRIO_VARYING) const final override |
4cbc312a | 1619 | { |
0bd96163 | 1620 | if (op1.known_isnan () || op2.known_isnan ()) |
4cbc312a AH |
1621 | { |
1622 | r = range_true (type); | |
1623 | return true; | |
1624 | } | |
e02c9d91 JJ |
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 (); | |
5b079541 | 1631 | if (!range_op_handler (LT_EXPR).fold_range (r, type, op1_no_nan, |
66be6ed8 | 1632 | op2_no_nan, trio)) |
4cbc312a AH |
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. | |
be43d5d3 | 1636 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
4cbc312a AH |
1637 | return true; |
1638 | else | |
1639 | { | |
1640 | r = range_true_and_false (type); | |
1641 | return true; | |
1642 | } | |
1643 | } | |
2e158eae AH |
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; | |
4cbc312a | 1652 | } fop_unordered_lt; |
24012539 | 1653 | |
2e158eae AH |
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, type)) | |
1661 | { | |
1662 | case BRS_TRUE: | |
36eec799 | 1663 | if (op2.maybe_isnan ()) |
bdf00185 | 1664 | r.set_varying (type); |
10bd26d6 AH |
1665 | else if (op2.undefined_p ()) |
1666 | return false; | |
bdf00185 AH |
1667 | else |
1668 | build_lt (r, type, op2); | |
2e158eae AH |
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 (); | |
10bd26d6 AH |
1676 | else if (op2.undefined_p ()) |
1677 | return false; | |
2e158eae AH |
1678 | else if (build_ge (r, type, 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, type)) | |
1695 | { | |
1696 | case BRS_TRUE: | |
36eec799 | 1697 | if (op1.maybe_isnan ()) |
bdf00185 | 1698 | r.set_varying (type); |
10bd26d6 AH |
1699 | else if (op1.undefined_p ()) |
1700 | return false; | |
bdf00185 AH |
1701 | else |
1702 | build_gt (r, type, op1); | |
2e158eae AH |
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 (); | |
10bd26d6 AH |
1710 | else if (op1.undefined_p ()) |
1711 | return false; | |
2e158eae AH |
1712 | else if (build_le (r, type, op1)) |
1713 | r.clear_nan (); | |
1714 | break; | |
1715 | ||
1716 | default: | |
1717 | break; | |
1718 | } | |
1719 | return true; | |
1720 | } | |
1721 | ||
9c0fed50 | 1722 | class foperator_unordered_le : public range_operator |
24012539 | 1723 | { |
9c0fed50 AM |
1724 | using range_operator::fold_range; |
1725 | using range_operator::op1_range; | |
1726 | using range_operator::op2_range; | |
4cbc312a AH |
1727 | public: |
1728 | bool fold_range (irange &r, tree type, | |
1729 | const frange &op1, const frange &op2, | |
66be6ed8 | 1730 | relation_trio trio = TRIO_VARYING) const final override |
4cbc312a | 1731 | { |
0bd96163 | 1732 | if (op1.known_isnan () || op2.known_isnan ()) |
4cbc312a AH |
1733 | { |
1734 | r = range_true (type); | |
1735 | return true; | |
1736 | } | |
e02c9d91 JJ |
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 (); | |
d251d14c | 1743 | if (!range_op_handler (LE_EXPR).fold_range (r, type, op1_no_nan, |
66be6ed8 | 1744 | op2_no_nan, trio)) |
4cbc312a AH |
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. | |
be43d5d3 | 1748 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
4cbc312a AH |
1749 | return true; |
1750 | else | |
1751 | { | |
1752 | r = range_true_and_false (type); | |
1753 | return true; | |
1754 | } | |
1755 | } | |
fe7371e7 AH |
1756 | bool op1_range (frange &r, tree type, |
1757 | const irange &lhs, const frange &op2, | |
b565ac19 | 1758 | relation_trio = TRIO_VARYING) const final override; |
fe7371e7 AH |
1759 | bool op2_range (frange &r, tree type, |
1760 | const irange &lhs, const frange &op1, | |
b565ac19 | 1761 | relation_trio = TRIO_VARYING) const final override; |
4cbc312a | 1762 | } fop_unordered_le; |
24012539 | 1763 | |
fe7371e7 AH |
1764 | bool |
1765 | foperator_unordered_le::op1_range (frange &r, tree type, | |
1766 | const irange &lhs, const frange &op2, | |
b565ac19 | 1767 | relation_trio) const |
fe7371e7 AH |
1768 | { |
1769 | switch (get_bool_state (r, lhs, type)) | |
1770 | { | |
1771 | case BRS_TRUE: | |
36eec799 | 1772 | if (op2.maybe_isnan ()) |
bdf00185 | 1773 | r.set_varying (type); |
10bd26d6 AH |
1774 | else if (op2.undefined_p ()) |
1775 | return false; | |
bdf00185 AH |
1776 | else |
1777 | build_le (r, type, op2); | |
fe7371e7 AH |
1778 | break; |
1779 | ||
1780 | case BRS_FALSE: | |
3dfdc0d1 AH |
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, op2)) | |
f0068278 | 1786 | r.clear_nan (); |
fe7371e7 AH |
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, | |
b565ac19 | 1800 | relation_trio) const |
fe7371e7 AH |
1801 | { |
1802 | switch (get_bool_state (r, lhs, type)) | |
1803 | { | |
1804 | case BRS_TRUE: | |
36eec799 | 1805 | if (op1.maybe_isnan ()) |
bdf00185 | 1806 | r.set_varying (type); |
10bd26d6 AH |
1807 | else if (op1.undefined_p ()) |
1808 | return false; | |
bdf00185 AH |
1809 | else |
1810 | build_ge (r, type, op1); | |
fe7371e7 AH |
1811 | break; |
1812 | ||
1813 | case BRS_FALSE: | |
3dfdc0d1 AH |
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 (); | |
10bd26d6 AH |
1818 | else if (op1.undefined_p ()) |
1819 | return false; | |
3dfdc0d1 | 1820 | else if (build_lt (r, type, op1)) |
f0068278 | 1821 | r.clear_nan (); |
fe7371e7 AH |
1822 | break; |
1823 | ||
1824 | default: | |
1825 | break; | |
1826 | } | |
1827 | return true; | |
1828 | } | |
1829 | ||
9c0fed50 | 1830 | class foperator_unordered_gt : public range_operator |
4cbc312a | 1831 | { |
9c0fed50 AM |
1832 | using range_operator::fold_range; |
1833 | using range_operator::op1_range; | |
1834 | using range_operator::op2_range; | |
24012539 AH |
1835 | public: |
1836 | bool fold_range (irange &r, tree type, | |
d2278da1 | 1837 | const frange &op1, const frange &op2, |
66be6ed8 | 1838 | relation_trio trio = TRIO_VARYING) const final override |
24012539 | 1839 | { |
0bd96163 | 1840 | if (op1.known_isnan () || op2.known_isnan ()) |
4cbc312a AH |
1841 | { |
1842 | r = range_true (type); | |
1843 | return true; | |
1844 | } | |
e02c9d91 JJ |
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 (); | |
f544e7e8 | 1851 | if (!range_op_handler (GT_EXPR).fold_range (r, type, op1_no_nan, |
66be6ed8 | 1852 | op2_no_nan, trio)) |
4cbc312a AH |
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. | |
be43d5d3 | 1856 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
4cbc312a | 1857 | return true; |
d2278da1 | 1858 | else |
4cbc312a AH |
1859 | { |
1860 | r = range_true_and_false (type); | |
1861 | return true; | |
1862 | } | |
1863 | } | |
fe7371e7 AH |
1864 | bool op1_range (frange &r, tree type, |
1865 | const irange &lhs, const frange &op2, | |
b565ac19 | 1866 | relation_trio = TRIO_VARYING) const final override; |
fe7371e7 AH |
1867 | bool op2_range (frange &r, tree type, |
1868 | const irange &lhs, const frange &op1, | |
b565ac19 | 1869 | relation_trio = TRIO_VARYING) const final override; |
4cbc312a AH |
1870 | } fop_unordered_gt; |
1871 | ||
fe7371e7 AH |
1872 | bool |
1873 | foperator_unordered_gt::op1_range (frange &r, | |
1874 | tree type, | |
1875 | const irange &lhs, | |
1876 | const frange &op2, | |
b565ac19 | 1877 | relation_trio) const |
fe7371e7 AH |
1878 | { |
1879 | switch (get_bool_state (r, lhs, type)) | |
1880 | { | |
1881 | case BRS_TRUE: | |
36eec799 | 1882 | if (op2.maybe_isnan ()) |
bdf00185 | 1883 | r.set_varying (type); |
10bd26d6 AH |
1884 | else if (op2.undefined_p ()) |
1885 | return false; | |
bdf00185 AH |
1886 | else |
1887 | build_gt (r, type, op2); | |
fe7371e7 AH |
1888 | break; |
1889 | ||
1890 | case BRS_FALSE: | |
3dfdc0d1 AH |
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 (); | |
10bd26d6 AH |
1895 | else if (op2.undefined_p ()) |
1896 | return false; | |
3dfdc0d1 | 1897 | else if (build_le (r, type, op2)) |
f0068278 | 1898 | r.clear_nan (); |
fe7371e7 AH |
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, | |
b565ac19 | 1912 | relation_trio) const |
fe7371e7 AH |
1913 | { |
1914 | switch (get_bool_state (r, lhs, type)) | |
1915 | { | |
1916 | case BRS_TRUE: | |
36eec799 | 1917 | if (op1.maybe_isnan ()) |
bdf00185 | 1918 | r.set_varying (type); |
10bd26d6 AH |
1919 | else if (op1.undefined_p ()) |
1920 | return false; | |
bdf00185 AH |
1921 | else |
1922 | build_lt (r, type, op1); | |
fe7371e7 AH |
1923 | break; |
1924 | ||
1925 | case BRS_FALSE: | |
3dfdc0d1 AH |
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 (); | |
10bd26d6 AH |
1930 | else if (op1.undefined_p ()) |
1931 | return false; | |
3dfdc0d1 | 1932 | else if (build_ge (r, type, op1)) |
f0068278 | 1933 | r.clear_nan (); |
fe7371e7 AH |
1934 | break; |
1935 | ||
1936 | default: | |
1937 | break; | |
1938 | } | |
1939 | return true; | |
1940 | } | |
1941 | ||
9c0fed50 | 1942 | class foperator_unordered_ge : public range_operator |
4cbc312a | 1943 | { |
9c0fed50 AM |
1944 | using range_operator::fold_range; |
1945 | using range_operator::op1_range; | |
1946 | using range_operator::op2_range; | |
4cbc312a AH |
1947 | public: |
1948 | bool fold_range (irange &r, tree type, | |
1949 | const frange &op1, const frange &op2, | |
66be6ed8 | 1950 | relation_trio trio = TRIO_VARYING) const final override |
4cbc312a | 1951 | { |
0bd96163 | 1952 | if (op1.known_isnan () || op2.known_isnan ()) |
4cbc312a AH |
1953 | { |
1954 | r = range_true (type); | |
1955 | return true; | |
1956 | } | |
e02c9d91 JJ |
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 (); | |
a0a8f1c7 | 1963 | if (!range_op_handler (GE_EXPR).fold_range (r, type, op1_no_nan, |
66be6ed8 | 1964 | op2_no_nan, trio)) |
4cbc312a AH |
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. | |
be43d5d3 | 1968 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
4cbc312a AH |
1969 | return true; |
1970 | else | |
1971 | { | |
1972 | r = range_true_and_false (type); | |
1973 | return true; | |
1974 | } | |
1975 | } | |
fe7371e7 AH |
1976 | bool op1_range (frange &r, tree type, |
1977 | const irange &lhs, const frange &op2, | |
b565ac19 | 1978 | relation_trio = TRIO_VARYING) const final override; |
fe7371e7 AH |
1979 | bool op2_range (frange &r, tree type, |
1980 | const irange &lhs, const frange &op1, | |
b565ac19 | 1981 | relation_trio = TRIO_VARYING) const final override; |
4cbc312a AH |
1982 | } fop_unordered_ge; |
1983 | ||
fe7371e7 AH |
1984 | bool |
1985 | foperator_unordered_ge::op1_range (frange &r, | |
1986 | tree type, | |
1987 | const irange &lhs, | |
1988 | const frange &op2, | |
b565ac19 | 1989 | relation_trio) const |
fe7371e7 AH |
1990 | { |
1991 | switch (get_bool_state (r, lhs, type)) | |
1992 | { | |
1993 | case BRS_TRUE: | |
36eec799 | 1994 | if (op2.maybe_isnan ()) |
bdf00185 | 1995 | r.set_varying (type); |
10bd26d6 AH |
1996 | else if (op2.undefined_p ()) |
1997 | return false; | |
bdf00185 AH |
1998 | else |
1999 | build_ge (r, type, op2); | |
fe7371e7 AH |
2000 | break; |
2001 | ||
2002 | case BRS_FALSE: | |
3dfdc0d1 AH |
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 (); | |
10bd26d6 AH |
2007 | else if (op2.undefined_p ()) |
2008 | return false; | |
3dfdc0d1 | 2009 | else if (build_lt (r, type, op2)) |
f0068278 | 2010 | r.clear_nan (); |
fe7371e7 AH |
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, | |
b565ac19 | 2023 | relation_trio) const |
fe7371e7 AH |
2024 | { |
2025 | switch (get_bool_state (r, lhs, type)) | |
2026 | { | |
2027 | case BRS_TRUE: | |
36eec799 | 2028 | if (op1.maybe_isnan ()) |
bdf00185 | 2029 | r.set_varying (type); |
10bd26d6 AH |
2030 | else if (op1.undefined_p ()) |
2031 | return false; | |
bdf00185 AH |
2032 | else |
2033 | build_le (r, type, op1); | |
fe7371e7 AH |
2034 | break; |
2035 | ||
2036 | case BRS_FALSE: | |
3dfdc0d1 AH |
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 (); | |
10bd26d6 AH |
2041 | else if (op1.undefined_p ()) |
2042 | return false; | |
3dfdc0d1 | 2043 | else if (build_gt (r, type, op1)) |
f0068278 | 2044 | r.clear_nan (); |
fe7371e7 AH |
2045 | break; |
2046 | ||
2047 | default: | |
2048 | break; | |
2049 | } | |
2050 | return true; | |
2051 | } | |
2052 | ||
9c0fed50 | 2053 | class foperator_unordered_equal : public range_operator |
4cbc312a | 2054 | { |
9c0fed50 AM |
2055 | using range_operator::fold_range; |
2056 | using range_operator::op1_range; | |
2057 | using range_operator::op2_range; | |
4cbc312a AH |
2058 | public: |
2059 | bool fold_range (irange &r, tree type, | |
2060 | const frange &op1, const frange &op2, | |
66be6ed8 | 2061 | relation_trio trio = TRIO_VARYING) const final override |
4cbc312a | 2062 | { |
7a4e57ff | 2063 | if (op1.known_isnan () || op2.known_isnan ()) |
4cbc312a AH |
2064 | { |
2065 | r = range_true (type); | |
2066 | return true; | |
2067 | } | |
e02c9d91 JJ |
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 (); | |
2dbf1e61 | 2074 | if (!range_op_handler (EQ_EXPR).fold_range (r, type, op1_no_nan, |
66be6ed8 | 2075 | op2_no_nan, trio)) |
4cbc312a AH |
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. | |
be43d5d3 | 2079 | if (!maybe_isnan (op1, op2) || r == range_true (type)) |
4cbc312a AH |
2080 | return true; |
2081 | else | |
2082 | { | |
2083 | r = range_true_and_false (type); | |
2084 | return true; | |
2085 | } | |
24012539 | 2086 | } |
fe7371e7 AH |
2087 | bool op1_range (frange &r, tree type, |
2088 | const irange &lhs, const frange &op2, | |
b565ac19 | 2089 | relation_trio = TRIO_VARYING) const final override; |
fe7371e7 AH |
2090 | bool op2_range (frange &r, tree type, |
2091 | const irange &lhs, const frange &op1, | |
b565ac19 | 2092 | relation_trio rel = TRIO_VARYING) const final override |
fe7371e7 | 2093 | { |
b565ac19 | 2094 | return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); |
fe7371e7 | 2095 | } |
4cbc312a | 2096 | } fop_unordered_equal; |
24012539 | 2097 | |
fe7371e7 AH |
2098 | bool |
2099 | foperator_unordered_equal::op1_range (frange &r, tree type, | |
2100 | const irange &lhs, | |
2101 | const frange &op2, | |
b565ac19 | 2102 | relation_trio) const |
fe7371e7 AH |
2103 | { |
2104 | switch (get_bool_state (r, lhs, 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); | |
c46b5b0a | 2111 | // Add the possibility of a NAN. |
fe7371e7 AH |
2112 | r.update_nan (); |
2113 | break; | |
2114 | ||
2115 | case BRS_FALSE: | |
3dfdc0d1 AH |
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 | { | |
c46b5b0a | 2122 | // The false side indicates !NAN and not equal. We can at least |
3dfdc0d1 AH |
2123 | // represent !NAN. |
2124 | r.set_varying (type); | |
2125 | r.clear_nan (); | |
2126 | } | |
fe7371e7 AH |
2127 | break; |
2128 | ||
2129 | default: | |
2130 | break; | |
2131 | } | |
2132 | return true; | |
2133 | } | |
a6efab5f | 2134 | |
9c0fed50 | 2135 | class foperator_ltgt : public range_operator |
5fe05ffe | 2136 | { |
9c0fed50 AM |
2137 | using range_operator::fold_range; |
2138 | using range_operator::op1_range; | |
2139 | using range_operator::op2_range; | |
5fe05ffe JJ |
2140 | public: |
2141 | bool fold_range (irange &r, tree type, | |
2142 | const frange &op1, const frange &op2, | |
979e0fbf | 2143 | relation_trio trio = TRIO_VARYING) const final override |
5fe05ffe JJ |
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 (); | |
eb29c3e1 | 2156 | if (!range_op_handler (NE_EXPR).fold_range (r, type, op1_no_nan, |
979e0fbf | 2157 | op2_no_nan, trio)) |
5fe05ffe JJ |
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, 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, 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 | ||
d4c2f1d3 JJ |
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, | |
a0ee2e52 | 2222 | const frange &lhs, bool div_op2 = false) |
d4c2f1d3 JJ |
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. | |
7c6cd9c0 | 2232 | // If NANs aren't honored, we get for 0 / 0 UNDEFINED, so punt as well. |
d4c2f1d3 | 2233 | // Or if lhs is a known NAN, we also don't know anything. |
7c6cd9c0 | 2234 | if (r.known_isnan () || lhs.known_isnan () || r.undefined_p ()) |
d4c2f1d3 JJ |
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 ()) | |
a0ee2e52 JJ |
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 | } | |
d4c2f1d3 JJ |
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 | ||
5747470e JJ |
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, 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) | |
19cb965e | 2313 | lb = dconstm0; |
5747470e JJ |
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; | |
19cb965e | 2347 | ub = dconstm0; |
5747470e JJ |
2348 | } |
2349 | else | |
2350 | { | |
2351 | lb = dconstninf; | |
2352 | ub = dconstinf; | |
2353 | } | |
2354 | } | |
2355 | ||
bad177e8 JJ |
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. | |
44f80a37 JJ |
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. */ | |
bad177e8 JJ |
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)) | |
a1d5c729 JJ |
2374 | { |
2375 | frange_nextafter (TYPE_MODE (type), lb, 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 | } | |
44f80a37 JJ |
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 | } | |
a1d5c729 | 2395 | } |
bad177e8 | 2396 | if (real_isfinite (&ub)) |
a1d5c729 JJ |
2397 | { |
2398 | frange_nextafter (TYPE_MODE (type), ub, 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 | } | |
44f80a37 JJ |
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 | } | |
a1d5c729 JJ |
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; | |
ccaee0d2 | 2419 | ret.set (type, lb, ub, lhs.get_nan_state ()); |
a1d5c729 | 2420 | flag_finite_math_only = save_flag_finite_math_only; |
bad177e8 JJ |
2421 | return ret; |
2422 | } | |
2423 | ||
29dbd7ef AM |
2424 | bool |
2425 | operator_plus::op1_range (frange &r, tree type, const frange &lhs, | |
2426 | const frange &op2, relation_trio) const | |
9d96a286 | 2427 | { |
29dbd7ef AM |
2428 | if (lhs.undefined_p ()) |
2429 | return false; | |
2eb50117 | 2430 | range_op_handler minus (MINUS_EXPR); |
29dbd7ef AM |
2431 | if (!minus) |
2432 | return false; | |
2433 | frange wlhs = float_widen_lhs_range (type, lhs); | |
2434 | return float_binary_op_range_finish (minus.fold_range (r, type, wlhs, op2), | |
2435 | r, type, wlhs); | |
2436 | } | |
0ef5649e | 2437 | |
29dbd7ef AM |
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, op1); | |
2444 | } | |
2445 | ||
2446 | void | |
24e97ac4 | 2447 | operator_plus::rv_fold (frange &r, tree type, |
29dbd7ef AM |
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 | { | |
848b5f3a AH |
2454 | REAL_VALUE_TYPE lb, ub; |
2455 | bool maybe_nan = false; | |
2456 | ||
29dbd7ef AM |
2457 | frange_arithmetic (PLUS_EXPR, type, lb, lh_lb, rh_lb, dconstninf); |
2458 | frange_arithmetic (PLUS_EXPR, type, ub, lh_ub, rh_ub, dconstinf); | |
2459 | ||
2460 | // [-INF] + [+INF] = NAN | |
2461 | if (real_isinf (&lh_lb, true) && real_isinf (&rh_ub, false)) | |
2462 | maybe_nan = true; | |
2463 | // [+INF] + [-INF] = NAN | |
2464 | else if (real_isinf (&lh_ub, false) && real_isinf (&rh_lb, true)) | |
2465 | maybe_nan = true; | |
24e97ac4 AH |
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)); | |
29dbd7ef | 2481 | } |
9d96a286 | 2482 | |
9d96a286 | 2483 | |
d5818a36 AM |
2484 | bool |
2485 | operator_minus::op1_range (frange &r, tree type, | |
2486 | const frange &lhs, const frange &op2, | |
2487 | relation_trio) const | |
38ec5e4b | 2488 | { |
d5818a36 AM |
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 | range_op_handler (PLUS_EXPR).fold_range (r, type, wlhs, op2), | |
2494 | r, type, wlhs); | |
2495 | } | |
38ec5e4b | 2496 | |
d5818a36 AM |
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 (fold_range (r, type, op1, wlhs), | |
2506 | r, type, wlhs); | |
2507 | } | |
2508 | ||
2509 | void | |
24e97ac4 | 2510 | operator_minus::rv_fold (frange &r, tree type, |
d5818a36 AM |
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 | { | |
848b5f3a AH |
2517 | REAL_VALUE_TYPE lb, ub; |
2518 | bool maybe_nan = false; | |
2519 | ||
d5818a36 AM |
2520 | frange_arithmetic (MINUS_EXPR, type, lb, lh_lb, rh_ub, dconstninf); |
2521 | frange_arithmetic (MINUS_EXPR, type, ub, lh_ub, rh_lb, dconstinf); | |
2522 | ||
2523 | // [+INF] - [+INF] = NAN | |
2524 | if (real_isinf (&lh_ub, false) && real_isinf (&rh_ub, false)) | |
2525 | maybe_nan = true; | |
2526 | // [-INF] - [-INF] = NAN | |
2527 | else if (real_isinf (&lh_lb, true) && real_isinf (&rh_lb, true)) | |
2528 | maybe_nan = true; | |
24e97ac4 AH |
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)); | |
d5818a36 | 2544 | } |
38ec5e4b | 2545 | |
2f7f9edd | 2546 | |
a13c4440 AM |
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 | } | |
5747470e JJ |
2568 | |
2569 | ||
a13c4440 AM |
2570 | bool |
2571 | operator_mult::op1_range (frange &r, tree type, | |
2572 | const frange &lhs, const frange &op2, | |
2573 | relation_trio) const | |
2f7f9edd | 2574 | { |
a13c4440 AM |
2575 | if (lhs.undefined_p ()) |
2576 | return false; | |
2eb50117 | 2577 | range_op_handler rdiv (RDIV_EXPR); |
a13c4440 AM |
2578 | if (!rdiv) |
2579 | return false; | |
2580 | frange wlhs = float_widen_lhs_range (type, lhs); | |
2581 | bool ret = rdiv.fold_range (r, type, wlhs, op2); | |
2582 | if (ret == false) | |
2583 | return false; | |
2584 | if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) | |
bad177e8 | 2585 | return float_binary_op_range_finish (ret, r, type, wlhs); |
a13c4440 AM |
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 (lhs_lb, lhs_ub) && contains_zero_p (op2_lb, 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 (lhs_lb, lhs_ub, op2_lb, 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, wlhs); | |
2607 | } | |
2f7f9edd | 2608 | |
a13c4440 AM |
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, op1); | |
2615 | } | |
2f7f9edd | 2616 | |
a13c4440 | 2617 | void |
24e97ac4 | 2618 | operator_mult::rv_fold (frange &r, tree type, |
a13c4440 AM |
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)); | |
848b5f3a AH |
2631 | REAL_VALUE_TYPE lb, ub; |
2632 | bool maybe_nan = false; | |
a13c4440 AM |
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 (lh_lb, lh_ub) && singleton_inf_p (rh_lb, rh_ub)) | |
2639 | || (zero_p (rh_lb, rh_ub) && singleton_inf_p (lh_lb, lh_ub))) | |
2640 | { | |
24e97ac4 | 2641 | r.set_nan (type); |
a13c4440 AM |
2642 | return; |
2643 | } | |
2f7f9edd | 2644 | |
a13c4440 AM |
2645 | // Otherwise, if one range includes zero and the other ends with +-INF, |
2646 | // it is a maybe NAN. | |
2647 | if ((contains_zero_p (lh_lb, lh_ub) | |
2648 | && (real_isinf (&rh_lb) || real_isinf (&rh_ub))) | |
2649 | || (contains_zero_p (rh_lb, 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 (lh_lb, lh_ub) | |
2662 | || singleton_inf_p (rh_lb, rh_ub)) | |
24e97ac4 AH |
2663 | { |
2664 | inf_range (lb, ub, signbit_known); | |
2665 | r.set (type, lb, ub, nan_state (true)); | |
2666 | return; | |
2667 | } | |
a13c4440 AM |
2668 | |
2669 | // If one of the multiplicands must be zero, the resulting | |
2670 | // range is +-0 and NAN. | |
2671 | if (zero_p (lh_lb, lh_ub) || zero_p (rh_lb, rh_ub)) | |
24e97ac4 AH |
2672 | { |
2673 | zero_range (lb, ub, signbit_known); | |
2674 | r.set (type, lb, ub, nan_state (true)); | |
2675 | return; | |
2676 | } | |
a13c4440 AM |
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. | |
24e97ac4 AH |
2684 | zero_to_inf_range (lb, ub, signbit_known); |
2685 | r.set (type, lb, ub, nan_state (true)); | |
2686 | return; | |
a13c4440 AM |
2687 | } |
2688 | } | |
2f7f9edd | 2689 | |
a13c4440 AM |
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 (MULT_EXPR, type, cp[0], lh_lb, rh_lb, dconstninf); | |
2694 | frange_arithmetic (MULT_EXPR, type, cp[4], lh_lb, rh_lb, 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 (lh_lb, 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 (MULT_EXPR, type, cp[1], lh_lb, rh_ub, dconstninf); | |
2718 | frange_arithmetic (MULT_EXPR, type, cp[5], lh_lb, rh_ub, dconstinf); | |
2719 | frange_arithmetic (MULT_EXPR, type, cp[2], lh_ub, rh_lb, dconstninf); | |
2720 | frange_arithmetic (MULT_EXPR, type, cp[6], lh_ub, rh_lb, dconstinf); | |
2721 | } | |
2722 | frange_arithmetic (MULT_EXPR, type, cp[3], lh_ub, rh_ub, dconstninf); | |
2723 | frange_arithmetic (MULT_EXPR, type, cp[7], lh_ub, rh_ub, dconstinf); | |
5747470e | 2724 | |
a13c4440 | 2725 | find_range (lb, ub, cp); |
24e97ac4 AH |
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)); | |
a13c4440 AM |
2730 | } |
2731 | ||
2732 | ||
2733 | class foperator_div : public range_operator | |
2d5c4a16 | 2734 | { |
9c0fed50 AM |
2735 | using range_operator::op1_range; |
2736 | using range_operator::op2_range; | |
d4c2f1d3 JJ |
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; | |
bad177e8 | 2745 | frange wlhs = float_widen_lhs_range (type, lhs); |
a13c4440 | 2746 | bool ret = range_op_handler (MULT_EXPR).fold_range (r, type, wlhs, op2); |
4500baac JJ |
2747 | if (!ret) |
2748 | return ret; | |
bad177e8 JJ |
2749 | if (wlhs.known_isnan () || op2.known_isnan () || op2.undefined_p ()) |
2750 | return float_binary_op_range_finish (ret, r, type, wlhs); | |
2751 | const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); | |
2752 | const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); | |
4500baac JJ |
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 (lhs_lb, lhs_ub) | |
2756 | && (real_isinf (&op2_lb) || real_isinf (&op2_ub))) | |
2757 | || ((contains_zero_p (op2_lb, 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 (lhs_lb, lhs_ub, op2_lb, op2_ub); | |
2765 | zero_to_inf_range (lb, ub, signbit_known); | |
2766 | r.set (type, lb, ub); | |
2767 | } | |
bad177e8 | 2768 | return float_binary_op_range_finish (ret, r, type, wlhs); |
d4c2f1d3 JJ |
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; | |
bad177e8 JJ |
2777 | frange wlhs = float_widen_lhs_range (type, lhs); |
2778 | bool ret = fold_range (r, type, op1, wlhs); | |
4500baac JJ |
2779 | if (!ret) |
2780 | return ret; | |
bad177e8 JJ |
2781 | if (wlhs.known_isnan () || op1.known_isnan () || op1.undefined_p ()) |
2782 | return float_binary_op_range_finish (ret, r, type, wlhs, true); | |
2783 | const REAL_VALUE_TYPE &lhs_lb = wlhs.lower_bound (); | |
2784 | const REAL_VALUE_TYPE &lhs_ub = wlhs.upper_bound (); | |
4500baac JJ |
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 (lhs_lb, lhs_ub) && contains_zero_p (op1_lb, 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 (lhs_lb, lhs_ub, op1_lb, op1_ub); | |
2796 | zero_to_inf_range (lb, ub, signbit_known); | |
2797 | r.set (type, lb, ub); | |
2798 | } | |
bad177e8 | 2799 | return float_binary_op_range_finish (ret, r, type, wlhs, true); |
d4c2f1d3 JJ |
2800 | } |
2801 | private: | |
24e97ac4 | 2802 | void rv_fold (frange &r, tree type, |
2d5c4a16 JJ |
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. | |
5747470e | 2810 | if ((zero_p (lh_lb, lh_ub) && zero_p (rh_lb, rh_ub)) |
4500baac | 2811 | || (singleton_inf_p (lh_lb, lh_ub) && singleton_inf_p (rh_lb, rh_ub))) |
2d5c4a16 | 2812 | { |
24e97ac4 | 2813 | r.set_nan (type); |
2d5c4a16 JJ |
2814 | return; |
2815 | } | |
2816 | ||
848b5f3a AH |
2817 | REAL_VALUE_TYPE lb, ub; |
2818 | bool maybe_nan = false; | |
2d5c4a16 | 2819 | // If +-0.0 is in both ranges, it is a maybe NAN. |
5747470e JJ |
2820 | if (contains_zero_p (lh_lb, lh_ub) && contains_zero_p (rh_lb, rh_ub)) |
2821 | maybe_nan = true; | |
2d5c4a16 JJ |
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))) | |
5747470e | 2825 | maybe_nan = true; |
2d5c4a16 | 2826 | |
5747470e | 2827 | int signbit_known = signbit_known_p (lh_lb, lh_ub, rh_lb, rh_ub); |
2d5c4a16 JJ |
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). | |
5747470e | 2833 | if (zero_p (lh_lb, lh_ub) || singleton_inf_p (rh_lb, rh_ub)) |
24e97ac4 AH |
2834 | { |
2835 | zero_range (lb, ub, signbit_known); | |
2836 | r.set (type, lb, ub, nan_state (maybe_nan)); | |
2837 | return; | |
2838 | } | |
2d5c4a16 JJ |
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). | |
5747470e | 2844 | if (zero_p (rh_lb, rh_ub) || singleton_inf_p (lh_lb, lh_ub)) |
24e97ac4 AH |
2845 | { |
2846 | inf_range (lb, ub, signbit_known); | |
2847 | r.set (type, lb, ub, nan_state (maybe_nan)); | |
2848 | return; | |
2849 | } | |
2d5c4a16 JJ |
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 | |
c46b5b0a | 2857 | // [-INF, -0.0]. If they vary, VARYING. |
2d5c4a16 JJ |
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. | |
5747470e | 2864 | if (maybe_nan) |
24e97ac4 AH |
2865 | { |
2866 | zero_to_inf_range (lb, ub, signbit_known); | |
2867 | r.set (type, lb, ub, nan_state (maybe_nan)); | |
2868 | return; | |
2869 | } | |
2d5c4a16 JJ |
2870 | |
2871 | REAL_VALUE_TYPE cp[8]; | |
2872 | // Do a cross-division. At this point none of the divisions should | |
2873 | // produce a NAN. | |
2d5c4a16 JJ |
2874 | frange_arithmetic (RDIV_EXPR, type, cp[0], lh_lb, rh_lb, dconstninf); |
2875 | frange_arithmetic (RDIV_EXPR, type, cp[1], lh_lb, rh_ub, dconstninf); | |
2876 | frange_arithmetic (RDIV_EXPR, type, cp[2], lh_ub, rh_lb, dconstninf); | |
2877 | frange_arithmetic (RDIV_EXPR, type, cp[3], lh_ub, rh_ub, dconstninf); | |
2878 | frange_arithmetic (RDIV_EXPR, type, cp[4], lh_lb, rh_lb, dconstinf); | |
2879 | frange_arithmetic (RDIV_EXPR, type, cp[5], lh_lb, rh_ub, dconstinf); | |
2880 | frange_arithmetic (RDIV_EXPR, type, cp[6], lh_ub, rh_lb, dconstinf); | |
2881 | frange_arithmetic (RDIV_EXPR, type, cp[7], lh_ub, rh_ub, dconstinf); | |
2882 | ||
5747470e | 2883 | find_range (lb, ub, cp); |
2d5c4a16 JJ |
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. | |
5747470e | 2888 | if (contains_zero_p (rh_lb, rh_ub)) |
2d5c4a16 | 2889 | { |
5747470e | 2890 | if (signbit_known <= 0) |
2d5c4a16 | 2891 | real_inf (&lb, true); |
5747470e | 2892 | if (signbit_known >= 0) |
2d5c4a16 JJ |
2893 | real_inf (&ub, false); |
2894 | } | |
24e97ac4 AH |
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)); | |
2d5c4a16 JJ |
2899 | } |
2900 | } fop_div; | |
2901 | ||
a6efab5f | 2902 | |
a13c4440 | 2903 | // Initialize any float operators to the primary table |
07767389 AM |
2904 | |
2905 | void | |
2906 | range_op_table::initialize_float_ops () | |
2907 | { | |
4cbc312a AH |
2908 | set (UNLE_EXPR, fop_unordered_le); |
2909 | set (UNLT_EXPR, fop_unordered_lt); | |
2910 | set (UNGE_EXPR, fop_unordered_ge); | |
2911 | set (UNGT_EXPR, fop_unordered_gt); | |
2912 | set (UNEQ_EXPR, fop_unordered_equal); | |
24012539 AH |
2913 | set (ORDERED_EXPR, fop_ordered); |
2914 | set (UNORDERED_EXPR, fop_unordered); | |
5fe05ffe | 2915 | set (LTGT_EXPR, fop_ltgt); |
2d5c4a16 | 2916 | set (RDIV_EXPR, fop_div); |
a6efab5f AH |
2917 | } |
2918 | ||
1c0670c6 AH |
2919 | #if CHECKING_P |
2920 | #include "selftest.h" | |
2921 | ||
2922 | namespace selftest | |
2923 | { | |
2924 | ||
2925 | // Build an frange from string endpoints. | |
2926 | ||
d438b67e | 2927 | static inline frange |
1c0670c6 AH |
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 | { | |
a0c1a059 AH |
2939 | frange r, r0, r1; |
2940 | frange trange (float_type_node); | |
2941 | ||
2942 | // negate([-5, +10]) => [-10, 5] | |
2943 | r0 = frange_float ("-5", "10"); | |
56518bef | 2944 | range_op_handler (NEGATE_EXPR).fold_range (r, float_type_node, r0, trange); |
a0c1a059 AH |
2945 | ASSERT_EQ (r, frange_float ("-10", "5")); |
2946 | ||
2947 | // negate([0, 1] -NAN) => [-1, -0] +NAN | |
2948 | r0 = frange_float ("0", "1"); | |
2949 | r0.update_nan (true); | |
56518bef | 2950 | range_op_handler (NEGATE_EXPR).fold_range (r, float_type_node, r0, trange); |
a0c1a059 AH |
2951 | r1 = frange_float ("-1", "-0"); |
2952 | r1.update_nan (false); | |
2953 | ASSERT_EQ (r, r1); | |
68b0615b AH |
2954 | |
2955 | // [-INF,+INF] + [-INF,+INF] could be a NAN. | |
2eb50117 | 2956 | range_op_handler plus (PLUS_EXPR); |
68b0615b AH |
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, r0, r1); | |
2962 | if (HONOR_NANS (float_type_node)) | |
2963 | ASSERT_TRUE (r.maybe_isnan ()); | |
1c0670c6 AH |
2964 | } |
2965 | ||
2966 | } // namespace selftest | |
2967 | ||
2968 | #endif // CHECKING_P |