value-pointer-equiv.cc revision 1.1 1 1.1 mrg /* Context-aware pointer equivalence tracker.
2 1.1 mrg Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 1.1 mrg Contributed by Aldy Hernandez <aldyh (at) redhat.com>
4 1.1 mrg
5 1.1 mrg This file is part of GCC.
6 1.1 mrg
7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under
8 1.1 mrg the terms of the GNU General Public License as published by the Free
9 1.1 mrg Software Foundation; either version 3, or (at your option) any later
10 1.1 mrg version.
11 1.1 mrg
12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 1.1 mrg for more details.
16 1.1 mrg
17 1.1 mrg You should have received a copy of the GNU General Public License
18 1.1 mrg along with GCC; see the file COPYING3. If not see
19 1.1 mrg <http://www.gnu.org/licenses/>. */
20 1.1 mrg
21 1.1 mrg #include "config.h"
22 1.1 mrg #include "system.h"
23 1.1 mrg #include "coretypes.h"
24 1.1 mrg #include "backend.h"
25 1.1 mrg #include "tree.h"
26 1.1 mrg #include "gimple.h"
27 1.1 mrg #include "tree-pass.h"
28 1.1 mrg #include "ssa.h"
29 1.1 mrg #include "gimple-pretty-print.h"
30 1.1 mrg #include "cfganal.h"
31 1.1 mrg #include "gimple-fold.h"
32 1.1 mrg #include "tree-eh.h"
33 1.1 mrg #include "gimple-iterator.h"
34 1.1 mrg #include "tree-cfg.h"
35 1.1 mrg #include "tree-ssa-loop-manip.h"
36 1.1 mrg #include "tree-ssa-loop.h"
37 1.1 mrg #include "cfgloop.h"
38 1.1 mrg #include "tree-scalar-evolution.h"
39 1.1 mrg #include "tree-ssa-propagate.h"
40 1.1 mrg #include "alloc-pool.h"
41 1.1 mrg #include "domwalk.h"
42 1.1 mrg #include "tree-cfgcleanup.h"
43 1.1 mrg #include "vr-values.h"
44 1.1 mrg #include "gimple-range.h"
45 1.1 mrg #include "fold-const.h"
46 1.1 mrg #include "value-pointer-equiv.h"
47 1.1 mrg
48 1.1 mrg // Unwindable SSA equivalence table for pointers.
49 1.1 mrg //
50 1.1 mrg // The main query point is get_replacement() which returns what a
51 1.1 mrg // given SSA can be replaced with in the current scope.
52 1.1 mrg
53 1.1 mrg class ssa_equiv_stack
54 1.1 mrg {
55 1.1 mrg public:
56 1.1 mrg ssa_equiv_stack ();
57 1.1 mrg void enter (basic_block);
58 1.1 mrg void leave (basic_block);
59 1.1 mrg void push_replacement (tree name, tree replacement);
60 1.1 mrg tree get_replacement (tree name);
61 1.1 mrg
62 1.1 mrg private:
63 1.1 mrg auto_vec<std::pair <tree, tree>> m_stack;
64 1.1 mrg auto_vec<tree> m_replacements;
65 1.1 mrg const std::pair <tree, tree> m_marker = std::make_pair (NULL, NULL);
66 1.1 mrg };
67 1.1 mrg
68 1.1 mrg ssa_equiv_stack::ssa_equiv_stack ()
69 1.1 mrg {
70 1.1 mrg m_replacements.safe_grow_cleared (num_ssa_names + 1);
71 1.1 mrg }
72 1.1 mrg
73 1.1 mrg // Pushes a marker at the given point.
74 1.1 mrg
75 1.1 mrg void
76 1.1 mrg ssa_equiv_stack::enter (basic_block)
77 1.1 mrg {
78 1.1 mrg m_stack.safe_push (m_marker);
79 1.1 mrg }
80 1.1 mrg
81 1.1 mrg // Pops the stack to the last marker, while performing replacements
82 1.1 mrg // along the way.
83 1.1 mrg
84 1.1 mrg void
85 1.1 mrg ssa_equiv_stack::leave (basic_block)
86 1.1 mrg {
87 1.1 mrg gcc_checking_assert (!m_stack.is_empty ());
88 1.1 mrg while (m_stack.last () != m_marker)
89 1.1 mrg {
90 1.1 mrg std::pair<tree, tree> e = m_stack.pop ();
91 1.1 mrg m_replacements[SSA_NAME_VERSION (e.first)] = e.second;
92 1.1 mrg }
93 1.1 mrg m_stack.pop ();
94 1.1 mrg }
95 1.1 mrg
96 1.1 mrg // Set the equivalence of NAME to REPLACEMENT.
97 1.1 mrg
98 1.1 mrg void
99 1.1 mrg ssa_equiv_stack::push_replacement (tree name, tree replacement)
100 1.1 mrg {
101 1.1 mrg unsigned v = SSA_NAME_VERSION (name);
102 1.1 mrg
103 1.1 mrg if (v >= m_replacements.length ())
104 1.1 mrg m_replacements.safe_grow_cleared (num_ssa_names + 1);
105 1.1 mrg
106 1.1 mrg tree old = m_replacements[v];
107 1.1 mrg m_replacements[v] = replacement;
108 1.1 mrg m_stack.safe_push (std::make_pair (name, old));
109 1.1 mrg }
110 1.1 mrg
111 1.1 mrg // Return the equivalence of NAME.
112 1.1 mrg
113 1.1 mrg tree
114 1.1 mrg ssa_equiv_stack::get_replacement (tree name)
115 1.1 mrg {
116 1.1 mrg unsigned v = SSA_NAME_VERSION (name);
117 1.1 mrg
118 1.1 mrg if (v >= m_replacements.length ())
119 1.1 mrg m_replacements.safe_grow_cleared (num_ssa_names + 1);
120 1.1 mrg
121 1.1 mrg return m_replacements[v];
122 1.1 mrg }
123 1.1 mrg
124 1.1 mrg pointer_equiv_analyzer::pointer_equiv_analyzer (gimple_ranger *r)
125 1.1 mrg {
126 1.1 mrg m_ranger = r;
127 1.1 mrg m_global_points.safe_grow_cleared (num_ssa_names + 1);
128 1.1 mrg m_cond_points = new ssa_equiv_stack;
129 1.1 mrg }
130 1.1 mrg
131 1.1 mrg pointer_equiv_analyzer::~pointer_equiv_analyzer ()
132 1.1 mrg {
133 1.1 mrg delete m_cond_points;
134 1.1 mrg }
135 1.1 mrg
136 1.1 mrg // Set the global pointer equivalency for SSA to POINTEE.
137 1.1 mrg
138 1.1 mrg void
139 1.1 mrg pointer_equiv_analyzer::set_global_equiv (tree ssa, tree pointee)
140 1.1 mrg {
141 1.1 mrg unsigned v = SSA_NAME_VERSION (ssa);
142 1.1 mrg
143 1.1 mrg if (v >= m_global_points.length ())
144 1.1 mrg m_global_points.safe_grow_cleared (num_ssa_names + 1);
145 1.1 mrg
146 1.1 mrg m_global_points[v] = pointee;
147 1.1 mrg }
148 1.1 mrg
149 1.1 mrg // Set the conditional pointer equivalency for SSA to POINTEE.
150 1.1 mrg
151 1.1 mrg void
152 1.1 mrg pointer_equiv_analyzer::set_cond_equiv (tree ssa, tree pointee)
153 1.1 mrg {
154 1.1 mrg m_cond_points->push_replacement (ssa, pointee);
155 1.1 mrg }
156 1.1 mrg
157 1.1 mrg // Return the current pointer equivalency info for SSA, or NULL if
158 1.1 mrg // none is available. Note that global info takes priority over
159 1.1 mrg // conditional info.
160 1.1 mrg
161 1.1 mrg tree
162 1.1 mrg pointer_equiv_analyzer::get_equiv (tree ssa)
163 1.1 mrg {
164 1.1 mrg unsigned v = SSA_NAME_VERSION (ssa);
165 1.1 mrg
166 1.1 mrg if (v >= m_global_points.length ())
167 1.1 mrg m_global_points.safe_grow_cleared (num_ssa_names + 1);
168 1.1 mrg
169 1.1 mrg tree ret = m_global_points[v];
170 1.1 mrg if (ret)
171 1.1 mrg return ret;
172 1.1 mrg return m_cond_points->get_replacement (ssa);
173 1.1 mrg }
174 1.1 mrg
175 1.1 mrg // Method to be called on entry to a BB.
176 1.1 mrg
177 1.1 mrg void
178 1.1 mrg pointer_equiv_analyzer::enter (basic_block bb)
179 1.1 mrg {
180 1.1 mrg m_cond_points->enter (bb);
181 1.1 mrg
182 1.1 mrg for (gphi_iterator iter = gsi_start_phis (bb);
183 1.1 mrg !gsi_end_p (iter);
184 1.1 mrg gsi_next (&iter))
185 1.1 mrg {
186 1.1 mrg gphi *phi = iter.phi ();
187 1.1 mrg tree lhs = gimple_phi_result (phi);
188 1.1 mrg if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
189 1.1 mrg continue;
190 1.1 mrg tree arg0 = gimple_phi_arg_def (phi, 0);
191 1.1 mrg if (TREE_CODE (arg0) == SSA_NAME && !is_gimple_min_invariant (arg0))
192 1.1 mrg arg0 = get_equiv (arg0);
193 1.1 mrg if (arg0 && is_gimple_min_invariant (arg0))
194 1.1 mrg {
195 1.1 mrg // If all the PHI args point to the same place, set the
196 1.1 mrg // pointer equivalency info for the PHI result. This can
197 1.1 mrg // happen for passes that create redundant PHIs like
198 1.1 mrg // PHI<&foo, &foo> or PHI<&foo>.
199 1.1 mrg for (size_t i = 1; i < gimple_phi_num_args (phi); ++i)
200 1.1 mrg {
201 1.1 mrg tree argi = gimple_phi_arg_def (phi, i);
202 1.1 mrg if (TREE_CODE (argi) == SSA_NAME
203 1.1 mrg && !is_gimple_min_invariant (argi))
204 1.1 mrg argi = get_equiv (argi);
205 1.1 mrg if (!argi || !operand_equal_p (arg0, argi))
206 1.1 mrg return;
207 1.1 mrg }
208 1.1 mrg set_global_equiv (lhs, arg0);
209 1.1 mrg }
210 1.1 mrg }
211 1.1 mrg
212 1.1 mrg edge pred = single_pred_edge_ignoring_loop_edges (bb, false);
213 1.1 mrg if (pred)
214 1.1 mrg visit_edge (pred);
215 1.1 mrg }
216 1.1 mrg
217 1.1 mrg // Method to be called on exit from a BB.
218 1.1 mrg
219 1.1 mrg void
220 1.1 mrg pointer_equiv_analyzer::leave (basic_block bb)
221 1.1 mrg {
222 1.1 mrg m_cond_points->leave (bb);
223 1.1 mrg }
224 1.1 mrg
225 1.1 mrg // Helper function to return the pointer equivalency information for
226 1.1 mrg // EXPR from a gimple statement with CODE. This returns either the
227 1.1 mrg // cached pointer equivalency info for an SSA, or an invariant in case
228 1.1 mrg // EXPR is one (i.e. &foo). Returns NULL if EXPR is neither an SSA
229 1.1 mrg // nor an invariant.
230 1.1 mrg
231 1.1 mrg tree
232 1.1 mrg pointer_equiv_analyzer::get_equiv_expr (tree_code code, tree expr)
233 1.1 mrg {
234 1.1 mrg if (code == SSA_NAME)
235 1.1 mrg return get_equiv (expr);
236 1.1 mrg
237 1.1 mrg if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS
238 1.1 mrg && is_gimple_min_invariant (expr))
239 1.1 mrg return expr;
240 1.1 mrg
241 1.1 mrg return NULL;
242 1.1 mrg }
243 1.1 mrg
244 1.1 mrg // Hack to provide context to the gimple fold callback.
245 1.1 mrg static struct
246 1.1 mrg {
247 1.1 mrg gimple *m_stmt;
248 1.1 mrg gimple_ranger *m_ranger;
249 1.1 mrg pointer_equiv_analyzer *m_pta;
250 1.1 mrg } x_fold_context;
251 1.1 mrg
252 1.1 mrg // Gimple fold callback.
253 1.1 mrg static tree
254 1.1 mrg pta_valueize (tree name)
255 1.1 mrg {
256 1.1 mrg tree ret
257 1.1 mrg = x_fold_context.m_ranger->value_of_expr (name, x_fold_context.m_stmt);
258 1.1 mrg
259 1.1 mrg if (!ret && supported_pointer_equiv_p (name))
260 1.1 mrg ret = x_fold_context.m_pta->get_equiv (name);
261 1.1 mrg
262 1.1 mrg return ret ? ret : name;
263 1.1 mrg }
264 1.1 mrg
265 1.1 mrg // Method to be called on gimple statements during traversal of the IL.
266 1.1 mrg
267 1.1 mrg void
268 1.1 mrg pointer_equiv_analyzer::visit_stmt (gimple *stmt)
269 1.1 mrg {
270 1.1 mrg if (gimple_code (stmt) != GIMPLE_ASSIGN)
271 1.1 mrg return;
272 1.1 mrg
273 1.1 mrg tree lhs = gimple_assign_lhs (stmt);
274 1.1 mrg if (!supported_pointer_equiv_p (lhs))
275 1.1 mrg return;
276 1.1 mrg
277 1.1 mrg tree rhs = gimple_assign_rhs1 (stmt);
278 1.1 mrg rhs = get_equiv_expr (gimple_assign_rhs_code (stmt), rhs);
279 1.1 mrg if (rhs)
280 1.1 mrg {
281 1.1 mrg set_global_equiv (lhs, rhs);
282 1.1 mrg return;
283 1.1 mrg }
284 1.1 mrg
285 1.1 mrg // If we couldn't find anything, try fold.
286 1.1 mrg x_fold_context = { stmt, m_ranger, this};
287 1.1 mrg rhs = gimple_fold_stmt_to_constant_1 (stmt, pta_valueize, pta_valueize);
288 1.1 mrg if (rhs)
289 1.1 mrg {
290 1.1 mrg rhs = get_equiv_expr (TREE_CODE (rhs), rhs);
291 1.1 mrg if (rhs)
292 1.1 mrg {
293 1.1 mrg set_global_equiv (lhs, rhs);
294 1.1 mrg return;
295 1.1 mrg }
296 1.1 mrg }
297 1.1 mrg }
298 1.1 mrg
299 1.1 mrg // If the edge in E is a conditional that sets a pointer equality, set the
300 1.1 mrg // conditional pointer equivalency information.
301 1.1 mrg
302 1.1 mrg void
303 1.1 mrg pointer_equiv_analyzer::visit_edge (edge e)
304 1.1 mrg {
305 1.1 mrg gimple *stmt = last_stmt (e->src);
306 1.1 mrg tree lhs;
307 1.1 mrg // Recognize: x_13 [==,!=] &foo.
308 1.1 mrg if (stmt
309 1.1 mrg && gimple_code (stmt) == GIMPLE_COND
310 1.1 mrg && (lhs = gimple_cond_lhs (stmt))
311 1.1 mrg && TREE_CODE (lhs) == SSA_NAME
312 1.1 mrg && POINTER_TYPE_P (TREE_TYPE (lhs))
313 1.1 mrg && TREE_CODE (gimple_cond_rhs (stmt)) == ADDR_EXPR)
314 1.1 mrg {
315 1.1 mrg tree_code code = gimple_cond_code (stmt);
316 1.1 mrg if ((code == EQ_EXPR && e->flags & EDGE_TRUE_VALUE)
317 1.1 mrg || ((code == NE_EXPR && e->flags & EDGE_FALSE_VALUE)))
318 1.1 mrg set_cond_equiv (lhs, gimple_cond_rhs (stmt));
319 1.1 mrg }
320 1.1 mrg }
321