1e4b17023SJohn Marino /* Backward propagation of indirect loads through PHIs.
2e4b17023SJohn Marino Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3e4b17023SJohn Marino Contributed by Richard Guenther <rguenther@suse.de>
4e4b17023SJohn Marino
5e4b17023SJohn Marino This file is part of GCC.
6e4b17023SJohn Marino
7e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify
8e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
9e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
10e4b17023SJohn Marino any later version.
11e4b17023SJohn Marino
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful,
13e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
14e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15e4b17023SJohn Marino GNU General Public License for more details.
16e4b17023SJohn Marino
17e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
19e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
20e4b17023SJohn Marino
21e4b17023SJohn Marino #include "config.h"
22e4b17023SJohn Marino #include "system.h"
23e4b17023SJohn Marino #include "coretypes.h"
24e4b17023SJohn Marino #include "tm.h"
25e4b17023SJohn Marino #include "tree.h"
26e4b17023SJohn Marino #include "tm_p.h"
27e4b17023SJohn Marino #include "basic-block.h"
28e4b17023SJohn Marino #include "timevar.h"
29e4b17023SJohn Marino #include "tree-pretty-print.h"
30e4b17023SJohn Marino #include "gimple-pretty-print.h"
31e4b17023SJohn Marino #include "tree-flow.h"
32e4b17023SJohn Marino #include "tree-pass.h"
33e4b17023SJohn Marino #include "tree-dump.h"
34e4b17023SJohn Marino #include "langhooks.h"
35e4b17023SJohn Marino #include "flags.h"
36e4b17023SJohn Marino
37e4b17023SJohn Marino /* This pass propagates indirect loads through the PHI node for its
38e4b17023SJohn Marino address to make the load source possibly non-addressable and to
39e4b17023SJohn Marino allow for PHI optimization to trigger.
40e4b17023SJohn Marino
41e4b17023SJohn Marino For example the pass changes
42e4b17023SJohn Marino
43e4b17023SJohn Marino # addr_1 = PHI <&a, &b>
44e4b17023SJohn Marino tmp_1 = *addr_1;
45e4b17023SJohn Marino
46e4b17023SJohn Marino to
47e4b17023SJohn Marino
48e4b17023SJohn Marino # tmp_1 = PHI <a, b>
49e4b17023SJohn Marino
50e4b17023SJohn Marino but also handles more complex scenarios like
51e4b17023SJohn Marino
52e4b17023SJohn Marino D.2077_2 = &this_1(D)->a1;
53e4b17023SJohn Marino ...
54e4b17023SJohn Marino
55e4b17023SJohn Marino # b_12 = PHI <&c(2), D.2077_2(3)>
56e4b17023SJohn Marino D.2114_13 = *b_12;
57e4b17023SJohn Marino ...
58e4b17023SJohn Marino
59e4b17023SJohn Marino # b_15 = PHI <b_12(4), &b(5)>
60e4b17023SJohn Marino D.2080_5 = &this_1(D)->a0;
61e4b17023SJohn Marino ...
62e4b17023SJohn Marino
63e4b17023SJohn Marino # b_18 = PHI <D.2080_5(6), &c(7)>
64e4b17023SJohn Marino ...
65e4b17023SJohn Marino
66e4b17023SJohn Marino # b_21 = PHI <b_15(8), b_18(9)>
67e4b17023SJohn Marino D.2076_8 = *b_21;
68e4b17023SJohn Marino
69e4b17023SJohn Marino where the addresses loaded are defined by PHIs itself.
70e4b17023SJohn Marino The above happens for
71e4b17023SJohn Marino
72e4b17023SJohn Marino std::max(std::min(a0, c), std::min(std::max(a1, c), b))
73e4b17023SJohn Marino
74e4b17023SJohn Marino where this pass transforms it to a form later PHI optimization
75e4b17023SJohn Marino recognizes and transforms it to the simple
76e4b17023SJohn Marino
77e4b17023SJohn Marino D.2109_10 = this_1(D)->a1;
78e4b17023SJohn Marino D.2110_11 = c;
79e4b17023SJohn Marino D.2114_31 = MAX_EXPR <D.2109_10, D.2110_11>;
80e4b17023SJohn Marino D.2115_14 = b;
81e4b17023SJohn Marino D.2125_17 = MIN_EXPR <D.2115_14, D.2114_31>;
82e4b17023SJohn Marino D.2119_16 = this_1(D)->a0;
83e4b17023SJohn Marino D.2124_32 = MIN_EXPR <D.2110_11, D.2119_16>;
84e4b17023SJohn Marino D.2076_33 = MAX_EXPR <D.2125_17, D.2124_32>;
85e4b17023SJohn Marino
86e4b17023SJohn Marino The pass does a dominator walk processing loads using a basic-block
87e4b17023SJohn Marino local analysis and stores the result for use by transformations on
88e4b17023SJohn Marino dominated basic-blocks. */
89e4b17023SJohn Marino
90e4b17023SJohn Marino
91e4b17023SJohn Marino /* Structure to keep track of the value of a dereferenced PHI result
92e4b17023SJohn Marino and the virtual operand used for that dereference. */
93e4b17023SJohn Marino
94e4b17023SJohn Marino struct phiprop_d
95e4b17023SJohn Marino {
96e4b17023SJohn Marino tree value;
97e4b17023SJohn Marino tree vuse;
98e4b17023SJohn Marino };
99e4b17023SJohn Marino
100e4b17023SJohn Marino /* Verify if the value recorded for NAME in PHIVN is still valid at
101e4b17023SJohn Marino the start of basic block BB. */
102e4b17023SJohn Marino
103e4b17023SJohn Marino static bool
phivn_valid_p(struct phiprop_d * phivn,tree name,basic_block bb)104e4b17023SJohn Marino phivn_valid_p (struct phiprop_d *phivn, tree name, basic_block bb)
105e4b17023SJohn Marino {
106e4b17023SJohn Marino tree vuse = phivn[SSA_NAME_VERSION (name)].vuse;
107e4b17023SJohn Marino gimple use_stmt;
108e4b17023SJohn Marino imm_use_iterator ui2;
109e4b17023SJohn Marino bool ok = true;
110e4b17023SJohn Marino
111e4b17023SJohn Marino /* The def stmts of the virtual uses need to be dominated by bb. */
112e4b17023SJohn Marino gcc_assert (vuse != NULL_TREE);
113e4b17023SJohn Marino
114e4b17023SJohn Marino FOR_EACH_IMM_USE_STMT (use_stmt, ui2, vuse)
115e4b17023SJohn Marino {
116e4b17023SJohn Marino /* If BB does not dominate a VDEF, the value is invalid. */
117e4b17023SJohn Marino if ((gimple_vdef (use_stmt) != NULL_TREE
118e4b17023SJohn Marino || gimple_code (use_stmt) == GIMPLE_PHI)
119e4b17023SJohn Marino && !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
120e4b17023SJohn Marino {
121e4b17023SJohn Marino ok = false;
122e4b17023SJohn Marino BREAK_FROM_IMM_USE_STMT (ui2);
123e4b17023SJohn Marino }
124e4b17023SJohn Marino }
125e4b17023SJohn Marino
126e4b17023SJohn Marino return ok;
127e4b17023SJohn Marino }
128e4b17023SJohn Marino
129e4b17023SJohn Marino /* Insert a new phi node for the dereference of PHI at basic_block
130e4b17023SJohn Marino BB with the virtual operands from USE_STMT. */
131e4b17023SJohn Marino
132e4b17023SJohn Marino static tree
phiprop_insert_phi(basic_block bb,gimple phi,gimple use_stmt,struct phiprop_d * phivn,size_t n)133e4b17023SJohn Marino phiprop_insert_phi (basic_block bb, gimple phi, gimple use_stmt,
134e4b17023SJohn Marino struct phiprop_d *phivn, size_t n)
135e4b17023SJohn Marino {
136e4b17023SJohn Marino tree res;
137e4b17023SJohn Marino gimple new_phi;
138e4b17023SJohn Marino edge_iterator ei;
139e4b17023SJohn Marino edge e;
140e4b17023SJohn Marino
141e4b17023SJohn Marino gcc_assert (is_gimple_assign (use_stmt)
142e4b17023SJohn Marino && gimple_assign_rhs_code (use_stmt) == MEM_REF);
143e4b17023SJohn Marino
144e4b17023SJohn Marino /* Build a new PHI node to replace the definition of
145e4b17023SJohn Marino the indirect reference lhs. */
146e4b17023SJohn Marino res = gimple_assign_lhs (use_stmt);
147e4b17023SJohn Marino SSA_NAME_DEF_STMT (res) = new_phi = create_phi_node (res, bb);
148e4b17023SJohn Marino
149e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
150e4b17023SJohn Marino {
151e4b17023SJohn Marino fprintf (dump_file, "Inserting PHI for result of load ");
152e4b17023SJohn Marino print_gimple_stmt (dump_file, use_stmt, 0, 0);
153e4b17023SJohn Marino }
154e4b17023SJohn Marino
155e4b17023SJohn Marino /* Add PHI arguments for each edge inserting loads of the
156e4b17023SJohn Marino addressable operands. */
157e4b17023SJohn Marino FOR_EACH_EDGE (e, ei, bb->preds)
158e4b17023SJohn Marino {
159e4b17023SJohn Marino tree old_arg, new_var;
160e4b17023SJohn Marino gimple tmp;
161e4b17023SJohn Marino source_location locus;
162e4b17023SJohn Marino
163e4b17023SJohn Marino old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
164e4b17023SJohn Marino locus = gimple_phi_arg_location_from_edge (phi, e);
165e4b17023SJohn Marino while (TREE_CODE (old_arg) == SSA_NAME
166e4b17023SJohn Marino && (SSA_NAME_VERSION (old_arg) >= n
167e4b17023SJohn Marino || phivn[SSA_NAME_VERSION (old_arg)].value == NULL_TREE))
168e4b17023SJohn Marino {
169e4b17023SJohn Marino gimple def_stmt = SSA_NAME_DEF_STMT (old_arg);
170e4b17023SJohn Marino old_arg = gimple_assign_rhs1 (def_stmt);
171e4b17023SJohn Marino locus = gimple_location (def_stmt);
172e4b17023SJohn Marino }
173e4b17023SJohn Marino
174e4b17023SJohn Marino if (TREE_CODE (old_arg) == SSA_NAME)
175e4b17023SJohn Marino {
176e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
177e4b17023SJohn Marino {
178e4b17023SJohn Marino fprintf (dump_file, " for edge defining ");
179e4b17023SJohn Marino print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0);
180e4b17023SJohn Marino fprintf (dump_file, " reusing PHI result ");
181e4b17023SJohn Marino print_generic_expr (dump_file,
182e4b17023SJohn Marino phivn[SSA_NAME_VERSION (old_arg)].value, 0);
183e4b17023SJohn Marino fprintf (dump_file, "\n");
184e4b17023SJohn Marino }
185e4b17023SJohn Marino /* Reuse a formerly created dereference. */
186e4b17023SJohn Marino new_var = phivn[SSA_NAME_VERSION (old_arg)].value;
187e4b17023SJohn Marino }
188e4b17023SJohn Marino else
189e4b17023SJohn Marino {
190e4b17023SJohn Marino tree rhs = gimple_assign_rhs1 (use_stmt);
191e4b17023SJohn Marino gcc_assert (TREE_CODE (old_arg) == ADDR_EXPR);
192e4b17023SJohn Marino new_var = create_tmp_reg (TREE_TYPE (rhs), NULL);
193e4b17023SJohn Marino if (!is_gimple_min_invariant (old_arg))
194e4b17023SJohn Marino old_arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
195e4b17023SJohn Marino else
196e4b17023SJohn Marino old_arg = unshare_expr (old_arg);
197e4b17023SJohn Marino tmp = gimple_build_assign (new_var,
198e4b17023SJohn Marino fold_build2 (MEM_REF, TREE_TYPE (rhs),
199e4b17023SJohn Marino old_arg,
200e4b17023SJohn Marino TREE_OPERAND (rhs, 1)));
201e4b17023SJohn Marino gcc_assert (is_gimple_reg (new_var));
202e4b17023SJohn Marino add_referenced_var (new_var);
203e4b17023SJohn Marino new_var = make_ssa_name (new_var, tmp);
204e4b17023SJohn Marino gimple_assign_set_lhs (tmp, new_var);
205e4b17023SJohn Marino gimple_set_location (tmp, locus);
206e4b17023SJohn Marino
207e4b17023SJohn Marino gsi_insert_on_edge (e, tmp);
208e4b17023SJohn Marino update_stmt (tmp);
209e4b17023SJohn Marino
210e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
211e4b17023SJohn Marino {
212e4b17023SJohn Marino fprintf (dump_file, " for edge defining ");
213e4b17023SJohn Marino print_generic_expr (dump_file, PHI_ARG_DEF_FROM_EDGE (phi, e), 0);
214e4b17023SJohn Marino fprintf (dump_file, " inserting load ");
215e4b17023SJohn Marino print_gimple_stmt (dump_file, tmp, 0, 0);
216e4b17023SJohn Marino }
217e4b17023SJohn Marino }
218e4b17023SJohn Marino
219e4b17023SJohn Marino add_phi_arg (new_phi, new_var, e, locus);
220e4b17023SJohn Marino }
221e4b17023SJohn Marino
222e4b17023SJohn Marino update_stmt (new_phi);
223e4b17023SJohn Marino
224e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
225e4b17023SJohn Marino print_gimple_stmt (dump_file, new_phi, 0, 0);
226e4b17023SJohn Marino
227e4b17023SJohn Marino return res;
228e4b17023SJohn Marino }
229e4b17023SJohn Marino
230e4b17023SJohn Marino /* Propagate between the phi node arguments of PHI in BB and phi result
231e4b17023SJohn Marino users. For now this matches
232e4b17023SJohn Marino # p_2 = PHI <&x, &y>
233e4b17023SJohn Marino <Lx>:;
234e4b17023SJohn Marino p_3 = p_2;
235e4b17023SJohn Marino z_2 = *p_3;
236e4b17023SJohn Marino and converts it to
237e4b17023SJohn Marino # z_2 = PHI <x, y>
238e4b17023SJohn Marino <Lx>:;
239e4b17023SJohn Marino Returns true if a transformation was done and edge insertions
240e4b17023SJohn Marino need to be committed. Global data PHIVN and N is used to track
241e4b17023SJohn Marino past transformation results. We need to be especially careful here
242e4b17023SJohn Marino with aliasing issues as we are moving memory reads. */
243e4b17023SJohn Marino
244e4b17023SJohn Marino static bool
propagate_with_phi(basic_block bb,gimple phi,struct phiprop_d * phivn,size_t n)245e4b17023SJohn Marino propagate_with_phi (basic_block bb, gimple phi, struct phiprop_d *phivn,
246e4b17023SJohn Marino size_t n)
247e4b17023SJohn Marino {
248e4b17023SJohn Marino tree ptr = PHI_RESULT (phi);
249e4b17023SJohn Marino gimple use_stmt;
250e4b17023SJohn Marino tree res = NULL_TREE;
251e4b17023SJohn Marino gimple_stmt_iterator gsi;
252e4b17023SJohn Marino imm_use_iterator ui;
253e4b17023SJohn Marino use_operand_p arg_p, use;
254e4b17023SJohn Marino ssa_op_iter i;
255e4b17023SJohn Marino bool phi_inserted;
256e4b17023SJohn Marino tree type = NULL_TREE;
257e4b17023SJohn Marino bool one_invariant = false;
258e4b17023SJohn Marino
259e4b17023SJohn Marino if (!POINTER_TYPE_P (TREE_TYPE (ptr))
260e4b17023SJohn Marino || !is_gimple_reg_type (TREE_TYPE (TREE_TYPE (ptr))))
261e4b17023SJohn Marino return false;
262e4b17023SJohn Marino
263e4b17023SJohn Marino /* Check if we can "cheaply" dereference all phi arguments. */
264e4b17023SJohn Marino FOR_EACH_PHI_ARG (arg_p, phi, i, SSA_OP_USE)
265e4b17023SJohn Marino {
266e4b17023SJohn Marino tree arg = USE_FROM_PTR (arg_p);
267e4b17023SJohn Marino /* Walk the ssa chain until we reach a ssa name we already
268e4b17023SJohn Marino created a value for or we reach a definition of the form
269e4b17023SJohn Marino ssa_name_n = &var; */
270e4b17023SJohn Marino while (TREE_CODE (arg) == SSA_NAME
271e4b17023SJohn Marino && !SSA_NAME_IS_DEFAULT_DEF (arg)
272e4b17023SJohn Marino && (SSA_NAME_VERSION (arg) >= n
273e4b17023SJohn Marino || phivn[SSA_NAME_VERSION (arg)].value == NULL_TREE))
274e4b17023SJohn Marino {
275e4b17023SJohn Marino gimple def_stmt = SSA_NAME_DEF_STMT (arg);
276e4b17023SJohn Marino if (!gimple_assign_single_p (def_stmt))
277e4b17023SJohn Marino return false;
278e4b17023SJohn Marino arg = gimple_assign_rhs1 (def_stmt);
279e4b17023SJohn Marino }
280e4b17023SJohn Marino if (TREE_CODE (arg) != ADDR_EXPR
281e4b17023SJohn Marino && !(TREE_CODE (arg) == SSA_NAME
282e4b17023SJohn Marino && SSA_NAME_VERSION (arg) < n
283e4b17023SJohn Marino && phivn[SSA_NAME_VERSION (arg)].value != NULL_TREE
284e4b17023SJohn Marino && (!type
285e4b17023SJohn Marino || types_compatible_p
286e4b17023SJohn Marino (type, TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value)))
287e4b17023SJohn Marino && phivn_valid_p (phivn, arg, bb)))
288e4b17023SJohn Marino return false;
289e4b17023SJohn Marino if (!type
290e4b17023SJohn Marino && TREE_CODE (arg) == SSA_NAME)
291e4b17023SJohn Marino type = TREE_TYPE (phivn[SSA_NAME_VERSION (arg)].value);
292e4b17023SJohn Marino if (TREE_CODE (arg) == ADDR_EXPR
293e4b17023SJohn Marino && is_gimple_min_invariant (arg))
294e4b17023SJohn Marino one_invariant = true;
295e4b17023SJohn Marino }
296e4b17023SJohn Marino
297e4b17023SJohn Marino /* If we neither have an address of a decl nor can reuse a previously
298e4b17023SJohn Marino inserted load, do not hoist anything. */
299e4b17023SJohn Marino if (!one_invariant
300e4b17023SJohn Marino && !type)
301e4b17023SJohn Marino return false;
302e4b17023SJohn Marino
303e4b17023SJohn Marino /* Find a dereferencing use. First follow (single use) ssa
304e4b17023SJohn Marino copy chains for ptr. */
305e4b17023SJohn Marino while (single_imm_use (ptr, &use, &use_stmt)
306e4b17023SJohn Marino && gimple_assign_ssa_name_copy_p (use_stmt))
307e4b17023SJohn Marino ptr = gimple_assign_lhs (use_stmt);
308e4b17023SJohn Marino
309e4b17023SJohn Marino /* Replace the first dereference of *ptr if there is one and if we
310e4b17023SJohn Marino can move the loads to the place of the ptr phi node. */
311e4b17023SJohn Marino phi_inserted = false;
312e4b17023SJohn Marino FOR_EACH_IMM_USE_STMT (use_stmt, ui, ptr)
313e4b17023SJohn Marino {
314e4b17023SJohn Marino gimple def_stmt;
315e4b17023SJohn Marino tree vuse;
316e4b17023SJohn Marino
317*95d28233SJohn Marino /* Only replace loads in blocks that post-dominate the PHI node. That
318*95d28233SJohn Marino makes sure we don't end up speculating loads. */
319*95d28233SJohn Marino if (!dominated_by_p (CDI_POST_DOMINATORS,
320*95d28233SJohn Marino bb, gimple_bb (use_stmt)))
321*95d28233SJohn Marino continue;
322*95d28233SJohn Marino
323e4b17023SJohn Marino /* Check whether this is a load of *ptr. */
324e4b17023SJohn Marino if (!(is_gimple_assign (use_stmt)
325e4b17023SJohn Marino && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
326e4b17023SJohn Marino && gimple_assign_rhs_code (use_stmt) == MEM_REF
327e4b17023SJohn Marino && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == ptr
328e4b17023SJohn Marino && integer_zerop (TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 1))
329e4b17023SJohn Marino && (!type
330e4b17023SJohn Marino || types_compatible_p
331e4b17023SJohn Marino (TREE_TYPE (gimple_assign_lhs (use_stmt)), type))
332e4b17023SJohn Marino /* We cannot replace a load that may throw or is volatile. */
333e4b17023SJohn Marino && !stmt_can_throw_internal (use_stmt)))
334e4b17023SJohn Marino continue;
335e4b17023SJohn Marino
336e4b17023SJohn Marino /* Check if we can move the loads. The def stmt of the virtual use
337e4b17023SJohn Marino needs to be in a different basic block dominating bb. */
338e4b17023SJohn Marino vuse = gimple_vuse (use_stmt);
339e4b17023SJohn Marino def_stmt = SSA_NAME_DEF_STMT (vuse);
340e4b17023SJohn Marino if (!SSA_NAME_IS_DEFAULT_DEF (vuse)
341e4b17023SJohn Marino && (gimple_bb (def_stmt) == bb
342e4b17023SJohn Marino || !dominated_by_p (CDI_DOMINATORS,
343e4b17023SJohn Marino bb, gimple_bb (def_stmt))))
344e4b17023SJohn Marino goto next;
345e4b17023SJohn Marino
346e4b17023SJohn Marino /* Found a proper dereference. Insert a phi node if this
347e4b17023SJohn Marino is the first load transformation. */
348e4b17023SJohn Marino if (!phi_inserted)
349e4b17023SJohn Marino {
350e4b17023SJohn Marino res = phiprop_insert_phi (bb, phi, use_stmt, phivn, n);
351e4b17023SJohn Marino type = TREE_TYPE (res);
352e4b17023SJohn Marino
353e4b17023SJohn Marino /* Remember the value we created for *ptr. */
354e4b17023SJohn Marino phivn[SSA_NAME_VERSION (ptr)].value = res;
355e4b17023SJohn Marino phivn[SSA_NAME_VERSION (ptr)].vuse = vuse;
356e4b17023SJohn Marino
357e4b17023SJohn Marino /* Remove old stmt. The phi is taken care of by DCE, if we
358e4b17023SJohn Marino want to delete it here we also have to delete all intermediate
359e4b17023SJohn Marino copies. */
360e4b17023SJohn Marino gsi = gsi_for_stmt (use_stmt);
361e4b17023SJohn Marino gsi_remove (&gsi, true);
362e4b17023SJohn Marino
363e4b17023SJohn Marino phi_inserted = true;
364e4b17023SJohn Marino }
365e4b17023SJohn Marino else
366e4b17023SJohn Marino {
367e4b17023SJohn Marino /* Further replacements are easy, just make a copy out of the
368e4b17023SJohn Marino load. */
369e4b17023SJohn Marino gimple_assign_set_rhs1 (use_stmt, res);
370e4b17023SJohn Marino update_stmt (use_stmt);
371e4b17023SJohn Marino }
372e4b17023SJohn Marino
373e4b17023SJohn Marino next:;
374e4b17023SJohn Marino /* Continue searching for a proper dereference. */
375e4b17023SJohn Marino }
376e4b17023SJohn Marino
377e4b17023SJohn Marino return phi_inserted;
378e4b17023SJohn Marino }
379e4b17023SJohn Marino
380e4b17023SJohn Marino /* Main entry for phiprop pass. */
381e4b17023SJohn Marino
382e4b17023SJohn Marino static unsigned int
tree_ssa_phiprop(void)383e4b17023SJohn Marino tree_ssa_phiprop (void)
384e4b17023SJohn Marino {
385e4b17023SJohn Marino VEC(basic_block, heap) *bbs;
386e4b17023SJohn Marino struct phiprop_d *phivn;
387e4b17023SJohn Marino bool did_something = false;
388e4b17023SJohn Marino basic_block bb;
389e4b17023SJohn Marino gimple_stmt_iterator gsi;
390e4b17023SJohn Marino unsigned i;
391e4b17023SJohn Marino size_t n;
392e4b17023SJohn Marino
393e4b17023SJohn Marino calculate_dominance_info (CDI_DOMINATORS);
394*95d28233SJohn Marino calculate_dominance_info (CDI_POST_DOMINATORS);
395e4b17023SJohn Marino
396e4b17023SJohn Marino n = num_ssa_names;
397e4b17023SJohn Marino phivn = XCNEWVEC (struct phiprop_d, n);
398e4b17023SJohn Marino
399e4b17023SJohn Marino /* Walk the dominator tree in preorder. */
400e4b17023SJohn Marino bbs = get_all_dominated_blocks (CDI_DOMINATORS,
401e4b17023SJohn Marino single_succ (ENTRY_BLOCK_PTR));
402e4b17023SJohn Marino FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
403e4b17023SJohn Marino for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
404e4b17023SJohn Marino did_something |= propagate_with_phi (bb, gsi_stmt (gsi), phivn, n);
405e4b17023SJohn Marino
406e4b17023SJohn Marino if (did_something)
407e4b17023SJohn Marino gsi_commit_edge_inserts ();
408e4b17023SJohn Marino
409e4b17023SJohn Marino VEC_free (basic_block, heap, bbs);
410e4b17023SJohn Marino free (phivn);
411e4b17023SJohn Marino
412*95d28233SJohn Marino free_dominance_info (CDI_POST_DOMINATORS);
413*95d28233SJohn Marino
414e4b17023SJohn Marino return 0;
415e4b17023SJohn Marino }
416e4b17023SJohn Marino
417e4b17023SJohn Marino static bool
gate_phiprop(void)418e4b17023SJohn Marino gate_phiprop (void)
419e4b17023SJohn Marino {
420e4b17023SJohn Marino return flag_tree_phiprop;
421e4b17023SJohn Marino }
422e4b17023SJohn Marino
423e4b17023SJohn Marino struct gimple_opt_pass pass_phiprop =
424e4b17023SJohn Marino {
425e4b17023SJohn Marino {
426e4b17023SJohn Marino GIMPLE_PASS,
427e4b17023SJohn Marino "phiprop", /* name */
428e4b17023SJohn Marino gate_phiprop, /* gate */
429e4b17023SJohn Marino tree_ssa_phiprop, /* execute */
430e4b17023SJohn Marino NULL, /* sub */
431e4b17023SJohn Marino NULL, /* next */
432e4b17023SJohn Marino 0, /* static_pass_number */
433e4b17023SJohn Marino TV_TREE_PHIPROP, /* tv_id */
434e4b17023SJohn Marino PROP_cfg | PROP_ssa, /* properties_required */
435e4b17023SJohn Marino 0, /* properties_provided */
436e4b17023SJohn Marino 0, /* properties_destroyed */
437e4b17023SJohn Marino 0, /* todo_flags_start */
438e4b17023SJohn Marino TODO_ggc_collect
439e4b17023SJohn Marino | TODO_update_ssa
440e4b17023SJohn Marino | TODO_verify_ssa /* todo_flags_finish */
441e4b17023SJohn Marino }
442e4b17023SJohn Marino };
443