1e4b17023SJohn Marino /* Predictive commoning.
2e4b17023SJohn Marino    Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011, 2012
3e4b17023SJohn Marino    Free Software Foundation, Inc.
4e4b17023SJohn Marino 
5e4b17023SJohn Marino This file is part of GCC.
6e4b17023SJohn Marino 
7e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it
8e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
9e4b17023SJohn Marino Free Software Foundation; either version 3, or (at your option) any
10e4b17023SJohn Marino later version.
11e4b17023SJohn Marino 
12e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
13e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15e4b17023SJohn Marino for more details.
16e4b17023SJohn Marino 
17e4b17023SJohn Marino You should have received a copy of the GNU General Public License
18e4b17023SJohn Marino along with GCC; see the file COPYING3.  If not see
19e4b17023SJohn Marino <http://www.gnu.org/licenses/>.  */
20e4b17023SJohn Marino 
21e4b17023SJohn Marino /* This file implements the predictive commoning optimization.  Predictive
22e4b17023SJohn Marino    commoning can be viewed as CSE around a loop, and with some improvements,
23e4b17023SJohn Marino    as generalized strength reduction-- i.e., reusing values computed in
24e4b17023SJohn Marino    earlier iterations of a loop in the later ones.  So far, the pass only
25e4b17023SJohn Marino    handles the most useful case, that is, reusing values of memory references.
26e4b17023SJohn Marino    If you think this is all just a special case of PRE, you are sort of right;
27e4b17023SJohn Marino    however, concentrating on loops is simpler, and makes it possible to
28e4b17023SJohn Marino    incorporate data dependence analysis to detect the opportunities, perform
29e4b17023SJohn Marino    loop unrolling to avoid copies together with renaming immediately,
30e4b17023SJohn Marino    and if needed, we could also take register pressure into account.
31e4b17023SJohn Marino 
32e4b17023SJohn Marino    Let us demonstrate what is done on an example:
33e4b17023SJohn Marino 
34e4b17023SJohn Marino    for (i = 0; i < 100; i++)
35e4b17023SJohn Marino      {
36e4b17023SJohn Marino        a[i+2] = a[i] + a[i+1];
37e4b17023SJohn Marino        b[10] = b[10] + i;
38e4b17023SJohn Marino        c[i] = c[99 - i];
39e4b17023SJohn Marino        d[i] = d[i + 1];
40e4b17023SJohn Marino      }
41e4b17023SJohn Marino 
42e4b17023SJohn Marino    1) We find data references in the loop, and split them to mutually
43e4b17023SJohn Marino       independent groups (i.e., we find components of a data dependence
44e4b17023SJohn Marino       graph).  We ignore read-read dependences whose distance is not constant.
45e4b17023SJohn Marino       (TODO -- we could also ignore antidependences).  In this example, we
46e4b17023SJohn Marino       find the following groups:
47e4b17023SJohn Marino 
48e4b17023SJohn Marino       a[i]{read}, a[i+1]{read}, a[i+2]{write}
49e4b17023SJohn Marino       b[10]{read}, b[10]{write}
50e4b17023SJohn Marino       c[99 - i]{read}, c[i]{write}
51e4b17023SJohn Marino       d[i + 1]{read}, d[i]{write}
52e4b17023SJohn Marino 
53e4b17023SJohn Marino    2) Inside each of the group, we verify several conditions:
54e4b17023SJohn Marino       a) all the references must differ in indices only, and the indices
55e4b17023SJohn Marino 	 must all have the same step
56e4b17023SJohn Marino       b) the references must dominate loop latch (and thus, they must be
57e4b17023SJohn Marino 	 ordered by dominance relation).
58e4b17023SJohn Marino       c) the distance of the indices must be a small multiple of the step
59e4b17023SJohn Marino       We are then able to compute the difference of the references (# of
60e4b17023SJohn Marino       iterations before they point to the same place as the first of them).
61e4b17023SJohn Marino       Also, in case there are writes in the loop, we split the groups into
62e4b17023SJohn Marino       chains whose head is the write whose values are used by the reads in
63e4b17023SJohn Marino       the same chain.  The chains are then processed independently,
64e4b17023SJohn Marino       making the further transformations simpler.  Also, the shorter chains
65e4b17023SJohn Marino       need the same number of registers, but may require lower unrolling
66e4b17023SJohn Marino       factor in order to get rid of the copies on the loop latch.
67e4b17023SJohn Marino 
68e4b17023SJohn Marino       In our example, we get the following chains (the chain for c is invalid).
69e4b17023SJohn Marino 
70e4b17023SJohn Marino       a[i]{read,+0}, a[i+1]{read,-1}, a[i+2]{write,-2}
71e4b17023SJohn Marino       b[10]{read,+0}, b[10]{write,+0}
72e4b17023SJohn Marino       d[i + 1]{read,+0}, d[i]{write,+1}
73e4b17023SJohn Marino 
74e4b17023SJohn Marino    3) For each read, we determine the read or write whose value it reuses,
75e4b17023SJohn Marino       together with the distance of this reuse.  I.e. we take the last
76e4b17023SJohn Marino       reference before it with distance 0, or the last of the references
77e4b17023SJohn Marino       with the smallest positive distance to the read.  Then, we remove
78e4b17023SJohn Marino       the references that are not used in any of these chains, discard the
79e4b17023SJohn Marino       empty groups, and propagate all the links so that they point to the
80e4b17023SJohn Marino       single root reference of the chain (adjusting their distance
81e4b17023SJohn Marino       appropriately).  Some extra care needs to be taken for references with
82e4b17023SJohn Marino       step 0.  In our example (the numbers indicate the distance of the
83e4b17023SJohn Marino       reuse),
84e4b17023SJohn Marino 
85e4b17023SJohn Marino       a[i] --> (*) 2, a[i+1] --> (*) 1, a[i+2] (*)
86e4b17023SJohn Marino       b[10] --> (*) 1, b[10] (*)
87e4b17023SJohn Marino 
88e4b17023SJohn Marino    4) The chains are combined together if possible.  If the corresponding
89e4b17023SJohn Marino       elements of two chains are always combined together with the same
90e4b17023SJohn Marino       operator, we remember just the result of this combination, instead
91e4b17023SJohn Marino       of remembering the values separately.  We may need to perform
92e4b17023SJohn Marino       reassociation to enable combining, for example
93e4b17023SJohn Marino 
94e4b17023SJohn Marino       e[i] + f[i+1] + e[i+1] + f[i]
95e4b17023SJohn Marino 
96e4b17023SJohn Marino       can be reassociated as
97e4b17023SJohn Marino 
98e4b17023SJohn Marino       (e[i] + f[i]) + (e[i+1] + f[i+1])
99e4b17023SJohn Marino 
100e4b17023SJohn Marino       and we can combine the chains for e and f into one chain.
101e4b17023SJohn Marino 
102e4b17023SJohn Marino    5) For each root reference (end of the chain) R, let N be maximum distance
103e4b17023SJohn Marino       of a reference reusing its value.  Variables R0 upto RN are created,
104e4b17023SJohn Marino       together with phi nodes that transfer values from R1 .. RN to
105e4b17023SJohn Marino       R0 .. R(N-1).
106e4b17023SJohn Marino       Initial values are loaded to R0..R(N-1) (in case not all references
107e4b17023SJohn Marino       must necessarily be accessed and they may trap, we may fail here;
108e4b17023SJohn Marino       TODO sometimes, the loads could be guarded by a check for the number
109e4b17023SJohn Marino       of iterations).  Values loaded/stored in roots are also copied to
110e4b17023SJohn Marino       RN.  Other reads are replaced with the appropriate variable Ri.
111e4b17023SJohn Marino       Everything is put to SSA form.
112e4b17023SJohn Marino 
113e4b17023SJohn Marino       As a small improvement, if R0 is dead after the root (i.e., all uses of
114e4b17023SJohn Marino       the value with the maximum distance dominate the root), we can avoid
115e4b17023SJohn Marino       creating RN and use R0 instead of it.
116e4b17023SJohn Marino 
117e4b17023SJohn Marino       In our example, we get (only the parts concerning a and b are shown):
118e4b17023SJohn Marino       for (i = 0; i < 100; i++)
119e4b17023SJohn Marino 	{
120e4b17023SJohn Marino 	  f = phi (a[0], s);
121e4b17023SJohn Marino 	  s = phi (a[1], f);
122e4b17023SJohn Marino 	  x = phi (b[10], x);
123e4b17023SJohn Marino 
124e4b17023SJohn Marino 	  f = f + s;
125e4b17023SJohn Marino 	  a[i+2] = f;
126e4b17023SJohn Marino 	  x = x + i;
127e4b17023SJohn Marino 	  b[10] = x;
128e4b17023SJohn Marino 	}
129e4b17023SJohn Marino 
130e4b17023SJohn Marino    6) Factor F for unrolling is determined as the smallest common multiple of
131e4b17023SJohn Marino       (N + 1) for each root reference (N for references for that we avoided
132e4b17023SJohn Marino       creating RN).  If F and the loop is small enough, loop is unrolled F
133e4b17023SJohn Marino       times.  The stores to RN (R0) in the copies of the loop body are
134e4b17023SJohn Marino       periodically replaced with R0, R1, ... (R1, R2, ...), so that they can
135e4b17023SJohn Marino       be coalesced and the copies can be eliminated.
136e4b17023SJohn Marino 
137e4b17023SJohn Marino       TODO -- copy propagation and other optimizations may change the live
138e4b17023SJohn Marino       ranges of the temporary registers and prevent them from being coalesced;
139e4b17023SJohn Marino       this may increase the register pressure.
140e4b17023SJohn Marino 
141e4b17023SJohn Marino       In our case, F = 2 and the (main loop of the) result is
142e4b17023SJohn Marino 
143e4b17023SJohn Marino       for (i = 0; i < ...; i += 2)
144e4b17023SJohn Marino         {
145e4b17023SJohn Marino           f = phi (a[0], f);
146e4b17023SJohn Marino           s = phi (a[1], s);
147e4b17023SJohn Marino           x = phi (b[10], x);
148e4b17023SJohn Marino 
149e4b17023SJohn Marino           f = f + s;
150e4b17023SJohn Marino           a[i+2] = f;
151e4b17023SJohn Marino           x = x + i;
152e4b17023SJohn Marino           b[10] = x;
153e4b17023SJohn Marino 
154e4b17023SJohn Marino           s = s + f;
155e4b17023SJohn Marino           a[i+3] = s;
156e4b17023SJohn Marino           x = x + i;
157e4b17023SJohn Marino           b[10] = x;
158e4b17023SJohn Marino        }
159e4b17023SJohn Marino 
160e4b17023SJohn Marino    TODO -- stores killing other stores can be taken into account, e.g.,
161e4b17023SJohn Marino    for (i = 0; i < n; i++)
162e4b17023SJohn Marino      {
163e4b17023SJohn Marino        a[i] = 1;
164e4b17023SJohn Marino        a[i+2] = 2;
165e4b17023SJohn Marino      }
166e4b17023SJohn Marino 
167e4b17023SJohn Marino    can be replaced with
168e4b17023SJohn Marino 
169e4b17023SJohn Marino    t0 = a[0];
170e4b17023SJohn Marino    t1 = a[1];
171e4b17023SJohn Marino    for (i = 0; i < n; i++)
172e4b17023SJohn Marino      {
173e4b17023SJohn Marino        a[i] = 1;
174e4b17023SJohn Marino        t2 = 2;
175e4b17023SJohn Marino        t0 = t1;
176e4b17023SJohn Marino        t1 = t2;
177e4b17023SJohn Marino      }
178e4b17023SJohn Marino    a[n] = t0;
179e4b17023SJohn Marino    a[n+1] = t1;
180e4b17023SJohn Marino 
181e4b17023SJohn Marino    The interesting part is that this would generalize store motion; still, since
182e4b17023SJohn Marino    sm is performed elsewhere, it does not seem that important.
183e4b17023SJohn Marino 
184e4b17023SJohn Marino    Predictive commoning can be generalized for arbitrary computations (not
185e4b17023SJohn Marino    just memory loads), and also nontrivial transfer functions (e.g., replacing
186e4b17023SJohn Marino    i * i with ii_last + 2 * i + 1), to generalize strength reduction.  */
187e4b17023SJohn Marino 
188e4b17023SJohn Marino #include "config.h"
189e4b17023SJohn Marino #include "system.h"
190e4b17023SJohn Marino #include "coretypes.h"
191e4b17023SJohn Marino #include "tm.h"
192e4b17023SJohn Marino #include "tree.h"
193e4b17023SJohn Marino #include "tm_p.h"
194e4b17023SJohn Marino #include "cfgloop.h"
195e4b17023SJohn Marino #include "tree-flow.h"
196e4b17023SJohn Marino #include "ggc.h"
197e4b17023SJohn Marino #include "tree-data-ref.h"
198e4b17023SJohn Marino #include "tree-scalar-evolution.h"
199e4b17023SJohn Marino #include "tree-chrec.h"
200e4b17023SJohn Marino #include "params.h"
201e4b17023SJohn Marino #include "tree-pretty-print.h"
202e4b17023SJohn Marino #include "gimple-pretty-print.h"
203e4b17023SJohn Marino #include "tree-pass.h"
204e4b17023SJohn Marino #include "tree-affine.h"
205e4b17023SJohn Marino #include "tree-inline.h"
206e4b17023SJohn Marino 
207e4b17023SJohn Marino /* The maximum number of iterations between the considered memory
208e4b17023SJohn Marino    references.  */
209e4b17023SJohn Marino 
210e4b17023SJohn Marino #define MAX_DISTANCE (target_avail_regs < 16 ? 4 : 8)
211e4b17023SJohn Marino 
212e4b17023SJohn Marino /* Data references (or phi nodes that carry data reference values across
213e4b17023SJohn Marino    loop iterations).  */
214e4b17023SJohn Marino 
215e4b17023SJohn Marino typedef struct dref_d
216e4b17023SJohn Marino {
217e4b17023SJohn Marino   /* The reference itself.  */
218e4b17023SJohn Marino   struct data_reference *ref;
219e4b17023SJohn Marino 
220e4b17023SJohn Marino   /* The statement in that the reference appears.  */
221e4b17023SJohn Marino   gimple stmt;
222e4b17023SJohn Marino 
223e4b17023SJohn Marino   /* In case that STMT is a phi node, this field is set to the SSA name
224e4b17023SJohn Marino      defined by it in replace_phis_by_defined_names (in order to avoid
225e4b17023SJohn Marino      pointing to phi node that got reallocated in the meantime).  */
226e4b17023SJohn Marino   tree name_defined_by_phi;
227e4b17023SJohn Marino 
228e4b17023SJohn Marino   /* Distance of the reference from the root of the chain (in number of
229e4b17023SJohn Marino      iterations of the loop).  */
230e4b17023SJohn Marino   unsigned distance;
231e4b17023SJohn Marino 
232e4b17023SJohn Marino   /* Number of iterations offset from the first reference in the component.  */
233e4b17023SJohn Marino   double_int offset;
234e4b17023SJohn Marino 
235e4b17023SJohn Marino   /* Number of the reference in a component, in dominance ordering.  */
236e4b17023SJohn Marino   unsigned pos;
237e4b17023SJohn Marino 
238e4b17023SJohn Marino   /* True if the memory reference is always accessed when the loop is
239e4b17023SJohn Marino      entered.  */
240e4b17023SJohn Marino   unsigned always_accessed : 1;
241e4b17023SJohn Marino } *dref;
242e4b17023SJohn Marino 
243e4b17023SJohn Marino DEF_VEC_P (dref);
244e4b17023SJohn Marino DEF_VEC_ALLOC_P (dref, heap);
245e4b17023SJohn Marino 
246e4b17023SJohn Marino /* Type of the chain of the references.  */
247e4b17023SJohn Marino 
248e4b17023SJohn Marino enum chain_type
249e4b17023SJohn Marino {
250e4b17023SJohn Marino   /* The addresses of the references in the chain are constant.  */
251e4b17023SJohn Marino   CT_INVARIANT,
252e4b17023SJohn Marino 
253e4b17023SJohn Marino   /* There are only loads in the chain.  */
254e4b17023SJohn Marino   CT_LOAD,
255e4b17023SJohn Marino 
256e4b17023SJohn Marino   /* Root of the chain is store, the rest are loads.  */
257e4b17023SJohn Marino   CT_STORE_LOAD,
258e4b17023SJohn Marino 
259e4b17023SJohn Marino   /* A combination of two chains.  */
260e4b17023SJohn Marino   CT_COMBINATION
261e4b17023SJohn Marino };
262e4b17023SJohn Marino 
263e4b17023SJohn Marino /* Chains of data references.  */
264e4b17023SJohn Marino 
265e4b17023SJohn Marino typedef struct chain
266e4b17023SJohn Marino {
267e4b17023SJohn Marino   /* Type of the chain.  */
268e4b17023SJohn Marino   enum chain_type type;
269e4b17023SJohn Marino 
270e4b17023SJohn Marino   /* For combination chains, the operator and the two chains that are
271e4b17023SJohn Marino      combined, and the type of the result.  */
272e4b17023SJohn Marino   enum tree_code op;
273e4b17023SJohn Marino   tree rslt_type;
274e4b17023SJohn Marino   struct chain *ch1, *ch2;
275e4b17023SJohn Marino 
276e4b17023SJohn Marino   /* The references in the chain.  */
277e4b17023SJohn Marino   VEC(dref,heap) *refs;
278e4b17023SJohn Marino 
279e4b17023SJohn Marino   /* The maximum distance of the reference in the chain from the root.  */
280e4b17023SJohn Marino   unsigned length;
281e4b17023SJohn Marino 
282e4b17023SJohn Marino   /* The variables used to copy the value throughout iterations.  */
283e4b17023SJohn Marino   VEC(tree,heap) *vars;
284e4b17023SJohn Marino 
285e4b17023SJohn Marino   /* Initializers for the variables.  */
286e4b17023SJohn Marino   VEC(tree,heap) *inits;
287e4b17023SJohn Marino 
288e4b17023SJohn Marino   /* True if there is a use of a variable with the maximal distance
289e4b17023SJohn Marino      that comes after the root in the loop.  */
290e4b17023SJohn Marino   unsigned has_max_use_after : 1;
291e4b17023SJohn Marino 
292e4b17023SJohn Marino   /* True if all the memory references in the chain are always accessed.  */
293e4b17023SJohn Marino   unsigned all_always_accessed : 1;
294e4b17023SJohn Marino 
295e4b17023SJohn Marino   /* True if this chain was combined together with some other chain.  */
296e4b17023SJohn Marino   unsigned combined : 1;
297e4b17023SJohn Marino } *chain_p;
298e4b17023SJohn Marino 
299e4b17023SJohn Marino DEF_VEC_P (chain_p);
300e4b17023SJohn Marino DEF_VEC_ALLOC_P (chain_p, heap);
301e4b17023SJohn Marino 
302e4b17023SJohn Marino /* Describes the knowledge about the step of the memory references in
303e4b17023SJohn Marino    the component.  */
304e4b17023SJohn Marino 
305e4b17023SJohn Marino enum ref_step_type
306e4b17023SJohn Marino {
307e4b17023SJohn Marino   /* The step is zero.  */
308e4b17023SJohn Marino   RS_INVARIANT,
309e4b17023SJohn Marino 
310e4b17023SJohn Marino   /* The step is nonzero.  */
311e4b17023SJohn Marino   RS_NONZERO,
312e4b17023SJohn Marino 
313e4b17023SJohn Marino   /* The step may or may not be nonzero.  */
314e4b17023SJohn Marino   RS_ANY
315e4b17023SJohn Marino };
316e4b17023SJohn Marino 
317e4b17023SJohn Marino /* Components of the data dependence graph.  */
318e4b17023SJohn Marino 
319e4b17023SJohn Marino struct component
320e4b17023SJohn Marino {
321e4b17023SJohn Marino   /* The references in the component.  */
322e4b17023SJohn Marino   VEC(dref,heap) *refs;
323e4b17023SJohn Marino 
324e4b17023SJohn Marino   /* What we know about the step of the references in the component.  */
325e4b17023SJohn Marino   enum ref_step_type comp_step;
326e4b17023SJohn Marino 
327e4b17023SJohn Marino   /* Next component in the list.  */
328e4b17023SJohn Marino   struct component *next;
329e4b17023SJohn Marino };
330e4b17023SJohn Marino 
331e4b17023SJohn Marino /* Bitmap of ssa names defined by looparound phi nodes covered by chains.  */
332e4b17023SJohn Marino 
333e4b17023SJohn Marino static bitmap looparound_phis;
334e4b17023SJohn Marino 
335e4b17023SJohn Marino /* Cache used by tree_to_aff_combination_expand.  */
336e4b17023SJohn Marino 
337e4b17023SJohn Marino static struct pointer_map_t *name_expansions;
338e4b17023SJohn Marino 
339e4b17023SJohn Marino /* Dumps data reference REF to FILE.  */
340e4b17023SJohn Marino 
341e4b17023SJohn Marino extern void dump_dref (FILE *, dref);
342e4b17023SJohn Marino void
dump_dref(FILE * file,dref ref)343e4b17023SJohn Marino dump_dref (FILE *file, dref ref)
344e4b17023SJohn Marino {
345e4b17023SJohn Marino   if (ref->ref)
346e4b17023SJohn Marino     {
347e4b17023SJohn Marino       fprintf (file, "    ");
348e4b17023SJohn Marino       print_generic_expr (file, DR_REF (ref->ref), TDF_SLIM);
349e4b17023SJohn Marino       fprintf (file, " (id %u%s)\n", ref->pos,
350e4b17023SJohn Marino 	       DR_IS_READ (ref->ref) ? "" : ", write");
351e4b17023SJohn Marino 
352e4b17023SJohn Marino       fprintf (file, "      offset ");
353e4b17023SJohn Marino       dump_double_int (file, ref->offset, false);
354e4b17023SJohn Marino       fprintf (file, "\n");
355e4b17023SJohn Marino 
356e4b17023SJohn Marino       fprintf (file, "      distance %u\n", ref->distance);
357e4b17023SJohn Marino     }
358e4b17023SJohn Marino   else
359e4b17023SJohn Marino     {
360e4b17023SJohn Marino       if (gimple_code (ref->stmt) == GIMPLE_PHI)
361e4b17023SJohn Marino 	fprintf (file, "    looparound ref\n");
362e4b17023SJohn Marino       else
363e4b17023SJohn Marino 	fprintf (file, "    combination ref\n");
364e4b17023SJohn Marino       fprintf (file, "      in statement ");
365e4b17023SJohn Marino       print_gimple_stmt (file, ref->stmt, 0, TDF_SLIM);
366e4b17023SJohn Marino       fprintf (file, "\n");
367e4b17023SJohn Marino       fprintf (file, "      distance %u\n", ref->distance);
368e4b17023SJohn Marino     }
369e4b17023SJohn Marino 
370e4b17023SJohn Marino }
371e4b17023SJohn Marino 
372e4b17023SJohn Marino /* Dumps CHAIN to FILE.  */
373e4b17023SJohn Marino 
374e4b17023SJohn Marino extern void dump_chain (FILE *, chain_p);
375e4b17023SJohn Marino void
dump_chain(FILE * file,chain_p chain)376e4b17023SJohn Marino dump_chain (FILE *file, chain_p chain)
377e4b17023SJohn Marino {
378e4b17023SJohn Marino   dref a;
379e4b17023SJohn Marino   const char *chain_type;
380e4b17023SJohn Marino   unsigned i;
381e4b17023SJohn Marino   tree var;
382e4b17023SJohn Marino 
383e4b17023SJohn Marino   switch (chain->type)
384e4b17023SJohn Marino     {
385e4b17023SJohn Marino     case CT_INVARIANT:
386e4b17023SJohn Marino       chain_type = "Load motion";
387e4b17023SJohn Marino       break;
388e4b17023SJohn Marino 
389e4b17023SJohn Marino     case CT_LOAD:
390e4b17023SJohn Marino       chain_type = "Loads-only";
391e4b17023SJohn Marino       break;
392e4b17023SJohn Marino 
393e4b17023SJohn Marino     case CT_STORE_LOAD:
394e4b17023SJohn Marino       chain_type = "Store-loads";
395e4b17023SJohn Marino       break;
396e4b17023SJohn Marino 
397e4b17023SJohn Marino     case CT_COMBINATION:
398e4b17023SJohn Marino       chain_type = "Combination";
399e4b17023SJohn Marino       break;
400e4b17023SJohn Marino 
401e4b17023SJohn Marino     default:
402e4b17023SJohn Marino       gcc_unreachable ();
403e4b17023SJohn Marino     }
404e4b17023SJohn Marino 
405e4b17023SJohn Marino   fprintf (file, "%s chain %p%s\n", chain_type, (void *) chain,
406e4b17023SJohn Marino 	   chain->combined ? " (combined)" : "");
407e4b17023SJohn Marino   if (chain->type != CT_INVARIANT)
408e4b17023SJohn Marino     fprintf (file, "  max distance %u%s\n", chain->length,
409e4b17023SJohn Marino 	     chain->has_max_use_after ? "" : ", may reuse first");
410e4b17023SJohn Marino 
411e4b17023SJohn Marino   if (chain->type == CT_COMBINATION)
412e4b17023SJohn Marino     {
413e4b17023SJohn Marino       fprintf (file, "  equal to %p %s %p in type ",
414e4b17023SJohn Marino 	       (void *) chain->ch1, op_symbol_code (chain->op),
415e4b17023SJohn Marino 	       (void *) chain->ch2);
416e4b17023SJohn Marino       print_generic_expr (file, chain->rslt_type, TDF_SLIM);
417e4b17023SJohn Marino       fprintf (file, "\n");
418e4b17023SJohn Marino     }
419e4b17023SJohn Marino 
420e4b17023SJohn Marino   if (chain->vars)
421e4b17023SJohn Marino     {
422e4b17023SJohn Marino       fprintf (file, "  vars");
423e4b17023SJohn Marino       FOR_EACH_VEC_ELT (tree, chain->vars, i, var)
424e4b17023SJohn Marino 	{
425e4b17023SJohn Marino 	  fprintf (file, " ");
426e4b17023SJohn Marino 	  print_generic_expr (file, var, TDF_SLIM);
427e4b17023SJohn Marino 	}
428e4b17023SJohn Marino       fprintf (file, "\n");
429e4b17023SJohn Marino     }
430e4b17023SJohn Marino 
431e4b17023SJohn Marino   if (chain->inits)
432e4b17023SJohn Marino     {
433e4b17023SJohn Marino       fprintf (file, "  inits");
434e4b17023SJohn Marino       FOR_EACH_VEC_ELT (tree, chain->inits, i, var)
435e4b17023SJohn Marino 	{
436e4b17023SJohn Marino 	  fprintf (file, " ");
437e4b17023SJohn Marino 	  print_generic_expr (file, var, TDF_SLIM);
438e4b17023SJohn Marino 	}
439e4b17023SJohn Marino       fprintf (file, "\n");
440e4b17023SJohn Marino     }
441e4b17023SJohn Marino 
442e4b17023SJohn Marino   fprintf (file, "  references:\n");
443e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, a)
444e4b17023SJohn Marino     dump_dref (file, a);
445e4b17023SJohn Marino 
446e4b17023SJohn Marino   fprintf (file, "\n");
447e4b17023SJohn Marino }
448e4b17023SJohn Marino 
449e4b17023SJohn Marino /* Dumps CHAINS to FILE.  */
450e4b17023SJohn Marino 
451e4b17023SJohn Marino extern void dump_chains (FILE *, VEC (chain_p, heap) *);
452e4b17023SJohn Marino void
dump_chains(FILE * file,VEC (chain_p,heap)* chains)453e4b17023SJohn Marino dump_chains (FILE *file, VEC (chain_p, heap) *chains)
454e4b17023SJohn Marino {
455e4b17023SJohn Marino   chain_p chain;
456e4b17023SJohn Marino   unsigned i;
457e4b17023SJohn Marino 
458e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, chains, i, chain)
459e4b17023SJohn Marino     dump_chain (file, chain);
460e4b17023SJohn Marino }
461e4b17023SJohn Marino 
462e4b17023SJohn Marino /* Dumps COMP to FILE.  */
463e4b17023SJohn Marino 
464e4b17023SJohn Marino extern void dump_component (FILE *, struct component *);
465e4b17023SJohn Marino void
dump_component(FILE * file,struct component * comp)466e4b17023SJohn Marino dump_component (FILE *file, struct component *comp)
467e4b17023SJohn Marino {
468e4b17023SJohn Marino   dref a;
469e4b17023SJohn Marino   unsigned i;
470e4b17023SJohn Marino 
471e4b17023SJohn Marino   fprintf (file, "Component%s:\n",
472e4b17023SJohn Marino 	   comp->comp_step == RS_INVARIANT ? " (invariant)" : "");
473e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, comp->refs, i, a)
474e4b17023SJohn Marino     dump_dref (file, a);
475e4b17023SJohn Marino   fprintf (file, "\n");
476e4b17023SJohn Marino }
477e4b17023SJohn Marino 
478e4b17023SJohn Marino /* Dumps COMPS to FILE.  */
479e4b17023SJohn Marino 
480e4b17023SJohn Marino extern void dump_components (FILE *, struct component *);
481e4b17023SJohn Marino void
dump_components(FILE * file,struct component * comps)482e4b17023SJohn Marino dump_components (FILE *file, struct component *comps)
483e4b17023SJohn Marino {
484e4b17023SJohn Marino   struct component *comp;
485e4b17023SJohn Marino 
486e4b17023SJohn Marino   for (comp = comps; comp; comp = comp->next)
487e4b17023SJohn Marino     dump_component (file, comp);
488e4b17023SJohn Marino }
489e4b17023SJohn Marino 
490e4b17023SJohn Marino /* Frees a chain CHAIN.  */
491e4b17023SJohn Marino 
492e4b17023SJohn Marino static void
release_chain(chain_p chain)493e4b17023SJohn Marino release_chain (chain_p chain)
494e4b17023SJohn Marino {
495e4b17023SJohn Marino   dref ref;
496e4b17023SJohn Marino   unsigned i;
497e4b17023SJohn Marino 
498e4b17023SJohn Marino   if (chain == NULL)
499e4b17023SJohn Marino     return;
500e4b17023SJohn Marino 
501e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, ref)
502e4b17023SJohn Marino     free (ref);
503e4b17023SJohn Marino 
504e4b17023SJohn Marino   VEC_free (dref, heap, chain->refs);
505e4b17023SJohn Marino   VEC_free (tree, heap, chain->vars);
506e4b17023SJohn Marino   VEC_free (tree, heap, chain->inits);
507e4b17023SJohn Marino 
508e4b17023SJohn Marino   free (chain);
509e4b17023SJohn Marino }
510e4b17023SJohn Marino 
511e4b17023SJohn Marino /* Frees CHAINS.  */
512e4b17023SJohn Marino 
513e4b17023SJohn Marino static void
release_chains(VEC (chain_p,heap)* chains)514e4b17023SJohn Marino release_chains (VEC (chain_p, heap) *chains)
515e4b17023SJohn Marino {
516e4b17023SJohn Marino   unsigned i;
517e4b17023SJohn Marino   chain_p chain;
518e4b17023SJohn Marino 
519e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, chains, i, chain)
520e4b17023SJohn Marino     release_chain (chain);
521e4b17023SJohn Marino   VEC_free (chain_p, heap, chains);
522e4b17023SJohn Marino }
523e4b17023SJohn Marino 
524e4b17023SJohn Marino /* Frees a component COMP.  */
525e4b17023SJohn Marino 
526e4b17023SJohn Marino static void
release_component(struct component * comp)527e4b17023SJohn Marino release_component (struct component *comp)
528e4b17023SJohn Marino {
529e4b17023SJohn Marino   VEC_free (dref, heap, comp->refs);
530e4b17023SJohn Marino   free (comp);
531e4b17023SJohn Marino }
532e4b17023SJohn Marino 
533e4b17023SJohn Marino /* Frees list of components COMPS.  */
534e4b17023SJohn Marino 
535e4b17023SJohn Marino static void
release_components(struct component * comps)536e4b17023SJohn Marino release_components (struct component *comps)
537e4b17023SJohn Marino {
538e4b17023SJohn Marino   struct component *act, *next;
539e4b17023SJohn Marino 
540e4b17023SJohn Marino   for (act = comps; act; act = next)
541e4b17023SJohn Marino     {
542e4b17023SJohn Marino       next = act->next;
543e4b17023SJohn Marino       release_component (act);
544e4b17023SJohn Marino     }
545e4b17023SJohn Marino }
546e4b17023SJohn Marino 
547e4b17023SJohn Marino /* Finds a root of tree given by FATHERS containing A, and performs path
548e4b17023SJohn Marino    shortening.  */
549e4b17023SJohn Marino 
550e4b17023SJohn Marino static unsigned
component_of(unsigned fathers[],unsigned a)551e4b17023SJohn Marino component_of (unsigned fathers[], unsigned a)
552e4b17023SJohn Marino {
553e4b17023SJohn Marino   unsigned root, n;
554e4b17023SJohn Marino 
555e4b17023SJohn Marino   for (root = a; root != fathers[root]; root = fathers[root])
556e4b17023SJohn Marino     continue;
557e4b17023SJohn Marino 
558e4b17023SJohn Marino   for (; a != root; a = n)
559e4b17023SJohn Marino     {
560e4b17023SJohn Marino       n = fathers[a];
561e4b17023SJohn Marino       fathers[a] = root;
562e4b17023SJohn Marino     }
563e4b17023SJohn Marino 
564e4b17023SJohn Marino   return root;
565e4b17023SJohn Marino }
566e4b17023SJohn Marino 
567e4b17023SJohn Marino /* Join operation for DFU.  FATHERS gives the tree, SIZES are sizes of the
568e4b17023SJohn Marino    components, A and B are components to merge.  */
569e4b17023SJohn Marino 
570e4b17023SJohn Marino static void
merge_comps(unsigned fathers[],unsigned sizes[],unsigned a,unsigned b)571e4b17023SJohn Marino merge_comps (unsigned fathers[], unsigned sizes[], unsigned a, unsigned b)
572e4b17023SJohn Marino {
573e4b17023SJohn Marino   unsigned ca = component_of (fathers, a);
574e4b17023SJohn Marino   unsigned cb = component_of (fathers, b);
575e4b17023SJohn Marino 
576e4b17023SJohn Marino   if (ca == cb)
577e4b17023SJohn Marino     return;
578e4b17023SJohn Marino 
579e4b17023SJohn Marino   if (sizes[ca] < sizes[cb])
580e4b17023SJohn Marino     {
581e4b17023SJohn Marino       sizes[cb] += sizes[ca];
582e4b17023SJohn Marino       fathers[ca] = cb;
583e4b17023SJohn Marino     }
584e4b17023SJohn Marino   else
585e4b17023SJohn Marino     {
586e4b17023SJohn Marino       sizes[ca] += sizes[cb];
587e4b17023SJohn Marino       fathers[cb] = ca;
588e4b17023SJohn Marino     }
589e4b17023SJohn Marino }
590e4b17023SJohn Marino 
591e4b17023SJohn Marino /* Returns true if A is a reference that is suitable for predictive commoning
592e4b17023SJohn Marino    in the innermost loop that contains it.  REF_STEP is set according to the
593e4b17023SJohn Marino    step of the reference A.  */
594e4b17023SJohn Marino 
595e4b17023SJohn Marino static bool
suitable_reference_p(struct data_reference * a,enum ref_step_type * ref_step)596e4b17023SJohn Marino suitable_reference_p (struct data_reference *a, enum ref_step_type *ref_step)
597e4b17023SJohn Marino {
598e4b17023SJohn Marino   tree ref = DR_REF (a), step = DR_STEP (a);
599e4b17023SJohn Marino 
600e4b17023SJohn Marino   if (!step
601e4b17023SJohn Marino       || TREE_THIS_VOLATILE (ref)
602e4b17023SJohn Marino       || !is_gimple_reg_type (TREE_TYPE (ref))
603e4b17023SJohn Marino       || tree_could_throw_p (ref))
604e4b17023SJohn Marino     return false;
605e4b17023SJohn Marino 
606e4b17023SJohn Marino   if (integer_zerop (step))
607e4b17023SJohn Marino     *ref_step = RS_INVARIANT;
608e4b17023SJohn Marino   else if (integer_nonzerop (step))
609e4b17023SJohn Marino     *ref_step = RS_NONZERO;
610e4b17023SJohn Marino   else
611e4b17023SJohn Marino     *ref_step = RS_ANY;
612e4b17023SJohn Marino 
613e4b17023SJohn Marino   return true;
614e4b17023SJohn Marino }
615e4b17023SJohn Marino 
616e4b17023SJohn Marino /* Stores DR_OFFSET (DR) + DR_INIT (DR) to OFFSET.  */
617e4b17023SJohn Marino 
618e4b17023SJohn Marino static void
aff_combination_dr_offset(struct data_reference * dr,aff_tree * offset)619e4b17023SJohn Marino aff_combination_dr_offset (struct data_reference *dr, aff_tree *offset)
620e4b17023SJohn Marino {
621e4b17023SJohn Marino   tree type = TREE_TYPE (DR_OFFSET (dr));
622e4b17023SJohn Marino   aff_tree delta;
623e4b17023SJohn Marino 
624e4b17023SJohn Marino   tree_to_aff_combination_expand (DR_OFFSET (dr), type, offset,
625e4b17023SJohn Marino 				  &name_expansions);
626e4b17023SJohn Marino   aff_combination_const (&delta, type, tree_to_double_int (DR_INIT (dr)));
627e4b17023SJohn Marino   aff_combination_add (offset, &delta);
628e4b17023SJohn Marino }
629e4b17023SJohn Marino 
630e4b17023SJohn Marino /* Determines number of iterations of the innermost enclosing loop before B
631e4b17023SJohn Marino    refers to exactly the same location as A and stores it to OFF.  If A and
632e4b17023SJohn Marino    B do not have the same step, they never meet, or anything else fails,
633e4b17023SJohn Marino    returns false, otherwise returns true.  Both A and B are assumed to
634e4b17023SJohn Marino    satisfy suitable_reference_p.  */
635e4b17023SJohn Marino 
636e4b17023SJohn Marino static bool
determine_offset(struct data_reference * a,struct data_reference * b,double_int * off)637e4b17023SJohn Marino determine_offset (struct data_reference *a, struct data_reference *b,
638e4b17023SJohn Marino 		  double_int *off)
639e4b17023SJohn Marino {
640e4b17023SJohn Marino   aff_tree diff, baseb, step;
641e4b17023SJohn Marino   tree typea, typeb;
642e4b17023SJohn Marino 
643e4b17023SJohn Marino   /* Check that both the references access the location in the same type.  */
644e4b17023SJohn Marino   typea = TREE_TYPE (DR_REF (a));
645e4b17023SJohn Marino   typeb = TREE_TYPE (DR_REF (b));
646e4b17023SJohn Marino   if (!useless_type_conversion_p (typeb, typea))
647e4b17023SJohn Marino     return false;
648e4b17023SJohn Marino 
649e4b17023SJohn Marino   /* Check whether the base address and the step of both references is the
650e4b17023SJohn Marino      same.  */
651e4b17023SJohn Marino   if (!operand_equal_p (DR_STEP (a), DR_STEP (b), 0)
652e4b17023SJohn Marino       || !operand_equal_p (DR_BASE_ADDRESS (a), DR_BASE_ADDRESS (b), 0))
653e4b17023SJohn Marino     return false;
654e4b17023SJohn Marino 
655e4b17023SJohn Marino   if (integer_zerop (DR_STEP (a)))
656e4b17023SJohn Marino     {
657e4b17023SJohn Marino       /* If the references have loop invariant address, check that they access
658e4b17023SJohn Marino 	 exactly the same location.  */
659e4b17023SJohn Marino       *off = double_int_zero;
660e4b17023SJohn Marino       return (operand_equal_p (DR_OFFSET (a), DR_OFFSET (b), 0)
661e4b17023SJohn Marino 	      && operand_equal_p (DR_INIT (a), DR_INIT (b), 0));
662e4b17023SJohn Marino     }
663e4b17023SJohn Marino 
664e4b17023SJohn Marino   /* Compare the offsets of the addresses, and check whether the difference
665e4b17023SJohn Marino      is a multiple of step.  */
666e4b17023SJohn Marino   aff_combination_dr_offset (a, &diff);
667e4b17023SJohn Marino   aff_combination_dr_offset (b, &baseb);
668e4b17023SJohn Marino   aff_combination_scale (&baseb, double_int_minus_one);
669e4b17023SJohn Marino   aff_combination_add (&diff, &baseb);
670e4b17023SJohn Marino 
671e4b17023SJohn Marino   tree_to_aff_combination_expand (DR_STEP (a), TREE_TYPE (DR_STEP (a)),
672e4b17023SJohn Marino 				  &step, &name_expansions);
673e4b17023SJohn Marino   return aff_combination_constant_multiple_p (&diff, &step, off);
674e4b17023SJohn Marino }
675e4b17023SJohn Marino 
676e4b17023SJohn Marino /* Returns the last basic block in LOOP for that we are sure that
677e4b17023SJohn Marino    it is executed whenever the loop is entered.  */
678e4b17023SJohn Marino 
679e4b17023SJohn Marino static basic_block
last_always_executed_block(struct loop * loop)680e4b17023SJohn Marino last_always_executed_block (struct loop *loop)
681e4b17023SJohn Marino {
682e4b17023SJohn Marino   unsigned i;
683e4b17023SJohn Marino   VEC (edge, heap) *exits = get_loop_exit_edges (loop);
684e4b17023SJohn Marino   edge ex;
685e4b17023SJohn Marino   basic_block last = loop->latch;
686e4b17023SJohn Marino 
687e4b17023SJohn Marino   FOR_EACH_VEC_ELT (edge, exits, i, ex)
688e4b17023SJohn Marino     last = nearest_common_dominator (CDI_DOMINATORS, last, ex->src);
689e4b17023SJohn Marino   VEC_free (edge, heap, exits);
690e4b17023SJohn Marino 
691e4b17023SJohn Marino   return last;
692e4b17023SJohn Marino }
693e4b17023SJohn Marino 
694e4b17023SJohn Marino /* Splits dependence graph on DATAREFS described by DEPENDS to components.  */
695e4b17023SJohn Marino 
696e4b17023SJohn Marino static struct component *
split_data_refs_to_components(struct loop * loop,VEC (data_reference_p,heap)* datarefs,VEC (ddr_p,heap)* depends)697e4b17023SJohn Marino split_data_refs_to_components (struct loop *loop,
698e4b17023SJohn Marino 			       VEC (data_reference_p, heap) *datarefs,
699e4b17023SJohn Marino 			       VEC (ddr_p, heap) *depends)
700e4b17023SJohn Marino {
701e4b17023SJohn Marino   unsigned i, n = VEC_length (data_reference_p, datarefs);
702e4b17023SJohn Marino   unsigned ca, ia, ib, bad;
703e4b17023SJohn Marino   unsigned *comp_father = XNEWVEC (unsigned, n + 1);
704e4b17023SJohn Marino   unsigned *comp_size = XNEWVEC (unsigned, n + 1);
705e4b17023SJohn Marino   struct component **comps;
706e4b17023SJohn Marino   struct data_reference *dr, *dra, *drb;
707e4b17023SJohn Marino   struct data_dependence_relation *ddr;
708e4b17023SJohn Marino   struct component *comp_list = NULL, *comp;
709e4b17023SJohn Marino   dref dataref;
710e4b17023SJohn Marino   basic_block last_always_executed = last_always_executed_block (loop);
711e4b17023SJohn Marino 
712e4b17023SJohn Marino   FOR_EACH_VEC_ELT (data_reference_p, datarefs, i, dr)
713e4b17023SJohn Marino     {
714e4b17023SJohn Marino       if (!DR_REF (dr))
715e4b17023SJohn Marino 	{
716e4b17023SJohn Marino 	  /* A fake reference for call or asm_expr that may clobber memory;
717e4b17023SJohn Marino 	     just fail.  */
718e4b17023SJohn Marino 	  goto end;
719e4b17023SJohn Marino 	}
720e4b17023SJohn Marino       dr->aux = (void *) (size_t) i;
721e4b17023SJohn Marino       comp_father[i] = i;
722e4b17023SJohn Marino       comp_size[i] = 1;
723e4b17023SJohn Marino     }
724e4b17023SJohn Marino 
725e4b17023SJohn Marino   /* A component reserved for the "bad" data references.  */
726e4b17023SJohn Marino   comp_father[n] = n;
727e4b17023SJohn Marino   comp_size[n] = 1;
728e4b17023SJohn Marino 
729e4b17023SJohn Marino   FOR_EACH_VEC_ELT (data_reference_p, datarefs, i, dr)
730e4b17023SJohn Marino     {
731e4b17023SJohn Marino       enum ref_step_type dummy;
732e4b17023SJohn Marino 
733e4b17023SJohn Marino       if (!suitable_reference_p (dr, &dummy))
734e4b17023SJohn Marino 	{
735e4b17023SJohn Marino 	  ia = (unsigned) (size_t) dr->aux;
736e4b17023SJohn Marino 	  merge_comps (comp_father, comp_size, n, ia);
737e4b17023SJohn Marino 	}
738e4b17023SJohn Marino     }
739e4b17023SJohn Marino 
740e4b17023SJohn Marino   FOR_EACH_VEC_ELT (ddr_p, depends, i, ddr)
741e4b17023SJohn Marino     {
742e4b17023SJohn Marino       double_int dummy_off;
743e4b17023SJohn Marino 
744e4b17023SJohn Marino       if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
745e4b17023SJohn Marino 	continue;
746e4b17023SJohn Marino 
747e4b17023SJohn Marino       dra = DDR_A (ddr);
748e4b17023SJohn Marino       drb = DDR_B (ddr);
749e4b17023SJohn Marino       ia = component_of (comp_father, (unsigned) (size_t) dra->aux);
750e4b17023SJohn Marino       ib = component_of (comp_father, (unsigned) (size_t) drb->aux);
751e4b17023SJohn Marino       if (ia == ib)
752e4b17023SJohn Marino 	continue;
753e4b17023SJohn Marino 
754e4b17023SJohn Marino       bad = component_of (comp_father, n);
755e4b17023SJohn Marino 
756e4b17023SJohn Marino       /* If both A and B are reads, we may ignore unsuitable dependences.  */
757e4b17023SJohn Marino       if (DR_IS_READ (dra) && DR_IS_READ (drb)
758e4b17023SJohn Marino 	  && (ia == bad || ib == bad
759e4b17023SJohn Marino 	      || !determine_offset (dra, drb, &dummy_off)))
760e4b17023SJohn Marino 	continue;
761e4b17023SJohn Marino 
762e4b17023SJohn Marino       merge_comps (comp_father, comp_size, ia, ib);
763e4b17023SJohn Marino     }
764e4b17023SJohn Marino 
765e4b17023SJohn Marino   comps = XCNEWVEC (struct component *, n);
766e4b17023SJohn Marino   bad = component_of (comp_father, n);
767e4b17023SJohn Marino   FOR_EACH_VEC_ELT (data_reference_p, datarefs, i, dr)
768e4b17023SJohn Marino     {
769e4b17023SJohn Marino       ia = (unsigned) (size_t) dr->aux;
770e4b17023SJohn Marino       ca = component_of (comp_father, ia);
771e4b17023SJohn Marino       if (ca == bad)
772e4b17023SJohn Marino 	continue;
773e4b17023SJohn Marino 
774e4b17023SJohn Marino       comp = comps[ca];
775e4b17023SJohn Marino       if (!comp)
776e4b17023SJohn Marino 	{
777e4b17023SJohn Marino 	  comp = XCNEW (struct component);
778e4b17023SJohn Marino 	  comp->refs = VEC_alloc (dref, heap, comp_size[ca]);
779e4b17023SJohn Marino 	  comps[ca] = comp;
780e4b17023SJohn Marino 	}
781e4b17023SJohn Marino 
782e4b17023SJohn Marino       dataref = XCNEW (struct dref_d);
783e4b17023SJohn Marino       dataref->ref = dr;
784e4b17023SJohn Marino       dataref->stmt = DR_STMT (dr);
785e4b17023SJohn Marino       dataref->offset = double_int_zero;
786e4b17023SJohn Marino       dataref->distance = 0;
787e4b17023SJohn Marino 
788e4b17023SJohn Marino       dataref->always_accessed
789e4b17023SJohn Marino 	      = dominated_by_p (CDI_DOMINATORS, last_always_executed,
790e4b17023SJohn Marino 				gimple_bb (dataref->stmt));
791e4b17023SJohn Marino       dataref->pos = VEC_length (dref, comp->refs);
792e4b17023SJohn Marino       VEC_quick_push (dref, comp->refs, dataref);
793e4b17023SJohn Marino     }
794e4b17023SJohn Marino 
795e4b17023SJohn Marino   for (i = 0; i < n; i++)
796e4b17023SJohn Marino     {
797e4b17023SJohn Marino       comp = comps[i];
798e4b17023SJohn Marino       if (comp)
799e4b17023SJohn Marino 	{
800e4b17023SJohn Marino 	  comp->next = comp_list;
801e4b17023SJohn Marino 	  comp_list = comp;
802e4b17023SJohn Marino 	}
803e4b17023SJohn Marino     }
804e4b17023SJohn Marino   free (comps);
805e4b17023SJohn Marino 
806e4b17023SJohn Marino end:
807e4b17023SJohn Marino   free (comp_father);
808e4b17023SJohn Marino   free (comp_size);
809e4b17023SJohn Marino   return comp_list;
810e4b17023SJohn Marino }
811e4b17023SJohn Marino 
812e4b17023SJohn Marino /* Returns true if the component COMP satisfies the conditions
813e4b17023SJohn Marino    described in 2) at the beginning of this file.  LOOP is the current
814e4b17023SJohn Marino    loop.  */
815e4b17023SJohn Marino 
816e4b17023SJohn Marino static bool
suitable_component_p(struct loop * loop,struct component * comp)817e4b17023SJohn Marino suitable_component_p (struct loop *loop, struct component *comp)
818e4b17023SJohn Marino {
819e4b17023SJohn Marino   unsigned i;
820e4b17023SJohn Marino   dref a, first;
821e4b17023SJohn Marino   basic_block ba, bp = loop->header;
822e4b17023SJohn Marino   bool ok, has_write = false;
823e4b17023SJohn Marino 
824e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, comp->refs, i, a)
825e4b17023SJohn Marino     {
826e4b17023SJohn Marino       ba = gimple_bb (a->stmt);
827e4b17023SJohn Marino 
828e4b17023SJohn Marino       if (!just_once_each_iteration_p (loop, ba))
829e4b17023SJohn Marino 	return false;
830e4b17023SJohn Marino 
831e4b17023SJohn Marino       gcc_assert (dominated_by_p (CDI_DOMINATORS, ba, bp));
832e4b17023SJohn Marino       bp = ba;
833e4b17023SJohn Marino 
834e4b17023SJohn Marino       if (DR_IS_WRITE (a->ref))
835e4b17023SJohn Marino 	has_write = true;
836e4b17023SJohn Marino     }
837e4b17023SJohn Marino 
838e4b17023SJohn Marino   first = VEC_index (dref, comp->refs, 0);
839e4b17023SJohn Marino   ok = suitable_reference_p (first->ref, &comp->comp_step);
840e4b17023SJohn Marino   gcc_assert (ok);
841e4b17023SJohn Marino   first->offset = double_int_zero;
842e4b17023SJohn Marino 
843e4b17023SJohn Marino   for (i = 1; VEC_iterate (dref, comp->refs, i, a); i++)
844e4b17023SJohn Marino     {
845e4b17023SJohn Marino       if (!determine_offset (first->ref, a->ref, &a->offset))
846e4b17023SJohn Marino 	return false;
847e4b17023SJohn Marino 
848e4b17023SJohn Marino #ifdef ENABLE_CHECKING
849e4b17023SJohn Marino       {
850e4b17023SJohn Marino 	enum ref_step_type a_step;
851e4b17023SJohn Marino 	ok = suitable_reference_p (a->ref, &a_step);
852e4b17023SJohn Marino 	gcc_assert (ok && a_step == comp->comp_step);
853e4b17023SJohn Marino       }
854e4b17023SJohn Marino #endif
855e4b17023SJohn Marino     }
856e4b17023SJohn Marino 
857e4b17023SJohn Marino   /* If there is a write inside the component, we must know whether the
858e4b17023SJohn Marino      step is nonzero or not -- we would not otherwise be able to recognize
859e4b17023SJohn Marino      whether the value accessed by reads comes from the OFFSET-th iteration
860e4b17023SJohn Marino      or the previous one.  */
861e4b17023SJohn Marino   if (has_write && comp->comp_step == RS_ANY)
862e4b17023SJohn Marino     return false;
863e4b17023SJohn Marino 
864e4b17023SJohn Marino   return true;
865e4b17023SJohn Marino }
866e4b17023SJohn Marino 
867e4b17023SJohn Marino /* Check the conditions on references inside each of components COMPS,
868e4b17023SJohn Marino    and remove the unsuitable components from the list.  The new list
869e4b17023SJohn Marino    of components is returned.  The conditions are described in 2) at
870e4b17023SJohn Marino    the beginning of this file.  LOOP is the current loop.  */
871e4b17023SJohn Marino 
872e4b17023SJohn Marino static struct component *
filter_suitable_components(struct loop * loop,struct component * comps)873e4b17023SJohn Marino filter_suitable_components (struct loop *loop, struct component *comps)
874e4b17023SJohn Marino {
875e4b17023SJohn Marino   struct component **comp, *act;
876e4b17023SJohn Marino 
877e4b17023SJohn Marino   for (comp = &comps; *comp; )
878e4b17023SJohn Marino     {
879e4b17023SJohn Marino       act = *comp;
880e4b17023SJohn Marino       if (suitable_component_p (loop, act))
881e4b17023SJohn Marino 	comp = &act->next;
882e4b17023SJohn Marino       else
883e4b17023SJohn Marino 	{
884e4b17023SJohn Marino 	  dref ref;
885e4b17023SJohn Marino 	  unsigned i;
886e4b17023SJohn Marino 
887e4b17023SJohn Marino 	  *comp = act->next;
888e4b17023SJohn Marino 	  FOR_EACH_VEC_ELT (dref, act->refs, i, ref)
889e4b17023SJohn Marino 	    free (ref);
890e4b17023SJohn Marino 	  release_component (act);
891e4b17023SJohn Marino 	}
892e4b17023SJohn Marino     }
893e4b17023SJohn Marino 
894e4b17023SJohn Marino   return comps;
895e4b17023SJohn Marino }
896e4b17023SJohn Marino 
897e4b17023SJohn Marino /* Compares two drefs A and B by their offset and position.  Callback for
898e4b17023SJohn Marino    qsort.  */
899e4b17023SJohn Marino 
900e4b17023SJohn Marino static int
order_drefs(const void * a,const void * b)901e4b17023SJohn Marino order_drefs (const void *a, const void *b)
902e4b17023SJohn Marino {
903e4b17023SJohn Marino   const dref *const da = (const dref *) a;
904e4b17023SJohn Marino   const dref *const db = (const dref *) b;
905e4b17023SJohn Marino   int offcmp = double_int_scmp ((*da)->offset, (*db)->offset);
906e4b17023SJohn Marino 
907e4b17023SJohn Marino   if (offcmp != 0)
908e4b17023SJohn Marino     return offcmp;
909e4b17023SJohn Marino 
910e4b17023SJohn Marino   return (*da)->pos - (*db)->pos;
911e4b17023SJohn Marino }
912e4b17023SJohn Marino 
913e4b17023SJohn Marino /* Returns root of the CHAIN.  */
914e4b17023SJohn Marino 
915e4b17023SJohn Marino static inline dref
get_chain_root(chain_p chain)916e4b17023SJohn Marino get_chain_root (chain_p chain)
917e4b17023SJohn Marino {
918e4b17023SJohn Marino   return VEC_index (dref, chain->refs, 0);
919e4b17023SJohn Marino }
920e4b17023SJohn Marino 
921e4b17023SJohn Marino /* Adds REF to the chain CHAIN.  */
922e4b17023SJohn Marino 
923e4b17023SJohn Marino static void
add_ref_to_chain(chain_p chain,dref ref)924e4b17023SJohn Marino add_ref_to_chain (chain_p chain, dref ref)
925e4b17023SJohn Marino {
926e4b17023SJohn Marino   dref root = get_chain_root (chain);
927e4b17023SJohn Marino   double_int dist;
928e4b17023SJohn Marino 
929e4b17023SJohn Marino   gcc_assert (double_int_scmp (root->offset, ref->offset) <= 0);
930e4b17023SJohn Marino   dist = double_int_sub (ref->offset, root->offset);
931e4b17023SJohn Marino   if (double_int_ucmp (uhwi_to_double_int (MAX_DISTANCE), dist) <= 0)
932e4b17023SJohn Marino     {
933e4b17023SJohn Marino       free (ref);
934e4b17023SJohn Marino       return;
935e4b17023SJohn Marino     }
936e4b17023SJohn Marino   gcc_assert (double_int_fits_in_uhwi_p (dist));
937e4b17023SJohn Marino 
938e4b17023SJohn Marino   VEC_safe_push (dref, heap, chain->refs, ref);
939e4b17023SJohn Marino 
940e4b17023SJohn Marino   ref->distance = double_int_to_uhwi (dist);
941e4b17023SJohn Marino 
942e4b17023SJohn Marino   if (ref->distance >= chain->length)
943e4b17023SJohn Marino     {
944e4b17023SJohn Marino       chain->length = ref->distance;
945e4b17023SJohn Marino       chain->has_max_use_after = false;
946e4b17023SJohn Marino     }
947e4b17023SJohn Marino 
948e4b17023SJohn Marino   if (ref->distance == chain->length
949e4b17023SJohn Marino       && ref->pos > root->pos)
950e4b17023SJohn Marino     chain->has_max_use_after = true;
951e4b17023SJohn Marino 
952e4b17023SJohn Marino   chain->all_always_accessed &= ref->always_accessed;
953e4b17023SJohn Marino }
954e4b17023SJohn Marino 
955e4b17023SJohn Marino /* Returns the chain for invariant component COMP.  */
956e4b17023SJohn Marino 
957e4b17023SJohn Marino static chain_p
make_invariant_chain(struct component * comp)958e4b17023SJohn Marino make_invariant_chain (struct component *comp)
959e4b17023SJohn Marino {
960e4b17023SJohn Marino   chain_p chain = XCNEW (struct chain);
961e4b17023SJohn Marino   unsigned i;
962e4b17023SJohn Marino   dref ref;
963e4b17023SJohn Marino 
964e4b17023SJohn Marino   chain->type = CT_INVARIANT;
965e4b17023SJohn Marino 
966e4b17023SJohn Marino   chain->all_always_accessed = true;
967e4b17023SJohn Marino 
968e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, comp->refs, i, ref)
969e4b17023SJohn Marino     {
970e4b17023SJohn Marino       VEC_safe_push (dref, heap, chain->refs, ref);
971e4b17023SJohn Marino       chain->all_always_accessed &= ref->always_accessed;
972e4b17023SJohn Marino     }
973e4b17023SJohn Marino 
974e4b17023SJohn Marino   return chain;
975e4b17023SJohn Marino }
976e4b17023SJohn Marino 
977e4b17023SJohn Marino /* Make a new chain rooted at REF.  */
978e4b17023SJohn Marino 
979e4b17023SJohn Marino static chain_p
make_rooted_chain(dref ref)980e4b17023SJohn Marino make_rooted_chain (dref ref)
981e4b17023SJohn Marino {
982e4b17023SJohn Marino   chain_p chain = XCNEW (struct chain);
983e4b17023SJohn Marino 
984e4b17023SJohn Marino   chain->type = DR_IS_READ (ref->ref) ? CT_LOAD : CT_STORE_LOAD;
985e4b17023SJohn Marino 
986e4b17023SJohn Marino   VEC_safe_push (dref, heap, chain->refs, ref);
987e4b17023SJohn Marino   chain->all_always_accessed = ref->always_accessed;
988e4b17023SJohn Marino 
989e4b17023SJohn Marino   ref->distance = 0;
990e4b17023SJohn Marino 
991e4b17023SJohn Marino   return chain;
992e4b17023SJohn Marino }
993e4b17023SJohn Marino 
994e4b17023SJohn Marino /* Returns true if CHAIN is not trivial.  */
995e4b17023SJohn Marino 
996e4b17023SJohn Marino static bool
nontrivial_chain_p(chain_p chain)997e4b17023SJohn Marino nontrivial_chain_p (chain_p chain)
998e4b17023SJohn Marino {
999e4b17023SJohn Marino   return chain != NULL && VEC_length (dref, chain->refs) > 1;
1000e4b17023SJohn Marino }
1001e4b17023SJohn Marino 
1002e4b17023SJohn Marino /* Returns the ssa name that contains the value of REF, or NULL_TREE if there
1003e4b17023SJohn Marino    is no such name.  */
1004e4b17023SJohn Marino 
1005e4b17023SJohn Marino static tree
name_for_ref(dref ref)1006e4b17023SJohn Marino name_for_ref (dref ref)
1007e4b17023SJohn Marino {
1008e4b17023SJohn Marino   tree name;
1009e4b17023SJohn Marino 
1010e4b17023SJohn Marino   if (is_gimple_assign (ref->stmt))
1011e4b17023SJohn Marino     {
1012e4b17023SJohn Marino       if (!ref->ref || DR_IS_READ (ref->ref))
1013e4b17023SJohn Marino 	name = gimple_assign_lhs (ref->stmt);
1014e4b17023SJohn Marino       else
1015e4b17023SJohn Marino 	name = gimple_assign_rhs1 (ref->stmt);
1016e4b17023SJohn Marino     }
1017e4b17023SJohn Marino   else
1018e4b17023SJohn Marino     name = PHI_RESULT (ref->stmt);
1019e4b17023SJohn Marino 
1020e4b17023SJohn Marino   return (TREE_CODE (name) == SSA_NAME ? name : NULL_TREE);
1021e4b17023SJohn Marino }
1022e4b17023SJohn Marino 
1023e4b17023SJohn Marino /* Returns true if REF is a valid initializer for ROOT with given DISTANCE (in
1024e4b17023SJohn Marino    iterations of the innermost enclosing loop).  */
1025e4b17023SJohn Marino 
1026e4b17023SJohn Marino static bool
valid_initializer_p(struct data_reference * ref,unsigned distance,struct data_reference * root)1027e4b17023SJohn Marino valid_initializer_p (struct data_reference *ref,
1028e4b17023SJohn Marino 		     unsigned distance, struct data_reference *root)
1029e4b17023SJohn Marino {
1030e4b17023SJohn Marino   aff_tree diff, base, step;
1031e4b17023SJohn Marino   double_int off;
1032e4b17023SJohn Marino 
1033e4b17023SJohn Marino   /* Both REF and ROOT must be accessing the same object.  */
1034e4b17023SJohn Marino   if (!operand_equal_p (DR_BASE_ADDRESS (ref), DR_BASE_ADDRESS (root), 0))
1035e4b17023SJohn Marino     return false;
1036e4b17023SJohn Marino 
1037e4b17023SJohn Marino   /* The initializer is defined outside of loop, hence its address must be
1038e4b17023SJohn Marino      invariant inside the loop.  */
1039e4b17023SJohn Marino   gcc_assert (integer_zerop (DR_STEP (ref)));
1040e4b17023SJohn Marino 
1041e4b17023SJohn Marino   /* If the address of the reference is invariant, initializer must access
1042e4b17023SJohn Marino      exactly the same location.  */
1043e4b17023SJohn Marino   if (integer_zerop (DR_STEP (root)))
1044e4b17023SJohn Marino     return (operand_equal_p (DR_OFFSET (ref), DR_OFFSET (root), 0)
1045e4b17023SJohn Marino 	    && operand_equal_p (DR_INIT (ref), DR_INIT (root), 0));
1046e4b17023SJohn Marino 
1047e4b17023SJohn Marino   /* Verify that this index of REF is equal to the root's index at
1048e4b17023SJohn Marino      -DISTANCE-th iteration.  */
1049e4b17023SJohn Marino   aff_combination_dr_offset (root, &diff);
1050e4b17023SJohn Marino   aff_combination_dr_offset (ref, &base);
1051e4b17023SJohn Marino   aff_combination_scale (&base, double_int_minus_one);
1052e4b17023SJohn Marino   aff_combination_add (&diff, &base);
1053e4b17023SJohn Marino 
1054e4b17023SJohn Marino   tree_to_aff_combination_expand (DR_STEP (root), TREE_TYPE (DR_STEP (root)),
1055e4b17023SJohn Marino 				  &step, &name_expansions);
1056e4b17023SJohn Marino   if (!aff_combination_constant_multiple_p (&diff, &step, &off))
1057e4b17023SJohn Marino     return false;
1058e4b17023SJohn Marino 
1059e4b17023SJohn Marino   if (!double_int_equal_p (off, uhwi_to_double_int (distance)))
1060e4b17023SJohn Marino     return false;
1061e4b17023SJohn Marino 
1062e4b17023SJohn Marino   return true;
1063e4b17023SJohn Marino }
1064e4b17023SJohn Marino 
1065e4b17023SJohn Marino /* Finds looparound phi node of LOOP that copies the value of REF, and if its
1066e4b17023SJohn Marino    initial value is correct (equal to initial value of REF shifted by one
1067e4b17023SJohn Marino    iteration), returns the phi node.  Otherwise, NULL_TREE is returned.  ROOT
1068e4b17023SJohn Marino    is the root of the current chain.  */
1069e4b17023SJohn Marino 
1070e4b17023SJohn Marino static gimple
find_looparound_phi(struct loop * loop,dref ref,dref root)1071e4b17023SJohn Marino find_looparound_phi (struct loop *loop, dref ref, dref root)
1072e4b17023SJohn Marino {
1073e4b17023SJohn Marino   tree name, init, init_ref;
1074e4b17023SJohn Marino   gimple phi = NULL, init_stmt;
1075e4b17023SJohn Marino   edge latch = loop_latch_edge (loop);
1076e4b17023SJohn Marino   struct data_reference init_dr;
1077e4b17023SJohn Marino   gimple_stmt_iterator psi;
1078e4b17023SJohn Marino 
1079e4b17023SJohn Marino   if (is_gimple_assign (ref->stmt))
1080e4b17023SJohn Marino     {
1081e4b17023SJohn Marino       if (DR_IS_READ (ref->ref))
1082e4b17023SJohn Marino 	name = gimple_assign_lhs (ref->stmt);
1083e4b17023SJohn Marino       else
1084e4b17023SJohn Marino 	name = gimple_assign_rhs1 (ref->stmt);
1085e4b17023SJohn Marino     }
1086e4b17023SJohn Marino   else
1087e4b17023SJohn Marino     name = PHI_RESULT (ref->stmt);
1088e4b17023SJohn Marino   if (!name)
1089e4b17023SJohn Marino     return NULL;
1090e4b17023SJohn Marino 
1091e4b17023SJohn Marino   for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
1092e4b17023SJohn Marino     {
1093e4b17023SJohn Marino       phi = gsi_stmt (psi);
1094e4b17023SJohn Marino       if (PHI_ARG_DEF_FROM_EDGE (phi, latch) == name)
1095e4b17023SJohn Marino 	break;
1096e4b17023SJohn Marino     }
1097e4b17023SJohn Marino 
1098e4b17023SJohn Marino   if (gsi_end_p (psi))
1099e4b17023SJohn Marino     return NULL;
1100e4b17023SJohn Marino 
1101e4b17023SJohn Marino   init = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (loop));
1102e4b17023SJohn Marino   if (TREE_CODE (init) != SSA_NAME)
1103e4b17023SJohn Marino     return NULL;
1104e4b17023SJohn Marino   init_stmt = SSA_NAME_DEF_STMT (init);
1105e4b17023SJohn Marino   if (gimple_code (init_stmt) != GIMPLE_ASSIGN)
1106e4b17023SJohn Marino     return NULL;
1107e4b17023SJohn Marino   gcc_assert (gimple_assign_lhs (init_stmt) == init);
1108e4b17023SJohn Marino 
1109e4b17023SJohn Marino   init_ref = gimple_assign_rhs1 (init_stmt);
1110e4b17023SJohn Marino   if (!REFERENCE_CLASS_P (init_ref)
1111e4b17023SJohn Marino       && !DECL_P (init_ref))
1112e4b17023SJohn Marino     return NULL;
1113e4b17023SJohn Marino 
1114e4b17023SJohn Marino   /* Analyze the behavior of INIT_REF with respect to LOOP (innermost
1115e4b17023SJohn Marino      loop enclosing PHI).  */
1116e4b17023SJohn Marino   memset (&init_dr, 0, sizeof (struct data_reference));
1117e4b17023SJohn Marino   DR_REF (&init_dr) = init_ref;
1118e4b17023SJohn Marino   DR_STMT (&init_dr) = phi;
1119e4b17023SJohn Marino   if (!dr_analyze_innermost (&init_dr, loop))
1120e4b17023SJohn Marino     return NULL;
1121e4b17023SJohn Marino 
1122e4b17023SJohn Marino   if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
1123e4b17023SJohn Marino     return NULL;
1124e4b17023SJohn Marino 
1125e4b17023SJohn Marino   return phi;
1126e4b17023SJohn Marino }
1127e4b17023SJohn Marino 
1128e4b17023SJohn Marino /* Adds a reference for the looparound copy of REF in PHI to CHAIN.  */
1129e4b17023SJohn Marino 
1130e4b17023SJohn Marino static void
insert_looparound_copy(chain_p chain,dref ref,gimple phi)1131e4b17023SJohn Marino insert_looparound_copy (chain_p chain, dref ref, gimple phi)
1132e4b17023SJohn Marino {
1133e4b17023SJohn Marino   dref nw = XCNEW (struct dref_d), aref;
1134e4b17023SJohn Marino   unsigned i;
1135e4b17023SJohn Marino 
1136e4b17023SJohn Marino   nw->stmt = phi;
1137e4b17023SJohn Marino   nw->distance = ref->distance + 1;
1138e4b17023SJohn Marino   nw->always_accessed = 1;
1139e4b17023SJohn Marino 
1140e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, aref)
1141e4b17023SJohn Marino     if (aref->distance >= nw->distance)
1142e4b17023SJohn Marino       break;
1143e4b17023SJohn Marino   VEC_safe_insert (dref, heap, chain->refs, i, nw);
1144e4b17023SJohn Marino 
1145e4b17023SJohn Marino   if (nw->distance > chain->length)
1146e4b17023SJohn Marino     {
1147e4b17023SJohn Marino       chain->length = nw->distance;
1148e4b17023SJohn Marino       chain->has_max_use_after = false;
1149e4b17023SJohn Marino     }
1150e4b17023SJohn Marino }
1151e4b17023SJohn Marino 
1152e4b17023SJohn Marino /* For references in CHAIN that are copied around the LOOP (created previously
1153e4b17023SJohn Marino    by PRE, or by user), add the results of such copies to the chain.  This
1154e4b17023SJohn Marino    enables us to remove the copies by unrolling, and may need less registers
1155e4b17023SJohn Marino    (also, it may allow us to combine chains together).  */
1156e4b17023SJohn Marino 
1157e4b17023SJohn Marino static void
add_looparound_copies(struct loop * loop,chain_p chain)1158e4b17023SJohn Marino add_looparound_copies (struct loop *loop, chain_p chain)
1159e4b17023SJohn Marino {
1160e4b17023SJohn Marino   unsigned i;
1161e4b17023SJohn Marino   dref ref, root = get_chain_root (chain);
1162e4b17023SJohn Marino   gimple phi;
1163e4b17023SJohn Marino 
1164e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, ref)
1165e4b17023SJohn Marino     {
1166e4b17023SJohn Marino       phi = find_looparound_phi (loop, ref, root);
1167e4b17023SJohn Marino       if (!phi)
1168e4b17023SJohn Marino 	continue;
1169e4b17023SJohn Marino 
1170e4b17023SJohn Marino       bitmap_set_bit (looparound_phis, SSA_NAME_VERSION (PHI_RESULT (phi)));
1171e4b17023SJohn Marino       insert_looparound_copy (chain, ref, phi);
1172e4b17023SJohn Marino     }
1173e4b17023SJohn Marino }
1174e4b17023SJohn Marino 
1175e4b17023SJohn Marino /* Find roots of the values and determine distances in the component COMP.
1176e4b17023SJohn Marino    The references are redistributed into CHAINS.  LOOP is the current
1177e4b17023SJohn Marino    loop.  */
1178e4b17023SJohn Marino 
1179e4b17023SJohn Marino static void
determine_roots_comp(struct loop * loop,struct component * comp,VEC (chain_p,heap)** chains)1180e4b17023SJohn Marino determine_roots_comp (struct loop *loop,
1181e4b17023SJohn Marino 		      struct component *comp,
1182e4b17023SJohn Marino 		      VEC (chain_p, heap) **chains)
1183e4b17023SJohn Marino {
1184e4b17023SJohn Marino   unsigned i;
1185e4b17023SJohn Marino   dref a;
1186e4b17023SJohn Marino   chain_p chain = NULL;
1187e4b17023SJohn Marino   double_int last_ofs = double_int_zero;
1188e4b17023SJohn Marino 
1189e4b17023SJohn Marino   /* Invariants are handled specially.  */
1190e4b17023SJohn Marino   if (comp->comp_step == RS_INVARIANT)
1191e4b17023SJohn Marino     {
1192e4b17023SJohn Marino       chain = make_invariant_chain (comp);
1193e4b17023SJohn Marino       VEC_safe_push (chain_p, heap, *chains, chain);
1194e4b17023SJohn Marino       return;
1195e4b17023SJohn Marino     }
1196e4b17023SJohn Marino 
1197e4b17023SJohn Marino   VEC_qsort (dref, comp->refs, order_drefs);
1198e4b17023SJohn Marino 
1199e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, comp->refs, i, a)
1200e4b17023SJohn Marino     {
1201e4b17023SJohn Marino       if (!chain || DR_IS_WRITE (a->ref)
1202e4b17023SJohn Marino 	  || double_int_ucmp (uhwi_to_double_int (MAX_DISTANCE),
1203e4b17023SJohn Marino 			      double_int_sub (a->offset, last_ofs)) <= 0)
1204e4b17023SJohn Marino 	{
1205e4b17023SJohn Marino 	  if (nontrivial_chain_p (chain))
1206e4b17023SJohn Marino 	    {
1207e4b17023SJohn Marino 	      add_looparound_copies (loop, chain);
1208e4b17023SJohn Marino 	      VEC_safe_push (chain_p, heap, *chains, chain);
1209e4b17023SJohn Marino 	    }
1210e4b17023SJohn Marino 	  else
1211e4b17023SJohn Marino 	    release_chain (chain);
1212e4b17023SJohn Marino 	  chain = make_rooted_chain (a);
1213e4b17023SJohn Marino 	  last_ofs = a->offset;
1214e4b17023SJohn Marino 	  continue;
1215e4b17023SJohn Marino 	}
1216e4b17023SJohn Marino 
1217e4b17023SJohn Marino       add_ref_to_chain (chain, a);
1218e4b17023SJohn Marino     }
1219e4b17023SJohn Marino 
1220e4b17023SJohn Marino   if (nontrivial_chain_p (chain))
1221e4b17023SJohn Marino     {
1222e4b17023SJohn Marino       add_looparound_copies (loop, chain);
1223e4b17023SJohn Marino       VEC_safe_push (chain_p, heap, *chains, chain);
1224e4b17023SJohn Marino     }
1225e4b17023SJohn Marino   else
1226e4b17023SJohn Marino     release_chain (chain);
1227e4b17023SJohn Marino }
1228e4b17023SJohn Marino 
1229e4b17023SJohn Marino /* Find roots of the values and determine distances in components COMPS, and
1230e4b17023SJohn Marino    separates the references to CHAINS.  LOOP is the current loop.  */
1231e4b17023SJohn Marino 
1232e4b17023SJohn Marino static void
determine_roots(struct loop * loop,struct component * comps,VEC (chain_p,heap)** chains)1233e4b17023SJohn Marino determine_roots (struct loop *loop,
1234e4b17023SJohn Marino 		 struct component *comps, VEC (chain_p, heap) **chains)
1235e4b17023SJohn Marino {
1236e4b17023SJohn Marino   struct component *comp;
1237e4b17023SJohn Marino 
1238e4b17023SJohn Marino   for (comp = comps; comp; comp = comp->next)
1239e4b17023SJohn Marino     determine_roots_comp (loop, comp, chains);
1240e4b17023SJohn Marino }
1241e4b17023SJohn Marino 
1242e4b17023SJohn Marino /* Replace the reference in statement STMT with temporary variable
1243e4b17023SJohn Marino    NEW_TREE.  If SET is true, NEW_TREE is instead initialized to the value of
1244e4b17023SJohn Marino    the reference in the statement.  IN_LHS is true if the reference
1245e4b17023SJohn Marino    is in the lhs of STMT, false if it is in rhs.  */
1246e4b17023SJohn Marino 
1247e4b17023SJohn Marino static void
replace_ref_with(gimple stmt,tree new_tree,bool set,bool in_lhs)1248e4b17023SJohn Marino replace_ref_with (gimple stmt, tree new_tree, bool set, bool in_lhs)
1249e4b17023SJohn Marino {
1250e4b17023SJohn Marino   tree val;
1251e4b17023SJohn Marino   gimple new_stmt;
1252e4b17023SJohn Marino   gimple_stmt_iterator bsi, psi;
1253e4b17023SJohn Marino 
1254e4b17023SJohn Marino   if (gimple_code (stmt) == GIMPLE_PHI)
1255e4b17023SJohn Marino     {
1256e4b17023SJohn Marino       gcc_assert (!in_lhs && !set);
1257e4b17023SJohn Marino 
1258e4b17023SJohn Marino       val = PHI_RESULT (stmt);
1259e4b17023SJohn Marino       bsi = gsi_after_labels (gimple_bb (stmt));
1260e4b17023SJohn Marino       psi = gsi_for_stmt (stmt);
1261e4b17023SJohn Marino       remove_phi_node (&psi, false);
1262e4b17023SJohn Marino 
1263e4b17023SJohn Marino       /* Turn the phi node into GIMPLE_ASSIGN.  */
1264e4b17023SJohn Marino       new_stmt = gimple_build_assign (val, new_tree);
1265e4b17023SJohn Marino       gsi_insert_before (&bsi, new_stmt, GSI_NEW_STMT);
1266e4b17023SJohn Marino       return;
1267e4b17023SJohn Marino     }
1268e4b17023SJohn Marino 
1269e4b17023SJohn Marino   /* Since the reference is of gimple_reg type, it should only
1270e4b17023SJohn Marino      appear as lhs or rhs of modify statement.  */
1271e4b17023SJohn Marino   gcc_assert (is_gimple_assign (stmt));
1272e4b17023SJohn Marino 
1273e4b17023SJohn Marino   bsi = gsi_for_stmt (stmt);
1274e4b17023SJohn Marino 
1275e4b17023SJohn Marino   /* If we do not need to initialize NEW_TREE, just replace the use of OLD.  */
1276e4b17023SJohn Marino   if (!set)
1277e4b17023SJohn Marino     {
1278e4b17023SJohn Marino       gcc_assert (!in_lhs);
1279e4b17023SJohn Marino       gimple_assign_set_rhs_from_tree (&bsi, new_tree);
1280e4b17023SJohn Marino       stmt = gsi_stmt (bsi);
1281e4b17023SJohn Marino       update_stmt (stmt);
1282e4b17023SJohn Marino       return;
1283e4b17023SJohn Marino     }
1284e4b17023SJohn Marino 
1285e4b17023SJohn Marino   if (in_lhs)
1286e4b17023SJohn Marino     {
1287e4b17023SJohn Marino       /* We have statement
1288e4b17023SJohn Marino 
1289e4b17023SJohn Marino 	 OLD = VAL
1290e4b17023SJohn Marino 
1291e4b17023SJohn Marino 	 If OLD is a memory reference, then VAL is gimple_val, and we transform
1292e4b17023SJohn Marino 	 this to
1293e4b17023SJohn Marino 
1294e4b17023SJohn Marino 	 OLD = VAL
1295e4b17023SJohn Marino 	 NEW = VAL
1296e4b17023SJohn Marino 
1297e4b17023SJohn Marino 	 Otherwise, we are replacing a combination chain,
1298e4b17023SJohn Marino 	 VAL is the expression that performs the combination, and OLD is an
1299e4b17023SJohn Marino 	 SSA name.  In this case, we transform the assignment to
1300e4b17023SJohn Marino 
1301e4b17023SJohn Marino 	 OLD = VAL
1302e4b17023SJohn Marino 	 NEW = OLD
1303e4b17023SJohn Marino 
1304e4b17023SJohn Marino 	 */
1305e4b17023SJohn Marino 
1306e4b17023SJohn Marino       val = gimple_assign_lhs (stmt);
1307e4b17023SJohn Marino       if (TREE_CODE (val) != SSA_NAME)
1308e4b17023SJohn Marino 	{
1309e4b17023SJohn Marino 	  val = gimple_assign_rhs1 (stmt);
1310e4b17023SJohn Marino 	  gcc_assert (gimple_assign_single_p (stmt));
1311e4b17023SJohn Marino 	  if (TREE_CLOBBER_P (val))
1312e4b17023SJohn Marino 	    {
1313e4b17023SJohn Marino 	      val = gimple_default_def (cfun, SSA_NAME_VAR (new_tree));
1314e4b17023SJohn Marino 	      if (val == NULL_TREE)
1315e4b17023SJohn Marino 		{
1316e4b17023SJohn Marino 		  val = make_ssa_name (SSA_NAME_VAR (new_tree),
1317e4b17023SJohn Marino 				       gimple_build_nop ());
1318e4b17023SJohn Marino 		  set_default_def (SSA_NAME_VAR (new_tree), val);
1319e4b17023SJohn Marino 		}
1320e4b17023SJohn Marino 	    }
1321e4b17023SJohn Marino 	  else
1322e4b17023SJohn Marino 	    gcc_assert (gimple_assign_copy_p (stmt));
1323e4b17023SJohn Marino 	}
1324e4b17023SJohn Marino     }
1325e4b17023SJohn Marino   else
1326e4b17023SJohn Marino     {
1327e4b17023SJohn Marino       /* VAL = OLD
1328e4b17023SJohn Marino 
1329e4b17023SJohn Marino 	 is transformed to
1330e4b17023SJohn Marino 
1331e4b17023SJohn Marino 	 VAL = OLD
1332e4b17023SJohn Marino 	 NEW = VAL  */
1333e4b17023SJohn Marino 
1334e4b17023SJohn Marino       val = gimple_assign_lhs (stmt);
1335e4b17023SJohn Marino     }
1336e4b17023SJohn Marino 
1337e4b17023SJohn Marino   new_stmt = gimple_build_assign (new_tree, unshare_expr (val));
1338e4b17023SJohn Marino   gsi_insert_after (&bsi, new_stmt, GSI_NEW_STMT);
1339e4b17023SJohn Marino }
1340e4b17023SJohn Marino 
1341e4b17023SJohn Marino /* Returns the reference to the address of REF in the ITER-th iteration of
1342e4b17023SJohn Marino    LOOP, or NULL if we fail to determine it (ITER may be negative).  We
1343e4b17023SJohn Marino    try to preserve the original shape of the reference (not rewrite it
1344e4b17023SJohn Marino    as an indirect ref to the address), to make tree_could_trap_p in
1345e4b17023SJohn Marino    prepare_initializers_chain return false more often.  */
1346e4b17023SJohn Marino 
1347e4b17023SJohn Marino static tree
ref_at_iteration(struct loop * loop,tree ref,int iter)1348e4b17023SJohn Marino ref_at_iteration (struct loop *loop, tree ref, int iter)
1349e4b17023SJohn Marino {
1350e4b17023SJohn Marino   tree idx, *idx_p, type, val, op0 = NULL_TREE, ret;
1351e4b17023SJohn Marino   affine_iv iv;
1352e4b17023SJohn Marino   bool ok;
1353e4b17023SJohn Marino 
1354e4b17023SJohn Marino   if (handled_component_p (ref))
1355e4b17023SJohn Marino     {
1356e4b17023SJohn Marino       op0 = ref_at_iteration (loop, TREE_OPERAND (ref, 0), iter);
1357e4b17023SJohn Marino       if (!op0)
1358e4b17023SJohn Marino 	return NULL_TREE;
1359e4b17023SJohn Marino     }
1360e4b17023SJohn Marino   else if (!INDIRECT_REF_P (ref)
1361e4b17023SJohn Marino 	   && TREE_CODE (ref) != MEM_REF)
1362e4b17023SJohn Marino     return unshare_expr (ref);
1363e4b17023SJohn Marino 
1364e4b17023SJohn Marino   if (TREE_CODE (ref) == MEM_REF)
1365e4b17023SJohn Marino     {
1366e4b17023SJohn Marino       ret = unshare_expr (ref);
1367e4b17023SJohn Marino       idx = TREE_OPERAND (ref, 0);
1368e4b17023SJohn Marino       idx_p = &TREE_OPERAND (ret, 0);
1369e4b17023SJohn Marino     }
1370e4b17023SJohn Marino   else if (TREE_CODE (ref) == COMPONENT_REF)
1371e4b17023SJohn Marino     {
1372e4b17023SJohn Marino       /* Check that the offset is loop invariant.  */
1373e4b17023SJohn Marino       if (TREE_OPERAND (ref, 2)
1374e4b17023SJohn Marino 	  && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 2)))
1375e4b17023SJohn Marino 	return NULL_TREE;
1376e4b17023SJohn Marino 
1377e4b17023SJohn Marino       return build3 (COMPONENT_REF, TREE_TYPE (ref), op0,
1378e4b17023SJohn Marino 		     unshare_expr (TREE_OPERAND (ref, 1)),
1379e4b17023SJohn Marino 		     unshare_expr (TREE_OPERAND (ref, 2)));
1380e4b17023SJohn Marino     }
1381e4b17023SJohn Marino   else if (TREE_CODE (ref) == ARRAY_REF)
1382e4b17023SJohn Marino     {
1383e4b17023SJohn Marino       /* Check that the lower bound and the step are loop invariant.  */
1384e4b17023SJohn Marino       if (TREE_OPERAND (ref, 2)
1385e4b17023SJohn Marino 	  && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 2)))
1386e4b17023SJohn Marino 	return NULL_TREE;
1387e4b17023SJohn Marino       if (TREE_OPERAND (ref, 3)
1388e4b17023SJohn Marino 	  && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 3)))
1389e4b17023SJohn Marino 	return NULL_TREE;
1390e4b17023SJohn Marino 
1391e4b17023SJohn Marino       ret = build4 (ARRAY_REF, TREE_TYPE (ref), op0, NULL_TREE,
1392e4b17023SJohn Marino 		    unshare_expr (TREE_OPERAND (ref, 2)),
1393e4b17023SJohn Marino 		    unshare_expr (TREE_OPERAND (ref, 3)));
1394e4b17023SJohn Marino       idx = TREE_OPERAND (ref, 1);
1395e4b17023SJohn Marino       idx_p = &TREE_OPERAND (ret, 1);
1396e4b17023SJohn Marino     }
1397e4b17023SJohn Marino   else
1398e4b17023SJohn Marino     return NULL_TREE;
1399e4b17023SJohn Marino 
1400e4b17023SJohn Marino   ok = simple_iv (loop, loop, idx, &iv, true);
1401e4b17023SJohn Marino   if (!ok)
1402e4b17023SJohn Marino     return NULL_TREE;
1403e4b17023SJohn Marino   iv.base = expand_simple_operations (iv.base);
1404e4b17023SJohn Marino   if (integer_zerop (iv.step))
1405e4b17023SJohn Marino     *idx_p = unshare_expr (iv.base);
1406e4b17023SJohn Marino   else
1407e4b17023SJohn Marino     {
1408e4b17023SJohn Marino       type = TREE_TYPE (iv.base);
1409e4b17023SJohn Marino       if (POINTER_TYPE_P (type))
1410e4b17023SJohn Marino 	{
1411e4b17023SJohn Marino 	  val = fold_build2 (MULT_EXPR, sizetype, iv.step,
1412e4b17023SJohn Marino 			     size_int (iter));
1413e4b17023SJohn Marino 	  val = fold_build_pointer_plus (iv.base, val);
1414e4b17023SJohn Marino 	}
1415e4b17023SJohn Marino       else
1416e4b17023SJohn Marino 	{
1417e4b17023SJohn Marino 	  val = fold_build2 (MULT_EXPR, type, iv.step,
1418e4b17023SJohn Marino 			     build_int_cst_type (type, iter));
1419e4b17023SJohn Marino 	  val = fold_build2 (PLUS_EXPR, type, iv.base, val);
1420e4b17023SJohn Marino 	}
1421e4b17023SJohn Marino       *idx_p = unshare_expr (val);
1422e4b17023SJohn Marino     }
1423e4b17023SJohn Marino 
1424e4b17023SJohn Marino   return ret;
1425e4b17023SJohn Marino }
1426e4b17023SJohn Marino 
1427e4b17023SJohn Marino /* Get the initialization expression for the INDEX-th temporary variable
1428e4b17023SJohn Marino    of CHAIN.  */
1429e4b17023SJohn Marino 
1430e4b17023SJohn Marino static tree
get_init_expr(chain_p chain,unsigned index)1431e4b17023SJohn Marino get_init_expr (chain_p chain, unsigned index)
1432e4b17023SJohn Marino {
1433e4b17023SJohn Marino   if (chain->type == CT_COMBINATION)
1434e4b17023SJohn Marino     {
1435e4b17023SJohn Marino       tree e1 = get_init_expr (chain->ch1, index);
1436e4b17023SJohn Marino       tree e2 = get_init_expr (chain->ch2, index);
1437e4b17023SJohn Marino 
1438e4b17023SJohn Marino       return fold_build2 (chain->op, chain->rslt_type, e1, e2);
1439e4b17023SJohn Marino     }
1440e4b17023SJohn Marino   else
1441e4b17023SJohn Marino     return VEC_index (tree, chain->inits, index);
1442e4b17023SJohn Marino }
1443e4b17023SJohn Marino 
1444e4b17023SJohn Marino /* Marks all virtual operands of statement STMT for renaming.  */
1445e4b17023SJohn Marino 
1446e4b17023SJohn Marino void
mark_virtual_ops_for_renaming(gimple stmt)1447e4b17023SJohn Marino mark_virtual_ops_for_renaming (gimple stmt)
1448e4b17023SJohn Marino {
1449e4b17023SJohn Marino   tree var;
1450e4b17023SJohn Marino 
1451e4b17023SJohn Marino   if (gimple_code (stmt) == GIMPLE_PHI)
1452e4b17023SJohn Marino     {
1453e4b17023SJohn Marino       var = PHI_RESULT (stmt);
1454e4b17023SJohn Marino       if (is_gimple_reg (var))
1455e4b17023SJohn Marino 	return;
1456e4b17023SJohn Marino 
1457e4b17023SJohn Marino       if (TREE_CODE (var) == SSA_NAME)
1458e4b17023SJohn Marino 	var = SSA_NAME_VAR (var);
1459e4b17023SJohn Marino       mark_sym_for_renaming (var);
1460e4b17023SJohn Marino       return;
1461e4b17023SJohn Marino     }
1462e4b17023SJohn Marino 
1463e4b17023SJohn Marino   update_stmt (stmt);
1464e4b17023SJohn Marino   if (gimple_vuse (stmt))
1465e4b17023SJohn Marino     mark_sym_for_renaming (gimple_vop (cfun));
1466e4b17023SJohn Marino }
1467e4b17023SJohn Marino 
1468e4b17023SJohn Marino /* Returns a new temporary variable used for the I-th variable carrying
1469e4b17023SJohn Marino    value of REF.  The variable's uid is marked in TMP_VARS.  */
1470e4b17023SJohn Marino 
1471e4b17023SJohn Marino static tree
predcom_tmp_var(tree ref,unsigned i,bitmap tmp_vars)1472e4b17023SJohn Marino predcom_tmp_var (tree ref, unsigned i, bitmap tmp_vars)
1473e4b17023SJohn Marino {
1474e4b17023SJohn Marino   tree type = TREE_TYPE (ref);
1475e4b17023SJohn Marino   /* We never access the components of the temporary variable in predictive
1476e4b17023SJohn Marino      commoning.  */
1477e4b17023SJohn Marino   tree var = create_tmp_reg (type, get_lsm_tmp_name (ref, i));
1478e4b17023SJohn Marino 
1479e4b17023SJohn Marino   add_referenced_var (var);
1480e4b17023SJohn Marino   bitmap_set_bit (tmp_vars, DECL_UID (var));
1481e4b17023SJohn Marino   return var;
1482e4b17023SJohn Marino }
1483e4b17023SJohn Marino 
1484e4b17023SJohn Marino /* Creates the variables for CHAIN, as well as phi nodes for them and
1485e4b17023SJohn Marino    initialization on entry to LOOP.  Uids of the newly created
1486e4b17023SJohn Marino    temporary variables are marked in TMP_VARS.  */
1487e4b17023SJohn Marino 
1488e4b17023SJohn Marino static void
initialize_root_vars(struct loop * loop,chain_p chain,bitmap tmp_vars)1489e4b17023SJohn Marino initialize_root_vars (struct loop *loop, chain_p chain, bitmap tmp_vars)
1490e4b17023SJohn Marino {
1491e4b17023SJohn Marino   unsigned i;
1492e4b17023SJohn Marino   unsigned n = chain->length;
1493e4b17023SJohn Marino   dref root = get_chain_root (chain);
1494e4b17023SJohn Marino   bool reuse_first = !chain->has_max_use_after;
1495e4b17023SJohn Marino   tree ref, init, var, next;
1496e4b17023SJohn Marino   gimple phi;
1497e4b17023SJohn Marino   gimple_seq stmts;
1498e4b17023SJohn Marino   edge entry = loop_preheader_edge (loop), latch = loop_latch_edge (loop);
1499e4b17023SJohn Marino 
1500e4b17023SJohn Marino   /* If N == 0, then all the references are within the single iteration.  And
1501e4b17023SJohn Marino      since this is an nonempty chain, reuse_first cannot be true.  */
1502e4b17023SJohn Marino   gcc_assert (n > 0 || !reuse_first);
1503e4b17023SJohn Marino 
1504e4b17023SJohn Marino   chain->vars = VEC_alloc (tree, heap, n + 1);
1505e4b17023SJohn Marino 
1506e4b17023SJohn Marino   if (chain->type == CT_COMBINATION)
1507e4b17023SJohn Marino     ref = gimple_assign_lhs (root->stmt);
1508e4b17023SJohn Marino   else
1509e4b17023SJohn Marino     ref = DR_REF (root->ref);
1510e4b17023SJohn Marino 
1511e4b17023SJohn Marino   for (i = 0; i < n + (reuse_first ? 0 : 1); i++)
1512e4b17023SJohn Marino     {
1513e4b17023SJohn Marino       var = predcom_tmp_var (ref, i, tmp_vars);
1514e4b17023SJohn Marino       VEC_quick_push (tree, chain->vars, var);
1515e4b17023SJohn Marino     }
1516e4b17023SJohn Marino   if (reuse_first)
1517e4b17023SJohn Marino     VEC_quick_push (tree, chain->vars, VEC_index (tree, chain->vars, 0));
1518e4b17023SJohn Marino 
1519e4b17023SJohn Marino   FOR_EACH_VEC_ELT (tree, chain->vars, i, var)
1520e4b17023SJohn Marino     VEC_replace (tree, chain->vars, i, make_ssa_name (var, NULL));
1521e4b17023SJohn Marino 
1522e4b17023SJohn Marino   for (i = 0; i < n; i++)
1523e4b17023SJohn Marino     {
1524e4b17023SJohn Marino       var = VEC_index (tree, chain->vars, i);
1525e4b17023SJohn Marino       next = VEC_index (tree, chain->vars, i + 1);
1526e4b17023SJohn Marino       init = get_init_expr (chain, i);
1527e4b17023SJohn Marino 
1528e4b17023SJohn Marino       init = force_gimple_operand (init, &stmts, true, NULL_TREE);
1529e4b17023SJohn Marino       if (stmts)
1530e4b17023SJohn Marino 	gsi_insert_seq_on_edge_immediate (entry, stmts);
1531e4b17023SJohn Marino 
1532e4b17023SJohn Marino       phi = create_phi_node (var, loop->header);
1533e4b17023SJohn Marino       SSA_NAME_DEF_STMT (var) = phi;
1534e4b17023SJohn Marino       add_phi_arg (phi, init, entry, UNKNOWN_LOCATION);
1535e4b17023SJohn Marino       add_phi_arg (phi, next, latch, UNKNOWN_LOCATION);
1536e4b17023SJohn Marino     }
1537e4b17023SJohn Marino }
1538e4b17023SJohn Marino 
1539e4b17023SJohn Marino /* Create the variables and initialization statement for root of chain
1540e4b17023SJohn Marino    CHAIN.  Uids of the newly created temporary variables are marked
1541e4b17023SJohn Marino    in TMP_VARS.  */
1542e4b17023SJohn Marino 
1543e4b17023SJohn Marino static void
initialize_root(struct loop * loop,chain_p chain,bitmap tmp_vars)1544e4b17023SJohn Marino initialize_root (struct loop *loop, chain_p chain, bitmap tmp_vars)
1545e4b17023SJohn Marino {
1546e4b17023SJohn Marino   dref root = get_chain_root (chain);
1547e4b17023SJohn Marino   bool in_lhs = (chain->type == CT_STORE_LOAD
1548e4b17023SJohn Marino 		 || chain->type == CT_COMBINATION);
1549e4b17023SJohn Marino 
1550e4b17023SJohn Marino   initialize_root_vars (loop, chain, tmp_vars);
1551e4b17023SJohn Marino   replace_ref_with (root->stmt,
1552e4b17023SJohn Marino 		    VEC_index (tree, chain->vars, chain->length),
1553e4b17023SJohn Marino 		    true, in_lhs);
1554e4b17023SJohn Marino }
1555e4b17023SJohn Marino 
1556e4b17023SJohn Marino /* Initializes a variable for load motion for ROOT and prepares phi nodes and
1557e4b17023SJohn Marino    initialization on entry to LOOP if necessary.  The ssa name for the variable
1558e4b17023SJohn Marino    is stored in VARS.  If WRITTEN is true, also a phi node to copy its value
1559e4b17023SJohn Marino    around the loop is created.  Uid of the newly created temporary variable
1560e4b17023SJohn Marino    is marked in TMP_VARS.  INITS is the list containing the (single)
1561e4b17023SJohn Marino    initializer.  */
1562e4b17023SJohn Marino 
1563e4b17023SJohn Marino static void
initialize_root_vars_lm(struct loop * loop,dref root,bool written,VEC (tree,heap)** vars,VEC (tree,heap)* inits,bitmap tmp_vars)1564e4b17023SJohn Marino initialize_root_vars_lm (struct loop *loop, dref root, bool written,
1565e4b17023SJohn Marino 			 VEC(tree, heap) **vars, VEC(tree, heap) *inits,
1566e4b17023SJohn Marino 			 bitmap tmp_vars)
1567e4b17023SJohn Marino {
1568e4b17023SJohn Marino   unsigned i;
1569e4b17023SJohn Marino   tree ref = DR_REF (root->ref), init, var, next;
1570e4b17023SJohn Marino   gimple_seq stmts;
1571e4b17023SJohn Marino   gimple phi;
1572e4b17023SJohn Marino   edge entry = loop_preheader_edge (loop), latch = loop_latch_edge (loop);
1573e4b17023SJohn Marino 
1574e4b17023SJohn Marino   /* Find the initializer for the variable, and check that it cannot
1575e4b17023SJohn Marino      trap.  */
1576e4b17023SJohn Marino   init = VEC_index (tree, inits, 0);
1577e4b17023SJohn Marino 
1578e4b17023SJohn Marino   *vars = VEC_alloc (tree, heap, written ? 2 : 1);
1579e4b17023SJohn Marino   var = predcom_tmp_var (ref, 0, tmp_vars);
1580e4b17023SJohn Marino   VEC_quick_push (tree, *vars, var);
1581e4b17023SJohn Marino   if (written)
1582e4b17023SJohn Marino     VEC_quick_push (tree, *vars, VEC_index (tree, *vars, 0));
1583e4b17023SJohn Marino 
1584e4b17023SJohn Marino   FOR_EACH_VEC_ELT (tree, *vars, i, var)
1585e4b17023SJohn Marino     VEC_replace (tree, *vars, i, make_ssa_name (var, NULL));
1586e4b17023SJohn Marino 
1587e4b17023SJohn Marino   var = VEC_index (tree, *vars, 0);
1588e4b17023SJohn Marino 
1589e4b17023SJohn Marino   init = force_gimple_operand (init, &stmts, written, NULL_TREE);
1590e4b17023SJohn Marino   if (stmts)
1591e4b17023SJohn Marino     gsi_insert_seq_on_edge_immediate (entry, stmts);
1592e4b17023SJohn Marino 
1593e4b17023SJohn Marino   if (written)
1594e4b17023SJohn Marino     {
1595e4b17023SJohn Marino       next = VEC_index (tree, *vars, 1);
1596e4b17023SJohn Marino       phi = create_phi_node (var, loop->header);
1597e4b17023SJohn Marino       SSA_NAME_DEF_STMT (var) = phi;
1598e4b17023SJohn Marino       add_phi_arg (phi, init, entry, UNKNOWN_LOCATION);
1599e4b17023SJohn Marino       add_phi_arg (phi, next, latch, UNKNOWN_LOCATION);
1600e4b17023SJohn Marino     }
1601e4b17023SJohn Marino   else
1602e4b17023SJohn Marino     {
1603e4b17023SJohn Marino       gimple init_stmt = gimple_build_assign (var, init);
1604e4b17023SJohn Marino       mark_virtual_ops_for_renaming (init_stmt);
1605e4b17023SJohn Marino       gsi_insert_on_edge_immediate (entry, init_stmt);
1606e4b17023SJohn Marino     }
1607e4b17023SJohn Marino }
1608e4b17023SJohn Marino 
1609e4b17023SJohn Marino 
1610e4b17023SJohn Marino /* Execute load motion for references in chain CHAIN.  Uids of the newly
1611e4b17023SJohn Marino    created temporary variables are marked in TMP_VARS.  */
1612e4b17023SJohn Marino 
1613e4b17023SJohn Marino static void
execute_load_motion(struct loop * loop,chain_p chain,bitmap tmp_vars)1614e4b17023SJohn Marino execute_load_motion (struct loop *loop, chain_p chain, bitmap tmp_vars)
1615e4b17023SJohn Marino {
1616e4b17023SJohn Marino   VEC (tree, heap) *vars;
1617e4b17023SJohn Marino   dref a;
1618e4b17023SJohn Marino   unsigned n_writes = 0, ridx, i;
1619e4b17023SJohn Marino   tree var;
1620e4b17023SJohn Marino 
1621e4b17023SJohn Marino   gcc_assert (chain->type == CT_INVARIANT);
1622e4b17023SJohn Marino   gcc_assert (!chain->combined);
1623e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, a)
1624e4b17023SJohn Marino     if (DR_IS_WRITE (a->ref))
1625e4b17023SJohn Marino       n_writes++;
1626e4b17023SJohn Marino 
1627e4b17023SJohn Marino   /* If there are no reads in the loop, there is nothing to do.  */
1628e4b17023SJohn Marino   if (n_writes == VEC_length (dref, chain->refs))
1629e4b17023SJohn Marino     return;
1630e4b17023SJohn Marino 
1631e4b17023SJohn Marino   initialize_root_vars_lm (loop, get_chain_root (chain), n_writes > 0,
1632e4b17023SJohn Marino 			   &vars, chain->inits, tmp_vars);
1633e4b17023SJohn Marino 
1634e4b17023SJohn Marino   ridx = 0;
1635e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, a)
1636e4b17023SJohn Marino     {
1637e4b17023SJohn Marino       bool is_read = DR_IS_READ (a->ref);
1638e4b17023SJohn Marino       mark_virtual_ops_for_renaming (a->stmt);
1639e4b17023SJohn Marino 
1640e4b17023SJohn Marino       if (DR_IS_WRITE (a->ref))
1641e4b17023SJohn Marino 	{
1642e4b17023SJohn Marino 	  n_writes--;
1643e4b17023SJohn Marino 	  if (n_writes)
1644e4b17023SJohn Marino 	    {
1645e4b17023SJohn Marino 	      var = VEC_index (tree, vars, 0);
1646e4b17023SJohn Marino 	      var = make_ssa_name (SSA_NAME_VAR (var), NULL);
1647e4b17023SJohn Marino 	      VEC_replace (tree, vars, 0, var);
1648e4b17023SJohn Marino 	    }
1649e4b17023SJohn Marino 	  else
1650e4b17023SJohn Marino 	    ridx = 1;
1651e4b17023SJohn Marino 	}
1652e4b17023SJohn Marino 
1653e4b17023SJohn Marino       replace_ref_with (a->stmt, VEC_index (tree, vars, ridx),
1654e4b17023SJohn Marino 			!is_read, !is_read);
1655e4b17023SJohn Marino     }
1656e4b17023SJohn Marino 
1657e4b17023SJohn Marino   VEC_free (tree, heap, vars);
1658e4b17023SJohn Marino }
1659e4b17023SJohn Marino 
1660e4b17023SJohn Marino /* Returns the single statement in that NAME is used, excepting
1661e4b17023SJohn Marino    the looparound phi nodes contained in one of the chains.  If there is no
1662e4b17023SJohn Marino    such statement, or more statements, NULL is returned.  */
1663e4b17023SJohn Marino 
1664e4b17023SJohn Marino static gimple
single_nonlooparound_use(tree name)1665e4b17023SJohn Marino single_nonlooparound_use (tree name)
1666e4b17023SJohn Marino {
1667e4b17023SJohn Marino   use_operand_p use;
1668e4b17023SJohn Marino   imm_use_iterator it;
1669e4b17023SJohn Marino   gimple stmt, ret = NULL;
1670e4b17023SJohn Marino 
1671e4b17023SJohn Marino   FOR_EACH_IMM_USE_FAST (use, it, name)
1672e4b17023SJohn Marino     {
1673e4b17023SJohn Marino       stmt = USE_STMT (use);
1674e4b17023SJohn Marino 
1675e4b17023SJohn Marino       if (gimple_code (stmt) == GIMPLE_PHI)
1676e4b17023SJohn Marino 	{
1677e4b17023SJohn Marino 	  /* Ignore uses in looparound phi nodes.  Uses in other phi nodes
1678e4b17023SJohn Marino 	     could not be processed anyway, so just fail for them.  */
1679e4b17023SJohn Marino 	  if (bitmap_bit_p (looparound_phis,
1680e4b17023SJohn Marino 			    SSA_NAME_VERSION (PHI_RESULT (stmt))))
1681e4b17023SJohn Marino 	    continue;
1682e4b17023SJohn Marino 
1683e4b17023SJohn Marino 	  return NULL;
1684e4b17023SJohn Marino 	}
1685e4b17023SJohn Marino       else if (is_gimple_debug (stmt))
1686e4b17023SJohn Marino 	continue;
1687e4b17023SJohn Marino       else if (ret != NULL)
1688e4b17023SJohn Marino 	return NULL;
1689e4b17023SJohn Marino       else
1690e4b17023SJohn Marino 	ret = stmt;
1691e4b17023SJohn Marino     }
1692e4b17023SJohn Marino 
1693e4b17023SJohn Marino   return ret;
1694e4b17023SJohn Marino }
1695e4b17023SJohn Marino 
1696e4b17023SJohn Marino /* Remove statement STMT, as well as the chain of assignments in that it is
1697e4b17023SJohn Marino    used.  */
1698e4b17023SJohn Marino 
1699e4b17023SJohn Marino static void
remove_stmt(gimple stmt)1700e4b17023SJohn Marino remove_stmt (gimple stmt)
1701e4b17023SJohn Marino {
1702e4b17023SJohn Marino   tree name;
1703e4b17023SJohn Marino   gimple next;
1704e4b17023SJohn Marino   gimple_stmt_iterator psi;
1705e4b17023SJohn Marino 
1706e4b17023SJohn Marino   if (gimple_code (stmt) == GIMPLE_PHI)
1707e4b17023SJohn Marino     {
1708e4b17023SJohn Marino       name = PHI_RESULT (stmt);
1709e4b17023SJohn Marino       next = single_nonlooparound_use (name);
1710e4b17023SJohn Marino       reset_debug_uses (stmt);
1711e4b17023SJohn Marino       psi = gsi_for_stmt (stmt);
1712e4b17023SJohn Marino       remove_phi_node (&psi, true);
1713e4b17023SJohn Marino 
1714e4b17023SJohn Marino       if (!next
1715e4b17023SJohn Marino 	  || !gimple_assign_ssa_name_copy_p (next)
1716e4b17023SJohn Marino 	  || gimple_assign_rhs1 (next) != name)
1717e4b17023SJohn Marino 	return;
1718e4b17023SJohn Marino 
1719e4b17023SJohn Marino       stmt = next;
1720e4b17023SJohn Marino     }
1721e4b17023SJohn Marino 
1722e4b17023SJohn Marino   while (1)
1723e4b17023SJohn Marino     {
1724e4b17023SJohn Marino       gimple_stmt_iterator bsi;
1725e4b17023SJohn Marino 
1726e4b17023SJohn Marino       bsi = gsi_for_stmt (stmt);
1727e4b17023SJohn Marino 
1728e4b17023SJohn Marino       name = gimple_assign_lhs (stmt);
1729e4b17023SJohn Marino       gcc_assert (TREE_CODE (name) == SSA_NAME);
1730e4b17023SJohn Marino 
1731e4b17023SJohn Marino       next = single_nonlooparound_use (name);
1732e4b17023SJohn Marino       reset_debug_uses (stmt);
1733e4b17023SJohn Marino 
1734e4b17023SJohn Marino       mark_virtual_ops_for_renaming (stmt);
1735e4b17023SJohn Marino       gsi_remove (&bsi, true);
1736e4b17023SJohn Marino       release_defs (stmt);
1737e4b17023SJohn Marino 
1738e4b17023SJohn Marino       if (!next
1739e4b17023SJohn Marino 	  || !gimple_assign_ssa_name_copy_p (next)
1740e4b17023SJohn Marino 	  || gimple_assign_rhs1 (next) != name)
1741e4b17023SJohn Marino 	return;
1742e4b17023SJohn Marino 
1743e4b17023SJohn Marino       stmt = next;
1744e4b17023SJohn Marino     }
1745e4b17023SJohn Marino }
1746e4b17023SJohn Marino 
1747e4b17023SJohn Marino /* Perform the predictive commoning optimization for a chain CHAIN.
1748e4b17023SJohn Marino    Uids of the newly created temporary variables are marked in TMP_VARS.*/
1749e4b17023SJohn Marino 
1750e4b17023SJohn Marino static void
execute_pred_commoning_chain(struct loop * loop,chain_p chain,bitmap tmp_vars)1751e4b17023SJohn Marino execute_pred_commoning_chain (struct loop *loop, chain_p chain,
1752e4b17023SJohn Marino 			     bitmap tmp_vars)
1753e4b17023SJohn Marino {
1754e4b17023SJohn Marino   unsigned i;
1755e4b17023SJohn Marino   dref a, root;
1756e4b17023SJohn Marino   tree var;
1757e4b17023SJohn Marino 
1758e4b17023SJohn Marino   if (chain->combined)
1759e4b17023SJohn Marino     {
1760e4b17023SJohn Marino       /* For combined chains, just remove the statements that are used to
1761e4b17023SJohn Marino 	 compute the values of the expression (except for the root one).  */
1762e4b17023SJohn Marino       for (i = 1; VEC_iterate (dref, chain->refs, i, a); i++)
1763e4b17023SJohn Marino 	remove_stmt (a->stmt);
1764e4b17023SJohn Marino     }
1765e4b17023SJohn Marino   else
1766e4b17023SJohn Marino     {
1767e4b17023SJohn Marino       /* For non-combined chains, set up the variables that hold its value,
1768e4b17023SJohn Marino 	 and replace the uses of the original references by these
1769e4b17023SJohn Marino 	 variables.  */
1770e4b17023SJohn Marino       root = get_chain_root (chain);
1771e4b17023SJohn Marino       mark_virtual_ops_for_renaming (root->stmt);
1772e4b17023SJohn Marino 
1773e4b17023SJohn Marino       initialize_root (loop, chain, tmp_vars);
1774e4b17023SJohn Marino       for (i = 1; VEC_iterate (dref, chain->refs, i, a); i++)
1775e4b17023SJohn Marino 	{
1776e4b17023SJohn Marino 	  mark_virtual_ops_for_renaming (a->stmt);
1777e4b17023SJohn Marino 	  var = VEC_index (tree, chain->vars, chain->length - a->distance);
1778e4b17023SJohn Marino 	  replace_ref_with (a->stmt, var, false, false);
1779e4b17023SJohn Marino 	}
1780e4b17023SJohn Marino     }
1781e4b17023SJohn Marino }
1782e4b17023SJohn Marino 
1783e4b17023SJohn Marino /* Determines the unroll factor necessary to remove as many temporary variable
1784e4b17023SJohn Marino    copies as possible.  CHAINS is the list of chains that will be
1785e4b17023SJohn Marino    optimized.  */
1786e4b17023SJohn Marino 
1787e4b17023SJohn Marino static unsigned
determine_unroll_factor(VEC (chain_p,heap)* chains)1788e4b17023SJohn Marino determine_unroll_factor (VEC (chain_p, heap) *chains)
1789e4b17023SJohn Marino {
1790e4b17023SJohn Marino   chain_p chain;
1791e4b17023SJohn Marino   unsigned factor = 1, af, nfactor, i;
1792e4b17023SJohn Marino   unsigned max = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);
1793e4b17023SJohn Marino 
1794e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, chains, i, chain)
1795e4b17023SJohn Marino     {
1796e4b17023SJohn Marino       if (chain->type == CT_INVARIANT || chain->combined)
1797e4b17023SJohn Marino 	continue;
1798e4b17023SJohn Marino 
1799e4b17023SJohn Marino       /* The best unroll factor for this chain is equal to the number of
1800e4b17023SJohn Marino 	 temporary variables that we create for it.  */
1801e4b17023SJohn Marino       af = chain->length;
1802e4b17023SJohn Marino       if (chain->has_max_use_after)
1803e4b17023SJohn Marino 	af++;
1804e4b17023SJohn Marino 
1805e4b17023SJohn Marino       nfactor = factor * af / gcd (factor, af);
1806e4b17023SJohn Marino       if (nfactor <= max)
1807e4b17023SJohn Marino 	factor = nfactor;
1808e4b17023SJohn Marino     }
1809e4b17023SJohn Marino 
1810e4b17023SJohn Marino   return factor;
1811e4b17023SJohn Marino }
1812e4b17023SJohn Marino 
1813e4b17023SJohn Marino /* Perform the predictive commoning optimization for CHAINS.
1814e4b17023SJohn Marino    Uids of the newly created temporary variables are marked in TMP_VARS.  */
1815e4b17023SJohn Marino 
1816e4b17023SJohn Marino static void
execute_pred_commoning(struct loop * loop,VEC (chain_p,heap)* chains,bitmap tmp_vars)1817e4b17023SJohn Marino execute_pred_commoning (struct loop *loop, VEC (chain_p, heap) *chains,
1818e4b17023SJohn Marino 			bitmap tmp_vars)
1819e4b17023SJohn Marino {
1820e4b17023SJohn Marino   chain_p chain;
1821e4b17023SJohn Marino   unsigned i;
1822e4b17023SJohn Marino 
1823e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, chains, i, chain)
1824e4b17023SJohn Marino     {
1825e4b17023SJohn Marino       if (chain->type == CT_INVARIANT)
1826e4b17023SJohn Marino 	execute_load_motion (loop, chain, tmp_vars);
1827e4b17023SJohn Marino       else
1828e4b17023SJohn Marino 	execute_pred_commoning_chain (loop, chain, tmp_vars);
1829e4b17023SJohn Marino     }
1830e4b17023SJohn Marino 
1831e4b17023SJohn Marino   update_ssa (TODO_update_ssa_only_virtuals);
1832e4b17023SJohn Marino }
1833e4b17023SJohn Marino 
1834e4b17023SJohn Marino /* For each reference in CHAINS, if its defining statement is
1835e4b17023SJohn Marino    phi node, record the ssa name that is defined by it.  */
1836e4b17023SJohn Marino 
1837e4b17023SJohn Marino static void
replace_phis_by_defined_names(VEC (chain_p,heap)* chains)1838e4b17023SJohn Marino replace_phis_by_defined_names (VEC (chain_p, heap) *chains)
1839e4b17023SJohn Marino {
1840e4b17023SJohn Marino   chain_p chain;
1841e4b17023SJohn Marino   dref a;
1842e4b17023SJohn Marino   unsigned i, j;
1843e4b17023SJohn Marino 
1844e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, chains, i, chain)
1845e4b17023SJohn Marino     FOR_EACH_VEC_ELT (dref, chain->refs, j, a)
1846e4b17023SJohn Marino       {
1847e4b17023SJohn Marino 	if (gimple_code (a->stmt) == GIMPLE_PHI)
1848e4b17023SJohn Marino 	  {
1849e4b17023SJohn Marino 	    a->name_defined_by_phi = PHI_RESULT (a->stmt);
1850e4b17023SJohn Marino 	    a->stmt = NULL;
1851e4b17023SJohn Marino 	  }
1852e4b17023SJohn Marino       }
1853e4b17023SJohn Marino }
1854e4b17023SJohn Marino 
1855e4b17023SJohn Marino /* For each reference in CHAINS, if name_defined_by_phi is not
1856e4b17023SJohn Marino    NULL, use it to set the stmt field.  */
1857e4b17023SJohn Marino 
1858e4b17023SJohn Marino static void
replace_names_by_phis(VEC (chain_p,heap)* chains)1859e4b17023SJohn Marino replace_names_by_phis (VEC (chain_p, heap) *chains)
1860e4b17023SJohn Marino {
1861e4b17023SJohn Marino   chain_p chain;
1862e4b17023SJohn Marino   dref a;
1863e4b17023SJohn Marino   unsigned i, j;
1864e4b17023SJohn Marino 
1865e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, chains, i, chain)
1866e4b17023SJohn Marino     FOR_EACH_VEC_ELT (dref, chain->refs, j, a)
1867e4b17023SJohn Marino       if (a->stmt == NULL)
1868e4b17023SJohn Marino 	{
1869e4b17023SJohn Marino 	  a->stmt = SSA_NAME_DEF_STMT (a->name_defined_by_phi);
1870e4b17023SJohn Marino 	  gcc_assert (gimple_code (a->stmt) == GIMPLE_PHI);
1871e4b17023SJohn Marino 	  a->name_defined_by_phi = NULL_TREE;
1872e4b17023SJohn Marino 	}
1873e4b17023SJohn Marino }
1874e4b17023SJohn Marino 
1875e4b17023SJohn Marino /* Wrapper over execute_pred_commoning, to pass it as a callback
1876e4b17023SJohn Marino    to tree_transform_and_unroll_loop.  */
1877e4b17023SJohn Marino 
1878e4b17023SJohn Marino struct epcc_data
1879e4b17023SJohn Marino {
1880e4b17023SJohn Marino   VEC (chain_p, heap) *chains;
1881e4b17023SJohn Marino   bitmap tmp_vars;
1882e4b17023SJohn Marino };
1883e4b17023SJohn Marino 
1884e4b17023SJohn Marino static void
execute_pred_commoning_cbck(struct loop * loop,void * data)1885e4b17023SJohn Marino execute_pred_commoning_cbck (struct loop *loop, void *data)
1886e4b17023SJohn Marino {
1887e4b17023SJohn Marino   struct epcc_data *const dta = (struct epcc_data *) data;
1888e4b17023SJohn Marino 
1889e4b17023SJohn Marino   /* Restore phi nodes that were replaced by ssa names before
1890e4b17023SJohn Marino      tree_transform_and_unroll_loop (see detailed description in
1891e4b17023SJohn Marino      tree_predictive_commoning_loop).  */
1892e4b17023SJohn Marino   replace_names_by_phis (dta->chains);
1893e4b17023SJohn Marino   execute_pred_commoning (loop, dta->chains, dta->tmp_vars);
1894e4b17023SJohn Marino }
1895e4b17023SJohn Marino 
1896e4b17023SJohn Marino /* Base NAME and all the names in the chain of phi nodes that use it
1897e4b17023SJohn Marino    on variable VAR.  The phi nodes are recognized by being in the copies of
1898e4b17023SJohn Marino    the header of the LOOP.  */
1899e4b17023SJohn Marino 
1900e4b17023SJohn Marino static void
base_names_in_chain_on(struct loop * loop,tree name,tree var)1901e4b17023SJohn Marino base_names_in_chain_on (struct loop *loop, tree name, tree var)
1902e4b17023SJohn Marino {
1903e4b17023SJohn Marino   gimple stmt, phi;
1904e4b17023SJohn Marino   imm_use_iterator iter;
1905e4b17023SJohn Marino 
1906e4b17023SJohn Marino   SSA_NAME_VAR (name) = var;
1907e4b17023SJohn Marino 
1908e4b17023SJohn Marino   while (1)
1909e4b17023SJohn Marino     {
1910e4b17023SJohn Marino       phi = NULL;
1911e4b17023SJohn Marino       FOR_EACH_IMM_USE_STMT (stmt, iter, name)
1912e4b17023SJohn Marino 	{
1913e4b17023SJohn Marino 	  if (gimple_code (stmt) == GIMPLE_PHI
1914e4b17023SJohn Marino 	      && flow_bb_inside_loop_p (loop, gimple_bb (stmt)))
1915e4b17023SJohn Marino 	    {
1916e4b17023SJohn Marino 	      phi = stmt;
1917e4b17023SJohn Marino 	      BREAK_FROM_IMM_USE_STMT (iter);
1918e4b17023SJohn Marino 	    }
1919e4b17023SJohn Marino 	}
1920e4b17023SJohn Marino       if (!phi)
1921e4b17023SJohn Marino 	return;
1922e4b17023SJohn Marino 
1923e4b17023SJohn Marino       name = PHI_RESULT (phi);
1924e4b17023SJohn Marino       SSA_NAME_VAR (name) = var;
1925e4b17023SJohn Marino     }
1926e4b17023SJohn Marino }
1927e4b17023SJohn Marino 
1928e4b17023SJohn Marino /* Given an unrolled LOOP after predictive commoning, remove the
1929e4b17023SJohn Marino    register copies arising from phi nodes by changing the base
1930e4b17023SJohn Marino    variables of SSA names.  TMP_VARS is the set of the temporary variables
1931e4b17023SJohn Marino    for those we want to perform this.  */
1932e4b17023SJohn Marino 
1933e4b17023SJohn Marino static void
eliminate_temp_copies(struct loop * loop,bitmap tmp_vars)1934e4b17023SJohn Marino eliminate_temp_copies (struct loop *loop, bitmap tmp_vars)
1935e4b17023SJohn Marino {
1936e4b17023SJohn Marino   edge e;
1937e4b17023SJohn Marino   gimple phi, stmt;
1938e4b17023SJohn Marino   tree name, use, var;
1939e4b17023SJohn Marino   gimple_stmt_iterator psi;
1940e4b17023SJohn Marino 
1941e4b17023SJohn Marino   e = loop_latch_edge (loop);
1942e4b17023SJohn Marino   for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
1943e4b17023SJohn Marino     {
1944e4b17023SJohn Marino       phi = gsi_stmt (psi);
1945e4b17023SJohn Marino       name = PHI_RESULT (phi);
1946e4b17023SJohn Marino       var = SSA_NAME_VAR (name);
1947e4b17023SJohn Marino       if (!bitmap_bit_p (tmp_vars, DECL_UID (var)))
1948e4b17023SJohn Marino 	continue;
1949e4b17023SJohn Marino       use = PHI_ARG_DEF_FROM_EDGE (phi, e);
1950e4b17023SJohn Marino       gcc_assert (TREE_CODE (use) == SSA_NAME);
1951e4b17023SJohn Marino 
1952e4b17023SJohn Marino       /* Base all the ssa names in the ud and du chain of NAME on VAR.  */
1953e4b17023SJohn Marino       stmt = SSA_NAME_DEF_STMT (use);
1954e4b17023SJohn Marino       while (gimple_code (stmt) == GIMPLE_PHI
1955e4b17023SJohn Marino 	     /* In case we could not unroll the loop enough to eliminate
1956e4b17023SJohn Marino 		all copies, we may reach the loop header before the defining
1957e4b17023SJohn Marino 		statement (in that case, some register copies will be present
1958e4b17023SJohn Marino 		in loop latch in the final code, corresponding to the newly
1959e4b17023SJohn Marino 		created looparound phi nodes).  */
1960e4b17023SJohn Marino 	     && gimple_bb (stmt) != loop->header)
1961e4b17023SJohn Marino 	{
1962e4b17023SJohn Marino 	  gcc_assert (single_pred_p (gimple_bb (stmt)));
1963e4b17023SJohn Marino 	  use = PHI_ARG_DEF (stmt, 0);
1964e4b17023SJohn Marino 	  stmt = SSA_NAME_DEF_STMT (use);
1965e4b17023SJohn Marino 	}
1966e4b17023SJohn Marino 
1967e4b17023SJohn Marino       base_names_in_chain_on (loop, use, var);
1968e4b17023SJohn Marino     }
1969e4b17023SJohn Marino }
1970e4b17023SJohn Marino 
1971e4b17023SJohn Marino /* Returns true if CHAIN is suitable to be combined.  */
1972e4b17023SJohn Marino 
1973e4b17023SJohn Marino static bool
chain_can_be_combined_p(chain_p chain)1974e4b17023SJohn Marino chain_can_be_combined_p (chain_p chain)
1975e4b17023SJohn Marino {
1976e4b17023SJohn Marino   return (!chain->combined
1977e4b17023SJohn Marino 	  && (chain->type == CT_LOAD || chain->type == CT_COMBINATION));
1978e4b17023SJohn Marino }
1979e4b17023SJohn Marino 
1980e4b17023SJohn Marino /* Returns the modify statement that uses NAME.  Skips over assignment
1981e4b17023SJohn Marino    statements, NAME is replaced with the actual name used in the returned
1982e4b17023SJohn Marino    statement.  */
1983e4b17023SJohn Marino 
1984e4b17023SJohn Marino static gimple
find_use_stmt(tree * name)1985e4b17023SJohn Marino find_use_stmt (tree *name)
1986e4b17023SJohn Marino {
1987e4b17023SJohn Marino   gimple stmt;
1988e4b17023SJohn Marino   tree rhs, lhs;
1989e4b17023SJohn Marino 
1990e4b17023SJohn Marino   /* Skip over assignments.  */
1991e4b17023SJohn Marino   while (1)
1992e4b17023SJohn Marino     {
1993e4b17023SJohn Marino       stmt = single_nonlooparound_use (*name);
1994e4b17023SJohn Marino       if (!stmt)
1995e4b17023SJohn Marino 	return NULL;
1996e4b17023SJohn Marino 
1997e4b17023SJohn Marino       if (gimple_code (stmt) != GIMPLE_ASSIGN)
1998e4b17023SJohn Marino 	return NULL;
1999e4b17023SJohn Marino 
2000e4b17023SJohn Marino       lhs = gimple_assign_lhs (stmt);
2001e4b17023SJohn Marino       if (TREE_CODE (lhs) != SSA_NAME)
2002e4b17023SJohn Marino 	return NULL;
2003e4b17023SJohn Marino 
2004e4b17023SJohn Marino       if (gimple_assign_copy_p (stmt))
2005e4b17023SJohn Marino 	{
2006e4b17023SJohn Marino 	  rhs = gimple_assign_rhs1 (stmt);
2007e4b17023SJohn Marino 	  if (rhs != *name)
2008e4b17023SJohn Marino 	    return NULL;
2009e4b17023SJohn Marino 
2010e4b17023SJohn Marino 	  *name = lhs;
2011e4b17023SJohn Marino 	}
2012e4b17023SJohn Marino       else if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
2013e4b17023SJohn Marino 	       == GIMPLE_BINARY_RHS)
2014e4b17023SJohn Marino 	return stmt;
2015e4b17023SJohn Marino       else
2016e4b17023SJohn Marino 	return NULL;
2017e4b17023SJohn Marino     }
2018e4b17023SJohn Marino }
2019e4b17023SJohn Marino 
2020e4b17023SJohn Marino /* Returns true if we may perform reassociation for operation CODE in TYPE.  */
2021e4b17023SJohn Marino 
2022e4b17023SJohn Marino static bool
may_reassociate_p(tree type,enum tree_code code)2023e4b17023SJohn Marino may_reassociate_p (tree type, enum tree_code code)
2024e4b17023SJohn Marino {
2025e4b17023SJohn Marino   if (FLOAT_TYPE_P (type)
2026e4b17023SJohn Marino       && !flag_unsafe_math_optimizations)
2027e4b17023SJohn Marino     return false;
2028e4b17023SJohn Marino 
2029e4b17023SJohn Marino   return (commutative_tree_code (code)
2030e4b17023SJohn Marino 	  && associative_tree_code (code));
2031e4b17023SJohn Marino }
2032e4b17023SJohn Marino 
2033e4b17023SJohn Marino /* If the operation used in STMT is associative and commutative, go through the
2034e4b17023SJohn Marino    tree of the same operations and returns its root.  Distance to the root
2035e4b17023SJohn Marino    is stored in DISTANCE.  */
2036e4b17023SJohn Marino 
2037e4b17023SJohn Marino static gimple
find_associative_operation_root(gimple stmt,unsigned * distance)2038e4b17023SJohn Marino find_associative_operation_root (gimple stmt, unsigned *distance)
2039e4b17023SJohn Marino {
2040e4b17023SJohn Marino   tree lhs;
2041e4b17023SJohn Marino   gimple next;
2042e4b17023SJohn Marino   enum tree_code code = gimple_assign_rhs_code (stmt);
2043e4b17023SJohn Marino   tree type = TREE_TYPE (gimple_assign_lhs (stmt));
2044e4b17023SJohn Marino   unsigned dist = 0;
2045e4b17023SJohn Marino 
2046e4b17023SJohn Marino   if (!may_reassociate_p (type, code))
2047e4b17023SJohn Marino     return NULL;
2048e4b17023SJohn Marino 
2049e4b17023SJohn Marino   while (1)
2050e4b17023SJohn Marino     {
2051e4b17023SJohn Marino       lhs = gimple_assign_lhs (stmt);
2052e4b17023SJohn Marino       gcc_assert (TREE_CODE (lhs) == SSA_NAME);
2053e4b17023SJohn Marino 
2054e4b17023SJohn Marino       next = find_use_stmt (&lhs);
2055e4b17023SJohn Marino       if (!next
2056e4b17023SJohn Marino 	  || gimple_assign_rhs_code (next) != code)
2057e4b17023SJohn Marino 	break;
2058e4b17023SJohn Marino 
2059e4b17023SJohn Marino       stmt = next;
2060e4b17023SJohn Marino       dist++;
2061e4b17023SJohn Marino     }
2062e4b17023SJohn Marino 
2063e4b17023SJohn Marino   if (distance)
2064e4b17023SJohn Marino     *distance = dist;
2065e4b17023SJohn Marino   return stmt;
2066e4b17023SJohn Marino }
2067e4b17023SJohn Marino 
2068e4b17023SJohn Marino /* Returns the common statement in that NAME1 and NAME2 have a use.  If there
2069e4b17023SJohn Marino    is no such statement, returns NULL_TREE.  In case the operation used on
2070e4b17023SJohn Marino    NAME1 and NAME2 is associative and commutative, returns the root of the
2071e4b17023SJohn Marino    tree formed by this operation instead of the statement that uses NAME1 or
2072e4b17023SJohn Marino    NAME2.  */
2073e4b17023SJohn Marino 
2074e4b17023SJohn Marino static gimple
find_common_use_stmt(tree * name1,tree * name2)2075e4b17023SJohn Marino find_common_use_stmt (tree *name1, tree *name2)
2076e4b17023SJohn Marino {
2077e4b17023SJohn Marino   gimple stmt1, stmt2;
2078e4b17023SJohn Marino 
2079e4b17023SJohn Marino   stmt1 = find_use_stmt (name1);
2080e4b17023SJohn Marino   if (!stmt1)
2081e4b17023SJohn Marino     return NULL;
2082e4b17023SJohn Marino 
2083e4b17023SJohn Marino   stmt2 = find_use_stmt (name2);
2084e4b17023SJohn Marino   if (!stmt2)
2085e4b17023SJohn Marino     return NULL;
2086e4b17023SJohn Marino 
2087e4b17023SJohn Marino   if (stmt1 == stmt2)
2088e4b17023SJohn Marino     return stmt1;
2089e4b17023SJohn Marino 
2090e4b17023SJohn Marino   stmt1 = find_associative_operation_root (stmt1, NULL);
2091e4b17023SJohn Marino   if (!stmt1)
2092e4b17023SJohn Marino     return NULL;
2093e4b17023SJohn Marino   stmt2 = find_associative_operation_root (stmt2, NULL);
2094e4b17023SJohn Marino   if (!stmt2)
2095e4b17023SJohn Marino     return NULL;
2096e4b17023SJohn Marino 
2097e4b17023SJohn Marino   return (stmt1 == stmt2 ? stmt1 : NULL);
2098e4b17023SJohn Marino }
2099e4b17023SJohn Marino 
2100e4b17023SJohn Marino /* Checks whether R1 and R2 are combined together using CODE, with the result
2101e4b17023SJohn Marino    in RSLT_TYPE, in order R1 CODE R2 if SWAP is false and in order R2 CODE R1
2102e4b17023SJohn Marino    if it is true.  If CODE is ERROR_MARK, set these values instead.  */
2103e4b17023SJohn Marino 
2104e4b17023SJohn Marino static bool
combinable_refs_p(dref r1,dref r2,enum tree_code * code,bool * swap,tree * rslt_type)2105e4b17023SJohn Marino combinable_refs_p (dref r1, dref r2,
2106e4b17023SJohn Marino 		   enum tree_code *code, bool *swap, tree *rslt_type)
2107e4b17023SJohn Marino {
2108e4b17023SJohn Marino   enum tree_code acode;
2109e4b17023SJohn Marino   bool aswap;
2110e4b17023SJohn Marino   tree atype;
2111e4b17023SJohn Marino   tree name1, name2;
2112e4b17023SJohn Marino   gimple stmt;
2113e4b17023SJohn Marino 
2114e4b17023SJohn Marino   name1 = name_for_ref (r1);
2115e4b17023SJohn Marino   name2 = name_for_ref (r2);
2116e4b17023SJohn Marino   gcc_assert (name1 != NULL_TREE && name2 != NULL_TREE);
2117e4b17023SJohn Marino 
2118e4b17023SJohn Marino   stmt = find_common_use_stmt (&name1, &name2);
2119e4b17023SJohn Marino 
2120*95d28233SJohn Marino   if (!stmt
2121*95d28233SJohn Marino       /* A simple post-dominance check - make sure the combination
2122*95d28233SJohn Marino          is executed under the same condition as the references.  */
2123*95d28233SJohn Marino       || (gimple_bb (stmt) != gimple_bb (r1->stmt)
2124*95d28233SJohn Marino 	  && gimple_bb (stmt) != gimple_bb (r2->stmt)))
2125e4b17023SJohn Marino     return false;
2126e4b17023SJohn Marino 
2127e4b17023SJohn Marino   acode = gimple_assign_rhs_code (stmt);
2128e4b17023SJohn Marino   aswap = (!commutative_tree_code (acode)
2129e4b17023SJohn Marino 	   && gimple_assign_rhs1 (stmt) != name1);
2130e4b17023SJohn Marino   atype = TREE_TYPE (gimple_assign_lhs (stmt));
2131e4b17023SJohn Marino 
2132e4b17023SJohn Marino   if (*code == ERROR_MARK)
2133e4b17023SJohn Marino     {
2134e4b17023SJohn Marino       *code = acode;
2135e4b17023SJohn Marino       *swap = aswap;
2136e4b17023SJohn Marino       *rslt_type = atype;
2137e4b17023SJohn Marino       return true;
2138e4b17023SJohn Marino     }
2139e4b17023SJohn Marino 
2140e4b17023SJohn Marino   return (*code == acode
2141e4b17023SJohn Marino 	  && *swap == aswap
2142e4b17023SJohn Marino 	  && *rslt_type == atype);
2143e4b17023SJohn Marino }
2144e4b17023SJohn Marino 
2145e4b17023SJohn Marino /* Remove OP from the operation on rhs of STMT, and replace STMT with
2146e4b17023SJohn Marino    an assignment of the remaining operand.  */
2147e4b17023SJohn Marino 
2148e4b17023SJohn Marino static void
remove_name_from_operation(gimple stmt,tree op)2149e4b17023SJohn Marino remove_name_from_operation (gimple stmt, tree op)
2150e4b17023SJohn Marino {
2151e4b17023SJohn Marino   tree other_op;
2152e4b17023SJohn Marino   gimple_stmt_iterator si;
2153e4b17023SJohn Marino 
2154e4b17023SJohn Marino   gcc_assert (is_gimple_assign (stmt));
2155e4b17023SJohn Marino 
2156e4b17023SJohn Marino   if (gimple_assign_rhs1 (stmt) == op)
2157e4b17023SJohn Marino     other_op = gimple_assign_rhs2 (stmt);
2158e4b17023SJohn Marino   else
2159e4b17023SJohn Marino     other_op = gimple_assign_rhs1 (stmt);
2160e4b17023SJohn Marino 
2161e4b17023SJohn Marino   si = gsi_for_stmt (stmt);
2162e4b17023SJohn Marino   gimple_assign_set_rhs_from_tree (&si, other_op);
2163e4b17023SJohn Marino 
2164e4b17023SJohn Marino   /* We should not have reallocated STMT.  */
2165e4b17023SJohn Marino   gcc_assert (gsi_stmt (si) == stmt);
2166e4b17023SJohn Marino 
2167e4b17023SJohn Marino   update_stmt (stmt);
2168e4b17023SJohn Marino }
2169e4b17023SJohn Marino 
2170e4b17023SJohn Marino /* Reassociates the expression in that NAME1 and NAME2 are used so that they
2171e4b17023SJohn Marino    are combined in a single statement, and returns this statement.  */
2172e4b17023SJohn Marino 
2173e4b17023SJohn Marino static gimple
reassociate_to_the_same_stmt(tree name1,tree name2)2174e4b17023SJohn Marino reassociate_to_the_same_stmt (tree name1, tree name2)
2175e4b17023SJohn Marino {
2176e4b17023SJohn Marino   gimple stmt1, stmt2, root1, root2, s1, s2;
2177e4b17023SJohn Marino   gimple new_stmt, tmp_stmt;
2178e4b17023SJohn Marino   tree new_name, tmp_name, var, r1, r2;
2179e4b17023SJohn Marino   unsigned dist1, dist2;
2180e4b17023SJohn Marino   enum tree_code code;
2181e4b17023SJohn Marino   tree type = TREE_TYPE (name1);
2182e4b17023SJohn Marino   gimple_stmt_iterator bsi;
2183e4b17023SJohn Marino 
2184e4b17023SJohn Marino   stmt1 = find_use_stmt (&name1);
2185e4b17023SJohn Marino   stmt2 = find_use_stmt (&name2);
2186e4b17023SJohn Marino   root1 = find_associative_operation_root (stmt1, &dist1);
2187e4b17023SJohn Marino   root2 = find_associative_operation_root (stmt2, &dist2);
2188e4b17023SJohn Marino   code = gimple_assign_rhs_code (stmt1);
2189e4b17023SJohn Marino 
2190e4b17023SJohn Marino   gcc_assert (root1 && root2 && root1 == root2
2191e4b17023SJohn Marino 	      && code == gimple_assign_rhs_code (stmt2));
2192e4b17023SJohn Marino 
2193e4b17023SJohn Marino   /* Find the root of the nearest expression in that both NAME1 and NAME2
2194e4b17023SJohn Marino      are used.  */
2195e4b17023SJohn Marino   r1 = name1;
2196e4b17023SJohn Marino   s1 = stmt1;
2197e4b17023SJohn Marino   r2 = name2;
2198e4b17023SJohn Marino   s2 = stmt2;
2199e4b17023SJohn Marino 
2200e4b17023SJohn Marino   while (dist1 > dist2)
2201e4b17023SJohn Marino     {
2202e4b17023SJohn Marino       s1 = find_use_stmt (&r1);
2203e4b17023SJohn Marino       r1 = gimple_assign_lhs (s1);
2204e4b17023SJohn Marino       dist1--;
2205e4b17023SJohn Marino     }
2206e4b17023SJohn Marino   while (dist2 > dist1)
2207e4b17023SJohn Marino     {
2208e4b17023SJohn Marino       s2 = find_use_stmt (&r2);
2209e4b17023SJohn Marino       r2 = gimple_assign_lhs (s2);
2210e4b17023SJohn Marino       dist2--;
2211e4b17023SJohn Marino     }
2212e4b17023SJohn Marino 
2213e4b17023SJohn Marino   while (s1 != s2)
2214e4b17023SJohn Marino     {
2215e4b17023SJohn Marino       s1 = find_use_stmt (&r1);
2216e4b17023SJohn Marino       r1 = gimple_assign_lhs (s1);
2217e4b17023SJohn Marino       s2 = find_use_stmt (&r2);
2218e4b17023SJohn Marino       r2 = gimple_assign_lhs (s2);
2219e4b17023SJohn Marino     }
2220e4b17023SJohn Marino 
2221e4b17023SJohn Marino   /* Remove NAME1 and NAME2 from the statements in that they are used
2222e4b17023SJohn Marino      currently.  */
2223e4b17023SJohn Marino   remove_name_from_operation (stmt1, name1);
2224e4b17023SJohn Marino   remove_name_from_operation (stmt2, name2);
2225e4b17023SJohn Marino 
2226e4b17023SJohn Marino   /* Insert the new statement combining NAME1 and NAME2 before S1, and
2227e4b17023SJohn Marino      combine it with the rhs of S1.  */
2228e4b17023SJohn Marino   var = create_tmp_reg (type, "predreastmp");
2229e4b17023SJohn Marino   add_referenced_var (var);
2230e4b17023SJohn Marino   new_name = make_ssa_name (var, NULL);
2231e4b17023SJohn Marino   new_stmt = gimple_build_assign_with_ops (code, new_name, name1, name2);
2232e4b17023SJohn Marino 
2233e4b17023SJohn Marino   var = create_tmp_reg (type, "predreastmp");
2234e4b17023SJohn Marino   add_referenced_var (var);
2235e4b17023SJohn Marino   tmp_name = make_ssa_name (var, NULL);
2236e4b17023SJohn Marino 
2237e4b17023SJohn Marino   /* Rhs of S1 may now be either a binary expression with operation
2238e4b17023SJohn Marino      CODE, or gimple_val (in case that stmt1 == s1 or stmt2 == s1,
2239e4b17023SJohn Marino      so that name1 or name2 was removed from it).  */
2240e4b17023SJohn Marino   tmp_stmt = gimple_build_assign_with_ops (gimple_assign_rhs_code (s1),
2241e4b17023SJohn Marino 					   tmp_name,
2242e4b17023SJohn Marino 					   gimple_assign_rhs1 (s1),
2243e4b17023SJohn Marino 					   gimple_assign_rhs2 (s1));
2244e4b17023SJohn Marino 
2245e4b17023SJohn Marino   bsi = gsi_for_stmt (s1);
2246e4b17023SJohn Marino   gimple_assign_set_rhs_with_ops (&bsi, code, new_name, tmp_name);
2247e4b17023SJohn Marino   s1 = gsi_stmt (bsi);
2248e4b17023SJohn Marino   update_stmt (s1);
2249e4b17023SJohn Marino 
2250e4b17023SJohn Marino   gsi_insert_before (&bsi, new_stmt, GSI_SAME_STMT);
2251e4b17023SJohn Marino   gsi_insert_before (&bsi, tmp_stmt, GSI_SAME_STMT);
2252e4b17023SJohn Marino 
2253e4b17023SJohn Marino   return new_stmt;
2254e4b17023SJohn Marino }
2255e4b17023SJohn Marino 
2256e4b17023SJohn Marino /* Returns the statement that combines references R1 and R2.  In case R1
2257e4b17023SJohn Marino    and R2 are not used in the same statement, but they are used with an
2258e4b17023SJohn Marino    associative and commutative operation in the same expression, reassociate
2259e4b17023SJohn Marino    the expression so that they are used in the same statement.  */
2260e4b17023SJohn Marino 
2261e4b17023SJohn Marino static gimple
stmt_combining_refs(dref r1,dref r2)2262e4b17023SJohn Marino stmt_combining_refs (dref r1, dref r2)
2263e4b17023SJohn Marino {
2264e4b17023SJohn Marino   gimple stmt1, stmt2;
2265e4b17023SJohn Marino   tree name1 = name_for_ref (r1);
2266e4b17023SJohn Marino   tree name2 = name_for_ref (r2);
2267e4b17023SJohn Marino 
2268e4b17023SJohn Marino   stmt1 = find_use_stmt (&name1);
2269e4b17023SJohn Marino   stmt2 = find_use_stmt (&name2);
2270e4b17023SJohn Marino   if (stmt1 == stmt2)
2271e4b17023SJohn Marino     return stmt1;
2272e4b17023SJohn Marino 
2273e4b17023SJohn Marino   return reassociate_to_the_same_stmt (name1, name2);
2274e4b17023SJohn Marino }
2275e4b17023SJohn Marino 
2276e4b17023SJohn Marino /* Tries to combine chains CH1 and CH2 together.  If this succeeds, the
2277e4b17023SJohn Marino    description of the new chain is returned, otherwise we return NULL.  */
2278e4b17023SJohn Marino 
2279e4b17023SJohn Marino static chain_p
combine_chains(chain_p ch1,chain_p ch2)2280e4b17023SJohn Marino combine_chains (chain_p ch1, chain_p ch2)
2281e4b17023SJohn Marino {
2282e4b17023SJohn Marino   dref r1, r2, nw;
2283e4b17023SJohn Marino   enum tree_code op = ERROR_MARK;
2284e4b17023SJohn Marino   bool swap = false;
2285e4b17023SJohn Marino   chain_p new_chain;
2286e4b17023SJohn Marino   unsigned i;
2287e4b17023SJohn Marino   gimple root_stmt;
2288e4b17023SJohn Marino   tree rslt_type = NULL_TREE;
2289e4b17023SJohn Marino 
2290e4b17023SJohn Marino   if (ch1 == ch2)
2291e4b17023SJohn Marino     return NULL;
2292e4b17023SJohn Marino   if (ch1->length != ch2->length)
2293e4b17023SJohn Marino     return NULL;
2294e4b17023SJohn Marino 
2295e4b17023SJohn Marino   if (VEC_length (dref, ch1->refs) != VEC_length (dref, ch2->refs))
2296e4b17023SJohn Marino     return NULL;
2297e4b17023SJohn Marino 
2298e4b17023SJohn Marino   for (i = 0; (VEC_iterate (dref, ch1->refs, i, r1)
2299e4b17023SJohn Marino 	       && VEC_iterate (dref, ch2->refs, i, r2)); i++)
2300e4b17023SJohn Marino     {
2301e4b17023SJohn Marino       if (r1->distance != r2->distance)
2302e4b17023SJohn Marino 	return NULL;
2303e4b17023SJohn Marino 
2304e4b17023SJohn Marino       if (!combinable_refs_p (r1, r2, &op, &swap, &rslt_type))
2305e4b17023SJohn Marino 	return NULL;
2306e4b17023SJohn Marino     }
2307e4b17023SJohn Marino 
2308e4b17023SJohn Marino   if (swap)
2309e4b17023SJohn Marino     {
2310e4b17023SJohn Marino       chain_p tmp = ch1;
2311e4b17023SJohn Marino       ch1 = ch2;
2312e4b17023SJohn Marino       ch2 = tmp;
2313e4b17023SJohn Marino     }
2314e4b17023SJohn Marino 
2315e4b17023SJohn Marino   new_chain = XCNEW (struct chain);
2316e4b17023SJohn Marino   new_chain->type = CT_COMBINATION;
2317e4b17023SJohn Marino   new_chain->op = op;
2318e4b17023SJohn Marino   new_chain->ch1 = ch1;
2319e4b17023SJohn Marino   new_chain->ch2 = ch2;
2320e4b17023SJohn Marino   new_chain->rslt_type = rslt_type;
2321e4b17023SJohn Marino   new_chain->length = ch1->length;
2322e4b17023SJohn Marino 
2323e4b17023SJohn Marino   for (i = 0; (VEC_iterate (dref, ch1->refs, i, r1)
2324e4b17023SJohn Marino 	       && VEC_iterate (dref, ch2->refs, i, r2)); i++)
2325e4b17023SJohn Marino     {
2326e4b17023SJohn Marino       nw = XCNEW (struct dref_d);
2327e4b17023SJohn Marino       nw->stmt = stmt_combining_refs (r1, r2);
2328e4b17023SJohn Marino       nw->distance = r1->distance;
2329e4b17023SJohn Marino 
2330e4b17023SJohn Marino       VEC_safe_push (dref, heap, new_chain->refs, nw);
2331e4b17023SJohn Marino     }
2332e4b17023SJohn Marino 
2333e4b17023SJohn Marino   new_chain->has_max_use_after = false;
2334e4b17023SJohn Marino   root_stmt = get_chain_root (new_chain)->stmt;
2335e4b17023SJohn Marino   for (i = 1; VEC_iterate (dref, new_chain->refs, i, nw); i++)
2336e4b17023SJohn Marino     {
2337e4b17023SJohn Marino       if (nw->distance == new_chain->length
2338e4b17023SJohn Marino 	  && !stmt_dominates_stmt_p (nw->stmt, root_stmt))
2339e4b17023SJohn Marino 	{
2340e4b17023SJohn Marino 	  new_chain->has_max_use_after = true;
2341e4b17023SJohn Marino 	  break;
2342e4b17023SJohn Marino 	}
2343e4b17023SJohn Marino     }
2344e4b17023SJohn Marino 
2345e4b17023SJohn Marino   ch1->combined = true;
2346e4b17023SJohn Marino   ch2->combined = true;
2347e4b17023SJohn Marino   return new_chain;
2348e4b17023SJohn Marino }
2349e4b17023SJohn Marino 
2350e4b17023SJohn Marino /* Try to combine the CHAINS.  */
2351e4b17023SJohn Marino 
2352e4b17023SJohn Marino static void
try_combine_chains(VEC (chain_p,heap)** chains)2353e4b17023SJohn Marino try_combine_chains (VEC (chain_p, heap) **chains)
2354e4b17023SJohn Marino {
2355e4b17023SJohn Marino   unsigned i, j;
2356e4b17023SJohn Marino   chain_p ch1, ch2, cch;
2357e4b17023SJohn Marino   VEC (chain_p, heap) *worklist = NULL;
2358e4b17023SJohn Marino 
2359e4b17023SJohn Marino   FOR_EACH_VEC_ELT (chain_p, *chains, i, ch1)
2360e4b17023SJohn Marino     if (chain_can_be_combined_p (ch1))
2361e4b17023SJohn Marino       VEC_safe_push (chain_p, heap, worklist, ch1);
2362e4b17023SJohn Marino 
2363e4b17023SJohn Marino   while (!VEC_empty (chain_p, worklist))
2364e4b17023SJohn Marino     {
2365e4b17023SJohn Marino       ch1 = VEC_pop (chain_p, worklist);
2366e4b17023SJohn Marino       if (!chain_can_be_combined_p (ch1))
2367e4b17023SJohn Marino 	continue;
2368e4b17023SJohn Marino 
2369e4b17023SJohn Marino       FOR_EACH_VEC_ELT (chain_p, *chains, j, ch2)
2370e4b17023SJohn Marino 	{
2371e4b17023SJohn Marino 	  if (!chain_can_be_combined_p (ch2))
2372e4b17023SJohn Marino 	    continue;
2373e4b17023SJohn Marino 
2374e4b17023SJohn Marino 	  cch = combine_chains (ch1, ch2);
2375e4b17023SJohn Marino 	  if (cch)
2376e4b17023SJohn Marino 	    {
2377e4b17023SJohn Marino 	      VEC_safe_push (chain_p, heap, worklist, cch);
2378e4b17023SJohn Marino 	      VEC_safe_push (chain_p, heap, *chains, cch);
2379e4b17023SJohn Marino 	      break;
2380e4b17023SJohn Marino 	    }
2381e4b17023SJohn Marino 	}
2382e4b17023SJohn Marino     }
2383e4b17023SJohn Marino }
2384e4b17023SJohn Marino 
2385e4b17023SJohn Marino /* Prepare initializers for CHAIN in LOOP.  Returns false if this is
2386e4b17023SJohn Marino    impossible because one of these initializers may trap, true otherwise.  */
2387e4b17023SJohn Marino 
2388e4b17023SJohn Marino static bool
prepare_initializers_chain(struct loop * loop,chain_p chain)2389e4b17023SJohn Marino prepare_initializers_chain (struct loop *loop, chain_p chain)
2390e4b17023SJohn Marino {
2391e4b17023SJohn Marino   unsigned i, n = (chain->type == CT_INVARIANT) ? 1 : chain->length;
2392e4b17023SJohn Marino   struct data_reference *dr = get_chain_root (chain)->ref;
2393e4b17023SJohn Marino   tree init;
2394e4b17023SJohn Marino   gimple_seq stmts;
2395e4b17023SJohn Marino   dref laref;
2396e4b17023SJohn Marino   edge entry = loop_preheader_edge (loop);
2397e4b17023SJohn Marino 
2398e4b17023SJohn Marino   /* Find the initializers for the variables, and check that they cannot
2399e4b17023SJohn Marino      trap.  */
2400e4b17023SJohn Marino   chain->inits = VEC_alloc (tree, heap, n);
2401e4b17023SJohn Marino   for (i = 0; i < n; i++)
2402e4b17023SJohn Marino     VEC_quick_push (tree, chain->inits, NULL_TREE);
2403e4b17023SJohn Marino 
2404e4b17023SJohn Marino   /* If we have replaced some looparound phi nodes, use their initializers
2405e4b17023SJohn Marino      instead of creating our own.  */
2406e4b17023SJohn Marino   FOR_EACH_VEC_ELT (dref, chain->refs, i, laref)
2407e4b17023SJohn Marino     {
2408e4b17023SJohn Marino       if (gimple_code (laref->stmt) != GIMPLE_PHI)
2409e4b17023SJohn Marino 	continue;
2410e4b17023SJohn Marino 
2411e4b17023SJohn Marino       gcc_assert (laref->distance > 0);
2412e4b17023SJohn Marino       VEC_replace (tree, chain->inits, n - laref->distance,
2413e4b17023SJohn Marino 		   PHI_ARG_DEF_FROM_EDGE (laref->stmt, entry));
2414e4b17023SJohn Marino     }
2415e4b17023SJohn Marino 
2416e4b17023SJohn Marino   for (i = 0; i < n; i++)
2417e4b17023SJohn Marino     {
2418e4b17023SJohn Marino       if (VEC_index (tree, chain->inits, i) != NULL_TREE)
2419e4b17023SJohn Marino 	continue;
2420e4b17023SJohn Marino 
2421e4b17023SJohn Marino       init = ref_at_iteration (loop, DR_REF (dr), (int) i - n);
2422e4b17023SJohn Marino       if (!init)
2423e4b17023SJohn Marino 	return false;
2424e4b17023SJohn Marino 
2425e4b17023SJohn Marino       if (!chain->all_always_accessed && tree_could_trap_p (init))
2426e4b17023SJohn Marino 	return false;
2427e4b17023SJohn Marino 
2428e4b17023SJohn Marino       init = force_gimple_operand (init, &stmts, false, NULL_TREE);
2429e4b17023SJohn Marino       if (stmts)
2430e4b17023SJohn Marino 	gsi_insert_seq_on_edge_immediate (entry, stmts);
2431e4b17023SJohn Marino 
2432e4b17023SJohn Marino       VEC_replace (tree, chain->inits, i, init);
2433e4b17023SJohn Marino     }
2434e4b17023SJohn Marino 
2435e4b17023SJohn Marino   return true;
2436e4b17023SJohn Marino }
2437e4b17023SJohn Marino 
2438e4b17023SJohn Marino /* Prepare initializers for CHAINS in LOOP, and free chains that cannot
2439e4b17023SJohn Marino    be used because the initializers might trap.  */
2440e4b17023SJohn Marino 
2441e4b17023SJohn Marino static void
prepare_initializers(struct loop * loop,VEC (chain_p,heap)* chains)2442e4b17023SJohn Marino prepare_initializers (struct loop *loop, VEC (chain_p, heap) *chains)
2443e4b17023SJohn Marino {
2444e4b17023SJohn Marino   chain_p chain;
2445e4b17023SJohn Marino   unsigned i;
2446e4b17023SJohn Marino 
2447e4b17023SJohn Marino   for (i = 0; i < VEC_length (chain_p, chains); )
2448e4b17023SJohn Marino     {
2449e4b17023SJohn Marino       chain = VEC_index (chain_p, chains, i);
2450e4b17023SJohn Marino       if (prepare_initializers_chain (loop, chain))
2451e4b17023SJohn Marino 	i++;
2452e4b17023SJohn Marino       else
2453e4b17023SJohn Marino 	{
2454e4b17023SJohn Marino 	  release_chain (chain);
2455e4b17023SJohn Marino 	  VEC_unordered_remove (chain_p, chains, i);
2456e4b17023SJohn Marino 	}
2457e4b17023SJohn Marino     }
2458e4b17023SJohn Marino }
2459e4b17023SJohn Marino 
2460e4b17023SJohn Marino /* Performs predictive commoning for LOOP.  Returns true if LOOP was
2461e4b17023SJohn Marino    unrolled.  */
2462e4b17023SJohn Marino 
2463e4b17023SJohn Marino static bool
tree_predictive_commoning_loop(struct loop * loop)2464e4b17023SJohn Marino tree_predictive_commoning_loop (struct loop *loop)
2465e4b17023SJohn Marino {
2466e4b17023SJohn Marino   VEC (loop_p, heap) *loop_nest;
2467e4b17023SJohn Marino   VEC (data_reference_p, heap) *datarefs;
2468e4b17023SJohn Marino   VEC (ddr_p, heap) *dependences;
2469e4b17023SJohn Marino   struct component *components;
2470e4b17023SJohn Marino   VEC (chain_p, heap) *chains = NULL;
2471e4b17023SJohn Marino   unsigned unroll_factor;
2472e4b17023SJohn Marino   struct tree_niter_desc desc;
2473e4b17023SJohn Marino   bool unroll = false;
2474e4b17023SJohn Marino   edge exit;
2475e4b17023SJohn Marino   bitmap tmp_vars;
2476e4b17023SJohn Marino 
2477e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2478e4b17023SJohn Marino     fprintf (dump_file, "Processing loop %d\n",  loop->num);
2479e4b17023SJohn Marino 
2480e4b17023SJohn Marino   /* Find the data references and split them into components according to their
2481e4b17023SJohn Marino      dependence relations.  */
2482e4b17023SJohn Marino   datarefs = VEC_alloc (data_reference_p, heap, 10);
2483e4b17023SJohn Marino   dependences = VEC_alloc (ddr_p, heap, 10);
2484e4b17023SJohn Marino   loop_nest = VEC_alloc (loop_p, heap, 3);
2485e4b17023SJohn Marino   if (! compute_data_dependences_for_loop (loop, true, &loop_nest, &datarefs,
2486e4b17023SJohn Marino 					   &dependences))
2487e4b17023SJohn Marino     {
2488e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2489e4b17023SJohn Marino 	fprintf (dump_file, "Cannot analyze data dependencies\n");
2490e4b17023SJohn Marino       VEC_free (loop_p, heap, loop_nest);
2491e4b17023SJohn Marino       free_data_refs (datarefs);
2492e4b17023SJohn Marino       free_dependence_relations (dependences);
2493e4b17023SJohn Marino       return false;
2494e4b17023SJohn Marino     }
2495e4b17023SJohn Marino 
2496e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2497e4b17023SJohn Marino     dump_data_dependence_relations (dump_file, dependences);
2498e4b17023SJohn Marino 
2499e4b17023SJohn Marino   components = split_data_refs_to_components (loop, datarefs, dependences);
2500e4b17023SJohn Marino   VEC_free (loop_p, heap, loop_nest);
2501e4b17023SJohn Marino   free_dependence_relations (dependences);
2502e4b17023SJohn Marino   if (!components)
2503e4b17023SJohn Marino     {
2504e4b17023SJohn Marino       free_data_refs (datarefs);
2505e4b17023SJohn Marino       return false;
2506e4b17023SJohn Marino     }
2507e4b17023SJohn Marino 
2508e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2509e4b17023SJohn Marino     {
2510e4b17023SJohn Marino       fprintf (dump_file, "Initial state:\n\n");
2511e4b17023SJohn Marino       dump_components (dump_file, components);
2512e4b17023SJohn Marino     }
2513e4b17023SJohn Marino 
2514e4b17023SJohn Marino   /* Find the suitable components and split them into chains.  */
2515e4b17023SJohn Marino   components = filter_suitable_components (loop, components);
2516e4b17023SJohn Marino 
2517e4b17023SJohn Marino   tmp_vars = BITMAP_ALLOC (NULL);
2518e4b17023SJohn Marino   looparound_phis = BITMAP_ALLOC (NULL);
2519e4b17023SJohn Marino   determine_roots (loop, components, &chains);
2520e4b17023SJohn Marino   release_components (components);
2521e4b17023SJohn Marino 
2522e4b17023SJohn Marino   if (!chains)
2523e4b17023SJohn Marino     {
2524e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2525e4b17023SJohn Marino 	fprintf (dump_file,
2526e4b17023SJohn Marino 		 "Predictive commoning failed: no suitable chains\n");
2527e4b17023SJohn Marino       goto end;
2528e4b17023SJohn Marino     }
2529e4b17023SJohn Marino   prepare_initializers (loop, chains);
2530e4b17023SJohn Marino 
2531e4b17023SJohn Marino   /* Try to combine the chains that are always worked with together.  */
2532e4b17023SJohn Marino   try_combine_chains (&chains);
2533e4b17023SJohn Marino 
2534e4b17023SJohn Marino   if (dump_file && (dump_flags & TDF_DETAILS))
2535e4b17023SJohn Marino     {
2536e4b17023SJohn Marino       fprintf (dump_file, "Before commoning:\n\n");
2537e4b17023SJohn Marino       dump_chains (dump_file, chains);
2538e4b17023SJohn Marino     }
2539e4b17023SJohn Marino 
2540e4b17023SJohn Marino   /* Determine the unroll factor, and if the loop should be unrolled, ensure
2541e4b17023SJohn Marino      that its number of iterations is divisible by the factor.  */
2542e4b17023SJohn Marino   unroll_factor = determine_unroll_factor (chains);
2543e4b17023SJohn Marino   scev_reset ();
2544e4b17023SJohn Marino   unroll = (unroll_factor > 1
2545e4b17023SJohn Marino 	    && can_unroll_loop_p (loop, unroll_factor, &desc));
2546e4b17023SJohn Marino   exit = single_dom_exit (loop);
2547e4b17023SJohn Marino 
2548e4b17023SJohn Marino   /* Execute the predictive commoning transformations, and possibly unroll the
2549e4b17023SJohn Marino      loop.  */
2550e4b17023SJohn Marino   if (unroll)
2551e4b17023SJohn Marino     {
2552e4b17023SJohn Marino       struct epcc_data dta;
2553e4b17023SJohn Marino 
2554e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2555e4b17023SJohn Marino 	fprintf (dump_file, "Unrolling %u times.\n", unroll_factor);
2556e4b17023SJohn Marino 
2557e4b17023SJohn Marino       dta.chains = chains;
2558e4b17023SJohn Marino       dta.tmp_vars = tmp_vars;
2559e4b17023SJohn Marino 
2560e4b17023SJohn Marino       update_ssa (TODO_update_ssa_only_virtuals);
2561e4b17023SJohn Marino 
2562e4b17023SJohn Marino       /* Cfg manipulations performed in tree_transform_and_unroll_loop before
2563e4b17023SJohn Marino 	 execute_pred_commoning_cbck is called may cause phi nodes to be
2564e4b17023SJohn Marino 	 reallocated, which is a problem since CHAINS may point to these
2565e4b17023SJohn Marino 	 statements.  To fix this, we store the ssa names defined by the
2566e4b17023SJohn Marino 	 phi nodes here instead of the phi nodes themselves, and restore
2567e4b17023SJohn Marino 	 the phi nodes in execute_pred_commoning_cbck.  A bit hacky.  */
2568e4b17023SJohn Marino       replace_phis_by_defined_names (chains);
2569e4b17023SJohn Marino 
2570e4b17023SJohn Marino       tree_transform_and_unroll_loop (loop, unroll_factor, exit, &desc,
2571e4b17023SJohn Marino 				      execute_pred_commoning_cbck, &dta);
2572e4b17023SJohn Marino       eliminate_temp_copies (loop, tmp_vars);
2573e4b17023SJohn Marino     }
2574e4b17023SJohn Marino   else
2575e4b17023SJohn Marino     {
2576e4b17023SJohn Marino       if (dump_file && (dump_flags & TDF_DETAILS))
2577e4b17023SJohn Marino 	fprintf (dump_file,
2578e4b17023SJohn Marino 		 "Executing predictive commoning without unrolling.\n");
2579e4b17023SJohn Marino       execute_pred_commoning (loop, chains, tmp_vars);
2580e4b17023SJohn Marino     }
2581e4b17023SJohn Marino 
2582e4b17023SJohn Marino end: ;
2583e4b17023SJohn Marino   release_chains (chains);
2584e4b17023SJohn Marino   free_data_refs (datarefs);
2585e4b17023SJohn Marino   BITMAP_FREE (tmp_vars);
2586e4b17023SJohn Marino   BITMAP_FREE (looparound_phis);
2587e4b17023SJohn Marino 
2588e4b17023SJohn Marino   free_affine_expand_cache (&name_expansions);
2589e4b17023SJohn Marino 
2590e4b17023SJohn Marino   return unroll;
2591e4b17023SJohn Marino }
2592e4b17023SJohn Marino 
2593e4b17023SJohn Marino /* Runs predictive commoning.  */
2594e4b17023SJohn Marino 
2595e4b17023SJohn Marino unsigned
tree_predictive_commoning(void)2596e4b17023SJohn Marino tree_predictive_commoning (void)
2597e4b17023SJohn Marino {
2598e4b17023SJohn Marino   bool unrolled = false;
2599e4b17023SJohn Marino   struct loop *loop;
2600e4b17023SJohn Marino   loop_iterator li;
2601e4b17023SJohn Marino   unsigned ret = 0;
2602e4b17023SJohn Marino 
2603e4b17023SJohn Marino   initialize_original_copy_tables ();
2604e4b17023SJohn Marino   FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
2605e4b17023SJohn Marino     if (optimize_loop_for_speed_p (loop))
2606e4b17023SJohn Marino       {
2607e4b17023SJohn Marino 	unrolled |= tree_predictive_commoning_loop (loop);
2608e4b17023SJohn Marino       }
2609e4b17023SJohn Marino 
2610e4b17023SJohn Marino   if (unrolled)
2611e4b17023SJohn Marino     {
2612e4b17023SJohn Marino       scev_reset ();
2613e4b17023SJohn Marino       ret = TODO_cleanup_cfg;
2614e4b17023SJohn Marino     }
2615e4b17023SJohn Marino   free_original_copy_tables ();
2616e4b17023SJohn Marino 
2617e4b17023SJohn Marino   return ret;
2618e4b17023SJohn Marino }
2619