xref: /dflybsd-src/contrib/gcc-4.7/gcc/tree-ssa-phiopt.c (revision 81fc95a5293ee307c688a350a3feb4734aaddbb4)
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