1 | /* Header file for mixed range operator class. |
2 | Copyright (C) 2017-2024 Free Software Foundation, Inc. |
3 | Contributed by Andrew MacLeod <amacleod@redhat.com> |
4 | and Aldy Hernandez <aldyh@redhat.com>. |
5 | |
6 | This file is part of GCC. |
7 | |
8 | GCC is free software; you can redistribute it and/or modify it under |
9 | the terms of the GNU General Public License as published by the Free |
10 | Software Foundation; either version 3, or (at your option) any later |
11 | version. |
12 | |
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ |
21 | |
22 | #ifndef GCC_RANGE_OP_MIXED_H |
23 | #define GCC_RANGE_OP_MIXED_H |
24 | |
25 | void update_known_bitmask (irange &, tree_code, const irange &, const irange &); |
26 | bool minus_op1_op2_relation_effect (irange &lhs_range, tree type, |
27 | const irange &, const irange &, |
28 | relation_kind rel); |
29 | |
30 | |
31 | // Return TRUE if 0 is within [WMIN, WMAX]. |
32 | |
33 | inline bool |
34 | wi_includes_zero_p (tree type, const wide_int &wmin, const wide_int &wmax) |
35 | { |
36 | signop sign = TYPE_SIGN (type); |
37 | return wi::le_p (x: wmin, y: 0, sgn: sign) && wi::ge_p (x: wmax, y: 0, sgn: sign); |
38 | } |
39 | |
40 | // Return TRUE if [WMIN, WMAX] is the singleton 0. |
41 | |
42 | inline bool |
43 | wi_zero_p (tree type, const wide_int &wmin, const wide_int &wmax) |
44 | { |
45 | unsigned prec = TYPE_PRECISION (type); |
46 | return wmin == wmax && wi::eq_p (x: wmin, y: wi::zero (precision: prec)); |
47 | } |
48 | |
49 | |
50 | enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL }; |
51 | bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type); |
52 | |
53 | // If the range of either op1 or op2 is undefined, set the result to |
54 | // varying and return TRUE. If the caller truly cares about a result, |
55 | // they should pass in a varying if it has an undefined that it wants |
56 | // treated as a varying. |
57 | |
58 | inline bool |
59 | empty_range_varying (vrange &r, tree type, |
60 | const vrange &op1, const vrange & op2) |
61 | { |
62 | if (op1.undefined_p () || op2.undefined_p ()) |
63 | { |
64 | r.set_varying (type); |
65 | return true; |
66 | } |
67 | else |
68 | return false; |
69 | } |
70 | |
71 | // For relation opcodes, first try to see if the supplied relation |
72 | // forces a true or false result, and return that. |
73 | // Then check for undefined operands. If none of this applies, |
74 | // return false. |
75 | |
76 | inline bool |
77 | relop_early_resolve (irange &r, tree type, const vrange &op1, |
78 | const vrange &op2, relation_trio trio, |
79 | relation_kind my_rel) |
80 | { |
81 | relation_kind rel = trio.op1_op2 (); |
82 | // If known relation is a complete subset of this relation, always true. |
83 | if (relation_union (r1: rel, r2: my_rel) == my_rel) |
84 | { |
85 | r = range_true (type); |
86 | return true; |
87 | } |
88 | |
89 | // If known relation has no subset of this relation, always false. |
90 | if (relation_intersect (r1: rel, r2: my_rel) == VREL_UNDEFINED) |
91 | { |
92 | r = range_false (type); |
93 | return true; |
94 | } |
95 | |
96 | // If either operand is undefined, return VARYING. |
97 | if (empty_range_varying (r, type, op1, op2)) |
98 | return true; |
99 | |
100 | return false; |
101 | } |
102 | |
103 | // ---------------------------------------------------------------------- |
104 | // Mixed Mode Operators. |
105 | // ---------------------------------------------------------------------- |
106 | |
107 | class operator_equal : public range_operator |
108 | { |
109 | public: |
110 | using range_operator::fold_range; |
111 | using range_operator::op1_range; |
112 | using range_operator::op2_range; |
113 | using range_operator::op1_op2_relation; |
114 | bool fold_range (irange &r, tree type, |
115 | const irange &op1, const irange &op2, |
116 | relation_trio = TRIO_VARYING) const final override; |
117 | bool fold_range (irange &r, tree type, |
118 | const frange &op1, const frange &op2, |
119 | relation_trio = TRIO_VARYING) const final override; |
120 | |
121 | bool op1_range (irange &r, tree type, |
122 | const irange &lhs, const irange &val, |
123 | relation_trio = TRIO_VARYING) const final override; |
124 | bool op1_range (frange &r, tree type, |
125 | const irange &lhs, const frange &op2, |
126 | relation_trio = TRIO_VARYING) const final override; |
127 | |
128 | bool op2_range (irange &r, tree type, |
129 | const irange &lhs, const irange &val, |
130 | relation_trio = TRIO_VARYING) const final override; |
131 | bool op2_range (frange &r, tree type, |
132 | const irange &lhs, const frange &op1, |
133 | relation_trio rel = TRIO_VARYING) const final override; |
134 | |
135 | relation_kind op1_op2_relation (const irange &lhs, const irange &, |
136 | const irange &) const final override; |
137 | relation_kind op1_op2_relation (const irange &lhs, const frange &, |
138 | const frange &) const final override; |
139 | void update_bitmask (irange &r, const irange &lh, |
140 | const irange &rh) const final override; |
141 | // Check op1 and op2 for compatibility. |
142 | bool operand_check_p (tree, tree t1, tree t2) const final override |
143 | { return range_compatible_p (type1: t1, type2: t2); } |
144 | }; |
145 | |
146 | class operator_not_equal : public range_operator |
147 | { |
148 | public: |
149 | using range_operator::fold_range; |
150 | using range_operator::op1_range; |
151 | using range_operator::op2_range; |
152 | using range_operator::op1_op2_relation; |
153 | bool fold_range (irange &r, tree type, |
154 | const irange &op1, const irange &op2, |
155 | relation_trio = TRIO_VARYING) const final override; |
156 | bool fold_range (irange &r, tree type, |
157 | const frange &op1, const frange &op2, |
158 | relation_trio rel = TRIO_VARYING) const final override; |
159 | |
160 | bool op1_range (irange &r, tree type, |
161 | const irange &lhs, const irange &op2, |
162 | relation_trio = TRIO_VARYING) const final override; |
163 | bool op1_range (frange &r, tree type, |
164 | const irange &lhs, const frange &op2, |
165 | relation_trio = TRIO_VARYING) const final override; |
166 | |
167 | bool op2_range (irange &r, tree type, |
168 | const irange &lhs, const irange &op1, |
169 | relation_trio = TRIO_VARYING) const final override; |
170 | bool op2_range (frange &r, tree type, |
171 | const irange &lhs, const frange &op1, |
172 | relation_trio = TRIO_VARYING) const final override; |
173 | |
174 | relation_kind op1_op2_relation (const irange &lhs, const irange &, |
175 | const irange &) const final override; |
176 | relation_kind op1_op2_relation (const irange &lhs, const frange &, |
177 | const frange &) const final override; |
178 | void update_bitmask (irange &r, const irange &lh, |
179 | const irange &rh) const final override; |
180 | // Check op1 and op2 for compatibility. |
181 | bool operand_check_p (tree, tree t1, tree t2) const final override |
182 | { return range_compatible_p (type1: t1, type2: t2); } |
183 | }; |
184 | |
185 | class operator_lt : public range_operator |
186 | { |
187 | public: |
188 | using range_operator::fold_range; |
189 | using range_operator::op1_range; |
190 | using range_operator::op2_range; |
191 | using range_operator::op1_op2_relation; |
192 | bool fold_range (irange &r, tree type, |
193 | const irange &op1, const irange &op2, |
194 | relation_trio = TRIO_VARYING) const final override; |
195 | bool fold_range (irange &r, tree type, |
196 | const frange &op1, const frange &op2, |
197 | relation_trio = TRIO_VARYING) const final override; |
198 | bool op1_range (irange &r, tree type, |
199 | const irange &lhs, const irange &op2, |
200 | relation_trio = TRIO_VARYING) const final override; |
201 | bool op1_range (frange &r, tree type, |
202 | const irange &lhs, const frange &op2, |
203 | relation_trio = TRIO_VARYING) const final override; |
204 | bool op2_range (irange &r, tree type, |
205 | const irange &lhs, const irange &op1, |
206 | relation_trio = TRIO_VARYING) const final override; |
207 | bool op2_range (frange &r, tree type, |
208 | const irange &lhs, const frange &op1, |
209 | relation_trio = TRIO_VARYING) const final override; |
210 | relation_kind op1_op2_relation (const irange &lhs, const irange &, |
211 | const irange &) const final override; |
212 | relation_kind op1_op2_relation (const irange &lhs, const frange &, |
213 | const frange &) const final override; |
214 | void update_bitmask (irange &r, const irange &lh, |
215 | const irange &rh) const final override; |
216 | // Check op1 and op2 for compatibility. |
217 | bool operand_check_p (tree, tree t1, tree t2) const final override |
218 | { return range_compatible_p (type1: t1, type2: t2); } |
219 | }; |
220 | |
221 | class operator_le : public range_operator |
222 | { |
223 | public: |
224 | using range_operator::fold_range; |
225 | using range_operator::op1_range; |
226 | using range_operator::op2_range; |
227 | using range_operator::op1_op2_relation; |
228 | bool fold_range (irange &r, tree type, |
229 | const irange &op1, const irange &op2, |
230 | relation_trio = TRIO_VARYING) const final override; |
231 | bool fold_range (irange &r, tree type, |
232 | const frange &op1, const frange &op2, |
233 | relation_trio rel = TRIO_VARYING) const final override; |
234 | |
235 | bool op1_range (irange &r, tree type, |
236 | const irange &lhs, const irange &op2, |
237 | relation_trio = TRIO_VARYING) const final override; |
238 | bool op1_range (frange &r, tree type, |
239 | const irange &lhs, const frange &op2, |
240 | relation_trio rel = TRIO_VARYING) const final override; |
241 | |
242 | bool op2_range (irange &r, tree type, |
243 | const irange &lhs, const irange &op1, |
244 | relation_trio = TRIO_VARYING) const final override; |
245 | bool op2_range (frange &r, tree type, |
246 | const irange &lhs, const frange &op1, |
247 | relation_trio rel = TRIO_VARYING) const final override; |
248 | |
249 | relation_kind op1_op2_relation (const irange &lhs, const irange &, |
250 | const irange &) const final override; |
251 | relation_kind op1_op2_relation (const irange &lhs, const frange &, |
252 | const frange &) const final override; |
253 | void update_bitmask (irange &r, const irange &lh, |
254 | const irange &rh) const final override; |
255 | // Check op1 and op2 for compatibility. |
256 | bool operand_check_p (tree, tree t1, tree t2) const final override |
257 | { return range_compatible_p (type1: t1, type2: t2); } |
258 | }; |
259 | |
260 | class operator_gt : public range_operator |
261 | { |
262 | public: |
263 | using range_operator::fold_range; |
264 | using range_operator::op1_range; |
265 | using range_operator::op2_range; |
266 | using range_operator::op1_op2_relation; |
267 | bool fold_range (irange &r, tree type, |
268 | const irange &op1, const irange &op2, |
269 | relation_trio = TRIO_VARYING) const final override; |
270 | bool fold_range (irange &r, tree type, |
271 | const frange &op1, const frange &op2, |
272 | relation_trio = TRIO_VARYING) const final override; |
273 | |
274 | bool op1_range (irange &r, tree type, |
275 | const irange &lhs, const irange &op2, |
276 | relation_trio = TRIO_VARYING) const final override; |
277 | bool op1_range (frange &r, tree type, |
278 | const irange &lhs, const frange &op2, |
279 | relation_trio = TRIO_VARYING) const final override; |
280 | |
281 | bool op2_range (irange &r, tree type, |
282 | const irange &lhs, const irange &op1, |
283 | relation_trio = TRIO_VARYING) const final override; |
284 | bool op2_range (frange &r, tree type, |
285 | const irange &lhs, const frange &op1, |
286 | relation_trio = TRIO_VARYING) const final override; |
287 | relation_kind op1_op2_relation (const irange &lhs, const irange &, |
288 | const irange &) const final override; |
289 | relation_kind op1_op2_relation (const irange &lhs, const frange &, |
290 | const frange &) const final override; |
291 | void update_bitmask (irange &r, const irange &lh, |
292 | const irange &rh) const final override; |
293 | // Check op1 and op2 for compatibility. |
294 | bool operand_check_p (tree, tree t1, tree t2) const final override |
295 | { return range_compatible_p (type1: t1, type2: t2); } |
296 | }; |
297 | |
298 | class operator_ge : public range_operator |
299 | { |
300 | public: |
301 | using range_operator::fold_range; |
302 | using range_operator::op1_range; |
303 | using range_operator::op2_range; |
304 | using range_operator::op1_op2_relation; |
305 | bool fold_range (irange &r, tree type, |
306 | const irange &op1, const irange &op2, |
307 | relation_trio = TRIO_VARYING) const final override; |
308 | bool fold_range (irange &r, tree type, |
309 | const frange &op1, const frange &op2, |
310 | relation_trio = TRIO_VARYING) const final override; |
311 | |
312 | bool op1_range (irange &r, tree type, |
313 | const irange &lhs, const irange &op2, |
314 | relation_trio = TRIO_VARYING) const final override; |
315 | bool op1_range (frange &r, tree type, |
316 | const irange &lhs, const frange &op2, |
317 | relation_trio = TRIO_VARYING) const final override; |
318 | |
319 | bool op2_range (irange &r, tree type, |
320 | const irange &lhs, const irange &op1, |
321 | relation_trio = TRIO_VARYING) const final override; |
322 | bool op2_range (frange &r, tree type, |
323 | const irange &lhs, const frange &op1, |
324 | relation_trio = TRIO_VARYING) const final override; |
325 | |
326 | relation_kind op1_op2_relation (const irange &lhs, const irange &, |
327 | const irange &) const final override; |
328 | relation_kind op1_op2_relation (const irange &lhs, const frange &, |
329 | const frange &) const final override; |
330 | void update_bitmask (irange &r, const irange &lh, |
331 | const irange &rh) const final override; |
332 | // Check op1 and op2 for compatibility. |
333 | bool operand_check_p (tree, tree t1, tree t2) const final override |
334 | { return range_compatible_p (type1: t1, type2: t2); } |
335 | }; |
336 | |
337 | class operator_identity : public range_operator |
338 | { |
339 | public: |
340 | using range_operator::fold_range; |
341 | using range_operator::op1_range; |
342 | using range_operator::lhs_op1_relation; |
343 | bool fold_range (irange &r, tree type, |
344 | const irange &op1, const irange &op2, |
345 | relation_trio rel = TRIO_VARYING) const final override; |
346 | bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED, |
347 | const frange &op1, const frange &op2 ATTRIBUTE_UNUSED, |
348 | relation_trio = TRIO_VARYING) const final override; |
349 | bool op1_range (irange &r, tree type, |
350 | const irange &lhs, const irange &op2, |
351 | relation_trio rel = TRIO_VARYING) const final override; |
352 | bool op1_range (frange &r, tree type ATTRIBUTE_UNUSED, |
353 | const frange &lhs, const frange &op2 ATTRIBUTE_UNUSED, |
354 | relation_trio = TRIO_VARYING) const final override; |
355 | relation_kind lhs_op1_relation (const irange &lhs, |
356 | const irange &op1, const irange &op2, |
357 | relation_kind rel) const final override; |
358 | }; |
359 | |
360 | class operator_cst : public range_operator |
361 | { |
362 | public: |
363 | using range_operator::fold_range; |
364 | bool fold_range (irange &r, tree type, |
365 | const irange &op1, const irange &op2, |
366 | relation_trio rel = TRIO_VARYING) const final override; |
367 | bool fold_range (frange &r, tree type, |
368 | const frange &op1, const frange &op2, |
369 | relation_trio = TRIO_VARYING) const final override; |
370 | }; |
371 | |
372 | |
373 | class operator_cast: public range_operator |
374 | { |
375 | public: |
376 | using range_operator::fold_range; |
377 | using range_operator::op1_range; |
378 | using range_operator::lhs_op1_relation; |
379 | bool fold_range (irange &r, tree type, |
380 | const irange &op1, const irange &op2, |
381 | relation_trio rel = TRIO_VARYING) const final override; |
382 | bool op1_range (irange &r, tree type, |
383 | const irange &lhs, const irange &op2, |
384 | relation_trio rel = TRIO_VARYING) const final override; |
385 | relation_kind lhs_op1_relation (const irange &lhs, |
386 | const irange &op1, const irange &op2, |
387 | relation_kind) const final override; |
388 | void update_bitmask (irange &r, const irange &lh, |
389 | const irange &rh) const final override; |
390 | private: |
391 | bool truncating_cast_p (const irange &inner, const irange &outer) const; |
392 | bool inside_domain_p (const wide_int &min, const wide_int &max, |
393 | const irange &outer) const; |
394 | void fold_pair (irange &r, unsigned index, const irange &inner, |
395 | const irange &outer) const; |
396 | }; |
397 | |
398 | class operator_plus : public range_operator |
399 | { |
400 | public: |
401 | using range_operator::op1_range; |
402 | using range_operator::op2_range; |
403 | using range_operator::lhs_op1_relation; |
404 | using range_operator::lhs_op2_relation; |
405 | bool op1_range (irange &r, tree type, |
406 | const irange &lhs, const irange &op2, |
407 | relation_trio) const final override; |
408 | bool op1_range (frange &r, tree type, |
409 | const frange &lhs, const frange &op2, |
410 | relation_trio = TRIO_VARYING) const final override; |
411 | |
412 | bool op2_range (irange &r, tree type, |
413 | const irange &lhs, const irange &op1, |
414 | relation_trio) const final override; |
415 | bool op2_range (frange &r, tree type, |
416 | const frange &lhs, const frange &op1, |
417 | relation_trio = TRIO_VARYING) const final override; |
418 | |
419 | relation_kind lhs_op1_relation (const irange &lhs, const irange &op1, |
420 | const irange &op2, |
421 | relation_kind rel) const final override; |
422 | relation_kind lhs_op2_relation (const irange &lhs, const irange &op1, |
423 | const irange &op2, |
424 | relation_kind rel) const final override; |
425 | void update_bitmask (irange &r, const irange &lh, |
426 | const irange &rh) const final override; |
427 | |
428 | virtual bool overflow_free_p (const irange &lh, const irange &rh, |
429 | relation_trio = TRIO_VARYING) const; |
430 | // Check compatibility of all operands. |
431 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
432 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
433 | private: |
434 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
435 | const wide_int &lh_ub, const wide_int &rh_lb, |
436 | const wide_int &rh_ub) const final override; |
437 | void rv_fold (frange &r, tree type, |
438 | const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
439 | const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, |
440 | relation_kind) const final override; |
441 | }; |
442 | |
443 | class operator_abs : public range_operator |
444 | { |
445 | public: |
446 | using range_operator::fold_range; |
447 | using range_operator::op1_range; |
448 | bool fold_range (frange &r, tree type, |
449 | const frange &op1, const frange &, |
450 | relation_trio = TRIO_VARYING) const final override; |
451 | |
452 | bool op1_range (irange &r, tree type, const irange &lhs, |
453 | const irange &op2, relation_trio) const final override; |
454 | bool op1_range (frange &r, tree type, |
455 | const frange &lhs, const frange &op2, |
456 | relation_trio rel = TRIO_VARYING) const final override; |
457 | void update_bitmask (irange &r, const irange &lh, |
458 | const irange &rh) const final override; |
459 | // Check compatibility of LHS and op1. |
460 | bool operand_check_p (tree t1, tree t2, tree) const final override |
461 | { return range_compatible_p (type1: t1, type2: t2); } |
462 | private: |
463 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
464 | const wide_int &lh_ub, const wide_int &rh_lb, |
465 | const wide_int &rh_ub) const final override; |
466 | |
467 | }; |
468 | |
469 | class operator_minus : public range_operator |
470 | { |
471 | public: |
472 | using range_operator::fold_range; |
473 | using range_operator::op1_range; |
474 | using range_operator::op2_range; |
475 | using range_operator::lhs_op1_relation; |
476 | bool op1_range (irange &r, tree type, |
477 | const irange &lhs, const irange &op2, |
478 | relation_trio) const final override; |
479 | bool op1_range (frange &r, tree type, |
480 | const frange &lhs, const frange &op2, |
481 | relation_trio = TRIO_VARYING) const final override; |
482 | |
483 | bool op2_range (irange &r, tree type, |
484 | const irange &lhs, const irange &op1, |
485 | relation_trio) const final override; |
486 | bool op2_range (frange &r, tree type, |
487 | const frange &lhs, |
488 | const frange &op1, |
489 | relation_trio = TRIO_VARYING) const final override; |
490 | |
491 | relation_kind lhs_op1_relation (const irange &lhs, |
492 | const irange &op1, const irange &op2, |
493 | relation_kind rel) const final override; |
494 | bool op1_op2_relation_effect (irange &lhs_range, tree type, |
495 | const irange &op1_range, |
496 | const irange &op2_range, |
497 | relation_kind rel) const final override; |
498 | void update_bitmask (irange &r, const irange &lh, |
499 | const irange &rh) const final override; |
500 | |
501 | virtual bool overflow_free_p (const irange &lh, const irange &rh, |
502 | relation_trio = TRIO_VARYING) const; |
503 | // Check compatibility of all operands. |
504 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
505 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
506 | private: |
507 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
508 | const wide_int &lh_ub, const wide_int &rh_lb, |
509 | const wide_int &rh_ub) const final override; |
510 | void rv_fold (frange &r, tree type, |
511 | const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
512 | const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, |
513 | relation_kind) const final override; |
514 | }; |
515 | |
516 | class operator_negate : public range_operator |
517 | { |
518 | public: |
519 | using range_operator::fold_range; |
520 | using range_operator::op1_range; |
521 | bool fold_range (irange &r, tree type, |
522 | const irange &op1, const irange &op2, |
523 | relation_trio rel = TRIO_VARYING) const final override; |
524 | bool fold_range (frange &r, tree type, |
525 | const frange &op1, const frange &op2, |
526 | relation_trio = TRIO_VARYING) const final override; |
527 | |
528 | bool op1_range (irange &r, tree type, |
529 | const irange &lhs, const irange &op2, |
530 | relation_trio rel = TRIO_VARYING) const final override; |
531 | bool op1_range (frange &r, tree type, |
532 | const frange &lhs, const frange &op2, |
533 | relation_trio rel = TRIO_VARYING) const final override; |
534 | // Check compatibility of LHS and op1. |
535 | bool operand_check_p (tree t1, tree t2, tree) const final override |
536 | { return range_compatible_p (type1: t1, type2: t2); } |
537 | }; |
538 | |
539 | |
540 | class cross_product_operator : public range_operator |
541 | { |
542 | public: |
543 | virtual bool wi_op_overflows (wide_int &r, |
544 | tree type, |
545 | const wide_int &, |
546 | const wide_int &) const = 0; |
547 | void wi_cross_product (irange &r, tree type, |
548 | const wide_int &lh_lb, |
549 | const wide_int &lh_ub, |
550 | const wide_int &rh_lb, |
551 | const wide_int &rh_ub) const; |
552 | }; |
553 | |
554 | class operator_mult : public cross_product_operator |
555 | { |
556 | public: |
557 | using range_operator::op1_range; |
558 | using range_operator::op2_range; |
559 | bool op1_range (irange &r, tree type, |
560 | const irange &lhs, const irange &op2, |
561 | relation_trio) const final override; |
562 | bool op1_range (frange &r, tree type, |
563 | const frange &lhs, const frange &op2, |
564 | relation_trio = TRIO_VARYING) const final override; |
565 | |
566 | bool op2_range (irange &r, tree type, |
567 | const irange &lhs, const irange &op1, |
568 | relation_trio) const final override; |
569 | bool op2_range (frange &r, tree type, |
570 | const frange &lhs, const frange &op1, |
571 | relation_trio = TRIO_VARYING) const final override; |
572 | |
573 | void update_bitmask (irange &r, const irange &lh, |
574 | const irange &rh) const final override; |
575 | |
576 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
577 | const wide_int &lh_ub, const wide_int &rh_lb, |
578 | const wide_int &rh_ub) const final override; |
579 | bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, |
580 | const wide_int &w1) const final override; |
581 | |
582 | void rv_fold (frange &r, tree type, |
583 | const REAL_VALUE_TYPE &lh_lb, const REAL_VALUE_TYPE &lh_ub, |
584 | const REAL_VALUE_TYPE &rh_lb, const REAL_VALUE_TYPE &rh_ub, |
585 | relation_kind kind) const final override; |
586 | virtual bool overflow_free_p (const irange &lh, const irange &rh, |
587 | relation_trio = TRIO_VARYING) const; |
588 | // Check compatibility of all operands. |
589 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
590 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
591 | }; |
592 | |
593 | class operator_addr_expr : public range_operator |
594 | { |
595 | public: |
596 | using range_operator::fold_range; |
597 | using range_operator::op1_range; |
598 | bool fold_range (irange &r, tree type, |
599 | const irange &op1, const irange &op2, |
600 | relation_trio rel = TRIO_VARYING) const final override; |
601 | bool op1_range (irange &r, tree type, |
602 | const irange &lhs, const irange &op2, |
603 | relation_trio rel = TRIO_VARYING) const final override; |
604 | }; |
605 | |
606 | class operator_bitwise_not : public range_operator |
607 | { |
608 | public: |
609 | using range_operator::fold_range; |
610 | using range_operator::op1_range; |
611 | bool fold_range (irange &r, tree type, |
612 | const irange &lh, const irange &rh, |
613 | relation_trio rel = TRIO_VARYING) const final override; |
614 | bool op1_range (irange &r, tree type, |
615 | const irange &lhs, const irange &op2, |
616 | relation_trio rel = TRIO_VARYING) const final override; |
617 | void update_bitmask (irange &r, const irange &lh, |
618 | const irange &rh) const final override; |
619 | // Check compatibility of all operands. |
620 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
621 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
622 | }; |
623 | |
624 | class operator_bitwise_xor : public range_operator |
625 | { |
626 | public: |
627 | using range_operator::op1_range; |
628 | using range_operator::op2_range; |
629 | bool op1_range (irange &r, tree type, |
630 | const irange &lhs, const irange &op2, |
631 | relation_trio rel = TRIO_VARYING) const final override; |
632 | bool op2_range (irange &r, tree type, |
633 | const irange &lhs, const irange &op1, |
634 | relation_trio rel = TRIO_VARYING) const final override; |
635 | bool op1_op2_relation_effect (irange &lhs_range, |
636 | tree type, |
637 | const irange &op1_range, |
638 | const irange &op2_range, |
639 | relation_kind rel) const final override; |
640 | void update_bitmask (irange &r, const irange &lh, |
641 | const irange &rh) const final override; |
642 | // Check compatibility of all operands. |
643 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
644 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
645 | private: |
646 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
647 | const wide_int &lh_ub, const wide_int &rh_lb, |
648 | const wide_int &rh_ub) const final override; |
649 | }; |
650 | |
651 | class operator_bitwise_and : public range_operator |
652 | { |
653 | public: |
654 | using range_operator::op1_range; |
655 | using range_operator::op2_range; |
656 | using range_operator::lhs_op1_relation; |
657 | bool op1_range (irange &r, tree type, |
658 | const irange &lhs, const irange &op2, |
659 | relation_trio rel = TRIO_VARYING) const override; |
660 | bool op2_range (irange &r, tree type, |
661 | const irange &lhs, const irange &op1, |
662 | relation_trio rel = TRIO_VARYING) const override; |
663 | relation_kind lhs_op1_relation (const irange &lhs, |
664 | const irange &op1, const irange &op2, |
665 | relation_kind) const override; |
666 | void update_bitmask (irange &r, const irange &lh, |
667 | const irange &rh) const override; |
668 | // Check compatibility of all operands. |
669 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
670 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
671 | protected: |
672 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
673 | const wide_int &lh_ub, const wide_int &rh_lb, |
674 | const wide_int &rh_ub) const override; |
675 | void simple_op1_range_solver (irange &r, tree type, |
676 | const irange &lhs, |
677 | const irange &op2) const; |
678 | }; |
679 | |
680 | class operator_bitwise_or : public range_operator |
681 | { |
682 | public: |
683 | using range_operator::op1_range; |
684 | using range_operator::op2_range; |
685 | bool op1_range (irange &r, tree type, |
686 | const irange &lhs, const irange &op2, |
687 | relation_trio rel = TRIO_VARYING) const override; |
688 | bool op2_range (irange &r, tree type, |
689 | const irange &lhs, const irange &op1, |
690 | relation_trio rel = TRIO_VARYING) const override; |
691 | void update_bitmask (irange &r, const irange &lh, |
692 | const irange &rh) const override; |
693 | // Check compatibility of all operands. |
694 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
695 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
696 | protected: |
697 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
698 | const wide_int &lh_ub, const wide_int &rh_lb, |
699 | const wide_int &rh_ub) const override; |
700 | }; |
701 | |
702 | class operator_min : public range_operator |
703 | { |
704 | public: |
705 | void update_bitmask (irange &r, const irange &lh, |
706 | const irange &rh) const override; |
707 | // Check compatibility of all operands. |
708 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
709 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
710 | protected: |
711 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
712 | const wide_int &lh_ub, const wide_int &rh_lb, |
713 | const wide_int &rh_ub) const override; |
714 | }; |
715 | |
716 | class operator_max : public range_operator |
717 | { |
718 | public: |
719 | void update_bitmask (irange &r, const irange &lh, |
720 | const irange &rh) const override; |
721 | // Check compatibility of all operands. |
722 | bool operand_check_p (tree t1, tree t2, tree t3) const final override |
723 | { return range_compatible_p (type1: t1, type2: t2) && range_compatible_p (type1: t1, type2: t3); } |
724 | protected: |
725 | void wi_fold (irange &r, tree type, const wide_int &lh_lb, |
726 | const wide_int &lh_ub, const wide_int &rh_lb, |
727 | const wide_int &rh_ub) const override; |
728 | }; |
729 | #endif // GCC_RANGE_OP_MIXED_H |
730 | |