]>
Commit | Line | Data |
---|---|---|
4c85ff75 | 1 | /* Code for GIMPLE range related routines. |
7adcbafe | 2 | Copyright (C) 2019-2022 Free Software Foundation, Inc. |
4c85ff75 AM |
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 | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GCC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License 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 | #include "config.h" | |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
25 | #include "backend.h" | |
26 | #include "insn-codes.h" | |
27 | #include "tree.h" | |
28 | #include "gimple.h" | |
29 | #include "ssa.h" | |
30 | #include "gimple-pretty-print.h" | |
31 | #include "optabs-tree.h" | |
ba206889 | 32 | #include "gimple-iterator.h" |
4c85ff75 AM |
33 | #include "gimple-fold.h" |
34 | #include "wide-int.h" | |
35 | #include "fold-const.h" | |
36 | #include "case-cfn-macros.h" | |
37 | #include "omp-general.h" | |
38 | #include "cfgloop.h" | |
39 | #include "tree-ssa-loop.h" | |
40 | #include "tree-scalar-evolution.h" | |
d5a8c138 | 41 | #include "langhooks.h" |
4c85ff75 AM |
42 | #include "vr-values.h" |
43 | #include "range.h" | |
44 | #include "value-query.h" | |
51ce0638 | 45 | #include "gimple-range-op.h" |
e68c8280 | 46 | #include "gimple-range.h" |
4c85ff75 AM |
47 | // Construct a fur_source, and set the m_query field. |
48 | ||
49 | fur_source::fur_source (range_query *q) | |
50 | { | |
51 | if (q) | |
52 | m_query = q; | |
53 | else if (cfun) | |
54 | m_query = get_range_query (cfun); | |
55 | else | |
56 | m_query = get_global_range_query (); | |
57 | m_gori = NULL; | |
58 | } | |
59 | ||
60 | // Invoke range_of_expr on EXPR. | |
61 | ||
62 | bool | |
45c8523d | 63 | fur_source::get_operand (vrange &r, tree expr) |
4c85ff75 AM |
64 | { |
65 | return m_query->range_of_expr (r, expr); | |
66 | } | |
67 | ||
68 | // Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current | |
69 | // range_query to get the range on the edge. | |
70 | ||
71 | bool | |
45c8523d | 72 | fur_source::get_phi_operand (vrange &r, tree expr, edge e) |
4c85ff75 AM |
73 | { |
74 | return m_query->range_on_edge (r, e, expr); | |
75 | } | |
76 | ||
77 | // Default is no relation. | |
78 | ||
79 | relation_kind | |
80 | fur_source::query_relation (tree op1 ATTRIBUTE_UNUSED, | |
81 | tree op2 ATTRIBUTE_UNUSED) | |
82 | { | |
ade5531c | 83 | return VREL_VARYING; |
4c85ff75 AM |
84 | } |
85 | ||
86 | // Default registers nothing. | |
87 | ||
88 | void | |
89 | fur_source::register_relation (gimple *s ATTRIBUTE_UNUSED, | |
90 | relation_kind k ATTRIBUTE_UNUSED, | |
91 | tree op1 ATTRIBUTE_UNUSED, | |
92 | tree op2 ATTRIBUTE_UNUSED) | |
93 | { | |
94 | } | |
95 | ||
96 | // Default registers nothing. | |
97 | ||
98 | void | |
99 | fur_source::register_relation (edge e ATTRIBUTE_UNUSED, | |
100 | relation_kind k ATTRIBUTE_UNUSED, | |
101 | tree op1 ATTRIBUTE_UNUSED, | |
102 | tree op2 ATTRIBUTE_UNUSED) | |
103 | { | |
104 | } | |
105 | ||
106 | // This version of fur_source will pick a range up off an edge. | |
107 | ||
108 | class fur_edge : public fur_source | |
109 | { | |
110 | public: | |
111 | fur_edge (edge e, range_query *q = NULL); | |
45c8523d AH |
112 | virtual bool get_operand (vrange &r, tree expr) override; |
113 | virtual bool get_phi_operand (vrange &r, tree expr, edge e) override; | |
4c85ff75 AM |
114 | private: |
115 | edge m_edge; | |
116 | }; | |
117 | ||
118 | // Instantiate an edge based fur_source. | |
119 | ||
120 | inline | |
121 | fur_edge::fur_edge (edge e, range_query *q) : fur_source (q) | |
122 | { | |
123 | m_edge = e; | |
124 | } | |
125 | ||
126 | // Get the value of EXPR on edge m_edge. | |
127 | ||
128 | bool | |
45c8523d | 129 | fur_edge::get_operand (vrange &r, tree expr) |
4c85ff75 AM |
130 | { |
131 | return m_query->range_on_edge (r, m_edge, expr); | |
132 | } | |
133 | ||
134 | // Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current | |
135 | // range_query to get the range on the edge. | |
136 | ||
137 | bool | |
45c8523d | 138 | fur_edge::get_phi_operand (vrange &r, tree expr, edge e) |
4c85ff75 AM |
139 | { |
140 | // Edge to edge recalculations not supoprted yet, until we sort it out. | |
141 | gcc_checking_assert (e == m_edge); | |
142 | return m_query->range_on_edge (r, e, expr); | |
143 | } | |
144 | ||
145 | // Instantiate a stmt based fur_source. | |
146 | ||
147 | fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q) | |
148 | { | |
149 | m_stmt = s; | |
150 | } | |
151 | ||
152 | // Retreive range of EXPR as it occurs as a use on stmt M_STMT. | |
153 | ||
154 | bool | |
45c8523d | 155 | fur_stmt::get_operand (vrange &r, tree expr) |
4c85ff75 AM |
156 | { |
157 | return m_query->range_of_expr (r, expr, m_stmt); | |
158 | } | |
159 | ||
160 | // Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current | |
161 | // range_query to get the range on the edge. | |
162 | ||
163 | bool | |
45c8523d | 164 | fur_stmt::get_phi_operand (vrange &r, tree expr, edge e) |
4c85ff75 AM |
165 | { |
166 | // Pick up the range of expr from edge E. | |
167 | fur_edge e_src (e, m_query); | |
168 | return e_src.get_operand (r, expr); | |
169 | } | |
170 | ||
171 | // Return relation based from m_stmt. | |
172 | ||
173 | relation_kind | |
174 | fur_stmt::query_relation (tree op1, tree op2) | |
175 | { | |
176 | return m_query->query_relation (m_stmt, op1, op2); | |
177 | } | |
178 | ||
179 | // Instantiate a stmt based fur_source with a GORI object. | |
180 | ||
181 | ||
182 | fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q) | |
183 | : fur_stmt (s, q) | |
184 | { | |
185 | gcc_checking_assert (gori); | |
186 | m_gori = gori; | |
187 | // Set relations if there is an oracle in the range_query. | |
188 | // This will enable registering of relationships as they are discovered. | |
189 | m_oracle = q->oracle (); | |
190 | ||
191 | } | |
192 | ||
193 | // Register a relation on a stmt if there is an oracle. | |
194 | ||
195 | void | |
196 | fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2) | |
197 | { | |
198 | if (m_oracle) | |
3674d8e6 | 199 | m_oracle->register_stmt (s, k, op1, op2); |
4c85ff75 AM |
200 | } |
201 | ||
202 | // Register a relation on an edge if there is an oracle. | |
203 | ||
204 | void | |
205 | fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2) | |
206 | { | |
207 | if (m_oracle) | |
3674d8e6 | 208 | m_oracle->register_edge (e, k, op1, op2); |
4c85ff75 AM |
209 | } |
210 | ||
211 | // This version of fur_source will pick a range up from a list of ranges | |
212 | // supplied by the caller. | |
213 | ||
214 | class fur_list : public fur_source | |
215 | { | |
216 | public: | |
45c8523d AH |
217 | fur_list (vrange &r1); |
218 | fur_list (vrange &r1, vrange &r2); | |
219 | fur_list (unsigned num, vrange **list); | |
220 | virtual bool get_operand (vrange &r, tree expr) override; | |
221 | virtual bool get_phi_operand (vrange &r, tree expr, edge e) override; | |
4c85ff75 | 222 | private: |
45c8523d AH |
223 | vrange *m_local[2]; |
224 | vrange **m_list; | |
4c85ff75 AM |
225 | unsigned m_index; |
226 | unsigned m_limit; | |
227 | }; | |
228 | ||
229 | // One range supplied for unary operations. | |
230 | ||
45c8523d | 231 | fur_list::fur_list (vrange &r1) : fur_source (NULL) |
4c85ff75 AM |
232 | { |
233 | m_list = m_local; | |
234 | m_index = 0; | |
235 | m_limit = 1; | |
45c8523d | 236 | m_local[0] = &r1; |
4c85ff75 AM |
237 | } |
238 | ||
239 | // Two ranges supplied for binary operations. | |
240 | ||
45c8523d | 241 | fur_list::fur_list (vrange &r1, vrange &r2) : fur_source (NULL) |
4c85ff75 AM |
242 | { |
243 | m_list = m_local; | |
244 | m_index = 0; | |
245 | m_limit = 2; | |
45c8523d AH |
246 | m_local[0] = &r1; |
247 | m_local[1] = &r2; | |
4c85ff75 AM |
248 | } |
249 | ||
250 | // Arbitrary number of ranges in a vector. | |
251 | ||
45c8523d | 252 | fur_list::fur_list (unsigned num, vrange **list) : fur_source (NULL) |
4c85ff75 AM |
253 | { |
254 | m_list = list; | |
255 | m_index = 0; | |
256 | m_limit = num; | |
257 | } | |
258 | ||
259 | // Get the next operand from the vector, ensure types are compatible. | |
260 | ||
261 | bool | |
45c8523d | 262 | fur_list::get_operand (vrange &r, tree expr) |
4c85ff75 AM |
263 | { |
264 | if (m_index >= m_limit) | |
265 | return m_query->range_of_expr (r, expr); | |
45c8523d | 266 | r = *m_list[m_index++]; |
4c85ff75 AM |
267 | gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ())); |
268 | return true; | |
269 | } | |
270 | ||
271 | // This will simply pick the next operand from the vector. | |
272 | bool | |
45c8523d | 273 | fur_list::get_phi_operand (vrange &r, tree expr, edge e ATTRIBUTE_UNUSED) |
4c85ff75 AM |
274 | { |
275 | return get_operand (r, expr); | |
276 | } | |
277 | ||
278 | // Fold stmt S into range R using R1 as the first operand. | |
279 | ||
280 | bool | |
45c8523d | 281 | fold_range (vrange &r, gimple *s, vrange &r1) |
4c85ff75 AM |
282 | { |
283 | fold_using_range f; | |
284 | fur_list src (r1); | |
285 | return f.fold_stmt (r, s, src); | |
286 | } | |
287 | ||
288 | // Fold stmt S into range R using R1 and R2 as the first two operands. | |
289 | ||
290 | bool | |
45c8523d | 291 | fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2) |
4c85ff75 AM |
292 | { |
293 | fold_using_range f; | |
294 | fur_list src (r1, r2); | |
295 | return f.fold_stmt (r, s, src); | |
296 | } | |
297 | ||
298 | // Fold stmt S into range R using NUM_ELEMENTS from VECTOR as the initial | |
299 | // operands encountered. | |
300 | ||
301 | bool | |
45c8523d | 302 | fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector) |
4c85ff75 AM |
303 | { |
304 | fold_using_range f; | |
305 | fur_list src (num_elements, vector); | |
306 | return f.fold_stmt (r, s, src); | |
307 | } | |
308 | ||
309 | // Fold stmt S into range R using range query Q. | |
310 | ||
311 | bool | |
45c8523d | 312 | fold_range (vrange &r, gimple *s, range_query *q) |
4c85ff75 AM |
313 | { |
314 | fold_using_range f; | |
315 | fur_stmt src (s, q); | |
316 | return f.fold_stmt (r, s, src); | |
317 | } | |
318 | ||
319 | // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE. | |
320 | ||
321 | bool | |
45c8523d | 322 | fold_range (vrange &r, gimple *s, edge on_edge, range_query *q) |
4c85ff75 AM |
323 | { |
324 | fold_using_range f; | |
325 | fur_edge src (on_edge, q); | |
326 | return f.fold_stmt (r, s, src); | |
327 | } | |
328 | ||
329 | // ------------------------------------------------------------------------- | |
330 | ||
331 | // Adjust the range for a pointer difference where the operands came | |
332 | // from a memchr. | |
333 | // | |
334 | // This notices the following sequence: | |
335 | // | |
336 | // def = __builtin_memchr (arg, 0, sz) | |
337 | // n = def - arg | |
338 | // | |
339 | // The range for N can be narrowed to [0, PTRDIFF_MAX - 1]. | |
340 | ||
341 | static void | |
342 | adjust_pointer_diff_expr (irange &res, const gimple *diff_stmt) | |
343 | { | |
344 | tree op0 = gimple_assign_rhs1 (diff_stmt); | |
345 | tree op1 = gimple_assign_rhs2 (diff_stmt); | |
346 | tree op0_ptype = TREE_TYPE (TREE_TYPE (op0)); | |
347 | tree op1_ptype = TREE_TYPE (TREE_TYPE (op1)); | |
348 | gimple *call; | |
349 | ||
350 | if (TREE_CODE (op0) == SSA_NAME | |
351 | && TREE_CODE (op1) == SSA_NAME | |
352 | && (call = SSA_NAME_DEF_STMT (op0)) | |
353 | && is_gimple_call (call) | |
354 | && gimple_call_builtin_p (call, BUILT_IN_MEMCHR) | |
355 | && TYPE_MODE (op0_ptype) == TYPE_MODE (char_type_node) | |
356 | && TYPE_PRECISION (op0_ptype) == TYPE_PRECISION (char_type_node) | |
357 | && TYPE_MODE (op1_ptype) == TYPE_MODE (char_type_node) | |
358 | && TYPE_PRECISION (op1_ptype) == TYPE_PRECISION (char_type_node) | |
359 | && gimple_call_builtin_p (call, BUILT_IN_MEMCHR) | |
360 | && vrp_operand_equal_p (op1, gimple_call_arg (call, 0)) | |
361 | && integer_zerop (gimple_call_arg (call, 1))) | |
362 | { | |
363 | tree max = vrp_val_max (ptrdiff_type_node); | |
ad451b02 AM |
364 | unsigned prec = TYPE_PRECISION (TREE_TYPE (max)); |
365 | wide_int wmaxm1 = wi::to_wide (max, prec) - 1; | |
71f2928e | 366 | res.intersect (int_range<2> (TREE_TYPE (max), wi::zero (prec), wmaxm1)); |
4c85ff75 AM |
367 | } |
368 | } | |
369 | ||
bccf4b88 AH |
370 | // Adjust the range for an IMAGPART_EXPR. |
371 | ||
372 | static void | |
45c8523d | 373 | adjust_imagpart_expr (vrange &res, const gimple *stmt) |
bccf4b88 AH |
374 | { |
375 | tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); | |
376 | ||
377 | if (TREE_CODE (name) != SSA_NAME || !SSA_NAME_DEF_STMT (name)) | |
378 | return; | |
379 | ||
380 | gimple *def_stmt = SSA_NAME_DEF_STMT (name); | |
381 | if (is_gimple_call (def_stmt) && gimple_call_internal_p (def_stmt)) | |
382 | { | |
383 | switch (gimple_call_internal_fn (def_stmt)) | |
384 | { | |
385 | case IFN_ADD_OVERFLOW: | |
386 | case IFN_SUB_OVERFLOW: | |
387 | case IFN_MUL_OVERFLOW: | |
388 | case IFN_ATOMIC_COMPARE_EXCHANGE: | |
389 | { | |
390 | int_range<2> r; | |
391 | r.set_varying (boolean_type_node); | |
392 | tree type = TREE_TYPE (gimple_assign_lhs (stmt)); | |
393 | range_cast (r, type); | |
394 | res.intersect (r); | |
395 | } | |
396 | default: | |
397 | break; | |
398 | } | |
399 | return; | |
400 | } | |
d44dc131 JJ |
401 | if (is_gimple_assign (def_stmt) |
402 | && gimple_assign_rhs_code (def_stmt) == COMPLEX_CST) | |
bccf4b88 AH |
403 | { |
404 | tree cst = gimple_assign_rhs1 (def_stmt); | |
405 | if (TREE_CODE (cst) == COMPLEX_CST) | |
406 | { | |
71f2928e AH |
407 | int_range<2> imag (TREE_IMAGPART (cst), TREE_IMAGPART (cst)); |
408 | res.intersect (imag); | |
bccf4b88 AH |
409 | } |
410 | } | |
411 | } | |
412 | ||
413 | // Adjust the range for a REALPART_EXPR. | |
414 | ||
415 | static void | |
45c8523d | 416 | adjust_realpart_expr (vrange &res, const gimple *stmt) |
bccf4b88 AH |
417 | { |
418 | tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); | |
419 | ||
420 | if (TREE_CODE (name) != SSA_NAME) | |
421 | return; | |
422 | ||
423 | gimple *def_stmt = SSA_NAME_DEF_STMT (name); | |
424 | if (!SSA_NAME_DEF_STMT (name)) | |
425 | return; | |
426 | ||
d44dc131 JJ |
427 | if (is_gimple_assign (def_stmt) |
428 | && gimple_assign_rhs_code (def_stmt) == COMPLEX_CST) | |
bccf4b88 AH |
429 | { |
430 | tree cst = gimple_assign_rhs1 (def_stmt); | |
431 | if (TREE_CODE (cst) == COMPLEX_CST) | |
432 | { | |
433 | tree imag = TREE_REALPART (cst); | |
434 | int_range<2> tmp (imag, imag); | |
435 | res.intersect (tmp); | |
436 | } | |
437 | } | |
438 | } | |
439 | ||
4c85ff75 AM |
440 | // This function looks for situations when walking the use/def chains |
441 | // may provide additonal contextual range information not exposed on | |
bccf4b88 | 442 | // this statement. |
4c85ff75 AM |
443 | |
444 | static void | |
45c8523d | 445 | gimple_range_adjustment (vrange &res, const gimple *stmt) |
4c85ff75 AM |
446 | { |
447 | switch (gimple_expr_code (stmt)) | |
448 | { | |
449 | case POINTER_DIFF_EXPR: | |
45c8523d | 450 | adjust_pointer_diff_expr (as_a <irange> (res), stmt); |
4c85ff75 AM |
451 | return; |
452 | ||
453 | case IMAGPART_EXPR: | |
bccf4b88 AH |
454 | adjust_imagpart_expr (res, stmt); |
455 | return; | |
456 | ||
457 | case REALPART_EXPR: | |
458 | adjust_realpart_expr (res, stmt); | |
459 | return; | |
4c85ff75 AM |
460 | |
461 | default: | |
462 | break; | |
463 | } | |
464 | } | |
465 | ||
4c85ff75 AM |
466 | // Calculate a range for statement S and return it in R. If NAME is provided it |
467 | // represents the SSA_NAME on the LHS of the statement. It is only required | |
468 | // if there is more than one lhs/output. If a range cannot | |
469 | // be calculated, return false. | |
470 | ||
471 | bool | |
45c8523d | 472 | fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name) |
4c85ff75 AM |
473 | { |
474 | bool res = false; | |
475 | // If name and S are specified, make sure it is an LHS of S. | |
476 | gcc_checking_assert (!name || !gimple_get_lhs (s) || | |
477 | name == gimple_get_lhs (s)); | |
478 | ||
479 | if (!name) | |
480 | name = gimple_get_lhs (s); | |
481 | ||
482 | // Process addresses. | |
483 | if (gimple_code (s) == GIMPLE_ASSIGN | |
484 | && gimple_assign_rhs_code (s) == ADDR_EXPR) | |
45c8523d | 485 | return range_of_address (as_a <irange> (r), s, src); |
4c85ff75 | 486 | |
51ce0638 AM |
487 | gimple_range_op_handler handler (s); |
488 | if (handler) | |
489 | res = range_of_range_op (r, handler, src); | |
4c85ff75 AM |
490 | else if (is_a<gphi *>(s)) |
491 | res = range_of_phi (r, as_a<gphi *> (s), src); | |
492 | else if (is_a<gcall *>(s)) | |
493 | res = range_of_call (r, as_a<gcall *> (s), src); | |
494 | else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR) | |
495 | res = range_of_cond_expr (r, as_a<gassign *> (s), src); | |
496 | ||
497 | if (!res) | |
498 | { | |
478cc962 AM |
499 | // If no name specified or range is unsupported, bail. |
500 | if (!name || !gimple_range_ssa_p (name)) | |
4c85ff75 AM |
501 | return false; |
502 | // We don't understand the stmt, so return the global range. | |
45c8523d | 503 | gimple_range_global (r, name); |
4c85ff75 AM |
504 | return true; |
505 | } | |
506 | ||
507 | if (r.undefined_p ()) | |
508 | return true; | |
509 | ||
510 | // We sometimes get compatible types copied from operands, make sure | |
511 | // the correct type is being returned. | |
512 | if (name && TREE_TYPE (name) != r.type ()) | |
513 | { | |
514 | gcc_checking_assert (range_compatible_p (r.type (), TREE_TYPE (name))); | |
515 | range_cast (r, TREE_TYPE (name)); | |
516 | } | |
517 | return true; | |
518 | } | |
519 | ||
520 | // Calculate a range for range_op statement S and return it in R. If any | |
521 | // If a range cannot be calculated, return false. | |
522 | ||
523 | bool | |
51ce0638 AM |
524 | fold_using_range::range_of_range_op (vrange &r, |
525 | gimple_range_op_handler &handler, | |
526 | fur_source &src) | |
4c85ff75 | 527 | { |
51ce0638 AM |
528 | gcc_checking_assert (handler); |
529 | gimple *s = handler.stmt (); | |
478cc962 AM |
530 | tree type = gimple_range_type (s); |
531 | if (!type) | |
532 | return false; | |
4c85ff75 | 533 | |
51ce0638 AM |
534 | tree lhs = handler.lhs (); |
535 | tree op1 = handler.operand1 (); | |
536 | tree op2 = handler.operand2 (); | |
5608e410 AM |
537 | |
538 | // Certain types of builtin functions may have no arguments. | |
539 | if (!op1) | |
540 | { | |
541 | Value_Range r1 (type); | |
542 | if (!handler.fold_range (r, type, r1, r1)) | |
543 | r.set_varying (type); | |
544 | return true; | |
545 | } | |
546 | ||
45c8523d AH |
547 | Value_Range range1 (TREE_TYPE (op1)); |
548 | Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1)); | |
4c85ff75 AM |
549 | |
550 | if (src.get_operand (range1, op1)) | |
551 | { | |
552 | if (!op2) | |
553 | { | |
554 | // Fold range, and register any dependency if available. | |
45c8523d AH |
555 | Value_Range r2 (type); |
556 | r2.set_varying (type); | |
2f92f685 AM |
557 | if (!handler.fold_range (r, type, range1, r2)) |
558 | r.set_varying (type); | |
4c85ff75 AM |
559 | if (lhs && gimple_range_ssa_p (op1)) |
560 | { | |
561 | if (src.gori ()) | |
562 | src.gori ()->register_dependency (lhs, op1); | |
563 | relation_kind rel; | |
cf5bea76 | 564 | rel = handler.lhs_op1_relation (r, range1, range1); |
ade5531c | 565 | if (rel != VREL_VARYING) |
4c85ff75 AM |
566 | src.register_relation (s, rel, lhs, op1); |
567 | } | |
568 | } | |
569 | else if (src.get_operand (range2, op2)) | |
570 | { | |
571 | relation_kind rel = src.query_relation (op1, op2); | |
ade5531c | 572 | if (dump_file && (dump_flags & TDF_DETAILS) && rel != VREL_VARYING) |
4c85ff75 AM |
573 | { |
574 | fprintf (dump_file, " folding with relation "); | |
2f0b6a97 | 575 | print_generic_expr (dump_file, op1, TDF_SLIM); |
4c85ff75 | 576 | print_relation (dump_file, rel); |
2f0b6a97 | 577 | print_generic_expr (dump_file, op2, TDF_SLIM); |
4c85ff75 AM |
578 | fputc ('\n', dump_file); |
579 | } | |
580 | // Fold range, and register any dependency if available. | |
b565ac19 AM |
581 | if (!handler.fold_range (r, type, range1, range2, |
582 | relation_trio::op1_op2 (rel))) | |
2f92f685 | 583 | r.set_varying (type); |
a9058b08 | 584 | if (irange::supports_p (type)) |
45c8523d | 585 | relation_fold_and_or (as_a <irange> (r), s, src); |
4c85ff75 AM |
586 | if (lhs) |
587 | { | |
588 | if (src.gori ()) | |
589 | { | |
590 | src.gori ()->register_dependency (lhs, op1); | |
591 | src.gori ()->register_dependency (lhs, op2); | |
592 | } | |
593 | if (gimple_range_ssa_p (op1)) | |
594 | { | |
cf5bea76 | 595 | rel = handler.lhs_op1_relation (r, range1, range2, rel); |
ade5531c | 596 | if (rel != VREL_VARYING) |
4c85ff75 AM |
597 | src.register_relation (s, rel, lhs, op1); |
598 | } | |
599 | if (gimple_range_ssa_p (op2)) | |
600 | { | |
b565ac19 | 601 | rel = handler.lhs_op2_relation (r, range1, range2, rel); |
ade5531c | 602 | if (rel != VREL_VARYING) |
4c85ff75 AM |
603 | src.register_relation (s, rel, lhs, op2); |
604 | } | |
605 | } | |
fec75ab8 AH |
606 | // Check for an existing BB, as we maybe asked to fold an |
607 | // artificial statement not in the CFG. | |
608 | else if (is_a<gcond *> (s) && gimple_bb (s)) | |
198bc5ec AH |
609 | { |
610 | basic_block bb = gimple_bb (s); | |
611 | edge e0 = EDGE_SUCC (bb, 0); | |
612 | edge e1 = EDGE_SUCC (bb, 1); | |
613 | ||
614 | if (!single_pred_p (e0->dest)) | |
615 | e0 = NULL; | |
616 | if (!single_pred_p (e1->dest)) | |
617 | e1 = NULL; | |
45c8523d AH |
618 | src.register_outgoing_edges (as_a<gcond *> (s), |
619 | as_a <irange> (r), e0, e1); | |
198bc5ec | 620 | } |
4c85ff75 AM |
621 | } |
622 | else | |
623 | r.set_varying (type); | |
624 | } | |
625 | else | |
626 | r.set_varying (type); | |
627 | // Make certain range-op adjustments that aren't handled any other way. | |
628 | gimple_range_adjustment (r, s); | |
629 | return true; | |
630 | } | |
631 | ||
632 | // Calculate the range of an assignment containing an ADDR_EXPR. | |
633 | // Return the range in R. | |
634 | // If a range cannot be calculated, set it to VARYING and return true. | |
635 | ||
636 | bool | |
637 | fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) | |
638 | { | |
639 | gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); | |
640 | gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); | |
641 | ||
642 | bool strict_overflow_p; | |
643 | tree expr = gimple_assign_rhs1 (stmt); | |
644 | poly_int64 bitsize, bitpos; | |
645 | tree offset; | |
646 | machine_mode mode; | |
647 | int unsignedp, reversep, volatilep; | |
648 | tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, | |
649 | &bitpos, &offset, &mode, &unsignedp, | |
650 | &reversep, &volatilep); | |
651 | ||
652 | ||
653 | if (base != NULL_TREE | |
654 | && TREE_CODE (base) == MEM_REF | |
655 | && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) | |
656 | { | |
657 | tree ssa = TREE_OPERAND (base, 0); | |
658 | tree lhs = gimple_get_lhs (stmt); | |
659 | if (lhs && gimple_range_ssa_p (ssa) && src.gori ()) | |
660 | src.gori ()->register_dependency (lhs, ssa); | |
4c85ff75 AM |
661 | src.get_operand (r, ssa); |
662 | range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt))); | |
663 | ||
664 | poly_offset_int off = 0; | |
665 | bool off_cst = false; | |
666 | if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST) | |
667 | { | |
668 | off = mem_ref_offset (base); | |
669 | if (offset) | |
670 | off += poly_offset_int::from (wi::to_poly_wide (offset), | |
671 | SIGNED); | |
672 | off <<= LOG2_BITS_PER_UNIT; | |
673 | off += bitpos; | |
674 | off_cst = true; | |
675 | } | |
676 | /* If &X->a is equal to X, the range of X is the result. */ | |
677 | if (off_cst && known_eq (off, 0)) | |
c39cb6bf | 678 | return true; |
4c85ff75 AM |
679 | else if (flag_delete_null_pointer_checks |
680 | && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) | |
681 | { | |
c39cb6bf JJ |
682 | /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't |
683 | allow going from non-NULL pointer to NULL. */ | |
45c8523d | 684 | if (r.undefined_p () || !r.contains_p (build_zero_cst (r.type ()))) |
c39cb6bf JJ |
685 | { |
686 | /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT | |
687 | using POINTER_PLUS_EXPR if off_cst and just fall back to | |
688 | this. */ | |
45c8523d | 689 | r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); |
c39cb6bf JJ |
690 | return true; |
691 | } | |
4c85ff75 AM |
692 | } |
693 | /* If MEM_REF has a "positive" offset, consider it non-NULL | |
694 | always, for -fdelete-null-pointer-checks also "negative" | |
695 | ones. Punt for unknown offsets (e.g. variable ones). */ | |
696 | if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) | |
697 | && off_cst | |
698 | && known_ne (off, 0) | |
699 | && (flag_delete_null_pointer_checks || known_gt (off, 0))) | |
700 | { | |
45c8523d | 701 | r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); |
4c85ff75 AM |
702 | return true; |
703 | } | |
45c8523d | 704 | r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt))); |
4c85ff75 AM |
705 | return true; |
706 | } | |
707 | ||
708 | // Handle "= &a". | |
709 | if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p)) | |
710 | { | |
45c8523d | 711 | r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); |
4c85ff75 AM |
712 | return true; |
713 | } | |
714 | ||
715 | // Otherwise return varying. | |
45c8523d | 716 | r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt))); |
4c85ff75 AM |
717 | return true; |
718 | } | |
719 | ||
720 | // Calculate a range for phi statement S and return it in R. | |
721 | // If a range cannot be calculated, return false. | |
722 | ||
723 | bool | |
45c8523d | 724 | fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src) |
4c85ff75 AM |
725 | { |
726 | tree phi_def = gimple_phi_result (phi); | |
478cc962 | 727 | tree type = gimple_range_type (phi); |
45c8523d AH |
728 | Value_Range arg_range (type); |
729 | Value_Range equiv_range (type); | |
4c85ff75 AM |
730 | unsigned x; |
731 | ||
478cc962 | 732 | if (!type) |
4c85ff75 AM |
733 | return false; |
734 | ||
73cf73af AM |
735 | // Track if all executable arguments are the same. |
736 | tree single_arg = NULL_TREE; | |
737 | bool seen_arg = false; | |
738 | ||
4c85ff75 AM |
739 | // Start with an empty range, unioning in each argument's range. |
740 | r.set_undefined (); | |
741 | for (x = 0; x < gimple_phi_num_args (phi); x++) | |
742 | { | |
743 | tree arg = gimple_phi_arg_def (phi, x); | |
6d936684 AM |
744 | // An argument that is the same as the def provides no new range. |
745 | if (arg == phi_def) | |
746 | continue; | |
747 | ||
4c85ff75 AM |
748 | edge e = gimple_phi_arg_edge (phi, x); |
749 | ||
4c85ff75 AM |
750 | // Get the range of the argument on its edge. |
751 | src.get_phi_operand (arg_range, arg, e); | |
73cf73af AM |
752 | |
753 | if (!arg_range.undefined_p ()) | |
754 | { | |
755 | // Register potential dependencies for stale value tracking. | |
e43b15c8 AM |
756 | // Likewise, if the incoming PHI argument is equivalent to this |
757 | // PHI definition, it provides no new info. Accumulate these ranges | |
758 | // in case all arguments are equivalences. | |
ade5531c | 759 | if (src.query ()->query_relation (e, arg, phi_def, false) == VREL_EQ) |
e43b15c8 AM |
760 | equiv_range.union_(arg_range); |
761 | else | |
762 | r.union_ (arg_range); | |
763 | ||
73cf73af AM |
764 | if (gimple_range_ssa_p (arg) && src.gori ()) |
765 | src.gori ()->register_dependency (phi_def, arg); | |
766 | ||
767 | // Track if all arguments are the same. | |
768 | if (!seen_arg) | |
769 | { | |
770 | seen_arg = true; | |
771 | single_arg = arg; | |
772 | } | |
773 | else if (single_arg != arg) | |
774 | single_arg = NULL_TREE; | |
775 | } | |
776 | ||
4c85ff75 | 777 | // Once the value reaches varying, stop looking. |
73cf73af | 778 | if (r.varying_p () && single_arg == NULL_TREE) |
4c85ff75 AM |
779 | break; |
780 | } | |
781 | ||
661c02e5 AM |
782 | // If all arguments were equivalences, use the equivalence ranges as no |
783 | // arguments were processed. | |
e43b15c8 | 784 | if (r.undefined_p () && !equiv_range.undefined_p ()) |
661c02e5 AM |
785 | r = equiv_range; |
786 | ||
73cf73af AM |
787 | // If the PHI boils down to a single effective argument, look at it. |
788 | if (single_arg) | |
789 | { | |
790 | // Symbolic arguments are equivalences. | |
791 | if (gimple_range_ssa_p (single_arg)) | |
ade5531c | 792 | src.register_relation (phi, VREL_EQ, phi_def, single_arg); |
73cf73af AM |
793 | else if (src.get_operand (arg_range, single_arg) |
794 | && arg_range.singleton_p ()) | |
795 | { | |
796 | // Numerical arguments that are a constant can be returned as | |
797 | // the constant. This can help fold later cases where even this | |
798 | // constant might have been UNDEFINED via an unreachable edge. | |
799 | r = arg_range; | |
800 | return true; | |
801 | } | |
802 | } | |
803 | ||
4c85ff75 | 804 | // If SCEV is available, query if this PHI has any knonwn values. |
460dcec4 | 805 | if (scev_initialized_p () |
6d41f7c3 | 806 | && !POINTER_TYPE_P (TREE_TYPE (phi_def))) |
4c85ff75 | 807 | { |
4c85ff75 AM |
808 | class loop *l = loop_containing_stmt (phi); |
809 | if (l && loop_outer (l)) | |
810 | { | |
6d41f7c3 | 811 | Value_Range loop_range (type); |
4c85ff75 AM |
812 | range_of_ssa_name_with_loop_info (loop_range, phi_def, l, phi, src); |
813 | if (!loop_range.varying_p ()) | |
814 | { | |
815 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
816 | { | |
817 | fprintf (dump_file, " Loops range found for "); | |
818 | print_generic_expr (dump_file, phi_def, TDF_SLIM); | |
819 | fprintf (dump_file, ": "); | |
820 | loop_range.dump (dump_file); | |
821 | fprintf (dump_file, " and calculated range :"); | |
822 | r.dump (dump_file); | |
823 | fprintf (dump_file, "\n"); | |
824 | } | |
825 | r.intersect (loop_range); | |
826 | } | |
827 | } | |
828 | } | |
829 | ||
830 | return true; | |
831 | } | |
832 | ||
833 | // Calculate a range for call statement S and return it in R. | |
834 | // If a range cannot be calculated, return false. | |
835 | ||
836 | bool | |
5608e410 | 837 | fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &) |
4c85ff75 | 838 | { |
478cc962 AM |
839 | tree type = gimple_range_type (call); |
840 | if (!type) | |
841 | return false; | |
842 | ||
4c85ff75 AM |
843 | tree lhs = gimple_call_lhs (call); |
844 | bool strict_overflow_p; | |
845 | ||
5608e410 | 846 | if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p)) |
45c8523d | 847 | r.set_nonnegative (type); |
4c85ff75 AM |
848 | else if (gimple_call_nonnull_result_p (call) |
849 | || gimple_call_nonnull_arg (call)) | |
45c8523d | 850 | r.set_nonzero (type); |
4c85ff75 AM |
851 | else |
852 | r.set_varying (type); | |
853 | ||
854 | // If there is an LHS, intersect that with what is known. | |
855 | if (lhs) | |
856 | { | |
45c8523d AH |
857 | Value_Range def (TREE_TYPE (lhs)); |
858 | gimple_range_global (def, lhs); | |
4c85ff75 AM |
859 | r.intersect (def); |
860 | } | |
861 | return true; | |
862 | } | |
863 | ||
4c85ff75 AM |
864 | // Calculate a range for COND_EXPR statement S and return it in R. |
865 | // If a range cannot be calculated, return false. | |
866 | ||
867 | bool | |
45c8523d | 868 | fold_using_range::range_of_cond_expr (vrange &r, gassign *s, fur_source &src) |
4c85ff75 | 869 | { |
4c85ff75 AM |
870 | tree cond = gimple_assign_rhs1 (s); |
871 | tree op1 = gimple_assign_rhs2 (s); | |
872 | tree op2 = gimple_assign_rhs3 (s); | |
873 | ||
478cc962 AM |
874 | tree type = gimple_range_type (s); |
875 | if (!type) | |
4c85ff75 AM |
876 | return false; |
877 | ||
45c8523d AH |
878 | Value_Range range1 (TREE_TYPE (op1)); |
879 | Value_Range range2 (TREE_TYPE (op2)); | |
880 | Value_Range cond_range (TREE_TYPE (cond)); | |
478cc962 AM |
881 | gcc_checking_assert (gimple_assign_rhs_code (s) == COND_EXPR); |
882 | gcc_checking_assert (range_compatible_p (TREE_TYPE (op1), TREE_TYPE (op2))); | |
4c85ff75 AM |
883 | src.get_operand (cond_range, cond); |
884 | src.get_operand (range1, op1); | |
885 | src.get_operand (range2, op2); | |
886 | ||
e15425e8 AM |
887 | // Try to see if there is a dependence between the COND and either operand |
888 | if (src.gori ()) | |
889 | if (src.gori ()->condexpr_adjust (range1, range2, s, cond, op1, op2, src)) | |
890 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
891 | { | |
892 | fprintf (dump_file, "Possible COND_EXPR adjustment. Range op1 : "); | |
893 | range1.dump(dump_file); | |
894 | fprintf (dump_file, " and Range op2: "); | |
895 | range2.dump(dump_file); | |
896 | fprintf (dump_file, "\n"); | |
897 | } | |
898 | ||
4c85ff75 AM |
899 | // If the condition is known, choose the appropriate expression. |
900 | if (cond_range.singleton_p ()) | |
901 | { | |
902 | // False, pick second operand. | |
903 | if (cond_range.zero_p ()) | |
904 | r = range2; | |
905 | else | |
906 | r = range1; | |
907 | } | |
908 | else | |
909 | { | |
910 | r = range1; | |
911 | r.union_ (range2); | |
912 | } | |
ea789238 AM |
913 | gcc_checking_assert (r.undefined_p () |
914 | || range_compatible_p (r.type (), type)); | |
4c85ff75 AM |
915 | return true; |
916 | } | |
917 | ||
6d41f7c3 AH |
918 | // Return the lower bound of R as a tree. |
919 | ||
920 | static inline tree | |
921 | tree_lower_bound (const vrange &r, tree type) | |
922 | { | |
923 | if (is_a <irange> (r)) | |
924 | return wide_int_to_tree (type, as_a <irange> (r).lower_bound ()); | |
925 | // ?? Handle floats when they contain endpoints. | |
926 | return NULL; | |
927 | } | |
928 | ||
929 | // Return the upper bound of R as a tree. | |
930 | ||
931 | static inline tree | |
932 | tree_upper_bound (const vrange &r, tree type) | |
933 | { | |
934 | if (is_a <irange> (r)) | |
935 | return wide_int_to_tree (type, as_a <irange> (r).upper_bound ()); | |
936 | // ?? Handle floats when they contain endpoints. | |
937 | return NULL; | |
938 | } | |
939 | ||
4c85ff75 AM |
940 | // If SCEV has any information about phi node NAME, return it as a range in R. |
941 | ||
942 | void | |
6d41f7c3 | 943 | fold_using_range::range_of_ssa_name_with_loop_info (vrange &r, tree name, |
4c85ff75 AM |
944 | class loop *l, gphi *phi, |
945 | fur_source &src) | |
946 | { | |
947 | gcc_checking_assert (TREE_CODE (name) == SSA_NAME); | |
948 | tree min, max, type = TREE_TYPE (name); | |
460dcec4 | 949 | if (bounds_of_var_in_loop (&min, &max, src.query (), l, phi, name)) |
4c85ff75 | 950 | { |
6d41f7c3 | 951 | if (!is_gimple_constant (min)) |
4c85ff75 AM |
952 | { |
953 | if (src.query ()->range_of_expr (r, min, phi) && !r.undefined_p ()) | |
6d41f7c3 | 954 | min = tree_lower_bound (r, type); |
4c85ff75 AM |
955 | else |
956 | min = vrp_val_min (type); | |
957 | } | |
6d41f7c3 | 958 | if (!is_gimple_constant (max)) |
4c85ff75 AM |
959 | { |
960 | if (src.query ()->range_of_expr (r, max, phi) && !r.undefined_p ()) | |
6d41f7c3 | 961 | max = tree_upper_bound (r, type); |
4c85ff75 AM |
962 | else |
963 | max = vrp_val_max (type); | |
964 | } | |
6d41f7c3 AH |
965 | if (min && max) |
966 | { | |
967 | r.set (min, max); | |
968 | return; | |
969 | } | |
4c85ff75 | 970 | } |
6d41f7c3 | 971 | r.set_varying (type); |
4c85ff75 AM |
972 | } |
973 | ||
974 | // ----------------------------------------------------------------------- | |
975 | ||
976 | // Check if an && or || expression can be folded based on relations. ie | |
977 | // c_2 = a_6 > b_7 | |
978 | // c_3 = a_6 < b_7 | |
979 | // c_4 = c_2 && c_3 | |
980 | // c_2 and c_3 can never be true at the same time, | |
981 | // Therefore c_4 can always resolve to false based purely on the relations. | |
982 | ||
983 | void | |
984 | fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, | |
985 | fur_source &src) | |
986 | { | |
987 | // No queries or already folded. | |
988 | if (!src.gori () || !src.query ()->oracle () || lhs_range.singleton_p ()) | |
989 | return; | |
990 | ||
991 | // Only care about AND and OR expressions. | |
992 | enum tree_code code = gimple_expr_code (s); | |
993 | bool is_and = false; | |
994 | if (code == BIT_AND_EXPR || code == TRUTH_AND_EXPR) | |
995 | is_and = true; | |
996 | else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR) | |
997 | return; | |
998 | ||
51ce0638 AM |
999 | gimple_range_op_handler handler (s); |
1000 | tree lhs = handler.lhs (); | |
1001 | tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); | |
1002 | tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); | |
4c85ff75 AM |
1003 | |
1004 | // Deal with || and && only when there is a full set of symbolics. | |
1005 | if (!lhs || !ssa1 || !ssa2 | |
1006 | || (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE) | |
1007 | || (TREE_CODE (TREE_TYPE (ssa1)) != BOOLEAN_TYPE) | |
1008 | || (TREE_CODE (TREE_TYPE (ssa2)) != BOOLEAN_TYPE)) | |
1009 | return; | |
1010 | ||
1011 | // Now we know its a boolean AND or OR expression with boolean operands. | |
1012 | // Ideally we search dependencies for common names, and see what pops out. | |
1013 | // until then, simply try to resolve direct dependencies. | |
1014 | ||
918ccccb AM |
1015 | gimple *ssa1_stmt = SSA_NAME_DEF_STMT (ssa1); |
1016 | gimple *ssa2_stmt = SSA_NAME_DEF_STMT (ssa2); | |
1017 | ||
51ce0638 AM |
1018 | gimple_range_op_handler handler1 (ssa1_stmt); |
1019 | gimple_range_op_handler handler2 (ssa2_stmt); | |
918ccccb AM |
1020 | |
1021 | // If either handler is not present, no relation can be found. | |
1022 | if (!handler1 || !handler2) | |
1023 | return; | |
1024 | ||
1025 | // Both stmts will need to have 2 ssa names in the stmt. | |
51ce0638 AM |
1026 | tree ssa1_dep1 = gimple_range_ssa_p (handler1.operand1 ()); |
1027 | tree ssa1_dep2 = gimple_range_ssa_p (handler1.operand2 ()); | |
1028 | tree ssa2_dep1 = gimple_range_ssa_p (handler2.operand1 ()); | |
1029 | tree ssa2_dep2 = gimple_range_ssa_p (handler2.operand2 ()); | |
918ccccb AM |
1030 | |
1031 | if (!ssa1_dep1 || !ssa1_dep2 || !ssa2_dep1 || !ssa2_dep2) | |
4c85ff75 AM |
1032 | return; |
1033 | ||
4c85ff75 AM |
1034 | // Make sure they are the same dependencies, and detect the order of the |
1035 | // relationship. | |
1036 | bool reverse_op2 = true; | |
1037 | if (ssa1_dep1 == ssa2_dep1 && ssa1_dep2 == ssa2_dep2) | |
1038 | reverse_op2 = false; | |
1039 | else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1) | |
1040 | return; | |
1041 | ||
4c85ff75 AM |
1042 | int_range<2> bool_one (boolean_true_node, boolean_true_node); |
1043 | ||
cf5bea76 AH |
1044 | relation_kind relation1 = handler1.op1_op2_relation (bool_one); |
1045 | relation_kind relation2 = handler2.op1_op2_relation (bool_one); | |
ade5531c | 1046 | if (relation1 == VREL_VARYING || relation2 == VREL_VARYING) |
4c85ff75 AM |
1047 | return; |
1048 | ||
1049 | if (reverse_op2) | |
1050 | relation2 = relation_negate (relation2); | |
1051 | ||
1052 | // x && y is false if the relation intersection of the true cases is NULL. | |
ade5531c | 1053 | if (is_and && relation_intersect (relation1, relation2) == VREL_UNDEFINED) |
4c85ff75 AM |
1054 | lhs_range = int_range<2> (boolean_false_node, boolean_false_node); |
1055 | // x || y is true if the union of the true cases is NO-RELATION.. | |
1056 | // ie, one or the other being true covers the full range of possibilties. | |
ade5531c | 1057 | else if (!is_and && relation_union (relation1, relation2) == VREL_VARYING) |
4c85ff75 AM |
1058 | lhs_range = bool_one; |
1059 | else | |
1060 | return; | |
1061 | ||
1062 | range_cast (lhs_range, TREE_TYPE (lhs)); | |
1063 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
1064 | { | |
1065 | fprintf (dump_file, " Relation adjustment: "); | |
1066 | print_generic_expr (dump_file, ssa1, TDF_SLIM); | |
1067 | fprintf (dump_file, " and "); | |
1068 | print_generic_expr (dump_file, ssa2, TDF_SLIM); | |
1069 | fprintf (dump_file, " combine to produce "); | |
1070 | lhs_range.dump (dump_file); | |
1071 | fputc ('\n', dump_file); | |
1072 | } | |
1073 | ||
1074 | return; | |
1075 | } | |
1076 | ||
1077 | // Register any outgoing edge relations from a conditional branch. | |
1078 | ||
1079 | void | |
198bc5ec | 1080 | fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e1) |
4c85ff75 | 1081 | { |
a0accaa9 | 1082 | int_range<2> e0_range, e1_range; |
4c85ff75 | 1083 | tree name; |
4c85ff75 AM |
1084 | basic_block bb = gimple_bb (s); |
1085 | ||
51ce0638 | 1086 | gimple_range_op_handler handler (s); |
70daecc0 AM |
1087 | if (!handler) |
1088 | return; | |
1089 | ||
198bc5ec | 1090 | if (e0) |
a0accaa9 AM |
1091 | { |
1092 | // If this edge is never taken, ignore it. | |
1093 | gcond_edge_range (e0_range, e0); | |
1094 | e0_range.intersect (lhs_range); | |
1095 | if (e0_range.undefined_p ()) | |
1096 | e0 = NULL; | |
1097 | } | |
1098 | ||
198bc5ec | 1099 | if (e1) |
a0accaa9 AM |
1100 | { |
1101 | // If this edge is never taken, ignore it. | |
1102 | gcond_edge_range (e1_range, e1); | |
1103 | e1_range.intersect (lhs_range); | |
1104 | if (e1_range.undefined_p ()) | |
1105 | e1 = NULL; | |
1106 | } | |
4c85ff75 | 1107 | |
4c85ff75 AM |
1108 | if (!e0 && !e1) |
1109 | return; | |
1110 | ||
1111 | // First, register the gcond itself. This will catch statements like | |
1112 | // if (a_2 < b_5) | |
51ce0638 AM |
1113 | tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); |
1114 | tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); | |
4c85ff75 AM |
1115 | if (ssa1 && ssa2) |
1116 | { | |
4c85ff75 AM |
1117 | if (e0) |
1118 | { | |
cf5bea76 | 1119 | relation_kind relation = handler.op1_op2_relation (e0_range); |
ade5531c | 1120 | if (relation != VREL_VARYING) |
198bc5ec | 1121 | register_relation (e0, relation, ssa1, ssa2); |
4c85ff75 AM |
1122 | } |
1123 | if (e1) | |
1124 | { | |
cf5bea76 | 1125 | relation_kind relation = handler.op1_op2_relation (e1_range); |
ade5531c | 1126 | if (relation != VREL_VARYING) |
198bc5ec | 1127 | register_relation (e1, relation, ssa1, ssa2); |
4c85ff75 AM |
1128 | } |
1129 | } | |
1130 | ||
1131 | // Outgoing relations of GORI exports require a gori engine. | |
198bc5ec | 1132 | if (!gori ()) |
4c85ff75 AM |
1133 | return; |
1134 | ||
4c85ff75 AM |
1135 | // Now look for other relations in the exports. This will find stmts |
1136 | // leading to the condition such as: | |
1137 | // c_2 = a_4 < b_7 | |
1138 | // if (c_2) | |
198bc5ec | 1139 | FOR_EACH_GORI_EXPORT_NAME (*(gori ()), bb, name) |
4c85ff75 AM |
1140 | { |
1141 | if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE) | |
1142 | continue; | |
1143 | gimple *stmt = SSA_NAME_DEF_STMT (name); | |
51ce0638 | 1144 | gimple_range_op_handler handler (stmt); |
4c85ff75 AM |
1145 | if (!handler) |
1146 | continue; | |
51ce0638 AM |
1147 | tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); |
1148 | tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); | |
45c8523d | 1149 | Value_Range r (TREE_TYPE (name)); |
4c85ff75 AM |
1150 | if (ssa1 && ssa2) |
1151 | { | |
198bc5ec | 1152 | if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query) |
4c85ff75 AM |
1153 | && r.singleton_p ()) |
1154 | { | |
cf5bea76 | 1155 | relation_kind relation = handler.op1_op2_relation (r); |
ade5531c | 1156 | if (relation != VREL_VARYING) |
198bc5ec | 1157 | register_relation (e0, relation, ssa1, ssa2); |
4c85ff75 | 1158 | } |
198bc5ec | 1159 | if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query) |
4c85ff75 AM |
1160 | && r.singleton_p ()) |
1161 | { | |
cf5bea76 | 1162 | relation_kind relation = handler.op1_op2_relation (r); |
ade5531c | 1163 | if (relation != VREL_VARYING) |
198bc5ec | 1164 | register_relation (e1, relation, ssa1, ssa2); |
4c85ff75 AM |
1165 | } |
1166 | } | |
1167 | } | |
1168 | } |