]>
| Commit | Line | Data |
|---|---|---|
| 156d7d8d | 1 | /* Gimple range inference implementation. |
| 6441eb6d | 2 | Copyright (C) 2022-2025 Free Software Foundation, Inc. |
| b7501739 AM |
3 | Contributed by Andrew MacLeod <amacleod@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 "tree.h" | |
| 27 | #include "gimple.h" | |
| 28 | #include "ssa.h" | |
| 29 | #include "gimple-pretty-print.h" | |
| 30 | #include "gimple-range.h" | |
| 3ae9def0 | 31 | #include "value-range-storage.h" |
| b7501739 AM |
32 | #include "tree-cfg.h" |
| 33 | #include "target.h" | |
| 34 | #include "attribs.h" | |
| 35 | #include "gimple-iterator.h" | |
| 36 | #include "gimple-walk.h" | |
| 37 | #include "cfganal.h" | |
| 53e6d7a3 | 38 | #include "tree-dfa.h" |
| b7501739 | 39 | |
| 07441e41 AM |
40 | // Create the global oracle. |
| 41 | ||
| 42 | infer_range_oracle infer_oracle; | |
| 43 | ||
| 44 | // This class is merely an accessor which is granted internals to | |
| 45 | // gimple_infer_range such that non_null_loadstore as a static callback can | |
| 46 | // call the protected add_nonzero (). | |
| 47 | // Static functions ccannot be friends, so we do it through a class wrapper. | |
| 48 | ||
| 49 | class non_null_wrapper | |
| 50 | { | |
| 51 | public: | |
| 52 | inline non_null_wrapper (gimple_infer_range *infer) : m_infer (infer) { } | |
| 53 | inline void add_nonzero (tree name) { m_infer->add_nonzero (name); } | |
| 54 | inline void add_range (tree t, vrange &r) { m_infer->add_range (t, r); } | |
| 55 | private: | |
| 56 | gimple_infer_range *m_infer; | |
| 57 | }; | |
| 58 | ||
| b7501739 AM |
59 | // Adapted from infer_nonnull_range_by_dereference and check_loadstore |
| 60 | // to process nonnull ssa_name OP in S. DATA contains a pointer to a | |
| 156d7d8d | 61 | // stmt range inference instance. |
| b7501739 AM |
62 | |
| 63 | static bool | |
| 64 | non_null_loadstore (gimple *, tree op, tree, void *data) | |
| 65 | { | |
| 66 | if (TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF) | |
| 67 | { | |
| 68 | /* Some address spaces may legitimately dereference zero. */ | |
| 69 | addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (op)); | |
| 70 | if (!targetm.addr_space.zero_address_valid (as)) | |
| 71 | { | |
| 07441e41 AM |
72 | non_null_wrapper wrapper ((gimple_infer_range *)data); |
| 73 | wrapper.add_nonzero (TREE_OPERAND (op, 0)); | |
| b7501739 AM |
74 | } |
| 75 | } | |
| 76 | return false; | |
| 77 | } | |
| 78 | ||
| 53e6d7a3 AM |
79 | // Process an ASSUME call to see if there are any inferred ranges available. |
| 80 | ||
| 81 | void | |
| 82 | gimple_infer_range::check_assume_func (gcall *call) | |
| 83 | { | |
| 84 | tree arg; | |
| 85 | unsigned i; | |
| 86 | tree assume_id = TREE_OPERAND (gimple_call_arg (call, 0), 0); | |
| 87 | if (!assume_id) | |
| 88 | return; | |
| 89 | struct function *fun = DECL_STRUCT_FUNCTION (assume_id); | |
| 90 | if (!fun) | |
| 91 | return; | |
| c46b5b0a | 92 | // Loop over arguments, matching them to the assume parameters. |
| 53e6d7a3 AM |
93 | for (arg = DECL_ARGUMENTS (assume_id), i = 1; |
| 94 | arg && i < gimple_call_num_args (call); | |
| 95 | i++, arg = DECL_CHAIN (arg)) | |
| 96 | { | |
| 97 | tree op = gimple_call_arg (call, i); | |
| 98 | tree type = TREE_TYPE (op); | |
| 3dedfad5 | 99 | if (gimple_range_ssa_p (op) && value_range::supports_type_p (type)) |
| 53e6d7a3 AM |
100 | { |
| 101 | tree default_def = ssa_default_def (fun, arg); | |
| 102 | if (!default_def || type != TREE_TYPE (default_def)) | |
| 103 | continue; | |
| 104 | // Query the global range of the default def in the assume function. | |
| 3dedfad5 | 105 | value_range assume_range (type); |
| 99f3ad2e | 106 | gimple_range_global (assume_range, default_def, fun); |
| 53e6d7a3 AM |
107 | // If there is a non-varying result, add it as an inferred range. |
| 108 | if (!assume_range.varying_p ()) | |
| 109 | { | |
| 110 | add_range (op, assume_range); | |
| 111 | if (dump_file) | |
| 112 | { | |
| 113 | print_generic_expr (dump_file, assume_id, TDF_SLIM); | |
| 114 | fprintf (dump_file, " assume inferred range of "); | |
| 115 | print_generic_expr (dump_file, op, TDF_SLIM); | |
| 116 | fprintf (dump_file, " (param "); | |
| 117 | print_generic_expr (dump_file, arg, TDF_SLIM); | |
| 118 | fprintf (dump_file, ") = "); | |
| 119 | assume_range.dump (dump_file); | |
| 120 | fputc ('\n', dump_file); | |
| 121 | } | |
| 122 | } | |
| 123 | } | |
| 124 | } | |
| 125 | } | |
| 126 | ||
| a8bb495a | 127 | // Add NAME and RANGE to the range inference summary. |
| b7501739 AM |
128 | |
| 129 | void | |
| 45c8523d | 130 | gimple_infer_range::add_range (tree name, vrange &range) |
| b7501739 | 131 | { |
| efc4255d AM |
132 | // Do not add an inferred range if it is VARYING. |
| 133 | if (range.varying_p ()) | |
| 134 | return; | |
| b7501739 AM |
135 | m_names[num_args] = name; |
| 136 | m_ranges[num_args] = range; | |
| 137 | if (num_args < size_limit - 1) | |
| 138 | num_args++; | |
| 139 | } | |
| 140 | ||
| 156d7d8d | 141 | // Add a nonzero range for NAME to the range inference summary. |
| b7501739 AM |
142 | |
| 143 | void | |
| 156d7d8d | 144 | gimple_infer_range::add_nonzero (tree name) |
| b7501739 AM |
145 | { |
| 146 | if (!gimple_range_ssa_p (name)) | |
| 147 | return; | |
| da73261c | 148 | prange nz; |
| b7501739 AM |
149 | nz.set_nonzero (TREE_TYPE (name)); |
| 150 | add_range (name, nz); | |
| 151 | } | |
| 152 | ||
| 156d7d8d | 153 | // Process S for range inference and fill in the summary list. |
| faddf229 | 154 | // This is the routine where any new inferred ranges should be added. |
| efc4255d | 155 | // If USE_RANGEOPS is true, invoke range-ops on stmts with a single |
| faddf229 | 156 | // ssa-name a constant to reflect an inferred range. ie |
| efc4255d AM |
157 | // x_2 = y_3 + 1 will provide an inferred range for y_3 of [-INF, +INF - 1]. |
| 158 | // This defaults to FALSE as it can be expensive., | |
| b7501739 | 159 | |
| faddf229 AM |
160 | gimple_infer_range::gimple_infer_range (gimple *s, range_query *q, |
| 161 | bool use_rangeops) | |
| b7501739 AM |
162 | { |
| 163 | num_args = 0; | |
| 164 | ||
| 165 | if (is_a<gphi *> (s)) | |
| 166 | return; | |
| 167 | ||
| faddf229 AM |
168 | // Default to the global query if none provided. |
| 169 | if (!q) | |
| 170 | q = get_global_range_query (); | |
| 171 | ||
| b7501739 AM |
172 | if (is_a<gcall *> (s) && flag_delete_null_pointer_checks) |
| 173 | { | |
| 174 | tree fntype = gimple_call_fntype (s); | |
| 175 | bitmap nonnullargs = get_nonnull_args (fntype); | |
| 176 | // Process any non-null arguments | |
| 177 | if (nonnullargs) | |
| 178 | { | |
| 179 | for (unsigned i = 0; i < gimple_call_num_args (s); i++) | |
| 180 | { | |
| 181 | if (bitmap_empty_p (nonnullargs) | |
| 182 | || bitmap_bit_p (nonnullargs, i)) | |
| 183 | { | |
| 184 | tree op = gimple_call_arg (s, i); | |
| 185 | if (POINTER_TYPE_P (TREE_TYPE (op))) | |
| 186 | add_nonzero (op); | |
| 187 | } | |
| 188 | } | |
| 189 | BITMAP_FREE (nonnullargs); | |
| 190 | } | |
| 912d5cfb JJ |
191 | if (fntype) |
| 192 | for (tree attrs = TYPE_ATTRIBUTES (fntype); | |
| 193 | (attrs = lookup_attribute ("nonnull_if_nonzero", attrs)); | |
| 194 | attrs = TREE_CHAIN (attrs)) | |
| 195 | { | |
| 196 | tree args = TREE_VALUE (attrs); | |
| 197 | unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; | |
| 198 | unsigned int idx2 | |
| 199 | = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; | |
| e33409a8 JJ |
200 | unsigned int idx3 = idx2; |
| 201 | if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args))) | |
| 202 | idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1; | |
| 912d5cfb | 203 | if (idx < gimple_call_num_args (s) |
| e33409a8 JJ |
204 | && idx2 < gimple_call_num_args (s) |
| 205 | && idx3 < gimple_call_num_args (s)) | |
| 912d5cfb JJ |
206 | { |
| 207 | tree arg = gimple_call_arg (s, idx); | |
| 208 | tree arg2 = gimple_call_arg (s, idx2); | |
| e33409a8 | 209 | tree arg3 = gimple_call_arg (s, idx3); |
| 912d5cfb JJ |
210 | if (!POINTER_TYPE_P (TREE_TYPE (arg)) |
| 211 | || !INTEGRAL_TYPE_P (TREE_TYPE (arg2)) | |
| e33409a8 JJ |
212 | || !INTEGRAL_TYPE_P (TREE_TYPE (arg3)) |
| 213 | || integer_zerop (arg2) | |
| 214 | || integer_zerop (arg3)) | |
| 912d5cfb | 215 | continue; |
| e33409a8 | 216 | if (integer_nonzerop (arg2) && integer_nonzerop (arg3)) |
| 912d5cfb | 217 | add_nonzero (arg); |
| 1e27e9a3 JJ |
218 | else |
| 219 | { | |
| 220 | value_range r (TREE_TYPE (arg2)); | |
| 221 | if (q->range_of_expr (r, arg2, s) | |
| 222 | && !r.contains_p (build_zero_cst (TREE_TYPE (arg2)))) | |
| e33409a8 JJ |
223 | { |
| 224 | if (idx2 == idx3) | |
| 225 | add_nonzero (arg); | |
| 226 | else | |
| 227 | { | |
| 228 | value_range r2 (TREE_TYPE (arg3)); | |
| 229 | tree zero3 = build_zero_cst (TREE_TYPE (arg3)); | |
| 230 | if (q->range_of_expr (r2, arg3, s) | |
| 231 | && !r2.contains_p (zero3)) | |
| 232 | add_nonzero (arg); | |
| 233 | } | |
| 234 | } | |
| 1e27e9a3 | 235 | } |
| 912d5cfb JJ |
236 | } |
| 237 | } | |
| b7501739 AM |
238 | // Fallthru and walk load/store ops now. |
| 239 | } | |
| 240 | ||
| 53e6d7a3 AM |
241 | // Check for inferred ranges from ASSUME calls. |
| 242 | if (is_a<gcall *> (s) && gimple_call_internal_p (s) | |
| 243 | && gimple_call_internal_fn (s) == IFN_ASSUME) | |
| 244 | check_assume_func (as_a<gcall *> (s)); | |
| 245 | ||
| b7501739 AM |
246 | // Look for possible non-null values. |
| 247 | if (flag_delete_null_pointer_checks && gimple_code (s) != GIMPLE_ASM | |
| 248 | && !gimple_clobber_p (s)) | |
| 249 | walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore, | |
| 250 | non_null_loadstore); | |
| 251 | ||
| efc4255d AM |
252 | // Gated by flag. |
| 253 | if (!use_rangeops) | |
| 254 | return; | |
| 255 | ||
| 256 | // Check if there are any inferred ranges from range-ops. | |
| 257 | gimple_range_op_handler handler (s); | |
| 258 | if (!handler) | |
| 259 | return; | |
| 260 | ||
| 261 | // Only proceed if ONE operand is an SSA_NAME, This may provide an | |
| 262 | // inferred range for 'y + 3' , but will bypass expressions like | |
| 263 | // 'y + z' as it depends on symbolic values. | |
| 264 | tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); | |
| 265 | tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); | |
| 266 | if ((ssa1 != NULL) == (ssa2 != NULL)) | |
| 267 | return; | |
| 268 | ||
| 269 | // The other operand should be a constant, so just use the global range | |
| 270 | // query to pick up any other values. | |
| 271 | if (ssa1) | |
| 272 | { | |
| 3dedfad5 | 273 | value_range op1 (TREE_TYPE (ssa1)); |
| faddf229 | 274 | if (op1_range (op1, s, q) && !op1.varying_p ()) |
| efc4255d AM |
275 | add_range (ssa1, op1); |
| 276 | } | |
| 277 | else | |
| 278 | { | |
| 279 | gcc_checking_assert (ssa2); | |
| 3dedfad5 | 280 | value_range op2 (TREE_TYPE (ssa2)); |
| faddf229 | 281 | if (op2_range (op2, s, q) && !op2.varying_p ()) |
| efc4255d AM |
282 | add_range (ssa2, op2); |
| 283 | } | |
| b7501739 AM |
284 | } |
| 285 | ||
| 07441e41 AM |
286 | // Create an single inferred range for NAMe using range R. |
| 287 | ||
| 288 | gimple_infer_range::gimple_infer_range (tree name, vrange &r) | |
| 289 | { | |
| 290 | num_args = 0; | |
| 291 | add_range (name, r); | |
| 292 | } | |
| 293 | ||
| b7501739 AM |
294 | // ------------------------------------------------------------------------- |
| 295 | ||
| c46b5b0a | 296 | // This class is an element in the list of inferred ranges. |
| b7501739 AM |
297 | |
| 298 | class exit_range | |
| 299 | { | |
| 300 | public: | |
| 301 | tree name; | |
| 07441e41 | 302 | gimple *stmt; |
| e1366a7e | 303 | vrange_storage *range; |
| b7501739 AM |
304 | exit_range *next; |
| 305 | }; | |
| 306 | ||
| 07441e41 | 307 | |
| b7501739 AM |
308 | // If there is an element which matches SSA, return a pointer to the element. |
| 309 | // Otherwise return NULL. | |
| 310 | ||
| 311 | exit_range * | |
| 156d7d8d | 312 | infer_range_manager::exit_range_head::find_ptr (tree ssa) |
| b7501739 AM |
313 | { |
| 314 | // Return NULL if SSA is not in this list. | |
| 315 | if (!m_names || !bitmap_bit_p (m_names, SSA_NAME_VERSION (ssa))) | |
| 316 | return NULL; | |
| 317 | for (exit_range *ptr = head; ptr != NULL; ptr = ptr->next) | |
| 318 | if (ptr->name == ssa) | |
| 319 | return ptr; | |
| 320 | // Should be unreachable. | |
| 321 | gcc_unreachable (); | |
| 322 | return NULL; | |
| 323 | } | |
| 324 | ||
| 156d7d8d | 325 | // Construct a range infer manager. DO_SEARCH indicates whether an immediate |
| b7501739 AM |
326 | // use scan should be made the first time a name is processed. This is for |
| 327 | // on-demand clients who may not visit every statement and may miss uses. | |
| faddf229 AM |
328 | // Q is the range_query to use for any lookups. Default is NULL which maps |
| 329 | // to the global_range_query. | |
| b7501739 | 330 | |
| faddf229 | 331 | infer_range_manager::infer_range_manager (bool do_search, range_query *q) |
| b7501739 | 332 | { |
| faddf229 AM |
333 | // Set the range query to use. |
| 334 | m_query = q ? q : get_global_range_query (); | |
| 335 | ||
| b7501739 AM |
336 | bitmap_obstack_initialize (&m_bitmaps); |
| 337 | m_on_exit.create (0); | |
| 338 | m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); | |
| 339 | // m_seen == NULL indicates no scanning. Otherwise the bit indicates a | |
| 340 | // scan has been performed on NAME. | |
| 341 | if (do_search) | |
| 342 | m_seen = BITMAP_ALLOC (&m_bitmaps); | |
| 343 | else | |
| 344 | m_seen = NULL; | |
| 345 | obstack_init (&m_list_obstack); | |
| 346 | // Non-zero elements are very common, so cache them for each ssa-name. | |
| 347 | m_nonzero.create (0); | |
| 348 | m_nonzero.safe_grow_cleared (num_ssa_names + 1); | |
| e1366a7e | 349 | m_range_allocator = new vrange_allocator; |
| b7501739 AM |
350 | } |
| 351 | ||
| 156d7d8d | 352 | // Destruct a range infer manager. |
| b7501739 | 353 | |
| 156d7d8d | 354 | infer_range_manager::~infer_range_manager () |
| b7501739 AM |
355 | { |
| 356 | m_nonzero.release (); | |
| 357 | obstack_free (&m_list_obstack, NULL); | |
| 358 | m_on_exit.release (); | |
| 359 | bitmap_obstack_release (&m_bitmaps); | |
| 3ae9def0 | 360 | delete m_range_allocator; |
| b7501739 AM |
361 | } |
| 362 | ||
| 363 | // Return a non-zero range value of the appropriate type for NAME from | |
| 364 | // the cache, creating it if necessary. | |
| 365 | ||
| 45c8523d | 366 | const vrange& |
| 156d7d8d | 367 | infer_range_manager::get_nonzero (tree name) |
| b7501739 AM |
368 | { |
| 369 | unsigned v = SSA_NAME_VERSION (name); | |
| 370 | if (v >= m_nonzero.length ()) | |
| 371 | m_nonzero.safe_grow_cleared (num_ssa_names + 20); | |
| 372 | if (!m_nonzero[v]) | |
| 373 | { | |
| e1366a7e AH |
374 | m_nonzero[v] |
| 375 | = (irange *) m_range_allocator->alloc (sizeof (int_range <2>)); | |
| 45c8523d | 376 | m_nonzero[v]->set_nonzero (TREE_TYPE (name)); |
| b7501739 AM |
377 | } |
| 378 | return *(m_nonzero[v]); | |
| 379 | } | |
| 380 | ||
| 07441e41 AM |
381 | // Return TRUE if NAME has a range inference in block BB. If NAME is NULL, |
| 382 | // return TRUE if there are any name sin BB. | |
| b7501739 AM |
383 | |
| 384 | bool | |
| 07441e41 | 385 | infer_range_manager::has_range_p (basic_block bb, tree name) |
| b7501739 AM |
386 | { |
| 387 | // Check if this is an immediate use search model. | |
| 07441e41 | 388 | if (name && m_seen && !bitmap_bit_p (m_seen, SSA_NAME_VERSION (name))) |
| b7501739 AM |
389 | register_all_uses (name); |
| 390 | ||
| 391 | if (bb->index >= (int)m_on_exit.length ()) | |
| 392 | return false; | |
| 07441e41 AM |
393 | |
| 394 | bitmap b = m_on_exit[bb->index].m_names; | |
| 395 | if (!b) | |
| b7501739 | 396 | return false; |
| 07441e41 AM |
397 | |
| 398 | if (name) | |
| 399 | return bitmap_bit_p (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name)); | |
| 400 | return !bitmap_empty_p (b); | |
| b7501739 AM |
401 | } |
| 402 | ||
| 156d7d8d | 403 | // Return TRUE if NAME has a range inference in block BB, and adjust range R |
| b7501739 AM |
404 | // to include it. |
| 405 | ||
| 406 | bool | |
| 45c8523d | 407 | infer_range_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb) |
| b7501739 | 408 | { |
| 07441e41 | 409 | if (!has_range_p (bb, name)) |
| b7501739 AM |
410 | return false; |
| 411 | exit_range *ptr = m_on_exit[bb->index].find_ptr (name); | |
| 412 | gcc_checking_assert (ptr); | |
| 413 | // Return true if this exit range changes R, otherwise false. | |
| e1366a7e | 414 | tree type = TREE_TYPE (name); |
| 3dedfad5 | 415 | value_range tmp (type); |
| e1366a7e AH |
416 | ptr->range->get_vrange (tmp, type); |
| 417 | return r.intersect (tmp); | |
| b7501739 AM |
418 | } |
| 419 | ||
| 07441e41 AM |
420 | // Add all inferred ranges in INFER at stmt S. |
| 421 | ||
| 422 | void | |
| 423 | infer_range_manager::add_ranges (gimple *s, gimple_infer_range &infer) | |
| 424 | { | |
| 425 | for (unsigned x = 0; x < infer.num (); x++) | |
| c7fd6c43 AM |
426 | { |
| 427 | tree arg = infer.name (x); | |
| 428 | value_range r (TREE_TYPE (arg)); | |
| 429 | m_query->range_of_expr (r, arg, s); | |
| 430 | // Only add the inferred range if it changes the current range. | |
| 431 | if (r.intersect (infer.range (x))) | |
| 432 | add_range (arg, s, infer.range (x)); | |
| 433 | } | |
| 07441e41 AM |
434 | } |
| 435 | ||
| 436 | // Add range R as an inferred range for NAME on stmt S. | |
| b7501739 AM |
437 | |
| 438 | void | |
| 07441e41 | 439 | infer_range_manager::add_range (tree name, gimple *s, const vrange &r) |
| b7501739 | 440 | { |
| 07441e41 AM |
441 | basic_block bb = gimple_bb (s); |
| 442 | if (!bb) | |
| 443 | return; | |
| b7501739 AM |
444 | if (bb->index >= (int)m_on_exit.length ()) |
| 445 | m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); | |
| 446 | ||
| 447 | // Create the summary list bitmap if it doesn't exist. | |
| 448 | if (!m_on_exit[bb->index].m_names) | |
| 449 | m_on_exit[bb->index].m_names = BITMAP_ALLOC (&m_bitmaps); | |
| 450 | ||
| 451 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
| 452 | { | |
| 453 | fprintf (dump_file, " on-exit update "); | |
| 454 | print_generic_expr (dump_file, name, TDF_SLIM); | |
| 455 | fprintf (dump_file, " in BB%d : ",bb->index); | |
| 456 | r.dump (dump_file); | |
| 457 | fprintf (dump_file, "\n"); | |
| 458 | } | |
| 459 | ||
| 460 | // If NAME already has a range, intersect them and done. | |
| 461 | exit_range *ptr = m_on_exit[bb->index].find_ptr (name); | |
| 462 | if (ptr) | |
| 463 | { | |
| e1366a7e | 464 | tree type = TREE_TYPE (name); |
| 3dedfad5 | 465 | value_range cur (r), name_range (type); |
| e1366a7e | 466 | ptr->range->get_vrange (name_range, type); |
| b7501739 | 467 | // If no new info is added, just return. |
| e1366a7e | 468 | if (!cur.intersect (name_range)) |
| b7501739 AM |
469 | return; |
| 470 | if (ptr->range->fits_p (cur)) | |
| e1366a7e | 471 | ptr->range->set_vrange (cur); |
| b7501739 | 472 | else |
| e1366a7e | 473 | ptr->range = m_range_allocator->clone (cur); |
| 07441e41 | 474 | ptr->stmt = s; |
| b7501739 AM |
475 | return; |
| 476 | } | |
| 477 | ||
| 478 | // Otherwise create a record. | |
| 479 | bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name)); | |
| 480 | ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range)); | |
| 3ae9def0 | 481 | ptr->range = m_range_allocator->clone (r); |
| b7501739 | 482 | ptr->name = name; |
| 07441e41 | 483 | ptr->stmt = s; |
| b7501739 AM |
484 | ptr->next = m_on_exit[bb->index].head; |
| 485 | m_on_exit[bb->index].head = ptr; | |
| 486 | } | |
| 487 | ||
| 07441e41 | 488 | // Add a non-zero inferred range for NAME at stmt S. |
| b7501739 AM |
489 | |
| 490 | void | |
| 07441e41 | 491 | infer_range_manager::add_nonzero (tree name, gimple *s) |
| b7501739 | 492 | { |
| 07441e41 | 493 | add_range (name, s, get_nonzero (name)); |
| b7501739 AM |
494 | } |
| 495 | ||
| 156d7d8d | 496 | // Follow immediate use chains and find all inferred ranges for NAME. |
| b7501739 AM |
497 | |
| 498 | void | |
| 156d7d8d | 499 | infer_range_manager::register_all_uses (tree name) |
| b7501739 AM |
500 | { |
| 501 | gcc_checking_assert (m_seen); | |
| 502 | ||
| 503 | // Check if we've already processed this name. | |
| 504 | unsigned v = SSA_NAME_VERSION (name); | |
| 505 | if (bitmap_bit_p (m_seen, v)) | |
| 506 | return; | |
| 507 | bitmap_set_bit (m_seen, v); | |
| 508 | ||
| 509 | use_operand_p use_p; | |
| 510 | imm_use_iterator iter; | |
| 511 | ||
| 156d7d8d | 512 | // Loop over each immediate use and see if it has an inferred range. |
| b7501739 AM |
513 | FOR_EACH_IMM_USE_FAST (use_p, iter, name) |
| 514 | { | |
| 515 | gimple *s = USE_STMT (use_p); | |
| faddf229 | 516 | gimple_infer_range infer (s, m_query); |
| 156d7d8d | 517 | for (unsigned x = 0; x < infer.num (); x++) |
| b7501739 | 518 | { |
| 156d7d8d | 519 | if (name == infer.name (x)) |
| 07441e41 | 520 | add_range (name, s, infer.range (x)); |
| b7501739 AM |
521 | } |
| 522 | } | |
| 523 | } |