1e4b17023SJohn Marino /* Optimization of PHI nodes by converting them into straightline code.
2e4b17023SJohn Marino Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3e4b17023SJohn Marino Free Software Foundation, Inc.
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 it
8e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
9e4b17023SJohn Marino Free Software Foundation; either version 3, or (at your option) any
10e4b17023SJohn Marino later version.
11e4b17023SJohn Marino
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
13e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15e4b17023SJohn Marino 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 "ggc.h"
26e4b17023SJohn Marino #include "tree.h"
27e4b17023SJohn Marino #include "flags.h"
28e4b17023SJohn Marino #include "tm_p.h"
29e4b17023SJohn Marino #include "basic-block.h"
30e4b17023SJohn Marino #include "timevar.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 "pointer-set.h"
36e4b17023SJohn Marino #include "domwalk.h"
37e4b17023SJohn Marino #include "cfgloop.h"
38e4b17023SJohn Marino #include "tree-data-ref.h"
39e4b17023SJohn Marino
40e4b17023SJohn Marino static unsigned int tree_ssa_phiopt (void);
41e4b17023SJohn Marino static unsigned int tree_ssa_phiopt_worker (bool);
42e4b17023SJohn Marino static bool conditional_replacement (basic_block, basic_block,
43e4b17023SJohn Marino edge, edge, gimple, tree, tree);
44e4b17023SJohn Marino static bool value_replacement (basic_block, basic_block,
45e4b17023SJohn Marino edge, edge, gimple, tree, tree);
46e4b17023SJohn Marino static bool minmax_replacement (basic_block, basic_block,
47e4b17023SJohn Marino edge, edge, gimple, tree, tree);
48e4b17023SJohn Marino static bool abs_replacement (basic_block, basic_block,
49e4b17023SJohn Marino edge, edge, gimple, tree, tree);
50e4b17023SJohn Marino static bool cond_store_replacement (basic_block, basic_block, edge, edge,
51e4b17023SJohn Marino struct pointer_set_t *);
52e4b17023SJohn Marino static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block);
53e4b17023SJohn Marino static struct pointer_set_t * get_non_trapping (void);
54e4b17023SJohn Marino static void replace_phi_edge_with_variable (basic_block, edge, gimple, tree);
55e4b17023SJohn Marino
56e4b17023SJohn Marino /* This pass tries to replaces an if-then-else block with an
57e4b17023SJohn Marino assignment. We have four kinds of transformations. Some of these
58e4b17023SJohn Marino transformations are also performed by the ifcvt RTL optimizer.
59e4b17023SJohn Marino
60e4b17023SJohn Marino Conditional Replacement
61e4b17023SJohn Marino -----------------------
62e4b17023SJohn Marino
63e4b17023SJohn Marino This transformation, implemented in conditional_replacement,
64e4b17023SJohn Marino replaces
65e4b17023SJohn Marino
66e4b17023SJohn Marino bb0:
67e4b17023SJohn Marino if (cond) goto bb2; else goto bb1;
68e4b17023SJohn Marino bb1:
69e4b17023SJohn Marino bb2:
70e4b17023SJohn Marino x = PHI <0 (bb1), 1 (bb0), ...>;
71e4b17023SJohn Marino
72e4b17023SJohn Marino with
73e4b17023SJohn Marino
74e4b17023SJohn Marino bb0:
75e4b17023SJohn Marino x' = cond;
76e4b17023SJohn Marino goto bb2;
77e4b17023SJohn Marino bb2:
78e4b17023SJohn Marino x = PHI <x' (bb0), ...>;
79e4b17023SJohn Marino
80e4b17023SJohn Marino We remove bb1 as it becomes unreachable. This occurs often due to
81e4b17023SJohn Marino gimplification of conditionals.
82e4b17023SJohn Marino
83e4b17023SJohn Marino Value Replacement
84e4b17023SJohn Marino -----------------
85e4b17023SJohn Marino
86e4b17023SJohn Marino This transformation, implemented in value_replacement, replaces
87e4b17023SJohn Marino
88e4b17023SJohn Marino bb0:
89e4b17023SJohn Marino if (a != b) goto bb2; else goto bb1;
90e4b17023SJohn Marino bb1:
91e4b17023SJohn Marino bb2:
92e4b17023SJohn Marino x = PHI <a (bb1), b (bb0), ...>;
93e4b17023SJohn Marino
94e4b17023SJohn Marino with
95e4b17023SJohn Marino
96e4b17023SJohn Marino bb0:
97e4b17023SJohn Marino bb2:
98e4b17023SJohn Marino x = PHI <b (bb0), ...>;
99e4b17023SJohn Marino
100e4b17023SJohn Marino This opportunity can sometimes occur as a result of other
101e4b17023SJohn Marino optimizations.
102e4b17023SJohn Marino
103e4b17023SJohn Marino ABS Replacement
104e4b17023SJohn Marino ---------------
105e4b17023SJohn Marino
106e4b17023SJohn Marino This transformation, implemented in abs_replacement, replaces
107e4b17023SJohn Marino
108e4b17023SJohn Marino bb0:
109e4b17023SJohn Marino if (a >= 0) goto bb2; else goto bb1;
110e4b17023SJohn Marino bb1:
111e4b17023SJohn Marino x = -a;
112e4b17023SJohn Marino bb2:
113e4b17023SJohn Marino x = PHI <x (bb1), a (bb0), ...>;
114e4b17023SJohn Marino
115e4b17023SJohn Marino with
116e4b17023SJohn Marino
117e4b17023SJohn Marino bb0:
118e4b17023SJohn Marino x' = ABS_EXPR< a >;
119e4b17023SJohn Marino bb2:
120e4b17023SJohn Marino x = PHI <x' (bb0), ...>;
121e4b17023SJohn Marino
122e4b17023SJohn Marino MIN/MAX Replacement
123e4b17023SJohn Marino -------------------
124e4b17023SJohn Marino
125e4b17023SJohn Marino This transformation, minmax_replacement replaces
126e4b17023SJohn Marino
127e4b17023SJohn Marino bb0:
128e4b17023SJohn Marino if (a <= b) goto bb2; else goto bb1;
129e4b17023SJohn Marino bb1:
130e4b17023SJohn Marino bb2:
131e4b17023SJohn Marino x = PHI <b (bb1), a (bb0), ...>;
132e4b17023SJohn Marino
133e4b17023SJohn Marino with
134e4b17023SJohn Marino
135e4b17023SJohn Marino bb0:
136e4b17023SJohn Marino x' = MIN_EXPR (a, b)
137e4b17023SJohn Marino bb2:
138e4b17023SJohn Marino x = PHI <x' (bb0), ...>;
139e4b17023SJohn Marino
140e4b17023SJohn Marino A similar transformation is done for MAX_EXPR. */
141e4b17023SJohn Marino
142e4b17023SJohn Marino static unsigned int
tree_ssa_phiopt(void)143e4b17023SJohn Marino tree_ssa_phiopt (void)
144e4b17023SJohn Marino {
145e4b17023SJohn Marino return tree_ssa_phiopt_worker (false);
146e4b17023SJohn Marino }
147e4b17023SJohn Marino
148e4b17023SJohn Marino /* This pass tries to transform conditional stores into unconditional
149e4b17023SJohn Marino ones, enabling further simplifications with the simpler then and else
150e4b17023SJohn Marino blocks. In particular it replaces this:
151e4b17023SJohn Marino
152e4b17023SJohn Marino bb0:
153e4b17023SJohn Marino if (cond) goto bb2; else goto bb1;
154e4b17023SJohn Marino bb1:
155e4b17023SJohn Marino *p = RHS;
156e4b17023SJohn Marino bb2:
157e4b17023SJohn Marino
158e4b17023SJohn Marino with
159e4b17023SJohn Marino
160e4b17023SJohn Marino bb0:
161e4b17023SJohn Marino if (cond) goto bb1; else goto bb2;
162e4b17023SJohn Marino bb1:
163e4b17023SJohn Marino condtmp' = *p;
164e4b17023SJohn Marino bb2:
165e4b17023SJohn Marino condtmp = PHI <RHS, condtmp'>
166e4b17023SJohn Marino *p = condtmp;
167e4b17023SJohn Marino
168e4b17023SJohn Marino This transformation can only be done under several constraints,
169e4b17023SJohn Marino documented below. It also replaces:
170e4b17023SJohn Marino
171e4b17023SJohn Marino bb0:
172e4b17023SJohn Marino if (cond) goto bb2; else goto bb1;
173e4b17023SJohn Marino bb1:
174e4b17023SJohn Marino *p = RHS1;
175e4b17023SJohn Marino goto bb3;
176e4b17023SJohn Marino bb2:
177e4b17023SJohn Marino *p = RHS2;
178e4b17023SJohn Marino bb3:
179e4b17023SJohn Marino
180e4b17023SJohn Marino with
181e4b17023SJohn Marino
182e4b17023SJohn Marino bb0:
183e4b17023SJohn Marino if (cond) goto bb3; else goto bb1;
184e4b17023SJohn Marino bb1:
185e4b17023SJohn Marino bb3:
186e4b17023SJohn Marino condtmp = PHI <RHS1, RHS2>
187e4b17023SJohn Marino *p = condtmp; */
188e4b17023SJohn Marino
189e4b17023SJohn Marino static unsigned int
tree_ssa_cs_elim(void)190e4b17023SJohn Marino tree_ssa_cs_elim (void)
191e4b17023SJohn Marino {
192e4b17023SJohn Marino return tree_ssa_phiopt_worker (true);
193e4b17023SJohn Marino }
194e4b17023SJohn Marino
195e4b17023SJohn Marino /* For conditional store replacement we need a temporary to
196e4b17023SJohn Marino put the old contents of the memory in. */
197e4b17023SJohn Marino static tree condstoretemp;
198e4b17023SJohn Marino
199e4b17023SJohn Marino /* The core routine of conditional store replacement and normal
200e4b17023SJohn Marino phi optimizations. Both share much of the infrastructure in how
201e4b17023SJohn Marino to match applicable basic block patterns. DO_STORE_ELIM is true
202e4b17023SJohn Marino when we want to do conditional store replacement, false otherwise. */
203e4b17023SJohn Marino static unsigned int
tree_ssa_phiopt_worker(bool do_store_elim)204e4b17023SJohn Marino tree_ssa_phiopt_worker (bool do_store_elim)
205e4b17023SJohn Marino {
206e4b17023SJohn Marino basic_block bb;
207e4b17023SJohn Marino basic_block *bb_order;
208e4b17023SJohn Marino unsigned n, i;
209e4b17023SJohn Marino bool cfgchanged = false;
210e4b17023SJohn Marino struct pointer_set_t *nontrap = 0;
211e4b17023SJohn Marino
212e4b17023SJohn Marino if (do_store_elim)
213e4b17023SJohn Marino {
214e4b17023SJohn Marino condstoretemp = NULL_TREE;
215e4b17023SJohn Marino /* Calculate the set of non-trapping memory accesses. */
216e4b17023SJohn Marino nontrap = get_non_trapping ();
217e4b17023SJohn Marino }
218e4b17023SJohn Marino
219e4b17023SJohn Marino /* Search every basic block for COND_EXPR we may be able to optimize.
220e4b17023SJohn Marino
221e4b17023SJohn Marino We walk the blocks in order that guarantees that a block with
222e4b17023SJohn Marino a single predecessor is processed before the predecessor.
223e4b17023SJohn Marino This ensures that we collapse inner ifs before visiting the
224e4b17023SJohn Marino outer ones, and also that we do not try to visit a removed
225e4b17023SJohn Marino block. */
226e4b17023SJohn Marino bb_order = blocks_in_phiopt_order ();
227e4b17023SJohn Marino n = n_basic_blocks - NUM_FIXED_BLOCKS;
228e4b17023SJohn Marino
229e4b17023SJohn Marino for (i = 0; i < n; i++)
230e4b17023SJohn Marino {
231e4b17023SJohn Marino gimple cond_stmt, phi;
232e4b17023SJohn Marino basic_block bb1, bb2;
233e4b17023SJohn Marino edge e1, e2;
234e4b17023SJohn Marino tree arg0, arg1;
235e4b17023SJohn Marino
236e4b17023SJohn Marino bb = bb_order[i];
237e4b17023SJohn Marino
238e4b17023SJohn Marino cond_stmt = last_stmt (bb);
239e4b17023SJohn Marino /* Check to see if the last statement is a GIMPLE_COND. */
240e4b17023SJohn Marino if (!cond_stmt
241e4b17023SJohn Marino || gimple_code (cond_stmt) != GIMPLE_COND)
242e4b17023SJohn Marino continue;
243e4b17023SJohn Marino
244e4b17023SJohn Marino e1 = EDGE_SUCC (bb, 0);
245e4b17023SJohn Marino bb1 = e1->dest;
246e4b17023SJohn Marino e2 = EDGE_SUCC (bb, 1);
247e4b17023SJohn Marino bb2 = e2->dest;
248e4b17023SJohn Marino
249e4b17023SJohn Marino /* We cannot do the optimization on abnormal edges. */
250e4b17023SJohn Marino if ((e1->flags & EDGE_ABNORMAL) != 0
251e4b17023SJohn Marino || (e2->flags & EDGE_ABNORMAL) != 0)
252e4b17023SJohn Marino continue;
253e4b17023SJohn Marino
254e4b17023SJohn Marino /* If either bb1's succ or bb2 or bb2's succ is non NULL. */
255e4b17023SJohn Marino if (EDGE_COUNT (bb1->succs) == 0
256e4b17023SJohn Marino || bb2 == NULL
257e4b17023SJohn Marino || EDGE_COUNT (bb2->succs) == 0)
258e4b17023SJohn Marino continue;
259e4b17023SJohn Marino
260e4b17023SJohn Marino /* Find the bb which is the fall through to the other. */
261e4b17023SJohn Marino if (EDGE_SUCC (bb1, 0)->dest == bb2)
262e4b17023SJohn Marino ;
263e4b17023SJohn Marino else if (EDGE_SUCC (bb2, 0)->dest == bb1)
264e4b17023SJohn Marino {
265e4b17023SJohn Marino basic_block bb_tmp = bb1;
266e4b17023SJohn Marino edge e_tmp = e1;
267e4b17023SJohn Marino bb1 = bb2;
268e4b17023SJohn Marino bb2 = bb_tmp;
269e4b17023SJohn Marino e1 = e2;
270e4b17023SJohn Marino e2 = e_tmp;
271e4b17023SJohn Marino }
272e4b17023SJohn Marino else if (do_store_elim
273e4b17023SJohn Marino && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
274e4b17023SJohn Marino {
275e4b17023SJohn Marino basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;
276e4b17023SJohn Marino
277e4b17023SJohn Marino if (!single_succ_p (bb1)
278e4b17023SJohn Marino || (EDGE_SUCC (bb1, 0)->flags & EDGE_FALLTHRU) == 0
279e4b17023SJohn Marino || !single_succ_p (bb2)
280e4b17023SJohn Marino || (EDGE_SUCC (bb2, 0)->flags & EDGE_FALLTHRU) == 0
281e4b17023SJohn Marino || EDGE_COUNT (bb3->preds) != 2)
282e4b17023SJohn Marino continue;
283e4b17023SJohn Marino if (cond_if_else_store_replacement (bb1, bb2, bb3))
284e4b17023SJohn Marino cfgchanged = true;
285e4b17023SJohn Marino continue;
286e4b17023SJohn Marino }
287e4b17023SJohn Marino else
288e4b17023SJohn Marino continue;
289e4b17023SJohn Marino
290e4b17023SJohn Marino e1 = EDGE_SUCC (bb1, 0);
291e4b17023SJohn Marino
292e4b17023SJohn Marino /* Make sure that bb1 is just a fall through. */
293e4b17023SJohn Marino if (!single_succ_p (bb1)
294e4b17023SJohn Marino || (e1->flags & EDGE_FALLTHRU) == 0)
295e4b17023SJohn Marino continue;
296e4b17023SJohn Marino
297e4b17023SJohn Marino /* Also make sure that bb1 only have one predecessor and that it
298e4b17023SJohn Marino is bb. */
299e4b17023SJohn Marino if (!single_pred_p (bb1)
300e4b17023SJohn Marino || single_pred (bb1) != bb)
301e4b17023SJohn Marino continue;
302e4b17023SJohn Marino
303e4b17023SJohn Marino if (do_store_elim)
304e4b17023SJohn Marino {
305e4b17023SJohn Marino /* bb1 is the middle block, bb2 the join block, bb the split block,
306e4b17023SJohn Marino e1 the fallthrough edge from bb1 to bb2. We can't do the
307e4b17023SJohn Marino optimization if the join block has more than two predecessors. */
308e4b17023SJohn Marino if (EDGE_COUNT (bb2->preds) > 2)
309e4b17023SJohn Marino continue;
310e4b17023SJohn Marino if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
311e4b17023SJohn Marino cfgchanged = true;
312e4b17023SJohn Marino }
313e4b17023SJohn Marino else
314e4b17023SJohn Marino {
315e4b17023SJohn Marino gimple_seq phis = phi_nodes (bb2);
316e4b17023SJohn Marino gimple_stmt_iterator gsi;
317e4b17023SJohn Marino
318e4b17023SJohn Marino /* Check to make sure that there is only one non-virtual PHI node.
319e4b17023SJohn Marino TODO: we could do it with more than one iff the other PHI nodes
320e4b17023SJohn Marino have the same elements for these two edges. */
321e4b17023SJohn Marino phi = NULL;
322e4b17023SJohn Marino for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
323e4b17023SJohn Marino {
324e4b17023SJohn Marino if (!is_gimple_reg (gimple_phi_result (gsi_stmt (gsi))))
325e4b17023SJohn Marino continue;
326e4b17023SJohn Marino if (phi)
327e4b17023SJohn Marino {
328e4b17023SJohn Marino phi = NULL;
329e4b17023SJohn Marino break;
330e4b17023SJohn Marino }
331e4b17023SJohn Marino phi = gsi_stmt (gsi);
332e4b17023SJohn Marino }
333e4b17023SJohn Marino if (!phi)
334e4b17023SJohn Marino continue;
335e4b17023SJohn Marino
336e4b17023SJohn Marino arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
337e4b17023SJohn Marino arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
338e4b17023SJohn Marino
339e4b17023SJohn Marino /* Something is wrong if we cannot find the arguments in the PHI
340e4b17023SJohn Marino node. */
341e4b17023SJohn Marino gcc_assert (arg0 != NULL && arg1 != NULL);
342e4b17023SJohn Marino
343e4b17023SJohn Marino /* Do the replacement of conditional if it can be done. */
344e4b17023SJohn Marino if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
345e4b17023SJohn Marino cfgchanged = true;
346e4b17023SJohn Marino else if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
347e4b17023SJohn Marino cfgchanged = true;
348e4b17023SJohn Marino else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
349e4b17023SJohn Marino cfgchanged = true;
350e4b17023SJohn Marino else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
351e4b17023SJohn Marino cfgchanged = true;
352e4b17023SJohn Marino }
353e4b17023SJohn Marino }
354e4b17023SJohn Marino
355e4b17023SJohn Marino free (bb_order);
356e4b17023SJohn Marino
357e4b17023SJohn Marino if (do_store_elim)
358e4b17023SJohn Marino pointer_set_destroy (nontrap);
359e4b17023SJohn Marino /* If the CFG has changed, we should cleanup the CFG. */
360e4b17023SJohn Marino if (cfgchanged && do_store_elim)
361e4b17023SJohn Marino {
362e4b17023SJohn Marino /* In cond-store replacement we have added some loads on edges
363e4b17023SJohn Marino and new VOPS (as we moved the store, and created a load). */
364e4b17023SJohn Marino gsi_commit_edge_inserts ();
365e4b17023SJohn Marino return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
366e4b17023SJohn Marino }
367e4b17023SJohn Marino else if (cfgchanged)
368e4b17023SJohn Marino return TODO_cleanup_cfg;
369e4b17023SJohn Marino return 0;
370e4b17023SJohn Marino }
371e4b17023SJohn Marino
372e4b17023SJohn Marino /* Returns the list of basic blocks in the function in an order that guarantees
373e4b17023SJohn Marino that if a block X has just a single predecessor Y, then Y is after X in the
374e4b17023SJohn Marino ordering. */
375e4b17023SJohn Marino
376e4b17023SJohn Marino basic_block *
blocks_in_phiopt_order(void)377e4b17023SJohn Marino blocks_in_phiopt_order (void)
378e4b17023SJohn Marino {
379e4b17023SJohn Marino basic_block x, y;
380e4b17023SJohn Marino basic_block *order = XNEWVEC (basic_block, n_basic_blocks);
381e4b17023SJohn Marino unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS;
382e4b17023SJohn Marino unsigned np, i;
383e4b17023SJohn Marino sbitmap visited = sbitmap_alloc (last_basic_block);
384e4b17023SJohn Marino
385e4b17023SJohn Marino #define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index))
386e4b17023SJohn Marino #define VISITED_P(BB) (TEST_BIT (visited, (BB)->index))
387e4b17023SJohn Marino
388e4b17023SJohn Marino sbitmap_zero (visited);
389e4b17023SJohn Marino
390e4b17023SJohn Marino MARK_VISITED (ENTRY_BLOCK_PTR);
391e4b17023SJohn Marino FOR_EACH_BB (x)
392e4b17023SJohn Marino {
393e4b17023SJohn Marino if (VISITED_P (x))
394e4b17023SJohn Marino continue;
395e4b17023SJohn Marino
396e4b17023SJohn Marino /* Walk the predecessors of x as long as they have precisely one
397e4b17023SJohn Marino predecessor and add them to the list, so that they get stored
398e4b17023SJohn Marino after x. */
399e4b17023SJohn Marino for (y = x, np = 1;
400e4b17023SJohn Marino single_pred_p (y) && !VISITED_P (single_pred (y));
401e4b17023SJohn Marino y = single_pred (y))
402e4b17023SJohn Marino np++;
403e4b17023SJohn Marino for (y = x, i = n - np;
404e4b17023SJohn Marino single_pred_p (y) && !VISITED_P (single_pred (y));
405e4b17023SJohn Marino y = single_pred (y), i++)
406e4b17023SJohn Marino {
407e4b17023SJohn Marino order[i] = y;
408e4b17023SJohn Marino MARK_VISITED (y);
409e4b17023SJohn Marino }
410e4b17023SJohn Marino order[i] = y;
411e4b17023SJohn Marino MARK_VISITED (y);
412e4b17023SJohn Marino
413e4b17023SJohn Marino gcc_assert (i == n - 1);
414e4b17023SJohn Marino n -= np;
415e4b17023SJohn Marino }
416e4b17023SJohn Marino
417e4b17023SJohn Marino sbitmap_free (visited);
418e4b17023SJohn Marino gcc_assert (n == 0);
419e4b17023SJohn Marino return order;
420e4b17023SJohn Marino
421e4b17023SJohn Marino #undef MARK_VISITED
422e4b17023SJohn Marino #undef VISITED_P
423e4b17023SJohn Marino }
424e4b17023SJohn Marino
425e4b17023SJohn Marino
426e4b17023SJohn Marino /* Return TRUE if block BB has no executable statements, otherwise return
427e4b17023SJohn Marino FALSE. */
428e4b17023SJohn Marino
429e4b17023SJohn Marino bool
empty_block_p(basic_block bb)430e4b17023SJohn Marino empty_block_p (basic_block bb)
431e4b17023SJohn Marino {
432e4b17023SJohn Marino /* BB must have no executable statements. */
433e4b17023SJohn Marino gimple_stmt_iterator gsi = gsi_after_labels (bb);
434e4b17023SJohn Marino if (gsi_end_p (gsi))
435e4b17023SJohn Marino return true;
436e4b17023SJohn Marino if (is_gimple_debug (gsi_stmt (gsi)))
437e4b17023SJohn Marino gsi_next_nondebug (&gsi);
438e4b17023SJohn Marino return gsi_end_p (gsi);
439e4b17023SJohn Marino }
440e4b17023SJohn Marino
441e4b17023SJohn Marino /* Replace PHI node element whose edge is E in block BB with variable NEW.
442e4b17023SJohn Marino Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
443e4b17023SJohn Marino is known to have two edges, one of which must reach BB). */
444e4b17023SJohn Marino
445e4b17023SJohn Marino static void
replace_phi_edge_with_variable(basic_block cond_block,edge e,gimple phi,tree new_tree)446e4b17023SJohn Marino replace_phi_edge_with_variable (basic_block cond_block,
447e4b17023SJohn Marino edge e, gimple phi, tree new_tree)
448e4b17023SJohn Marino {
449e4b17023SJohn Marino basic_block bb = gimple_bb (phi);
450e4b17023SJohn Marino basic_block block_to_remove;
451e4b17023SJohn Marino gimple_stmt_iterator gsi;
452e4b17023SJohn Marino
453e4b17023SJohn Marino /* Change the PHI argument to new. */
454e4b17023SJohn Marino SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new_tree);
455e4b17023SJohn Marino
456e4b17023SJohn Marino /* Remove the empty basic block. */
457e4b17023SJohn Marino if (EDGE_SUCC (cond_block, 0)->dest == bb)
458e4b17023SJohn Marino {
459e4b17023SJohn Marino EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU;
460e4b17023SJohn Marino EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
461e4b17023SJohn Marino EDGE_SUCC (cond_block, 0)->probability = REG_BR_PROB_BASE;
462e4b17023SJohn Marino EDGE_SUCC (cond_block, 0)->count += EDGE_SUCC (cond_block, 1)->count;
463e4b17023SJohn Marino
464e4b17023SJohn Marino block_to_remove = EDGE_SUCC (cond_block, 1)->dest;
465e4b17023SJohn Marino }
466e4b17023SJohn Marino else
467e4b17023SJohn Marino {
468e4b17023SJohn Marino EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU;
469e4b17023SJohn Marino EDGE_SUCC (cond_block, 1)->flags
470e4b17023SJohn Marino &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
471e4b17023SJohn Marino EDGE_SUCC (cond_block, 1)->probability = REG_BR_PROB_BASE;
472e4b17023SJohn Marino EDGE_SUCC (cond_block, 1)->count += EDGE_SUCC (cond_block, 0)->count;
473e4b17023SJohn Marino
474e4b17023SJohn Marino block_to_remove = EDGE_SUCC (cond_block, 0)->dest;
475e4b17023SJohn Marino }
476e4b17023SJohn Marino delete_basic_block (block_to_remove);
477e4b17023SJohn Marino
478e4b17023SJohn Marino /* Eliminate the COND_EXPR at the end of COND_BLOCK. */
479e4b17023SJohn Marino gsi = gsi_last_bb (cond_block);
480e4b17023SJohn Marino gsi_remove (&gsi, true);
481e4b17023SJohn Marino
482e4b17023SJohn Marino if (dump_file && (dump_flags & TDF_DETAILS))
483e4b17023SJohn Marino fprintf (dump_file,
484e4b17023SJohn Marino "COND_EXPR in block %d and PHI in block %d converted to straightline code.\n",
485e4b17023SJohn Marino cond_block->index,
486e4b17023SJohn Marino bb->index);
487e4b17023SJohn Marino }
488e4b17023SJohn Marino
489e4b17023SJohn Marino /* The function conditional_replacement does the main work of doing the
490e4b17023SJohn Marino conditional replacement. Return true if the replacement is done.
491e4b17023SJohn Marino Otherwise return false.
492e4b17023SJohn Marino BB is the basic block where the replacement is going to be done on. ARG0
493e4b17023SJohn Marino is argument 0 from PHI. Likewise for ARG1. */
494e4b17023SJohn Marino
495e4b17023SJohn Marino static bool
conditional_replacement(basic_block cond_bb,basic_block middle_bb,edge e0,edge e1,gimple phi,tree arg0,tree arg1)496e4b17023SJohn Marino conditional_replacement (basic_block cond_bb, basic_block middle_bb,
497e4b17023SJohn Marino edge e0, edge e1, gimple phi,
498e4b17023SJohn Marino tree arg0, tree arg1)
499e4b17023SJohn Marino {
500e4b17023SJohn Marino tree result;
501e4b17023SJohn Marino gimple stmt, new_stmt;
502e4b17023SJohn Marino tree cond;
503e4b17023SJohn Marino gimple_stmt_iterator gsi;
504e4b17023SJohn Marino edge true_edge, false_edge;
505e4b17023SJohn Marino tree new_var, new_var2;
506e4b17023SJohn Marino
507e4b17023SJohn Marino /* FIXME: Gimplification of complex type is too hard for now. */
508e4b17023SJohn Marino if (TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
509e4b17023SJohn Marino || TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE)
510e4b17023SJohn Marino return false;
511e4b17023SJohn Marino
512e4b17023SJohn Marino /* The PHI arguments have the constants 0 and 1, then convert
513e4b17023SJohn Marino it to the conditional. */
514e4b17023SJohn Marino if ((integer_zerop (arg0) && integer_onep (arg1))
515e4b17023SJohn Marino || (integer_zerop (arg1) && integer_onep (arg0)))
516e4b17023SJohn Marino ;
517e4b17023SJohn Marino else
518e4b17023SJohn Marino return false;
519e4b17023SJohn Marino
520e4b17023SJohn Marino if (!empty_block_p (middle_bb))
521e4b17023SJohn Marino return false;
522e4b17023SJohn Marino
523e4b17023SJohn Marino /* At this point we know we have a GIMPLE_COND with two successors.
524e4b17023SJohn Marino One successor is BB, the other successor is an empty block which
525e4b17023SJohn Marino falls through into BB.
526e4b17023SJohn Marino
527e4b17023SJohn Marino There is a single PHI node at the join point (BB) and its arguments
528e4b17023SJohn Marino are constants (0, 1).
529e4b17023SJohn Marino
530e4b17023SJohn Marino So, given the condition COND, and the two PHI arguments, we can
531e4b17023SJohn Marino rewrite this PHI into non-branching code:
532e4b17023SJohn Marino
533e4b17023SJohn Marino dest = (COND) or dest = COND'
534e4b17023SJohn Marino
535e4b17023SJohn Marino We use the condition as-is if the argument associated with the
536e4b17023SJohn Marino true edge has the value one or the argument associated with the
537e4b17023SJohn Marino false edge as the value zero. Note that those conditions are not
538e4b17023SJohn Marino the same since only one of the outgoing edges from the GIMPLE_COND
539e4b17023SJohn Marino will directly reach BB and thus be associated with an argument. */
540e4b17023SJohn Marino
541e4b17023SJohn Marino stmt = last_stmt (cond_bb);
542e4b17023SJohn Marino result = PHI_RESULT (phi);
543e4b17023SJohn Marino
544e4b17023SJohn Marino /* To handle special cases like floating point comparison, it is easier and
545e4b17023SJohn Marino less error-prone to build a tree and gimplify it on the fly though it is
546e4b17023SJohn Marino less efficient. */
547e4b17023SJohn Marino cond = fold_build2_loc (gimple_location (stmt),
548e4b17023SJohn Marino gimple_cond_code (stmt), boolean_type_node,
549e4b17023SJohn Marino gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
550e4b17023SJohn Marino
551e4b17023SJohn Marino /* We need to know which is the true edge and which is the false
552e4b17023SJohn Marino edge so that we know when to invert the condition below. */
553e4b17023SJohn Marino extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
554e4b17023SJohn Marino if ((e0 == true_edge && integer_zerop (arg0))
555e4b17023SJohn Marino || (e0 == false_edge && integer_onep (arg0))
556e4b17023SJohn Marino || (e1 == true_edge && integer_zerop (arg1))
557e4b17023SJohn Marino || (e1 == false_edge && integer_onep (arg1)))
558e4b17023SJohn Marino cond = fold_build1_loc (gimple_location (stmt),
559e4b17023SJohn Marino TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);
560e4b17023SJohn Marino
561e4b17023SJohn Marino /* Insert our new statements at the end of conditional block before the
562e4b17023SJohn Marino COND_STMT. */
563e4b17023SJohn Marino gsi = gsi_for_stmt (stmt);
564e4b17023SJohn Marino new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true,
565e4b17023SJohn Marino GSI_SAME_STMT);
566e4b17023SJohn Marino
567e4b17023SJohn Marino if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var)))
568e4b17023SJohn Marino {
569e4b17023SJohn Marino source_location locus_0, locus_1;
570e4b17023SJohn Marino
571e4b17023SJohn Marino new_var2 = create_tmp_var (TREE_TYPE (result), NULL);
572e4b17023SJohn Marino add_referenced_var (new_var2);
573e4b17023SJohn Marino new_stmt = gimple_build_assign_with_ops (CONVERT_EXPR, new_var2,
574e4b17023SJohn Marino new_var, NULL);
575e4b17023SJohn Marino new_var2 = make_ssa_name (new_var2, new_stmt);
576e4b17023SJohn Marino gimple_assign_set_lhs (new_stmt, new_var2);
577e4b17023SJohn Marino gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
578e4b17023SJohn Marino new_var = new_var2;
579e4b17023SJohn Marino
580e4b17023SJohn Marino /* Set the locus to the first argument, unless is doesn't have one. */
581e4b17023SJohn Marino locus_0 = gimple_phi_arg_location (phi, 0);
582e4b17023SJohn Marino locus_1 = gimple_phi_arg_location (phi, 1);
583e4b17023SJohn Marino if (locus_0 == UNKNOWN_LOCATION)
584e4b17023SJohn Marino locus_0 = locus_1;
585e4b17023SJohn Marino gimple_set_location (new_stmt, locus_0);
586e4b17023SJohn Marino }
587e4b17023SJohn Marino
588e4b17023SJohn Marino replace_phi_edge_with_variable (cond_bb, e1, phi, new_var);
589e4b17023SJohn Marino
590e4b17023SJohn Marino /* Note that we optimized this PHI. */
591e4b17023SJohn Marino return true;
592e4b17023SJohn Marino }
593e4b17023SJohn Marino
594e4b17023SJohn Marino /* Update *ARG which is defined in STMT so that it contains the
595e4b17023SJohn Marino computed value if that seems profitable. Return true if the
596e4b17023SJohn Marino statement is made dead by that rewriting. */
597e4b17023SJohn Marino
598e4b17023SJohn Marino static bool
jump_function_from_stmt(tree * arg,gimple stmt)599e4b17023SJohn Marino jump_function_from_stmt (tree *arg, gimple stmt)
600e4b17023SJohn Marino {
601e4b17023SJohn Marino enum tree_code code = gimple_assign_rhs_code (stmt);
602e4b17023SJohn Marino if (code == ADDR_EXPR)
603e4b17023SJohn Marino {
604e4b17023SJohn Marino /* For arg = &p->i transform it to p, if possible. */
605e4b17023SJohn Marino tree rhs1 = gimple_assign_rhs1 (stmt);
606e4b17023SJohn Marino HOST_WIDE_INT offset;
607e4b17023SJohn Marino tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs1, 0),
608e4b17023SJohn Marino &offset);
609e4b17023SJohn Marino if (tem
610e4b17023SJohn Marino && TREE_CODE (tem) == MEM_REF
611e4b17023SJohn Marino && double_int_zero_p
612e4b17023SJohn Marino (double_int_add (mem_ref_offset (tem),
613e4b17023SJohn Marino shwi_to_double_int (offset))))
614e4b17023SJohn Marino {
615e4b17023SJohn Marino *arg = TREE_OPERAND (tem, 0);
616e4b17023SJohn Marino return true;
617e4b17023SJohn Marino }
618e4b17023SJohn Marino }
619e4b17023SJohn Marino /* TODO: Much like IPA-CP jump-functions we want to handle constant
620e4b17023SJohn Marino additions symbolically here, and we'd need to update the comparison
621e4b17023SJohn Marino code that compares the arg + cst tuples in our caller. For now the
622e4b17023SJohn Marino code above exactly handles the VEC_BASE pattern from vec.h. */
623e4b17023SJohn Marino return false;
624e4b17023SJohn Marino }
625e4b17023SJohn Marino
626e4b17023SJohn Marino /* The function value_replacement does the main work of doing the value
627e4b17023SJohn Marino replacement. Return true if the replacement is done. Otherwise return
628e4b17023SJohn Marino false.
629e4b17023SJohn Marino BB is the basic block where the replacement is going to be done on. ARG0
630e4b17023SJohn Marino is argument 0 from the PHI. Likewise for ARG1. */
631e4b17023SJohn Marino
632e4b17023SJohn Marino static bool
value_replacement(basic_block cond_bb,basic_block middle_bb,edge e0,edge e1,gimple phi,tree arg0,tree arg1)633e4b17023SJohn Marino value_replacement (basic_block cond_bb, basic_block middle_bb,
634e4b17023SJohn Marino edge e0, edge e1, gimple phi,
635e4b17023SJohn Marino tree arg0, tree arg1)
636e4b17023SJohn Marino {
637e4b17023SJohn Marino gimple_stmt_iterator gsi;
638e4b17023SJohn Marino gimple cond;
639e4b17023SJohn Marino edge true_edge, false_edge;
640e4b17023SJohn Marino enum tree_code code;
641e4b17023SJohn Marino
642e4b17023SJohn Marino /* If the type says honor signed zeros we cannot do this
643e4b17023SJohn Marino optimization. */
644e4b17023SJohn Marino if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
645e4b17023SJohn Marino return false;
646e4b17023SJohn Marino
647e4b17023SJohn Marino /* Allow a single statement in MIDDLE_BB that defines one of the PHI
648e4b17023SJohn Marino arguments. */
649e4b17023SJohn Marino gsi = gsi_after_labels (middle_bb);
650e4b17023SJohn Marino if (!gsi_end_p (gsi))
651e4b17023SJohn Marino {
652e4b17023SJohn Marino if (is_gimple_debug (gsi_stmt (gsi)))
653e4b17023SJohn Marino gsi_next_nondebug (&gsi);
654e4b17023SJohn Marino if (!gsi_end_p (gsi))
655e4b17023SJohn Marino {
656e4b17023SJohn Marino gimple stmt = gsi_stmt (gsi);
657e4b17023SJohn Marino tree lhs;
658e4b17023SJohn Marino gsi_next_nondebug (&gsi);
659e4b17023SJohn Marino if (!gsi_end_p (gsi))
660e4b17023SJohn Marino return false;
661e4b17023SJohn Marino if (!is_gimple_assign (stmt))
662e4b17023SJohn Marino return false;
663e4b17023SJohn Marino /* Now try to adjust arg0 or arg1 according to the computation
664e4b17023SJohn Marino in the single statement. */
665e4b17023SJohn Marino lhs = gimple_assign_lhs (stmt);
666e4b17023SJohn Marino if (!((lhs == arg0
667e4b17023SJohn Marino && jump_function_from_stmt (&arg0, stmt))
668e4b17023SJohn Marino || (lhs == arg1
669e4b17023SJohn Marino && jump_function_from_stmt (&arg1, stmt))))
670e4b17023SJohn Marino return false;
671e4b17023SJohn Marino }
672e4b17023SJohn Marino }
673e4b17023SJohn Marino
674e4b17023SJohn Marino cond = last_stmt (cond_bb);
675e4b17023SJohn Marino code = gimple_cond_code (cond);
676e4b17023SJohn Marino
677e4b17023SJohn Marino /* This transformation is only valid for equality comparisons. */
678e4b17023SJohn Marino if (code != NE_EXPR && code != EQ_EXPR)
679e4b17023SJohn Marino return false;
680e4b17023SJohn Marino
681e4b17023SJohn Marino /* We need to know which is the true edge and which is the false
682e4b17023SJohn Marino edge so that we know if have abs or negative abs. */
683e4b17023SJohn Marino extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
684e4b17023SJohn Marino
685e4b17023SJohn Marino /* At this point we know we have a COND_EXPR with two successors.
686e4b17023SJohn Marino One successor is BB, the other successor is an empty block which
687e4b17023SJohn Marino falls through into BB.
688e4b17023SJohn Marino
689e4b17023SJohn Marino The condition for the COND_EXPR is known to be NE_EXPR or EQ_EXPR.
690e4b17023SJohn Marino
691e4b17023SJohn Marino There is a single PHI node at the join point (BB) with two arguments.
692e4b17023SJohn Marino
693e4b17023SJohn Marino We now need to verify that the two arguments in the PHI node match
694e4b17023SJohn Marino the two arguments to the equality comparison. */
695e4b17023SJohn Marino
696e4b17023SJohn Marino if ((operand_equal_for_phi_arg_p (arg0, gimple_cond_lhs (cond))
697e4b17023SJohn Marino && operand_equal_for_phi_arg_p (arg1, gimple_cond_rhs (cond)))
698e4b17023SJohn Marino || (operand_equal_for_phi_arg_p (arg1, gimple_cond_lhs (cond))
699e4b17023SJohn Marino && operand_equal_for_phi_arg_p (arg0, gimple_cond_rhs (cond))))
700e4b17023SJohn Marino {
701e4b17023SJohn Marino edge e;
702e4b17023SJohn Marino tree arg;
703e4b17023SJohn Marino
704e4b17023SJohn Marino /* For NE_EXPR, we want to build an assignment result = arg where
705e4b17023SJohn Marino arg is the PHI argument associated with the true edge. For
706e4b17023SJohn Marino EQ_EXPR we want the PHI argument associated with the false edge. */
707e4b17023SJohn Marino e = (code == NE_EXPR ? true_edge : false_edge);
708e4b17023SJohn Marino
709e4b17023SJohn Marino /* Unfortunately, E may not reach BB (it may instead have gone to
710e4b17023SJohn Marino OTHER_BLOCK). If that is the case, then we want the single outgoing
711e4b17023SJohn Marino edge from OTHER_BLOCK which reaches BB and represents the desired
712e4b17023SJohn Marino path from COND_BLOCK. */
713e4b17023SJohn Marino if (e->dest == middle_bb)
714e4b17023SJohn Marino e = single_succ_edge (e->dest);
715e4b17023SJohn Marino
716e4b17023SJohn Marino /* Now we know the incoming edge to BB that has the argument for the
717e4b17023SJohn Marino RHS of our new assignment statement. */
718e4b17023SJohn Marino if (e0 == e)
719e4b17023SJohn Marino arg = arg0;
720e4b17023SJohn Marino else
721e4b17023SJohn Marino arg = arg1;
722e4b17023SJohn Marino
723e4b17023SJohn Marino replace_phi_edge_with_variable (cond_bb, e1, phi, arg);
724e4b17023SJohn Marino
725e4b17023SJohn Marino /* Note that we optimized this PHI. */
726e4b17023SJohn Marino return true;
727e4b17023SJohn Marino }
728e4b17023SJohn Marino return false;
729e4b17023SJohn Marino }
730e4b17023SJohn Marino
731e4b17023SJohn Marino /* The function minmax_replacement does the main work of doing the minmax
732e4b17023SJohn Marino replacement. Return true if the replacement is done. Otherwise return
733e4b17023SJohn Marino false.
734e4b17023SJohn Marino BB is the basic block where the replacement is going to be done on. ARG0
735e4b17023SJohn Marino is argument 0 from the PHI. Likewise for ARG1. */
736e4b17023SJohn Marino
737e4b17023SJohn Marino static bool
minmax_replacement(basic_block cond_bb,basic_block middle_bb,edge e0,edge e1,gimple phi,tree arg0,tree arg1)738e4b17023SJohn Marino minmax_replacement (basic_block cond_bb, basic_block middle_bb,
739e4b17023SJohn Marino edge e0, edge e1, gimple phi,
740e4b17023SJohn Marino tree arg0, tree arg1)
741e4b17023SJohn Marino {
742e4b17023SJohn Marino tree result, type;
743e4b17023SJohn Marino gimple cond, new_stmt;
744e4b17023SJohn Marino edge true_edge, false_edge;
745e4b17023SJohn Marino enum tree_code cmp, minmax, ass_code;
746e4b17023SJohn Marino tree smaller, larger, arg_true, arg_false;
747e4b17023SJohn Marino gimple_stmt_iterator gsi, gsi_from;
748e4b17023SJohn Marino
749e4b17023SJohn Marino type = TREE_TYPE (PHI_RESULT (phi));
750e4b17023SJohn Marino
751e4b17023SJohn Marino /* The optimization may be unsafe due to NaNs. */
752e4b17023SJohn Marino if (HONOR_NANS (TYPE_MODE (type)))
753e4b17023SJohn Marino return false;
754e4b17023SJohn Marino
755e4b17023SJohn Marino cond = last_stmt (cond_bb);
756e4b17023SJohn Marino cmp = gimple_cond_code (cond);
757e4b17023SJohn Marino
758e4b17023SJohn Marino /* This transformation is only valid for order comparisons. Record which
759e4b17023SJohn Marino operand is smaller/larger if the result of the comparison is true. */
760e4b17023SJohn Marino if (cmp == LT_EXPR || cmp == LE_EXPR)
761e4b17023SJohn Marino {
762e4b17023SJohn Marino smaller = gimple_cond_lhs (cond);
763e4b17023SJohn Marino larger = gimple_cond_rhs (cond);
764e4b17023SJohn Marino }
765e4b17023SJohn Marino else if (cmp == GT_EXPR || cmp == GE_EXPR)
766e4b17023SJohn Marino {
767e4b17023SJohn Marino smaller = gimple_cond_rhs (cond);
768e4b17023SJohn Marino larger = gimple_cond_lhs (cond);
769e4b17023SJohn Marino }
770e4b17023SJohn Marino else
771e4b17023SJohn Marino return false;
772e4b17023SJohn Marino
773e4b17023SJohn Marino /* We need to know which is the true edge and which is the false
774e4b17023SJohn Marino edge so that we know if have abs or negative abs. */
775e4b17023SJohn Marino extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
776e4b17023SJohn Marino
777e4b17023SJohn Marino /* Forward the edges over the middle basic block. */
778e4b17023SJohn Marino if (true_edge->dest == middle_bb)
779e4b17023SJohn Marino true_edge = EDGE_SUCC (true_edge->dest, 0);
780e4b17023SJohn Marino if (false_edge->dest == middle_bb)
781e4b17023SJohn Marino false_edge = EDGE_SUCC (false_edge->dest, 0);
782e4b17023SJohn Marino
783e4b17023SJohn Marino if (true_edge == e0)
784e4b17023SJohn Marino {
785e4b17023SJohn Marino gcc_assert (false_edge == e1);
786e4b17023SJohn Marino arg_true = arg0;
787e4b17023SJohn Marino arg_false = arg1;
788e4b17023SJohn Marino }
789e4b17023SJohn Marino else
790e4b17023SJohn Marino {
791e4b17023SJohn Marino gcc_assert (false_edge == e0);
792e4b17023SJohn Marino gcc_assert (true_edge == e1);
793e4b17023SJohn Marino arg_true = arg1;
794e4b17023SJohn Marino arg_false = arg0;
795e4b17023SJohn Marino }
796e4b17023SJohn Marino
797e4b17023SJohn Marino if (empty_block_p (middle_bb))
798e4b17023SJohn Marino {
799e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (arg_true, smaller)
800e4b17023SJohn Marino && operand_equal_for_phi_arg_p (arg_false, larger))
801e4b17023SJohn Marino {
802e4b17023SJohn Marino /* Case
803e4b17023SJohn Marino
804e4b17023SJohn Marino if (smaller < larger)
805e4b17023SJohn Marino rslt = smaller;
806e4b17023SJohn Marino else
807e4b17023SJohn Marino rslt = larger; */
808e4b17023SJohn Marino minmax = MIN_EXPR;
809e4b17023SJohn Marino }
810e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (arg_false, smaller)
811e4b17023SJohn Marino && operand_equal_for_phi_arg_p (arg_true, larger))
812e4b17023SJohn Marino minmax = MAX_EXPR;
813e4b17023SJohn Marino else
814e4b17023SJohn Marino return false;
815e4b17023SJohn Marino }
816e4b17023SJohn Marino else
817e4b17023SJohn Marino {
818e4b17023SJohn Marino /* Recognize the following case, assuming d <= u:
819e4b17023SJohn Marino
820e4b17023SJohn Marino if (a <= u)
821e4b17023SJohn Marino b = MAX (a, d);
822e4b17023SJohn Marino x = PHI <b, u>
823e4b17023SJohn Marino
824e4b17023SJohn Marino This is equivalent to
825e4b17023SJohn Marino
826e4b17023SJohn Marino b = MAX (a, d);
827e4b17023SJohn Marino x = MIN (b, u); */
828e4b17023SJohn Marino
829e4b17023SJohn Marino gimple assign = last_and_only_stmt (middle_bb);
830e4b17023SJohn Marino tree lhs, op0, op1, bound;
831e4b17023SJohn Marino
832e4b17023SJohn Marino if (!assign
833e4b17023SJohn Marino || gimple_code (assign) != GIMPLE_ASSIGN)
834e4b17023SJohn Marino return false;
835e4b17023SJohn Marino
836e4b17023SJohn Marino lhs = gimple_assign_lhs (assign);
837e4b17023SJohn Marino ass_code = gimple_assign_rhs_code (assign);
838e4b17023SJohn Marino if (ass_code != MAX_EXPR && ass_code != MIN_EXPR)
839e4b17023SJohn Marino return false;
840e4b17023SJohn Marino op0 = gimple_assign_rhs1 (assign);
841e4b17023SJohn Marino op1 = gimple_assign_rhs2 (assign);
842e4b17023SJohn Marino
843e4b17023SJohn Marino if (true_edge->src == middle_bb)
844e4b17023SJohn Marino {
845e4b17023SJohn Marino /* We got here if the condition is true, i.e., SMALLER < LARGER. */
846e4b17023SJohn Marino if (!operand_equal_for_phi_arg_p (lhs, arg_true))
847e4b17023SJohn Marino return false;
848e4b17023SJohn Marino
849e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (arg_false, larger))
850e4b17023SJohn Marino {
851e4b17023SJohn Marino /* Case
852e4b17023SJohn Marino
853e4b17023SJohn Marino if (smaller < larger)
854e4b17023SJohn Marino {
855e4b17023SJohn Marino r' = MAX_EXPR (smaller, bound)
856e4b17023SJohn Marino }
857e4b17023SJohn Marino r = PHI <r', larger> --> to be turned to MIN_EXPR. */
858e4b17023SJohn Marino if (ass_code != MAX_EXPR)
859e4b17023SJohn Marino return false;
860e4b17023SJohn Marino
861e4b17023SJohn Marino minmax = MIN_EXPR;
862e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (op0, smaller))
863e4b17023SJohn Marino bound = op1;
864e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (op1, smaller))
865e4b17023SJohn Marino bound = op0;
866e4b17023SJohn Marino else
867e4b17023SJohn Marino return false;
868e4b17023SJohn Marino
869e4b17023SJohn Marino /* We need BOUND <= LARGER. */
870e4b17023SJohn Marino if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
871e4b17023SJohn Marino bound, larger)))
872e4b17023SJohn Marino return false;
873e4b17023SJohn Marino }
874e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (arg_false, smaller))
875e4b17023SJohn Marino {
876e4b17023SJohn Marino /* Case
877e4b17023SJohn Marino
878e4b17023SJohn Marino if (smaller < larger)
879e4b17023SJohn Marino {
880e4b17023SJohn Marino r' = MIN_EXPR (larger, bound)
881e4b17023SJohn Marino }
882e4b17023SJohn Marino r = PHI <r', smaller> --> to be turned to MAX_EXPR. */
883e4b17023SJohn Marino if (ass_code != MIN_EXPR)
884e4b17023SJohn Marino return false;
885e4b17023SJohn Marino
886e4b17023SJohn Marino minmax = MAX_EXPR;
887e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (op0, larger))
888e4b17023SJohn Marino bound = op1;
889e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (op1, larger))
890e4b17023SJohn Marino bound = op0;
891e4b17023SJohn Marino else
892e4b17023SJohn Marino return false;
893e4b17023SJohn Marino
894e4b17023SJohn Marino /* We need BOUND >= SMALLER. */
895e4b17023SJohn Marino if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
896e4b17023SJohn Marino bound, smaller)))
897e4b17023SJohn Marino return false;
898e4b17023SJohn Marino }
899e4b17023SJohn Marino else
900e4b17023SJohn Marino return false;
901e4b17023SJohn Marino }
902e4b17023SJohn Marino else
903e4b17023SJohn Marino {
904e4b17023SJohn Marino /* We got here if the condition is false, i.e., SMALLER > LARGER. */
905e4b17023SJohn Marino if (!operand_equal_for_phi_arg_p (lhs, arg_false))
906e4b17023SJohn Marino return false;
907e4b17023SJohn Marino
908e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (arg_true, larger))
909e4b17023SJohn Marino {
910e4b17023SJohn Marino /* Case
911e4b17023SJohn Marino
912e4b17023SJohn Marino if (smaller > larger)
913e4b17023SJohn Marino {
914e4b17023SJohn Marino r' = MIN_EXPR (smaller, bound)
915e4b17023SJohn Marino }
916e4b17023SJohn Marino r = PHI <r', larger> --> to be turned to MAX_EXPR. */
917e4b17023SJohn Marino if (ass_code != MIN_EXPR)
918e4b17023SJohn Marino return false;
919e4b17023SJohn Marino
920e4b17023SJohn Marino minmax = MAX_EXPR;
921e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (op0, smaller))
922e4b17023SJohn Marino bound = op1;
923e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (op1, smaller))
924e4b17023SJohn Marino bound = op0;
925e4b17023SJohn Marino else
926e4b17023SJohn Marino return false;
927e4b17023SJohn Marino
928e4b17023SJohn Marino /* We need BOUND >= LARGER. */
929e4b17023SJohn Marino if (!integer_nonzerop (fold_build2 (GE_EXPR, boolean_type_node,
930e4b17023SJohn Marino bound, larger)))
931e4b17023SJohn Marino return false;
932e4b17023SJohn Marino }
933e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (arg_true, smaller))
934e4b17023SJohn Marino {
935e4b17023SJohn Marino /* Case
936e4b17023SJohn Marino
937e4b17023SJohn Marino if (smaller > larger)
938e4b17023SJohn Marino {
939e4b17023SJohn Marino r' = MAX_EXPR (larger, bound)
940e4b17023SJohn Marino }
941e4b17023SJohn Marino r = PHI <r', smaller> --> to be turned to MIN_EXPR. */
942e4b17023SJohn Marino if (ass_code != MAX_EXPR)
943e4b17023SJohn Marino return false;
944e4b17023SJohn Marino
945e4b17023SJohn Marino minmax = MIN_EXPR;
946e4b17023SJohn Marino if (operand_equal_for_phi_arg_p (op0, larger))
947e4b17023SJohn Marino bound = op1;
948e4b17023SJohn Marino else if (operand_equal_for_phi_arg_p (op1, larger))
949e4b17023SJohn Marino bound = op0;
950e4b17023SJohn Marino else
951e4b17023SJohn Marino return false;
952e4b17023SJohn Marino
953e4b17023SJohn Marino /* We need BOUND <= SMALLER. */
954e4b17023SJohn Marino if (!integer_nonzerop (fold_build2 (LE_EXPR, boolean_type_node,
955e4b17023SJohn Marino bound, smaller)))
956e4b17023SJohn Marino return false;
957e4b17023SJohn Marino }
958e4b17023SJohn Marino else
959e4b17023SJohn Marino return false;
960e4b17023SJohn Marino }
961e4b17023SJohn Marino
962e4b17023SJohn Marino /* Move the statement from the middle block. */
963e4b17023SJohn Marino gsi = gsi_last_bb (cond_bb);
964e4b17023SJohn Marino gsi_from = gsi_last_nondebug_bb (middle_bb);
965e4b17023SJohn Marino gsi_move_before (&gsi_from, &gsi);
966e4b17023SJohn Marino }
967e4b17023SJohn Marino
968e4b17023SJohn Marino /* Emit the statement to compute min/max. */
969e4b17023SJohn Marino result = duplicate_ssa_name (PHI_RESULT (phi), NULL);
970e4b17023SJohn Marino new_stmt = gimple_build_assign_with_ops (minmax, result, arg0, arg1);
971e4b17023SJohn Marino gsi = gsi_last_bb (cond_bb);
972e4b17023SJohn Marino gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
973e4b17023SJohn Marino
974e4b17023SJohn Marino replace_phi_edge_with_variable (cond_bb, e1, phi, result);
975e4b17023SJohn Marino return true;
976e4b17023SJohn Marino }
977e4b17023SJohn Marino
978e4b17023SJohn Marino /* The function absolute_replacement does the main work of doing the absolute
979e4b17023SJohn Marino replacement. Return true if the replacement is done. Otherwise return
980e4b17023SJohn Marino false.
981e4b17023SJohn Marino bb is the basic block where the replacement is going to be done on. arg0
982e4b17023SJohn Marino is argument 0 from the phi. Likewise for arg1. */
983e4b17023SJohn Marino
984e4b17023SJohn Marino static bool
abs_replacement(basic_block cond_bb,basic_block middle_bb,edge e0 ATTRIBUTE_UNUSED,edge e1,gimple phi,tree arg0,tree arg1)985e4b17023SJohn Marino abs_replacement (basic_block cond_bb, basic_block middle_bb,
986e4b17023SJohn Marino edge e0 ATTRIBUTE_UNUSED, edge e1,
987e4b17023SJohn Marino gimple phi, tree arg0, tree arg1)
988e4b17023SJohn Marino {
989e4b17023SJohn Marino tree result;
990e4b17023SJohn Marino gimple new_stmt, cond;
991e4b17023SJohn Marino gimple_stmt_iterator gsi;
992e4b17023SJohn Marino edge true_edge, false_edge;
993e4b17023SJohn Marino gimple assign;
994e4b17023SJohn Marino edge e;
995e4b17023SJohn Marino tree rhs, lhs;
996e4b17023SJohn Marino bool negate;
997e4b17023SJohn Marino enum tree_code cond_code;
998e4b17023SJohn Marino
999e4b17023SJohn Marino /* If the type says honor signed zeros we cannot do this
1000e4b17023SJohn Marino optimization. */
1001e4b17023SJohn Marino if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
1002e4b17023SJohn Marino return false;
1003e4b17023SJohn Marino
1004e4b17023SJohn Marino /* OTHER_BLOCK must have only one executable statement which must have the
1005e4b17023SJohn Marino form arg0 = -arg1 or arg1 = -arg0. */
1006e4b17023SJohn Marino
1007e4b17023SJohn Marino assign = last_and_only_stmt (middle_bb);
1008e4b17023SJohn Marino /* If we did not find the proper negation assignment, then we can not
1009e4b17023SJohn Marino optimize. */
1010e4b17023SJohn Marino if (assign == NULL)
1011e4b17023SJohn Marino return false;
1012e4b17023SJohn Marino
1013e4b17023SJohn Marino /* If we got here, then we have found the only executable statement
1014e4b17023SJohn Marino in OTHER_BLOCK. If it is anything other than arg = -arg1 or
1015e4b17023SJohn Marino arg1 = -arg0, then we can not optimize. */
1016e4b17023SJohn Marino if (gimple_code (assign) != GIMPLE_ASSIGN)
1017e4b17023SJohn Marino return false;
1018e4b17023SJohn Marino
1019e4b17023SJohn Marino lhs = gimple_assign_lhs (assign);
1020e4b17023SJohn Marino
1021e4b17023SJohn Marino if (gimple_assign_rhs_code (assign) != NEGATE_EXPR)
1022e4b17023SJohn Marino return false;
1023e4b17023SJohn Marino
1024e4b17023SJohn Marino rhs = gimple_assign_rhs1 (assign);
1025e4b17023SJohn Marino
1026e4b17023SJohn Marino /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */
1027e4b17023SJohn Marino if (!(lhs == arg0 && rhs == arg1)
1028e4b17023SJohn Marino && !(lhs == arg1 && rhs == arg0))
1029e4b17023SJohn Marino return false;
1030e4b17023SJohn Marino
1031e4b17023SJohn Marino cond = last_stmt (cond_bb);
1032e4b17023SJohn Marino result = PHI_RESULT (phi);
1033e4b17023SJohn Marino
1034e4b17023SJohn Marino /* Only relationals comparing arg[01] against zero are interesting. */
1035e4b17023SJohn Marino cond_code = gimple_cond_code (cond);
1036e4b17023SJohn Marino if (cond_code != GT_EXPR && cond_code != GE_EXPR
1037e4b17023SJohn Marino && cond_code != LT_EXPR && cond_code != LE_EXPR)
1038e4b17023SJohn Marino return false;
1039e4b17023SJohn Marino
1040e4b17023SJohn Marino /* Make sure the conditional is arg[01] OP y. */
1041e4b17023SJohn Marino if (gimple_cond_lhs (cond) != rhs)
1042e4b17023SJohn Marino return false;
1043e4b17023SJohn Marino
1044e4b17023SJohn Marino if (FLOAT_TYPE_P (TREE_TYPE (gimple_cond_rhs (cond)))
1045e4b17023SJohn Marino ? real_zerop (gimple_cond_rhs (cond))
1046e4b17023SJohn Marino : integer_zerop (gimple_cond_rhs (cond)))
1047e4b17023SJohn Marino ;
1048e4b17023SJohn Marino else
1049e4b17023SJohn Marino return false;
1050e4b17023SJohn Marino
1051e4b17023SJohn Marino /* We need to know which is the true edge and which is the false
1052e4b17023SJohn Marino edge so that we know if have abs or negative abs. */
1053e4b17023SJohn Marino extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
1054e4b17023SJohn Marino
1055e4b17023SJohn Marino /* For GT_EXPR/GE_EXPR, if the true edge goes to OTHER_BLOCK, then we
1056e4b17023SJohn Marino will need to negate the result. Similarly for LT_EXPR/LE_EXPR if
1057e4b17023SJohn Marino the false edge goes to OTHER_BLOCK. */
1058e4b17023SJohn Marino if (cond_code == GT_EXPR || cond_code == GE_EXPR)
1059e4b17023SJohn Marino e = true_edge;
1060e4b17023SJohn Marino else
1061e4b17023SJohn Marino e = false_edge;
1062e4b17023SJohn Marino
1063e4b17023SJohn Marino if (e->dest == middle_bb)
1064e4b17023SJohn Marino negate = true;
1065e4b17023SJohn Marino else
1066e4b17023SJohn Marino negate = false;
1067e4b17023SJohn Marino
1068e4b17023SJohn Marino result = duplicate_ssa_name (result, NULL);
1069e4b17023SJohn Marino
1070e4b17023SJohn Marino if (negate)
1071e4b17023SJohn Marino {
1072e4b17023SJohn Marino tree tmp = create_tmp_var (TREE_TYPE (result), NULL);
1073e4b17023SJohn Marino add_referenced_var (tmp);
1074e4b17023SJohn Marino lhs = make_ssa_name (tmp, NULL);
1075e4b17023SJohn Marino }
1076e4b17023SJohn Marino else
1077e4b17023SJohn Marino lhs = result;
1078e4b17023SJohn Marino
1079e4b17023SJohn Marino /* Build the modify expression with abs expression. */
1080e4b17023SJohn Marino new_stmt = gimple_build_assign_with_ops (ABS_EXPR, lhs, rhs, NULL);
1081e4b17023SJohn Marino
1082e4b17023SJohn Marino gsi = gsi_last_bb (cond_bb);
1083e4b17023SJohn Marino gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
1084e4b17023SJohn Marino
1085e4b17023SJohn Marino if (negate)
1086e4b17023SJohn Marino {
1087e4b17023SJohn Marino /* Get the right GSI. We want to insert after the recently
1088e4b17023SJohn Marino added ABS_EXPR statement (which we know is the first statement
1089e4b17023SJohn Marino in the block. */
1090e4b17023SJohn Marino new_stmt = gimple_build_assign_with_ops (NEGATE_EXPR, result, lhs, NULL);
1091e4b17023SJohn Marino
1092e4b17023SJohn Marino gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
1093e4b17023SJohn Marino }
1094e4b17023SJohn Marino
1095e4b17023SJohn Marino replace_phi_edge_with_variable (cond_bb, e1, phi, result);
1096e4b17023SJohn Marino
1097e4b17023SJohn Marino /* Note that we optimized this PHI. */
1098e4b17023SJohn Marino return true;
1099e4b17023SJohn Marino }
1100e4b17023SJohn Marino
1101e4b17023SJohn Marino /* Auxiliary functions to determine the set of memory accesses which
1102e4b17023SJohn Marino can't trap because they are preceded by accesses to the same memory
1103e4b17023SJohn Marino portion. We do that for MEM_REFs, so we only need to track
1104e4b17023SJohn Marino the SSA_NAME of the pointer indirectly referenced. The algorithm
1105e4b17023SJohn Marino simply is a walk over all instructions in dominator order. When
1106e4b17023SJohn Marino we see an MEM_REF we determine if we've already seen a same
1107e4b17023SJohn Marino ref anywhere up to the root of the dominator tree. If we do the
1108e4b17023SJohn Marino current access can't trap. If we don't see any dominating access
1109e4b17023SJohn Marino the current access might trap, but might also make later accesses
1110e4b17023SJohn Marino non-trapping, so we remember it. We need to be careful with loads
1111e4b17023SJohn Marino or stores, for instance a load might not trap, while a store would,
1112e4b17023SJohn Marino so if we see a dominating read access this doesn't mean that a later
1113e4b17023SJohn Marino write access would not trap. Hence we also need to differentiate the
1114e4b17023SJohn Marino type of access(es) seen.
1115e4b17023SJohn Marino
1116e4b17023SJohn Marino ??? We currently are very conservative and assume that a load might
1117e4b17023SJohn Marino trap even if a store doesn't (write-only memory). This probably is
1118e4b17023SJohn Marino overly conservative. */
1119e4b17023SJohn Marino
1120e4b17023SJohn Marino /* A hash-table of SSA_NAMEs, and in which basic block an MEM_REF
1121e4b17023SJohn Marino through it was seen, which would constitute a no-trap region for
1122e4b17023SJohn Marino same accesses. */
1123e4b17023SJohn Marino struct name_to_bb
1124e4b17023SJohn Marino {
1125e4b17023SJohn Marino unsigned int ssa_name_ver;
1126e4b17023SJohn Marino bool store;
1127e4b17023SJohn Marino HOST_WIDE_INT offset, size;
1128e4b17023SJohn Marino basic_block bb;
1129e4b17023SJohn Marino };
1130e4b17023SJohn Marino
1131e4b17023SJohn Marino /* The hash table for remembering what we've seen. */
1132e4b17023SJohn Marino static htab_t seen_ssa_names;
1133e4b17023SJohn Marino
1134e4b17023SJohn Marino /* The set of MEM_REFs which can't trap. */
1135e4b17023SJohn Marino static struct pointer_set_t *nontrap_set;
1136e4b17023SJohn Marino
1137e4b17023SJohn Marino /* The hash function. */
1138e4b17023SJohn Marino static hashval_t
name_to_bb_hash(const void * p)1139e4b17023SJohn Marino name_to_bb_hash (const void *p)
1140e4b17023SJohn Marino {
1141e4b17023SJohn Marino const struct name_to_bb *n = (const struct name_to_bb *) p;
1142e4b17023SJohn Marino return n->ssa_name_ver ^ (((hashval_t) n->store) << 31)
1143e4b17023SJohn Marino ^ (n->offset << 6) ^ (n->size << 3);
1144e4b17023SJohn Marino }
1145e4b17023SJohn Marino
1146e4b17023SJohn Marino /* The equality function of *P1 and *P2. */
1147e4b17023SJohn Marino static int
name_to_bb_eq(const void * p1,const void * p2)1148e4b17023SJohn Marino name_to_bb_eq (const void *p1, const void *p2)
1149e4b17023SJohn Marino {
1150e4b17023SJohn Marino const struct name_to_bb *n1 = (const struct name_to_bb *)p1;
1151e4b17023SJohn Marino const struct name_to_bb *n2 = (const struct name_to_bb *)p2;
1152e4b17023SJohn Marino
1153e4b17023SJohn Marino return n1->ssa_name_ver == n2->ssa_name_ver
1154e4b17023SJohn Marino && n1->store == n2->store
1155e4b17023SJohn Marino && n1->offset == n2->offset
1156e4b17023SJohn Marino && n1->size == n2->size;
1157e4b17023SJohn Marino }
1158e4b17023SJohn Marino
1159e4b17023SJohn Marino /* We see the expression EXP in basic block BB. If it's an interesting
1160e4b17023SJohn Marino expression (an MEM_REF through an SSA_NAME) possibly insert the
1161e4b17023SJohn Marino expression into the set NONTRAP or the hash table of seen expressions.
1162e4b17023SJohn Marino STORE is true if this expression is on the LHS, otherwise it's on
1163e4b17023SJohn Marino the RHS. */
1164e4b17023SJohn Marino static void
add_or_mark_expr(basic_block bb,tree exp,struct pointer_set_t * nontrap,bool store)1165e4b17023SJohn Marino add_or_mark_expr (basic_block bb, tree exp,
1166e4b17023SJohn Marino struct pointer_set_t *nontrap, bool store)
1167e4b17023SJohn Marino {
1168e4b17023SJohn Marino HOST_WIDE_INT size;
1169e4b17023SJohn Marino
1170e4b17023SJohn Marino if (TREE_CODE (exp) == MEM_REF
1171e4b17023SJohn Marino && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME
1172e4b17023SJohn Marino && host_integerp (TREE_OPERAND (exp, 1), 0)
1173e4b17023SJohn Marino && (size = int_size_in_bytes (TREE_TYPE (exp))) > 0)
1174e4b17023SJohn Marino {
1175e4b17023SJohn Marino tree name = TREE_OPERAND (exp, 0);
1176e4b17023SJohn Marino struct name_to_bb map;
1177e4b17023SJohn Marino void **slot;
1178e4b17023SJohn Marino struct name_to_bb *n2bb;
1179e4b17023SJohn Marino basic_block found_bb = 0;
1180e4b17023SJohn Marino
1181e4b17023SJohn Marino /* Try to find the last seen MEM_REF through the same
1182e4b17023SJohn Marino SSA_NAME, which can trap. */
1183e4b17023SJohn Marino map.ssa_name_ver = SSA_NAME_VERSION (name);
1184e4b17023SJohn Marino map.bb = 0;
1185e4b17023SJohn Marino map.store = store;
1186e4b17023SJohn Marino map.offset = tree_low_cst (TREE_OPERAND (exp, 1), 0);
1187e4b17023SJohn Marino map.size = size;
1188e4b17023SJohn Marino
1189e4b17023SJohn Marino slot = htab_find_slot (seen_ssa_names, &map, INSERT);
1190e4b17023SJohn Marino n2bb = (struct name_to_bb *) *slot;
1191e4b17023SJohn Marino if (n2bb)
1192e4b17023SJohn Marino found_bb = n2bb->bb;
1193e4b17023SJohn Marino
1194e4b17023SJohn Marino /* If we've found a trapping MEM_REF, _and_ it dominates EXP
1195e4b17023SJohn Marino (it's in a basic block on the path from us to the dominator root)
1196e4b17023SJohn Marino then we can't trap. */
1197e4b17023SJohn Marino if (found_bb && found_bb->aux == (void *)1)
1198e4b17023SJohn Marino {
1199e4b17023SJohn Marino pointer_set_insert (nontrap, exp);
1200e4b17023SJohn Marino }
1201e4b17023SJohn Marino else
1202e4b17023SJohn Marino {
1203e4b17023SJohn Marino /* EXP might trap, so insert it into the hash table. */
1204e4b17023SJohn Marino if (n2bb)
1205e4b17023SJohn Marino {
1206e4b17023SJohn Marino n2bb->bb = bb;
1207e4b17023SJohn Marino }
1208e4b17023SJohn Marino else
1209e4b17023SJohn Marino {
1210e4b17023SJohn Marino n2bb = XNEW (struct name_to_bb);
1211e4b17023SJohn Marino n2bb->ssa_name_ver = SSA_NAME_VERSION (name);
1212e4b17023SJohn Marino n2bb->bb = bb;
1213e4b17023SJohn Marino n2bb->store = store;
1214e4b17023SJohn Marino n2bb->offset = map.offset;
1215e4b17023SJohn Marino n2bb->size = size;
1216e4b17023SJohn Marino *slot = n2bb;
1217e4b17023SJohn Marino }
1218e4b17023SJohn Marino }
1219e4b17023SJohn Marino }
1220e4b17023SJohn Marino }
1221e4b17023SJohn Marino
1222e4b17023SJohn Marino /* Called by walk_dominator_tree, when entering the block BB. */
1223e4b17023SJohn Marino static void
nt_init_block(struct dom_walk_data * data ATTRIBUTE_UNUSED,basic_block bb)1224e4b17023SJohn Marino nt_init_block (struct dom_walk_data *data ATTRIBUTE_UNUSED, basic_block bb)
1225e4b17023SJohn Marino {
1226e4b17023SJohn Marino gimple_stmt_iterator gsi;
1227e4b17023SJohn Marino /* Mark this BB as being on the path to dominator root. */
1228e4b17023SJohn Marino bb->aux = (void*)1;
1229e4b17023SJohn Marino
1230e4b17023SJohn Marino /* And walk the statements in order. */
1231e4b17023SJohn Marino for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1232e4b17023SJohn Marino {
1233e4b17023SJohn Marino gimple stmt = gsi_stmt (gsi);
1234e4b17023SJohn Marino
1235*5ce9237cSJohn Marino if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt))
1236e4b17023SJohn Marino {
1237e4b17023SJohn Marino add_or_mark_expr (bb, gimple_assign_lhs (stmt), nontrap_set, true);
1238e4b17023SJohn Marino add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), nontrap_set, false);
1239e4b17023SJohn Marino }
1240e4b17023SJohn Marino }
1241e4b17023SJohn Marino }
1242e4b17023SJohn Marino
1243e4b17023SJohn Marino /* Called by walk_dominator_tree, when basic block BB is exited. */
1244e4b17023SJohn Marino static void
nt_fini_block(struct dom_walk_data * data ATTRIBUTE_UNUSED,basic_block bb)1245e4b17023SJohn Marino nt_fini_block (struct dom_walk_data *data ATTRIBUTE_UNUSED, basic_block bb)
1246e4b17023SJohn Marino {
1247e4b17023SJohn Marino /* This BB isn't on the path to dominator root anymore. */
1248e4b17023SJohn Marino bb->aux = NULL;
1249e4b17023SJohn Marino }
1250e4b17023SJohn Marino
1251e4b17023SJohn Marino /* This is the entry point of gathering non trapping memory accesses.
1252e4b17023SJohn Marino It will do a dominator walk over the whole function, and it will
1253e4b17023SJohn Marino make use of the bb->aux pointers. It returns a set of trees
1254e4b17023SJohn Marino (the MEM_REFs itself) which can't trap. */
1255e4b17023SJohn Marino static struct pointer_set_t *
get_non_trapping(void)1256e4b17023SJohn Marino get_non_trapping (void)
1257e4b17023SJohn Marino {
1258e4b17023SJohn Marino struct pointer_set_t *nontrap;
1259e4b17023SJohn Marino struct dom_walk_data walk_data;
1260e4b17023SJohn Marino
1261e4b17023SJohn Marino nontrap = pointer_set_create ();
1262e4b17023SJohn Marino seen_ssa_names = htab_create (128, name_to_bb_hash, name_to_bb_eq,
1263e4b17023SJohn Marino free);
1264e4b17023SJohn Marino /* We're going to do a dominator walk, so ensure that we have
1265e4b17023SJohn Marino dominance information. */
1266e4b17023SJohn Marino calculate_dominance_info (CDI_DOMINATORS);
1267e4b17023SJohn Marino
1268e4b17023SJohn Marino /* Setup callbacks for the generic dominator tree walker. */
1269e4b17023SJohn Marino nontrap_set = nontrap;
1270e4b17023SJohn Marino walk_data.dom_direction = CDI_DOMINATORS;
1271e4b17023SJohn Marino walk_data.initialize_block_local_data = NULL;
1272e4b17023SJohn Marino walk_data.before_dom_children = nt_init_block;
1273e4b17023SJohn Marino walk_data.after_dom_children = nt_fini_block;
1274e4b17023SJohn Marino walk_data.global_data = NULL;
1275e4b17023SJohn Marino walk_data.block_local_data_size = 0;
1276e4b17023SJohn Marino
1277e4b17023SJohn Marino init_walk_dominator_tree (&walk_data);
1278e4b17023SJohn Marino walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
1279e4b17023SJohn Marino fini_walk_dominator_tree (&walk_data);
1280e4b17023SJohn Marino htab_delete (seen_ssa_names);
1281e4b17023SJohn Marino
1282e4b17023SJohn Marino return nontrap;
1283e4b17023SJohn Marino }
1284e4b17023SJohn Marino
1285e4b17023SJohn Marino /* Do the main work of conditional store replacement. We already know
1286e4b17023SJohn Marino that the recognized pattern looks like so:
1287e4b17023SJohn Marino
1288e4b17023SJohn Marino split:
1289e4b17023SJohn Marino if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
1290e4b17023SJohn Marino MIDDLE_BB:
1291e4b17023SJohn Marino something
1292e4b17023SJohn Marino fallthrough (edge E0)
1293e4b17023SJohn Marino JOIN_BB:
1294e4b17023SJohn Marino some more
1295e4b17023SJohn Marino
1296e4b17023SJohn Marino We check that MIDDLE_BB contains only one store, that that store
1297e4b17023SJohn Marino doesn't trap (not via NOTRAP, but via checking if an access to the same
1298e4b17023SJohn Marino memory location dominates us) and that the store has a "simple" RHS. */
1299e4b17023SJohn Marino
1300e4b17023SJohn Marino static bool
cond_store_replacement(basic_block middle_bb,basic_block join_bb,edge e0,edge e1,struct pointer_set_t * nontrap)1301e4b17023SJohn Marino cond_store_replacement (basic_block middle_bb, basic_block join_bb,
1302e4b17023SJohn Marino edge e0, edge e1, struct pointer_set_t *nontrap)
1303e4b17023SJohn Marino {
1304e4b17023SJohn Marino gimple assign = last_and_only_stmt (middle_bb);
1305e4b17023SJohn Marino tree lhs, rhs, name;
1306e4b17023SJohn Marino gimple newphi, new_stmt;
1307e4b17023SJohn Marino gimple_stmt_iterator gsi;
1308e4b17023SJohn Marino source_location locus;
1309e4b17023SJohn Marino
1310e4b17023SJohn Marino /* Check if middle_bb contains of only one store. */
1311e4b17023SJohn Marino if (!assign
1312*5ce9237cSJohn Marino || !gimple_assign_single_p (assign)
1313*5ce9237cSJohn Marino || gimple_has_volatile_ops (assign))
1314e4b17023SJohn Marino return false;
1315e4b17023SJohn Marino
1316e4b17023SJohn Marino locus = gimple_location (assign);
1317e4b17023SJohn Marino lhs = gimple_assign_lhs (assign);
1318e4b17023SJohn Marino rhs = gimple_assign_rhs1 (assign);
1319e4b17023SJohn Marino if (TREE_CODE (lhs) != MEM_REF
1320e4b17023SJohn Marino || TREE_CODE (TREE_OPERAND (lhs, 0)) != SSA_NAME
1321e4b17023SJohn Marino || !is_gimple_reg_type (TREE_TYPE (lhs)))
1322e4b17023SJohn Marino return false;
1323e4b17023SJohn Marino
1324e4b17023SJohn Marino /* Prove that we can move the store down. We could also check
1325e4b17023SJohn Marino TREE_THIS_NOTRAP here, but in that case we also could move stores,
1326e4b17023SJohn Marino whose value is not available readily, which we want to avoid. */
1327e4b17023SJohn Marino if (!pointer_set_contains (nontrap, lhs))
1328e4b17023SJohn Marino return false;
1329e4b17023SJohn Marino
1330e4b17023SJohn Marino /* Now we've checked the constraints, so do the transformation:
1331e4b17023SJohn Marino 1) Remove the single store. */
1332e4b17023SJohn Marino gsi = gsi_for_stmt (assign);
1333e4b17023SJohn Marino unlink_stmt_vdef (assign);
1334e4b17023SJohn Marino gsi_remove (&gsi, true);
1335e4b17023SJohn Marino release_defs (assign);
1336e4b17023SJohn Marino
1337e4b17023SJohn Marino /* 2) Create a temporary where we can store the old content
1338e4b17023SJohn Marino of the memory touched by the store, if we need to. */
1339e4b17023SJohn Marino if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
1340e4b17023SJohn Marino condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
1341e4b17023SJohn Marino add_referenced_var (condstoretemp);
1342e4b17023SJohn Marino
1343e4b17023SJohn Marino /* 3) Insert a load from the memory of the store to the temporary
1344e4b17023SJohn Marino on the edge which did not contain the store. */
1345e4b17023SJohn Marino lhs = unshare_expr (lhs);
1346e4b17023SJohn Marino new_stmt = gimple_build_assign (condstoretemp, lhs);
1347e4b17023SJohn Marino name = make_ssa_name (condstoretemp, new_stmt);
1348e4b17023SJohn Marino gimple_assign_set_lhs (new_stmt, name);
1349e4b17023SJohn Marino gimple_set_location (new_stmt, locus);
1350e4b17023SJohn Marino gsi_insert_on_edge (e1, new_stmt);
1351e4b17023SJohn Marino
1352e4b17023SJohn Marino /* 4) Create a PHI node at the join block, with one argument
1353e4b17023SJohn Marino holding the old RHS, and the other holding the temporary
1354e4b17023SJohn Marino where we stored the old memory contents. */
1355e4b17023SJohn Marino newphi = create_phi_node (condstoretemp, join_bb);
1356e4b17023SJohn Marino add_phi_arg (newphi, rhs, e0, locus);
1357e4b17023SJohn Marino add_phi_arg (newphi, name, e1, locus);
1358e4b17023SJohn Marino
1359e4b17023SJohn Marino lhs = unshare_expr (lhs);
1360e4b17023SJohn Marino new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
1361e4b17023SJohn Marino
1362e4b17023SJohn Marino /* 5) Insert that PHI node. */
1363e4b17023SJohn Marino gsi = gsi_after_labels (join_bb);
1364e4b17023SJohn Marino if (gsi_end_p (gsi))
1365e4b17023SJohn Marino {
1366e4b17023SJohn Marino gsi = gsi_last_bb (join_bb);
1367e4b17023SJohn Marino gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
1368e4b17023SJohn Marino }
1369e4b17023SJohn Marino else
1370e4b17023SJohn Marino gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
1371e4b17023SJohn Marino
1372e4b17023SJohn Marino return true;
1373e4b17023SJohn Marino }
1374e4b17023SJohn Marino
1375e4b17023SJohn Marino /* Do the main work of conditional store replacement. */
1376e4b17023SJohn Marino
1377e4b17023SJohn Marino static bool
cond_if_else_store_replacement_1(basic_block then_bb,basic_block else_bb,basic_block join_bb,gimple then_assign,gimple else_assign)1378e4b17023SJohn Marino cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
1379e4b17023SJohn Marino basic_block join_bb, gimple then_assign,
1380e4b17023SJohn Marino gimple else_assign)
1381e4b17023SJohn Marino {
1382e4b17023SJohn Marino tree lhs_base, lhs, then_rhs, else_rhs;
1383e4b17023SJohn Marino source_location then_locus, else_locus;
1384e4b17023SJohn Marino gimple_stmt_iterator gsi;
1385e4b17023SJohn Marino gimple newphi, new_stmt;
1386e4b17023SJohn Marino
1387e4b17023SJohn Marino if (then_assign == NULL
1388e4b17023SJohn Marino || !gimple_assign_single_p (then_assign)
1389e4b17023SJohn Marino || gimple_clobber_p (then_assign)
1390*5ce9237cSJohn Marino || gimple_has_volatile_ops (then_assign)
1391e4b17023SJohn Marino || else_assign == NULL
1392e4b17023SJohn Marino || !gimple_assign_single_p (else_assign)
1393*5ce9237cSJohn Marino || gimple_clobber_p (else_assign)
1394*5ce9237cSJohn Marino || gimple_has_volatile_ops (else_assign))
1395e4b17023SJohn Marino return false;
1396e4b17023SJohn Marino
1397e4b17023SJohn Marino lhs = gimple_assign_lhs (then_assign);
1398e4b17023SJohn Marino if (!is_gimple_reg_type (TREE_TYPE (lhs))
1399e4b17023SJohn Marino || !operand_equal_p (lhs, gimple_assign_lhs (else_assign), 0))
1400e4b17023SJohn Marino return false;
1401e4b17023SJohn Marino
1402e4b17023SJohn Marino lhs_base = get_base_address (lhs);
1403e4b17023SJohn Marino if (lhs_base == NULL_TREE
1404e4b17023SJohn Marino || (!DECL_P (lhs_base) && TREE_CODE (lhs_base) != MEM_REF))
1405e4b17023SJohn Marino return false;
1406e4b17023SJohn Marino
1407e4b17023SJohn Marino then_rhs = gimple_assign_rhs1 (then_assign);
1408e4b17023SJohn Marino else_rhs = gimple_assign_rhs1 (else_assign);
1409e4b17023SJohn Marino then_locus = gimple_location (then_assign);
1410e4b17023SJohn Marino else_locus = gimple_location (else_assign);
1411e4b17023SJohn Marino
1412e4b17023SJohn Marino /* Now we've checked the constraints, so do the transformation:
1413e4b17023SJohn Marino 1) Remove the stores. */
1414e4b17023SJohn Marino gsi = gsi_for_stmt (then_assign);
1415e4b17023SJohn Marino unlink_stmt_vdef (then_assign);
1416e4b17023SJohn Marino gsi_remove (&gsi, true);
1417e4b17023SJohn Marino release_defs (then_assign);
1418e4b17023SJohn Marino
1419e4b17023SJohn Marino gsi = gsi_for_stmt (else_assign);
1420e4b17023SJohn Marino unlink_stmt_vdef (else_assign);
1421e4b17023SJohn Marino gsi_remove (&gsi, true);
1422e4b17023SJohn Marino release_defs (else_assign);
1423e4b17023SJohn Marino
1424e4b17023SJohn Marino /* 2) Create a temporary where we can store the old content
1425e4b17023SJohn Marino of the memory touched by the store, if we need to. */
1426e4b17023SJohn Marino if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
1427e4b17023SJohn Marino condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
1428e4b17023SJohn Marino add_referenced_var (condstoretemp);
1429e4b17023SJohn Marino
1430e4b17023SJohn Marino /* 3) Create a PHI node at the join block, with one argument
1431e4b17023SJohn Marino holding the old RHS, and the other holding the temporary
1432e4b17023SJohn Marino where we stored the old memory contents. */
1433e4b17023SJohn Marino newphi = create_phi_node (condstoretemp, join_bb);
1434e4b17023SJohn Marino add_phi_arg (newphi, then_rhs, EDGE_SUCC (then_bb, 0), then_locus);
1435e4b17023SJohn Marino add_phi_arg (newphi, else_rhs, EDGE_SUCC (else_bb, 0), else_locus);
1436e4b17023SJohn Marino
1437e4b17023SJohn Marino new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
1438e4b17023SJohn Marino
1439e4b17023SJohn Marino /* 4) Insert that PHI node. */
1440e4b17023SJohn Marino gsi = gsi_after_labels (join_bb);
1441e4b17023SJohn Marino if (gsi_end_p (gsi))
1442e4b17023SJohn Marino {
1443e4b17023SJohn Marino gsi = gsi_last_bb (join_bb);
1444e4b17023SJohn Marino gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
1445e4b17023SJohn Marino }
1446e4b17023SJohn Marino else
1447e4b17023SJohn Marino gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
1448e4b17023SJohn Marino
1449e4b17023SJohn Marino return true;
1450e4b17023SJohn Marino }
1451e4b17023SJohn Marino
1452e4b17023SJohn Marino /* Conditional store replacement. We already know
1453e4b17023SJohn Marino that the recognized pattern looks like so:
1454e4b17023SJohn Marino
1455e4b17023SJohn Marino split:
1456e4b17023SJohn Marino if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
1457e4b17023SJohn Marino THEN_BB:
1458e4b17023SJohn Marino ...
1459e4b17023SJohn Marino X = Y;
1460e4b17023SJohn Marino ...
1461e4b17023SJohn Marino goto JOIN_BB;
1462e4b17023SJohn Marino ELSE_BB:
1463e4b17023SJohn Marino ...
1464e4b17023SJohn Marino X = Z;
1465e4b17023SJohn Marino ...
1466e4b17023SJohn Marino fallthrough (edge E0)
1467e4b17023SJohn Marino JOIN_BB:
1468e4b17023SJohn Marino some more
1469e4b17023SJohn Marino
1470e4b17023SJohn Marino We check that it is safe to sink the store to JOIN_BB by verifying that
1471e4b17023SJohn Marino there are no read-after-write or write-after-write dependencies in
1472e4b17023SJohn Marino THEN_BB and ELSE_BB. */
1473e4b17023SJohn Marino
1474e4b17023SJohn Marino static bool
cond_if_else_store_replacement(basic_block then_bb,basic_block else_bb,basic_block join_bb)1475e4b17023SJohn Marino cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
1476e4b17023SJohn Marino basic_block join_bb)
1477e4b17023SJohn Marino {
1478e4b17023SJohn Marino gimple then_assign = last_and_only_stmt (then_bb);
1479e4b17023SJohn Marino gimple else_assign = last_and_only_stmt (else_bb);
1480e4b17023SJohn Marino VEC (data_reference_p, heap) *then_datarefs, *else_datarefs;
1481e4b17023SJohn Marino VEC (ddr_p, heap) *then_ddrs, *else_ddrs;
1482e4b17023SJohn Marino gimple then_store, else_store;
1483e4b17023SJohn Marino bool found, ok = false, res;
1484e4b17023SJohn Marino struct data_dependence_relation *ddr;
1485e4b17023SJohn Marino data_reference_p then_dr, else_dr;
1486e4b17023SJohn Marino int i, j;
1487e4b17023SJohn Marino tree then_lhs, else_lhs;
1488e4b17023SJohn Marino VEC (gimple, heap) *then_stores, *else_stores;
1489e4b17023SJohn Marino basic_block blocks[3];
1490e4b17023SJohn Marino
1491e4b17023SJohn Marino if (MAX_STORES_TO_SINK == 0)
1492e4b17023SJohn Marino return false;
1493e4b17023SJohn Marino
1494e4b17023SJohn Marino /* Handle the case with single statement in THEN_BB and ELSE_BB. */
1495e4b17023SJohn Marino if (then_assign && else_assign)
1496e4b17023SJohn Marino return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
1497e4b17023SJohn Marino then_assign, else_assign);
1498e4b17023SJohn Marino
1499e4b17023SJohn Marino /* Find data references. */
1500e4b17023SJohn Marino then_datarefs = VEC_alloc (data_reference_p, heap, 1);
1501e4b17023SJohn Marino else_datarefs = VEC_alloc (data_reference_p, heap, 1);
1502e4b17023SJohn Marino if ((find_data_references_in_bb (NULL, then_bb, &then_datarefs)
1503e4b17023SJohn Marino == chrec_dont_know)
1504e4b17023SJohn Marino || !VEC_length (data_reference_p, then_datarefs)
1505e4b17023SJohn Marino || (find_data_references_in_bb (NULL, else_bb, &else_datarefs)
1506e4b17023SJohn Marino == chrec_dont_know)
1507e4b17023SJohn Marino || !VEC_length (data_reference_p, else_datarefs))
1508e4b17023SJohn Marino {
1509e4b17023SJohn Marino free_data_refs (then_datarefs);
1510e4b17023SJohn Marino free_data_refs (else_datarefs);
1511e4b17023SJohn Marino return false;
1512e4b17023SJohn Marino }
1513e4b17023SJohn Marino
1514e4b17023SJohn Marino /* Find pairs of stores with equal LHS. */
1515e4b17023SJohn Marino then_stores = VEC_alloc (gimple, heap, 1);
1516e4b17023SJohn Marino else_stores = VEC_alloc (gimple, heap, 1);
1517e4b17023SJohn Marino FOR_EACH_VEC_ELT (data_reference_p, then_datarefs, i, then_dr)
1518e4b17023SJohn Marino {
1519e4b17023SJohn Marino if (DR_IS_READ (then_dr))
1520e4b17023SJohn Marino continue;
1521e4b17023SJohn Marino
1522e4b17023SJohn Marino then_store = DR_STMT (then_dr);
1523e4b17023SJohn Marino then_lhs = gimple_get_lhs (then_store);
1524e4b17023SJohn Marino found = false;
1525e4b17023SJohn Marino
1526e4b17023SJohn Marino FOR_EACH_VEC_ELT (data_reference_p, else_datarefs, j, else_dr)
1527e4b17023SJohn Marino {
1528e4b17023SJohn Marino if (DR_IS_READ (else_dr))
1529e4b17023SJohn Marino continue;
1530e4b17023SJohn Marino
1531e4b17023SJohn Marino else_store = DR_STMT (else_dr);
1532e4b17023SJohn Marino else_lhs = gimple_get_lhs (else_store);
1533e4b17023SJohn Marino
1534e4b17023SJohn Marino if (operand_equal_p (then_lhs, else_lhs, 0))
1535e4b17023SJohn Marino {
1536e4b17023SJohn Marino found = true;
1537e4b17023SJohn Marino break;
1538e4b17023SJohn Marino }
1539e4b17023SJohn Marino }
1540e4b17023SJohn Marino
1541e4b17023SJohn Marino if (!found)
1542e4b17023SJohn Marino continue;
1543e4b17023SJohn Marino
1544e4b17023SJohn Marino VEC_safe_push (gimple, heap, then_stores, then_store);
1545e4b17023SJohn Marino VEC_safe_push (gimple, heap, else_stores, else_store);
1546e4b17023SJohn Marino }
1547e4b17023SJohn Marino
1548e4b17023SJohn Marino /* No pairs of stores found. */
1549e4b17023SJohn Marino if (!VEC_length (gimple, then_stores)
1550e4b17023SJohn Marino || VEC_length (gimple, then_stores) > (unsigned) MAX_STORES_TO_SINK)
1551e4b17023SJohn Marino {
1552e4b17023SJohn Marino free_data_refs (then_datarefs);
1553e4b17023SJohn Marino free_data_refs (else_datarefs);
1554e4b17023SJohn Marino VEC_free (gimple, heap, then_stores);
1555e4b17023SJohn Marino VEC_free (gimple, heap, else_stores);
1556e4b17023SJohn Marino return false;
1557e4b17023SJohn Marino }
1558e4b17023SJohn Marino
1559e4b17023SJohn Marino /* Compute and check data dependencies in both basic blocks. */
1560e4b17023SJohn Marino then_ddrs = VEC_alloc (ddr_p, heap, 1);
1561e4b17023SJohn Marino else_ddrs = VEC_alloc (ddr_p, heap, 1);
1562e4b17023SJohn Marino if (!compute_all_dependences (then_datarefs, &then_ddrs, NULL, false)
1563e4b17023SJohn Marino || !compute_all_dependences (else_datarefs, &else_ddrs, NULL, false))
1564e4b17023SJohn Marino {
1565e4b17023SJohn Marino free_dependence_relations (then_ddrs);
1566e4b17023SJohn Marino free_dependence_relations (else_ddrs);
1567e4b17023SJohn Marino free_data_refs (then_datarefs);
1568e4b17023SJohn Marino free_data_refs (else_datarefs);
1569e4b17023SJohn Marino VEC_free (gimple, heap, then_stores);
1570e4b17023SJohn Marino VEC_free (gimple, heap, else_stores);
1571e4b17023SJohn Marino return false;
1572e4b17023SJohn Marino }
1573e4b17023SJohn Marino blocks[0] = then_bb;
1574e4b17023SJohn Marino blocks[1] = else_bb;
1575e4b17023SJohn Marino blocks[2] = join_bb;
1576e4b17023SJohn Marino renumber_gimple_stmt_uids_in_blocks (blocks, 3);
1577e4b17023SJohn Marino
1578e4b17023SJohn Marino /* Check that there are no read-after-write or write-after-write dependencies
1579e4b17023SJohn Marino in THEN_BB. */
1580e4b17023SJohn Marino FOR_EACH_VEC_ELT (ddr_p, then_ddrs, i, ddr)
1581e4b17023SJohn Marino {
1582e4b17023SJohn Marino struct data_reference *dra = DDR_A (ddr);
1583e4b17023SJohn Marino struct data_reference *drb = DDR_B (ddr);
1584e4b17023SJohn Marino
1585e4b17023SJohn Marino if (DDR_ARE_DEPENDENT (ddr) != chrec_known
1586e4b17023SJohn Marino && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
1587e4b17023SJohn Marino && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
1588e4b17023SJohn Marino || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
1589e4b17023SJohn Marino && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
1590e4b17023SJohn Marino || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
1591e4b17023SJohn Marino {
1592e4b17023SJohn Marino free_dependence_relations (then_ddrs);
1593e4b17023SJohn Marino free_dependence_relations (else_ddrs);
1594e4b17023SJohn Marino free_data_refs (then_datarefs);
1595e4b17023SJohn Marino free_data_refs (else_datarefs);
1596e4b17023SJohn Marino VEC_free (gimple, heap, then_stores);
1597e4b17023SJohn Marino VEC_free (gimple, heap, else_stores);
1598e4b17023SJohn Marino return false;
1599e4b17023SJohn Marino }
1600e4b17023SJohn Marino }
1601e4b17023SJohn Marino
1602e4b17023SJohn Marino /* Check that there are no read-after-write or write-after-write dependencies
1603e4b17023SJohn Marino in ELSE_BB. */
1604e4b17023SJohn Marino FOR_EACH_VEC_ELT (ddr_p, else_ddrs, i, ddr)
1605e4b17023SJohn Marino {
1606e4b17023SJohn Marino struct data_reference *dra = DDR_A (ddr);
1607e4b17023SJohn Marino struct data_reference *drb = DDR_B (ddr);
1608e4b17023SJohn Marino
1609e4b17023SJohn Marino if (DDR_ARE_DEPENDENT (ddr) != chrec_known
1610e4b17023SJohn Marino && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
1611e4b17023SJohn Marino && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
1612e4b17023SJohn Marino || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
1613e4b17023SJohn Marino && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
1614e4b17023SJohn Marino || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
1615e4b17023SJohn Marino {
1616e4b17023SJohn Marino free_dependence_relations (then_ddrs);
1617e4b17023SJohn Marino free_dependence_relations (else_ddrs);
1618e4b17023SJohn Marino free_data_refs (then_datarefs);
1619e4b17023SJohn Marino free_data_refs (else_datarefs);
1620e4b17023SJohn Marino VEC_free (gimple, heap, then_stores);
1621e4b17023SJohn Marino VEC_free (gimple, heap, else_stores);
1622e4b17023SJohn Marino return false;
1623e4b17023SJohn Marino }
1624e4b17023SJohn Marino }
1625e4b17023SJohn Marino
1626e4b17023SJohn Marino /* Sink stores with same LHS. */
1627e4b17023SJohn Marino FOR_EACH_VEC_ELT (gimple, then_stores, i, then_store)
1628e4b17023SJohn Marino {
1629e4b17023SJohn Marino else_store = VEC_index (gimple, else_stores, i);
1630e4b17023SJohn Marino res = cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
1631e4b17023SJohn Marino then_store, else_store);
1632e4b17023SJohn Marino ok = ok || res;
1633e4b17023SJohn Marino }
1634e4b17023SJohn Marino
1635e4b17023SJohn Marino free_dependence_relations (then_ddrs);
1636e4b17023SJohn Marino free_dependence_relations (else_ddrs);
1637e4b17023SJohn Marino free_data_refs (then_datarefs);
1638e4b17023SJohn Marino free_data_refs (else_datarefs);
1639e4b17023SJohn Marino VEC_free (gimple, heap, then_stores);
1640e4b17023SJohn Marino VEC_free (gimple, heap, else_stores);
1641e4b17023SJohn Marino
1642e4b17023SJohn Marino return ok;
1643e4b17023SJohn Marino }
1644e4b17023SJohn Marino
1645e4b17023SJohn Marino /* Always do these optimizations if we have SSA
1646e4b17023SJohn Marino trees to work on. */
1647e4b17023SJohn Marino static bool
gate_phiopt(void)1648e4b17023SJohn Marino gate_phiopt (void)
1649e4b17023SJohn Marino {
1650e4b17023SJohn Marino return 1;
1651e4b17023SJohn Marino }
1652e4b17023SJohn Marino
1653e4b17023SJohn Marino struct gimple_opt_pass pass_phiopt =
1654e4b17023SJohn Marino {
1655e4b17023SJohn Marino {
1656e4b17023SJohn Marino GIMPLE_PASS,
1657e4b17023SJohn Marino "phiopt", /* name */
1658e4b17023SJohn Marino gate_phiopt, /* gate */
1659e4b17023SJohn Marino tree_ssa_phiopt, /* execute */
1660e4b17023SJohn Marino NULL, /* sub */
1661e4b17023SJohn Marino NULL, /* next */
1662e4b17023SJohn Marino 0, /* static_pass_number */
1663e4b17023SJohn Marino TV_TREE_PHIOPT, /* tv_id */
1664e4b17023SJohn Marino PROP_cfg | PROP_ssa, /* properties_required */
1665e4b17023SJohn Marino 0, /* properties_provided */
1666e4b17023SJohn Marino 0, /* properties_destroyed */
1667e4b17023SJohn Marino 0, /* todo_flags_start */
1668e4b17023SJohn Marino TODO_ggc_collect
1669e4b17023SJohn Marino | TODO_verify_ssa
1670e4b17023SJohn Marino | TODO_verify_flow
1671e4b17023SJohn Marino | TODO_verify_stmts /* todo_flags_finish */
1672e4b17023SJohn Marino }
1673e4b17023SJohn Marino };
1674e4b17023SJohn Marino
1675e4b17023SJohn Marino static bool
gate_cselim(void)1676e4b17023SJohn Marino gate_cselim (void)
1677e4b17023SJohn Marino {
1678e4b17023SJohn Marino return flag_tree_cselim;
1679e4b17023SJohn Marino }
1680e4b17023SJohn Marino
1681e4b17023SJohn Marino struct gimple_opt_pass pass_cselim =
1682e4b17023SJohn Marino {
1683e4b17023SJohn Marino {
1684e4b17023SJohn Marino GIMPLE_PASS,
1685e4b17023SJohn Marino "cselim", /* name */
1686e4b17023SJohn Marino gate_cselim, /* gate */
1687e4b17023SJohn Marino tree_ssa_cs_elim, /* execute */
1688e4b17023SJohn Marino NULL, /* sub */
1689e4b17023SJohn Marino NULL, /* next */
1690e4b17023SJohn Marino 0, /* static_pass_number */
1691e4b17023SJohn Marino TV_TREE_PHIOPT, /* tv_id */
1692e4b17023SJohn Marino PROP_cfg | PROP_ssa, /* properties_required */
1693e4b17023SJohn Marino 0, /* properties_provided */
1694e4b17023SJohn Marino 0, /* properties_destroyed */
1695e4b17023SJohn Marino 0, /* todo_flags_start */
1696e4b17023SJohn Marino TODO_ggc_collect
1697e4b17023SJohn Marino | TODO_verify_ssa
1698e4b17023SJohn Marino | TODO_verify_flow
1699e4b17023SJohn Marino | TODO_verify_stmts /* todo_flags_finish */
1700e4b17023SJohn Marino }
1701e4b17023SJohn Marino };
1702