1 /* Gimple range inference implementation.
2 Copyright (C) 2022 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"
39 // Adapted from infer_nonnull_range_by_dereference and check_loadstore
40 // to process nonnull ssa_name OP in S. DATA contains a pointer to a
41 // stmt range inference instance.
44 non_null_loadstore (gimple
*, tree op
, tree
, void *data
)
46 if (TREE_CODE (op
) == MEM_REF
|| TREE_CODE (op
) == TARGET_MEM_REF
)
48 /* Some address spaces may legitimately dereference zero. */
49 addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (op
));
50 if (!targetm
.addr_space
.zero_address_valid (as
))
52 tree ssa
= TREE_OPERAND (op
, 0);
53 ((gimple_infer_range
*)data
)->add_nonzero (ssa
);
59 // Add NAME and RANGE to the range inference summary.
62 gimple_infer_range::add_range (tree name
, vrange
&range
)
64 m_names
[num_args
] = name
;
65 m_ranges
[num_args
] = range
;
66 if (num_args
< size_limit
- 1)
70 // Add a nonzero range for NAME to the range inference summary.
73 gimple_infer_range::add_nonzero (tree name
)
75 if (!gimple_range_ssa_p (name
))
78 nz
.set_nonzero (TREE_TYPE (name
));
82 // Process S for range inference and fill in the summary list.
83 // This is the routine where new inferred ranges should be added.
85 gimple_infer_range::gimple_infer_range (gimple
*s
)
92 if (is_a
<gcall
*> (s
) && flag_delete_null_pointer_checks
)
94 tree fntype
= gimple_call_fntype (s
);
95 bitmap nonnullargs
= get_nonnull_args (fntype
);
96 // Process any non-null arguments
99 for (unsigned i
= 0; i
< gimple_call_num_args (s
); i
++)
101 if (bitmap_empty_p (nonnullargs
)
102 || bitmap_bit_p (nonnullargs
, i
))
104 tree op
= gimple_call_arg (s
, i
);
105 if (POINTER_TYPE_P (TREE_TYPE (op
)))
109 BITMAP_FREE (nonnullargs
);
111 // Fallthru and walk load/store ops now.
114 // Look for possible non-null values.
115 if (flag_delete_null_pointer_checks
&& gimple_code (s
) != GIMPLE_ASM
116 && !gimple_clobber_p (s
))
117 walk_stmt_load_store_ops (s
, (void *)this, non_null_loadstore
,
122 // -------------------------------------------------------------------------
124 // This class is an element in the list of infered ranges.
134 // If there is an element which matches SSA, return a pointer to the element.
135 // Otherwise return NULL.
138 infer_range_manager::exit_range_head::find_ptr (tree ssa
)
140 // Return NULL if SSA is not in this list.
141 if (!m_names
|| !bitmap_bit_p (m_names
, SSA_NAME_VERSION (ssa
)))
143 for (exit_range
*ptr
= head
; ptr
!= NULL
; ptr
= ptr
->next
)
144 if (ptr
->name
== ssa
)
146 // Should be unreachable.
151 // Construct a range infer manager. DO_SEARCH indicates whether an immediate
152 // use scan should be made the first time a name is processed. This is for
153 // on-demand clients who may not visit every statement and may miss uses.
155 infer_range_manager::infer_range_manager (bool do_search
)
157 bitmap_obstack_initialize (&m_bitmaps
);
158 m_on_exit
.create (0);
159 m_on_exit
.safe_grow_cleared (last_basic_block_for_fn (cfun
) + 1);
160 // m_seen == NULL indicates no scanning. Otherwise the bit indicates a
161 // scan has been performed on NAME.
163 m_seen
= BITMAP_ALLOC (&m_bitmaps
);
166 obstack_init (&m_list_obstack
);
167 // Non-zero elements are very common, so cache them for each ssa-name.
168 m_nonzero
.create (0);
169 m_nonzero
.safe_grow_cleared (num_ssa_names
+ 1);
170 m_range_allocator
= new obstack_vrange_allocator
;
173 // Destruct a range infer manager.
175 infer_range_manager::~infer_range_manager ()
177 m_nonzero
.release ();
178 obstack_free (&m_list_obstack
, NULL
);
179 m_on_exit
.release ();
180 bitmap_obstack_release (&m_bitmaps
);
181 delete m_range_allocator
;
184 // Return a non-zero range value of the appropriate type for NAME from
185 // the cache, creating it if necessary.
188 infer_range_manager::get_nonzero (tree name
)
190 unsigned v
= SSA_NAME_VERSION (name
);
191 if (v
>= m_nonzero
.length ())
192 m_nonzero
.safe_grow_cleared (num_ssa_names
+ 20);
195 m_nonzero
[v
] = m_range_allocator
->alloc_vrange (TREE_TYPE (name
));
196 m_nonzero
[v
]->set_nonzero (TREE_TYPE (name
));
198 return *(m_nonzero
[v
]);
201 // Return TRUE if NAME has a range inference in block BB.
204 infer_range_manager::has_range_p (tree name
, basic_block bb
)
206 // Check if this is an immediate use search model.
207 if (m_seen
&& !bitmap_bit_p (m_seen
, SSA_NAME_VERSION (name
)))
208 register_all_uses (name
);
210 if (bb
->index
>= (int)m_on_exit
.length ())
212 if (!m_on_exit
[bb
->index
].m_names
)
214 if (!bitmap_bit_p (m_on_exit
[bb
->index
].m_names
, SSA_NAME_VERSION (name
)))
219 // Return TRUE if NAME has a range inference in block BB, and adjust range R
223 infer_range_manager::maybe_adjust_range (vrange
&r
, tree name
, basic_block bb
)
225 if (!has_range_p (name
, bb
))
227 exit_range
*ptr
= m_on_exit
[bb
->index
].find_ptr (name
);
228 gcc_checking_assert (ptr
);
229 // Return true if this exit range changes R, otherwise false.
230 return r
.intersect (*(ptr
->range
));
233 // Add range R as an inferred range for NAME in block BB.
236 infer_range_manager::add_range (tree name
, basic_block bb
, const vrange
&r
)
238 if (bb
->index
>= (int)m_on_exit
.length ())
239 m_on_exit
.safe_grow_cleared (last_basic_block_for_fn (cfun
) + 1);
241 // Create the summary list bitmap if it doesn't exist.
242 if (!m_on_exit
[bb
->index
].m_names
)
243 m_on_exit
[bb
->index
].m_names
= BITMAP_ALLOC (&m_bitmaps
);
245 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
247 fprintf (dump_file
, " on-exit update ");
248 print_generic_expr (dump_file
, name
, TDF_SLIM
);
249 fprintf (dump_file
, " in BB%d : ",bb
->index
);
251 fprintf (dump_file
, "\n");
254 // If NAME already has a range, intersect them and done.
255 exit_range
*ptr
= m_on_exit
[bb
->index
].find_ptr (name
);
259 // If no new info is added, just return.
260 if (!cur
.intersect (*(ptr
->range
)))
262 if (ptr
->range
->fits_p (cur
))
267 ptr
->range
= m_range_allocator
->clone (v
);
272 // Otherwise create a record.
273 bitmap_set_bit (m_on_exit
[bb
->index
].m_names
, SSA_NAME_VERSION (name
));
274 ptr
= (exit_range
*)obstack_alloc (&m_list_obstack
, sizeof (exit_range
));
275 ptr
->range
= m_range_allocator
->clone (r
);
277 ptr
->next
= m_on_exit
[bb
->index
].head
;
278 m_on_exit
[bb
->index
].head
= ptr
;
281 // Add a non-zero inferred range for NAME in block BB.
284 infer_range_manager::add_nonzero (tree name
, basic_block bb
)
286 add_range (name
, bb
, get_nonzero (name
));
289 // Follow immediate use chains and find all inferred ranges for NAME.
292 infer_range_manager::register_all_uses (tree name
)
294 gcc_checking_assert (m_seen
);
296 // Check if we've already processed this name.
297 unsigned v
= SSA_NAME_VERSION (name
);
298 if (bitmap_bit_p (m_seen
, v
))
300 bitmap_set_bit (m_seen
, v
);
303 imm_use_iterator iter
;
305 // Loop over each immediate use and see if it has an inferred range.
306 FOR_EACH_IMM_USE_FAST (use_p
, iter
, name
)
308 gimple
*s
= USE_STMT (use_p
);
309 gimple_infer_range
infer (s
);
310 for (unsigned x
= 0; x
< infer
.num (); x
++)
312 if (name
== infer
.name (x
))
313 add_range (name
, gimple_bb (s
), infer
.range (x
));