1 /* Basic block path solver.
2 Copyright (C) 2021 Free Software Foundation, Inc.
3 Contributed by Aldy Hernandez <aldyh@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
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"
28 #include "value-range.h"
29 #include "gimple-range.h"
30 #include "tree-pretty-print.h"
31 #include "gimple-range-path.h"
34 // Internal construct to help facilitate debugging of solver.
35 #define DEBUG_SOLVER (0 && dump_file)
37 path_range_query::path_range_query (gimple_ranger
&ranger
)
40 m_cache
= new ssa_global_cache
;
41 m_has_cache_entry
= BITMAP_ALLOC (NULL
);
45 path_range_query::~path_range_query ()
47 BITMAP_FREE (m_has_cache_entry
);
51 // Mark cache entry for NAME as unused.
54 path_range_query::clear_cache (tree name
)
56 unsigned v
= SSA_NAME_VERSION (name
);
57 bitmap_clear_bit (m_has_cache_entry
, v
);
60 // If NAME has a cache entry, return it in R, and return TRUE.
63 path_range_query::get_cache (irange
&r
, tree name
)
65 if (!gimple_range_ssa_p (name
))
66 return get_global_range_query ()->range_of_expr (r
, name
);
68 unsigned v
= SSA_NAME_VERSION (name
);
69 if (bitmap_bit_p (m_has_cache_entry
, v
))
70 return m_cache
->get_global_range (r
, name
);
75 // Set the cache entry for NAME to R.
78 path_range_query::set_cache (const irange
&r
, tree name
)
80 unsigned v
= SSA_NAME_VERSION (name
);
81 bitmap_set_bit (m_has_cache_entry
, v
);
82 m_cache
->set_global_range (name
, r
);
86 path_range_query::dump (FILE *dump_file
)
88 if (m_path
->is_empty ())
93 extern void dump_ranger (FILE *, const vec
<basic_block
> &);
95 fprintf (dump_file
, "Path is:\n");
96 dump_ranger (dump_file
, *m_path
);
98 fprintf (dump_file
, "Imports:\n");
99 EXECUTE_IF_SET_IN_BITMAP (m_imports
, 0, i
, bi
)
101 tree name
= ssa_name (i
);
102 print_generic_expr (dump_file
, name
, TDF_SLIM
);
103 fprintf (dump_file
, "\n");
106 m_cache
->dump (dump_file
);
110 path_range_query::debug ()
115 // Return the range of NAME at the end of the path being analyzed.
118 path_range_query::range_of_expr (irange
&r
, tree name
, gimple
*stmt
)
120 if (!irange::supports_type_p (TREE_TYPE (name
)))
123 if (get_cache (r
, name
))
127 basic_block bb
= stmt
? gimple_bb (stmt
) : exit_bb ();
128 if (stmt
&& range_defined_in_block (r
, name
, bb
))
134 r
.set_varying (TREE_TYPE (name
));
138 // Return the range of STMT at the end of the path being analyzed.
139 // Anything but the final conditional in a BB will return VARYING.
142 path_range_query::range_of_stmt (irange
&r
, gimple
*stmt
, tree
)
144 tree type
= gimple_range_type (stmt
);
146 if (!irange::supports_type_p (type
))
149 if (gimple_code (stmt
) == GIMPLE_COND
&& fold_range (r
, stmt
, this))
152 r
.set_varying (type
);
156 // Initialize the current path to PATH. The current block is set to
157 // the entry block to the path.
159 // Note that the blocks are in reverse order, so the exit block is
163 path_range_query::set_path (const vec
<basic_block
> &path
)
165 gcc_checking_assert (path
.length () > 1);
167 m_pos
= m_path
->length () - 1;
168 bitmap_clear (m_has_cache_entry
);
171 // Return the range of the result of PHI in R.
174 path_range_query::ssa_range_in_phi (irange
&r
, gphi
*phi
)
176 tree name
= gimple_phi_result (phi
);
177 basic_block bb
= gimple_bb (phi
);
179 // We experimented with querying ranger's range_on_entry here, but
180 // the performance penalty was too high, for hardly any improvements.
183 // Try fold just in case we can resolve simple things like PHI <5(99), 6(88)>.
184 if (!fold_range (r
, phi
, this))
185 r
.set_varying (TREE_TYPE (name
));
190 basic_block prev
= prev_bb ();
191 edge e_in
= find_edge (prev
, bb
);
192 unsigned nargs
= gimple_phi_num_args (phi
);
194 for (size_t i
= 0; i
< nargs
; ++i
)
195 if (e_in
== gimple_phi_arg_edge (phi
, i
))
197 tree arg
= gimple_phi_arg_def (phi
, i
);
199 if (!get_cache (r
, arg
))
200 r
.set_varying (TREE_TYPE (name
));
207 // If NAME is defined in BB, set R to the range of NAME, and return
208 // TRUE. Otherwise, return FALSE.
211 path_range_query::range_defined_in_block (irange
&r
, tree name
, basic_block bb
)
213 gimple
*def_stmt
= SSA_NAME_DEF_STMT (name
);
214 basic_block def_bb
= gimple_bb (def_stmt
);
219 if (gimple_code (def_stmt
) == GIMPLE_PHI
)
220 ssa_range_in_phi (r
, as_a
<gphi
*> (def_stmt
));
221 else if (!fold_range (r
, def_stmt
, this))
222 r
.set_varying (TREE_TYPE (name
));
226 fprintf (dump_file
, "range_defined_in_block (BB%d) for ", bb
->index
);
227 print_generic_expr (dump_file
, name
, TDF_SLIM
);
228 fprintf (dump_file
, " is ");
230 fprintf (dump_file
, "\n");
235 // Precompute ranges defined in the current block, or ranges
236 // that are exported on an edge to the next block.
239 path_range_query::precompute_ranges_in_block (basic_block bb
)
242 int_range_max r
, cached_range
;
245 // Force recalculation of any names in the cache that are defined in
246 // this block. This can happen on interdependent SSA/phis in loops.
247 EXECUTE_IF_SET_IN_BITMAP (m_imports
, 0, i
, bi
)
249 tree name
= ssa_name (i
);
250 gimple
*def_stmt
= SSA_NAME_DEF_STMT (name
);
251 basic_block def_bb
= gimple_bb (def_stmt
);
257 // Solve imports defined in this block.
258 EXECUTE_IF_SET_IN_BITMAP (m_imports
, 0, i
, bi
)
260 tree name
= ssa_name (i
);
262 if (range_defined_in_block (r
, name
, bb
))
269 // Solve imports that are exported to the next block.
270 edge e
= find_edge (bb
, next_bb ());
271 EXECUTE_IF_SET_IN_BITMAP (m_imports
, 0, i
, bi
)
273 tree name
= ssa_name (i
);
274 gori_compute
&g
= m_ranger
.gori ();
275 bitmap exports
= g
.exports (bb
);
277 if (bitmap_bit_p (exports
, i
))
279 if (g
.outgoing_edge_range_p (r
, e
, name
, *this))
281 if (get_cache (cached_range
, name
))
282 r
.intersect (cached_range
);
287 fprintf (dump_file
, "outgoing_edge_range_p for ");
288 print_generic_expr (dump_file
, name
, TDF_SLIM
);
289 fprintf (dump_file
, " on edge %d->%d ",
290 e
->src
->index
, e
->dest
->index
);
291 fprintf (dump_file
, "is ");
293 fprintf (dump_file
, "\n");
300 // Precompute the ranges for IMPORTS along PATH.
302 // IMPORTS are the set of SSA names, any of which could potentially
303 // change the value of the final conditional in PATH.
306 path_range_query::precompute_ranges (const vec
<basic_block
> &path
,
307 const bitmap_head
*imports
)
313 fprintf (dump_file
, "path_range_query: precompute_ranges\n");
317 basic_block bb
= curr_bb ();
319 precompute_ranges_in_block (bb
);