annotate gcc/tree-ssa-loop-split.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Loop splitting.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2015-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This file is part of GCC.
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
7 under the terms of the GNU General Public License as published by the
kono
parents:
diff changeset
8 Free Software Foundation; either version 3, or (at your option) any
kono
parents:
diff changeset
9 later version.
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 GCC is distributed in the hope that it will be useful, but WITHOUT
kono
parents:
diff changeset
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
14 for more details.
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
17 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
18 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 #include "config.h"
kono
parents:
diff changeset
21 #include "system.h"
kono
parents:
diff changeset
22 #include "coretypes.h"
kono
parents:
diff changeset
23 #include "backend.h"
kono
parents:
diff changeset
24 #include "tree.h"
kono
parents:
diff changeset
25 #include "gimple.h"
kono
parents:
diff changeset
26 #include "tree-pass.h"
kono
parents:
diff changeset
27 #include "ssa.h"
kono
parents:
diff changeset
28 #include "fold-const.h"
kono
parents:
diff changeset
29 #include "tree-cfg.h"
kono
parents:
diff changeset
30 #include "tree-ssa.h"
kono
parents:
diff changeset
31 #include "tree-ssa-loop-niter.h"
kono
parents:
diff changeset
32 #include "tree-ssa-loop.h"
kono
parents:
diff changeset
33 #include "tree-ssa-loop-manip.h"
kono
parents:
diff changeset
34 #include "tree-into-ssa.h"
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
35 #include "tree-inline.h"
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
36 #include "tree-cfgcleanup.h"
111
kono
parents:
diff changeset
37 #include "cfgloop.h"
kono
parents:
diff changeset
38 #include "tree-scalar-evolution.h"
kono
parents:
diff changeset
39 #include "gimple-iterator.h"
kono
parents:
diff changeset
40 #include "gimple-pretty-print.h"
kono
parents:
diff changeset
41 #include "cfghooks.h"
kono
parents:
diff changeset
42 #include "gimple-fold.h"
kono
parents:
diff changeset
43 #include "gimplify-me.h"
kono
parents:
diff changeset
44
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
45 /* This file implements two kinds of loop splitting.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
46
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
47 One transformation of loops like:
111
kono
parents:
diff changeset
48
kono
parents:
diff changeset
49 for (i = 0; i < 100; i++)
kono
parents:
diff changeset
50 {
kono
parents:
diff changeset
51 if (i < 50)
kono
parents:
diff changeset
52 A;
kono
parents:
diff changeset
53 else
kono
parents:
diff changeset
54 B;
kono
parents:
diff changeset
55 }
kono
parents:
diff changeset
56
kono
parents:
diff changeset
57 into:
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 for (i = 0; i < 50; i++)
kono
parents:
diff changeset
60 {
kono
parents:
diff changeset
61 A;
kono
parents:
diff changeset
62 }
kono
parents:
diff changeset
63 for (; i < 100; i++)
kono
parents:
diff changeset
64 {
kono
parents:
diff changeset
65 B;
kono
parents:
diff changeset
66 }
kono
parents:
diff changeset
67
kono
parents:
diff changeset
68 */
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 /* Return true when BB inside LOOP is a potential iteration space
kono
parents:
diff changeset
71 split point, i.e. ends with a condition like "IV < comp", which
kono
parents:
diff changeset
72 is true on one side of the iteration space and false on the other,
kono
parents:
diff changeset
73 and the split point can be computed. If so, also return the border
kono
parents:
diff changeset
74 point in *BORDER and the comparison induction variable in IV. */
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 static tree
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
77 split_at_bb_p (class loop *loop, basic_block bb, tree *border, affine_iv *iv)
111
kono
parents:
diff changeset
78 {
kono
parents:
diff changeset
79 gimple *last;
kono
parents:
diff changeset
80 gcond *stmt;
kono
parents:
diff changeset
81 affine_iv iv2;
kono
parents:
diff changeset
82
kono
parents:
diff changeset
83 /* BB must end in a simple conditional jump. */
kono
parents:
diff changeset
84 last = last_stmt (bb);
kono
parents:
diff changeset
85 if (!last || gimple_code (last) != GIMPLE_COND)
kono
parents:
diff changeset
86 return NULL_TREE;
kono
parents:
diff changeset
87 stmt = as_a <gcond *> (last);
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 enum tree_code code = gimple_cond_code (stmt);
kono
parents:
diff changeset
90
kono
parents:
diff changeset
91 /* Only handle relational comparisons, for equality and non-equality
kono
parents:
diff changeset
92 we'd have to split the loop into two loops and a middle statement. */
kono
parents:
diff changeset
93 switch (code)
kono
parents:
diff changeset
94 {
kono
parents:
diff changeset
95 case LT_EXPR:
kono
parents:
diff changeset
96 case LE_EXPR:
kono
parents:
diff changeset
97 case GT_EXPR:
kono
parents:
diff changeset
98 case GE_EXPR:
kono
parents:
diff changeset
99 break;
kono
parents:
diff changeset
100 default:
kono
parents:
diff changeset
101 return NULL_TREE;
kono
parents:
diff changeset
102 }
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 if (loop_exits_from_bb_p (loop, bb))
kono
parents:
diff changeset
105 return NULL_TREE;
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 tree op0 = gimple_cond_lhs (stmt);
kono
parents:
diff changeset
108 tree op1 = gimple_cond_rhs (stmt);
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
109 class loop *useloop = loop_containing_stmt (stmt);
111
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 if (!simple_iv (loop, useloop, op0, iv, false))
kono
parents:
diff changeset
112 return NULL_TREE;
kono
parents:
diff changeset
113 if (!simple_iv (loop, useloop, op1, &iv2, false))
kono
parents:
diff changeset
114 return NULL_TREE;
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 /* Make it so that the first argument of the condition is
kono
parents:
diff changeset
117 the looping one. */
kono
parents:
diff changeset
118 if (!integer_zerop (iv2.step))
kono
parents:
diff changeset
119 {
kono
parents:
diff changeset
120 std::swap (op0, op1);
kono
parents:
diff changeset
121 std::swap (*iv, iv2);
kono
parents:
diff changeset
122 code = swap_tree_comparison (code);
kono
parents:
diff changeset
123 gimple_cond_set_condition (stmt, code, op0, op1);
kono
parents:
diff changeset
124 update_stmt (stmt);
kono
parents:
diff changeset
125 }
kono
parents:
diff changeset
126 else if (integer_zerop (iv->step))
kono
parents:
diff changeset
127 return NULL_TREE;
kono
parents:
diff changeset
128 if (!integer_zerop (iv2.step))
kono
parents:
diff changeset
129 return NULL_TREE;
kono
parents:
diff changeset
130 if (!iv->no_overflow)
kono
parents:
diff changeset
131 return NULL_TREE;
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
134 {
kono
parents:
diff changeset
135 fprintf (dump_file, "Found potential split point: ");
kono
parents:
diff changeset
136 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
kono
parents:
diff changeset
137 fprintf (dump_file, " { ");
kono
parents:
diff changeset
138 print_generic_expr (dump_file, iv->base, TDF_SLIM);
kono
parents:
diff changeset
139 fprintf (dump_file, " + I*");
kono
parents:
diff changeset
140 print_generic_expr (dump_file, iv->step, TDF_SLIM);
kono
parents:
diff changeset
141 fprintf (dump_file, " } %s ", get_tree_code_name (code));
kono
parents:
diff changeset
142 print_generic_expr (dump_file, iv2.base, TDF_SLIM);
kono
parents:
diff changeset
143 fprintf (dump_file, "\n");
kono
parents:
diff changeset
144 }
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 *border = iv2.base;
kono
parents:
diff changeset
147 return op0;
kono
parents:
diff changeset
148 }
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 /* Given a GUARD conditional stmt inside LOOP, which we want to make always
kono
parents:
diff changeset
151 true or false depending on INITIAL_TRUE, and adjusted values NEXTVAL
kono
parents:
diff changeset
152 (a post-increment IV) and NEWBOUND (the comparator) adjust the loop
kono
parents:
diff changeset
153 exit test statement to loop back only if the GUARD statement will
kono
parents:
diff changeset
154 also be true/false in the next iteration. */
kono
parents:
diff changeset
155
kono
parents:
diff changeset
156 static void
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
157 patch_loop_exit (class loop *loop, gcond *guard, tree nextval, tree newbound,
111
kono
parents:
diff changeset
158 bool initial_true)
kono
parents:
diff changeset
159 {
kono
parents:
diff changeset
160 edge exit = single_exit (loop);
kono
parents:
diff changeset
161 gcond *stmt = as_a <gcond *> (last_stmt (exit->src));
kono
parents:
diff changeset
162 gimple_cond_set_condition (stmt, gimple_cond_code (guard),
kono
parents:
diff changeset
163 nextval, newbound);
kono
parents:
diff changeset
164 update_stmt (stmt);
kono
parents:
diff changeset
165
kono
parents:
diff changeset
166 edge stay = EDGE_SUCC (exit->src, EDGE_SUCC (exit->src, 0) == exit);
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 exit->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
kono
parents:
diff changeset
169 stay->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 if (initial_true)
kono
parents:
diff changeset
172 {
kono
parents:
diff changeset
173 exit->flags |= EDGE_FALSE_VALUE;
kono
parents:
diff changeset
174 stay->flags |= EDGE_TRUE_VALUE;
kono
parents:
diff changeset
175 }
kono
parents:
diff changeset
176 else
kono
parents:
diff changeset
177 {
kono
parents:
diff changeset
178 exit->flags |= EDGE_TRUE_VALUE;
kono
parents:
diff changeset
179 stay->flags |= EDGE_FALSE_VALUE;
kono
parents:
diff changeset
180 }
kono
parents:
diff changeset
181 }
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 /* Give an induction variable GUARD_IV, and its affine descriptor IV,
kono
parents:
diff changeset
184 find the loop phi node in LOOP defining it directly, or create
kono
parents:
diff changeset
185 such phi node. Return that phi node. */
kono
parents:
diff changeset
186
kono
parents:
diff changeset
187 static gphi *
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
188 find_or_create_guard_phi (class loop *loop, tree guard_iv, affine_iv * /*iv*/)
111
kono
parents:
diff changeset
189 {
kono
parents:
diff changeset
190 gimple *def = SSA_NAME_DEF_STMT (guard_iv);
kono
parents:
diff changeset
191 gphi *phi;
kono
parents:
diff changeset
192 if ((phi = dyn_cast <gphi *> (def))
kono
parents:
diff changeset
193 && gimple_bb (phi) == loop->header)
kono
parents:
diff changeset
194 return phi;
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 /* XXX Create the PHI instead. */
kono
parents:
diff changeset
197 return NULL;
kono
parents:
diff changeset
198 }
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 /* Returns true if the exit values of all loop phi nodes can be
kono
parents:
diff changeset
201 determined easily (i.e. that connect_loop_phis can determine them). */
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 static bool
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
204 easy_exit_values (class loop *loop)
111
kono
parents:
diff changeset
205 {
kono
parents:
diff changeset
206 edge exit = single_exit (loop);
kono
parents:
diff changeset
207 edge latch = loop_latch_edge (loop);
kono
parents:
diff changeset
208 gphi_iterator psi;
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 /* Currently we regard the exit values as easy if they are the same
kono
parents:
diff changeset
211 as the value over the backedge. Which is the case if the definition
kono
parents:
diff changeset
212 of the backedge value dominates the exit edge. */
kono
parents:
diff changeset
213 for (psi = gsi_start_phis (loop->header); !gsi_end_p (psi); gsi_next (&psi))
kono
parents:
diff changeset
214 {
kono
parents:
diff changeset
215 gphi *phi = psi.phi ();
kono
parents:
diff changeset
216 tree next = PHI_ARG_DEF_FROM_EDGE (phi, latch);
kono
parents:
diff changeset
217 basic_block bb;
kono
parents:
diff changeset
218 if (TREE_CODE (next) == SSA_NAME
kono
parents:
diff changeset
219 && (bb = gimple_bb (SSA_NAME_DEF_STMT (next)))
kono
parents:
diff changeset
220 && !dominated_by_p (CDI_DOMINATORS, exit->src, bb))
kono
parents:
diff changeset
221 return false;
kono
parents:
diff changeset
222 }
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 return true;
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 /* This function updates the SSA form after connect_loops made a new
kono
parents:
diff changeset
228 edge NEW_E leading from LOOP1 exit to LOOP2 (via in intermediate
kono
parents:
diff changeset
229 conditional). I.e. the second loop can now be entered either
kono
parents:
diff changeset
230 via the original entry or via NEW_E, so the entry values of LOOP2
kono
parents:
diff changeset
231 phi nodes are either the original ones or those at the exit
kono
parents:
diff changeset
232 of LOOP1. Insert new phi nodes in LOOP2 pre-header reflecting
kono
parents:
diff changeset
233 this. The loops need to fulfill easy_exit_values(). */
kono
parents:
diff changeset
234
kono
parents:
diff changeset
235 static void
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
236 connect_loop_phis (class loop *loop1, class loop *loop2, edge new_e)
111
kono
parents:
diff changeset
237 {
kono
parents:
diff changeset
238 basic_block rest = loop_preheader_edge (loop2)->src;
kono
parents:
diff changeset
239 gcc_assert (new_e->dest == rest);
kono
parents:
diff changeset
240 edge skip_first = EDGE_PRED (rest, EDGE_PRED (rest, 0) == new_e);
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242 edge firste = loop_preheader_edge (loop1);
kono
parents:
diff changeset
243 edge seconde = loop_preheader_edge (loop2);
kono
parents:
diff changeset
244 edge firstn = loop_latch_edge (loop1);
kono
parents:
diff changeset
245 gphi_iterator psi_first, psi_second;
kono
parents:
diff changeset
246 for (psi_first = gsi_start_phis (loop1->header),
kono
parents:
diff changeset
247 psi_second = gsi_start_phis (loop2->header);
kono
parents:
diff changeset
248 !gsi_end_p (psi_first);
kono
parents:
diff changeset
249 gsi_next (&psi_first), gsi_next (&psi_second))
kono
parents:
diff changeset
250 {
kono
parents:
diff changeset
251 tree init, next, new_init;
kono
parents:
diff changeset
252 use_operand_p op;
kono
parents:
diff changeset
253 gphi *phi_first = psi_first.phi ();
kono
parents:
diff changeset
254 gphi *phi_second = psi_second.phi ();
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 init = PHI_ARG_DEF_FROM_EDGE (phi_first, firste);
kono
parents:
diff changeset
257 next = PHI_ARG_DEF_FROM_EDGE (phi_first, firstn);
kono
parents:
diff changeset
258 op = PHI_ARG_DEF_PTR_FROM_EDGE (phi_second, seconde);
kono
parents:
diff changeset
259 gcc_assert (operand_equal_for_phi_arg_p (init, USE_FROM_PTR (op)));
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 /* Prefer using original variable as a base for the new ssa name.
kono
parents:
diff changeset
262 This is necessary for virtual ops, and useful in order to avoid
kono
parents:
diff changeset
263 losing debug info for real ops. */
kono
parents:
diff changeset
264 if (TREE_CODE (next) == SSA_NAME
kono
parents:
diff changeset
265 && useless_type_conversion_p (TREE_TYPE (next),
kono
parents:
diff changeset
266 TREE_TYPE (init)))
kono
parents:
diff changeset
267 new_init = copy_ssa_name (next);
kono
parents:
diff changeset
268 else if (TREE_CODE (init) == SSA_NAME
kono
parents:
diff changeset
269 && useless_type_conversion_p (TREE_TYPE (init),
kono
parents:
diff changeset
270 TREE_TYPE (next)))
kono
parents:
diff changeset
271 new_init = copy_ssa_name (init);
kono
parents:
diff changeset
272 else if (useless_type_conversion_p (TREE_TYPE (next),
kono
parents:
diff changeset
273 TREE_TYPE (init)))
kono
parents:
diff changeset
274 new_init = make_temp_ssa_name (TREE_TYPE (next), NULL,
kono
parents:
diff changeset
275 "unrinittmp");
kono
parents:
diff changeset
276 else
kono
parents:
diff changeset
277 new_init = make_temp_ssa_name (TREE_TYPE (init), NULL,
kono
parents:
diff changeset
278 "unrinittmp");
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 gphi * newphi = create_phi_node (new_init, rest);
kono
parents:
diff changeset
281 add_phi_arg (newphi, init, skip_first, UNKNOWN_LOCATION);
kono
parents:
diff changeset
282 add_phi_arg (newphi, next, new_e, UNKNOWN_LOCATION);
kono
parents:
diff changeset
283 SET_USE (op, new_init);
kono
parents:
diff changeset
284 }
kono
parents:
diff changeset
285 }
kono
parents:
diff changeset
286
kono
parents:
diff changeset
287 /* The two loops LOOP1 and LOOP2 were just created by loop versioning,
kono
parents:
diff changeset
288 they are still equivalent and placed in two arms of a diamond, like so:
kono
parents:
diff changeset
289
kono
parents:
diff changeset
290 .------if (cond)------.
kono
parents:
diff changeset
291 v v
kono
parents:
diff changeset
292 pre1 pre2
kono
parents:
diff changeset
293 | |
kono
parents:
diff changeset
294 .--->h1 h2<----.
kono
parents:
diff changeset
295 | | | |
kono
parents:
diff changeset
296 | ex1---. .---ex2 |
kono
parents:
diff changeset
297 | / | | \ |
kono
parents:
diff changeset
298 '---l1 X | l2---'
kono
parents:
diff changeset
299 | |
kono
parents:
diff changeset
300 | |
kono
parents:
diff changeset
301 '--->join<---'
kono
parents:
diff changeset
302
kono
parents:
diff changeset
303 This function transforms the program such that LOOP1 is conditionally
kono
parents:
diff changeset
304 falling through to LOOP2, or skipping it. This is done by splitting
kono
parents:
diff changeset
305 the ex1->join edge at X in the diagram above, and inserting a condition
kono
parents:
diff changeset
306 whose one arm goes to pre2, resulting in this situation:
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 .------if (cond)------.
kono
parents:
diff changeset
309 v v
kono
parents:
diff changeset
310 pre1 .---------->pre2
kono
parents:
diff changeset
311 | | |
kono
parents:
diff changeset
312 .--->h1 | h2<----.
kono
parents:
diff changeset
313 | | | | |
kono
parents:
diff changeset
314 | ex1---. | .---ex2 |
kono
parents:
diff changeset
315 | / v | | \ |
kono
parents:
diff changeset
316 '---l1 skip---' | l2---'
kono
parents:
diff changeset
317 | |
kono
parents:
diff changeset
318 | |
kono
parents:
diff changeset
319 '--->join<---'
kono
parents:
diff changeset
320
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 The condition used is the exit condition of LOOP1, which effectively means
kono
parents:
diff changeset
323 that when the first loop exits (for whatever reason) but the real original
kono
parents:
diff changeset
324 exit expression is still false the second loop will be entered.
kono
parents:
diff changeset
325 The function returns the new edge cond->pre2.
kono
parents:
diff changeset
326
kono
parents:
diff changeset
327 This doesn't update the SSA form, see connect_loop_phis for that. */
kono
parents:
diff changeset
328
kono
parents:
diff changeset
329 static edge
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
330 connect_loops (class loop *loop1, class loop *loop2)
111
kono
parents:
diff changeset
331 {
kono
parents:
diff changeset
332 edge exit = single_exit (loop1);
kono
parents:
diff changeset
333 basic_block skip_bb = split_edge (exit);
kono
parents:
diff changeset
334 gcond *skip_stmt;
kono
parents:
diff changeset
335 gimple_stmt_iterator gsi;
kono
parents:
diff changeset
336 edge new_e, skip_e;
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 gimple *stmt = last_stmt (exit->src);
kono
parents:
diff changeset
339 skip_stmt = gimple_build_cond (gimple_cond_code (stmt),
kono
parents:
diff changeset
340 gimple_cond_lhs (stmt),
kono
parents:
diff changeset
341 gimple_cond_rhs (stmt),
kono
parents:
diff changeset
342 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
343 gsi = gsi_last_bb (skip_bb);
kono
parents:
diff changeset
344 gsi_insert_after (&gsi, skip_stmt, GSI_NEW_STMT);
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 skip_e = EDGE_SUCC (skip_bb, 0);
kono
parents:
diff changeset
347 skip_e->flags &= ~EDGE_FALLTHRU;
kono
parents:
diff changeset
348 new_e = make_edge (skip_bb, loop_preheader_edge (loop2)->src, 0);
kono
parents:
diff changeset
349 if (exit->flags & EDGE_TRUE_VALUE)
kono
parents:
diff changeset
350 {
kono
parents:
diff changeset
351 skip_e->flags |= EDGE_TRUE_VALUE;
kono
parents:
diff changeset
352 new_e->flags |= EDGE_FALSE_VALUE;
kono
parents:
diff changeset
353 }
kono
parents:
diff changeset
354 else
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 skip_e->flags |= EDGE_FALSE_VALUE;
kono
parents:
diff changeset
357 new_e->flags |= EDGE_TRUE_VALUE;
kono
parents:
diff changeset
358 }
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 new_e->probability = profile_probability::likely ();
kono
parents:
diff changeset
361 skip_e->probability = new_e->probability.invert ();
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363 return new_e;
kono
parents:
diff changeset
364 }
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 /* This returns the new bound for iterations given the original iteration
kono
parents:
diff changeset
367 space in NITER, an arbitrary new bound BORDER, assumed to be some
kono
parents:
diff changeset
368 comparison value with a different IV, the initial value GUARD_INIT of
kono
parents:
diff changeset
369 that other IV, and the comparison code GUARD_CODE that compares
kono
parents:
diff changeset
370 that other IV with BORDER. We return an SSA name, and place any
kono
parents:
diff changeset
371 necessary statements for that computation into *STMTS.
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 For example for such a loop:
kono
parents:
diff changeset
374
kono
parents:
diff changeset
375 for (i = beg, j = guard_init; i < end; i++, j++)
kono
parents:
diff changeset
376 if (j < border) // this is supposed to be true/false
kono
parents:
diff changeset
377 ...
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 we want to return a new bound (on j) that makes the loop iterate
kono
parents:
diff changeset
380 as long as the condition j < border stays true. We also don't want
kono
parents:
diff changeset
381 to iterate more often than the original loop, so we have to introduce
kono
parents:
diff changeset
382 some cut-off as well (via min/max), effectively resulting in:
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 newend = min (end+guard_init-beg, border)
kono
parents:
diff changeset
385 for (i = beg; j = guard_init; j < newend; i++, j++)
kono
parents:
diff changeset
386 if (j < c)
kono
parents:
diff changeset
387 ...
kono
parents:
diff changeset
388
kono
parents:
diff changeset
389 Depending on the direction of the IVs and if the exit tests
kono
parents:
diff changeset
390 are strict or non-strict we need to use MIN or MAX,
kono
parents:
diff changeset
391 and add or subtract 1. This routine computes newend above. */
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 static tree
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
394 compute_new_first_bound (gimple_seq *stmts, class tree_niter_desc *niter,
111
kono
parents:
diff changeset
395 tree border,
kono
parents:
diff changeset
396 enum tree_code guard_code, tree guard_init)
kono
parents:
diff changeset
397 {
kono
parents:
diff changeset
398 /* The niter structure contains the after-increment IV, we need
kono
parents:
diff changeset
399 the loop-enter base, so subtract STEP once. */
kono
parents:
diff changeset
400 tree controlbase = force_gimple_operand (niter->control.base,
kono
parents:
diff changeset
401 stmts, true, NULL_TREE);
kono
parents:
diff changeset
402 tree controlstep = niter->control.step;
kono
parents:
diff changeset
403 tree enddiff;
kono
parents:
diff changeset
404 if (POINTER_TYPE_P (TREE_TYPE (controlbase)))
kono
parents:
diff changeset
405 {
kono
parents:
diff changeset
406 controlstep = gimple_build (stmts, NEGATE_EXPR,
kono
parents:
diff changeset
407 TREE_TYPE (controlstep), controlstep);
kono
parents:
diff changeset
408 enddiff = gimple_build (stmts, POINTER_PLUS_EXPR,
kono
parents:
diff changeset
409 TREE_TYPE (controlbase),
kono
parents:
diff changeset
410 controlbase, controlstep);
kono
parents:
diff changeset
411 }
kono
parents:
diff changeset
412 else
kono
parents:
diff changeset
413 enddiff = gimple_build (stmts, MINUS_EXPR,
kono
parents:
diff changeset
414 TREE_TYPE (controlbase),
kono
parents:
diff changeset
415 controlbase, controlstep);
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 /* Compute end-beg. */
kono
parents:
diff changeset
418 gimple_seq stmts2;
kono
parents:
diff changeset
419 tree end = force_gimple_operand (niter->bound, &stmts2,
kono
parents:
diff changeset
420 true, NULL_TREE);
kono
parents:
diff changeset
421 gimple_seq_add_seq_without_update (stmts, stmts2);
kono
parents:
diff changeset
422 if (POINTER_TYPE_P (TREE_TYPE (enddiff)))
kono
parents:
diff changeset
423 {
kono
parents:
diff changeset
424 tree tem = gimple_convert (stmts, sizetype, enddiff);
kono
parents:
diff changeset
425 tem = gimple_build (stmts, NEGATE_EXPR, sizetype, tem);
kono
parents:
diff changeset
426 enddiff = gimple_build (stmts, POINTER_PLUS_EXPR,
kono
parents:
diff changeset
427 TREE_TYPE (enddiff),
kono
parents:
diff changeset
428 end, tem);
kono
parents:
diff changeset
429 }
kono
parents:
diff changeset
430 else
kono
parents:
diff changeset
431 enddiff = gimple_build (stmts, MINUS_EXPR, TREE_TYPE (enddiff),
kono
parents:
diff changeset
432 end, enddiff);
kono
parents:
diff changeset
433
kono
parents:
diff changeset
434 /* Compute guard_init + (end-beg). */
kono
parents:
diff changeset
435 tree newbound;
kono
parents:
diff changeset
436 enddiff = gimple_convert (stmts, TREE_TYPE (guard_init), enddiff);
kono
parents:
diff changeset
437 if (POINTER_TYPE_P (TREE_TYPE (guard_init)))
kono
parents:
diff changeset
438 {
kono
parents:
diff changeset
439 enddiff = gimple_convert (stmts, sizetype, enddiff);
kono
parents:
diff changeset
440 newbound = gimple_build (stmts, POINTER_PLUS_EXPR,
kono
parents:
diff changeset
441 TREE_TYPE (guard_init),
kono
parents:
diff changeset
442 guard_init, enddiff);
kono
parents:
diff changeset
443 }
kono
parents:
diff changeset
444 else
kono
parents:
diff changeset
445 newbound = gimple_build (stmts, PLUS_EXPR, TREE_TYPE (guard_init),
kono
parents:
diff changeset
446 guard_init, enddiff);
kono
parents:
diff changeset
447
kono
parents:
diff changeset
448 /* Depending on the direction of the IVs the new bound for the first
kono
parents:
diff changeset
449 loop is the minimum or maximum of old bound and border.
kono
parents:
diff changeset
450 Also, if the guard condition isn't strictly less or greater,
kono
parents:
diff changeset
451 we need to adjust the bound. */
kono
parents:
diff changeset
452 int addbound = 0;
kono
parents:
diff changeset
453 enum tree_code minmax;
kono
parents:
diff changeset
454 if (niter->cmp == LT_EXPR)
kono
parents:
diff changeset
455 {
kono
parents:
diff changeset
456 /* GT and LE are the same, inverted. */
kono
parents:
diff changeset
457 if (guard_code == GT_EXPR || guard_code == LE_EXPR)
kono
parents:
diff changeset
458 addbound = -1;
kono
parents:
diff changeset
459 minmax = MIN_EXPR;
kono
parents:
diff changeset
460 }
kono
parents:
diff changeset
461 else
kono
parents:
diff changeset
462 {
kono
parents:
diff changeset
463 gcc_assert (niter->cmp == GT_EXPR);
kono
parents:
diff changeset
464 if (guard_code == GE_EXPR || guard_code == LT_EXPR)
kono
parents:
diff changeset
465 addbound = 1;
kono
parents:
diff changeset
466 minmax = MAX_EXPR;
kono
parents:
diff changeset
467 }
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 if (addbound)
kono
parents:
diff changeset
470 {
kono
parents:
diff changeset
471 tree type2 = TREE_TYPE (newbound);
kono
parents:
diff changeset
472 if (POINTER_TYPE_P (type2))
kono
parents:
diff changeset
473 type2 = sizetype;
kono
parents:
diff changeset
474 newbound = gimple_build (stmts,
kono
parents:
diff changeset
475 POINTER_TYPE_P (TREE_TYPE (newbound))
kono
parents:
diff changeset
476 ? POINTER_PLUS_EXPR : PLUS_EXPR,
kono
parents:
diff changeset
477 TREE_TYPE (newbound),
kono
parents:
diff changeset
478 newbound,
kono
parents:
diff changeset
479 build_int_cst (type2, addbound));
kono
parents:
diff changeset
480 }
kono
parents:
diff changeset
481
kono
parents:
diff changeset
482 tree newend = gimple_build (stmts, minmax, TREE_TYPE (border),
kono
parents:
diff changeset
483 border, newbound);
kono
parents:
diff changeset
484 return newend;
kono
parents:
diff changeset
485 }
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 /* Checks if LOOP contains an conditional block whose condition
kono
parents:
diff changeset
488 depends on which side in the iteration space it is, and if so
kono
parents:
diff changeset
489 splits the iteration space into two loops. Returns true if the
kono
parents:
diff changeset
490 loop was split. NITER must contain the iteration descriptor for the
kono
parents:
diff changeset
491 single exit of LOOP. */
kono
parents:
diff changeset
492
kono
parents:
diff changeset
493 static bool
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
494 split_loop (class loop *loop1)
111
kono
parents:
diff changeset
495 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
496 class tree_niter_desc niter;
111
kono
parents:
diff changeset
497 basic_block *bbs;
kono
parents:
diff changeset
498 unsigned i;
kono
parents:
diff changeset
499 bool changed = false;
kono
parents:
diff changeset
500 tree guard_iv;
kono
parents:
diff changeset
501 tree border = NULL_TREE;
kono
parents:
diff changeset
502 affine_iv iv;
kono
parents:
diff changeset
503
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
504 if (!single_exit (loop1)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
505 /* ??? We could handle non-empty latches when we split the latch edge
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
506 (not the exit edge), and put the new exit condition in the new block.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
507 OTOH this executes some code unconditionally that might have been
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
508 skipped by the original exit before. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
509 || !empty_block_p (loop1->latch)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
510 || !easy_exit_values (loop1)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
511 || !number_of_iterations_exit (loop1, single_exit (loop1), &niter,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
512 false, true)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
513 || niter.cmp == ERROR_MARK
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
514 /* We can't yet handle loops controlled by a != predicate. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
515 || niter.cmp == NE_EXPR)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
516 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
517
111
kono
parents:
diff changeset
518 bbs = get_loop_body (loop1);
kono
parents:
diff changeset
519
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
520 if (!can_copy_bbs_p (bbs, loop1->num_nodes))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
521 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
522 free (bbs);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
523 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
524 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
525
111
kono
parents:
diff changeset
526 /* Find a splitting opportunity. */
kono
parents:
diff changeset
527 for (i = 0; i < loop1->num_nodes; i++)
kono
parents:
diff changeset
528 if ((guard_iv = split_at_bb_p (loop1, bbs[i], &border, &iv)))
kono
parents:
diff changeset
529 {
kono
parents:
diff changeset
530 /* Handling opposite steps is not implemented yet. Neither
kono
parents:
diff changeset
531 is handling different step sizes. */
kono
parents:
diff changeset
532 if ((tree_int_cst_sign_bit (iv.step)
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
533 != tree_int_cst_sign_bit (niter.control.step))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
534 || !tree_int_cst_equal (iv.step, niter.control.step))
111
kono
parents:
diff changeset
535 continue;
kono
parents:
diff changeset
536
kono
parents:
diff changeset
537 /* Find a loop PHI node that defines guard_iv directly,
kono
parents:
diff changeset
538 or create one doing that. */
kono
parents:
diff changeset
539 gphi *phi = find_or_create_guard_phi (loop1, guard_iv, &iv);
kono
parents:
diff changeset
540 if (!phi)
kono
parents:
diff changeset
541 continue;
kono
parents:
diff changeset
542 gcond *guard_stmt = as_a<gcond *> (last_stmt (bbs[i]));
kono
parents:
diff changeset
543 tree guard_init = PHI_ARG_DEF_FROM_EDGE (phi,
kono
parents:
diff changeset
544 loop_preheader_edge (loop1));
kono
parents:
diff changeset
545 enum tree_code guard_code = gimple_cond_code (guard_stmt);
kono
parents:
diff changeset
546
kono
parents:
diff changeset
547 /* Loop splitting is implemented by versioning the loop, placing
kono
parents:
diff changeset
548 the new loop after the old loop, make the first loop iterate
kono
parents:
diff changeset
549 as long as the conditional stays true (or false) and let the
kono
parents:
diff changeset
550 second (new) loop handle the rest of the iterations.
kono
parents:
diff changeset
551
kono
parents:
diff changeset
552 First we need to determine if the condition will start being true
kono
parents:
diff changeset
553 or false in the first loop. */
kono
parents:
diff changeset
554 bool initial_true;
kono
parents:
diff changeset
555 switch (guard_code)
kono
parents:
diff changeset
556 {
kono
parents:
diff changeset
557 case LT_EXPR:
kono
parents:
diff changeset
558 case LE_EXPR:
kono
parents:
diff changeset
559 initial_true = !tree_int_cst_sign_bit (iv.step);
kono
parents:
diff changeset
560 break;
kono
parents:
diff changeset
561 case GT_EXPR:
kono
parents:
diff changeset
562 case GE_EXPR:
kono
parents:
diff changeset
563 initial_true = tree_int_cst_sign_bit (iv.step);
kono
parents:
diff changeset
564 break;
kono
parents:
diff changeset
565 default:
kono
parents:
diff changeset
566 gcc_unreachable ();
kono
parents:
diff changeset
567 }
kono
parents:
diff changeset
568
kono
parents:
diff changeset
569 /* Build a condition that will skip the first loop when the
kono
parents:
diff changeset
570 guard condition won't ever be true (or false). */
kono
parents:
diff changeset
571 gimple_seq stmts2;
kono
parents:
diff changeset
572 border = force_gimple_operand (border, &stmts2, true, NULL_TREE);
kono
parents:
diff changeset
573 if (stmts2)
kono
parents:
diff changeset
574 gsi_insert_seq_on_edge_immediate (loop_preheader_edge (loop1),
kono
parents:
diff changeset
575 stmts2);
kono
parents:
diff changeset
576 tree cond = build2 (guard_code, boolean_type_node, guard_init, border);
kono
parents:
diff changeset
577 if (!initial_true)
kono
parents:
diff changeset
578 cond = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, cond);
kono
parents:
diff changeset
579
kono
parents:
diff changeset
580 /* Now version the loop, placing loop2 after loop1 connecting
kono
parents:
diff changeset
581 them, and fix up SSA form for that. */
kono
parents:
diff changeset
582 initialize_original_copy_tables ();
kono
parents:
diff changeset
583 basic_block cond_bb;
kono
parents:
diff changeset
584
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
585 class loop *loop2 = loop_version (loop1, cond, &cond_bb,
111
kono
parents:
diff changeset
586 profile_probability::always (),
kono
parents:
diff changeset
587 profile_probability::always (),
kono
parents:
diff changeset
588 profile_probability::always (),
kono
parents:
diff changeset
589 profile_probability::always (),
kono
parents:
diff changeset
590 true);
kono
parents:
diff changeset
591 gcc_assert (loop2);
kono
parents:
diff changeset
592 update_ssa (TODO_update_ssa);
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 edge new_e = connect_loops (loop1, loop2);
kono
parents:
diff changeset
595 connect_loop_phis (loop1, loop2, new_e);
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 /* The iterations of the second loop is now already
kono
parents:
diff changeset
598 exactly those that the first loop didn't do, but the
kono
parents:
diff changeset
599 iteration space of the first loop is still the original one.
kono
parents:
diff changeset
600 Compute the new bound for the guarding IV and patch the
kono
parents:
diff changeset
601 loop exit to use it instead of original IV and bound. */
kono
parents:
diff changeset
602 gimple_seq stmts = NULL;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
603 tree newend = compute_new_first_bound (&stmts, &niter, border,
111
kono
parents:
diff changeset
604 guard_code, guard_init);
kono
parents:
diff changeset
605 if (stmts)
kono
parents:
diff changeset
606 gsi_insert_seq_on_edge_immediate (loop_preheader_edge (loop1),
kono
parents:
diff changeset
607 stmts);
kono
parents:
diff changeset
608 tree guard_next = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (loop1));
kono
parents:
diff changeset
609 patch_loop_exit (loop1, guard_stmt, guard_next, newend, initial_true);
kono
parents:
diff changeset
610
kono
parents:
diff changeset
611 /* Finally patch out the two copies of the condition to be always
kono
parents:
diff changeset
612 true/false (or opposite). */
kono
parents:
diff changeset
613 gcond *force_true = as_a<gcond *> (last_stmt (bbs[i]));
kono
parents:
diff changeset
614 gcond *force_false = as_a<gcond *> (last_stmt (get_bb_copy (bbs[i])));
kono
parents:
diff changeset
615 if (!initial_true)
kono
parents:
diff changeset
616 std::swap (force_true, force_false);
kono
parents:
diff changeset
617 gimple_cond_make_true (force_true);
kono
parents:
diff changeset
618 gimple_cond_make_false (force_false);
kono
parents:
diff changeset
619 update_stmt (force_true);
kono
parents:
diff changeset
620 update_stmt (force_false);
kono
parents:
diff changeset
621
kono
parents:
diff changeset
622 free_original_copy_tables ();
kono
parents:
diff changeset
623
kono
parents:
diff changeset
624 /* We destroyed LCSSA form above. Eventually we might be able
kono
parents:
diff changeset
625 to fix it on the fly, for now simply punt and use the helper. */
kono
parents:
diff changeset
626 rewrite_into_loop_closed_ssa_1 (NULL, 0, SSA_OP_USE, loop1);
kono
parents:
diff changeset
627
kono
parents:
diff changeset
628 changed = true;
kono
parents:
diff changeset
629 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
630 fprintf (dump_file, ";; Loop split.\n");
kono
parents:
diff changeset
631
kono
parents:
diff changeset
632 /* Only deal with the first opportunity. */
kono
parents:
diff changeset
633 break;
kono
parents:
diff changeset
634 }
kono
parents:
diff changeset
635
kono
parents:
diff changeset
636 free (bbs);
kono
parents:
diff changeset
637 return changed;
kono
parents:
diff changeset
638 }
kono
parents:
diff changeset
639
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
640 /* Another transformation of loops like:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
641
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
642 for (i = INIT (); CHECK (i); i = NEXT ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
643 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
644 if (expr (a_1, a_2, ..., a_n)) // expr is pure
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
645 a_j = ...; // change at least one a_j
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
646 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
647 S; // not change any a_j
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
648 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
649
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
650 into:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
651
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
652 for (i = INIT (); CHECK (i); i = NEXT ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
653 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
654 if (expr (a_1, a_2, ..., a_n))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
655 a_j = ...;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
656 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
657 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
658 S;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
659 i = NEXT ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
660 break;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
661 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
662 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
663
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
664 for (; CHECK (i); i = NEXT ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
665 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
666 S;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
667 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
668
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
669 */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
670
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
671 /* Data structure to hold temporary information during loop split upon
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
672 semi-invariant conditional statement. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
673 class split_info {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
674 public:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
675 /* Array of all basic blocks in a loop, returned by get_loop_body(). */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
676 basic_block *bbs;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
677
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
678 /* All memory store/clobber statements in a loop. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
679 auto_vec<gimple *> memory_stores;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
680
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
681 /* Whether above memory stores vector has been filled. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
682 int need_init;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
683
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
684 /* Control dependencies of basic blocks in a loop. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
685 auto_vec<hash_set<basic_block> *> control_deps;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
686
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
687 split_info () : bbs (NULL), need_init (true) { }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
688
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
689 ~split_info ()
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
690 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
691 if (bbs)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
692 free (bbs);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
693
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
694 for (unsigned i = 0; i < control_deps.length (); i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
695 delete control_deps[i];
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
696 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
697 };
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
698
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
699 /* Find all statements with memory-write effect in LOOP, including memory
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
700 store and non-pure function call, and keep those in a vector. This work
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
701 is only done one time, for the vector should be constant during analysis
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
702 stage of semi-invariant condition. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
703
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
704 static void
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
705 find_vdef_in_loop (struct loop *loop)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
706 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
707 split_info *info = (split_info *) loop->aux;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
708 gphi *vphi = get_virtual_phi (loop->header);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
709
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
710 /* Indicate memory store vector has been filled. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
711 info->need_init = false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
712
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
713 /* If loop contains memory operation, there must be a virtual PHI node in
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
714 loop header basic block. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
715 if (vphi == NULL)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
716 return;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
717
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
718 /* All virtual SSA names inside the loop are connected to be a cyclic
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
719 graph via virtual PHI nodes. The virtual PHI node in loop header just
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
720 links the first and the last virtual SSA names, by using the last as
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
721 PHI operand to define the first. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
722 const edge latch = loop_latch_edge (loop);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
723 const tree first = gimple_phi_result (vphi);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
724 const tree last = PHI_ARG_DEF_FROM_EDGE (vphi, latch);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
725
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
726 /* The virtual SSA cyclic graph might consist of only one SSA name, who
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
727 is defined by itself.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
728
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
729 .MEM_1 = PHI <.MEM_2(loop entry edge), .MEM_1(latch edge)>
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
730
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
731 This means the loop contains only memory loads, so we can skip it. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
732 if (first == last)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
733 return;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
734
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
735 auto_vec<gimple *> other_stores;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
736 auto_vec<tree> worklist;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
737 auto_bitmap visited;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
738
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
739 bitmap_set_bit (visited, SSA_NAME_VERSION (first));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
740 bitmap_set_bit (visited, SSA_NAME_VERSION (last));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
741 worklist.safe_push (last);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
742
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
743 do
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
744 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
745 tree vuse = worklist.pop ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
746 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
747
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
748 /* We mark the first and last SSA names as visited at the beginning,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
749 and reversely start the process from the last SSA name towards the
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
750 first, which ensures that this do-while will not touch SSA names
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
751 defined outside the loop. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
752 gcc_assert (gimple_bb (stmt)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
753 && flow_bb_inside_loop_p (loop, gimple_bb (stmt)));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
754
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
755 if (gimple_code (stmt) == GIMPLE_PHI)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
756 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
757 gphi *phi = as_a <gphi *> (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
758
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
759 for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
760 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
761 tree arg = gimple_phi_arg_def (stmt, i);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
762
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
763 if (bitmap_set_bit (visited, SSA_NAME_VERSION (arg)))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
764 worklist.safe_push (arg);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
765 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
766 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
767 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
768 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
769 tree prev = gimple_vuse (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
770
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
771 /* Non-pure call statement is conservatively assumed to impact all
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
772 memory locations. So place call statements ahead of other memory
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
773 stores in the vector with an idea of of using them as shortcut
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
774 terminators to memory alias analysis. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
775 if (gimple_code (stmt) == GIMPLE_CALL)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
776 info->memory_stores.safe_push (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
777 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
778 other_stores.safe_push (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
779
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
780 if (bitmap_set_bit (visited, SSA_NAME_VERSION (prev)))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
781 worklist.safe_push (prev);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
782 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
783 } while (!worklist.is_empty ());
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
784
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
785 info->memory_stores.safe_splice (other_stores);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
786 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
787
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
788 /* Two basic blocks have equivalent control dependency if one dominates to
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
789 the other, and it is post-dominated by the latter. Given a basic block
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
790 BB in LOOP, find farest equivalent dominating basic block. For BB, there
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
791 is a constraint that BB does not post-dominate loop header of LOOP, this
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
792 means BB is control-dependent on at least one basic block in LOOP. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
793
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
794 static basic_block
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
795 get_control_equiv_head_block (struct loop *loop, basic_block bb)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
796 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
797 while (!bb->aux)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
798 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
799 basic_block dom_bb = get_immediate_dominator (CDI_DOMINATORS, bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
800
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
801 gcc_checking_assert (dom_bb && flow_bb_inside_loop_p (loop, dom_bb));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
802
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
803 if (!dominated_by_p (CDI_POST_DOMINATORS, dom_bb, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
804 break;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
805
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
806 bb = dom_bb;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
807 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
808 return bb;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
809 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
810
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
811 /* Given a BB in LOOP, find out all basic blocks in LOOP that BB is control-
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
812 dependent on. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
813
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
814 static hash_set<basic_block> *
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
815 find_control_dep_blocks (struct loop *loop, basic_block bb)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
816 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
817 /* BB has same control dependency as loop header, then it is not control-
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
818 dependent on any basic block in LOOP. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
819 if (dominated_by_p (CDI_POST_DOMINATORS, loop->header, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
820 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
821
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
822 basic_block equiv_head = get_control_equiv_head_block (loop, bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
823
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
824 if (equiv_head->aux)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
825 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
826 /* There is a basic block containing control dependency equivalent
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
827 to BB. No need to recompute that, and also set this information
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
828 to other equivalent basic blocks. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
829 for (; bb != equiv_head;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
830 bb = get_immediate_dominator (CDI_DOMINATORS, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
831 bb->aux = equiv_head->aux;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
832 return (hash_set<basic_block> *) equiv_head->aux;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
833 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
834
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
835 /* A basic block X is control-dependent on another Y iff there exists
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
836 a path from X to Y, in which every basic block other than X and Y
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
837 is post-dominated by Y, but X is not post-dominated by Y.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
838
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
839 According to this rule, traverse basic blocks in the loop backwards
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
840 starting from BB, if a basic block is post-dominated by BB, extend
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
841 current post-dominating path to this block, otherwise it is another
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
842 one that BB is control-dependent on. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
843
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
844 auto_vec<basic_block> pdom_worklist;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
845 hash_set<basic_block> pdom_visited;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
846 hash_set<basic_block> *dep_bbs = new hash_set<basic_block>;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
847
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
848 pdom_worklist.safe_push (equiv_head);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
849
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
850 do
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
851 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
852 basic_block pdom_bb = pdom_worklist.pop ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
853 edge_iterator ei;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
854 edge e;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
855
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
856 if (pdom_visited.add (pdom_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
857 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
858
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
859 FOR_EACH_EDGE (e, ei, pdom_bb->preds)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
860 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
861 basic_block pred_bb = e->src;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
862
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
863 if (!dominated_by_p (CDI_POST_DOMINATORS, pred_bb, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
864 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
865 dep_bbs->add (pred_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
866 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
867 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
868
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
869 pred_bb = get_control_equiv_head_block (loop, pred_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
870
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
871 if (pdom_visited.contains (pred_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
872 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
873
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
874 if (!pred_bb->aux)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
875 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
876 pdom_worklist.safe_push (pred_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
877 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
878 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
879
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
880 /* If control dependency of basic block is available, fast extend
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
881 post-dominating path using the information instead of advancing
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
882 forward step-by-step. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
883 hash_set<basic_block> *pred_dep_bbs
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
884 = (hash_set<basic_block> *) pred_bb->aux;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
885
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
886 for (hash_set<basic_block>::iterator iter = pred_dep_bbs->begin ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
887 iter != pred_dep_bbs->end (); ++iter)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
888 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
889 basic_block pred_dep_bb = *iter;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
890
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
891 /* Basic blocks can either be in control dependency of BB, or
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
892 must be post-dominated by BB, if so, extend the path from
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
893 these basic blocks. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
894 if (!dominated_by_p (CDI_POST_DOMINATORS, pred_dep_bb, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
895 dep_bbs->add (pred_dep_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
896 else if (!pdom_visited.contains (pred_dep_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
897 pdom_worklist.safe_push (pred_dep_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
898 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
899 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
900 } while (!pdom_worklist.is_empty ());
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
901
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
902 /* Record computed control dependencies in loop so that we can reach them
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
903 when reclaiming resources. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
904 ((split_info *) loop->aux)->control_deps.safe_push (dep_bbs);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
905
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
906 /* Associate control dependence with related equivalent basic blocks. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
907 for (equiv_head->aux = dep_bbs; bb != equiv_head;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
908 bb = get_immediate_dominator (CDI_DOMINATORS, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
909 bb->aux = dep_bbs;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
910
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
911 return dep_bbs;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
912 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
913
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
914 /* Forward declaration */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
915
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
916 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
917 stmt_semi_invariant_p_1 (struct loop *loop, gimple *stmt,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
918 const_basic_block skip_head,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
919 hash_map<gimple *, bool> &stmt_stat);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
920
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
921 /* Given STMT, memory load or pure call statement, check whether it is impacted
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
922 by some memory store in LOOP, excluding trace starting from SKIP_HEAD (the
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
923 trace is composed of SKIP_HEAD and those basic block dominated by it, always
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
924 corresponds to one branch of a conditional statement). If SKIP_HEAD is
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
925 NULL, all basic blocks of LOOP are checked. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
926
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
927 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
928 vuse_semi_invariant_p (struct loop *loop, gimple *stmt,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
929 const_basic_block skip_head)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
930 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
931 split_info *info = (split_info *) loop->aux;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
932 tree rhs = NULL_TREE;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
933 ao_ref ref;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
934 gimple *store;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
935 unsigned i;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
936
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
937 /* Collect memory store/clobber statements if haven't done that. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
938 if (info->need_init)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
939 find_vdef_in_loop (loop);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
940
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
941 if (is_gimple_assign (stmt))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
942 rhs = gimple_assign_rhs1 (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
943
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
944 ao_ref_init (&ref, rhs);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
945
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
946 FOR_EACH_VEC_ELT (info->memory_stores, i, store)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
947 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
948 /* Skip basic blocks dominated by SKIP_HEAD, if non-NULL. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
949 if (skip_head
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
950 && dominated_by_p (CDI_DOMINATORS, gimple_bb (store), skip_head))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
951 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
952
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
953 if (!ref.ref || stmt_may_clobber_ref_p_1 (store, &ref))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
954 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
955 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
956
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
957 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
958 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
959
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
960 /* Suppose one condition branch, led by SKIP_HEAD, is not executed since
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
961 certain iteration of LOOP, check whether an SSA name (NAME) remains
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
962 unchanged in next iteration. We call this characteristic semi-
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
963 invariantness. SKIP_HEAD might be NULL, if so, nothing excluded, all basic
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
964 blocks and control flows in the loop will be considered. Semi-invariant
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
965 state of checked statement is cached in hash map STMT_STAT to avoid
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
966 redundant computation in possible following re-check. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
967
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
968 static inline bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
969 ssa_semi_invariant_p (struct loop *loop, tree name,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
970 const_basic_block skip_head,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
971 hash_map<gimple *, bool> &stmt_stat)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
972 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
973 gimple *def = SSA_NAME_DEF_STMT (name);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
974 const_basic_block def_bb = gimple_bb (def);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
975
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
976 /* An SSA name defined outside loop is definitely semi-invariant. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
977 if (!def_bb || !flow_bb_inside_loop_p (loop, def_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
978 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
979
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
980 return stmt_semi_invariant_p_1 (loop, def, skip_head, stmt_stat);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
981 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
982
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
983 /* Check whether a loop iteration PHI node (LOOP_PHI) defines a value that is
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
984 semi-invariant in LOOP. Basic blocks dominated by SKIP_HEAD (if non-NULL),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
985 are excluded from LOOP. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
986
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
987 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
988 loop_iter_phi_semi_invariant_p (struct loop *loop, gphi *loop_phi,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
989 const_basic_block skip_head)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
990 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
991 const_edge latch = loop_latch_edge (loop);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
992 tree name = gimple_phi_result (loop_phi);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
993 tree from = PHI_ARG_DEF_FROM_EDGE (loop_phi, latch);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
994
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
995 gcc_checking_assert (from);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
996
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
997 /* Loop iteration PHI node locates in loop header, and it has two source
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
998 operands, one is an initial value coming from outside the loop, the other
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
999 is a value through latch of the loop, which is derived in last iteration,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1000 we call the latter latch value. From the PHI node to definition of latch
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1001 value, if excluding branch trace starting from SKIP_HEAD, except copy-
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1002 assignment or likewise, there is no other kind of value redefinition, SSA
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1003 name defined by the PHI node is semi-invariant.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1004
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1005 loop entry
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1006 | .--- latch ---.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1007 | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1008 v v |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1009 x_1 = PHI <x_0, x_3> |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1010 | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1011 v |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1012 .------- if (cond) -------. |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1013 | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1014 | [ SKIP ] |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1015 | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1016 | x_2 = ... |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1017 | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1018 '---- T ---->.<---- F ----' |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1019 | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1020 v |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1021 x_3 = PHI <x_1, x_2> |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1022 | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1023 '----------------------'
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1024
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1025 Suppose in certain iteration, execution flow in above graph goes through
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1026 true branch, which means that one source value to define x_3 in false
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1027 branch (x_2) is skipped, x_3 only comes from x_1, and x_1 in next
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1028 iterations is defined by x_3, we know that x_1 will never changed if COND
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1029 always chooses true branch from then on. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1030
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1031 while (from != name)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1032 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1033 /* A new value comes from a CONSTANT. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1034 if (TREE_CODE (from) != SSA_NAME)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1035 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1036
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1037 gimple *stmt = SSA_NAME_DEF_STMT (from);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1038 const_basic_block bb = gimple_bb (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1039
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1040 /* A new value comes from outside the loop. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1041 if (!bb || !flow_bb_inside_loop_p (loop, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1042 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1043
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1044 from = NULL_TREE;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1045
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1046 if (gimple_code (stmt) == GIMPLE_PHI)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1047 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1048 gphi *phi = as_a <gphi *> (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1049
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1050 for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1051 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1052 if (skip_head)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1053 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1054 const_edge e = gimple_phi_arg_edge (phi, i);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1055
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1056 /* Don't consider redefinitions in excluded basic blocks. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1057 if (dominated_by_p (CDI_DOMINATORS, e->src, skip_head))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1058 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1059 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1060
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1061 tree arg = gimple_phi_arg_def (phi, i);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1062
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1063 if (!from)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1064 from = arg;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1065 else if (!operand_equal_p (from, arg, 0))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1066 /* There are more than one source operands that provide
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1067 different values to the SSA name, it is variant. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1068 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1069 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1070 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1071 else if (gimple_code (stmt) == GIMPLE_ASSIGN)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1072 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1073 /* For simple value copy, check its rhs instead. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1074 if (gimple_assign_ssa_name_copy_p (stmt))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1075 from = gimple_assign_rhs1 (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1076 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1077
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1078 /* Any other kind of definition is deemed to introduce a new value
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1079 to the SSA name. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1080 if (!from)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1081 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1082 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1083 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1084 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1085
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1086 /* Check whether conditional predicates that BB is control-dependent on, are
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1087 semi-invariant in LOOP. Basic blocks dominated by SKIP_HEAD (if non-NULL),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1088 are excluded from LOOP. Semi-invariant state of checked statement is cached
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1089 in hash map STMT_STAT. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1090
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1091 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1092 control_dep_semi_invariant_p (struct loop *loop, basic_block bb,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1093 const_basic_block skip_head,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1094 hash_map<gimple *, bool> &stmt_stat)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1095 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1096 hash_set<basic_block> *dep_bbs = find_control_dep_blocks (loop, bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1097
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1098 if (!dep_bbs)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1099 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1100
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1101 for (hash_set<basic_block>::iterator iter = dep_bbs->begin ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1102 iter != dep_bbs->end (); ++iter)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1103 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1104 gimple *last = last_stmt (*iter);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1105
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1106 if (!last)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1107 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1108
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1109 /* Only check condition predicates. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1110 if (gimple_code (last) != GIMPLE_COND
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1111 && gimple_code (last) != GIMPLE_SWITCH)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1112 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1113
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1114 if (!stmt_semi_invariant_p_1 (loop, last, skip_head, stmt_stat))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1115 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1116 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1117
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1118 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1119 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1120
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1121 /* Check whether STMT is semi-invariant in LOOP, iff all its operands are
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1122 semi-invariant, consequently, all its defined values are semi-invariant.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1123 Basic blocks dominated by SKIP_HEAD (if non-NULL), are excluded from LOOP.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1124 Semi-invariant state of checked statement is cached in hash map
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1125 STMT_STAT. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1126
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1127 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1128 stmt_semi_invariant_p_1 (struct loop *loop, gimple *stmt,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1129 const_basic_block skip_head,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1130 hash_map<gimple *, bool> &stmt_stat)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1131 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1132 bool existed;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1133 bool &invar = stmt_stat.get_or_insert (stmt, &existed);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1134
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1135 if (existed)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1136 return invar;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1137
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1138 /* A statement might depend on itself, which is treated as variant. So set
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1139 state of statement under check to be variant to ensure that. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1140 invar = false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1141
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1142 if (gimple_code (stmt) == GIMPLE_PHI)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1143 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1144 gphi *phi = as_a <gphi *> (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1146 if (gimple_bb (stmt) == loop->header)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1147 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1148 invar = loop_iter_phi_semi_invariant_p (loop, phi, skip_head);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1149 return invar;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1150 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1151
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1152 /* For a loop PHI node that does not locate in loop header, it is semi-
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1153 invariant only if two conditions are met. The first is its source
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1154 values are derived from CONSTANT (including loop-invariant value), or
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1155 from SSA name defined by semi-invariant loop iteration PHI node. The
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1156 second is its source incoming edges are control-dependent on semi-
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1157 invariant conditional predicates. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1158 for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1159 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1160 const_edge e = gimple_phi_arg_edge (phi, i);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1161 tree arg = gimple_phi_arg_def (phi, i);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1162
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1163 if (TREE_CODE (arg) == SSA_NAME)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1164 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1165 if (!ssa_semi_invariant_p (loop, arg, skip_head, stmt_stat))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1166 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1167
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1168 /* If source value is defined in location from where the source
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1169 edge comes in, no need to check control dependency again
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1170 since this has been done in above SSA name check stage. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1171 if (e->src == gimple_bb (SSA_NAME_DEF_STMT (arg)))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1172 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1173 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1174
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1175 if (!control_dep_semi_invariant_p (loop, e->src, skip_head,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1176 stmt_stat))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1177 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1178 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1179 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1180 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1181 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1182 ssa_op_iter iter;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1183 tree use;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1184
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1185 /* Volatile memory load or return of normal (non-const/non-pure) call
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1186 should not be treated as constant in each iteration of loop. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1187 if (gimple_has_side_effects (stmt))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1188 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1189
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1190 /* Check if any memory store may kill memory load at this place. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1191 if (gimple_vuse (stmt) && !vuse_semi_invariant_p (loop, stmt, skip_head))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1192 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1193
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1194 /* Although operand of a statement might be SSA name, CONSTANT or
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1195 VARDECL, here we only need to check SSA name operands. This is
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1196 because check on VARDECL operands, which involve memory loads,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1197 must have been done prior to invocation of this function in
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1198 vuse_semi_invariant_p. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1199 FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1200 if (!ssa_semi_invariant_p (loop, use, skip_head, stmt_stat))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1201 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1202 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1203
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1204 if (!control_dep_semi_invariant_p (loop, gimple_bb (stmt), skip_head,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1205 stmt_stat))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1206 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1207
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1208 /* Here we SHOULD NOT use invar = true, since hash map might be changed due
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1209 to new insertion, and thus invar may point to invalid memory. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1210 stmt_stat.put (stmt, true);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1211 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1212 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1213
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1214 /* A helper function to check whether STMT is semi-invariant in LOOP. Basic
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1215 blocks dominated by SKIP_HEAD (if non-NULL), are excluded from LOOP. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1216
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1217 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1218 stmt_semi_invariant_p (struct loop *loop, gimple *stmt,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1219 const_basic_block skip_head)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1220 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1221 hash_map<gimple *, bool> stmt_stat;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1222 return stmt_semi_invariant_p_1 (loop, stmt, skip_head, stmt_stat);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1223 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1224
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1225 /* Determine when conditional statement never transfers execution to one of its
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1226 branch, whether we can remove the branch's leading basic block (BRANCH_BB)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1227 and those basic blocks dominated by BRANCH_BB. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1228
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1229 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1230 branch_removable_p (basic_block branch_bb)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1231 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1232 edge_iterator ei;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1233 edge e;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1234
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1235 if (single_pred_p (branch_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1236 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1237
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1238 FOR_EACH_EDGE (e, ei, branch_bb->preds)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1239 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1240 if (dominated_by_p (CDI_DOMINATORS, e->src, branch_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1241 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1242
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1243 if (dominated_by_p (CDI_DOMINATORS, branch_bb, e->src))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1244 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1245
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1246 /* The branch can be reached from opposite branch, or from some
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1247 statement not dominated by the conditional statement. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1248 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1249 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1250
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1251 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1252 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1253
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1254 /* Find out which branch of a conditional statement (COND) is invariant in the
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1255 execution context of LOOP. That is: once the branch is selected in certain
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1256 iteration of the loop, any operand that contributes to computation of the
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1257 conditional statement remains unchanged in all following iterations. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1258
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1259 static edge
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1260 get_cond_invariant_branch (struct loop *loop, gcond *cond)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1261 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1262 basic_block cond_bb = gimple_bb (cond);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1263 basic_block targ_bb[2];
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1264 bool invar[2];
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1265 unsigned invar_checks = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1266
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1267 for (unsigned i = 0; i < 2; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1268 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1269 targ_bb[i] = EDGE_SUCC (cond_bb, i)->dest;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1270
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1271 /* One branch directs to loop exit, no need to perform loop split upon
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1272 this conditional statement. Firstly, it is trivial if the exit branch
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1273 is semi-invariant, for the statement is just to break loop. Secondly,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1274 if the opposite branch is semi-invariant, it means that the statement
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1275 is real loop-invariant, which is covered by loop unswitch. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1276 if (!flow_bb_inside_loop_p (loop, targ_bb[i]))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1277 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1278 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1279
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1280 for (unsigned i = 0; i < 2; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1281 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1282 invar[!i] = false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1283
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1284 if (!branch_removable_p (targ_bb[i]))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1285 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1286
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1287 /* Given a semi-invariant branch, if its opposite branch dominates
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1288 loop latch, it and its following trace will only be executed in
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1289 final iteration of loop, namely it is not part of repeated body
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1290 of the loop. Similar to the above case that the branch is loop
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1291 exit, no need to split loop. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1292 if (dominated_by_p (CDI_DOMINATORS, loop->latch, targ_bb[i]))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1293 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1294
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1295 invar[!i] = stmt_semi_invariant_p (loop, cond, targ_bb[i]);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1296 invar_checks++;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1297 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1298
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1299 /* With both branches being invariant (handled by loop unswitch) or
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1300 variant is not what we want. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1301 if (invar[0] ^ !invar[1])
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1302 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1303
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1304 /* Found a real loop-invariant condition, do nothing. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1305 if (invar_checks < 2 && stmt_semi_invariant_p (loop, cond, NULL))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1306 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1307
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1308 return EDGE_SUCC (cond_bb, invar[0] ? 0 : 1);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1309 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1310
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1311 /* Calculate increased code size measured by estimated insn number if applying
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1312 loop split upon certain branch (BRANCH_EDGE) of a conditional statement. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1313
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1314 static int
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1315 compute_added_num_insns (struct loop *loop, const_edge branch_edge)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1316 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1317 basic_block cond_bb = branch_edge->src;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1318 unsigned branch = EDGE_SUCC (cond_bb, 1) == branch_edge;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1319 basic_block opposite_bb = EDGE_SUCC (cond_bb, !branch)->dest;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1320 basic_block *bbs = ((split_info *) loop->aux)->bbs;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1321 int num = 0;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1322
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1323 for (unsigned i = 0; i < loop->num_nodes; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1324 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1325 /* Do no count basic blocks only in opposite branch. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1326 if (dominated_by_p (CDI_DOMINATORS, bbs[i], opposite_bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1327 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1328
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1329 num += estimate_num_insns_seq (bb_seq (bbs[i]), &eni_size_weights);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1330 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1331
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1332 /* It is unnecessary to evaluate expression of the conditional statement
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1333 in new loop that contains only invariant branch. This expression should
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1334 be constant value (either true or false). Exclude code size of insns
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1335 that contribute to computation of the expression. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1336
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1337 auto_vec<gimple *> worklist;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1338 hash_set<gimple *> removed;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1339 gimple *stmt = last_stmt (cond_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1340
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1341 worklist.safe_push (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1342 removed.add (stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1343 num -= estimate_num_insns (stmt, &eni_size_weights);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1344
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1345 do
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1346 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1347 ssa_op_iter opnd_iter;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1348 use_operand_p opnd_p;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1349
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1350 stmt = worklist.pop ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1351 FOR_EACH_PHI_OR_STMT_USE (opnd_p, stmt, opnd_iter, SSA_OP_USE)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1352 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1353 tree opnd = USE_FROM_PTR (opnd_p);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1354
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1355 if (TREE_CODE (opnd) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (opnd))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1356 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1357
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1358 gimple *opnd_stmt = SSA_NAME_DEF_STMT (opnd);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1359 use_operand_p use_p;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1360 imm_use_iterator use_iter;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1361
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1362 if (removed.contains (opnd_stmt)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1363 || !flow_bb_inside_loop_p (loop, gimple_bb (opnd_stmt)))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1364 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1365
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1366 FOR_EACH_IMM_USE_FAST (use_p, use_iter, opnd)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1367 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1368 gimple *use_stmt = USE_STMT (use_p);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1369
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1370 if (!is_gimple_debug (use_stmt) && !removed.contains (use_stmt))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1371 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1372 opnd_stmt = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1373 break;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1374 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1375 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1376
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1377 if (opnd_stmt)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1378 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1379 worklist.safe_push (opnd_stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1380 removed.add (opnd_stmt);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1381 num -= estimate_num_insns (opnd_stmt, &eni_size_weights);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1382 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1383 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1384 } while (!worklist.is_empty ());
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1385
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1386 gcc_assert (num >= 0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1387 return num;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1388 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1389
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1390 /* Find out loop-invariant branch of a conditional statement (COND) if it has,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1391 and check whether it is eligible and profitable to perform loop split upon
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1392 this branch in LOOP. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1393
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1394 static edge
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1395 get_cond_branch_to_split_loop (struct loop *loop, gcond *cond)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1396 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1397 edge invar_branch = get_cond_invariant_branch (loop, cond);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1398 if (!invar_branch)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1399 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1400
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1401 /* When accurate profile information is available, and execution
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1402 frequency of the branch is too low, just let it go. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1403 profile_probability prob = invar_branch->probability;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1404 if (prob.reliable_p ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1405 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1406 int thres = param_min_loop_cond_split_prob;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1407
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1408 if (prob < profile_probability::always ().apply_scale (thres, 100))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1409 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1410 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1411
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1412 /* Add a threshold for increased code size to disable loop split. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1413 if (compute_added_num_insns (loop, invar_branch) > param_max_peeled_insns)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1414 return NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1415
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1416 return invar_branch;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1417 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1418
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1419 /* Given a loop (LOOP1) with a loop-invariant branch (INVAR_BRANCH) of some
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1420 conditional statement, perform loop split transformation illustrated
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1421 as the following graph.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1422
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1423 .-------T------ if (true) ------F------.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1424 | .---------------. |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1425 | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1426 v | v v
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1427 pre-header | pre-header
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1428 | .------------. | | .------------.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1429 | | | | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1430 | v | | | v |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1431 header | | header |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1432 | | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1433 .--- if (cond) ---. | | .--- if (true) ---. |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1434 | | | | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1435 invariant | | | invariant | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1436 | | | | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1437 '---T--->.<---F---' | | '---T--->.<---F---' |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1438 | | / | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1439 stmts | / stmts |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1440 | F T | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1441 / \ | / / \ |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1442 .-------* * [ if (cond) ] .-------* * |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1443 | | | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1444 | latch | | latch |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1445 | | | | | |
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1446 | '------------' | '------------'
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1447 '------------------------. .-----------'
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1448 loop1 | | loop2
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1449 v v
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1450 exits
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1451
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1452 In the graph, loop1 represents the part derived from original one, and
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1453 loop2 is duplicated using loop_version (), which corresponds to the part
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1454 of original one being splitted out. In original latch edge of loop1, we
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1455 insert a new conditional statement duplicated from the semi-invariant cond,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1456 and one of its branch goes back to loop1 header as a latch edge, and the
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1457 other branch goes to loop2 pre-header as an entry edge. And also in loop2,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1458 we abandon the variant branch of the conditional statement by setting a
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1459 constant bool condition, based on which branch is semi-invariant. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1460
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1461 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1462 do_split_loop_on_cond (struct loop *loop1, edge invar_branch)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1463 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1464 basic_block cond_bb = invar_branch->src;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1465 bool true_invar = !!(invar_branch->flags & EDGE_TRUE_VALUE);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1466 gcond *cond = as_a <gcond *> (last_stmt (cond_bb));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1467
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1468 gcc_assert (cond_bb->loop_father == loop1);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1469
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1470 if (dump_enabled_p ())
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1471 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, cond,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1472 "loop split on semi-invariant condition at %s branch\n",
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1473 true_invar ? "true" : "false");
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1474
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1475 initialize_original_copy_tables ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1476
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1477 struct loop *loop2 = loop_version (loop1, boolean_true_node, NULL,
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1478 profile_probability::always (),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1479 profile_probability::never (),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1480 profile_probability::always (),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1481 profile_probability::always (),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1482 true);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1483 if (!loop2)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1484 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1485 free_original_copy_tables ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1486 return false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1487 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1488
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1489 basic_block cond_bb_copy = get_bb_copy (cond_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1490 gcond *cond_copy = as_a<gcond *> (last_stmt (cond_bb_copy));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1491
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1492 /* Replace the condition in loop2 with a bool constant to let PassManager
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1493 remove the variant branch after current pass completes. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1494 if (true_invar)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1495 gimple_cond_make_true (cond_copy);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1496 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1497 gimple_cond_make_false (cond_copy);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1498
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1499 update_stmt (cond_copy);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1500
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1501 /* Insert a new conditional statement on latch edge of loop1, its condition
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1502 is duplicated from the semi-invariant. This statement acts as a switch
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1503 to transfer execution from loop1 to loop2, when loop1 enters into
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1504 invariant state. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1505 basic_block latch_bb = split_edge (loop_latch_edge (loop1));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1506 basic_block break_bb = split_edge (single_pred_edge (latch_bb));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1507 gimple *break_cond = gimple_build_cond (gimple_cond_code(cond),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1508 gimple_cond_lhs (cond),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1509 gimple_cond_rhs (cond),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1510 NULL_TREE, NULL_TREE);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1511
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1512 gimple_stmt_iterator gsi = gsi_last_bb (break_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1513 gsi_insert_after (&gsi, break_cond, GSI_NEW_STMT);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1514
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1515 edge to_loop1 = single_succ_edge (break_bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1516 edge to_loop2 = make_edge (break_bb, loop_preheader_edge (loop2)->src, 0);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1517
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1518 to_loop1->flags &= ~EDGE_FALLTHRU;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1519 to_loop1->flags |= true_invar ? EDGE_FALSE_VALUE : EDGE_TRUE_VALUE;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1520 to_loop2->flags |= true_invar ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1521
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1522 update_ssa (TODO_update_ssa);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1523
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1524 /* Due to introduction of a control flow edge from loop1 latch to loop2
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1525 pre-header, we should update PHIs in loop2 to reflect this connection
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1526 between loop1 and loop2. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1527 connect_loop_phis (loop1, loop2, to_loop2);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1528
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1529 free_original_copy_tables ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1530
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1531 rewrite_into_loop_closed_ssa_1 (NULL, 0, SSA_OP_USE, loop1);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1532
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1533 return true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1534 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1535
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1536 /* Traverse all conditional statements in LOOP, to find out a good candidate
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1537 upon which we can do loop split. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1538
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1539 static bool
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1540 split_loop_on_cond (struct loop *loop)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1541 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1542 split_info *info = new split_info ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1543 basic_block *bbs = info->bbs = get_loop_body (loop);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1544 bool do_split = false;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1545
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1546 /* Allocate an area to keep temporary info, and associate its address
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1547 with loop aux field. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1548 loop->aux = info;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1549
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1550 for (unsigned i = 0; i < loop->num_nodes; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1551 bbs[i]->aux = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1552
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1553 for (unsigned i = 0; i < loop->num_nodes; i++)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1554 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1555 basic_block bb = bbs[i];
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1556
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1557 /* We only consider conditional statement, which be executed at most once
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1558 in each iteration of the loop. So skip statements in inner loops. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1559 if ((bb->loop_father != loop) || (bb->flags & BB_IRREDUCIBLE_LOOP))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1560 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1561
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1562 /* Actually this check is not a must constraint. With it, we can ensure
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1563 conditional statement will always be executed in each iteration. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1564 if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1565 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1566
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1567 gimple *last = last_stmt (bb);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1568
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1569 if (!last || gimple_code (last) != GIMPLE_COND)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1570 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1571
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1572 gcond *cond = as_a <gcond *> (last);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1573 edge branch_edge = get_cond_branch_to_split_loop (loop, cond);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1574
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1575 if (branch_edge)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1576 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1577 do_split_loop_on_cond (loop, branch_edge);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1578 do_split = true;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1579 break;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1580 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1581 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1582
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1583 delete info;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1584 loop->aux = NULL;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1585
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1586 return do_split;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1587 }
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1588
111
kono
parents:
diff changeset
1589 /* Main entry point. Perform loop splitting on all suitable loops. */
kono
parents:
diff changeset
1590
kono
parents:
diff changeset
1591 static unsigned int
kono
parents:
diff changeset
1592 tree_ssa_split_loops (void)
kono
parents:
diff changeset
1593 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1594 class loop *loop;
111
kono
parents:
diff changeset
1595 bool changed = false;
kono
parents:
diff changeset
1596
kono
parents:
diff changeset
1597 gcc_assert (scev_initialized_p ());
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1598
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1599 calculate_dominance_info (CDI_POST_DOMINATORS);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1600
111
kono
parents:
diff changeset
1601 FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
kono
parents:
diff changeset
1602 loop->aux = NULL;
kono
parents:
diff changeset
1603
kono
parents:
diff changeset
1604 /* Go through all loops starting from innermost. */
kono
parents:
diff changeset
1605 FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
kono
parents:
diff changeset
1606 {
kono
parents:
diff changeset
1607 if (loop->aux)
kono
parents:
diff changeset
1608 {
kono
parents:
diff changeset
1609 /* If any of our inner loops was split, don't split us,
kono
parents:
diff changeset
1610 and mark our containing loop as having had splits as well. */
kono
parents:
diff changeset
1611 loop_outer (loop)->aux = loop;
kono
parents:
diff changeset
1612 continue;
kono
parents:
diff changeset
1613 }
kono
parents:
diff changeset
1614
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1615 if (optimize_loop_for_size_p (loop))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1616 continue;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1617
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1618 if (split_loop (loop) || split_loop_on_cond (loop))
111
kono
parents:
diff changeset
1619 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1620 /* Mark our containing loop as having had some split inner loops. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1621 loop_outer (loop)->aux = loop;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1622 changed = true;
111
kono
parents:
diff changeset
1623 }
kono
parents:
diff changeset
1624 }
kono
parents:
diff changeset
1625
kono
parents:
diff changeset
1626 FOR_EACH_LOOP (loop, LI_INCLUDE_ROOT)
kono
parents:
diff changeset
1627 loop->aux = NULL;
kono
parents:
diff changeset
1628
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1629 clear_aux_for_blocks ();
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1630
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1631 free_dominance_info (CDI_POST_DOMINATORS);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1632
111
kono
parents:
diff changeset
1633 if (changed)
kono
parents:
diff changeset
1634 return TODO_cleanup_cfg;
kono
parents:
diff changeset
1635 return 0;
kono
parents:
diff changeset
1636 }
kono
parents:
diff changeset
1637
kono
parents:
diff changeset
1638 /* Loop splitting pass. */
kono
parents:
diff changeset
1639
kono
parents:
diff changeset
1640 namespace {
kono
parents:
diff changeset
1641
kono
parents:
diff changeset
1642 const pass_data pass_data_loop_split =
kono
parents:
diff changeset
1643 {
kono
parents:
diff changeset
1644 GIMPLE_PASS, /* type */
kono
parents:
diff changeset
1645 "lsplit", /* name */
kono
parents:
diff changeset
1646 OPTGROUP_LOOP, /* optinfo_flags */
kono
parents:
diff changeset
1647 TV_LOOP_SPLIT, /* tv_id */
kono
parents:
diff changeset
1648 PROP_cfg, /* properties_required */
kono
parents:
diff changeset
1649 0, /* properties_provided */
kono
parents:
diff changeset
1650 0, /* properties_destroyed */
kono
parents:
diff changeset
1651 0, /* todo_flags_start */
kono
parents:
diff changeset
1652 0, /* todo_flags_finish */
kono
parents:
diff changeset
1653 };
kono
parents:
diff changeset
1654
kono
parents:
diff changeset
1655 class pass_loop_split : public gimple_opt_pass
kono
parents:
diff changeset
1656 {
kono
parents:
diff changeset
1657 public:
kono
parents:
diff changeset
1658 pass_loop_split (gcc::context *ctxt)
kono
parents:
diff changeset
1659 : gimple_opt_pass (pass_data_loop_split, ctxt)
kono
parents:
diff changeset
1660 {}
kono
parents:
diff changeset
1661
kono
parents:
diff changeset
1662 /* opt_pass methods: */
kono
parents:
diff changeset
1663 virtual bool gate (function *) { return flag_split_loops != 0; }
kono
parents:
diff changeset
1664 virtual unsigned int execute (function *);
kono
parents:
diff changeset
1665
kono
parents:
diff changeset
1666 }; // class pass_loop_split
kono
parents:
diff changeset
1667
kono
parents:
diff changeset
1668 unsigned int
kono
parents:
diff changeset
1669 pass_loop_split::execute (function *fun)
kono
parents:
diff changeset
1670 {
kono
parents:
diff changeset
1671 if (number_of_loops (fun) <= 1)
kono
parents:
diff changeset
1672 return 0;
kono
parents:
diff changeset
1673
kono
parents:
diff changeset
1674 return tree_ssa_split_loops ();
kono
parents:
diff changeset
1675 }
kono
parents:
diff changeset
1676
kono
parents:
diff changeset
1677 } // anon namespace
kono
parents:
diff changeset
1678
kono
parents:
diff changeset
1679 gimple_opt_pass *
kono
parents:
diff changeset
1680 make_pass_loop_split (gcc::context *ctxt)
kono
parents:
diff changeset
1681 {
kono
parents:
diff changeset
1682 return new pass_loop_split (ctxt);
kono
parents:
diff changeset
1683 }