1 /* Gimple range inference implementation.
2 Copyright (C) 2022-2025 Free Software Foundation, Inc.
3 Contributed by Andrew MacLeod <amacleod@redhat.com>.
5 This file is part of GCC.
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)
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.
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/>. */
23 #include "coretypes.h"
25 #include "insn-codes.h"
29 #include "gimple-pretty-print.h"
30 #include "gimple-range.h"
31 #include "value-range-storage.h"
35 #include "gimple-iterator.h"
36 #include "gimple-walk.h"
40 // Create the global oracle.
42 infer_range_oracle infer_oracle
;
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.
49 class non_null_wrapper
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
); }
56 gimple_infer_range
*m_infer
;
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
61 // stmt range inference instance.
64 non_null_loadstore (gimple
*, tree op
, tree
, void *data
)
66 if (TREE_CODE (op
) == MEM_REF
|| TREE_CODE (op
) == TARGET_MEM_REF
)
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
))
72 non_null_wrapper
wrapper ((gimple_infer_range
*)data
);
73 wrapper
.add_nonzero (TREE_OPERAND (op
, 0));
79 // Process an ASSUME call to see if there are any inferred ranges available.
82 gimple_infer_range::check_assume_func (gcall
*call
)
86 tree assume_id
= TREE_OPERAND (gimple_call_arg (call
, 0), 0);
89 struct function
*fun
= DECL_STRUCT_FUNCTION (assume_id
);
92 // Loop over arguments, matching them to the assume parameters.
93 for (arg
= DECL_ARGUMENTS (assume_id
), i
= 1;
94 arg
&& i
< gimple_call_num_args (call
);
95 i
++, arg
= DECL_CHAIN (arg
))
97 tree op
= gimple_call_arg (call
, i
);
98 tree type
= TREE_TYPE (op
);
99 if (gimple_range_ssa_p (op
) && value_range::supports_type_p (type
))
101 tree default_def
= ssa_default_def (fun
, arg
);
102 if (!default_def
|| type
!= TREE_TYPE (default_def
))
104 // Query the global range of the default def in the assume function.
105 value_range
assume_range (type
);
106 gimple_range_global (assume_range
, default_def
, fun
);
107 // If there is a non-varying result, add it as an inferred range.
108 if (!assume_range
.varying_p ())
110 add_range (op
, assume_range
);
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
);
127 // Add NAME and RANGE to the range inference summary.
130 gimple_infer_range::add_range (tree name
, vrange
&range
)
132 // Do not add an inferred range if it is VARYING.
133 if (range
.varying_p ())
135 m_names
[num_args
] = name
;
136 m_ranges
[num_args
] = range
;
137 if (num_args
< size_limit
- 1)
141 // Add a nonzero range for NAME to the range inference summary.
144 gimple_infer_range::add_nonzero (tree name
)
146 if (!gimple_range_ssa_p (name
))
149 nz
.set_nonzero (TREE_TYPE (name
));
150 add_range (name
, nz
);
153 // Process S for range inference and fill in the summary list.
154 // This is the routine where any new inferred ranges should be added.
155 // If USE_RANGEOPS is true, invoke range-ops on stmts with a single
156 // ssa-name a constant to reflect an inferred range. ie
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.,
160 gimple_infer_range::gimple_infer_range (gimple
*s
, range_query
*q
,
165 if (is_a
<gphi
*> (s
))
168 // Default to the global query if none provided.
170 q
= get_global_range_query ();
172 if (is_a
<gcall
*> (s
) && flag_delete_null_pointer_checks
)
174 tree fntype
= gimple_call_fntype (s
);
175 bitmap nonnullargs
= get_nonnull_args (fntype
);
176 // Process any non-null arguments
179 for (unsigned i
= 0; i
< gimple_call_num_args (s
); i
++)
181 if (bitmap_empty_p (nonnullargs
)
182 || bitmap_bit_p (nonnullargs
, i
))
184 tree op
= gimple_call_arg (s
, i
);
185 if (POINTER_TYPE_P (TREE_TYPE (op
)))
189 BITMAP_FREE (nonnullargs
);
192 for (tree attrs
= TYPE_ATTRIBUTES (fntype
);
193 (attrs
= lookup_attribute ("nonnull_if_nonzero", attrs
));
194 attrs
= TREE_CHAIN (attrs
))
196 tree args
= TREE_VALUE (attrs
);
197 unsigned int idx
= TREE_INT_CST_LOW (TREE_VALUE (args
)) - 1;
199 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args
))) - 1;
200 unsigned int idx3
= idx2
;
201 if (tree chain2
= TREE_CHAIN (TREE_CHAIN (args
)))
202 idx3
= TREE_INT_CST_LOW (TREE_VALUE (chain2
)) - 1;
203 if (idx
< gimple_call_num_args (s
)
204 && idx2
< gimple_call_num_args (s
)
205 && idx3
< gimple_call_num_args (s
))
207 tree arg
= gimple_call_arg (s
, idx
);
208 tree arg2
= gimple_call_arg (s
, idx2
);
209 tree arg3
= gimple_call_arg (s
, idx3
);
210 if (!POINTER_TYPE_P (TREE_TYPE (arg
))
211 || !INTEGRAL_TYPE_P (TREE_TYPE (arg2
))
212 || !INTEGRAL_TYPE_P (TREE_TYPE (arg3
))
213 || integer_zerop (arg2
)
214 || integer_zerop (arg3
))
216 if (integer_nonzerop (arg2
) && integer_nonzerop (arg3
))
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
))))
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
))
238 // Fallthru and walk load/store ops now.
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
));
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
,
256 // Check if there are any inferred ranges from range-ops.
257 gimple_range_op_handler
handler (s
);
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
))
269 // The other operand should be a constant, so just use the global range
270 // query to pick up any other values.
273 value_range
op1 (TREE_TYPE (ssa1
));
274 if (op1_range (op1
, s
, q
) && !op1
.varying_p ())
275 add_range (ssa1
, op1
);
279 gcc_checking_assert (ssa2
);
280 value_range
op2 (TREE_TYPE (ssa2
));
281 if (op2_range (op2
, s
, q
) && !op2
.varying_p ())
282 add_range (ssa2
, op2
);
286 // Create an single inferred range for NAMe using range R.
288 gimple_infer_range::gimple_infer_range (tree name
, vrange
&r
)
294 // -------------------------------------------------------------------------
296 // This class is an element in the list of inferred ranges.
303 vrange_storage
*range
;
308 // If there is an element which matches SSA, return a pointer to the element.
309 // Otherwise return NULL.
312 infer_range_manager::exit_range_head::find_ptr (tree ssa
)
314 // Return NULL if SSA is not in this list.
315 if (!m_names
|| !bitmap_bit_p (m_names
, SSA_NAME_VERSION (ssa
)))
317 for (exit_range
*ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
)
318 if (ptr
->name
== ssa
)
320 // Should be unreachable.
325 // Construct a range infer manager. DO_SEARCH indicates whether an immediate
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.
328 // Q is the range_query to use for any lookups. Default is NULL which maps
329 // to the global_range_query.
331 infer_range_manager::infer_range_manager (bool do_search
, range_query
*q
)
333 // Set the range query to use.
334 m_query
= q
? q
: get_global_range_query ();
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.
342 m_seen
= BITMAP_ALLOC (&m_bitmaps
);
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);
349 m_range_allocator
= new vrange_allocator
;
352 // Destruct a range infer manager.
354 infer_range_manager::~infer_range_manager ()
356 m_nonzero
.release ();
357 obstack_free (&m_list_obstack
, NULL
);
358 m_on_exit
.release ();
359 bitmap_obstack_release (&m_bitmaps
);
360 delete m_range_allocator
;
363 // Return a non-zero range value of the appropriate type for NAME from
364 // the cache, creating it if necessary.
367 infer_range_manager::get_nonzero (tree name
)
369 unsigned v
= SSA_NAME_VERSION (name
);
370 if (v
>= m_nonzero
.length ())
371 m_nonzero
.safe_grow_cleared (num_ssa_names
+ 20);
375 = (irange
*) m_range_allocator
->alloc (sizeof (int_range
<2>));
376 m_nonzero
[v
]->set_nonzero (TREE_TYPE (name
));
378 return *(m_nonzero
[v
]);
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.
385 infer_range_manager::has_range_p (basic_block bb
, tree name
)
387 // Check if this is an immediate use search model.
388 if (name
&& m_seen
&& !bitmap_bit_p (m_seen
, SSA_NAME_VERSION (name
)))
389 register_all_uses (name
);
391 if (bb
->index
>= (int)m_on_exit
.length ())
394 bitmap b
= m_on_exit
[bb
->index
].m_names
;
399 return bitmap_bit_p (m_on_exit
[bb
->index
].m_names
, SSA_NAME_VERSION (name
));
400 return !bitmap_empty_p (b
);
403 // Return TRUE if NAME has a range inference in block BB, and adjust range R
407 infer_range_manager::maybe_adjust_range (vrange
&r
, tree name
, basic_block bb
)
409 if (!has_range_p (bb
, name
))
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.
414 tree type
= TREE_TYPE (name
);
415 value_range
tmp (type
);
416 ptr
->range
->get_vrange (tmp
, type
);
417 return r
.intersect (tmp
);
420 // Add all inferred ranges in INFER at stmt S.
423 infer_range_manager::add_ranges (gimple
*s
, gimple_infer_range
&infer
)
425 for (unsigned x
= 0; x
< infer
.num (); x
++)
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
));
436 // Add range R as an inferred range for NAME on stmt S.
439 infer_range_manager::add_range (tree name
, gimple
*s
, const vrange
&r
)
441 basic_block bb
= gimple_bb (s
);
444 if (bb
->index
>= (int)m_on_exit
.length ())
445 m_on_exit
.safe_grow_cleared (last_basic_block_for_fn (cfun
) + 1);
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
);
451 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
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
);
457 fprintf (dump_file
, "\n");
460 // If NAME already has a range, intersect them and done.
461 exit_range
*ptr
= m_on_exit
[bb
->index
].find_ptr (name
);
464 tree type
= TREE_TYPE (name
);
465 value_range
cur (r
), name_range (type
);
466 ptr
->range
->get_vrange (name_range
, type
);
467 // If no new info is added, just return.
468 if (!cur
.intersect (name_range
))
470 if (ptr
->range
->fits_p (cur
))
471 ptr
->range
->set_vrange (cur
);
473 ptr
->range
= m_range_allocator
->clone (cur
);
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
));
481 ptr
->range
= m_range_allocator
->clone (r
);
484 ptr
->next
= m_on_exit
[bb
->index
].head
;
485 m_on_exit
[bb
->index
].head
= ptr
;
488 // Add a non-zero inferred range for NAME at stmt S.
491 infer_range_manager::add_nonzero (tree name
, gimple
*s
)
493 add_range (name
, s
, get_nonzero (name
));
496 // Follow immediate use chains and find all inferred ranges for NAME.
499 infer_range_manager::register_all_uses (tree name
)
501 gcc_checking_assert (m_seen
);
503 // Check if we've already processed this name.
504 unsigned v
= SSA_NAME_VERSION (name
);
505 if (bitmap_bit_p (m_seen
, v
))
507 bitmap_set_bit (m_seen
, v
);
510 imm_use_iterator iter
;
512 // Loop over each immediate use and see if it has an inferred range.
513 FOR_EACH_IMM_USE_FAST (use_p
, iter
, name
)
515 gimple
*s
= USE_STMT (use_p
);
516 gimple_infer_range
infer (s
, m_query
);
517 for (unsigned x
= 0; x
< infer
.num (); x
++)
519 if (name
== infer
.name (x
))
520 add_range (name
, s
, infer
.range (x
));