xref: /dflybsd-src/contrib/gcc-4.7/gcc/tree-ssa-reassoc.c (revision 8410f2e87ab8f15a4b7fc8c870a38f45ad7f7f8e)
1e4b17023SJohn Marino /* Reassociation for trees.
2e4b17023SJohn Marino    Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011
3e4b17023SJohn Marino    Free Software Foundation, Inc.
4e4b17023SJohn Marino    Contributed by Daniel Berlin <dan@dberlin.org>
5e4b17023SJohn Marino 
6e4b17023SJohn Marino This file is part of GCC.
7e4b17023SJohn Marino 
8e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify
9e4b17023SJohn Marino it under the terms of the GNU General Public License as published by
10e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
11e4b17023SJohn Marino any later version.
12e4b17023SJohn Marino 
13e4b17023SJohn Marino GCC is distributed in the hope that it will be useful,
14e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
15e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16e4b17023SJohn Marino GNU General Public License for more details.
17e4b17023SJohn Marino 
18e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
20e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
21e4b17023SJohn Marino 
22e4b17023SJohn Marino #include "config.h"
23e4b17023SJohn Marino #include "system.h"
24e4b17023SJohn Marino #include "coretypes.h"
25e4b17023SJohn Marino #include "tm.h"
26e4b17023SJohn Marino #include "tree.h"
27e4b17023SJohn Marino #include "basic-block.h"
28e4b17023SJohn Marino #include "tree-pretty-print.h"
29e4b17023SJohn Marino #include "gimple-pretty-print.h"
30e4b17023SJohn Marino #include "tree-inline.h"
31e4b17023SJohn Marino #include "tree-flow.h"
32e4b17023SJohn Marino #include "gimple.h"
33e4b17023SJohn Marino #include "tree-dump.h"
34e4b17023SJohn Marino #include "timevar.h"
35e4b17023SJohn Marino #include "tree-iterator.h"
36e4b17023SJohn Marino #include "tree-pass.h"
37e4b17023SJohn Marino #include "alloc-pool.h"
38e4b17023SJohn Marino #include "vec.h"
39e4b17023SJohn Marino #include "langhooks.h"
40e4b17023SJohn Marino #include "pointer-set.h"
41e4b17023SJohn Marino #include "cfgloop.h"
42e4b17023SJohn Marino #include "flags.h"
43e4b17023SJohn Marino #include "target.h"
44e4b17023SJohn Marino #include "params.h"
45e4b17023SJohn Marino #include "diagnostic-core.h"
46e4b17023SJohn Marino 
47e4b17023SJohn Marino /*  This is a simple global reassociation pass.  It is, in part, based
48e4b17023SJohn Marino     on the LLVM pass of the same name (They do some things more/less
49e4b17023SJohn Marino     than we do, in different orders, etc).
50e4b17023SJohn Marino 
51e4b17023SJohn Marino     It consists of five steps:
52e4b17023SJohn Marino 
53e4b17023SJohn Marino     1. Breaking up subtract operations into addition + negate, where
54e4b17023SJohn Marino     it would promote the reassociation of adds.
55e4b17023SJohn Marino 
56e4b17023SJohn Marino     2. Left linearization of the expression trees, so that (A+B)+(C+D)
57e4b17023SJohn Marino     becomes (((A+B)+C)+D), which is easier for us to rewrite later.
58e4b17023SJohn Marino     During linearization, we place the operands of the binary
59e4b17023SJohn Marino     expressions into a vector of operand_entry_t
60e4b17023SJohn Marino 
61e4b17023SJohn Marino     3. Optimization of the operand lists, eliminating things like a +
62e4b17023SJohn Marino     -a, a & a, etc.
63e4b17023SJohn Marino 
64e4b17023SJohn Marino     4. Rewrite the expression trees we linearized and optimized so
65e4b17023SJohn Marino     they are in proper rank order.
66e4b17023SJohn Marino 
67e4b17023SJohn Marino     5. Repropagate negates, as nothing else will clean it up ATM.
68e4b17023SJohn Marino 
69e4b17023SJohn Marino     A bit of theory on #4, since nobody seems to write anything down
70e4b17023SJohn Marino     about why it makes sense to do it the way they do it:
71e4b17023SJohn Marino 
72e4b17023SJohn Marino     We could do this much nicer theoretically, but don't (for reasons
73e4b17023SJohn Marino     explained after how to do it theoretically nice :P).
74e4b17023SJohn Marino 
75e4b17023SJohn Marino     In order to promote the most redundancy elimination, you want
76e4b17023SJohn Marino     binary expressions whose operands are the same rank (or
77e4b17023SJohn Marino     preferably, the same value) exposed to the redundancy eliminator,
78e4b17023SJohn Marino     for possible elimination.
79e4b17023SJohn Marino 
80e4b17023SJohn Marino     So the way to do this if we really cared, is to build the new op
81e4b17023SJohn Marino     tree from the leaves to the roots, merging as you go, and putting the
82e4b17023SJohn Marino     new op on the end of the worklist, until you are left with one
83e4b17023SJohn Marino     thing on the worklist.
84e4b17023SJohn Marino 
85e4b17023SJohn Marino     IE if you have to rewrite the following set of operands (listed with
86e4b17023SJohn Marino     rank in parentheses), with opcode PLUS_EXPR:
87e4b17023SJohn Marino 
88e4b17023SJohn Marino     a (1),  b (1),  c (1),  d (2), e (2)
89e4b17023SJohn Marino 
90e4b17023SJohn Marino 
91e4b17023SJohn Marino     We start with our merge worklist empty, and the ops list with all of
92e4b17023SJohn Marino     those on it.
93e4b17023SJohn Marino 
94e4b17023SJohn Marino     You want to first merge all leaves of the same rank, as much as
95e4b17023SJohn Marino     possible.
96e4b17023SJohn Marino 
97e4b17023SJohn Marino     So first build a binary op of
98e4b17023SJohn Marino 
99e4b17023SJohn Marino     mergetmp = a + b, and put "mergetmp" on the merge worklist.
100e4b17023SJohn Marino 
101e4b17023SJohn Marino     Because there is no three operand form of PLUS_EXPR, c is not going to
102e4b17023SJohn Marino     be exposed to redundancy elimination as a rank 1 operand.
103e4b17023SJohn Marino 
104e4b17023SJohn Marino     So you might as well throw it on the merge worklist (you could also
105e4b17023SJohn Marino     consider it to now be a rank two operand, and merge it with d and e,
106e4b17023SJohn Marino     but in this case, you then have evicted e from a binary op. So at
107e4b17023SJohn Marino     least in this situation, you can't win.)
108e4b17023SJohn Marino 
109e4b17023SJohn Marino     Then build a binary op of d + e
110e4b17023SJohn Marino     mergetmp2 = d + e
111e4b17023SJohn Marino 
112e4b17023SJohn Marino     and put mergetmp2 on the merge worklist.
113e4b17023SJohn Marino 
114e4b17023SJohn Marino     so merge worklist = {mergetmp, c, mergetmp2}
115e4b17023SJohn Marino 
116e4b17023SJohn Marino     Continue building binary ops of these operations until you have only
117e4b17023SJohn Marino     one operation left on the worklist.
118e4b17023SJohn Marino 
119e4b17023SJohn Marino     So we have
120e4b17023SJohn Marino 
121e4b17023SJohn Marino     build binary op
122e4b17023SJohn Marino     mergetmp3 = mergetmp + c
123e4b17023SJohn Marino 
124e4b17023SJohn Marino     worklist = {mergetmp2, mergetmp3}
125e4b17023SJohn Marino 
126e4b17023SJohn Marino     mergetmp4 = mergetmp2 + mergetmp3
127e4b17023SJohn Marino 
128e4b17023SJohn Marino     worklist = {mergetmp4}
129e4b17023SJohn Marino 
130e4b17023SJohn Marino     because we have one operation left, we can now just set the original
131e4b17023SJohn Marino     statement equal to the result of that operation.
132e4b17023SJohn Marino 
133e4b17023SJohn Marino     This will at least expose a + b  and d + e to redundancy elimination
134e4b17023SJohn Marino     as binary operations.
135e4b17023SJohn Marino 
136e4b17023SJohn Marino     For extra points, you can reuse the old statements to build the
137e4b17023SJohn Marino     mergetmps, since you shouldn't run out.
138e4b17023SJohn Marino 
139e4b17023SJohn Marino     So why don't we do this?
140e4b17023SJohn Marino 
141e4b17023SJohn Marino     Because it's expensive, and rarely will help.  Most trees we are
142e4b17023SJohn Marino     reassociating have 3 or less ops.  If they have 2 ops, they already
143e4b17023SJohn Marino     will be written into a nice single binary op.  If you have 3 ops, a
144e4b17023SJohn Marino     single simple check suffices to tell you whether the first two are of the
145e4b17023SJohn Marino     same rank.  If so, you know to order it
146e4b17023SJohn Marino 
147e4b17023SJohn Marino     mergetmp = op1 + op2
148e4b17023SJohn Marino     newstmt = mergetmp + op3
149e4b17023SJohn Marino 
150e4b17023SJohn Marino     instead of
151e4b17023SJohn Marino     mergetmp = op2 + op3
152e4b17023SJohn Marino     newstmt = mergetmp + op1
153e4b17023SJohn Marino 
154e4b17023SJohn Marino     If all three are of the same rank, you can't expose them all in a
155e4b17023SJohn Marino     single binary operator anyway, so the above is *still* the best you
156e4b17023SJohn Marino     can do.
157e4b17023SJohn Marino 
158e4b17023SJohn Marino     Thus, this is what we do.  When we have three ops left, we check to see
159e4b17023SJohn Marino     what order to put them in, and call it a day.  As a nod to vector sum
160e4b17023SJohn Marino     reduction, we check if any of the ops are really a phi node that is a
161e4b17023SJohn Marino     destructive update for the associating op, and keep the destructive
162e4b17023SJohn Marino     update together for vector sum reduction recognition.  */
163e4b17023SJohn Marino 
164e4b17023SJohn Marino 
165e4b17023SJohn Marino /* Statistics */
166e4b17023SJohn Marino static struct
167e4b17023SJohn Marino {
168e4b17023SJohn Marino   int linearized;
169e4b17023SJohn Marino   int constants_eliminated;
170e4b17023SJohn Marino   int ops_eliminated;
171e4b17023SJohn Marino   int rewritten;
172e4b17023SJohn Marino } reassociate_stats;
173e4b17023SJohn Marino 
174e4b17023SJohn Marino /* Operator, rank pair.  */
175e4b17023SJohn Marino typedef struct operand_entry
176e4b17023SJohn Marino {
177e4b17023SJohn Marino   unsigned int rank;
178e4b17023SJohn Marino   int id;
179e4b17023SJohn Marino   tree op;
180e4b17023SJohn Marino } *operand_entry_t;
181e4b17023SJohn Marino 
182e4b17023SJohn Marino static alloc_pool operand_entry_pool;
183e4b17023SJohn Marino 
184e4b17023SJohn Marino /* This is used to assign a unique ID to each struct operand_entry
185e4b17023SJohn Marino    so that qsort results are identical on different hosts.  */
186e4b17023SJohn Marino static int next_operand_entry_id;
187e4b17023SJohn Marino 
188e4b17023SJohn Marino /* Starting rank number for a given basic block, so that we can rank
189e4b17023SJohn Marino    operations using unmovable instructions in that BB based on the bb
190e4b17023SJohn Marino    depth.  */
191e4b17023SJohn Marino static long *bb_rank;
192e4b17023SJohn Marino 
193e4b17023SJohn Marino /* Operand->rank hashtable.  */
194e4b17023SJohn Marino static struct pointer_map_t *operand_rank;
195e4b17023SJohn Marino 
196e4b17023SJohn Marino /* Forward decls.  */
197e4b17023SJohn Marino static long get_rank (tree);
198e4b17023SJohn Marino 
199e4b17023SJohn Marino 
200e4b17023SJohn Marino /* Bias amount for loop-carried phis.  We want this to be larger than
201e4b17023SJohn Marino    the depth of any reassociation tree we can see, but not larger than
202e4b17023SJohn Marino    the rank difference between two blocks.  */
203e4b17023SJohn Marino #define PHI_LOOP_BIAS (1 << 15)
204e4b17023SJohn Marino 
205e4b17023SJohn Marino /* Rank assigned to a phi statement.  If STMT is a loop-carried phi of
206e4b17023SJohn Marino    an innermost loop, and the phi has only a single use which is inside
207e4b17023SJohn Marino    the loop, then the rank is the block rank of the loop latch plus an
208e4b17023SJohn Marino    extra bias for the loop-carried dependence.  This causes expressions
209e4b17023SJohn Marino    calculated into an accumulator variable to be independent for each
210e4b17023SJohn Marino    iteration of the loop.  If STMT is some other phi, the rank is the
211e4b17023SJohn Marino    block rank of its containing block.  */
212e4b17023SJohn Marino static long
phi_rank(gimple stmt)213e4b17023SJohn Marino phi_rank (gimple stmt)
214e4b17023SJohn Marino {
215e4b17023SJohn Marino   basic_block bb = gimple_bb (stmt);
216e4b17023SJohn Marino   struct loop *father = bb->loop_father;
217e4b17023SJohn Marino   tree res;
218e4b17023SJohn Marino   unsigned i;
219e4b17023SJohn Marino   use_operand_p use;
220e4b17023SJohn Marino   gimple use_stmt;
221e4b17023SJohn Marino 
222e4b17023SJohn Marino   /* We only care about real loops (those with a latch).  */
223e4b17023SJohn Marino   if (!father->latch)
224e4b17023SJohn Marino     return bb_rank[bb->index];
225e4b17023SJohn Marino 
226e4b17023SJohn Marino   /* Interesting phis must be in headers of innermost loops.  */
227e4b17023SJohn Marino   if (bb != father->header
228e4b17023SJohn Marino       || father->inner)
229e4b17023SJohn Marino     return bb_rank[bb->index];
230e4b17023SJohn Marino 
231e4b17023SJohn Marino   /* Ignore virtual SSA_NAMEs.  */
232e4b17023SJohn Marino   res = gimple_phi_result (stmt);
233e4b17023SJohn Marino   if (!is_gimple_reg (SSA_NAME_VAR (res)))
234e4b17023SJohn Marino     return bb_rank[bb->index];
235e4b17023SJohn Marino 
236e4b17023SJohn Marino   /* The phi definition must have a single use, and that use must be
237e4b17023SJohn Marino      within the loop.  Otherwise this isn't an accumulator pattern.  */
238e4b17023SJohn Marino   if (!single_imm_use (res, &use, &use_stmt)
239e4b17023SJohn Marino       || gimple_bb (use_stmt)->loop_father != father)
240e4b17023SJohn Marino     return bb_rank[bb->index];
241e4b17023SJohn Marino 
242e4b17023SJohn Marino   /* Look for phi arguments from within the loop.  If found, bias this phi.  */
243e4b17023SJohn Marino   for (i = 0; i < gimple_phi_num_args (stmt); i++)
244e4b17023SJohn Marino     {
245e4b17023SJohn Marino       tree arg = gimple_phi_arg_def (stmt, i);
246e4b17023SJohn Marino       if (TREE_CODE (arg) == SSA_NAME
247e4b17023SJohn Marino 	  && !SSA_NAME_IS_DEFAULT_DEF (arg))
248e4b17023SJohn Marino 	{
249e4b17023SJohn Marino 	  gimple def_stmt = SSA_NAME_DEF_STMT (arg);
250e4b17023SJohn Marino 	  if (gimple_bb (def_stmt)->loop_father == father)
251e4b17023SJohn Marino 	    return bb_rank[father->latch->index] + PHI_LOOP_BIAS;
252e4b17023SJohn Marino 	}
253e4b17023SJohn Marino     }
254e4b17023SJohn Marino 
255e4b17023SJohn Marino   /* Must be an uninteresting phi.  */
256e4b17023SJohn Marino   return bb_rank[bb->index];
257e4b17023SJohn Marino }
258e4b17023SJohn Marino 
259e4b17023SJohn Marino /* If EXP is an SSA_NAME defined by a PHI statement that represents a
260e4b17023SJohn Marino    loop-carried dependence of an innermost loop, return TRUE; else
261e4b17023SJohn Marino    return FALSE.  */
262e4b17023SJohn Marino static bool
loop_carried_phi(tree exp)263e4b17023SJohn Marino loop_carried_phi (tree exp)
264e4b17023SJohn Marino {
265e4b17023SJohn Marino   gimple phi_stmt;
266e4b17023SJohn Marino   long block_rank;
267e4b17023SJohn Marino 
268e4b17023SJohn Marino   if (TREE_CODE (exp) != SSA_NAME
269e4b17023SJohn Marino       || SSA_NAME_IS_DEFAULT_DEF (exp))
270e4b17023SJohn Marino     return false;
271e4b17023SJohn Marino 
272e4b17023SJohn Marino   phi_stmt = SSA_NAME_DEF_STMT (exp);
273e4b17023SJohn Marino 
274e4b17023SJohn Marino   if (gimple_code (SSA_NAME_DEF_STMT (exp)) != GIMPLE_PHI)
275e4b17023SJohn Marino     return false;
276e4b17023SJohn Marino 
277e4b17023SJohn Marino   /* Non-loop-carried phis have block rank.  Loop-carried phis have
278e4b17023SJohn Marino      an additional bias added in.  If this phi doesn't have block rank,
279e4b17023SJohn Marino      it's biased and should not be propagated.  */
280e4b17023SJohn Marino   block_rank = bb_rank[gimple_bb (phi_stmt)->index];
281e4b17023SJohn Marino 
282e4b17023SJohn Marino   if (phi_rank (phi_stmt) != block_rank)
283e4b17023SJohn Marino     return true;
284e4b17023SJohn Marino 
285e4b17023SJohn Marino   return false;
286e4b17023SJohn Marino }
287e4b17023SJohn Marino 
288e4b17023SJohn Marino /* Return the maximum of RANK and the rank that should be propagated
289e4b17023SJohn Marino    from expression OP.  For most operands, this is just the rank of OP.
290e4b17023SJohn Marino    For loop-carried phis, the value is zero to avoid undoing the bias
291e4b17023SJohn Marino    in favor of the phi.  */
292e4b17023SJohn Marino static long
propagate_rank(long rank,tree op)293e4b17023SJohn Marino propagate_rank (long rank, tree op)
294e4b17023SJohn Marino {
295e4b17023SJohn Marino   long op_rank;
296e4b17023SJohn Marino 
297e4b17023SJohn Marino   if (loop_carried_phi (op))
298e4b17023SJohn Marino     return rank;
299e4b17023SJohn Marino 
300e4b17023SJohn Marino   op_rank = get_rank (op);
301e4b17023SJohn Marino 
302e4b17023SJohn Marino   return MAX (rank, op_rank);
303e4b17023SJohn Marino }
304e4b17023SJohn Marino 
305e4b17023SJohn Marino /* Look up the operand rank structure for expression E.  */
306e4b17023SJohn Marino 
307e4b17023SJohn Marino static inline long
find_operand_rank(tree e)308e4b17023SJohn Marino find_operand_rank (tree e)
309e4b17023SJohn Marino {
310e4b17023SJohn Marino   void **slot = pointer_map_contains (operand_rank, e);
311e4b17023SJohn Marino   return slot ? (long) (intptr_t) *slot : -1;
312e4b17023SJohn Marino }
313e4b17023SJohn Marino 
314e4b17023SJohn Marino /* Insert {E,RANK} into the operand rank hashtable.  */
315e4b17023SJohn Marino 
316e4b17023SJohn Marino static inline void
insert_operand_rank(tree e,long rank)317e4b17023SJohn Marino insert_operand_rank (tree e, long rank)
318e4b17023SJohn Marino {
319e4b17023SJohn Marino   void **slot;
320e4b17023SJohn Marino   gcc_assert (rank > 0);
321e4b17023SJohn Marino   slot = pointer_map_insert (operand_rank, e);
322e4b17023SJohn Marino   gcc_assert (!*slot);
323e4b17023SJohn Marino   *slot = (void *) (intptr_t) rank;
324e4b17023SJohn Marino }
325e4b17023SJohn Marino 
326e4b17023SJohn Marino /* Given an expression E, return the rank of the expression.  */
327e4b17023SJohn Marino 
328e4b17023SJohn Marino static long
get_rank(tree e)329e4b17023SJohn Marino get_rank (tree e)
330e4b17023SJohn Marino {
331e4b17023SJohn Marino   /* Constants have rank 0.  */
332e4b17023SJohn Marino   if (is_gimple_min_invariant (e))
333e4b17023SJohn Marino     return 0;
334e4b17023SJohn Marino 
335e4b17023SJohn Marino   /* SSA_NAME's have the rank of the expression they are the result
336e4b17023SJohn Marino      of.
337e4b17023SJohn Marino      For globals and uninitialized values, the rank is 0.
338e4b17023SJohn Marino      For function arguments, use the pre-setup rank.
339e4b17023SJohn Marino      For PHI nodes, stores, asm statements, etc, we use the rank of
340e4b17023SJohn Marino      the BB.
341e4b17023SJohn Marino      For simple operations, the rank is the maximum rank of any of
342e4b17023SJohn Marino      its operands, or the bb_rank, whichever is less.
343e4b17023SJohn Marino      I make no claims that this is optimal, however, it gives good
344e4b17023SJohn Marino      results.  */
345e4b17023SJohn Marino 
346e4b17023SJohn Marino   /* We make an exception to the normal ranking system to break
347e4b17023SJohn Marino      dependences of accumulator variables in loops.  Suppose we
348e4b17023SJohn Marino      have a simple one-block loop containing:
349e4b17023SJohn Marino 
350e4b17023SJohn Marino        x_1 = phi(x_0, x_2)
351e4b17023SJohn Marino        b = a + x_1
352e4b17023SJohn Marino        c = b + d
353e4b17023SJohn Marino        x_2 = c + e
354e4b17023SJohn Marino 
355e4b17023SJohn Marino      As shown, each iteration of the calculation into x is fully
356e4b17023SJohn Marino      dependent upon the iteration before it.  We would prefer to
357e4b17023SJohn Marino      see this in the form:
358e4b17023SJohn Marino 
359e4b17023SJohn Marino        x_1 = phi(x_0, x_2)
360e4b17023SJohn Marino        b = a + d
361e4b17023SJohn Marino        c = b + e
362e4b17023SJohn Marino        x_2 = c + x_1
363e4b17023SJohn Marino 
364e4b17023SJohn Marino      If the loop is unrolled, the calculations of b and c from
365e4b17023SJohn Marino      different iterations can be interleaved.
366e4b17023SJohn Marino 
367e4b17023SJohn Marino      To obtain this result during reassociation, we bias the rank
368e4b17023SJohn Marino      of the phi definition x_1 upward, when it is recognized as an
369e4b17023SJohn Marino      accumulator pattern.  The artificial rank causes it to be
370e4b17023SJohn Marino      added last, providing the desired independence.  */
371e4b17023SJohn Marino 
372e4b17023SJohn Marino   if (TREE_CODE (e) == SSA_NAME)
373e4b17023SJohn Marino     {
374e4b17023SJohn Marino       gimple stmt;
375e4b17023SJohn Marino       long rank;
376e4b17023SJohn Marino       int i, n;
377e4b17023SJohn Marino       tree op;
378e4b17023SJohn Marino 
379e4b17023SJohn Marino       if (TREE_CODE (SSA_NAME_VAR (e)) == PARM_DECL
380e4b17023SJohn Marino 	  && SSA_NAME_IS_DEFAULT_DEF (e))
381e4b17023SJohn Marino 	return find_operand_rank (e);
382e4b17023SJohn Marino 
383e4b17023SJohn Marino       stmt = SSA_NAME_DEF_STMT (e);
384e4b17023SJohn Marino       if (gimple_bb (stmt) == NULL)
385e4b17023SJohn Marino 	return 0;
386e4b17023SJohn Marino 
387e4b17023SJohn Marino       if (gimple_code (stmt) == GIMPLE_PHI)
388e4b17023SJohn Marino 	return phi_rank (stmt);
389e4b17023SJohn Marino 
390e4b17023SJohn Marino       if (!is_gimple_assign (stmt)
391e4b17023SJohn Marino 	  || gimple_vdef (stmt))
392e4b17023SJohn Marino 	return bb_rank[gimple_bb (stmt)->index];
393e4b17023SJohn Marino 
394e4b17023SJohn Marino       /* If we already have a rank for this expression, use that.  */
395e4b17023SJohn Marino       rank = find_operand_rank (e);
396e4b17023SJohn Marino       if (rank != -1)
397e4b17023SJohn Marino 	return rank;
398e4b17023SJohn Marino 
399e4b17023SJohn Marino       /* Otherwise, find the maximum rank for the operands.  As an
400e4b17023SJohn Marino 	 exception, remove the bias from loop-carried phis when propagating
401e4b17023SJohn Marino 	 the rank so that dependent operations are not also biased.  */
402e4b17023SJohn Marino       rank = 0;
403e4b17023SJohn Marino       if (gimple_assign_single_p (stmt))
404e4b17023SJohn Marino 	{
405e4b17023SJohn Marino 	  tree rhs = gimple_assign_rhs1 (stmt);
406e4b17023SJohn Marino 	  n = TREE_OPERAND_LENGTH (rhs);
407e4b17023SJohn Marino 	  if (n == 0)
408e4b17023SJohn Marino 	    rank = propagate_rank (rank, rhs);
409e4b17023SJohn Marino 	  else
410e4b17023SJohn Marino 	    {
411e4b17023SJohn Marino 	      for (i = 0; i < n; i++)
412e4b17023SJohn Marino 		{
413e4b17023SJohn Marino 		  op = TREE_OPERAND (rhs, i);
414e4b17023SJohn Marino 
415e4b17023SJohn Marino 		  if (op != NULL_TREE)
416e4b17023SJohn Marino 		    rank = propagate_rank (rank, op);
417e4b17023SJohn Marino 		}
418e4b17023SJohn Marino 	    }
419e4b17023SJohn Marino 	}
420e4b17023SJohn Marino       else
421e4b17023SJohn Marino 	{
422e4b17023SJohn Marino 	  n = gimple_num_ops (stmt);
423e4b17023SJohn Marino 	  for (i = 1; i < n; i++)
424e4b17023SJohn Marino 	    {
425e4b17023SJohn Marino 	      op = gimple_op (stmt, i);
426e4b17023SJohn Marino 	      gcc_assert (op);
427e4b17023SJohn Marino 	      rank = propagate_rank (rank, op);
428e4b17023SJohn Marino 	    }
429e4b17023SJohn Marino 	}
430e4b17023SJohn Marino 
431e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
432e4b17023SJohn Marino 	{
433e4b17023SJohn Marino 	  fprintf (dump_file, "Rank for ");
434e4b17023SJohn Marino 	  print_generic_expr (dump_file, e, 0);
435e4b17023SJohn Marino 	  fprintf (dump_file, " is %ld\n", (rank + 1));
436e4b17023SJohn Marino 	}
437e4b17023SJohn Marino 
438e4b17023SJohn Marino       /* Note the rank in the hashtable so we don't recompute it.  */
439e4b17023SJohn Marino       insert_operand_rank (e, (rank + 1));
440e4b17023SJohn Marino       return (rank + 1);
441e4b17023SJohn Marino     }
442e4b17023SJohn Marino 
443e4b17023SJohn Marino   /* Globals, etc,  are rank 0 */
444e4b17023SJohn Marino   return 0;
445e4b17023SJohn Marino }
446e4b17023SJohn Marino 
447e4b17023SJohn Marino DEF_VEC_P(operand_entry_t);
448e4b17023SJohn Marino DEF_VEC_ALLOC_P(operand_entry_t, heap);
449e4b17023SJohn Marino 
450e4b17023SJohn Marino /* We want integer ones to end up last no matter what, since they are
451e4b17023SJohn Marino    the ones we can do the most with.  */
452e4b17023SJohn Marino #define INTEGER_CONST_TYPE 1 << 3
453e4b17023SJohn Marino #define FLOAT_CONST_TYPE 1 << 2
454e4b17023SJohn Marino #define OTHER_CONST_TYPE 1 << 1
455e4b17023SJohn Marino 
456e4b17023SJohn Marino /* Classify an invariant tree into integer, float, or other, so that
457e4b17023SJohn Marino    we can sort them to be near other constants of the same type.  */
458e4b17023SJohn Marino static inline int
constant_type(tree t)459e4b17023SJohn Marino constant_type (tree t)
460e4b17023SJohn Marino {
461e4b17023SJohn Marino   if (INTEGRAL_TYPE_P (TREE_TYPE (t)))
462e4b17023SJohn Marino     return INTEGER_CONST_TYPE;
463e4b17023SJohn Marino   else if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (t)))
464e4b17023SJohn Marino     return FLOAT_CONST_TYPE;
465e4b17023SJohn Marino   else
466e4b17023SJohn Marino     return OTHER_CONST_TYPE;
467e4b17023SJohn Marino }
468e4b17023SJohn Marino 
469e4b17023SJohn Marino /* qsort comparison function to sort operand entries PA and PB by rank
470e4b17023SJohn Marino    so that the sorted array is ordered by rank in decreasing order.  */
471e4b17023SJohn Marino static int
sort_by_operand_rank(const void * pa,const void * pb)472e4b17023SJohn Marino sort_by_operand_rank (const void *pa, const void *pb)
473e4b17023SJohn Marino {
474e4b17023SJohn Marino   const operand_entry_t oea = *(const operand_entry_t *)pa;
475e4b17023SJohn Marino   const operand_entry_t oeb = *(const operand_entry_t *)pb;
476e4b17023SJohn Marino 
477e4b17023SJohn Marino   /* It's nicer for optimize_expression if constants that are likely
478e4b17023SJohn Marino      to fold when added/multiplied//whatever are put next to each
479e4b17023SJohn Marino      other.  Since all constants have rank 0, order them by type.  */
480e4b17023SJohn Marino   if (oeb->rank == 0 &&  oea->rank == 0)
481e4b17023SJohn Marino     {
482e4b17023SJohn Marino       if (constant_type (oeb->op) != constant_type (oea->op))
483e4b17023SJohn Marino 	return constant_type (oeb->op) - constant_type (oea->op);
484e4b17023SJohn Marino       else
485e4b17023SJohn Marino 	/* To make sorting result stable, we use unique IDs to determine
486e4b17023SJohn Marino 	   order.  */
487e4b17023SJohn Marino         return oeb->id - oea->id;
488e4b17023SJohn Marino     }
489e4b17023SJohn Marino 
490e4b17023SJohn Marino   /* Lastly, make sure the versions that are the same go next to each
491e4b17023SJohn Marino      other.  We use SSA_NAME_VERSION because it's stable.  */
492e4b17023SJohn Marino   if ((oeb->rank - oea->rank == 0)
493e4b17023SJohn Marino       && TREE_CODE (oea->op) == SSA_NAME
494e4b17023SJohn Marino       && TREE_CODE (oeb->op) == SSA_NAME)
495e4b17023SJohn Marino     {
496e4b17023SJohn Marino       if (SSA_NAME_VERSION (oeb->op) != SSA_NAME_VERSION (oea->op))
497e4b17023SJohn Marino 	return SSA_NAME_VERSION (oeb->op) - SSA_NAME_VERSION (oea->op);
498e4b17023SJohn Marino       else
499e4b17023SJohn Marino 	return oeb->id - oea->id;
500e4b17023SJohn Marino     }
501e4b17023SJohn Marino 
502e4b17023SJohn Marino   if (oeb->rank != oea->rank)
503e4b17023SJohn Marino     return oeb->rank - oea->rank;
504e4b17023SJohn Marino   else
505e4b17023SJohn Marino     return oeb->id - oea->id;
506e4b17023SJohn Marino }
507e4b17023SJohn Marino 
508e4b17023SJohn Marino /* Add an operand entry to *OPS for the tree operand OP.  */
509e4b17023SJohn Marino 
510e4b17023SJohn Marino static void
add_to_ops_vec(VEC (operand_entry_t,heap)** ops,tree op)511e4b17023SJohn Marino add_to_ops_vec (VEC(operand_entry_t, heap) **ops, tree op)
512e4b17023SJohn Marino {
513e4b17023SJohn Marino   operand_entry_t oe = (operand_entry_t) pool_alloc (operand_entry_pool);
514e4b17023SJohn Marino 
515e4b17023SJohn Marino   oe->op = op;
516e4b17023SJohn Marino   oe->rank = get_rank (op);
517e4b17023SJohn Marino   oe->id = next_operand_entry_id++;
518e4b17023SJohn Marino   VEC_safe_push (operand_entry_t, heap, *ops, oe);
519e4b17023SJohn Marino }
520e4b17023SJohn Marino 
521e4b17023SJohn Marino /* Return true if STMT is reassociable operation containing a binary
522e4b17023SJohn Marino    operation with tree code CODE, and is inside LOOP.  */
523e4b17023SJohn Marino 
524e4b17023SJohn Marino static bool
is_reassociable_op(gimple stmt,enum tree_code code,struct loop * loop)525e4b17023SJohn Marino is_reassociable_op (gimple stmt, enum tree_code code, struct loop *loop)
526e4b17023SJohn Marino {
527e4b17023SJohn Marino   basic_block bb = gimple_bb (stmt);
528e4b17023SJohn Marino 
529e4b17023SJohn Marino   if (gimple_bb (stmt) == NULL)
530e4b17023SJohn Marino     return false;
531e4b17023SJohn Marino 
532e4b17023SJohn Marino   if (!flow_bb_inside_loop_p (loop, bb))
533e4b17023SJohn Marino     return false;
534e4b17023SJohn Marino 
535e4b17023SJohn Marino   if (is_gimple_assign (stmt)
536e4b17023SJohn Marino       && gimple_assign_rhs_code (stmt) == code
537e4b17023SJohn Marino       && has_single_use (gimple_assign_lhs (stmt)))
538e4b17023SJohn Marino     return true;
539e4b17023SJohn Marino 
540e4b17023SJohn Marino   return false;
541e4b17023SJohn Marino }
542e4b17023SJohn Marino 
543e4b17023SJohn Marino 
544e4b17023SJohn Marino /* Given NAME, if NAME is defined by a unary operation OPCODE, return the
545e4b17023SJohn Marino    operand of the negate operation.  Otherwise, return NULL.  */
546e4b17023SJohn Marino 
547e4b17023SJohn Marino static tree
get_unary_op(tree name,enum tree_code opcode)548e4b17023SJohn Marino get_unary_op (tree name, enum tree_code opcode)
549e4b17023SJohn Marino {
550e4b17023SJohn Marino   gimple stmt = SSA_NAME_DEF_STMT (name);
551e4b17023SJohn Marino 
552e4b17023SJohn Marino   if (!is_gimple_assign (stmt))
553e4b17023SJohn Marino     return NULL_TREE;
554e4b17023SJohn Marino 
555e4b17023SJohn Marino   if (gimple_assign_rhs_code (stmt) == opcode)
556e4b17023SJohn Marino     return gimple_assign_rhs1 (stmt);
557e4b17023SJohn Marino   return NULL_TREE;
558e4b17023SJohn Marino }
559e4b17023SJohn Marino 
560e4b17023SJohn Marino /* If CURR and LAST are a pair of ops that OPCODE allows us to
561e4b17023SJohn Marino    eliminate through equivalences, do so, remove them from OPS, and
562e4b17023SJohn Marino    return true.  Otherwise, return false.  */
563e4b17023SJohn Marino 
564e4b17023SJohn Marino static bool
eliminate_duplicate_pair(enum tree_code opcode,VEC (operand_entry_t,heap)** ops,bool * all_done,unsigned int i,operand_entry_t curr,operand_entry_t last)565e4b17023SJohn Marino eliminate_duplicate_pair (enum tree_code opcode,
566e4b17023SJohn Marino 			  VEC (operand_entry_t, heap) **ops,
567e4b17023SJohn Marino 			  bool *all_done,
568e4b17023SJohn Marino 			  unsigned int i,
569e4b17023SJohn Marino 			  operand_entry_t curr,
570e4b17023SJohn Marino 			  operand_entry_t last)
571e4b17023SJohn Marino {
572e4b17023SJohn Marino 
573e4b17023SJohn Marino   /* If we have two of the same op, and the opcode is & |, min, or max,
574e4b17023SJohn Marino      we can eliminate one of them.
575e4b17023SJohn Marino      If we have two of the same op, and the opcode is ^, we can
576e4b17023SJohn Marino      eliminate both of them.  */
577e4b17023SJohn Marino 
578e4b17023SJohn Marino   if (last && last->op == curr->op)
579e4b17023SJohn Marino     {
580e4b17023SJohn Marino       switch (opcode)
581e4b17023SJohn Marino 	{
582e4b17023SJohn Marino 	case MAX_EXPR:
583e4b17023SJohn Marino 	case MIN_EXPR:
584e4b17023SJohn Marino 	case BIT_IOR_EXPR:
585e4b17023SJohn Marino 	case BIT_AND_EXPR:
586e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
587e4b17023SJohn Marino 	    {
588e4b17023SJohn Marino 	      fprintf (dump_file, "Equivalence: ");
589e4b17023SJohn Marino 	      print_generic_expr (dump_file, curr->op, 0);
590e4b17023SJohn Marino 	      fprintf (dump_file, " [&|minmax] ");
591e4b17023SJohn Marino 	      print_generic_expr (dump_file, last->op, 0);
592e4b17023SJohn Marino 	      fprintf (dump_file, " -> ");
593e4b17023SJohn Marino 	      print_generic_stmt (dump_file, last->op, 0);
594e4b17023SJohn Marino 	    }
595e4b17023SJohn Marino 
596e4b17023SJohn Marino 	  VEC_ordered_remove (operand_entry_t, *ops, i);
597e4b17023SJohn Marino 	  reassociate_stats.ops_eliminated ++;
598e4b17023SJohn Marino 
599e4b17023SJohn Marino 	  return true;
600e4b17023SJohn Marino 
601e4b17023SJohn Marino 	case BIT_XOR_EXPR:
602e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
603e4b17023SJohn Marino 	    {
604e4b17023SJohn Marino 	      fprintf (dump_file, "Equivalence: ");
605e4b17023SJohn Marino 	      print_generic_expr (dump_file, curr->op, 0);
606e4b17023SJohn Marino 	      fprintf (dump_file, " ^ ");
607e4b17023SJohn Marino 	      print_generic_expr (dump_file, last->op, 0);
608e4b17023SJohn Marino 	      fprintf (dump_file, " -> nothing\n");
609e4b17023SJohn Marino 	    }
610e4b17023SJohn Marino 
611e4b17023SJohn Marino 	  reassociate_stats.ops_eliminated += 2;
612e4b17023SJohn Marino 
613e4b17023SJohn Marino 	  if (VEC_length (operand_entry_t, *ops) == 2)
614e4b17023SJohn Marino 	    {
615e4b17023SJohn Marino 	      VEC_free (operand_entry_t, heap, *ops);
616e4b17023SJohn Marino 	      *ops = NULL;
617e4b17023SJohn Marino 	      add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (last->op)));
618e4b17023SJohn Marino 	      *all_done = true;
619e4b17023SJohn Marino 	    }
620e4b17023SJohn Marino 	  else
621e4b17023SJohn Marino 	    {
622e4b17023SJohn Marino 	      VEC_ordered_remove (operand_entry_t, *ops, i-1);
623e4b17023SJohn Marino 	      VEC_ordered_remove (operand_entry_t, *ops, i-1);
624e4b17023SJohn Marino 	    }
625e4b17023SJohn Marino 
626e4b17023SJohn Marino 	  return true;
627e4b17023SJohn Marino 
628e4b17023SJohn Marino 	default:
629e4b17023SJohn Marino 	  break;
630e4b17023SJohn Marino 	}
631e4b17023SJohn Marino     }
632e4b17023SJohn Marino   return false;
633e4b17023SJohn Marino }
634e4b17023SJohn Marino 
VEC(tree,heap)635e4b17023SJohn Marino static VEC(tree, heap) *plus_negates;
636e4b17023SJohn Marino 
637e4b17023SJohn Marino /* If OPCODE is PLUS_EXPR, CURR->OP is a negate expression or a bitwise not
638e4b17023SJohn Marino    expression, look in OPS for a corresponding positive operation to cancel
639e4b17023SJohn Marino    it out.  If we find one, remove the other from OPS, replace
640e4b17023SJohn Marino    OPS[CURRINDEX] with 0 or -1, respectively, and return true.  Otherwise,
641e4b17023SJohn Marino    return false. */
642e4b17023SJohn Marino 
643e4b17023SJohn Marino static bool
644e4b17023SJohn Marino eliminate_plus_minus_pair (enum tree_code opcode,
645e4b17023SJohn Marino 			   VEC (operand_entry_t, heap) **ops,
646e4b17023SJohn Marino 			   unsigned int currindex,
647e4b17023SJohn Marino 			   operand_entry_t curr)
648e4b17023SJohn Marino {
649e4b17023SJohn Marino   tree negateop;
650e4b17023SJohn Marino   tree notop;
651e4b17023SJohn Marino   unsigned int i;
652e4b17023SJohn Marino   operand_entry_t oe;
653e4b17023SJohn Marino 
654e4b17023SJohn Marino   if (opcode != PLUS_EXPR || TREE_CODE (curr->op) != SSA_NAME)
655e4b17023SJohn Marino     return false;
656e4b17023SJohn Marino 
657e4b17023SJohn Marino   negateop = get_unary_op (curr->op, NEGATE_EXPR);
658e4b17023SJohn Marino   notop = get_unary_op (curr->op, BIT_NOT_EXPR);
659e4b17023SJohn Marino   if (negateop == NULL_TREE && notop == NULL_TREE)
660e4b17023SJohn Marino     return false;
661e4b17023SJohn Marino 
662e4b17023SJohn Marino   /* Any non-negated version will have a rank that is one less than
663e4b17023SJohn Marino      the current rank.  So once we hit those ranks, if we don't find
664e4b17023SJohn Marino      one, we can stop.  */
665e4b17023SJohn Marino 
666e4b17023SJohn Marino   for (i = currindex + 1;
667e4b17023SJohn Marino        VEC_iterate (operand_entry_t, *ops, i, oe)
668e4b17023SJohn Marino        && oe->rank >= curr->rank - 1 ;
669e4b17023SJohn Marino        i++)
670e4b17023SJohn Marino     {
671e4b17023SJohn Marino       if (oe->op == negateop)
672e4b17023SJohn Marino 	{
673e4b17023SJohn Marino 
674e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
675e4b17023SJohn Marino 	    {
676e4b17023SJohn Marino 	      fprintf (dump_file, "Equivalence: ");
677e4b17023SJohn Marino 	      print_generic_expr (dump_file, negateop, 0);
678e4b17023SJohn Marino 	      fprintf (dump_file, " + -");
679e4b17023SJohn Marino 	      print_generic_expr (dump_file, oe->op, 0);
680e4b17023SJohn Marino 	      fprintf (dump_file, " -> 0\n");
681e4b17023SJohn Marino 	    }
682e4b17023SJohn Marino 
683e4b17023SJohn Marino 	  VEC_ordered_remove (operand_entry_t, *ops, i);
684e4b17023SJohn Marino 	  add_to_ops_vec (ops, build_zero_cst (TREE_TYPE (oe->op)));
685e4b17023SJohn Marino 	  VEC_ordered_remove (operand_entry_t, *ops, currindex);
686e4b17023SJohn Marino 	  reassociate_stats.ops_eliminated ++;
687e4b17023SJohn Marino 
688e4b17023SJohn Marino 	  return true;
689e4b17023SJohn Marino 	}
690e4b17023SJohn Marino       else if (oe->op == notop)
691e4b17023SJohn Marino 	{
692e4b17023SJohn Marino 	  tree op_type = TREE_TYPE (oe->op);
693e4b17023SJohn Marino 
694e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
695e4b17023SJohn Marino 	    {
696e4b17023SJohn Marino 	      fprintf (dump_file, "Equivalence: ");
697e4b17023SJohn Marino 	      print_generic_expr (dump_file, notop, 0);
698e4b17023SJohn Marino 	      fprintf (dump_file, " + ~");
699e4b17023SJohn Marino 	      print_generic_expr (dump_file, oe->op, 0);
700e4b17023SJohn Marino 	      fprintf (dump_file, " -> -1\n");
701e4b17023SJohn Marino 	    }
702e4b17023SJohn Marino 
703e4b17023SJohn Marino 	  VEC_ordered_remove (operand_entry_t, *ops, i);
704e4b17023SJohn Marino 	  add_to_ops_vec (ops, build_int_cst_type (op_type, -1));
705e4b17023SJohn Marino 	  VEC_ordered_remove (operand_entry_t, *ops, currindex);
706e4b17023SJohn Marino 	  reassociate_stats.ops_eliminated ++;
707e4b17023SJohn Marino 
708e4b17023SJohn Marino 	  return true;
709e4b17023SJohn Marino 	}
710e4b17023SJohn Marino     }
711e4b17023SJohn Marino 
712e4b17023SJohn Marino   /* CURR->OP is a negate expr in a plus expr: save it for later
713e4b17023SJohn Marino      inspection in repropagate_negates().  */
714e4b17023SJohn Marino   if (negateop != NULL_TREE)
715e4b17023SJohn Marino     VEC_safe_push (tree, heap, plus_negates, curr->op);
716e4b17023SJohn Marino 
717e4b17023SJohn Marino   return false;
718e4b17023SJohn Marino }
719e4b17023SJohn Marino 
720e4b17023SJohn Marino /* If OPCODE is BIT_IOR_EXPR, BIT_AND_EXPR, and, CURR->OP is really a
721e4b17023SJohn Marino    bitwise not expression, look in OPS for a corresponding operand to
722e4b17023SJohn Marino    cancel it out.  If we find one, remove the other from OPS, replace
723e4b17023SJohn Marino    OPS[CURRINDEX] with 0, and return true.  Otherwise, return
724e4b17023SJohn Marino    false. */
725e4b17023SJohn Marino 
726e4b17023SJohn Marino static bool
eliminate_not_pairs(enum tree_code opcode,VEC (operand_entry_t,heap)** ops,unsigned int currindex,operand_entry_t curr)727e4b17023SJohn Marino eliminate_not_pairs (enum tree_code opcode,
728e4b17023SJohn Marino 		     VEC (operand_entry_t, heap) **ops,
729e4b17023SJohn Marino 		     unsigned int currindex,
730e4b17023SJohn Marino 		     operand_entry_t curr)
731e4b17023SJohn Marino {
732e4b17023SJohn Marino   tree notop;
733e4b17023SJohn Marino   unsigned int i;
734e4b17023SJohn Marino   operand_entry_t oe;
735e4b17023SJohn Marino 
736e4b17023SJohn Marino   if ((opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR)
737e4b17023SJohn Marino       || TREE_CODE (curr->op) != SSA_NAME)
738e4b17023SJohn Marino     return false;
739e4b17023SJohn Marino 
740e4b17023SJohn Marino   notop = get_unary_op (curr->op, BIT_NOT_EXPR);
741e4b17023SJohn Marino   if (notop == NULL_TREE)
742e4b17023SJohn Marino     return false;
743e4b17023SJohn Marino 
744e4b17023SJohn Marino   /* Any non-not version will have a rank that is one less than
745e4b17023SJohn Marino      the current rank.  So once we hit those ranks, if we don't find
746e4b17023SJohn Marino      one, we can stop.  */
747e4b17023SJohn Marino 
748e4b17023SJohn Marino   for (i = currindex + 1;
749e4b17023SJohn Marino        VEC_iterate (operand_entry_t, *ops, i, oe)
750e4b17023SJohn Marino        && oe->rank >= curr->rank - 1;
751e4b17023SJohn Marino        i++)
752e4b17023SJohn Marino     {
753e4b17023SJohn Marino       if (oe->op == notop)
754e4b17023SJohn Marino 	{
755e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
756e4b17023SJohn Marino 	    {
757e4b17023SJohn Marino 	      fprintf (dump_file, "Equivalence: ");
758e4b17023SJohn Marino 	      print_generic_expr (dump_file, notop, 0);
759e4b17023SJohn Marino 	      if (opcode == BIT_AND_EXPR)
760e4b17023SJohn Marino 		fprintf (dump_file, " & ~");
761e4b17023SJohn Marino 	      else if (opcode == BIT_IOR_EXPR)
762e4b17023SJohn Marino 		fprintf (dump_file, " | ~");
763e4b17023SJohn Marino 	      print_generic_expr (dump_file, oe->op, 0);
764e4b17023SJohn Marino 	      if (opcode == BIT_AND_EXPR)
765e4b17023SJohn Marino 		fprintf (dump_file, " -> 0\n");
766e4b17023SJohn Marino 	      else if (opcode == BIT_IOR_EXPR)
767e4b17023SJohn Marino 		fprintf (dump_file, " -> -1\n");
768e4b17023SJohn Marino 	    }
769e4b17023SJohn Marino 
770e4b17023SJohn Marino 	  if (opcode == BIT_AND_EXPR)
771e4b17023SJohn Marino 	    oe->op = build_zero_cst (TREE_TYPE (oe->op));
772e4b17023SJohn Marino 	  else if (opcode == BIT_IOR_EXPR)
773e4b17023SJohn Marino 	    oe->op = build_low_bits_mask (TREE_TYPE (oe->op),
774e4b17023SJohn Marino 					  TYPE_PRECISION (TREE_TYPE (oe->op)));
775e4b17023SJohn Marino 
776e4b17023SJohn Marino 	  reassociate_stats.ops_eliminated
777e4b17023SJohn Marino 	    += VEC_length (operand_entry_t, *ops) - 1;
778e4b17023SJohn Marino 	  VEC_free (operand_entry_t, heap, *ops);
779e4b17023SJohn Marino 	  *ops = NULL;
780e4b17023SJohn Marino 	  VEC_safe_push (operand_entry_t, heap, *ops, oe);
781e4b17023SJohn Marino 	  return true;
782e4b17023SJohn Marino 	}
783e4b17023SJohn Marino     }
784e4b17023SJohn Marino 
785e4b17023SJohn Marino   return false;
786e4b17023SJohn Marino }
787e4b17023SJohn Marino 
788e4b17023SJohn Marino /* Use constant value that may be present in OPS to try to eliminate
789e4b17023SJohn Marino    operands.  Note that this function is only really used when we've
790e4b17023SJohn Marino    eliminated ops for other reasons, or merged constants.  Across
791e4b17023SJohn Marino    single statements, fold already does all of this, plus more.  There
792e4b17023SJohn Marino    is little point in duplicating logic, so I've only included the
793e4b17023SJohn Marino    identities that I could ever construct testcases to trigger.  */
794e4b17023SJohn Marino 
795e4b17023SJohn Marino static void
eliminate_using_constants(enum tree_code opcode,VEC (operand_entry_t,heap)** ops)796e4b17023SJohn Marino eliminate_using_constants (enum tree_code opcode,
797e4b17023SJohn Marino 			   VEC(operand_entry_t, heap) **ops)
798e4b17023SJohn Marino {
799e4b17023SJohn Marino   operand_entry_t oelast = VEC_last (operand_entry_t, *ops);
800e4b17023SJohn Marino   tree type = TREE_TYPE (oelast->op);
801e4b17023SJohn Marino 
802e4b17023SJohn Marino   if (oelast->rank == 0
803e4b17023SJohn Marino       && (INTEGRAL_TYPE_P (type) || FLOAT_TYPE_P (type)))
804e4b17023SJohn Marino     {
805e4b17023SJohn Marino       switch (opcode)
806e4b17023SJohn Marino 	{
807e4b17023SJohn Marino 	case BIT_AND_EXPR:
808e4b17023SJohn Marino 	  if (integer_zerop (oelast->op))
809e4b17023SJohn Marino 	    {
810e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
811e4b17023SJohn Marino 		{
812e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
813e4b17023SJohn Marino 		    fprintf (dump_file, "Found & 0, removing all other ops\n");
814e4b17023SJohn Marino 
815e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated
816e4b17023SJohn Marino 		    += VEC_length (operand_entry_t, *ops) - 1;
817e4b17023SJohn Marino 
818e4b17023SJohn Marino 		  VEC_free (operand_entry_t, heap, *ops);
819e4b17023SJohn Marino 		  *ops = NULL;
820e4b17023SJohn Marino 		  VEC_safe_push (operand_entry_t, heap, *ops, oelast);
821e4b17023SJohn Marino 		  return;
822e4b17023SJohn Marino 		}
823e4b17023SJohn Marino 	    }
824e4b17023SJohn Marino 	  else if (integer_all_onesp (oelast->op))
825e4b17023SJohn Marino 	    {
826e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
827e4b17023SJohn Marino 		{
828e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
829e4b17023SJohn Marino 		    fprintf (dump_file, "Found & -1, removing\n");
830e4b17023SJohn Marino 		  VEC_pop (operand_entry_t, *ops);
831e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated++;
832e4b17023SJohn Marino 		}
833e4b17023SJohn Marino 	    }
834e4b17023SJohn Marino 	  break;
835e4b17023SJohn Marino 	case BIT_IOR_EXPR:
836e4b17023SJohn Marino 	  if (integer_all_onesp (oelast->op))
837e4b17023SJohn Marino 	    {
838e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
839e4b17023SJohn Marino 		{
840e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
841e4b17023SJohn Marino 		    fprintf (dump_file, "Found | -1, removing all other ops\n");
842e4b17023SJohn Marino 
843e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated
844e4b17023SJohn Marino 		    += VEC_length (operand_entry_t, *ops) - 1;
845e4b17023SJohn Marino 
846e4b17023SJohn Marino 		  VEC_free (operand_entry_t, heap, *ops);
847e4b17023SJohn Marino 		  *ops = NULL;
848e4b17023SJohn Marino 		  VEC_safe_push (operand_entry_t, heap, *ops, oelast);
849e4b17023SJohn Marino 		  return;
850e4b17023SJohn Marino 		}
851e4b17023SJohn Marino 	    }
852e4b17023SJohn Marino 	  else if (integer_zerop (oelast->op))
853e4b17023SJohn Marino 	    {
854e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
855e4b17023SJohn Marino 		{
856e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
857e4b17023SJohn Marino 		    fprintf (dump_file, "Found | 0, removing\n");
858e4b17023SJohn Marino 		  VEC_pop (operand_entry_t, *ops);
859e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated++;
860e4b17023SJohn Marino 		}
861e4b17023SJohn Marino 	    }
862e4b17023SJohn Marino 	  break;
863e4b17023SJohn Marino 	case MULT_EXPR:
864e4b17023SJohn Marino 	  if (integer_zerop (oelast->op)
865e4b17023SJohn Marino 	      || (FLOAT_TYPE_P (type)
866e4b17023SJohn Marino 		  && !HONOR_NANS (TYPE_MODE (type))
867e4b17023SJohn Marino 		  && !HONOR_SIGNED_ZEROS (TYPE_MODE (type))
868e4b17023SJohn Marino 		  && real_zerop (oelast->op)))
869e4b17023SJohn Marino 	    {
870e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
871e4b17023SJohn Marino 		{
872e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
873e4b17023SJohn Marino 		    fprintf (dump_file, "Found * 0, removing all other ops\n");
874e4b17023SJohn Marino 
875e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated
876e4b17023SJohn Marino 		    += VEC_length (operand_entry_t, *ops) - 1;
877e4b17023SJohn Marino 		  VEC_free (operand_entry_t, heap, *ops);
878e4b17023SJohn Marino 		  *ops = NULL;
879e4b17023SJohn Marino 		  VEC_safe_push (operand_entry_t, heap, *ops, oelast);
880e4b17023SJohn Marino 		  return;
881e4b17023SJohn Marino 		}
882e4b17023SJohn Marino 	    }
883e4b17023SJohn Marino 	  else if (integer_onep (oelast->op)
884e4b17023SJohn Marino 		   || (FLOAT_TYPE_P (type)
885e4b17023SJohn Marino 		       && !HONOR_SNANS (TYPE_MODE (type))
886e4b17023SJohn Marino 		       && real_onep (oelast->op)))
887e4b17023SJohn Marino 	    {
888e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
889e4b17023SJohn Marino 		{
890e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
891e4b17023SJohn Marino 		    fprintf (dump_file, "Found * 1, removing\n");
892e4b17023SJohn Marino 		  VEC_pop (operand_entry_t, *ops);
893e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated++;
894e4b17023SJohn Marino 		  return;
895e4b17023SJohn Marino 		}
896e4b17023SJohn Marino 	    }
897e4b17023SJohn Marino 	  break;
898e4b17023SJohn Marino 	case BIT_XOR_EXPR:
899e4b17023SJohn Marino 	case PLUS_EXPR:
900e4b17023SJohn Marino 	case MINUS_EXPR:
901e4b17023SJohn Marino 	  if (integer_zerop (oelast->op)
902e4b17023SJohn Marino 	      || (FLOAT_TYPE_P (type)
903e4b17023SJohn Marino 		  && (opcode == PLUS_EXPR || opcode == MINUS_EXPR)
904e4b17023SJohn Marino 		  && fold_real_zero_addition_p (type, oelast->op,
905e4b17023SJohn Marino 						opcode == MINUS_EXPR)))
906e4b17023SJohn Marino 	    {
907e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, *ops) != 1)
908e4b17023SJohn Marino 		{
909e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
910e4b17023SJohn Marino 		    fprintf (dump_file, "Found [|^+] 0, removing\n");
911e4b17023SJohn Marino 		  VEC_pop (operand_entry_t, *ops);
912e4b17023SJohn Marino 		  reassociate_stats.ops_eliminated++;
913e4b17023SJohn Marino 		  return;
914e4b17023SJohn Marino 		}
915e4b17023SJohn Marino 	    }
916e4b17023SJohn Marino 	  break;
917e4b17023SJohn Marino 	default:
918e4b17023SJohn Marino 	  break;
919e4b17023SJohn Marino 	}
920e4b17023SJohn Marino     }
921e4b17023SJohn Marino }
922e4b17023SJohn Marino 
923e4b17023SJohn Marino 
924e4b17023SJohn Marino static void linearize_expr_tree (VEC(operand_entry_t, heap) **, gimple,
925e4b17023SJohn Marino 				 bool, bool);
926e4b17023SJohn Marino 
927e4b17023SJohn Marino /* Structure for tracking and counting operands.  */
928e4b17023SJohn Marino typedef struct oecount_s {
929e4b17023SJohn Marino   int cnt;
930e4b17023SJohn Marino   int id;
931e4b17023SJohn Marino   enum tree_code oecode;
932e4b17023SJohn Marino   tree op;
933e4b17023SJohn Marino } oecount;
934e4b17023SJohn Marino 
935e4b17023SJohn Marino DEF_VEC_O(oecount);
936e4b17023SJohn Marino DEF_VEC_ALLOC_O(oecount,heap);
937e4b17023SJohn Marino 
938e4b17023SJohn Marino /* The heap for the oecount hashtable and the sorted list of operands.  */
VEC(oecount,heap)939e4b17023SJohn Marino static VEC (oecount, heap) *cvec;
940e4b17023SJohn Marino 
941e4b17023SJohn Marino /* Hash function for oecount.  */
942e4b17023SJohn Marino 
943e4b17023SJohn Marino static hashval_t
944e4b17023SJohn Marino oecount_hash (const void *p)
945e4b17023SJohn Marino {
946e4b17023SJohn Marino   const oecount *c = VEC_index (oecount, cvec, (size_t)p - 42);
947e4b17023SJohn Marino   return htab_hash_pointer (c->op) ^ (hashval_t)c->oecode;
948e4b17023SJohn Marino }
949e4b17023SJohn Marino 
950e4b17023SJohn Marino /* Comparison function for oecount.  */
951e4b17023SJohn Marino 
952e4b17023SJohn Marino static int
oecount_eq(const void * p1,const void * p2)953e4b17023SJohn Marino oecount_eq (const void *p1, const void *p2)
954e4b17023SJohn Marino {
955e4b17023SJohn Marino   const oecount *c1 = VEC_index (oecount, cvec, (size_t)p1 - 42);
956e4b17023SJohn Marino   const oecount *c2 = VEC_index (oecount, cvec, (size_t)p2 - 42);
957e4b17023SJohn Marino   return (c1->oecode == c2->oecode
958e4b17023SJohn Marino 	  && c1->op == c2->op);
959e4b17023SJohn Marino }
960e4b17023SJohn Marino 
961e4b17023SJohn Marino /* Comparison function for qsort sorting oecount elements by count.  */
962e4b17023SJohn Marino 
963e4b17023SJohn Marino static int
oecount_cmp(const void * p1,const void * p2)964e4b17023SJohn Marino oecount_cmp (const void *p1, const void *p2)
965e4b17023SJohn Marino {
966e4b17023SJohn Marino   const oecount *c1 = (const oecount *)p1;
967e4b17023SJohn Marino   const oecount *c2 = (const oecount *)p2;
968e4b17023SJohn Marino   if (c1->cnt != c2->cnt)
969e4b17023SJohn Marino     return c1->cnt - c2->cnt;
970e4b17023SJohn Marino   else
971e4b17023SJohn Marino     /* If counts are identical, use unique IDs to stabilize qsort.  */
972e4b17023SJohn Marino     return c1->id - c2->id;
973e4b17023SJohn Marino }
974e4b17023SJohn Marino 
975e4b17023SJohn Marino /* Walks the linear chain with result *DEF searching for an operation
976e4b17023SJohn Marino    with operand OP and code OPCODE removing that from the chain.  *DEF
977e4b17023SJohn Marino    is updated if there is only one operand but no operation left.  */
978e4b17023SJohn Marino 
979e4b17023SJohn Marino static void
zero_one_operation(tree * def,enum tree_code opcode,tree op)980e4b17023SJohn Marino zero_one_operation (tree *def, enum tree_code opcode, tree op)
981e4b17023SJohn Marino {
982e4b17023SJohn Marino   gimple stmt = SSA_NAME_DEF_STMT (*def);
983e4b17023SJohn Marino 
984e4b17023SJohn Marino   do
985e4b17023SJohn Marino     {
986e4b17023SJohn Marino       tree name = gimple_assign_rhs1 (stmt);
987e4b17023SJohn Marino 
988e4b17023SJohn Marino       /* If this is the operation we look for and one of the operands
989e4b17023SJohn Marino          is ours simply propagate the other operand into the stmts
990e4b17023SJohn Marino 	 single use.  */
991e4b17023SJohn Marino       if (gimple_assign_rhs_code (stmt) == opcode
992e4b17023SJohn Marino 	  && (name == op
993e4b17023SJohn Marino 	      || gimple_assign_rhs2 (stmt) == op))
994e4b17023SJohn Marino 	{
995e4b17023SJohn Marino 	  gimple use_stmt;
996e4b17023SJohn Marino 	  use_operand_p use;
997e4b17023SJohn Marino 	  gimple_stmt_iterator gsi;
998e4b17023SJohn Marino 	  if (name == op)
999e4b17023SJohn Marino 	    name = gimple_assign_rhs2 (stmt);
1000e4b17023SJohn Marino 	  gcc_assert (has_single_use (gimple_assign_lhs (stmt)));
1001e4b17023SJohn Marino 	  single_imm_use (gimple_assign_lhs (stmt), &use, &use_stmt);
1002e4b17023SJohn Marino 	  if (gimple_assign_lhs (stmt) == *def)
1003e4b17023SJohn Marino 	    *def = name;
1004e4b17023SJohn Marino 	  SET_USE (use, name);
1005e4b17023SJohn Marino 	  if (TREE_CODE (name) != SSA_NAME)
1006e4b17023SJohn Marino 	    update_stmt (use_stmt);
1007e4b17023SJohn Marino 	  gsi = gsi_for_stmt (stmt);
1008e4b17023SJohn Marino 	  gsi_remove (&gsi, true);
1009e4b17023SJohn Marino 	  release_defs (stmt);
1010e4b17023SJohn Marino 	  return;
1011e4b17023SJohn Marino 	}
1012e4b17023SJohn Marino 
1013e4b17023SJohn Marino       /* Continue walking the chain.  */
1014e4b17023SJohn Marino       gcc_assert (name != op
1015e4b17023SJohn Marino 		  && TREE_CODE (name) == SSA_NAME);
1016e4b17023SJohn Marino       stmt = SSA_NAME_DEF_STMT (name);
1017e4b17023SJohn Marino     }
1018e4b17023SJohn Marino   while (1);
1019e4b17023SJohn Marino }
1020e4b17023SJohn Marino 
1021e4b17023SJohn Marino /* Builds one statement performing OP1 OPCODE OP2 using TMPVAR for
1022e4b17023SJohn Marino    the result.  Places the statement after the definition of either
1023e4b17023SJohn Marino    OP1 or OP2.  Returns the new statement.  */
1024e4b17023SJohn Marino 
1025e4b17023SJohn Marino static gimple
build_and_add_sum(tree tmpvar,tree op1,tree op2,enum tree_code opcode)1026e4b17023SJohn Marino build_and_add_sum (tree tmpvar, tree op1, tree op2, enum tree_code opcode)
1027e4b17023SJohn Marino {
1028e4b17023SJohn Marino   gimple op1def = NULL, op2def = NULL;
1029e4b17023SJohn Marino   gimple_stmt_iterator gsi;
1030e4b17023SJohn Marino   tree op;
1031e4b17023SJohn Marino   gimple sum;
1032e4b17023SJohn Marino 
1033e4b17023SJohn Marino   /* Create the addition statement.  */
1034e4b17023SJohn Marino   sum = gimple_build_assign_with_ops (opcode, tmpvar, op1, op2);
1035e4b17023SJohn Marino   op = make_ssa_name (tmpvar, sum);
1036e4b17023SJohn Marino   gimple_assign_set_lhs (sum, op);
1037e4b17023SJohn Marino 
1038e4b17023SJohn Marino   /* Find an insertion place and insert.  */
1039e4b17023SJohn Marino   if (TREE_CODE (op1) == SSA_NAME)
1040e4b17023SJohn Marino     op1def = SSA_NAME_DEF_STMT (op1);
1041e4b17023SJohn Marino   if (TREE_CODE (op2) == SSA_NAME)
1042e4b17023SJohn Marino     op2def = SSA_NAME_DEF_STMT (op2);
1043e4b17023SJohn Marino   if ((!op1def || gimple_nop_p (op1def))
1044e4b17023SJohn Marino       && (!op2def || gimple_nop_p (op2def)))
1045e4b17023SJohn Marino     {
1046e4b17023SJohn Marino       gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
1047e4b17023SJohn Marino       gsi_insert_before (&gsi, sum, GSI_NEW_STMT);
1048e4b17023SJohn Marino     }
1049e4b17023SJohn Marino   else if ((!op1def || gimple_nop_p (op1def))
1050e4b17023SJohn Marino 	   || (op2def && !gimple_nop_p (op2def)
1051e4b17023SJohn Marino 	       && stmt_dominates_stmt_p (op1def, op2def)))
1052e4b17023SJohn Marino     {
1053e4b17023SJohn Marino       if (gimple_code (op2def) == GIMPLE_PHI)
1054e4b17023SJohn Marino 	{
1055e4b17023SJohn Marino 	  gsi = gsi_after_labels (gimple_bb (op2def));
1056e4b17023SJohn Marino 	  gsi_insert_before (&gsi, sum, GSI_NEW_STMT);
1057e4b17023SJohn Marino 	}
1058e4b17023SJohn Marino       else
1059e4b17023SJohn Marino 	{
1060e4b17023SJohn Marino 	  if (!stmt_ends_bb_p (op2def))
1061e4b17023SJohn Marino 	    {
1062e4b17023SJohn Marino 	      gsi = gsi_for_stmt (op2def);
1063e4b17023SJohn Marino 	      gsi_insert_after (&gsi, sum, GSI_NEW_STMT);
1064e4b17023SJohn Marino 	    }
1065e4b17023SJohn Marino 	  else
1066e4b17023SJohn Marino 	    {
1067e4b17023SJohn Marino 	      edge e;
1068e4b17023SJohn Marino 	      edge_iterator ei;
1069e4b17023SJohn Marino 
1070e4b17023SJohn Marino 	      FOR_EACH_EDGE (e, ei, gimple_bb (op2def)->succs)
1071e4b17023SJohn Marino 		if (e->flags & EDGE_FALLTHRU)
1072e4b17023SJohn Marino 		  gsi_insert_on_edge_immediate (e, sum);
1073e4b17023SJohn Marino 	    }
1074e4b17023SJohn Marino 	}
1075e4b17023SJohn Marino     }
1076e4b17023SJohn Marino   else
1077e4b17023SJohn Marino     {
1078e4b17023SJohn Marino       if (gimple_code (op1def) == GIMPLE_PHI)
1079e4b17023SJohn Marino 	{
1080e4b17023SJohn Marino 	  gsi = gsi_after_labels (gimple_bb (op1def));
1081e4b17023SJohn Marino 	  gsi_insert_before (&gsi, sum, GSI_NEW_STMT);
1082e4b17023SJohn Marino 	}
1083e4b17023SJohn Marino       else
1084e4b17023SJohn Marino 	{
1085e4b17023SJohn Marino 	  if (!stmt_ends_bb_p (op1def))
1086e4b17023SJohn Marino 	    {
1087e4b17023SJohn Marino 	      gsi = gsi_for_stmt (op1def);
1088e4b17023SJohn Marino 	      gsi_insert_after (&gsi, sum, GSI_NEW_STMT);
1089e4b17023SJohn Marino 	    }
1090e4b17023SJohn Marino 	  else
1091e4b17023SJohn Marino 	    {
1092e4b17023SJohn Marino 	      edge e;
1093e4b17023SJohn Marino 	      edge_iterator ei;
1094e4b17023SJohn Marino 
1095e4b17023SJohn Marino 	      FOR_EACH_EDGE (e, ei, gimple_bb (op1def)->succs)
1096e4b17023SJohn Marino 		if (e->flags & EDGE_FALLTHRU)
1097e4b17023SJohn Marino 		  gsi_insert_on_edge_immediate (e, sum);
1098e4b17023SJohn Marino 	    }
1099e4b17023SJohn Marino 	}
1100e4b17023SJohn Marino     }
1101e4b17023SJohn Marino   update_stmt (sum);
1102e4b17023SJohn Marino 
1103e4b17023SJohn Marino   return sum;
1104e4b17023SJohn Marino }
1105e4b17023SJohn Marino 
1106e4b17023SJohn Marino /* Perform un-distribution of divisions and multiplications.
1107e4b17023SJohn Marino    A * X + B * X is transformed into (A + B) * X and A / X + B / X
1108e4b17023SJohn Marino    to (A + B) / X for real X.
1109e4b17023SJohn Marino 
1110e4b17023SJohn Marino    The algorithm is organized as follows.
1111e4b17023SJohn Marino 
1112e4b17023SJohn Marino     - First we walk the addition chain *OPS looking for summands that
1113e4b17023SJohn Marino       are defined by a multiplication or a real division.  This results
1114e4b17023SJohn Marino       in the candidates bitmap with relevant indices into *OPS.
1115e4b17023SJohn Marino 
1116e4b17023SJohn Marino     - Second we build the chains of multiplications or divisions for
1117e4b17023SJohn Marino       these candidates, counting the number of occurences of (operand, code)
1118e4b17023SJohn Marino       pairs in all of the candidates chains.
1119e4b17023SJohn Marino 
1120e4b17023SJohn Marino     - Third we sort the (operand, code) pairs by number of occurence and
1121e4b17023SJohn Marino       process them starting with the pair with the most uses.
1122e4b17023SJohn Marino 
1123e4b17023SJohn Marino       * For each such pair we walk the candidates again to build a
1124e4b17023SJohn Marino         second candidate bitmap noting all multiplication/division chains
1125e4b17023SJohn Marino 	that have at least one occurence of (operand, code).
1126e4b17023SJohn Marino 
1127e4b17023SJohn Marino       * We build an alternate addition chain only covering these
1128e4b17023SJohn Marino         candidates with one (operand, code) operation removed from their
1129e4b17023SJohn Marino 	multiplication/division chain.
1130e4b17023SJohn Marino 
1131e4b17023SJohn Marino       * The first candidate gets replaced by the alternate addition chain
1132e4b17023SJohn Marino         multiplied/divided by the operand.
1133e4b17023SJohn Marino 
1134e4b17023SJohn Marino       * All candidate chains get disabled for further processing and
1135e4b17023SJohn Marino         processing of (operand, code) pairs continues.
1136e4b17023SJohn Marino 
1137e4b17023SJohn Marino   The alternate addition chains built are re-processed by the main
1138e4b17023SJohn Marino   reassociation algorithm which allows optimizing a * x * y + b * y * x
1139e4b17023SJohn Marino   to (a + b ) * x * y in one invocation of the reassociation pass.  */
1140e4b17023SJohn Marino 
1141e4b17023SJohn Marino static bool
undistribute_ops_list(enum tree_code opcode,VEC (operand_entry_t,heap)** ops,struct loop * loop)1142e4b17023SJohn Marino undistribute_ops_list (enum tree_code opcode,
1143e4b17023SJohn Marino 		       VEC (operand_entry_t, heap) **ops, struct loop *loop)
1144e4b17023SJohn Marino {
1145e4b17023SJohn Marino   unsigned int length = VEC_length (operand_entry_t, *ops);
1146e4b17023SJohn Marino   operand_entry_t oe1;
1147e4b17023SJohn Marino   unsigned i, j;
1148e4b17023SJohn Marino   sbitmap candidates, candidates2;
1149e4b17023SJohn Marino   unsigned nr_candidates, nr_candidates2;
1150e4b17023SJohn Marino   sbitmap_iterator sbi0;
1151e4b17023SJohn Marino   VEC (operand_entry_t, heap) **subops;
1152e4b17023SJohn Marino   htab_t ctable;
1153e4b17023SJohn Marino   bool changed = false;
1154e4b17023SJohn Marino   int next_oecount_id = 0;
1155e4b17023SJohn Marino 
1156e4b17023SJohn Marino   if (length <= 1
1157e4b17023SJohn Marino       || opcode != PLUS_EXPR)
1158e4b17023SJohn Marino     return false;
1159e4b17023SJohn Marino 
1160e4b17023SJohn Marino   /* Build a list of candidates to process.  */
1161e4b17023SJohn Marino   candidates = sbitmap_alloc (length);
1162e4b17023SJohn Marino   sbitmap_zero (candidates);
1163e4b17023SJohn Marino   nr_candidates = 0;
1164e4b17023SJohn Marino   FOR_EACH_VEC_ELT (operand_entry_t, *ops, i, oe1)
1165e4b17023SJohn Marino     {
1166e4b17023SJohn Marino       enum tree_code dcode;
1167e4b17023SJohn Marino       gimple oe1def;
1168e4b17023SJohn Marino 
1169e4b17023SJohn Marino       if (TREE_CODE (oe1->op) != SSA_NAME)
1170e4b17023SJohn Marino 	continue;
1171e4b17023SJohn Marino       oe1def = SSA_NAME_DEF_STMT (oe1->op);
1172e4b17023SJohn Marino       if (!is_gimple_assign (oe1def))
1173e4b17023SJohn Marino 	continue;
1174e4b17023SJohn Marino       dcode = gimple_assign_rhs_code (oe1def);
1175e4b17023SJohn Marino       if ((dcode != MULT_EXPR
1176e4b17023SJohn Marino 	   && dcode != RDIV_EXPR)
1177e4b17023SJohn Marino 	  || !is_reassociable_op (oe1def, dcode, loop))
1178e4b17023SJohn Marino 	continue;
1179e4b17023SJohn Marino 
1180e4b17023SJohn Marino       SET_BIT (candidates, i);
1181e4b17023SJohn Marino       nr_candidates++;
1182e4b17023SJohn Marino     }
1183e4b17023SJohn Marino 
1184e4b17023SJohn Marino   if (nr_candidates < 2)
1185e4b17023SJohn Marino     {
1186e4b17023SJohn Marino       sbitmap_free (candidates);
1187e4b17023SJohn Marino       return false;
1188e4b17023SJohn Marino     }
1189e4b17023SJohn Marino 
1190e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
1191e4b17023SJohn Marino     {
1192e4b17023SJohn Marino       fprintf (dump_file, "searching for un-distribute opportunities ");
1193e4b17023SJohn Marino       print_generic_expr (dump_file,
1194e4b17023SJohn Marino 	VEC_index (operand_entry_t, *ops,
1195e4b17023SJohn Marino 		   sbitmap_first_set_bit (candidates))->op, 0);
1196e4b17023SJohn Marino       fprintf (dump_file, " %d\n", nr_candidates);
1197e4b17023SJohn Marino     }
1198e4b17023SJohn Marino 
1199e4b17023SJohn Marino   /* Build linearized sub-operand lists and the counting table.  */
1200e4b17023SJohn Marino   cvec = NULL;
1201e4b17023SJohn Marino   ctable = htab_create (15, oecount_hash, oecount_eq, NULL);
1202e4b17023SJohn Marino   subops = XCNEWVEC (VEC (operand_entry_t, heap) *,
1203e4b17023SJohn Marino 		     VEC_length (operand_entry_t, *ops));
1204e4b17023SJohn Marino   EXECUTE_IF_SET_IN_SBITMAP (candidates, 0, i, sbi0)
1205e4b17023SJohn Marino     {
1206e4b17023SJohn Marino       gimple oedef;
1207e4b17023SJohn Marino       enum tree_code oecode;
1208e4b17023SJohn Marino       unsigned j;
1209e4b17023SJohn Marino 
1210e4b17023SJohn Marino       oedef = SSA_NAME_DEF_STMT (VEC_index (operand_entry_t, *ops, i)->op);
1211e4b17023SJohn Marino       oecode = gimple_assign_rhs_code (oedef);
1212e4b17023SJohn Marino       linearize_expr_tree (&subops[i], oedef,
1213e4b17023SJohn Marino 			   associative_tree_code (oecode), false);
1214e4b17023SJohn Marino 
1215e4b17023SJohn Marino       FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1)
1216e4b17023SJohn Marino 	{
1217e4b17023SJohn Marino 	  oecount c;
1218e4b17023SJohn Marino 	  void **slot;
1219e4b17023SJohn Marino 	  size_t idx;
1220e4b17023SJohn Marino 	  c.oecode = oecode;
1221e4b17023SJohn Marino 	  c.cnt = 1;
1222e4b17023SJohn Marino 	  c.id = next_oecount_id++;
1223e4b17023SJohn Marino 	  c.op = oe1->op;
1224e4b17023SJohn Marino 	  VEC_safe_push (oecount, heap, cvec, &c);
1225e4b17023SJohn Marino 	  idx = VEC_length (oecount, cvec) + 41;
1226e4b17023SJohn Marino 	  slot = htab_find_slot (ctable, (void *)idx, INSERT);
1227e4b17023SJohn Marino 	  if (!*slot)
1228e4b17023SJohn Marino 	    {
1229e4b17023SJohn Marino 	      *slot = (void *)idx;
1230e4b17023SJohn Marino 	    }
1231e4b17023SJohn Marino 	  else
1232e4b17023SJohn Marino 	    {
1233e4b17023SJohn Marino 	      VEC_pop (oecount, cvec);
1234e4b17023SJohn Marino 	      VEC_index (oecount, cvec, (size_t)*slot - 42)->cnt++;
1235e4b17023SJohn Marino 	    }
1236e4b17023SJohn Marino 	}
1237e4b17023SJohn Marino     }
1238e4b17023SJohn Marino   htab_delete (ctable);
1239e4b17023SJohn Marino 
1240e4b17023SJohn Marino   /* Sort the counting table.  */
1241e4b17023SJohn Marino   VEC_qsort (oecount, cvec, oecount_cmp);
1242e4b17023SJohn Marino 
1243e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
1244e4b17023SJohn Marino     {
1245e4b17023SJohn Marino       oecount *c;
1246e4b17023SJohn Marino       fprintf (dump_file, "Candidates:\n");
1247e4b17023SJohn Marino       FOR_EACH_VEC_ELT (oecount, cvec, j, c)
1248e4b17023SJohn Marino 	{
1249e4b17023SJohn Marino 	  fprintf (dump_file, "  %u %s: ", c->cnt,
1250e4b17023SJohn Marino 		   c->oecode == MULT_EXPR
1251e4b17023SJohn Marino 		   ? "*" : c->oecode == RDIV_EXPR ? "/" : "?");
1252e4b17023SJohn Marino 	  print_generic_expr (dump_file, c->op, 0);
1253e4b17023SJohn Marino 	  fprintf (dump_file, "\n");
1254e4b17023SJohn Marino 	}
1255e4b17023SJohn Marino     }
1256e4b17023SJohn Marino 
1257e4b17023SJohn Marino   /* Process the (operand, code) pairs in order of most occurence.  */
1258e4b17023SJohn Marino   candidates2 = sbitmap_alloc (length);
1259e4b17023SJohn Marino   while (!VEC_empty (oecount, cvec))
1260e4b17023SJohn Marino     {
1261e4b17023SJohn Marino       oecount *c = VEC_last (oecount, cvec);
1262e4b17023SJohn Marino       if (c->cnt < 2)
1263e4b17023SJohn Marino 	break;
1264e4b17023SJohn Marino 
1265e4b17023SJohn Marino       /* Now collect the operands in the outer chain that contain
1266e4b17023SJohn Marino          the common operand in their inner chain.  */
1267e4b17023SJohn Marino       sbitmap_zero (candidates2);
1268e4b17023SJohn Marino       nr_candidates2 = 0;
1269e4b17023SJohn Marino       EXECUTE_IF_SET_IN_SBITMAP (candidates, 0, i, sbi0)
1270e4b17023SJohn Marino 	{
1271e4b17023SJohn Marino 	  gimple oedef;
1272e4b17023SJohn Marino 	  enum tree_code oecode;
1273e4b17023SJohn Marino 	  unsigned j;
1274e4b17023SJohn Marino 	  tree op = VEC_index (operand_entry_t, *ops, i)->op;
1275e4b17023SJohn Marino 
1276e4b17023SJohn Marino 	  /* If we undistributed in this chain already this may be
1277e4b17023SJohn Marino 	     a constant.  */
1278e4b17023SJohn Marino 	  if (TREE_CODE (op) != SSA_NAME)
1279e4b17023SJohn Marino 	    continue;
1280e4b17023SJohn Marino 
1281e4b17023SJohn Marino 	  oedef = SSA_NAME_DEF_STMT (op);
1282e4b17023SJohn Marino 	  oecode = gimple_assign_rhs_code (oedef);
1283e4b17023SJohn Marino 	  if (oecode != c->oecode)
1284e4b17023SJohn Marino 	    continue;
1285e4b17023SJohn Marino 
1286e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1)
1287e4b17023SJohn Marino 	    {
1288e4b17023SJohn Marino 	      if (oe1->op == c->op)
1289e4b17023SJohn Marino 		{
1290e4b17023SJohn Marino 		  SET_BIT (candidates2, i);
1291e4b17023SJohn Marino 		  ++nr_candidates2;
1292e4b17023SJohn Marino 		  break;
1293e4b17023SJohn Marino 		}
1294e4b17023SJohn Marino 	    }
1295e4b17023SJohn Marino 	}
1296e4b17023SJohn Marino 
1297e4b17023SJohn Marino       if (nr_candidates2 >= 2)
1298e4b17023SJohn Marino 	{
1299e4b17023SJohn Marino 	  operand_entry_t oe1, oe2;
1300e4b17023SJohn Marino 	  tree tmpvar;
1301e4b17023SJohn Marino 	  gimple prod;
1302e4b17023SJohn Marino 	  int first = sbitmap_first_set_bit (candidates2);
1303e4b17023SJohn Marino 
1304e4b17023SJohn Marino 	  /* Build the new addition chain.  */
1305e4b17023SJohn Marino 	  oe1 = VEC_index (operand_entry_t, *ops, first);
1306e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
1307e4b17023SJohn Marino 	    {
1308e4b17023SJohn Marino 	      fprintf (dump_file, "Building (");
1309e4b17023SJohn Marino 	      print_generic_expr (dump_file, oe1->op, 0);
1310e4b17023SJohn Marino 	    }
1311e4b17023SJohn Marino 	  tmpvar = create_tmp_reg (TREE_TYPE (oe1->op), NULL);
1312e4b17023SJohn Marino 	  add_referenced_var (tmpvar);
1313e4b17023SJohn Marino 	  zero_one_operation (&oe1->op, c->oecode, c->op);
1314e4b17023SJohn Marino 	  EXECUTE_IF_SET_IN_SBITMAP (candidates2, first+1, i, sbi0)
1315e4b17023SJohn Marino 	    {
1316e4b17023SJohn Marino 	      gimple sum;
1317e4b17023SJohn Marino 	      oe2 = VEC_index (operand_entry_t, *ops, i);
1318e4b17023SJohn Marino 	      if (dump_file && (dump_flags & TDF_DETAILS))
1319e4b17023SJohn Marino 		{
1320e4b17023SJohn Marino 		  fprintf (dump_file, " + ");
1321e4b17023SJohn Marino 		  print_generic_expr (dump_file, oe2->op, 0);
1322e4b17023SJohn Marino 		}
1323e4b17023SJohn Marino 	      zero_one_operation (&oe2->op, c->oecode, c->op);
1324e4b17023SJohn Marino 	      sum = build_and_add_sum (tmpvar, oe1->op, oe2->op, opcode);
1325e4b17023SJohn Marino 	      oe2->op = build_zero_cst (TREE_TYPE (oe2->op));
1326e4b17023SJohn Marino 	      oe2->rank = 0;
1327e4b17023SJohn Marino 	      oe1->op = gimple_get_lhs (sum);
1328e4b17023SJohn Marino 	    }
1329e4b17023SJohn Marino 
1330e4b17023SJohn Marino 	  /* Apply the multiplication/division.  */
1331e4b17023SJohn Marino 	  prod = build_and_add_sum (tmpvar, oe1->op, c->op, c->oecode);
1332e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
1333e4b17023SJohn Marino 	    {
1334e4b17023SJohn Marino 	      fprintf (dump_file, ") %s ", c->oecode == MULT_EXPR ? "*" : "/");
1335e4b17023SJohn Marino 	      print_generic_expr (dump_file, c->op, 0);
1336e4b17023SJohn Marino 	      fprintf (dump_file, "\n");
1337e4b17023SJohn Marino 	    }
1338e4b17023SJohn Marino 
1339e4b17023SJohn Marino 	  /* Record it in the addition chain and disable further
1340e4b17023SJohn Marino 	     undistribution with this op.  */
1341e4b17023SJohn Marino 	  oe1->op = gimple_assign_lhs (prod);
1342e4b17023SJohn Marino 	  oe1->rank = get_rank (oe1->op);
1343e4b17023SJohn Marino 	  VEC_free (operand_entry_t, heap, subops[first]);
1344e4b17023SJohn Marino 
1345e4b17023SJohn Marino 	  changed = true;
1346e4b17023SJohn Marino 	}
1347e4b17023SJohn Marino 
1348e4b17023SJohn Marino       VEC_pop (oecount, cvec);
1349e4b17023SJohn Marino     }
1350e4b17023SJohn Marino 
1351e4b17023SJohn Marino   for (i = 0; i < VEC_length (operand_entry_t, *ops); ++i)
1352e4b17023SJohn Marino     VEC_free (operand_entry_t, heap, subops[i]);
1353e4b17023SJohn Marino   free (subops);
1354e4b17023SJohn Marino   VEC_free (oecount, heap, cvec);
1355e4b17023SJohn Marino   sbitmap_free (candidates);
1356e4b17023SJohn Marino   sbitmap_free (candidates2);
1357e4b17023SJohn Marino 
1358e4b17023SJohn Marino   return changed;
1359e4b17023SJohn Marino }
1360e4b17023SJohn Marino 
1361e4b17023SJohn Marino /* If OPCODE is BIT_IOR_EXPR or BIT_AND_EXPR and CURR is a comparison
1362e4b17023SJohn Marino    expression, examine the other OPS to see if any of them are comparisons
1363e4b17023SJohn Marino    of the same values, which we may be able to combine or eliminate.
1364e4b17023SJohn Marino    For example, we can rewrite (a < b) | (a == b) as (a <= b).  */
1365e4b17023SJohn Marino 
1366e4b17023SJohn Marino static bool
eliminate_redundant_comparison(enum tree_code opcode,VEC (operand_entry_t,heap)** ops,unsigned int currindex,operand_entry_t curr)1367e4b17023SJohn Marino eliminate_redundant_comparison (enum tree_code opcode,
1368e4b17023SJohn Marino 				VEC (operand_entry_t, heap) **ops,
1369e4b17023SJohn Marino 				unsigned int currindex,
1370e4b17023SJohn Marino 				operand_entry_t curr)
1371e4b17023SJohn Marino {
1372e4b17023SJohn Marino   tree op1, op2;
1373e4b17023SJohn Marino   enum tree_code lcode, rcode;
1374e4b17023SJohn Marino   gimple def1, def2;
1375e4b17023SJohn Marino   int i;
1376e4b17023SJohn Marino   operand_entry_t oe;
1377e4b17023SJohn Marino 
1378e4b17023SJohn Marino   if (opcode != BIT_IOR_EXPR && opcode != BIT_AND_EXPR)
1379e4b17023SJohn Marino     return false;
1380e4b17023SJohn Marino 
1381e4b17023SJohn Marino   /* Check that CURR is a comparison.  */
1382e4b17023SJohn Marino   if (TREE_CODE (curr->op) != SSA_NAME)
1383e4b17023SJohn Marino     return false;
1384e4b17023SJohn Marino   def1 = SSA_NAME_DEF_STMT (curr->op);
1385e4b17023SJohn Marino   if (!is_gimple_assign (def1))
1386e4b17023SJohn Marino     return false;
1387e4b17023SJohn Marino   lcode = gimple_assign_rhs_code (def1);
1388e4b17023SJohn Marino   if (TREE_CODE_CLASS (lcode) != tcc_comparison)
1389e4b17023SJohn Marino     return false;
1390e4b17023SJohn Marino   op1 = gimple_assign_rhs1 (def1);
1391e4b17023SJohn Marino   op2 = gimple_assign_rhs2 (def1);
1392e4b17023SJohn Marino 
1393e4b17023SJohn Marino   /* Now look for a similar comparison in the remaining OPS.  */
1394e4b17023SJohn Marino   for (i = currindex + 1;
1395e4b17023SJohn Marino        VEC_iterate (operand_entry_t, *ops, i, oe);
1396e4b17023SJohn Marino        i++)
1397e4b17023SJohn Marino     {
1398e4b17023SJohn Marino       tree t;
1399e4b17023SJohn Marino 
1400e4b17023SJohn Marino       if (TREE_CODE (oe->op) != SSA_NAME)
1401e4b17023SJohn Marino 	continue;
1402e4b17023SJohn Marino       def2 = SSA_NAME_DEF_STMT (oe->op);
1403e4b17023SJohn Marino       if (!is_gimple_assign (def2))
1404e4b17023SJohn Marino 	continue;
1405e4b17023SJohn Marino       rcode = gimple_assign_rhs_code (def2);
1406e4b17023SJohn Marino       if (TREE_CODE_CLASS (rcode) != tcc_comparison)
1407e4b17023SJohn Marino 	continue;
1408e4b17023SJohn Marino 
1409e4b17023SJohn Marino       /* If we got here, we have a match.  See if we can combine the
1410e4b17023SJohn Marino 	 two comparisons.  */
1411e4b17023SJohn Marino       if (opcode == BIT_IOR_EXPR)
1412e4b17023SJohn Marino 	t = maybe_fold_or_comparisons (lcode, op1, op2,
1413e4b17023SJohn Marino 				       rcode, gimple_assign_rhs1 (def2),
1414e4b17023SJohn Marino 				       gimple_assign_rhs2 (def2));
1415e4b17023SJohn Marino       else
1416e4b17023SJohn Marino 	t = maybe_fold_and_comparisons (lcode, op1, op2,
1417e4b17023SJohn Marino 					rcode, gimple_assign_rhs1 (def2),
1418e4b17023SJohn Marino 					gimple_assign_rhs2 (def2));
1419e4b17023SJohn Marino       if (!t)
1420e4b17023SJohn Marino 	continue;
1421e4b17023SJohn Marino 
1422e4b17023SJohn Marino       /* maybe_fold_and_comparisons and maybe_fold_or_comparisons
1423e4b17023SJohn Marino 	 always give us a boolean_type_node value back.  If the original
1424e4b17023SJohn Marino 	 BIT_AND_EXPR or BIT_IOR_EXPR was of a wider integer type,
1425e4b17023SJohn Marino 	 we need to convert.  */
1426e4b17023SJohn Marino       if (!useless_type_conversion_p (TREE_TYPE (curr->op), TREE_TYPE (t)))
1427e4b17023SJohn Marino 	t = fold_convert (TREE_TYPE (curr->op), t);
1428e4b17023SJohn Marino 
1429e4b17023SJohn Marino       if (TREE_CODE (t) != INTEGER_CST
1430e4b17023SJohn Marino 	  && !operand_equal_p (t, curr->op, 0))
1431e4b17023SJohn Marino 	{
1432e4b17023SJohn Marino 	  enum tree_code subcode;
1433e4b17023SJohn Marino 	  tree newop1, newop2;
1434e4b17023SJohn Marino 	  if (!COMPARISON_CLASS_P (t))
1435e4b17023SJohn Marino 	    continue;
1436e4b17023SJohn Marino 	  extract_ops_from_tree (t, &subcode, &newop1, &newop2);
1437e4b17023SJohn Marino 	  STRIP_USELESS_TYPE_CONVERSION (newop1);
1438e4b17023SJohn Marino 	  STRIP_USELESS_TYPE_CONVERSION (newop2);
1439e4b17023SJohn Marino 	  if (!is_gimple_val (newop1) || !is_gimple_val (newop2))
1440e4b17023SJohn Marino 	    continue;
1441e4b17023SJohn Marino 	}
1442e4b17023SJohn Marino 
1443e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
1444e4b17023SJohn Marino 	{
1445e4b17023SJohn Marino 	  fprintf (dump_file, "Equivalence: ");
1446e4b17023SJohn Marino 	  print_generic_expr (dump_file, curr->op, 0);
1447e4b17023SJohn Marino 	  fprintf (dump_file, " %s ", op_symbol_code (opcode));
1448e4b17023SJohn Marino 	  print_generic_expr (dump_file, oe->op, 0);
1449e4b17023SJohn Marino 	  fprintf (dump_file, " -> ");
1450e4b17023SJohn Marino 	  print_generic_expr (dump_file, t, 0);
1451e4b17023SJohn Marino 	  fprintf (dump_file, "\n");
1452e4b17023SJohn Marino 	}
1453e4b17023SJohn Marino 
1454e4b17023SJohn Marino       /* Now we can delete oe, as it has been subsumed by the new combined
1455e4b17023SJohn Marino          expression t.  */
1456e4b17023SJohn Marino       VEC_ordered_remove (operand_entry_t, *ops, i);
1457e4b17023SJohn Marino       reassociate_stats.ops_eliminated ++;
1458e4b17023SJohn Marino 
1459e4b17023SJohn Marino       /* If t is the same as curr->op, we're done.  Otherwise we must
1460e4b17023SJohn Marino 	 replace curr->op with t.  Special case is if we got a constant
1461e4b17023SJohn Marino 	 back, in which case we add it to the end instead of in place of
1462e4b17023SJohn Marino 	 the current entry.  */
1463e4b17023SJohn Marino       if (TREE_CODE (t) == INTEGER_CST)
1464e4b17023SJohn Marino 	{
1465e4b17023SJohn Marino 	  VEC_ordered_remove (operand_entry_t, *ops, currindex);
1466e4b17023SJohn Marino 	  add_to_ops_vec (ops, t);
1467e4b17023SJohn Marino 	}
1468e4b17023SJohn Marino       else if (!operand_equal_p (t, curr->op, 0))
1469e4b17023SJohn Marino 	{
1470e4b17023SJohn Marino 	  tree tmpvar;
1471e4b17023SJohn Marino 	  gimple sum;
1472e4b17023SJohn Marino 	  enum tree_code subcode;
1473e4b17023SJohn Marino 	  tree newop1;
1474e4b17023SJohn Marino 	  tree newop2;
1475e4b17023SJohn Marino 	  gcc_assert (COMPARISON_CLASS_P (t));
1476e4b17023SJohn Marino 	  tmpvar = create_tmp_var (TREE_TYPE (t), NULL);
1477e4b17023SJohn Marino 	  add_referenced_var (tmpvar);
1478e4b17023SJohn Marino 	  extract_ops_from_tree (t, &subcode, &newop1, &newop2);
1479e4b17023SJohn Marino 	  STRIP_USELESS_TYPE_CONVERSION (newop1);
1480e4b17023SJohn Marino 	  STRIP_USELESS_TYPE_CONVERSION (newop2);
1481e4b17023SJohn Marino 	  gcc_checking_assert (is_gimple_val (newop1)
1482e4b17023SJohn Marino 			       && is_gimple_val (newop2));
1483e4b17023SJohn Marino 	  sum = build_and_add_sum (tmpvar, newop1, newop2, subcode);
1484e4b17023SJohn Marino 	  curr->op = gimple_get_lhs (sum);
1485e4b17023SJohn Marino 	}
1486e4b17023SJohn Marino       return true;
1487e4b17023SJohn Marino     }
1488e4b17023SJohn Marino 
1489e4b17023SJohn Marino   return false;
1490e4b17023SJohn Marino }
1491e4b17023SJohn Marino 
1492e4b17023SJohn Marino /* Perform various identities and other optimizations on the list of
1493e4b17023SJohn Marino    operand entries, stored in OPS.  The tree code for the binary
1494e4b17023SJohn Marino    operation between all the operands is OPCODE.  */
1495e4b17023SJohn Marino 
1496e4b17023SJohn Marino static void
optimize_ops_list(enum tree_code opcode,VEC (operand_entry_t,heap)** ops)1497e4b17023SJohn Marino optimize_ops_list (enum tree_code opcode,
1498e4b17023SJohn Marino 		   VEC (operand_entry_t, heap) **ops)
1499e4b17023SJohn Marino {
1500e4b17023SJohn Marino   unsigned int length = VEC_length (operand_entry_t, *ops);
1501e4b17023SJohn Marino   unsigned int i;
1502e4b17023SJohn Marino   operand_entry_t oe;
1503e4b17023SJohn Marino   operand_entry_t oelast = NULL;
1504e4b17023SJohn Marino   bool iterate = false;
1505e4b17023SJohn Marino 
1506e4b17023SJohn Marino   if (length == 1)
1507e4b17023SJohn Marino     return;
1508e4b17023SJohn Marino 
1509e4b17023SJohn Marino   oelast = VEC_last (operand_entry_t, *ops);
1510e4b17023SJohn Marino 
1511e4b17023SJohn Marino   /* If the last two are constants, pop the constants off, merge them
1512e4b17023SJohn Marino      and try the next two.  */
1513e4b17023SJohn Marino   if (oelast->rank == 0 && is_gimple_min_invariant (oelast->op))
1514e4b17023SJohn Marino     {
1515e4b17023SJohn Marino       operand_entry_t oelm1 = VEC_index (operand_entry_t, *ops, length - 2);
1516e4b17023SJohn Marino 
1517e4b17023SJohn Marino       if (oelm1->rank == 0
1518e4b17023SJohn Marino 	  && is_gimple_min_invariant (oelm1->op)
1519e4b17023SJohn Marino 	  && useless_type_conversion_p (TREE_TYPE (oelm1->op),
1520e4b17023SJohn Marino 				       TREE_TYPE (oelast->op)))
1521e4b17023SJohn Marino 	{
1522e4b17023SJohn Marino 	  tree folded = fold_binary (opcode, TREE_TYPE (oelm1->op),
1523e4b17023SJohn Marino 				     oelm1->op, oelast->op);
1524e4b17023SJohn Marino 
1525e4b17023SJohn Marino 	  if (folded && is_gimple_min_invariant (folded))
1526e4b17023SJohn Marino 	    {
1527e4b17023SJohn Marino 	      if (dump_file && (dump_flags & TDF_DETAILS))
1528e4b17023SJohn Marino 		fprintf (dump_file, "Merging constants\n");
1529e4b17023SJohn Marino 
1530e4b17023SJohn Marino 	      VEC_pop (operand_entry_t, *ops);
1531e4b17023SJohn Marino 	      VEC_pop (operand_entry_t, *ops);
1532e4b17023SJohn Marino 
1533e4b17023SJohn Marino 	      add_to_ops_vec (ops, folded);
1534e4b17023SJohn Marino 	      reassociate_stats.constants_eliminated++;
1535e4b17023SJohn Marino 
1536e4b17023SJohn Marino 	      optimize_ops_list (opcode, ops);
1537e4b17023SJohn Marino 	      return;
1538e4b17023SJohn Marino 	    }
1539e4b17023SJohn Marino 	}
1540e4b17023SJohn Marino     }
1541e4b17023SJohn Marino 
1542e4b17023SJohn Marino   eliminate_using_constants (opcode, ops);
1543e4b17023SJohn Marino   oelast = NULL;
1544e4b17023SJohn Marino 
1545e4b17023SJohn Marino   for (i = 0; VEC_iterate (operand_entry_t, *ops, i, oe);)
1546e4b17023SJohn Marino     {
1547e4b17023SJohn Marino       bool done = false;
1548e4b17023SJohn Marino 
1549e4b17023SJohn Marino       if (eliminate_not_pairs (opcode, ops, i, oe))
1550e4b17023SJohn Marino 	return;
1551e4b17023SJohn Marino       if (eliminate_duplicate_pair (opcode, ops, &done, i, oe, oelast)
1552e4b17023SJohn Marino 	  || (!done && eliminate_plus_minus_pair (opcode, ops, i, oe))
1553e4b17023SJohn Marino 	  || (!done && eliminate_redundant_comparison (opcode, ops, i, oe)))
1554e4b17023SJohn Marino 	{
1555e4b17023SJohn Marino 	  if (done)
1556e4b17023SJohn Marino 	    return;
1557e4b17023SJohn Marino 	  iterate = true;
1558e4b17023SJohn Marino 	  oelast = NULL;
1559e4b17023SJohn Marino 	  continue;
1560e4b17023SJohn Marino 	}
1561e4b17023SJohn Marino       oelast = oe;
1562e4b17023SJohn Marino       i++;
1563e4b17023SJohn Marino     }
1564e4b17023SJohn Marino 
1565e4b17023SJohn Marino   length  = VEC_length (operand_entry_t, *ops);
1566e4b17023SJohn Marino   oelast = VEC_last (operand_entry_t, *ops);
1567e4b17023SJohn Marino 
1568e4b17023SJohn Marino   if (iterate)
1569e4b17023SJohn Marino     optimize_ops_list (opcode, ops);
1570e4b17023SJohn Marino }
1571e4b17023SJohn Marino 
1572e4b17023SJohn Marino /* The following functions are subroutines to optimize_range_tests and allow
1573e4b17023SJohn Marino    it to try to change a logical combination of comparisons into a range
1574e4b17023SJohn Marino    test.
1575e4b17023SJohn Marino 
1576e4b17023SJohn Marino    For example, both
1577e4b17023SJohn Marino 	X == 2 || X == 5 || X == 3 || X == 4
1578e4b17023SJohn Marino    and
1579e4b17023SJohn Marino 	X >= 2 && X <= 5
1580e4b17023SJohn Marino    are converted to
1581e4b17023SJohn Marino 	(unsigned) (X - 2) <= 3
1582e4b17023SJohn Marino 
1583e4b17023SJohn Marino    For more information see comments above fold_test_range in fold-const.c,
1584e4b17023SJohn Marino    this implementation is for GIMPLE.  */
1585e4b17023SJohn Marino 
1586e4b17023SJohn Marino struct range_entry
1587e4b17023SJohn Marino {
1588e4b17023SJohn Marino   tree exp;
1589e4b17023SJohn Marino   tree low;
1590e4b17023SJohn Marino   tree high;
1591e4b17023SJohn Marino   bool in_p;
1592e4b17023SJohn Marino   bool strict_overflow_p;
1593e4b17023SJohn Marino   unsigned int idx, next;
1594e4b17023SJohn Marino };
1595e4b17023SJohn Marino 
1596e4b17023SJohn Marino /* This is similar to make_range in fold-const.c, but on top of
1597e4b17023SJohn Marino    GIMPLE instead of trees.  */
1598e4b17023SJohn Marino 
1599e4b17023SJohn Marino static void
init_range_entry(struct range_entry * r,tree exp)1600e4b17023SJohn Marino init_range_entry (struct range_entry *r, tree exp)
1601e4b17023SJohn Marino {
1602e4b17023SJohn Marino   int in_p;
1603e4b17023SJohn Marino   tree low, high;
1604e4b17023SJohn Marino   bool is_bool, strict_overflow_p;
1605e4b17023SJohn Marino 
1606e4b17023SJohn Marino   r->exp = NULL_TREE;
1607e4b17023SJohn Marino   r->in_p = false;
1608e4b17023SJohn Marino   r->strict_overflow_p = false;
1609e4b17023SJohn Marino   r->low = NULL_TREE;
1610e4b17023SJohn Marino   r->high = NULL_TREE;
1611e4b17023SJohn Marino   if (TREE_CODE (exp) != SSA_NAME || !INTEGRAL_TYPE_P (TREE_TYPE (exp)))
1612e4b17023SJohn Marino     return;
1613e4b17023SJohn Marino 
1614e4b17023SJohn Marino   /* Start with simply saying "EXP != 0" and then look at the code of EXP
1615e4b17023SJohn Marino      and see if we can refine the range.  Some of the cases below may not
1616e4b17023SJohn Marino      happen, but it doesn't seem worth worrying about this.  We "continue"
1617e4b17023SJohn Marino      the outer loop when we've changed something; otherwise we "break"
1618e4b17023SJohn Marino      the switch, which will "break" the while.  */
1619e4b17023SJohn Marino   low = build_int_cst (TREE_TYPE (exp), 0);
1620e4b17023SJohn Marino   high = low;
1621e4b17023SJohn Marino   in_p = 0;
1622e4b17023SJohn Marino   strict_overflow_p = false;
1623e4b17023SJohn Marino   is_bool = false;
1624e4b17023SJohn Marino   if (TYPE_PRECISION (TREE_TYPE (exp)) == 1)
1625e4b17023SJohn Marino     {
1626e4b17023SJohn Marino       if (TYPE_UNSIGNED (TREE_TYPE (exp)))
1627e4b17023SJohn Marino 	is_bool = true;
1628e4b17023SJohn Marino       else
1629e4b17023SJohn Marino 	return;
1630e4b17023SJohn Marino     }
1631e4b17023SJohn Marino   else if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE)
1632e4b17023SJohn Marino     is_bool = true;
1633e4b17023SJohn Marino 
1634e4b17023SJohn Marino   while (1)
1635e4b17023SJohn Marino     {
1636e4b17023SJohn Marino       gimple stmt;
1637e4b17023SJohn Marino       enum tree_code code;
1638e4b17023SJohn Marino       tree arg0, arg1, exp_type;
1639e4b17023SJohn Marino       tree nexp;
1640e4b17023SJohn Marino       location_t loc;
1641e4b17023SJohn Marino 
1642e4b17023SJohn Marino       if (TREE_CODE (exp) != SSA_NAME)
1643e4b17023SJohn Marino 	break;
1644e4b17023SJohn Marino 
1645e4b17023SJohn Marino       stmt = SSA_NAME_DEF_STMT (exp);
1646e4b17023SJohn Marino       if (!is_gimple_assign (stmt))
1647e4b17023SJohn Marino 	break;
1648e4b17023SJohn Marino 
1649e4b17023SJohn Marino       code = gimple_assign_rhs_code (stmt);
1650e4b17023SJohn Marino       arg0 = gimple_assign_rhs1 (stmt);
1651e4b17023SJohn Marino       if (TREE_CODE (arg0) != SSA_NAME)
1652e4b17023SJohn Marino 	break;
1653e4b17023SJohn Marino       arg1 = gimple_assign_rhs2 (stmt);
1654e4b17023SJohn Marino       exp_type = TREE_TYPE (exp);
1655e4b17023SJohn Marino       loc = gimple_location (stmt);
1656e4b17023SJohn Marino       switch (code)
1657e4b17023SJohn Marino 	{
1658e4b17023SJohn Marino 	case BIT_NOT_EXPR:
1659e4b17023SJohn Marino 	  if (TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE)
1660e4b17023SJohn Marino 	    {
1661e4b17023SJohn Marino 	      in_p = !in_p;
1662e4b17023SJohn Marino 	      exp = arg0;
1663e4b17023SJohn Marino 	      continue;
1664e4b17023SJohn Marino 	    }
1665e4b17023SJohn Marino 	  break;
1666e4b17023SJohn Marino 	case SSA_NAME:
1667e4b17023SJohn Marino 	  exp = arg0;
1668e4b17023SJohn Marino 	  continue;
1669e4b17023SJohn Marino 	CASE_CONVERT:
1670e4b17023SJohn Marino 	  if (is_bool)
1671e4b17023SJohn Marino 	    goto do_default;
1672e4b17023SJohn Marino 	  if (TYPE_PRECISION (TREE_TYPE (arg0)) == 1)
1673e4b17023SJohn Marino 	    {
1674e4b17023SJohn Marino 	      if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
1675e4b17023SJohn Marino 		is_bool = true;
1676e4b17023SJohn Marino 	      else
1677e4b17023SJohn Marino 		return;
1678e4b17023SJohn Marino 	    }
1679e4b17023SJohn Marino 	  else if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE)
1680e4b17023SJohn Marino 	    is_bool = true;
1681e4b17023SJohn Marino 	  goto do_default;
1682e4b17023SJohn Marino 	case EQ_EXPR:
1683e4b17023SJohn Marino 	case NE_EXPR:
1684e4b17023SJohn Marino 	case LT_EXPR:
1685e4b17023SJohn Marino 	case LE_EXPR:
1686e4b17023SJohn Marino 	case GE_EXPR:
1687e4b17023SJohn Marino 	case GT_EXPR:
1688e4b17023SJohn Marino 	  is_bool = true;
1689e4b17023SJohn Marino 	  /* FALLTHRU */
1690e4b17023SJohn Marino 	default:
1691e4b17023SJohn Marino 	  if (!is_bool)
1692e4b17023SJohn Marino 	    return;
1693e4b17023SJohn Marino 	do_default:
1694e4b17023SJohn Marino 	  nexp = make_range_step (loc, code, arg0, arg1, exp_type,
1695e4b17023SJohn Marino 				  &low, &high, &in_p,
1696e4b17023SJohn Marino 				  &strict_overflow_p);
1697e4b17023SJohn Marino 	  if (nexp != NULL_TREE)
1698e4b17023SJohn Marino 	    {
1699e4b17023SJohn Marino 	      exp = nexp;
1700e4b17023SJohn Marino 	      gcc_assert (TREE_CODE (exp) == SSA_NAME);
1701e4b17023SJohn Marino 	      continue;
1702e4b17023SJohn Marino 	    }
1703e4b17023SJohn Marino 	  break;
1704e4b17023SJohn Marino 	}
1705e4b17023SJohn Marino       break;
1706e4b17023SJohn Marino     }
1707e4b17023SJohn Marino   if (is_bool)
1708e4b17023SJohn Marino     {
1709e4b17023SJohn Marino       r->exp = exp;
1710e4b17023SJohn Marino       r->in_p = in_p;
1711e4b17023SJohn Marino       r->low = low;
1712e4b17023SJohn Marino       r->high = high;
1713e4b17023SJohn Marino       r->strict_overflow_p = strict_overflow_p;
1714e4b17023SJohn Marino     }
1715e4b17023SJohn Marino }
1716e4b17023SJohn Marino 
1717e4b17023SJohn Marino /* Comparison function for qsort.  Sort entries
1718e4b17023SJohn Marino    without SSA_NAME exp first, then with SSA_NAMEs sorted
1719e4b17023SJohn Marino    by increasing SSA_NAME_VERSION, and for the same SSA_NAMEs
1720e4b17023SJohn Marino    by increasing ->low and if ->low is the same, by increasing
1721e4b17023SJohn Marino    ->high.  ->low == NULL_TREE means minimum, ->high == NULL_TREE
1722e4b17023SJohn Marino    maximum.  */
1723e4b17023SJohn Marino 
1724e4b17023SJohn Marino static int
range_entry_cmp(const void * a,const void * b)1725e4b17023SJohn Marino range_entry_cmp (const void *a, const void *b)
1726e4b17023SJohn Marino {
1727e4b17023SJohn Marino   const struct range_entry *p = (const struct range_entry *) a;
1728e4b17023SJohn Marino   const struct range_entry *q = (const struct range_entry *) b;
1729e4b17023SJohn Marino 
1730e4b17023SJohn Marino   if (p->exp != NULL_TREE && TREE_CODE (p->exp) == SSA_NAME)
1731e4b17023SJohn Marino     {
1732e4b17023SJohn Marino       if (q->exp != NULL_TREE && TREE_CODE (q->exp) == SSA_NAME)
1733e4b17023SJohn Marino 	{
1734e4b17023SJohn Marino 	  /* Group range_entries for the same SSA_NAME together.  */
1735e4b17023SJohn Marino 	  if (SSA_NAME_VERSION (p->exp) < SSA_NAME_VERSION (q->exp))
1736e4b17023SJohn Marino 	    return -1;
1737e4b17023SJohn Marino 	  else if (SSA_NAME_VERSION (p->exp) > SSA_NAME_VERSION (q->exp))
1738e4b17023SJohn Marino 	    return 1;
1739e4b17023SJohn Marino 	  /* If ->low is different, NULL low goes first, then by
1740e4b17023SJohn Marino 	     ascending low.  */
1741e4b17023SJohn Marino 	  if (p->low != NULL_TREE)
1742e4b17023SJohn Marino 	    {
1743e4b17023SJohn Marino 	      if (q->low != NULL_TREE)
1744e4b17023SJohn Marino 		{
1745e4b17023SJohn Marino 		  tree tem = fold_binary (LT_EXPR, boolean_type_node,
1746e4b17023SJohn Marino 					  p->low, q->low);
1747e4b17023SJohn Marino 		  if (tem && integer_onep (tem))
1748e4b17023SJohn Marino 		    return -1;
1749e4b17023SJohn Marino 		  tem = fold_binary (GT_EXPR, boolean_type_node,
1750e4b17023SJohn Marino 				     p->low, q->low);
1751e4b17023SJohn Marino 		  if (tem && integer_onep (tem))
1752e4b17023SJohn Marino 		    return 1;
1753e4b17023SJohn Marino 		}
1754e4b17023SJohn Marino 	      else
1755e4b17023SJohn Marino 		return 1;
1756e4b17023SJohn Marino 	    }
1757e4b17023SJohn Marino 	  else if (q->low != NULL_TREE)
1758e4b17023SJohn Marino 	    return -1;
1759e4b17023SJohn Marino 	  /* If ->high is different, NULL high goes last, before that by
1760e4b17023SJohn Marino 	     ascending high.  */
1761e4b17023SJohn Marino 	  if (p->high != NULL_TREE)
1762e4b17023SJohn Marino 	    {
1763e4b17023SJohn Marino 	      if (q->high != NULL_TREE)
1764e4b17023SJohn Marino 		{
1765e4b17023SJohn Marino 		  tree tem = fold_binary (LT_EXPR, boolean_type_node,
1766e4b17023SJohn Marino 					  p->high, q->high);
1767e4b17023SJohn Marino 		  if (tem && integer_onep (tem))
1768e4b17023SJohn Marino 		    return -1;
1769e4b17023SJohn Marino 		  tem = fold_binary (GT_EXPR, boolean_type_node,
1770e4b17023SJohn Marino 				     p->high, q->high);
1771e4b17023SJohn Marino 		  if (tem && integer_onep (tem))
1772e4b17023SJohn Marino 		    return 1;
1773e4b17023SJohn Marino 		}
1774e4b17023SJohn Marino 	      else
1775e4b17023SJohn Marino 		return -1;
1776e4b17023SJohn Marino 	    }
1777e4b17023SJohn Marino 	  else if (p->high != NULL_TREE)
1778e4b17023SJohn Marino 	    return 1;
1779e4b17023SJohn Marino 	  /* If both ranges are the same, sort below by ascending idx.  */
1780e4b17023SJohn Marino 	}
1781e4b17023SJohn Marino       else
1782e4b17023SJohn Marino 	return 1;
1783e4b17023SJohn Marino     }
1784e4b17023SJohn Marino   else if (q->exp != NULL_TREE && TREE_CODE (q->exp) == SSA_NAME)
1785e4b17023SJohn Marino     return -1;
1786e4b17023SJohn Marino 
1787e4b17023SJohn Marino   if (p->idx < q->idx)
1788e4b17023SJohn Marino     return -1;
1789e4b17023SJohn Marino   else
1790e4b17023SJohn Marino     {
1791e4b17023SJohn Marino       gcc_checking_assert (p->idx > q->idx);
1792e4b17023SJohn Marino       return 1;
1793e4b17023SJohn Marino     }
1794e4b17023SJohn Marino }
1795e4b17023SJohn Marino 
1796e4b17023SJohn Marino /* Helper routine of optimize_range_test.
1797e4b17023SJohn Marino    [EXP, IN_P, LOW, HIGH, STRICT_OVERFLOW_P] is a merged range for
1798e4b17023SJohn Marino    RANGE and OTHERRANGE through OTHERRANGE + COUNT - 1 ranges,
1799e4b17023SJohn Marino    OPCODE and OPS are arguments of optimize_range_tests.  Return
1800e4b17023SJohn Marino    true if the range merge has been successful.  */
1801e4b17023SJohn Marino 
1802e4b17023SJohn Marino static bool
update_range_test(struct range_entry * range,struct range_entry * otherrange,unsigned int count,enum tree_code opcode,VEC (operand_entry_t,heap)** ops,tree exp,bool in_p,tree low,tree high,bool strict_overflow_p)1803e4b17023SJohn Marino update_range_test (struct range_entry *range, struct range_entry *otherrange,
1804e4b17023SJohn Marino 		   unsigned int count, enum tree_code opcode,
1805e4b17023SJohn Marino 		   VEC (operand_entry_t, heap) **ops, tree exp, bool in_p,
1806e4b17023SJohn Marino 		   tree low, tree high, bool strict_overflow_p)
1807e4b17023SJohn Marino {
1808e4b17023SJohn Marino   tree op = VEC_index (operand_entry_t, *ops, range->idx)->op;
1809e4b17023SJohn Marino   location_t loc = gimple_location (SSA_NAME_DEF_STMT (op));
1810e4b17023SJohn Marino   tree tem = build_range_check (loc, TREE_TYPE (op), exp, in_p, low, high);
1811e4b17023SJohn Marino   enum warn_strict_overflow_code wc = WARN_STRICT_OVERFLOW_COMPARISON;
1812e4b17023SJohn Marino   gimple_stmt_iterator gsi;
1813e4b17023SJohn Marino 
1814e4b17023SJohn Marino   if (tem == NULL_TREE)
1815e4b17023SJohn Marino     return false;
1816e4b17023SJohn Marino 
1817e4b17023SJohn Marino   if (strict_overflow_p && issue_strict_overflow_warning (wc))
1818e4b17023SJohn Marino     warning_at (loc, OPT_Wstrict_overflow,
1819e4b17023SJohn Marino 		"assuming signed overflow does not occur "
1820e4b17023SJohn Marino 		"when simplifying range test");
1821e4b17023SJohn Marino 
1822e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
1823e4b17023SJohn Marino     {
1824e4b17023SJohn Marino       struct range_entry *r;
1825e4b17023SJohn Marino       fprintf (dump_file, "Optimizing range tests ");
1826e4b17023SJohn Marino       print_generic_expr (dump_file, range->exp, 0);
1827e4b17023SJohn Marino       fprintf (dump_file, " %c[", range->in_p ? '+' : '-');
1828e4b17023SJohn Marino       print_generic_expr (dump_file, range->low, 0);
1829e4b17023SJohn Marino       fprintf (dump_file, ", ");
1830e4b17023SJohn Marino       print_generic_expr (dump_file, range->high, 0);
1831e4b17023SJohn Marino       fprintf (dump_file, "]");
1832e4b17023SJohn Marino       for (r = otherrange; r < otherrange + count; r++)
1833e4b17023SJohn Marino 	{
1834e4b17023SJohn Marino 	  fprintf (dump_file, " and %c[", r->in_p ? '+' : '-');
1835e4b17023SJohn Marino 	  print_generic_expr (dump_file, r->low, 0);
1836e4b17023SJohn Marino 	  fprintf (dump_file, ", ");
1837e4b17023SJohn Marino 	  print_generic_expr (dump_file, r->high, 0);
1838e4b17023SJohn Marino 	  fprintf (dump_file, "]");
1839e4b17023SJohn Marino 	}
1840e4b17023SJohn Marino       fprintf (dump_file, "\n into ");
1841e4b17023SJohn Marino       print_generic_expr (dump_file, tem, 0);
1842e4b17023SJohn Marino       fprintf (dump_file, "\n");
1843e4b17023SJohn Marino     }
1844e4b17023SJohn Marino 
1845e4b17023SJohn Marino   if (opcode == BIT_IOR_EXPR)
1846e4b17023SJohn Marino     tem = invert_truthvalue_loc (loc, tem);
1847e4b17023SJohn Marino 
1848e4b17023SJohn Marino   tem = fold_convert_loc (loc, TREE_TYPE (op), tem);
1849e4b17023SJohn Marino   gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (op));
1850e4b17023SJohn Marino   tem = force_gimple_operand_gsi (&gsi, tem, true, NULL_TREE, true,
1851e4b17023SJohn Marino 				  GSI_SAME_STMT);
1852e4b17023SJohn Marino 
1853e4b17023SJohn Marino   VEC_index (operand_entry_t, *ops, range->idx)->op = tem;
1854e4b17023SJohn Marino   range->exp = exp;
1855e4b17023SJohn Marino   range->low = low;
1856e4b17023SJohn Marino   range->high = high;
1857e4b17023SJohn Marino   range->in_p = in_p;
1858e4b17023SJohn Marino   range->strict_overflow_p = false;
1859e4b17023SJohn Marino 
1860e4b17023SJohn Marino   for (range = otherrange; range < otherrange + count; range++)
1861e4b17023SJohn Marino     {
1862e4b17023SJohn Marino       VEC_index (operand_entry_t, *ops, range->idx)->op = error_mark_node;
1863e4b17023SJohn Marino       range->exp = NULL_TREE;
1864e4b17023SJohn Marino     }
1865e4b17023SJohn Marino   return true;
1866e4b17023SJohn Marino }
1867e4b17023SJohn Marino 
1868e4b17023SJohn Marino /* Optimize range tests, similarly how fold_range_test optimizes
1869e4b17023SJohn Marino    it on trees.  The tree code for the binary
1870e4b17023SJohn Marino    operation between all the operands is OPCODE.  */
1871e4b17023SJohn Marino 
1872e4b17023SJohn Marino static void
optimize_range_tests(enum tree_code opcode,VEC (operand_entry_t,heap)** ops)1873e4b17023SJohn Marino optimize_range_tests (enum tree_code opcode,
1874e4b17023SJohn Marino 		      VEC (operand_entry_t, heap) **ops)
1875e4b17023SJohn Marino {
1876e4b17023SJohn Marino   unsigned int length = VEC_length (operand_entry_t, *ops), i, j, first;
1877e4b17023SJohn Marino   operand_entry_t oe;
1878e4b17023SJohn Marino   struct range_entry *ranges;
1879e4b17023SJohn Marino   bool any_changes = false;
1880e4b17023SJohn Marino 
1881e4b17023SJohn Marino   if (length == 1)
1882e4b17023SJohn Marino     return;
1883e4b17023SJohn Marino 
1884e4b17023SJohn Marino   ranges = XNEWVEC (struct range_entry, length);
1885e4b17023SJohn Marino   for (i = 0; i < length; i++)
1886e4b17023SJohn Marino     {
1887e4b17023SJohn Marino       ranges[i].idx = i;
1888e4b17023SJohn Marino       init_range_entry (ranges + i, VEC_index (operand_entry_t, *ops, i)->op);
1889e4b17023SJohn Marino       /* For | invert it now, we will invert it again before emitting
1890e4b17023SJohn Marino 	 the optimized expression.  */
1891e4b17023SJohn Marino       if (opcode == BIT_IOR_EXPR)
1892e4b17023SJohn Marino 	ranges[i].in_p = !ranges[i].in_p;
1893e4b17023SJohn Marino     }
1894e4b17023SJohn Marino 
1895e4b17023SJohn Marino   qsort (ranges, length, sizeof (*ranges), range_entry_cmp);
1896e4b17023SJohn Marino   for (i = 0; i < length; i++)
1897e4b17023SJohn Marino     if (ranges[i].exp != NULL_TREE && TREE_CODE (ranges[i].exp) == SSA_NAME)
1898e4b17023SJohn Marino       break;
1899e4b17023SJohn Marino 
1900e4b17023SJohn Marino   /* Try to merge ranges.  */
1901e4b17023SJohn Marino   for (first = i; i < length; i++)
1902e4b17023SJohn Marino     {
1903e4b17023SJohn Marino       tree low = ranges[i].low;
1904e4b17023SJohn Marino       tree high = ranges[i].high;
1905e4b17023SJohn Marino       int in_p = ranges[i].in_p;
1906e4b17023SJohn Marino       bool strict_overflow_p = ranges[i].strict_overflow_p;
1907e4b17023SJohn Marino       int update_fail_count = 0;
1908e4b17023SJohn Marino 
1909e4b17023SJohn Marino       for (j = i + 1; j < length; j++)
1910e4b17023SJohn Marino 	{
1911e4b17023SJohn Marino 	  if (ranges[i].exp != ranges[j].exp)
1912e4b17023SJohn Marino 	    break;
1913e4b17023SJohn Marino 	  if (!merge_ranges (&in_p, &low, &high, in_p, low, high,
1914e4b17023SJohn Marino 			     ranges[j].in_p, ranges[j].low, ranges[j].high))
1915e4b17023SJohn Marino 	    break;
1916e4b17023SJohn Marino 	  strict_overflow_p |= ranges[j].strict_overflow_p;
1917e4b17023SJohn Marino 	}
1918e4b17023SJohn Marino 
1919e4b17023SJohn Marino       if (j == i + 1)
1920e4b17023SJohn Marino 	continue;
1921e4b17023SJohn Marino 
1922e4b17023SJohn Marino       if (update_range_test (ranges + i, ranges + i + 1, j - i - 1, opcode,
1923e4b17023SJohn Marino 			     ops, ranges[i].exp, in_p, low, high,
1924e4b17023SJohn Marino 			     strict_overflow_p))
1925e4b17023SJohn Marino 	{
1926e4b17023SJohn Marino 	  i = j - 1;
1927e4b17023SJohn Marino 	  any_changes = true;
1928e4b17023SJohn Marino 	}
1929e4b17023SJohn Marino       /* Avoid quadratic complexity if all merge_ranges calls would succeed,
1930e4b17023SJohn Marino 	 while update_range_test would fail.  */
1931e4b17023SJohn Marino       else if (update_fail_count == 64)
1932e4b17023SJohn Marino 	i = j - 1;
1933e4b17023SJohn Marino       else
1934e4b17023SJohn Marino 	++update_fail_count;
1935e4b17023SJohn Marino     }
1936e4b17023SJohn Marino 
1937e4b17023SJohn Marino   /* Optimize X == CST1 || X == CST2
1938e4b17023SJohn Marino      if popcount (CST1 ^ CST2) == 1 into
1939e4b17023SJohn Marino      (X & ~(CST1 ^ CST2)) == (CST1 & ~(CST1 ^ CST2)).
1940e4b17023SJohn Marino      Similarly for ranges.  E.g.
1941e4b17023SJohn Marino      X != 2 && X != 3 && X != 10 && X != 11
1942e4b17023SJohn Marino      will be transformed by the above loop into
1943e4b17023SJohn Marino      (X - 2U) <= 1U && (X - 10U) <= 1U
1944e4b17023SJohn Marino      and this loop can transform that into
1945e4b17023SJohn Marino      ((X & ~8) - 2U) <= 1U.  */
1946e4b17023SJohn Marino   for (i = first; i < length; i++)
1947e4b17023SJohn Marino     {
1948e4b17023SJohn Marino       tree lowi, highi, lowj, highj, type, lowxor, highxor, tem, exp;
1949e4b17023SJohn Marino 
1950e4b17023SJohn Marino       if (ranges[i].exp == NULL_TREE || ranges[i].in_p)
1951e4b17023SJohn Marino 	continue;
1952e4b17023SJohn Marino       type = TREE_TYPE (ranges[i].exp);
1953e4b17023SJohn Marino       if (!INTEGRAL_TYPE_P (type))
1954e4b17023SJohn Marino 	continue;
1955e4b17023SJohn Marino       lowi = ranges[i].low;
1956e4b17023SJohn Marino       if (lowi == NULL_TREE)
1957e4b17023SJohn Marino 	lowi = TYPE_MIN_VALUE (type);
1958e4b17023SJohn Marino       highi = ranges[i].high;
1959e4b17023SJohn Marino       if (highi == NULL_TREE)
1960e4b17023SJohn Marino 	continue;
1961e4b17023SJohn Marino       for (j = i + 1; j < length && j < i + 64; j++)
1962e4b17023SJohn Marino 	{
1963e4b17023SJohn Marino 	  if (ranges[j].exp == NULL_TREE)
1964e4b17023SJohn Marino 	    continue;
1965e4b17023SJohn Marino 	  if (ranges[i].exp != ranges[j].exp)
1966e4b17023SJohn Marino 	    break;
1967e4b17023SJohn Marino 	  if (ranges[j].in_p)
1968e4b17023SJohn Marino 	    continue;
1969e4b17023SJohn Marino 	  lowj = ranges[j].low;
1970e4b17023SJohn Marino 	  if (lowj == NULL_TREE)
1971e4b17023SJohn Marino 	    continue;
1972e4b17023SJohn Marino 	  highj = ranges[j].high;
1973e4b17023SJohn Marino 	  if (highj == NULL_TREE)
1974e4b17023SJohn Marino 	    highj = TYPE_MAX_VALUE (type);
1975e4b17023SJohn Marino 	  tem = fold_binary (GT_EXPR, boolean_type_node,
1976e4b17023SJohn Marino 			     lowj, highi);
1977e4b17023SJohn Marino 	  if (tem == NULL_TREE || !integer_onep (tem))
1978e4b17023SJohn Marino 	    continue;
1979e4b17023SJohn Marino 	  lowxor = fold_binary (BIT_XOR_EXPR, type, lowi, lowj);
1980e4b17023SJohn Marino 	  if (lowxor == NULL_TREE || TREE_CODE (lowxor) != INTEGER_CST)
1981e4b17023SJohn Marino 	    continue;
1982e4b17023SJohn Marino 	  gcc_checking_assert (!integer_zerop (lowxor));
1983e4b17023SJohn Marino 	  tem = fold_binary (MINUS_EXPR, type, lowxor,
1984e4b17023SJohn Marino 			     build_int_cst (type, 1));
1985e4b17023SJohn Marino 	  if (tem == NULL_TREE)
1986e4b17023SJohn Marino 	    continue;
1987e4b17023SJohn Marino 	  tem = fold_binary (BIT_AND_EXPR, type, lowxor, tem);
1988e4b17023SJohn Marino 	  if (tem == NULL_TREE || !integer_zerop (tem))
1989e4b17023SJohn Marino 	    continue;
1990e4b17023SJohn Marino 	  highxor = fold_binary (BIT_XOR_EXPR, type, highi, highj);
1991e4b17023SJohn Marino 	  if (!tree_int_cst_equal (lowxor, highxor))
1992e4b17023SJohn Marino 	    continue;
1993e4b17023SJohn Marino 	  tem = fold_build1 (BIT_NOT_EXPR, type, lowxor);
1994e4b17023SJohn Marino 	  exp = fold_build2 (BIT_AND_EXPR, type, ranges[i].exp, tem);
1995e4b17023SJohn Marino 	  lowj = fold_build2 (BIT_AND_EXPR, type, lowi, tem);
1996e4b17023SJohn Marino 	  highj = fold_build2 (BIT_AND_EXPR, type, highi, tem);
1997e4b17023SJohn Marino 	  if (update_range_test (ranges + i, ranges + j, 1, opcode, ops, exp,
1998e4b17023SJohn Marino 				 ranges[i].in_p, lowj, highj,
1999e4b17023SJohn Marino 				 ranges[i].strict_overflow_p
2000e4b17023SJohn Marino 				 || ranges[j].strict_overflow_p))
2001e4b17023SJohn Marino 	    {
2002e4b17023SJohn Marino 	      any_changes = true;
2003e4b17023SJohn Marino 	      break;
2004e4b17023SJohn Marino 	    }
2005e4b17023SJohn Marino 	}
2006e4b17023SJohn Marino     }
2007e4b17023SJohn Marino 
2008e4b17023SJohn Marino   if (any_changes)
2009e4b17023SJohn Marino     {
2010e4b17023SJohn Marino       j = 0;
2011e4b17023SJohn Marino       FOR_EACH_VEC_ELT (operand_entry_t, *ops, i, oe)
2012e4b17023SJohn Marino 	{
2013e4b17023SJohn Marino 	  if (oe->op == error_mark_node)
2014e4b17023SJohn Marino 	    continue;
2015e4b17023SJohn Marino 	  else if (i != j)
2016e4b17023SJohn Marino 	    VEC_replace (operand_entry_t, *ops, j, oe);
2017e4b17023SJohn Marino 	  j++;
2018e4b17023SJohn Marino 	}
2019e4b17023SJohn Marino       VEC_truncate (operand_entry_t, *ops, j);
2020e4b17023SJohn Marino     }
2021e4b17023SJohn Marino 
2022e4b17023SJohn Marino   XDELETEVEC (ranges);
2023e4b17023SJohn Marino }
2024e4b17023SJohn Marino 
2025e4b17023SJohn Marino /* Return true if OPERAND is defined by a PHI node which uses the LHS
2026e4b17023SJohn Marino    of STMT in it's operands.  This is also known as a "destructive
2027e4b17023SJohn Marino    update" operation.  */
2028e4b17023SJohn Marino 
2029e4b17023SJohn Marino static bool
is_phi_for_stmt(gimple stmt,tree operand)2030e4b17023SJohn Marino is_phi_for_stmt (gimple stmt, tree operand)
2031e4b17023SJohn Marino {
2032e4b17023SJohn Marino   gimple def_stmt;
2033e4b17023SJohn Marino   tree lhs;
2034e4b17023SJohn Marino   use_operand_p arg_p;
2035e4b17023SJohn Marino   ssa_op_iter i;
2036e4b17023SJohn Marino 
2037e4b17023SJohn Marino   if (TREE_CODE (operand) != SSA_NAME)
2038e4b17023SJohn Marino     return false;
2039e4b17023SJohn Marino 
2040e4b17023SJohn Marino   lhs = gimple_assign_lhs (stmt);
2041e4b17023SJohn Marino 
2042e4b17023SJohn Marino   def_stmt = SSA_NAME_DEF_STMT (operand);
2043e4b17023SJohn Marino   if (gimple_code (def_stmt) != GIMPLE_PHI)
2044e4b17023SJohn Marino     return false;
2045e4b17023SJohn Marino 
2046e4b17023SJohn Marino   FOR_EACH_PHI_ARG (arg_p, def_stmt, i, SSA_OP_USE)
2047e4b17023SJohn Marino     if (lhs == USE_FROM_PTR (arg_p))
2048e4b17023SJohn Marino       return true;
2049e4b17023SJohn Marino   return false;
2050e4b17023SJohn Marino }
2051e4b17023SJohn Marino 
2052e4b17023SJohn Marino /* Remove def stmt of VAR if VAR has zero uses and recurse
2053e4b17023SJohn Marino    on rhs1 operand if so.  */
2054e4b17023SJohn Marino 
2055e4b17023SJohn Marino static void
remove_visited_stmt_chain(tree var)2056e4b17023SJohn Marino remove_visited_stmt_chain (tree var)
2057e4b17023SJohn Marino {
2058e4b17023SJohn Marino   gimple stmt;
2059e4b17023SJohn Marino   gimple_stmt_iterator gsi;
2060e4b17023SJohn Marino 
2061e4b17023SJohn Marino   while (1)
2062e4b17023SJohn Marino     {
2063e4b17023SJohn Marino       if (TREE_CODE (var) != SSA_NAME || !has_zero_uses (var))
2064e4b17023SJohn Marino 	return;
2065e4b17023SJohn Marino       stmt = SSA_NAME_DEF_STMT (var);
2066e4b17023SJohn Marino       if (!is_gimple_assign (stmt)
2067e4b17023SJohn Marino 	  || !gimple_visited_p (stmt))
2068e4b17023SJohn Marino 	return;
2069e4b17023SJohn Marino       var = gimple_assign_rhs1 (stmt);
2070e4b17023SJohn Marino       gsi = gsi_for_stmt (stmt);
2071e4b17023SJohn Marino       gsi_remove (&gsi, true);
2072e4b17023SJohn Marino       release_defs (stmt);
2073e4b17023SJohn Marino     }
2074e4b17023SJohn Marino }
2075e4b17023SJohn Marino 
2076e4b17023SJohn Marino /* This function checks three consequtive operands in
2077e4b17023SJohn Marino    passed operands vector OPS starting from OPINDEX and
2078e4b17023SJohn Marino    swaps two operands if it is profitable for binary operation
2079e4b17023SJohn Marino    consuming OPINDEX + 1 abnd OPINDEX + 2 operands.
2080e4b17023SJohn Marino 
2081e4b17023SJohn Marino    We pair ops with the same rank if possible.
2082e4b17023SJohn Marino 
2083e4b17023SJohn Marino    The alternative we try is to see if STMT is a destructive
2084e4b17023SJohn Marino    update style statement, which is like:
2085e4b17023SJohn Marino    b = phi (a, ...)
2086e4b17023SJohn Marino    a = c + b;
2087e4b17023SJohn Marino    In that case, we want to use the destructive update form to
2088e4b17023SJohn Marino    expose the possible vectorizer sum reduction opportunity.
2089e4b17023SJohn Marino    In that case, the third operand will be the phi node. This
2090e4b17023SJohn Marino    check is not performed if STMT is null.
2091e4b17023SJohn Marino 
2092e4b17023SJohn Marino    We could, of course, try to be better as noted above, and do a
2093e4b17023SJohn Marino    lot of work to try to find these opportunities in >3 operand
2094e4b17023SJohn Marino    cases, but it is unlikely to be worth it.  */
2095e4b17023SJohn Marino 
2096e4b17023SJohn Marino static void
swap_ops_for_binary_stmt(VEC (operand_entry_t,heap)* ops,unsigned int opindex,gimple stmt)2097e4b17023SJohn Marino swap_ops_for_binary_stmt (VEC(operand_entry_t, heap) * ops,
2098e4b17023SJohn Marino 			  unsigned int opindex, gimple stmt)
2099e4b17023SJohn Marino {
2100e4b17023SJohn Marino   operand_entry_t oe1, oe2, oe3;
2101e4b17023SJohn Marino 
2102e4b17023SJohn Marino   oe1 = VEC_index (operand_entry_t, ops, opindex);
2103e4b17023SJohn Marino   oe2 = VEC_index (operand_entry_t, ops, opindex + 1);
2104e4b17023SJohn Marino   oe3 = VEC_index (operand_entry_t, ops, opindex + 2);
2105e4b17023SJohn Marino 
2106e4b17023SJohn Marino   if ((oe1->rank == oe2->rank
2107e4b17023SJohn Marino        && oe2->rank != oe3->rank)
2108e4b17023SJohn Marino       || (stmt && is_phi_for_stmt (stmt, oe3->op)
2109e4b17023SJohn Marino 	  && !is_phi_for_stmt (stmt, oe1->op)
2110e4b17023SJohn Marino 	  && !is_phi_for_stmt (stmt, oe2->op)))
2111e4b17023SJohn Marino     {
2112e4b17023SJohn Marino       struct operand_entry temp = *oe3;
2113e4b17023SJohn Marino       oe3->op = oe1->op;
2114e4b17023SJohn Marino       oe3->rank = oe1->rank;
2115e4b17023SJohn Marino       oe1->op = temp.op;
2116e4b17023SJohn Marino       oe1->rank= temp.rank;
2117e4b17023SJohn Marino     }
2118e4b17023SJohn Marino   else if ((oe1->rank == oe3->rank
2119e4b17023SJohn Marino 	    && oe2->rank != oe3->rank)
2120e4b17023SJohn Marino 	   || (stmt && is_phi_for_stmt (stmt, oe2->op)
2121e4b17023SJohn Marino 	       && !is_phi_for_stmt (stmt, oe1->op)
2122e4b17023SJohn Marino 	       && !is_phi_for_stmt (stmt, oe3->op)))
2123e4b17023SJohn Marino     {
2124e4b17023SJohn Marino       struct operand_entry temp = *oe2;
2125e4b17023SJohn Marino       oe2->op = oe1->op;
2126e4b17023SJohn Marino       oe2->rank = oe1->rank;
2127e4b17023SJohn Marino       oe1->op = temp.op;
2128e4b17023SJohn Marino       oe1->rank= temp.rank;
2129e4b17023SJohn Marino     }
2130e4b17023SJohn Marino }
2131e4b17023SJohn Marino 
2132e4b17023SJohn Marino /* Recursively rewrite our linearized statements so that the operators
2133e4b17023SJohn Marino    match those in OPS[OPINDEX], putting the computation in rank
2134e4b17023SJohn Marino    order.  */
2135e4b17023SJohn Marino 
2136e4b17023SJohn Marino static void
rewrite_expr_tree(gimple stmt,unsigned int opindex,VEC (operand_entry_t,heap)* ops,bool moved)2137e4b17023SJohn Marino rewrite_expr_tree (gimple stmt, unsigned int opindex,
2138e4b17023SJohn Marino 		   VEC(operand_entry_t, heap) * ops, bool moved)
2139e4b17023SJohn Marino {
2140e4b17023SJohn Marino   tree rhs1 = gimple_assign_rhs1 (stmt);
2141e4b17023SJohn Marino   tree rhs2 = gimple_assign_rhs2 (stmt);
2142e4b17023SJohn Marino   operand_entry_t oe;
2143e4b17023SJohn Marino 
2144e4b17023SJohn Marino   /* If we have three operands left, then we want to make sure the ones
2145e4b17023SJohn Marino      that get the double binary op are chosen wisely.  */
2146e4b17023SJohn Marino   if (opindex + 3 == VEC_length (operand_entry_t, ops))
2147e4b17023SJohn Marino     swap_ops_for_binary_stmt (ops, opindex, stmt);
2148e4b17023SJohn Marino 
2149e4b17023SJohn Marino   /* The final recursion case for this function is that you have
2150e4b17023SJohn Marino      exactly two operations left.
2151e4b17023SJohn Marino      If we had one exactly one op in the entire list to start with, we
2152e4b17023SJohn Marino      would have never called this function, and the tail recursion
2153e4b17023SJohn Marino      rewrites them one at a time.  */
2154e4b17023SJohn Marino   if (opindex + 2 == VEC_length (operand_entry_t, ops))
2155e4b17023SJohn Marino     {
2156e4b17023SJohn Marino       operand_entry_t oe1, oe2;
2157e4b17023SJohn Marino 
2158e4b17023SJohn Marino       oe1 = VEC_index (operand_entry_t, ops, opindex);
2159e4b17023SJohn Marino       oe2 = VEC_index (operand_entry_t, ops, opindex + 1);
2160e4b17023SJohn Marino 
2161e4b17023SJohn Marino       if (rhs1 != oe1->op || rhs2 != oe2->op)
2162e4b17023SJohn Marino 	{
2163e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
2164e4b17023SJohn Marino 	    {
2165e4b17023SJohn Marino 	      fprintf (dump_file, "Transforming ");
2166e4b17023SJohn Marino 	      print_gimple_stmt (dump_file, stmt, 0, 0);
2167e4b17023SJohn Marino 	    }
2168e4b17023SJohn Marino 
2169e4b17023SJohn Marino 	  gimple_assign_set_rhs1 (stmt, oe1->op);
2170e4b17023SJohn Marino 	  gimple_assign_set_rhs2 (stmt, oe2->op);
2171e4b17023SJohn Marino 	  update_stmt (stmt);
2172e4b17023SJohn Marino 	  if (rhs1 != oe1->op && rhs1 != oe2->op)
2173e4b17023SJohn Marino 	    remove_visited_stmt_chain (rhs1);
2174e4b17023SJohn Marino 
2175e4b17023SJohn Marino 	  if (dump_file && (dump_flags & TDF_DETAILS))
2176e4b17023SJohn Marino 	    {
2177e4b17023SJohn Marino 	      fprintf (dump_file, " into ");
2178e4b17023SJohn Marino 	      print_gimple_stmt (dump_file, stmt, 0, 0);
2179e4b17023SJohn Marino 	    }
2180e4b17023SJohn Marino 
2181e4b17023SJohn Marino 	}
2182e4b17023SJohn Marino       return;
2183e4b17023SJohn Marino     }
2184e4b17023SJohn Marino 
2185e4b17023SJohn Marino   /* If we hit here, we should have 3 or more ops left.  */
2186e4b17023SJohn Marino   gcc_assert (opindex + 2 < VEC_length (operand_entry_t, ops));
2187e4b17023SJohn Marino 
2188e4b17023SJohn Marino   /* Rewrite the next operator.  */
2189e4b17023SJohn Marino   oe = VEC_index (operand_entry_t, ops, opindex);
2190e4b17023SJohn Marino 
2191e4b17023SJohn Marino   if (oe->op != rhs2)
2192e4b17023SJohn Marino     {
2193e4b17023SJohn Marino       if (!moved)
2194e4b17023SJohn Marino 	{
2195e4b17023SJohn Marino 	  gimple_stmt_iterator gsinow, gsirhs1;
2196e4b17023SJohn Marino 	  gimple stmt1 = stmt, stmt2;
2197e4b17023SJohn Marino 	  unsigned int count;
2198e4b17023SJohn Marino 
2199e4b17023SJohn Marino 	  gsinow = gsi_for_stmt (stmt);
2200e4b17023SJohn Marino 	  count = VEC_length (operand_entry_t, ops) - opindex - 2;
2201e4b17023SJohn Marino 	  while (count-- != 0)
2202e4b17023SJohn Marino 	    {
2203e4b17023SJohn Marino 	      stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt1));
2204e4b17023SJohn Marino 	      gsirhs1 = gsi_for_stmt (stmt2);
2205e4b17023SJohn Marino 	      gsi_move_before (&gsirhs1, &gsinow);
2206e4b17023SJohn Marino 	      gsi_prev (&gsinow);
2207e4b17023SJohn Marino 	      stmt1 = stmt2;
2208e4b17023SJohn Marino 	    }
2209e4b17023SJohn Marino 	  moved = true;
2210e4b17023SJohn Marino 	}
2211e4b17023SJohn Marino 
2212e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2213e4b17023SJohn Marino 	{
2214e4b17023SJohn Marino 	  fprintf (dump_file, "Transforming ");
2215e4b17023SJohn Marino 	  print_gimple_stmt (dump_file, stmt, 0, 0);
2216e4b17023SJohn Marino 	}
2217e4b17023SJohn Marino 
2218e4b17023SJohn Marino       gimple_assign_set_rhs2 (stmt, oe->op);
2219e4b17023SJohn Marino       update_stmt (stmt);
2220e4b17023SJohn Marino 
2221e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2222e4b17023SJohn Marino 	{
2223e4b17023SJohn Marino 	  fprintf (dump_file, " into ");
2224e4b17023SJohn Marino 	  print_gimple_stmt (dump_file, stmt, 0, 0);
2225e4b17023SJohn Marino 	}
2226e4b17023SJohn Marino     }
2227e4b17023SJohn Marino   /* Recurse on the LHS of the binary operator, which is guaranteed to
2228e4b17023SJohn Marino      be the non-leaf side.  */
2229e4b17023SJohn Marino   rewrite_expr_tree (SSA_NAME_DEF_STMT (rhs1), opindex + 1, ops, moved);
2230e4b17023SJohn Marino }
2231e4b17023SJohn Marino 
2232e4b17023SJohn Marino /* Find out how many cycles we need to compute statements chain.
2233e4b17023SJohn Marino    OPS_NUM holds number os statements in a chain.  CPU_WIDTH is a
2234e4b17023SJohn Marino    maximum number of independent statements we may execute per cycle.  */
2235e4b17023SJohn Marino 
2236e4b17023SJohn Marino static int
get_required_cycles(int ops_num,int cpu_width)2237e4b17023SJohn Marino get_required_cycles (int ops_num, int cpu_width)
2238e4b17023SJohn Marino {
2239e4b17023SJohn Marino   int res;
2240e4b17023SJohn Marino   int elog;
2241e4b17023SJohn Marino   unsigned int rest;
2242e4b17023SJohn Marino 
2243e4b17023SJohn Marino   /* While we have more than 2 * cpu_width operands
2244e4b17023SJohn Marino      we may reduce number of operands by cpu_width
2245e4b17023SJohn Marino      per cycle.  */
2246e4b17023SJohn Marino   res = ops_num / (2 * cpu_width);
2247e4b17023SJohn Marino 
2248e4b17023SJohn Marino   /* Remained operands count may be reduced twice per cycle
2249e4b17023SJohn Marino      until we have only one operand.  */
2250e4b17023SJohn Marino   rest = (unsigned)(ops_num - res * cpu_width);
2251e4b17023SJohn Marino   elog = exact_log2 (rest);
2252e4b17023SJohn Marino   if (elog >= 0)
2253e4b17023SJohn Marino     res += elog;
2254e4b17023SJohn Marino   else
2255e4b17023SJohn Marino     res += floor_log2 (rest) + 1;
2256e4b17023SJohn Marino 
2257e4b17023SJohn Marino   return res;
2258e4b17023SJohn Marino }
2259e4b17023SJohn Marino 
2260e4b17023SJohn Marino /* Returns an optimal number of registers to use for computation of
2261e4b17023SJohn Marino    given statements.  */
2262e4b17023SJohn Marino 
2263e4b17023SJohn Marino static int
get_reassociation_width(int ops_num,enum tree_code opc,enum machine_mode mode)2264e4b17023SJohn Marino get_reassociation_width (int ops_num, enum tree_code opc,
2265e4b17023SJohn Marino 			 enum machine_mode mode)
2266e4b17023SJohn Marino {
2267e4b17023SJohn Marino   int param_width = PARAM_VALUE (PARAM_TREE_REASSOC_WIDTH);
2268e4b17023SJohn Marino   int width;
2269e4b17023SJohn Marino   int width_min;
2270e4b17023SJohn Marino   int cycles_best;
2271e4b17023SJohn Marino 
2272e4b17023SJohn Marino   if (param_width > 0)
2273e4b17023SJohn Marino     width = param_width;
2274e4b17023SJohn Marino   else
2275e4b17023SJohn Marino     width = targetm.sched.reassociation_width (opc, mode);
2276e4b17023SJohn Marino 
2277e4b17023SJohn Marino   if (width == 1)
2278e4b17023SJohn Marino     return width;
2279e4b17023SJohn Marino 
2280e4b17023SJohn Marino   /* Get the minimal time required for sequence computation.  */
2281e4b17023SJohn Marino   cycles_best = get_required_cycles (ops_num, width);
2282e4b17023SJohn Marino 
2283e4b17023SJohn Marino   /* Check if we may use less width and still compute sequence for
2284e4b17023SJohn Marino      the same time.  It will allow us to reduce registers usage.
2285e4b17023SJohn Marino      get_required_cycles is monotonically increasing with lower width
2286e4b17023SJohn Marino      so we can perform a binary search for the minimal width that still
2287e4b17023SJohn Marino      results in the optimal cycle count.  */
2288e4b17023SJohn Marino   width_min = 1;
2289e4b17023SJohn Marino   while (width > width_min)
2290e4b17023SJohn Marino     {
2291e4b17023SJohn Marino       int width_mid = (width + width_min) / 2;
2292e4b17023SJohn Marino 
2293e4b17023SJohn Marino       if (get_required_cycles (ops_num, width_mid) == cycles_best)
2294e4b17023SJohn Marino 	width = width_mid;
2295e4b17023SJohn Marino       else if (width_min < width_mid)
2296e4b17023SJohn Marino 	width_min = width_mid;
2297e4b17023SJohn Marino       else
2298e4b17023SJohn Marino 	break;
2299e4b17023SJohn Marino     }
2300e4b17023SJohn Marino 
2301e4b17023SJohn Marino   return width;
2302e4b17023SJohn Marino }
2303e4b17023SJohn Marino 
2304e4b17023SJohn Marino /* Recursively rewrite our linearized statements so that the operators
2305e4b17023SJohn Marino    match those in OPS[OPINDEX], putting the computation in rank
2306e4b17023SJohn Marino    order and trying to allow operations to be executed in
2307e4b17023SJohn Marino    parallel.  */
2308e4b17023SJohn Marino 
2309e4b17023SJohn Marino static void
rewrite_expr_tree_parallel(gimple stmt,int width,VEC (operand_entry_t,heap)* ops)2310e4b17023SJohn Marino rewrite_expr_tree_parallel (gimple stmt, int width,
2311e4b17023SJohn Marino 			    VEC(operand_entry_t, heap) * ops)
2312e4b17023SJohn Marino {
2313e4b17023SJohn Marino   enum tree_code opcode = gimple_assign_rhs_code (stmt);
2314e4b17023SJohn Marino   int op_num = VEC_length (operand_entry_t, ops);
2315*8410f2e8Szrj   gcc_assert (op_num > 0);
2316e4b17023SJohn Marino   int stmt_num = op_num - 1;
2317e4b17023SJohn Marino   gimple *stmts = XALLOCAVEC (gimple, stmt_num);
2318e4b17023SJohn Marino   int op_index = op_num - 1;
2319e4b17023SJohn Marino   int stmt_index = 0;
2320e4b17023SJohn Marino   int ready_stmts_end = 0;
2321e4b17023SJohn Marino   int i = 0;
2322e4b17023SJohn Marino   tree last_rhs1 = gimple_assign_rhs1 (stmt);
2323e4b17023SJohn Marino   tree lhs_var;
2324e4b17023SJohn Marino 
2325e4b17023SJohn Marino   /* We start expression rewriting from the top statements.
2326e4b17023SJohn Marino      So, in this loop we create a full list of statements
2327e4b17023SJohn Marino      we will work with.  */
2328e4b17023SJohn Marino   stmts[stmt_num - 1] = stmt;
2329e4b17023SJohn Marino   for (i = stmt_num - 2; i >= 0; i--)
2330e4b17023SJohn Marino     stmts[i] = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmts[i+1]));
2331e4b17023SJohn Marino 
2332e4b17023SJohn Marino   lhs_var = create_tmp_reg (TREE_TYPE (last_rhs1), NULL);
2333e4b17023SJohn Marino   add_referenced_var (lhs_var);
2334e4b17023SJohn Marino 
2335e4b17023SJohn Marino   for (i = 0; i < stmt_num; i++)
2336e4b17023SJohn Marino     {
2337e4b17023SJohn Marino       tree op1, op2;
2338e4b17023SJohn Marino 
2339e4b17023SJohn Marino       /* Determine whether we should use results of
2340e4b17023SJohn Marino 	 already handled statements or not.  */
2341e4b17023SJohn Marino       if (ready_stmts_end == 0
2342e4b17023SJohn Marino 	  && (i - stmt_index >= width || op_index < 1))
2343e4b17023SJohn Marino 	ready_stmts_end = i;
2344e4b17023SJohn Marino 
2345e4b17023SJohn Marino       /* Now we choose operands for the next statement.  Non zero
2346e4b17023SJohn Marino 	 value in ready_stmts_end means here that we should use
2347e4b17023SJohn Marino 	 the result of already generated statements as new operand.  */
2348e4b17023SJohn Marino       if (ready_stmts_end > 0)
2349e4b17023SJohn Marino 	{
2350e4b17023SJohn Marino 	  op1 = gimple_assign_lhs (stmts[stmt_index++]);
2351e4b17023SJohn Marino 	  if (ready_stmts_end > stmt_index)
2352e4b17023SJohn Marino 	    op2 = gimple_assign_lhs (stmts[stmt_index++]);
2353e4b17023SJohn Marino 	  else if (op_index >= 0)
2354e4b17023SJohn Marino 	    op2 = VEC_index (operand_entry_t, ops, op_index--)->op;
2355e4b17023SJohn Marino 	  else
2356e4b17023SJohn Marino 	    {
2357e4b17023SJohn Marino 	      gcc_assert (stmt_index < i);
2358e4b17023SJohn Marino 	      op2 = gimple_assign_lhs (stmts[stmt_index++]);
2359e4b17023SJohn Marino 	    }
2360e4b17023SJohn Marino 
2361e4b17023SJohn Marino 	  if (stmt_index >= ready_stmts_end)
2362e4b17023SJohn Marino 	    ready_stmts_end = 0;
2363e4b17023SJohn Marino 	}
2364e4b17023SJohn Marino       else
2365e4b17023SJohn Marino 	{
2366e4b17023SJohn Marino 	  if (op_index > 1)
2367e4b17023SJohn Marino 	    swap_ops_for_binary_stmt (ops, op_index - 2, NULL);
2368e4b17023SJohn Marino 	  op2 = VEC_index (operand_entry_t, ops, op_index--)->op;
2369e4b17023SJohn Marino 	  op1 = VEC_index (operand_entry_t, ops, op_index--)->op;
2370e4b17023SJohn Marino 	}
2371e4b17023SJohn Marino 
2372e4b17023SJohn Marino       /* If we emit the last statement then we should put
2373e4b17023SJohn Marino 	 operands into the last statement.  It will also
2374e4b17023SJohn Marino 	 break the loop.  */
2375e4b17023SJohn Marino       if (op_index < 0 && stmt_index == i)
2376e4b17023SJohn Marino 	i = stmt_num - 1;
2377e4b17023SJohn Marino 
2378e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2379e4b17023SJohn Marino 	{
2380e4b17023SJohn Marino 	  fprintf (dump_file, "Transforming ");
2381e4b17023SJohn Marino 	  print_gimple_stmt (dump_file, stmts[i], 0, 0);
2382e4b17023SJohn Marino 	}
2383e4b17023SJohn Marino 
2384e4b17023SJohn Marino       /* We keep original statement only for the last one.  All
2385e4b17023SJohn Marino 	 others are recreated.  */
2386e4b17023SJohn Marino       if (i == stmt_num - 1)
2387e4b17023SJohn Marino 	{
2388e4b17023SJohn Marino 	  gimple_assign_set_rhs1 (stmts[i], op1);
2389e4b17023SJohn Marino 	  gimple_assign_set_rhs2 (stmts[i], op2);
2390e4b17023SJohn Marino 	  update_stmt (stmts[i]);
2391e4b17023SJohn Marino 	}
2392e4b17023SJohn Marino       else
2393e4b17023SJohn Marino 	stmts[i] = build_and_add_sum (lhs_var, op1, op2, opcode);
2394e4b17023SJohn Marino 
2395e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2396e4b17023SJohn Marino 	{
2397e4b17023SJohn Marino 	  fprintf (dump_file, " into ");
2398e4b17023SJohn Marino 	  print_gimple_stmt (dump_file, stmts[i], 0, 0);
2399e4b17023SJohn Marino 	}
2400e4b17023SJohn Marino     }
2401e4b17023SJohn Marino 
2402e4b17023SJohn Marino   remove_visited_stmt_chain (last_rhs1);
2403e4b17023SJohn Marino }
2404e4b17023SJohn Marino 
2405e4b17023SJohn Marino /* Transform STMT, which is really (A +B) + (C + D) into the left
2406e4b17023SJohn Marino    linear form, ((A+B)+C)+D.
2407e4b17023SJohn Marino    Recurse on D if necessary.  */
2408e4b17023SJohn Marino 
2409e4b17023SJohn Marino static void
linearize_expr(gimple stmt)2410e4b17023SJohn Marino linearize_expr (gimple stmt)
2411e4b17023SJohn Marino {
2412e4b17023SJohn Marino   gimple_stmt_iterator gsinow, gsirhs;
2413e4b17023SJohn Marino   gimple binlhs = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
2414e4b17023SJohn Marino   gimple binrhs = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
2415e4b17023SJohn Marino   enum tree_code rhscode = gimple_assign_rhs_code (stmt);
2416e4b17023SJohn Marino   gimple newbinrhs = NULL;
2417e4b17023SJohn Marino   struct loop *loop = loop_containing_stmt (stmt);
2418e4b17023SJohn Marino 
2419e4b17023SJohn Marino   gcc_assert (is_reassociable_op (binlhs, rhscode, loop)
2420e4b17023SJohn Marino 	      && is_reassociable_op (binrhs, rhscode, loop));
2421e4b17023SJohn Marino 
2422e4b17023SJohn Marino   gsinow = gsi_for_stmt (stmt);
2423e4b17023SJohn Marino   gsirhs = gsi_for_stmt (binrhs);
2424e4b17023SJohn Marino   gsi_move_before (&gsirhs, &gsinow);
2425e4b17023SJohn Marino 
2426e4b17023SJohn Marino   gimple_assign_set_rhs2 (stmt, gimple_assign_rhs1 (binrhs));
2427e4b17023SJohn Marino   gimple_assign_set_rhs1 (binrhs, gimple_assign_lhs (binlhs));
2428e4b17023SJohn Marino   gimple_assign_set_rhs1 (stmt, gimple_assign_lhs (binrhs));
2429e4b17023SJohn Marino 
2430e4b17023SJohn Marino   if (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME)
2431e4b17023SJohn Marino     newbinrhs = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt));
2432e4b17023SJohn Marino 
2433e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2434e4b17023SJohn Marino     {
2435e4b17023SJohn Marino       fprintf (dump_file, "Linearized: ");
2436e4b17023SJohn Marino       print_gimple_stmt (dump_file, stmt, 0, 0);
2437e4b17023SJohn Marino     }
2438e4b17023SJohn Marino 
2439e4b17023SJohn Marino   reassociate_stats.linearized++;
2440e4b17023SJohn Marino   update_stmt (binrhs);
2441e4b17023SJohn Marino   update_stmt (binlhs);
2442e4b17023SJohn Marino   update_stmt (stmt);
2443e4b17023SJohn Marino 
2444e4b17023SJohn Marino   gimple_set_visited (stmt, true);
2445e4b17023SJohn Marino   gimple_set_visited (binlhs, true);
2446e4b17023SJohn Marino   gimple_set_visited (binrhs, true);
2447e4b17023SJohn Marino 
2448e4b17023SJohn Marino   /* Tail recurse on the new rhs if it still needs reassociation.  */
2449e4b17023SJohn Marino   if (newbinrhs && is_reassociable_op (newbinrhs, rhscode, loop))
2450e4b17023SJohn Marino     /* ??? This should probably be linearize_expr (newbinrhs) but I don't
2451e4b17023SJohn Marino 	   want to change the algorithm while converting to tuples.  */
2452e4b17023SJohn Marino     linearize_expr (stmt);
2453e4b17023SJohn Marino }
2454e4b17023SJohn Marino 
2455e4b17023SJohn Marino /* If LHS has a single immediate use that is a GIMPLE_ASSIGN statement, return
2456e4b17023SJohn Marino    it.  Otherwise, return NULL.  */
2457e4b17023SJohn Marino 
2458e4b17023SJohn Marino static gimple
get_single_immediate_use(tree lhs)2459e4b17023SJohn Marino get_single_immediate_use (tree lhs)
2460e4b17023SJohn Marino {
2461e4b17023SJohn Marino   use_operand_p immuse;
2462e4b17023SJohn Marino   gimple immusestmt;
2463e4b17023SJohn Marino 
2464e4b17023SJohn Marino   if (TREE_CODE (lhs) == SSA_NAME
2465e4b17023SJohn Marino       && single_imm_use (lhs, &immuse, &immusestmt)
2466e4b17023SJohn Marino       && is_gimple_assign (immusestmt))
2467e4b17023SJohn Marino     return immusestmt;
2468e4b17023SJohn Marino 
2469e4b17023SJohn Marino   return NULL;
2470e4b17023SJohn Marino }
2471e4b17023SJohn Marino 
2472e4b17023SJohn Marino /* Recursively negate the value of TONEGATE, and return the SSA_NAME
2473e4b17023SJohn Marino    representing the negated value.  Insertions of any necessary
2474e4b17023SJohn Marino    instructions go before GSI.
2475e4b17023SJohn Marino    This function is recursive in that, if you hand it "a_5" as the
2476e4b17023SJohn Marino    value to negate, and a_5 is defined by "a_5 = b_3 + b_4", it will
2477e4b17023SJohn Marino    transform b_3 + b_4 into a_5 = -b_3 + -b_4.  */
2478e4b17023SJohn Marino 
2479e4b17023SJohn Marino static tree
negate_value(tree tonegate,gimple_stmt_iterator * gsi)2480e4b17023SJohn Marino negate_value (tree tonegate, gimple_stmt_iterator *gsi)
2481e4b17023SJohn Marino {
2482e4b17023SJohn Marino   gimple negatedefstmt= NULL;
2483e4b17023SJohn Marino   tree resultofnegate;
2484e4b17023SJohn Marino 
2485e4b17023SJohn Marino   /* If we are trying to negate a name, defined by an add, negate the
2486e4b17023SJohn Marino      add operands instead.  */
2487e4b17023SJohn Marino   if (TREE_CODE (tonegate) == SSA_NAME)
2488e4b17023SJohn Marino     negatedefstmt = SSA_NAME_DEF_STMT (tonegate);
2489e4b17023SJohn Marino   if (TREE_CODE (tonegate) == SSA_NAME
2490e4b17023SJohn Marino       && is_gimple_assign (negatedefstmt)
2491e4b17023SJohn Marino       && TREE_CODE (gimple_assign_lhs (negatedefstmt)) == SSA_NAME
2492e4b17023SJohn Marino       && has_single_use (gimple_assign_lhs (negatedefstmt))
2493e4b17023SJohn Marino       && gimple_assign_rhs_code (negatedefstmt) == PLUS_EXPR)
2494e4b17023SJohn Marino     {
2495e4b17023SJohn Marino       gimple_stmt_iterator gsi;
2496e4b17023SJohn Marino       tree rhs1 = gimple_assign_rhs1 (negatedefstmt);
2497e4b17023SJohn Marino       tree rhs2 = gimple_assign_rhs2 (negatedefstmt);
2498e4b17023SJohn Marino 
2499e4b17023SJohn Marino       gsi = gsi_for_stmt (negatedefstmt);
2500e4b17023SJohn Marino       rhs1 = negate_value (rhs1, &gsi);
2501e4b17023SJohn Marino       gimple_assign_set_rhs1 (negatedefstmt, rhs1);
2502e4b17023SJohn Marino 
2503e4b17023SJohn Marino       gsi = gsi_for_stmt (negatedefstmt);
2504e4b17023SJohn Marino       rhs2 = negate_value (rhs2, &gsi);
2505e4b17023SJohn Marino       gimple_assign_set_rhs2 (negatedefstmt, rhs2);
2506e4b17023SJohn Marino 
2507e4b17023SJohn Marino       update_stmt (negatedefstmt);
2508e4b17023SJohn Marino       return gimple_assign_lhs (negatedefstmt);
2509e4b17023SJohn Marino     }
2510e4b17023SJohn Marino 
2511e4b17023SJohn Marino   tonegate = fold_build1 (NEGATE_EXPR, TREE_TYPE (tonegate), tonegate);
2512e4b17023SJohn Marino   resultofnegate = force_gimple_operand_gsi (gsi, tonegate, true,
2513e4b17023SJohn Marino 					     NULL_TREE, true, GSI_SAME_STMT);
2514e4b17023SJohn Marino   return resultofnegate;
2515e4b17023SJohn Marino }
2516e4b17023SJohn Marino 
2517e4b17023SJohn Marino /* Return true if we should break up the subtract in STMT into an add
2518e4b17023SJohn Marino    with negate.  This is true when we the subtract operands are really
2519e4b17023SJohn Marino    adds, or the subtract itself is used in an add expression.  In
2520e4b17023SJohn Marino    either case, breaking up the subtract into an add with negate
2521e4b17023SJohn Marino    exposes the adds to reassociation.  */
2522e4b17023SJohn Marino 
2523e4b17023SJohn Marino static bool
should_break_up_subtract(gimple stmt)2524e4b17023SJohn Marino should_break_up_subtract (gimple stmt)
2525e4b17023SJohn Marino {
2526e4b17023SJohn Marino   tree lhs = gimple_assign_lhs (stmt);
2527e4b17023SJohn Marino   tree binlhs = gimple_assign_rhs1 (stmt);
2528e4b17023SJohn Marino   tree binrhs = gimple_assign_rhs2 (stmt);
2529e4b17023SJohn Marino   gimple immusestmt;
2530e4b17023SJohn Marino   struct loop *loop = loop_containing_stmt (stmt);
2531e4b17023SJohn Marino 
2532e4b17023SJohn Marino   if (TREE_CODE (binlhs) == SSA_NAME
2533e4b17023SJohn Marino       && is_reassociable_op (SSA_NAME_DEF_STMT (binlhs), PLUS_EXPR, loop))
2534e4b17023SJohn Marino     return true;
2535e4b17023SJohn Marino 
2536e4b17023SJohn Marino   if (TREE_CODE (binrhs) == SSA_NAME
2537e4b17023SJohn Marino       && is_reassociable_op (SSA_NAME_DEF_STMT (binrhs), PLUS_EXPR, loop))
2538e4b17023SJohn Marino     return true;
2539e4b17023SJohn Marino 
2540e4b17023SJohn Marino   if (TREE_CODE (lhs) == SSA_NAME
2541e4b17023SJohn Marino       && (immusestmt = get_single_immediate_use (lhs))
2542e4b17023SJohn Marino       && is_gimple_assign (immusestmt)
2543e4b17023SJohn Marino       && (gimple_assign_rhs_code (immusestmt) == PLUS_EXPR
2544e4b17023SJohn Marino 	  ||  gimple_assign_rhs_code (immusestmt) == MULT_EXPR))
2545e4b17023SJohn Marino     return true;
2546e4b17023SJohn Marino   return false;
2547e4b17023SJohn Marino }
2548e4b17023SJohn Marino 
2549e4b17023SJohn Marino /* Transform STMT from A - B into A + -B.  */
2550e4b17023SJohn Marino 
2551e4b17023SJohn Marino static void
break_up_subtract(gimple stmt,gimple_stmt_iterator * gsip)2552e4b17023SJohn Marino break_up_subtract (gimple stmt, gimple_stmt_iterator *gsip)
2553e4b17023SJohn Marino {
2554e4b17023SJohn Marino   tree rhs1 = gimple_assign_rhs1 (stmt);
2555e4b17023SJohn Marino   tree rhs2 = gimple_assign_rhs2 (stmt);
2556e4b17023SJohn Marino 
2557e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2558e4b17023SJohn Marino     {
2559e4b17023SJohn Marino       fprintf (dump_file, "Breaking up subtract ");
2560e4b17023SJohn Marino       print_gimple_stmt (dump_file, stmt, 0, 0);
2561e4b17023SJohn Marino     }
2562e4b17023SJohn Marino 
2563e4b17023SJohn Marino   rhs2 = negate_value (rhs2, gsip);
2564e4b17023SJohn Marino   gimple_assign_set_rhs_with_ops (gsip, PLUS_EXPR, rhs1, rhs2);
2565e4b17023SJohn Marino   update_stmt (stmt);
2566e4b17023SJohn Marino }
2567e4b17023SJohn Marino 
2568e4b17023SJohn Marino /* Recursively linearize a binary expression that is the RHS of STMT.
2569e4b17023SJohn Marino    Place the operands of the expression tree in the vector named OPS.  */
2570e4b17023SJohn Marino 
2571e4b17023SJohn Marino static void
linearize_expr_tree(VEC (operand_entry_t,heap)** ops,gimple stmt,bool is_associative,bool set_visited)2572e4b17023SJohn Marino linearize_expr_tree (VEC(operand_entry_t, heap) **ops, gimple stmt,
2573e4b17023SJohn Marino 		     bool is_associative, bool set_visited)
2574e4b17023SJohn Marino {
2575e4b17023SJohn Marino   tree binlhs = gimple_assign_rhs1 (stmt);
2576e4b17023SJohn Marino   tree binrhs = gimple_assign_rhs2 (stmt);
2577e4b17023SJohn Marino   gimple binlhsdef, binrhsdef;
2578e4b17023SJohn Marino   bool binlhsisreassoc = false;
2579e4b17023SJohn Marino   bool binrhsisreassoc = false;
2580e4b17023SJohn Marino   enum tree_code rhscode = gimple_assign_rhs_code (stmt);
2581e4b17023SJohn Marino   struct loop *loop = loop_containing_stmt (stmt);
2582e4b17023SJohn Marino 
2583e4b17023SJohn Marino   if (set_visited)
2584e4b17023SJohn Marino     gimple_set_visited (stmt, true);
2585e4b17023SJohn Marino 
2586e4b17023SJohn Marino   if (TREE_CODE (binlhs) == SSA_NAME)
2587e4b17023SJohn Marino     {
2588e4b17023SJohn Marino       binlhsdef = SSA_NAME_DEF_STMT (binlhs);
2589e4b17023SJohn Marino       binlhsisreassoc = (is_reassociable_op (binlhsdef, rhscode, loop)
2590e4b17023SJohn Marino 			 && !stmt_could_throw_p (binlhsdef));
2591e4b17023SJohn Marino     }
2592e4b17023SJohn Marino 
2593e4b17023SJohn Marino   if (TREE_CODE (binrhs) == SSA_NAME)
2594e4b17023SJohn Marino     {
2595e4b17023SJohn Marino       binrhsdef = SSA_NAME_DEF_STMT (binrhs);
2596e4b17023SJohn Marino       binrhsisreassoc = (is_reassociable_op (binrhsdef, rhscode, loop)
2597e4b17023SJohn Marino 			 && !stmt_could_throw_p (binrhsdef));
2598e4b17023SJohn Marino     }
2599e4b17023SJohn Marino 
2600e4b17023SJohn Marino   /* If the LHS is not reassociable, but the RHS is, we need to swap
2601e4b17023SJohn Marino      them.  If neither is reassociable, there is nothing we can do, so
2602e4b17023SJohn Marino      just put them in the ops vector.  If the LHS is reassociable,
2603e4b17023SJohn Marino      linearize it.  If both are reassociable, then linearize the RHS
2604e4b17023SJohn Marino      and the LHS.  */
2605e4b17023SJohn Marino 
2606e4b17023SJohn Marino   if (!binlhsisreassoc)
2607e4b17023SJohn Marino     {
2608e4b17023SJohn Marino       tree temp;
2609e4b17023SJohn Marino 
2610e4b17023SJohn Marino       /* If this is not a associative operation like division, give up.  */
2611e4b17023SJohn Marino       if (!is_associative)
2612e4b17023SJohn Marino 	{
2613e4b17023SJohn Marino 	  add_to_ops_vec (ops, binrhs);
2614e4b17023SJohn Marino 	  return;
2615e4b17023SJohn Marino 	}
2616e4b17023SJohn Marino 
2617e4b17023SJohn Marino       if (!binrhsisreassoc)
2618e4b17023SJohn Marino 	{
2619e4b17023SJohn Marino 	  add_to_ops_vec (ops, binrhs);
2620e4b17023SJohn Marino 	  add_to_ops_vec (ops, binlhs);
2621e4b17023SJohn Marino 	  return;
2622e4b17023SJohn Marino 	}
2623e4b17023SJohn Marino 
2624e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2625e4b17023SJohn Marino 	{
2626e4b17023SJohn Marino 	  fprintf (dump_file, "swapping operands of ");
2627e4b17023SJohn Marino 	  print_gimple_stmt (dump_file, stmt, 0, 0);
2628e4b17023SJohn Marino 	}
2629e4b17023SJohn Marino 
2630e4b17023SJohn Marino       swap_tree_operands (stmt,
2631e4b17023SJohn Marino 			  gimple_assign_rhs1_ptr (stmt),
2632e4b17023SJohn Marino 			  gimple_assign_rhs2_ptr (stmt));
2633e4b17023SJohn Marino       update_stmt (stmt);
2634e4b17023SJohn Marino 
2635e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2636e4b17023SJohn Marino 	{
2637e4b17023SJohn Marino 	  fprintf (dump_file, " is now ");
2638e4b17023SJohn Marino 	  print_gimple_stmt (dump_file, stmt, 0, 0);
2639e4b17023SJohn Marino 	}
2640e4b17023SJohn Marino 
2641e4b17023SJohn Marino       /* We want to make it so the lhs is always the reassociative op,
2642e4b17023SJohn Marino 	 so swap.  */
2643e4b17023SJohn Marino       temp = binlhs;
2644e4b17023SJohn Marino       binlhs = binrhs;
2645e4b17023SJohn Marino       binrhs = temp;
2646e4b17023SJohn Marino     }
2647e4b17023SJohn Marino   else if (binrhsisreassoc)
2648e4b17023SJohn Marino     {
2649e4b17023SJohn Marino       linearize_expr (stmt);
2650e4b17023SJohn Marino       binlhs = gimple_assign_rhs1 (stmt);
2651e4b17023SJohn Marino       binrhs = gimple_assign_rhs2 (stmt);
2652e4b17023SJohn Marino     }
2653e4b17023SJohn Marino 
2654e4b17023SJohn Marino   gcc_assert (TREE_CODE (binrhs) != SSA_NAME
2655e4b17023SJohn Marino 	      || !is_reassociable_op (SSA_NAME_DEF_STMT (binrhs),
2656e4b17023SJohn Marino 				      rhscode, loop));
2657e4b17023SJohn Marino   linearize_expr_tree (ops, SSA_NAME_DEF_STMT (binlhs),
2658e4b17023SJohn Marino 		       is_associative, set_visited);
2659e4b17023SJohn Marino   add_to_ops_vec (ops, binrhs);
2660e4b17023SJohn Marino }
2661e4b17023SJohn Marino 
2662e4b17023SJohn Marino /* Repropagate the negates back into subtracts, since no other pass
2663e4b17023SJohn Marino    currently does it.  */
2664e4b17023SJohn Marino 
2665e4b17023SJohn Marino static void
repropagate_negates(void)2666e4b17023SJohn Marino repropagate_negates (void)
2667e4b17023SJohn Marino {
2668e4b17023SJohn Marino   unsigned int i = 0;
2669e4b17023SJohn Marino   tree negate;
2670e4b17023SJohn Marino 
2671e4b17023SJohn Marino   FOR_EACH_VEC_ELT (tree, plus_negates, i, negate)
2672e4b17023SJohn Marino     {
2673e4b17023SJohn Marino       gimple user = get_single_immediate_use (negate);
2674e4b17023SJohn Marino 
2675e4b17023SJohn Marino       if (!user || !is_gimple_assign (user))
2676e4b17023SJohn Marino 	continue;
2677e4b17023SJohn Marino 
2678e4b17023SJohn Marino       /* The negate operand can be either operand of a PLUS_EXPR
2679e4b17023SJohn Marino 	 (it can be the LHS if the RHS is a constant for example).
2680e4b17023SJohn Marino 
2681e4b17023SJohn Marino 	 Force the negate operand to the RHS of the PLUS_EXPR, then
2682e4b17023SJohn Marino 	 transform the PLUS_EXPR into a MINUS_EXPR.  */
2683e4b17023SJohn Marino       if (gimple_assign_rhs_code (user) == PLUS_EXPR)
2684e4b17023SJohn Marino 	{
2685e4b17023SJohn Marino 	  /* If the negated operand appears on the LHS of the
2686e4b17023SJohn Marino 	     PLUS_EXPR, exchange the operands of the PLUS_EXPR
2687e4b17023SJohn Marino 	     to force the negated operand to the RHS of the PLUS_EXPR.  */
2688e4b17023SJohn Marino 	  if (gimple_assign_rhs1 (user) == negate)
2689e4b17023SJohn Marino 	    {
2690e4b17023SJohn Marino 	      swap_tree_operands (user,
2691e4b17023SJohn Marino 				  gimple_assign_rhs1_ptr (user),
2692e4b17023SJohn Marino 				  gimple_assign_rhs2_ptr (user));
2693e4b17023SJohn Marino 	    }
2694e4b17023SJohn Marino 
2695e4b17023SJohn Marino 	  /* Now transform the PLUS_EXPR into a MINUS_EXPR and replace
2696e4b17023SJohn Marino 	     the RHS of the PLUS_EXPR with the operand of the NEGATE_EXPR.  */
2697e4b17023SJohn Marino 	  if (gimple_assign_rhs2 (user) == negate)
2698e4b17023SJohn Marino 	    {
2699e4b17023SJohn Marino 	      tree rhs1 = gimple_assign_rhs1 (user);
2700e4b17023SJohn Marino 	      tree rhs2 = get_unary_op (negate, NEGATE_EXPR);
2701e4b17023SJohn Marino 	      gimple_stmt_iterator gsi = gsi_for_stmt (user);
2702e4b17023SJohn Marino 	      gimple_assign_set_rhs_with_ops (&gsi, MINUS_EXPR, rhs1, rhs2);
2703e4b17023SJohn Marino 	      update_stmt (user);
2704e4b17023SJohn Marino 	    }
2705e4b17023SJohn Marino 	}
2706e4b17023SJohn Marino       else if (gimple_assign_rhs_code (user) == MINUS_EXPR)
2707e4b17023SJohn Marino 	{
2708e4b17023SJohn Marino 	  if (gimple_assign_rhs1 (user) == negate)
2709e4b17023SJohn Marino 	    {
2710e4b17023SJohn Marino 	      /* We have
2711e4b17023SJohn Marino 	           x = -a
2712e4b17023SJohn Marino 		   y = x - b
2713e4b17023SJohn Marino 		 which we transform into
2714e4b17023SJohn Marino 		   x = a + b
2715e4b17023SJohn Marino 		   y = -x .
2716e4b17023SJohn Marino 		 This pushes down the negate which we possibly can merge
2717e4b17023SJohn Marino 		 into some other operation, hence insert it into the
2718e4b17023SJohn Marino 		 plus_negates vector.  */
2719e4b17023SJohn Marino 	      gimple feed = SSA_NAME_DEF_STMT (negate);
2720e4b17023SJohn Marino 	      tree a = gimple_assign_rhs1 (feed);
2721e4b17023SJohn Marino 	      tree rhs2 = gimple_assign_rhs2 (user);
2722e4b17023SJohn Marino 	      gimple_stmt_iterator gsi = gsi_for_stmt (feed), gsi2;
2723e4b17023SJohn Marino 	      gimple_replace_lhs (feed, negate);
2724e4b17023SJohn Marino 	      gimple_assign_set_rhs_with_ops (&gsi, PLUS_EXPR, a, rhs2);
2725e4b17023SJohn Marino 	      update_stmt (gsi_stmt (gsi));
2726e4b17023SJohn Marino 	      gsi2 = gsi_for_stmt (user);
2727e4b17023SJohn Marino 	      gimple_assign_set_rhs_with_ops (&gsi2, NEGATE_EXPR, negate, NULL);
2728e4b17023SJohn Marino 	      update_stmt (gsi_stmt (gsi2));
2729e4b17023SJohn Marino 	      gsi_move_before (&gsi, &gsi2);
2730e4b17023SJohn Marino 	      VEC_safe_push (tree, heap, plus_negates,
2731e4b17023SJohn Marino 			     gimple_assign_lhs (gsi_stmt (gsi2)));
2732e4b17023SJohn Marino 	    }
2733e4b17023SJohn Marino 	  else
2734e4b17023SJohn Marino 	    {
2735e4b17023SJohn Marino 	      /* Transform "x = -a; y = b - x" into "y = b + a", getting
2736e4b17023SJohn Marino 	         rid of one operation.  */
2737e4b17023SJohn Marino 	      gimple feed = SSA_NAME_DEF_STMT (negate);
2738e4b17023SJohn Marino 	      tree a = gimple_assign_rhs1 (feed);
2739e4b17023SJohn Marino 	      tree rhs1 = gimple_assign_rhs1 (user);
2740e4b17023SJohn Marino 	      gimple_stmt_iterator gsi = gsi_for_stmt (user);
2741e4b17023SJohn Marino 	      gimple_assign_set_rhs_with_ops (&gsi, PLUS_EXPR, rhs1, a);
2742e4b17023SJohn Marino 	      update_stmt (gsi_stmt (gsi));
2743e4b17023SJohn Marino 	    }
2744e4b17023SJohn Marino 	}
2745e4b17023SJohn Marino     }
2746e4b17023SJohn Marino }
2747e4b17023SJohn Marino 
2748e4b17023SJohn Marino /* Returns true if OP is of a type for which we can do reassociation.
2749e4b17023SJohn Marino    That is for integral or non-saturating fixed-point types, and for
2750e4b17023SJohn Marino    floating point type when associative-math is enabled.  */
2751e4b17023SJohn Marino 
2752e4b17023SJohn Marino static bool
can_reassociate_p(tree op)2753e4b17023SJohn Marino can_reassociate_p (tree op)
2754e4b17023SJohn Marino {
2755e4b17023SJohn Marino   tree type = TREE_TYPE (op);
2756e4b17023SJohn Marino   if ((INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type))
2757e4b17023SJohn Marino       || NON_SAT_FIXED_POINT_TYPE_P (type)
2758e4b17023SJohn Marino       || (flag_associative_math && FLOAT_TYPE_P (type)))
2759e4b17023SJohn Marino     return true;
2760e4b17023SJohn Marino   return false;
2761e4b17023SJohn Marino }
2762e4b17023SJohn Marino 
2763e4b17023SJohn Marino /* Break up subtract operations in block BB.
2764e4b17023SJohn Marino 
2765e4b17023SJohn Marino    We do this top down because we don't know whether the subtract is
2766e4b17023SJohn Marino    part of a possible chain of reassociation except at the top.
2767e4b17023SJohn Marino 
2768e4b17023SJohn Marino    IE given
2769e4b17023SJohn Marino    d = f + g
2770e4b17023SJohn Marino    c = a + e
2771e4b17023SJohn Marino    b = c - d
2772e4b17023SJohn Marino    q = b - r
2773e4b17023SJohn Marino    k = t - q
2774e4b17023SJohn Marino 
2775e4b17023SJohn Marino    we want to break up k = t - q, but we won't until we've transformed q
2776e4b17023SJohn Marino    = b - r, which won't be broken up until we transform b = c - d.
2777e4b17023SJohn Marino 
2778e4b17023SJohn Marino    En passant, clear the GIMPLE visited flag on every statement.  */
2779e4b17023SJohn Marino 
2780e4b17023SJohn Marino static void
break_up_subtract_bb(basic_block bb)2781e4b17023SJohn Marino break_up_subtract_bb (basic_block bb)
2782e4b17023SJohn Marino {
2783e4b17023SJohn Marino   gimple_stmt_iterator gsi;
2784e4b17023SJohn Marino   basic_block son;
2785e4b17023SJohn Marino 
2786e4b17023SJohn Marino   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2787e4b17023SJohn Marino     {
2788e4b17023SJohn Marino       gimple stmt = gsi_stmt (gsi);
2789e4b17023SJohn Marino       gimple_set_visited (stmt, false);
2790e4b17023SJohn Marino 
2791e4b17023SJohn Marino       if (!is_gimple_assign (stmt)
2792e4b17023SJohn Marino 	  || !can_reassociate_p (gimple_assign_lhs (stmt)))
2793e4b17023SJohn Marino 	continue;
2794e4b17023SJohn Marino 
2795e4b17023SJohn Marino       /* Look for simple gimple subtract operations.  */
2796e4b17023SJohn Marino       if (gimple_assign_rhs_code (stmt) == MINUS_EXPR)
2797e4b17023SJohn Marino 	{
2798e4b17023SJohn Marino 	  if (!can_reassociate_p (gimple_assign_rhs1 (stmt))
2799e4b17023SJohn Marino 	      || !can_reassociate_p (gimple_assign_rhs2 (stmt)))
2800e4b17023SJohn Marino 	    continue;
2801e4b17023SJohn Marino 
2802e4b17023SJohn Marino 	  /* Check for a subtract used only in an addition.  If this
2803e4b17023SJohn Marino 	     is the case, transform it into add of a negate for better
2804e4b17023SJohn Marino 	     reassociation.  IE transform C = A-B into C = A + -B if C
2805e4b17023SJohn Marino 	     is only used in an addition.  */
2806e4b17023SJohn Marino 	  if (should_break_up_subtract (stmt))
2807e4b17023SJohn Marino 	    break_up_subtract (stmt, &gsi);
2808e4b17023SJohn Marino 	}
2809e4b17023SJohn Marino       else if (gimple_assign_rhs_code (stmt) == NEGATE_EXPR
2810e4b17023SJohn Marino 	       && can_reassociate_p (gimple_assign_rhs1 (stmt)))
2811e4b17023SJohn Marino 	VEC_safe_push (tree, heap, plus_negates, gimple_assign_lhs (stmt));
2812e4b17023SJohn Marino     }
2813e4b17023SJohn Marino   for (son = first_dom_son (CDI_DOMINATORS, bb);
2814e4b17023SJohn Marino        son;
2815e4b17023SJohn Marino        son = next_dom_son (CDI_DOMINATORS, son))
2816e4b17023SJohn Marino     break_up_subtract_bb (son);
2817e4b17023SJohn Marino }
2818e4b17023SJohn Marino 
2819e4b17023SJohn Marino /* Reassociate expressions in basic block BB and its post-dominator as
2820e4b17023SJohn Marino    children.  */
2821e4b17023SJohn Marino 
2822e4b17023SJohn Marino static void
reassociate_bb(basic_block bb)2823e4b17023SJohn Marino reassociate_bb (basic_block bb)
2824e4b17023SJohn Marino {
2825e4b17023SJohn Marino   gimple_stmt_iterator gsi;
2826e4b17023SJohn Marino   basic_block son;
2827e4b17023SJohn Marino 
2828e4b17023SJohn Marino   for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
2829e4b17023SJohn Marino     {
2830e4b17023SJohn Marino       gimple stmt = gsi_stmt (gsi);
2831e4b17023SJohn Marino 
2832e4b17023SJohn Marino       if (is_gimple_assign (stmt)
2833e4b17023SJohn Marino 	  && !stmt_could_throw_p (stmt))
2834e4b17023SJohn Marino 	{
2835e4b17023SJohn Marino 	  tree lhs, rhs1, rhs2;
2836e4b17023SJohn Marino 	  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
2837e4b17023SJohn Marino 
2838e4b17023SJohn Marino 	  /* If this is not a gimple binary expression, there is
2839e4b17023SJohn Marino 	     nothing for us to do with it.  */
2840e4b17023SJohn Marino 	  if (get_gimple_rhs_class (rhs_code) != GIMPLE_BINARY_RHS)
2841e4b17023SJohn Marino 	    continue;
2842e4b17023SJohn Marino 
2843e4b17023SJohn Marino 	  /* If this was part of an already processed statement,
2844e4b17023SJohn Marino 	     we don't need to touch it again. */
2845e4b17023SJohn Marino 	  if (gimple_visited_p (stmt))
2846e4b17023SJohn Marino 	    {
2847e4b17023SJohn Marino 	      /* This statement might have become dead because of previous
2848e4b17023SJohn Marino 		 reassociations.  */
2849e4b17023SJohn Marino 	      if (has_zero_uses (gimple_get_lhs (stmt)))
2850e4b17023SJohn Marino 		{
2851e4b17023SJohn Marino 		  gsi_remove (&gsi, true);
2852e4b17023SJohn Marino 		  release_defs (stmt);
2853e4b17023SJohn Marino 		  /* We might end up removing the last stmt above which
2854e4b17023SJohn Marino 		     places the iterator to the end of the sequence.
2855e4b17023SJohn Marino 		     Reset it to the last stmt in this case which might
2856e4b17023SJohn Marino 		     be the end of the sequence as well if we removed
2857e4b17023SJohn Marino 		     the last statement of the sequence.  In which case
2858e4b17023SJohn Marino 		     we need to bail out.  */
2859e4b17023SJohn Marino 		  if (gsi_end_p (gsi))
2860e4b17023SJohn Marino 		    {
2861e4b17023SJohn Marino 		      gsi = gsi_last_bb (bb);
2862e4b17023SJohn Marino 		      if (gsi_end_p (gsi))
2863e4b17023SJohn Marino 			break;
2864e4b17023SJohn Marino 		    }
2865e4b17023SJohn Marino 		}
2866e4b17023SJohn Marino 	      continue;
2867e4b17023SJohn Marino 	    }
2868e4b17023SJohn Marino 
2869e4b17023SJohn Marino 	  lhs = gimple_assign_lhs (stmt);
2870e4b17023SJohn Marino 	  rhs1 = gimple_assign_rhs1 (stmt);
2871e4b17023SJohn Marino 	  rhs2 = gimple_assign_rhs2 (stmt);
2872e4b17023SJohn Marino 
2873e4b17023SJohn Marino 	  /* For non-bit or min/max operations we can't associate
2874e4b17023SJohn Marino 	     all types.  Verify that here.  */
2875e4b17023SJohn Marino 	  if (rhs_code != BIT_IOR_EXPR
2876e4b17023SJohn Marino 	      && rhs_code != BIT_AND_EXPR
2877e4b17023SJohn Marino 	      && rhs_code != BIT_XOR_EXPR
2878e4b17023SJohn Marino 	      && rhs_code != MIN_EXPR
2879e4b17023SJohn Marino 	      && rhs_code != MAX_EXPR
2880e4b17023SJohn Marino 	      && (!can_reassociate_p (lhs)
2881e4b17023SJohn Marino 		  || !can_reassociate_p (rhs1)
2882e4b17023SJohn Marino 		  || !can_reassociate_p (rhs2)))
2883e4b17023SJohn Marino 	    continue;
2884e4b17023SJohn Marino 
2885e4b17023SJohn Marino 	  if (associative_tree_code (rhs_code))
2886e4b17023SJohn Marino 	    {
2887e4b17023SJohn Marino 	      VEC(operand_entry_t, heap) *ops = NULL;
2888e4b17023SJohn Marino 
2889e4b17023SJohn Marino 	      /* There may be no immediate uses left by the time we
2890e4b17023SJohn Marino 		 get here because we may have eliminated them all.  */
2891e4b17023SJohn Marino 	      if (TREE_CODE (lhs) == SSA_NAME && has_zero_uses (lhs))
2892e4b17023SJohn Marino 		continue;
2893e4b17023SJohn Marino 
2894e4b17023SJohn Marino 	      gimple_set_visited (stmt, true);
2895e4b17023SJohn Marino 	      linearize_expr_tree (&ops, stmt, true, true);
2896e4b17023SJohn Marino 	      VEC_qsort (operand_entry_t, ops, sort_by_operand_rank);
2897e4b17023SJohn Marino 	      optimize_ops_list (rhs_code, &ops);
2898e4b17023SJohn Marino 	      if (undistribute_ops_list (rhs_code, &ops,
2899e4b17023SJohn Marino 					 loop_containing_stmt (stmt)))
2900e4b17023SJohn Marino 		{
2901e4b17023SJohn Marino 		  VEC_qsort (operand_entry_t, ops, sort_by_operand_rank);
2902e4b17023SJohn Marino 		  optimize_ops_list (rhs_code, &ops);
2903e4b17023SJohn Marino 		}
2904e4b17023SJohn Marino 
2905e4b17023SJohn Marino 	      if (rhs_code == BIT_IOR_EXPR || rhs_code == BIT_AND_EXPR)
2906e4b17023SJohn Marino 		optimize_range_tests (rhs_code, &ops);
2907e4b17023SJohn Marino 
2908e4b17023SJohn Marino 	      if (VEC_length (operand_entry_t, ops) == 1)
2909e4b17023SJohn Marino 		{
2910e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
2911e4b17023SJohn Marino 		    {
2912e4b17023SJohn Marino 		      fprintf (dump_file, "Transforming ");
2913e4b17023SJohn Marino 		      print_gimple_stmt (dump_file, stmt, 0, 0);
2914e4b17023SJohn Marino 		    }
2915e4b17023SJohn Marino 
2916e4b17023SJohn Marino 		  rhs1 = gimple_assign_rhs1 (stmt);
2917e4b17023SJohn Marino 		  gimple_assign_set_rhs_from_tree (&gsi,
2918e4b17023SJohn Marino 						   VEC_last (operand_entry_t,
2919e4b17023SJohn Marino 							     ops)->op);
2920e4b17023SJohn Marino 		  update_stmt (stmt);
2921e4b17023SJohn Marino 		  remove_visited_stmt_chain (rhs1);
2922e4b17023SJohn Marino 
2923e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
2924e4b17023SJohn Marino 		    {
2925e4b17023SJohn Marino 		      fprintf (dump_file, " into ");
2926e4b17023SJohn Marino 		      print_gimple_stmt (dump_file, stmt, 0, 0);
2927e4b17023SJohn Marino 		    }
2928e4b17023SJohn Marino 		}
2929e4b17023SJohn Marino 	      else
2930e4b17023SJohn Marino 		{
2931e4b17023SJohn Marino 		  enum machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
2932e4b17023SJohn Marino 		  int ops_num = VEC_length (operand_entry_t, ops);
2933e4b17023SJohn Marino 		  int width = get_reassociation_width (ops_num, rhs_code, mode);
2934e4b17023SJohn Marino 
2935e4b17023SJohn Marino 		  if (dump_file && (dump_flags & TDF_DETAILS))
2936e4b17023SJohn Marino 		    fprintf (dump_file,
2937e4b17023SJohn Marino 			     "Width = %d was chosen for reassociation\n", width);
2938e4b17023SJohn Marino 
2939e4b17023SJohn Marino 		  if (width > 1
2940e4b17023SJohn Marino 		      && VEC_length (operand_entry_t, ops) > 3)
2941e4b17023SJohn Marino 		    rewrite_expr_tree_parallel (stmt, width, ops);
2942e4b17023SJohn Marino 		  else
2943e4b17023SJohn Marino 		    rewrite_expr_tree (stmt, 0, ops, false);
2944e4b17023SJohn Marino 		}
2945e4b17023SJohn Marino 
2946e4b17023SJohn Marino 	      VEC_free (operand_entry_t, heap, ops);
2947e4b17023SJohn Marino 	    }
2948e4b17023SJohn Marino 	}
2949e4b17023SJohn Marino     }
2950e4b17023SJohn Marino   for (son = first_dom_son (CDI_POST_DOMINATORS, bb);
2951e4b17023SJohn Marino        son;
2952e4b17023SJohn Marino        son = next_dom_son (CDI_POST_DOMINATORS, son))
2953e4b17023SJohn Marino     reassociate_bb (son);
2954e4b17023SJohn Marino }
2955e4b17023SJohn Marino 
2956e4b17023SJohn Marino void dump_ops_vector (FILE *file, VEC (operand_entry_t, heap) *ops);
2957e4b17023SJohn Marino void debug_ops_vector (VEC (operand_entry_t, heap) *ops);
2958e4b17023SJohn Marino 
2959e4b17023SJohn Marino /* Dump the operand entry vector OPS to FILE.  */
2960e4b17023SJohn Marino 
2961e4b17023SJohn Marino void
dump_ops_vector(FILE * file,VEC (operand_entry_t,heap)* ops)2962e4b17023SJohn Marino dump_ops_vector (FILE *file, VEC (operand_entry_t, heap) *ops)
2963e4b17023SJohn Marino {
2964e4b17023SJohn Marino   operand_entry_t oe;
2965e4b17023SJohn Marino   unsigned int i;
2966e4b17023SJohn Marino 
2967e4b17023SJohn Marino   FOR_EACH_VEC_ELT (operand_entry_t, ops, i, oe)
2968e4b17023SJohn Marino     {
2969e4b17023SJohn Marino       fprintf (file, "Op %d -> rank: %d, tree: ", i, oe->rank);
2970e4b17023SJohn Marino       print_generic_expr (file, oe->op, 0);
2971e4b17023SJohn Marino     }
2972e4b17023SJohn Marino }
2973e4b17023SJohn Marino 
2974e4b17023SJohn Marino /* Dump the operand entry vector OPS to STDERR.  */
2975e4b17023SJohn Marino 
2976e4b17023SJohn Marino DEBUG_FUNCTION void
debug_ops_vector(VEC (operand_entry_t,heap)* ops)2977e4b17023SJohn Marino debug_ops_vector (VEC (operand_entry_t, heap) *ops)
2978e4b17023SJohn Marino {
2979e4b17023SJohn Marino   dump_ops_vector (stderr, ops);
2980e4b17023SJohn Marino }
2981e4b17023SJohn Marino 
2982e4b17023SJohn Marino static void
do_reassoc(void)2983e4b17023SJohn Marino do_reassoc (void)
2984e4b17023SJohn Marino {
2985e4b17023SJohn Marino   break_up_subtract_bb (ENTRY_BLOCK_PTR);
2986e4b17023SJohn Marino   reassociate_bb (EXIT_BLOCK_PTR);
2987e4b17023SJohn Marino }
2988e4b17023SJohn Marino 
2989e4b17023SJohn Marino /* Initialize the reassociation pass.  */
2990e4b17023SJohn Marino 
2991e4b17023SJohn Marino static void
init_reassoc(void)2992e4b17023SJohn Marino init_reassoc (void)
2993e4b17023SJohn Marino {
2994e4b17023SJohn Marino   int i;
2995e4b17023SJohn Marino   long rank = 2;
2996e4b17023SJohn Marino   tree param;
2997e4b17023SJohn Marino   int *bbs = XNEWVEC (int, last_basic_block + 1);
2998e4b17023SJohn Marino 
2999e4b17023SJohn Marino   /* Find the loops, so that we can prevent moving calculations in
3000e4b17023SJohn Marino      them.  */
3001e4b17023SJohn Marino   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3002e4b17023SJohn Marino 
3003e4b17023SJohn Marino   memset (&reassociate_stats, 0, sizeof (reassociate_stats));
3004e4b17023SJohn Marino 
3005e4b17023SJohn Marino   operand_entry_pool = create_alloc_pool ("operand entry pool",
3006e4b17023SJohn Marino 					  sizeof (struct operand_entry), 30);
3007e4b17023SJohn Marino   next_operand_entry_id = 0;
3008e4b17023SJohn Marino 
3009e4b17023SJohn Marino   /* Reverse RPO (Reverse Post Order) will give us something where
3010e4b17023SJohn Marino      deeper loops come later.  */
3011e4b17023SJohn Marino   pre_and_rev_post_order_compute (NULL, bbs, false);
3012e4b17023SJohn Marino   bb_rank = XCNEWVEC (long, last_basic_block + 1);
3013e4b17023SJohn Marino   operand_rank = pointer_map_create ();
3014e4b17023SJohn Marino 
3015e4b17023SJohn Marino   /* Give each argument a distinct rank.   */
3016e4b17023SJohn Marino   for (param = DECL_ARGUMENTS (current_function_decl);
3017e4b17023SJohn Marino        param;
3018e4b17023SJohn Marino        param = DECL_CHAIN (param))
3019e4b17023SJohn Marino     {
3020e4b17023SJohn Marino       if (gimple_default_def (cfun, param) != NULL)
3021e4b17023SJohn Marino 	{
3022e4b17023SJohn Marino 	  tree def = gimple_default_def (cfun, param);
3023e4b17023SJohn Marino 	  insert_operand_rank (def, ++rank);
3024e4b17023SJohn Marino 	}
3025e4b17023SJohn Marino     }
3026e4b17023SJohn Marino 
3027e4b17023SJohn Marino   /* Give the chain decl a distinct rank. */
3028e4b17023SJohn Marino   if (cfun->static_chain_decl != NULL)
3029e4b17023SJohn Marino     {
3030e4b17023SJohn Marino       tree def = gimple_default_def (cfun, cfun->static_chain_decl);
3031e4b17023SJohn Marino       if (def != NULL)
3032e4b17023SJohn Marino 	insert_operand_rank (def, ++rank);
3033e4b17023SJohn Marino     }
3034e4b17023SJohn Marino 
3035e4b17023SJohn Marino   /* Set up rank for each BB  */
3036e4b17023SJohn Marino   for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
3037e4b17023SJohn Marino     bb_rank[bbs[i]] = ++rank  << 16;
3038e4b17023SJohn Marino 
3039e4b17023SJohn Marino   free (bbs);
3040e4b17023SJohn Marino   calculate_dominance_info (CDI_POST_DOMINATORS);
3041e4b17023SJohn Marino   plus_negates = NULL;
3042e4b17023SJohn Marino }
3043e4b17023SJohn Marino 
3044e4b17023SJohn Marino /* Cleanup after the reassociation pass, and print stats if
3045e4b17023SJohn Marino    requested.  */
3046e4b17023SJohn Marino 
3047e4b17023SJohn Marino static void
fini_reassoc(void)3048e4b17023SJohn Marino fini_reassoc (void)
3049e4b17023SJohn Marino {
3050e4b17023SJohn Marino   statistics_counter_event (cfun, "Linearized",
3051e4b17023SJohn Marino 			    reassociate_stats.linearized);
3052e4b17023SJohn Marino   statistics_counter_event (cfun, "Constants eliminated",
3053e4b17023SJohn Marino 			    reassociate_stats.constants_eliminated);
3054e4b17023SJohn Marino   statistics_counter_event (cfun, "Ops eliminated",
3055e4b17023SJohn Marino 			    reassociate_stats.ops_eliminated);
3056e4b17023SJohn Marino   statistics_counter_event (cfun, "Statements rewritten",
3057e4b17023SJohn Marino 			    reassociate_stats.rewritten);
3058e4b17023SJohn Marino 
3059e4b17023SJohn Marino   pointer_map_destroy (operand_rank);
3060e4b17023SJohn Marino   free_alloc_pool (operand_entry_pool);
3061e4b17023SJohn Marino   free (bb_rank);
3062e4b17023SJohn Marino   VEC_free (tree, heap, plus_negates);
3063e4b17023SJohn Marino   free_dominance_info (CDI_POST_DOMINATORS);
3064e4b17023SJohn Marino   loop_optimizer_finalize ();
3065e4b17023SJohn Marino }
3066e4b17023SJohn Marino 
3067e4b17023SJohn Marino /* Gate and execute functions for Reassociation.  */
3068e4b17023SJohn Marino 
3069e4b17023SJohn Marino static unsigned int
execute_reassoc(void)3070e4b17023SJohn Marino execute_reassoc (void)
3071e4b17023SJohn Marino {
3072e4b17023SJohn Marino   init_reassoc ();
3073e4b17023SJohn Marino 
3074e4b17023SJohn Marino   do_reassoc ();
3075e4b17023SJohn Marino   repropagate_negates ();
3076e4b17023SJohn Marino 
3077e4b17023SJohn Marino   fini_reassoc ();
3078e4b17023SJohn Marino   return 0;
3079e4b17023SJohn Marino }
3080e4b17023SJohn Marino 
3081e4b17023SJohn Marino static bool
gate_tree_ssa_reassoc(void)3082e4b17023SJohn Marino gate_tree_ssa_reassoc (void)
3083e4b17023SJohn Marino {
3084e4b17023SJohn Marino   return flag_tree_reassoc != 0;
3085e4b17023SJohn Marino }
3086e4b17023SJohn Marino 
3087e4b17023SJohn Marino struct gimple_opt_pass pass_reassoc =
3088e4b17023SJohn Marino {
3089e4b17023SJohn Marino  {
3090e4b17023SJohn Marino   GIMPLE_PASS,
3091e4b17023SJohn Marino   "reassoc",				/* name */
3092e4b17023SJohn Marino   gate_tree_ssa_reassoc,		/* gate */
3093e4b17023SJohn Marino   execute_reassoc,			/* execute */
3094e4b17023SJohn Marino   NULL,					/* sub */
3095e4b17023SJohn Marino   NULL,					/* next */
3096e4b17023SJohn Marino   0,					/* static_pass_number */
3097e4b17023SJohn Marino   TV_TREE_REASSOC,			/* tv_id */
3098e4b17023SJohn Marino   PROP_cfg | PROP_ssa,			/* properties_required */
3099e4b17023SJohn Marino   0,					/* properties_provided */
3100e4b17023SJohn Marino   0,					/* properties_destroyed */
3101e4b17023SJohn Marino   0,					/* todo_flags_start */
3102e4b17023SJohn Marino   TODO_verify_ssa
3103e4b17023SJohn Marino     | TODO_verify_flow
3104e4b17023SJohn Marino     | TODO_ggc_collect			/* todo_flags_finish */
3105e4b17023SJohn Marino  }
3106e4b17023SJohn Marino };
3107