1 /* Context-aware pointer equivalence tracker.
2 Copyright (C) 2020-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"
27 #include "tree-pass.h"
29 #include "gimple-pretty-print.h"
31 #include "gimple-fold.h"
33 #include "gimple-iterator.h"
35 #include "tree-ssa-loop-manip.h"
36 #include "tree-ssa-loop.h"
38 #include "tree-scalar-evolution.h"
39 #include "tree-ssa-propagate.h"
40 #include "alloc-pool.h"
42 #include "tree-cfgcleanup.h"
43 #include "vr-values.h"
44 #include "gimple-ssa-evrp-analyze.h"
45 #include "gimple-range.h"
46 #include "fold-const.h"
47 #include "value-pointer-equiv.h"
49 // Unwindable SSA equivalence table for pointers.
51 // The main query point is get_replacement() which returns what a
52 // given SSA can be replaced with in the current scope.
58 void enter (basic_block
);
59 void leave (basic_block
);
60 void push_replacement (tree name
, tree replacement
);
61 tree
get_replacement (tree name
) const;
64 auto_vec
<std::pair
<tree
, tree
>> m_stack
;
65 auto_vec
<tree
> m_replacements
;
66 const std::pair
<tree
, tree
> m_marker
= std::make_pair (NULL
, NULL
);
69 ssa_equiv_stack::ssa_equiv_stack ()
71 m_replacements
.safe_grow_cleared (num_ssa_names
);
74 // Pushes a marker at the given point.
77 ssa_equiv_stack::enter (basic_block
)
79 m_stack
.safe_push (m_marker
);
82 // Pops the stack to the last marker, while performing replacements
86 ssa_equiv_stack::leave (basic_block
)
88 gcc_checking_assert (!m_stack
.is_empty ());
89 while (m_stack
.last () != m_marker
)
91 std::pair
<tree
, tree
> e
= m_stack
.pop ();
92 m_replacements
[SSA_NAME_VERSION (e
.first
)] = e
.second
;
97 // Set the equivalence of NAME to REPLACEMENT.
100 ssa_equiv_stack::push_replacement (tree name
, tree replacement
)
102 tree old
= m_replacements
[SSA_NAME_VERSION (name
)];
103 m_replacements
[SSA_NAME_VERSION (name
)] = replacement
;
104 m_stack
.safe_push (std::make_pair (name
, old
));
107 // Return the equivalence of NAME.
110 ssa_equiv_stack::get_replacement (tree name
) const
112 return m_replacements
[SSA_NAME_VERSION (name
)];
115 pointer_equiv_analyzer::pointer_equiv_analyzer (gimple_ranger
*r
)
118 m_global_points
= new tree
[num_ssa_names
] ();
119 m_cond_points
= new ssa_equiv_stack
;
122 pointer_equiv_analyzer::~pointer_equiv_analyzer ()
124 delete[] m_global_points
;
125 delete m_cond_points
;
128 // Set the global pointer equivalency for SSA to POINTEE.
131 pointer_equiv_analyzer::set_global_equiv (tree ssa
, tree pointee
)
133 m_global_points
[SSA_NAME_VERSION (ssa
)] = pointee
;
136 // Set the conditional pointer equivalency for SSA to POINTEE.
139 pointer_equiv_analyzer::set_cond_equiv (tree ssa
, tree pointee
)
141 m_cond_points
->push_replacement (ssa
, pointee
);
144 // Return the current pointer equivalency info for SSA, or NULL if
145 // none is available. Note that global info takes priority over
149 pointer_equiv_analyzer::get_equiv (tree ssa
) const
151 tree ret
= m_global_points
[SSA_NAME_VERSION (ssa
)];
154 return m_cond_points
->get_replacement (ssa
);
157 // Method to be called on entry to a BB.
160 pointer_equiv_analyzer::enter (basic_block bb
)
162 m_cond_points
->enter (bb
);
164 for (gphi_iterator iter
= gsi_start_phis (bb
);
168 gphi
*phi
= iter
.phi ();
169 tree lhs
= gimple_phi_result (phi
);
170 if (!POINTER_TYPE_P (TREE_TYPE (lhs
)))
172 tree arg0
= gimple_phi_arg_def (phi
, 0);
173 if (TREE_CODE (arg0
) == SSA_NAME
&& !is_gimple_min_invariant (arg0
))
174 arg0
= get_equiv (arg0
);
175 if (arg0
&& is_gimple_min_invariant (arg0
))
177 // If all the PHI args point to the same place, set the
178 // pointer equivalency info for the PHI result. This can
179 // happen for passes that create redundant PHIs like
180 // PHI<&foo, &foo> or PHI<&foo>.
181 for (size_t i
= 1; i
< gimple_phi_num_args (phi
); ++i
)
183 tree argi
= gimple_phi_arg_def (phi
, i
);
184 if (TREE_CODE (argi
) == SSA_NAME
185 && !is_gimple_min_invariant (argi
))
186 argi
= get_equiv (argi
);
187 if (!argi
|| !operand_equal_p (arg0
, argi
))
190 set_global_equiv (lhs
, arg0
);
194 edge pred
= single_pred_edge_ignoring_loop_edges (bb
, false);
199 // Method to be called on exit from a BB.
202 pointer_equiv_analyzer::leave (basic_block bb
)
204 m_cond_points
->leave (bb
);
207 // Helper function to return the pointer equivalency information for
208 // EXPR from a gimple statement with CODE. This returns either the
209 // cached pointer equivalency info for an SSA, or an invariant in case
210 // EXPR is one (i.e. &foo). Returns NULL if EXPR is neither an SSA
214 pointer_equiv_analyzer::get_equiv_expr (tree_code code
, tree expr
) const
216 if (code
== SSA_NAME
)
217 return get_equiv (expr
);
219 if (get_gimple_rhs_class (code
) == GIMPLE_SINGLE_RHS
220 && is_gimple_min_invariant (expr
))
226 // Hack to provide context to the gimple fold callback.
230 gimple_ranger
*m_ranger
;
231 pointer_equiv_analyzer
*m_pta
;
234 // Gimple fold callback.
236 pta_valueize (tree name
)
239 = x_fold_context
.m_ranger
->value_of_expr (name
, x_fold_context
.m_stmt
);
241 if (!ret
&& supported_pointer_equiv_p (name
))
242 ret
= x_fold_context
.m_pta
->get_equiv (name
);
244 return ret
? ret
: name
;
247 // Method to be called on gimple statements during traversal of the IL.
250 pointer_equiv_analyzer::visit_stmt (gimple
*stmt
)
252 if (gimple_code (stmt
) != GIMPLE_ASSIGN
)
255 tree lhs
= gimple_assign_lhs (stmt
);
256 if (!supported_pointer_equiv_p (lhs
))
259 tree rhs
= gimple_assign_rhs1 (stmt
);
260 rhs
= get_equiv_expr (gimple_assign_rhs_code (stmt
), rhs
);
263 set_global_equiv (lhs
, rhs
);
267 // If we couldn't find anything, try fold.
268 x_fold_context
= { stmt
, m_ranger
, this};
269 rhs
= gimple_fold_stmt_to_constant_1 (stmt
, pta_valueize
, pta_valueize
);
272 rhs
= get_equiv_expr (TREE_CODE (rhs
), rhs
);
275 set_global_equiv (lhs
, rhs
);
281 // If the edge in E is a conditional that sets a pointer equality, set the
282 // conditional pointer equivalency information.
285 pointer_equiv_analyzer::visit_edge (edge e
)
287 gimple
*stmt
= last_stmt (e
->src
);
289 // Recognize: x_13 [==,!=] &foo.
291 && gimple_code (stmt
) == GIMPLE_COND
292 && (lhs
= gimple_cond_lhs (stmt
))
293 && TREE_CODE (lhs
) == SSA_NAME
294 && POINTER_TYPE_P (TREE_TYPE (lhs
))
295 && TREE_CODE (gimple_cond_rhs (stmt
)) == ADDR_EXPR
)
297 tree_code code
= gimple_cond_code (stmt
);
298 if ((code
== EQ_EXPR
&& e
->flags
& EDGE_TRUE_VALUE
)
299 || ((code
== NE_EXPR
&& e
->flags
& EDGE_FALSE_VALUE
)))
300 set_cond_equiv (lhs
, gimple_cond_rhs (stmt
));