File: | build/gcc/tree-ssa-loop-im.cc |
Warning: | line 1656, column 10 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Loop invariant motion. | |||
2 | Copyright (C) 2003-2023 Free Software Foundation, Inc. | |||
3 | ||||
4 | This file is part of GCC. | |||
5 | ||||
6 | GCC is free software; you can redistribute it and/or modify it | |||
7 | under the terms of the GNU General Public License as published by the | |||
8 | Free Software Foundation; either version 3, or (at your option) any | |||
9 | later version. | |||
10 | ||||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT | |||
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
14 | for more details. | |||
15 | ||||
16 | You should have received a copy of the GNU General Public License | |||
17 | along with GCC; see the file COPYING3. If not see | |||
18 | <http://www.gnu.org/licenses/>. */ | |||
19 | ||||
20 | #include "config.h" | |||
21 | #include "system.h" | |||
22 | #include "coretypes.h" | |||
23 | #include "backend.h" | |||
24 | #include "tree.h" | |||
25 | #include "gimple.h" | |||
26 | #include "cfghooks.h" | |||
27 | #include "tree-pass.h" | |||
28 | #include "ssa.h" | |||
29 | #include "gimple-pretty-print.h" | |||
30 | #include "fold-const.h" | |||
31 | #include "cfganal.h" | |||
32 | #include "tree-eh.h" | |||
33 | #include "gimplify.h" | |||
34 | #include "gimple-iterator.h" | |||
35 | #include "tree-cfg.h" | |||
36 | #include "tree-ssa-loop-manip.h" | |||
37 | #include "tree-ssa-loop.h" | |||
38 | #include "tree-into-ssa.h" | |||
39 | #include "cfgloop.h" | |||
40 | #include "tree-affine.h" | |||
41 | #include "tree-ssa-propagate.h" | |||
42 | #include "trans-mem.h" | |||
43 | #include "gimple-fold.h" | |||
44 | #include "tree-scalar-evolution.h" | |||
45 | #include "tree-ssa-loop-niter.h" | |||
46 | #include "alias.h" | |||
47 | #include "builtins.h" | |||
48 | #include "tree-dfa.h" | |||
49 | #include "tree-ssa.h" | |||
50 | #include "dbgcnt.h" | |||
51 | ||||
52 | /* TODO: Support for predicated code motion. I.e. | |||
53 | ||||
54 | while (1) | |||
55 | { | |||
56 | if (cond) | |||
57 | { | |||
58 | a = inv; | |||
59 | something; | |||
60 | } | |||
61 | } | |||
62 | ||||
63 | Where COND and INV are invariants, but evaluating INV may trap or be | |||
64 | invalid from some other reason if !COND. This may be transformed to | |||
65 | ||||
66 | if (cond) | |||
67 | a = inv; | |||
68 | while (1) | |||
69 | { | |||
70 | if (cond) | |||
71 | something; | |||
72 | } */ | |||
73 | ||||
74 | /* The auxiliary data kept for each statement. */ | |||
75 | ||||
76 | struct lim_aux_data | |||
77 | { | |||
78 | class loop *max_loop; /* The outermost loop in that the statement | |||
79 | is invariant. */ | |||
80 | ||||
81 | class loop *tgt_loop; /* The loop out of that we want to move the | |||
82 | invariant. */ | |||
83 | ||||
84 | class loop *always_executed_in; | |||
85 | /* The outermost loop for that we are sure | |||
86 | the statement is executed if the loop | |||
87 | is entered. */ | |||
88 | ||||
89 | unsigned cost; /* Cost of the computation performed by the | |||
90 | statement. */ | |||
91 | ||||
92 | unsigned ref; /* The simple_mem_ref in this stmt or 0. */ | |||
93 | ||||
94 | vec<gimple *> depends; /* Vector of statements that must be also | |||
95 | hoisted out of the loop when this statement | |||
96 | is hoisted; i.e. those that define the | |||
97 | operands of the statement and are inside of | |||
98 | the MAX_LOOP loop. */ | |||
99 | }; | |||
100 | ||||
101 | /* Maps statements to their lim_aux_data. */ | |||
102 | ||||
103 | static hash_map<gimple *, lim_aux_data *> *lim_aux_data_map; | |||
104 | ||||
105 | /* Description of a memory reference location. */ | |||
106 | ||||
107 | struct mem_ref_loc | |||
108 | { | |||
109 | tree *ref; /* The reference itself. */ | |||
110 | gimple *stmt; /* The statement in that it occurs. */ | |||
111 | }; | |||
112 | ||||
113 | ||||
114 | /* Description of a memory reference. */ | |||
115 | ||||
116 | class im_mem_ref | |||
117 | { | |||
118 | public: | |||
119 | unsigned id : 30; /* ID assigned to the memory reference | |||
120 | (its index in memory_accesses.refs_list) */ | |||
121 | unsigned ref_canonical : 1; /* Whether mem.ref was canonicalized. */ | |||
122 | unsigned ref_decomposed : 1; /* Whether the ref was hashed from mem. */ | |||
123 | hashval_t hash; /* Its hash value. */ | |||
124 | ||||
125 | /* The memory access itself and associated caching of alias-oracle | |||
126 | query meta-data. We are using mem.ref == error_mark_node for the | |||
127 | case the reference is represented by its single access stmt | |||
128 | in accesses_in_loop[0]. */ | |||
129 | ao_ref mem; | |||
130 | ||||
131 | bitmap stored; /* The set of loops in that this memory location | |||
132 | is stored to. */ | |||
133 | bitmap loaded; /* The set of loops in that this memory location | |||
134 | is loaded from. */ | |||
135 | vec<mem_ref_loc> accesses_in_loop; | |||
136 | /* The locations of the accesses. */ | |||
137 | ||||
138 | /* The following set is computed on demand. */ | |||
139 | bitmap_head dep_loop; /* The set of loops in that the memory | |||
140 | reference is {in,}dependent in | |||
141 | different modes. */ | |||
142 | }; | |||
143 | ||||
144 | /* We use six bits per loop in the ref->dep_loop bitmap to record | |||
145 | the dep_kind x dep_state combinations. */ | |||
146 | ||||
147 | enum dep_kind { lim_raw, sm_war, sm_waw }; | |||
148 | enum dep_state { dep_unknown, dep_independent, dep_dependent }; | |||
149 | ||||
150 | /* coldest outermost loop for given loop. */ | |||
151 | vec<class loop *> coldest_outermost_loop; | |||
152 | /* hotter outer loop nearest to given loop. */ | |||
153 | vec<class loop *> hotter_than_inner_loop; | |||
154 | ||||
155 | /* Populate the loop dependence cache of REF for LOOP, KIND with STATE. */ | |||
156 | ||||
157 | static void | |||
158 | record_loop_dependence (class loop *loop, im_mem_ref *ref, | |||
159 | dep_kind kind, dep_state state) | |||
160 | { | |||
161 | gcc_assert (state != dep_unknown)((void)(!(state != dep_unknown) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 161, __FUNCTION__), 0 : 0)); | |||
162 | unsigned bit = 6 * loop->num + kind * 2 + state == dep_dependent ? 1 : 0; | |||
163 | bitmap_set_bit (&ref->dep_loop, bit); | |||
164 | } | |||
165 | ||||
166 | /* Query the loop dependence cache of REF for LOOP, KIND. */ | |||
167 | ||||
168 | static dep_state | |||
169 | query_loop_dependence (class loop *loop, im_mem_ref *ref, dep_kind kind) | |||
170 | { | |||
171 | unsigned first_bit = 6 * loop->num + kind * 2; | |||
172 | if (bitmap_bit_p (&ref->dep_loop, first_bit)) | |||
173 | return dep_independent; | |||
174 | else if (bitmap_bit_p (&ref->dep_loop, first_bit + 1)) | |||
175 | return dep_dependent; | |||
176 | return dep_unknown; | |||
177 | } | |||
178 | ||||
179 | /* Mem_ref hashtable helpers. */ | |||
180 | ||||
181 | struct mem_ref_hasher : nofree_ptr_hash <im_mem_ref> | |||
182 | { | |||
183 | typedef ao_ref *compare_type; | |||
184 | static inline hashval_t hash (const im_mem_ref *); | |||
185 | static inline bool equal (const im_mem_ref *, const ao_ref *); | |||
186 | }; | |||
187 | ||||
188 | /* A hash function for class im_mem_ref object OBJ. */ | |||
189 | ||||
190 | inline hashval_t | |||
191 | mem_ref_hasher::hash (const im_mem_ref *mem) | |||
192 | { | |||
193 | return mem->hash; | |||
194 | } | |||
195 | ||||
196 | /* An equality function for class im_mem_ref object MEM1 with | |||
197 | memory reference OBJ2. */ | |||
198 | ||||
199 | inline bool | |||
200 | mem_ref_hasher::equal (const im_mem_ref *mem1, const ao_ref *obj2) | |||
201 | { | |||
202 | if (obj2->max_size_known_p ()) | |||
203 | return (mem1->ref_decomposed | |||
204 | && ((TREE_CODE (mem1->mem.base)((enum tree_code) (mem1->mem.base)->base.code) == MEM_REF | |||
205 | && TREE_CODE (obj2->base)((enum tree_code) (obj2->base)->base.code) == MEM_REF | |||
206 | && operand_equal_p (TREE_OPERAND (mem1->mem.base, 0)(*((const_cast<tree*> (tree_operand_check ((mem1->mem .base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 206, __FUNCTION__))))), | |||
207 | TREE_OPERAND (obj2->base, 0)(*((const_cast<tree*> (tree_operand_check ((obj2->base ), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 207, __FUNCTION__))))), 0) | |||
208 | && known_eq (mem_ref_offset (mem1->mem.base) * BITS_PER_UNIT + mem1->mem.offset,(!maybe_ne (mem_ref_offset (mem1->mem.base) * (8) + mem1-> mem.offset, mem_ref_offset (obj2->base) * (8) + obj2->offset )) | |||
209 | mem_ref_offset (obj2->base) * BITS_PER_UNIT + obj2->offset)(!maybe_ne (mem_ref_offset (mem1->mem.base) * (8) + mem1-> mem.offset, mem_ref_offset (obj2->base) * (8) + obj2->offset ))) | |||
210 | || (operand_equal_p (mem1->mem.base, obj2->base, 0) | |||
211 | && known_eq (mem1->mem.offset, obj2->offset)(!maybe_ne (mem1->mem.offset, obj2->offset)))) | |||
212 | && known_eq (mem1->mem.size, obj2->size)(!maybe_ne (mem1->mem.size, obj2->size)) | |||
213 | && known_eq (mem1->mem.max_size, obj2->max_size)(!maybe_ne (mem1->mem.max_size, obj2->max_size)) | |||
214 | && mem1->mem.volatile_p == obj2->volatile_p | |||
215 | && (mem1->mem.ref_alias_set == obj2->ref_alias_set | |||
216 | /* We are not canonicalizing alias-sets but for the | |||
217 | special-case we didn't canonicalize yet and the | |||
218 | incoming ref is a alias-set zero MEM we pick | |||
219 | the correct one already. */ | |||
220 | || (!mem1->ref_canonical | |||
221 | && (TREE_CODE (obj2->ref)((enum tree_code) (obj2->ref)->base.code) == MEM_REF | |||
222 | || TREE_CODE (obj2->ref)((enum tree_code) (obj2->ref)->base.code) == TARGET_MEM_REF) | |||
223 | && obj2->ref_alias_set == 0) | |||
224 | /* Likewise if there's a canonical ref with alias-set zero. */ | |||
225 | || (mem1->ref_canonical && mem1->mem.ref_alias_set == 0)) | |||
226 | && types_compatible_p (TREE_TYPE (mem1->mem.ref)((contains_struct_check ((mem1->mem.ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 226, __FUNCTION__))->typed.type), | |||
227 | TREE_TYPE (obj2->ref)((contains_struct_check ((obj2->ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 227, __FUNCTION__))->typed.type))); | |||
228 | else | |||
229 | return operand_equal_p (mem1->mem.ref, obj2->ref, 0); | |||
230 | } | |||
231 | ||||
232 | ||||
233 | /* Description of memory accesses in loops. */ | |||
234 | ||||
235 | static struct | |||
236 | { | |||
237 | /* The hash table of memory references accessed in loops. */ | |||
238 | hash_table<mem_ref_hasher> *refs; | |||
239 | ||||
240 | /* The list of memory references. */ | |||
241 | vec<im_mem_ref *> refs_list; | |||
242 | ||||
243 | /* The set of memory references accessed in each loop. */ | |||
244 | vec<bitmap_head> refs_loaded_in_loop; | |||
245 | ||||
246 | /* The set of memory references stored in each loop. */ | |||
247 | vec<bitmap_head> refs_stored_in_loop; | |||
248 | ||||
249 | /* The set of memory references stored in each loop, including subloops . */ | |||
250 | vec<bitmap_head> all_refs_stored_in_loop; | |||
251 | ||||
252 | /* Cache for expanding memory addresses. */ | |||
253 | hash_map<tree, name_expansion *> *ttae_cache; | |||
254 | } memory_accesses; | |||
255 | ||||
256 | /* Obstack for the bitmaps in the above data structures. */ | |||
257 | static bitmap_obstack lim_bitmap_obstack; | |||
258 | static obstack mem_ref_obstack; | |||
259 | ||||
260 | static bool ref_indep_loop_p (class loop *, im_mem_ref *, dep_kind); | |||
261 | static bool ref_always_accessed_p (class loop *, im_mem_ref *, bool); | |||
262 | static bool refs_independent_p (im_mem_ref *, im_mem_ref *, bool = true); | |||
263 | ||||
264 | /* Minimum cost of an expensive expression. */ | |||
265 | #define LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive) ((unsigned) param_lim_expensiveglobal_options.x_param_lim_expensive) | |||
266 | ||||
267 | /* The outermost loop for which execution of the header guarantees that the | |||
268 | block will be executed. */ | |||
269 | #define ALWAYS_EXECUTED_IN(BB)((class loop *) (BB)->aux) ((class loop *) (BB)->aux) | |||
270 | #define SET_ALWAYS_EXECUTED_IN(BB, VAL)((BB)->aux = (void *) (VAL)) ((BB)->aux = (void *) (VAL)) | |||
271 | ||||
272 | /* ID of the shared unanalyzable mem. */ | |||
273 | #define UNANALYZABLE_MEM_ID0 0 | |||
274 | ||||
275 | /* Whether the reference was analyzable. */ | |||
276 | #define MEM_ANALYZABLE(REF)((REF)->id != 0) ((REF)->id != UNANALYZABLE_MEM_ID0) | |||
277 | ||||
278 | static struct lim_aux_data * | |||
279 | init_lim_data (gimple *stmt) | |||
280 | { | |||
281 | lim_aux_data *p = XCNEW (struct lim_aux_data)((struct lim_aux_data *) xcalloc (1, sizeof (struct lim_aux_data ))); | |||
282 | lim_aux_data_map->put (stmt, p); | |||
283 | ||||
284 | return p; | |||
285 | } | |||
286 | ||||
287 | static struct lim_aux_data * | |||
288 | get_lim_data (gimple *stmt) | |||
289 | { | |||
290 | lim_aux_data **p = lim_aux_data_map->get (stmt); | |||
291 | if (!p) | |||
292 | return NULLnullptr; | |||
293 | ||||
294 | return *p; | |||
295 | } | |||
296 | ||||
297 | /* Releases the memory occupied by DATA. */ | |||
298 | ||||
299 | static void | |||
300 | free_lim_aux_data (struct lim_aux_data *data) | |||
301 | { | |||
302 | data->depends.release (); | |||
303 | free (data); | |||
304 | } | |||
305 | ||||
306 | static void | |||
307 | clear_lim_data (gimple *stmt) | |||
308 | { | |||
309 | lim_aux_data **p = lim_aux_data_map->get (stmt); | |||
310 | if (!p) | |||
311 | return; | |||
312 | ||||
313 | free_lim_aux_data (*p); | |||
314 | *p = NULLnullptr; | |||
315 | } | |||
316 | ||||
317 | ||||
318 | /* The possibilities of statement movement. */ | |||
319 | enum move_pos | |||
320 | { | |||
321 | MOVE_IMPOSSIBLE, /* No movement -- side effect expression. */ | |||
322 | MOVE_PRESERVE_EXECUTION, /* Must not cause the non-executed statement | |||
323 | become executed -- memory accesses, ... */ | |||
324 | MOVE_POSSIBLE /* Unlimited movement. */ | |||
325 | }; | |||
326 | ||||
327 | ||||
328 | /* If it is possible to hoist the statement STMT unconditionally, | |||
329 | returns MOVE_POSSIBLE. | |||
330 | If it is possible to hoist the statement STMT, but we must avoid making | |||
331 | it executed if it would not be executed in the original program (e.g. | |||
332 | because it may trap), return MOVE_PRESERVE_EXECUTION. | |||
333 | Otherwise return MOVE_IMPOSSIBLE. */ | |||
334 | ||||
335 | static enum move_pos | |||
336 | movement_possibility_1 (gimple *stmt) | |||
337 | { | |||
338 | tree lhs; | |||
339 | enum move_pos ret = MOVE_POSSIBLE; | |||
340 | ||||
341 | if (flag_unswitch_loopsglobal_options.x_flag_unswitch_loops | |||
342 | && gimple_code (stmt) == GIMPLE_COND) | |||
343 | { | |||
344 | /* If we perform unswitching, force the operands of the invariant | |||
345 | condition to be moved out of the loop. */ | |||
346 | return MOVE_POSSIBLE; | |||
347 | } | |||
348 | ||||
349 | if (gimple_code (stmt) == GIMPLE_PHI | |||
350 | && gimple_phi_num_args (stmt) <= 2 | |||
351 | && !virtual_operand_p (gimple_phi_result (stmt)) | |||
352 | && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (stmt))(tree_check ((gimple_phi_result (stmt)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 352, __FUNCTION__, (SSA_NAME)))->base.asm_written_flag) | |||
353 | return MOVE_POSSIBLE; | |||
354 | ||||
355 | if (gimple_get_lhs (stmt) == NULL_TREE(tree) nullptr) | |||
356 | return MOVE_IMPOSSIBLE; | |||
357 | ||||
358 | if (gimple_vdef (stmt)) | |||
359 | return MOVE_IMPOSSIBLE; | |||
360 | ||||
361 | if (stmt_ends_bb_p (stmt) | |||
362 | || gimple_has_volatile_ops (stmt) | |||
363 | || gimple_has_side_effects (stmt) | |||
364 | || stmt_could_throw_p (cfun(cfun + 0), stmt)) | |||
365 | return MOVE_IMPOSSIBLE; | |||
366 | ||||
367 | if (is_gimple_call (stmt)) | |||
368 | { | |||
369 | /* While pure or const call is guaranteed to have no side effects, we | |||
370 | cannot move it arbitrarily. Consider code like | |||
371 | ||||
372 | char *s = something (); | |||
373 | ||||
374 | while (1) | |||
375 | { | |||
376 | if (s) | |||
377 | t = strlen (s); | |||
378 | else | |||
379 | t = 0; | |||
380 | } | |||
381 | ||||
382 | Here the strlen call cannot be moved out of the loop, even though | |||
383 | s is invariant. In addition to possibly creating a call with | |||
384 | invalid arguments, moving out a function call that is not executed | |||
385 | may cause performance regressions in case the call is costly and | |||
386 | not executed at all. */ | |||
387 | ret = MOVE_PRESERVE_EXECUTION; | |||
388 | lhs = gimple_call_lhs (stmt); | |||
389 | } | |||
390 | else if (is_gimple_assign (stmt)) | |||
391 | lhs = gimple_assign_lhs (stmt); | |||
392 | else | |||
393 | return MOVE_IMPOSSIBLE; | |||
394 | ||||
395 | if (TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) == SSA_NAME | |||
396 | && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)(tree_check ((lhs), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 396, __FUNCTION__, (SSA_NAME)))->base.asm_written_flag) | |||
397 | return MOVE_IMPOSSIBLE; | |||
398 | ||||
399 | if (TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) != SSA_NAME | |||
400 | || gimple_could_trap_p (stmt)) | |||
401 | return MOVE_PRESERVE_EXECUTION; | |||
402 | ||||
403 | /* Non local loads in a transaction cannot be hoisted out. Well, | |||
404 | unless the load happens on every path out of the loop, but we | |||
405 | don't take this into account yet. */ | |||
406 | if (flag_tmglobal_options.x_flag_tm | |||
407 | && gimple_in_transaction (stmt) | |||
408 | && gimple_assign_single_p (stmt)) | |||
409 | { | |||
410 | tree rhs = gimple_assign_rhs1 (stmt); | |||
411 | if (DECL_P (rhs)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (rhs)->base.code))] == tcc_declaration) && is_global_var (rhs)) | |||
412 | { | |||
413 | if (dump_file) | |||
414 | { | |||
415 | fprintf (dump_file, "Cannot hoist conditional load of "); | |||
416 | print_generic_expr (dump_file, rhs, TDF_SLIM); | |||
417 | fprintf (dump_file, " because it is in a transaction.\n"); | |||
418 | } | |||
419 | return MOVE_IMPOSSIBLE; | |||
420 | } | |||
421 | } | |||
422 | ||||
423 | return ret; | |||
424 | } | |||
425 | ||||
426 | static enum move_pos | |||
427 | movement_possibility (gimple *stmt) | |||
428 | { | |||
429 | enum move_pos pos = movement_possibility_1 (stmt); | |||
430 | if (pos == MOVE_POSSIBLE) | |||
431 | { | |||
432 | use_operand_p use_p; | |||
433 | ssa_op_iter ssa_iter; | |||
434 | FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, ssa_iter, SSA_OP_USE)for ((use_p) = (gimple_code (stmt) == GIMPLE_PHI ? op_iter_init_phiuse (&(ssa_iter), as_a <gphi *> (stmt), 0x01) : op_iter_init_use (&(ssa_iter), stmt, 0x01)); !op_iter_done (&(ssa_iter )); (use_p) = op_iter_next_use (&(ssa_iter))) | |||
435 | if (TREE_CODE (USE_FROM_PTR (use_p))((enum tree_code) (get_use_from_ptr (use_p))->base.code) == SSA_NAME | |||
436 | && ssa_name_maybe_undef_p (USE_FROM_PTR (use_p)get_use_from_ptr (use_p))) | |||
437 | return MOVE_PRESERVE_EXECUTION; | |||
438 | } | |||
439 | return pos; | |||
440 | } | |||
441 | ||||
442 | ||||
443 | /* Compare the profile count inequality of bb and loop's preheader, it is | |||
444 | three-state as stated in profile-count.h, FALSE is returned if inequality | |||
445 | cannot be decided. */ | |||
446 | bool | |||
447 | bb_colder_than_loop_preheader (basic_block bb, class loop *loop) | |||
448 | { | |||
449 | gcc_assert (bb && loop)((void)(!(bb && loop) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 449, __FUNCTION__), 0 : 0)); | |||
450 | return bb->count < loop_preheader_edge (loop)->src->count; | |||
451 | } | |||
452 | ||||
453 | /* Check coldest loop between OUTERMOST_LOOP and LOOP by comparing profile | |||
454 | count. | |||
455 | It does three steps check: | |||
456 | 1) Check whether CURR_BB is cold in it's own loop_father, if it is cold, just | |||
457 | return NULL which means it should not be moved out at all; | |||
458 | 2) CURR_BB is NOT cold, check if pre-computed COLDEST_LOOP is outside of | |||
459 | OUTERMOST_LOOP, if it is inside of OUTERMOST_LOOP, return the COLDEST_LOOP; | |||
460 | 3) If COLDEST_LOOP is outside of OUTERMOST_LOOP, check whether there is a | |||
461 | hotter loop between OUTERMOST_LOOP and loop in pre-computed | |||
462 | HOTTER_THAN_INNER_LOOP, return it's nested inner loop, otherwise return | |||
463 | OUTERMOST_LOOP. | |||
464 | At last, the coldest_loop is inside of OUTERMOST_LOOP, just return it as | |||
465 | the hoist target. */ | |||
466 | ||||
467 | static class loop * | |||
468 | get_coldest_out_loop (class loop *outermost_loop, class loop *loop, | |||
469 | basic_block curr_bb) | |||
470 | { | |||
471 | gcc_assert (outermost_loop == loop((void)(!(outermost_loop == loop || flow_loop_nested_p (outermost_loop , loop)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 472, __FUNCTION__), 0 : 0)) | |||
472 | || flow_loop_nested_p (outermost_loop, loop))((void)(!(outermost_loop == loop || flow_loop_nested_p (outermost_loop , loop)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 472, __FUNCTION__), 0 : 0)); | |||
473 | ||||
474 | /* If bb_colder_than_loop_preheader returns false due to three-state | |||
475 | comparision, OUTERMOST_LOOP is returned finally to preserve the behavior. | |||
476 | Otherwise, return the coldest loop between OUTERMOST_LOOP and LOOP. */ | |||
477 | if (curr_bb && bb_colder_than_loop_preheader (curr_bb, loop)) | |||
478 | return NULLnullptr; | |||
479 | ||||
480 | class loop *coldest_loop = coldest_outermost_loop[loop->num]; | |||
481 | if (loop_depth (coldest_loop) < loop_depth (outermost_loop)) | |||
482 | { | |||
483 | class loop *hotter_loop = hotter_than_inner_loop[loop->num]; | |||
484 | if (!hotter_loop | |||
485 | || loop_depth (hotter_loop) < loop_depth (outermost_loop)) | |||
486 | return outermost_loop; | |||
487 | ||||
488 | /* hotter_loop is between OUTERMOST_LOOP and LOOP like: | |||
489 | [loop tree root, ..., coldest_loop, ..., outermost_loop, ..., | |||
490 | hotter_loop, second_coldest_loop, ..., loop] | |||
491 | return second_coldest_loop to be the hoist target. */ | |||
492 | class loop *aloop; | |||
493 | for (aloop = hotter_loop->inner; aloop; aloop = aloop->next) | |||
494 | if (aloop == loop || flow_loop_nested_p (aloop, loop)) | |||
495 | return aloop; | |||
496 | } | |||
497 | return coldest_loop; | |||
498 | } | |||
499 | ||||
500 | /* Suppose that operand DEF is used inside the LOOP. Returns the outermost | |||
501 | loop to that we could move the expression using DEF if it did not have | |||
502 | other operands, i.e. the outermost loop enclosing LOOP in that the value | |||
503 | of DEF is invariant. */ | |||
504 | ||||
505 | static class loop * | |||
506 | outermost_invariant_loop (tree def, class loop *loop) | |||
507 | { | |||
508 | gimple *def_stmt; | |||
509 | basic_block def_bb; | |||
510 | class loop *max_loop; | |||
511 | struct lim_aux_data *lim_data; | |||
512 | ||||
513 | if (!def) | |||
514 | return superloop_at_depth (loop, 1); | |||
515 | ||||
516 | if (TREE_CODE (def)((enum tree_code) (def)->base.code) != SSA_NAME) | |||
517 | { | |||
518 | gcc_assert (is_gimple_min_invariant (def))((void)(!(is_gimple_min_invariant (def)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 518, __FUNCTION__), 0 : 0)); | |||
519 | return superloop_at_depth (loop, 1); | |||
520 | } | |||
521 | ||||
522 | def_stmt = SSA_NAME_DEF_STMT (def)(tree_check ((def), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 522, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
523 | def_bb = gimple_bb (def_stmt); | |||
524 | if (!def_bb) | |||
525 | return superloop_at_depth (loop, 1); | |||
526 | ||||
527 | max_loop = find_common_loop (loop, def_bb->loop_father); | |||
528 | ||||
529 | lim_data = get_lim_data (def_stmt); | |||
530 | if (lim_data != NULLnullptr && lim_data->max_loop != NULLnullptr) | |||
531 | max_loop = find_common_loop (max_loop, | |||
532 | loop_outer (lim_data->max_loop)); | |||
533 | if (max_loop == loop) | |||
534 | return NULLnullptr; | |||
535 | max_loop = superloop_at_depth (loop, loop_depth (max_loop) + 1); | |||
536 | ||||
537 | return max_loop; | |||
538 | } | |||
539 | ||||
540 | /* DATA is a structure containing information associated with a statement | |||
541 | inside LOOP. DEF is one of the operands of this statement. | |||
542 | ||||
543 | Find the outermost loop enclosing LOOP in that value of DEF is invariant | |||
544 | and record this in DATA->max_loop field. If DEF itself is defined inside | |||
545 | this loop as well (i.e. we need to hoist it out of the loop if we want | |||
546 | to hoist the statement represented by DATA), record the statement in that | |||
547 | DEF is defined to the DATA->depends list. Additionally if ADD_COST is true, | |||
548 | add the cost of the computation of DEF to the DATA->cost. | |||
549 | ||||
550 | If DEF is not invariant in LOOP, return false. Otherwise return TRUE. */ | |||
551 | ||||
552 | static bool | |||
553 | add_dependency (tree def, struct lim_aux_data *data, class loop *loop, | |||
554 | bool add_cost) | |||
555 | { | |||
556 | gimple *def_stmt = SSA_NAME_DEF_STMT (def)(tree_check ((def), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 556, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
557 | basic_block def_bb = gimple_bb (def_stmt); | |||
558 | class loop *max_loop; | |||
559 | struct lim_aux_data *def_data; | |||
560 | ||||
561 | if (!def_bb) | |||
562 | return true; | |||
563 | ||||
564 | max_loop = outermost_invariant_loop (def, loop); | |||
565 | if (!max_loop) | |||
566 | return false; | |||
567 | ||||
568 | if (flow_loop_nested_p (data->max_loop, max_loop)) | |||
569 | data->max_loop = max_loop; | |||
570 | ||||
571 | def_data = get_lim_data (def_stmt); | |||
572 | if (!def_data) | |||
573 | return true; | |||
574 | ||||
575 | if (add_cost | |||
576 | /* Only add the cost if the statement defining DEF is inside LOOP, | |||
577 | i.e. if it is likely that by moving the invariants dependent | |||
578 | on it, we will be able to avoid creating a new register for | |||
579 | it (since it will be only used in these dependent invariants). */ | |||
580 | && def_bb->loop_father == loop) | |||
581 | data->cost += def_data->cost; | |||
582 | ||||
583 | data->depends.safe_push (def_stmt); | |||
584 | ||||
585 | return true; | |||
586 | } | |||
587 | ||||
588 | /* Returns an estimate for a cost of statement STMT. The values here | |||
589 | are just ad-hoc constants, similar to costs for inlining. */ | |||
590 | ||||
591 | static unsigned | |||
592 | stmt_cost (gimple *stmt) | |||
593 | { | |||
594 | /* Always try to create possibilities for unswitching. */ | |||
595 | if (gimple_code (stmt) == GIMPLE_COND | |||
596 | || gimple_code (stmt) == GIMPLE_PHI) | |||
597 | return LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive); | |||
598 | ||||
599 | /* We should be hoisting calls if possible. */ | |||
600 | if (is_gimple_call (stmt)) | |||
601 | { | |||
602 | tree fndecl; | |||
603 | ||||
604 | /* Unless the call is a builtin_constant_p; this always folds to a | |||
605 | constant, so moving it is useless. */ | |||
606 | fndecl = gimple_call_fndecl (stmt); | |||
607 | if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_CONSTANT_P)) | |||
608 | return 0; | |||
609 | ||||
610 | return LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive); | |||
611 | } | |||
612 | ||||
613 | /* Hoisting memory references out should almost surely be a win. */ | |||
614 | if (gimple_references_memory_p (stmt)) | |||
615 | return LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive); | |||
616 | ||||
617 | if (gimple_code (stmt) != GIMPLE_ASSIGN) | |||
618 | return 1; | |||
619 | ||||
620 | switch (gimple_assign_rhs_code (stmt)) | |||
621 | { | |||
622 | case MULT_EXPR: | |||
623 | case WIDEN_MULT_EXPR: | |||
624 | case WIDEN_MULT_PLUS_EXPR: | |||
625 | case WIDEN_MULT_MINUS_EXPR: | |||
626 | case DOT_PROD_EXPR: | |||
627 | case TRUNC_DIV_EXPR: | |||
628 | case CEIL_DIV_EXPR: | |||
629 | case FLOOR_DIV_EXPR: | |||
630 | case ROUND_DIV_EXPR: | |||
631 | case EXACT_DIV_EXPR: | |||
632 | case CEIL_MOD_EXPR: | |||
633 | case FLOOR_MOD_EXPR: | |||
634 | case ROUND_MOD_EXPR: | |||
635 | case TRUNC_MOD_EXPR: | |||
636 | case RDIV_EXPR: | |||
637 | /* Division and multiplication are usually expensive. */ | |||
638 | return LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive); | |||
639 | ||||
640 | case LSHIFT_EXPR: | |||
641 | case RSHIFT_EXPR: | |||
642 | case WIDEN_LSHIFT_EXPR: | |||
643 | case LROTATE_EXPR: | |||
644 | case RROTATE_EXPR: | |||
645 | /* Shifts and rotates are usually expensive. */ | |||
646 | return LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive); | |||
647 | ||||
648 | case CONSTRUCTOR: | |||
649 | /* Make vector construction cost proportional to the number | |||
650 | of elements. */ | |||
651 | return CONSTRUCTOR_NELTS (gimple_assign_rhs1 (stmt))(vec_safe_length (((tree_check ((gimple_assign_rhs1 (stmt)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 651, __FUNCTION__, (CONSTRUCTOR)))->constructor.elts))); | |||
652 | ||||
653 | case SSA_NAME: | |||
654 | case PAREN_EXPR: | |||
655 | /* Whether or not something is wrapped inside a PAREN_EXPR | |||
656 | should not change move cost. Nor should an intermediate | |||
657 | unpropagated SSA name copy. */ | |||
658 | return 0; | |||
659 | ||||
660 | default: | |||
661 | return 1; | |||
662 | } | |||
663 | } | |||
664 | ||||
665 | /* Finds the outermost loop between OUTER and LOOP in that the memory reference | |||
666 | REF is independent. If REF is not independent in LOOP, NULL is returned | |||
667 | instead. */ | |||
668 | ||||
669 | static class loop * | |||
670 | outermost_indep_loop (class loop *outer, class loop *loop, im_mem_ref *ref) | |||
671 | { | |||
672 | class loop *aloop; | |||
673 | ||||
674 | if (ref->stored && bitmap_bit_p (ref->stored, loop->num)) | |||
675 | return NULLnullptr; | |||
676 | ||||
677 | for (aloop = outer; | |||
678 | aloop != loop; | |||
679 | aloop = superloop_at_depth (loop, loop_depth (aloop) + 1)) | |||
680 | if ((!ref->stored || !bitmap_bit_p (ref->stored, aloop->num)) | |||
681 | && ref_indep_loop_p (aloop, ref, lim_raw)) | |||
682 | return aloop; | |||
683 | ||||
684 | if (ref_indep_loop_p (loop, ref, lim_raw)) | |||
685 | return loop; | |||
686 | else | |||
687 | return NULLnullptr; | |||
688 | } | |||
689 | ||||
690 | /* If there is a simple load or store to a memory reference in STMT, returns | |||
691 | the location of the memory reference, and sets IS_STORE according to whether | |||
692 | it is a store or load. Otherwise, returns NULL. */ | |||
693 | ||||
694 | static tree * | |||
695 | simple_mem_ref_in_stmt (gimple *stmt, bool *is_store) | |||
696 | { | |||
697 | tree *lhs, *rhs; | |||
698 | ||||
699 | /* Recognize SSA_NAME = MEM and MEM = (SSA_NAME | invariant) patterns. */ | |||
700 | if (!gimple_assign_single_p (stmt)) | |||
701 | return NULLnullptr; | |||
702 | ||||
703 | lhs = gimple_assign_lhs_ptr (stmt); | |||
704 | rhs = gimple_assign_rhs1_ptr (stmt); | |||
705 | ||||
706 | if (TREE_CODE (*lhs)((enum tree_code) (*lhs)->base.code) == SSA_NAME && gimple_vuse (stmt)) | |||
707 | { | |||
708 | *is_store = false; | |||
709 | return rhs; | |||
710 | } | |||
711 | else if (gimple_vdef (stmt) | |||
712 | && (TREE_CODE (*rhs)((enum tree_code) (*rhs)->base.code) == SSA_NAME || is_gimple_min_invariant (*rhs))) | |||
713 | { | |||
714 | *is_store = true; | |||
715 | return lhs; | |||
716 | } | |||
717 | else | |||
718 | return NULLnullptr; | |||
719 | } | |||
720 | ||||
721 | /* From a controlling predicate in DOM determine the arguments from | |||
722 | the PHI node PHI that are chosen if the predicate evaluates to | |||
723 | true and false and store them to *TRUE_ARG_P and *FALSE_ARG_P if | |||
724 | they are non-NULL. Returns true if the arguments can be determined, | |||
725 | else return false. */ | |||
726 | ||||
727 | static bool | |||
728 | extract_true_false_args_from_phi (basic_block dom, gphi *phi, | |||
729 | tree *true_arg_p, tree *false_arg_p) | |||
730 | { | |||
731 | edge te, fe; | |||
732 | if (! extract_true_false_controlled_edges (dom, gimple_bb (phi), | |||
733 | &te, &fe)) | |||
734 | return false; | |||
735 | ||||
736 | if (true_arg_p) | |||
737 | *true_arg_p = PHI_ARG_DEF (phi, te->dest_idx)gimple_phi_arg_def ((phi), (te->dest_idx)); | |||
738 | if (false_arg_p) | |||
739 | *false_arg_p = PHI_ARG_DEF (phi, fe->dest_idx)gimple_phi_arg_def ((phi), (fe->dest_idx)); | |||
740 | ||||
741 | return true; | |||
742 | } | |||
743 | ||||
744 | /* Determine the outermost loop to that it is possible to hoist a statement | |||
745 | STMT and store it to LIM_DATA (STMT)->max_loop. To do this we determine | |||
746 | the outermost loop in that the value computed by STMT is invariant. | |||
747 | If MUST_PRESERVE_EXEC is true, additionally choose such a loop that | |||
748 | we preserve the fact whether STMT is executed. It also fills other related | |||
749 | information to LIM_DATA (STMT). | |||
750 | ||||
751 | The function returns false if STMT cannot be hoisted outside of the loop it | |||
752 | is defined in, and true otherwise. */ | |||
753 | ||||
754 | static bool | |||
755 | determine_max_movement (gimple *stmt, bool must_preserve_exec) | |||
756 | { | |||
757 | basic_block bb = gimple_bb (stmt); | |||
758 | class loop *loop = bb->loop_father; | |||
759 | class loop *level; | |||
760 | struct lim_aux_data *lim_data = get_lim_data (stmt); | |||
761 | tree val; | |||
762 | ssa_op_iter iter; | |||
763 | ||||
764 | if (must_preserve_exec) | |||
765 | level = ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux); | |||
766 | else | |||
767 | level = superloop_at_depth (loop, 1); | |||
768 | lim_data->max_loop = get_coldest_out_loop (level, loop, bb); | |||
769 | if (!lim_data->max_loop) | |||
770 | return false; | |||
771 | ||||
772 | if (gphi *phi = dyn_cast <gphi *> (stmt)) | |||
773 | { | |||
774 | use_operand_p use_p; | |||
775 | unsigned min_cost = UINT_MAX(2147483647 *2U +1U); | |||
776 | unsigned total_cost = 0; | |||
777 | struct lim_aux_data *def_data; | |||
778 | ||||
779 | /* We will end up promoting dependencies to be unconditionally | |||
780 | evaluated. For this reason the PHI cost (and thus the | |||
781 | cost we remove from the loop by doing the invariant motion) | |||
782 | is that of the cheapest PHI argument dependency chain. */ | |||
783 | FOR_EACH_PHI_ARG (use_p, phi, iter, SSA_OP_USE)for ((use_p) = op_iter_init_phiuse (&(iter), phi, 0x01); ! op_iter_done (&(iter)); (use_p) = op_iter_next_use (& (iter))) | |||
784 | { | |||
785 | val = USE_FROM_PTR (use_p)get_use_from_ptr (use_p); | |||
786 | ||||
787 | if (TREE_CODE (val)((enum tree_code) (val)->base.code) != SSA_NAME) | |||
788 | { | |||
789 | /* Assign const 1 to constants. */ | |||
790 | min_cost = MIN (min_cost, 1)((min_cost) < (1) ? (min_cost) : (1)); | |||
791 | total_cost += 1; | |||
792 | continue; | |||
793 | } | |||
794 | if (!add_dependency (val, lim_data, loop, false)) | |||
795 | return false; | |||
796 | ||||
797 | gimple *def_stmt = SSA_NAME_DEF_STMT (val)(tree_check ((val), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 797, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
798 | if (gimple_bb (def_stmt) | |||
799 | && gimple_bb (def_stmt)->loop_father == loop) | |||
800 | { | |||
801 | def_data = get_lim_data (def_stmt); | |||
802 | if (def_data) | |||
803 | { | |||
804 | min_cost = MIN (min_cost, def_data->cost)((min_cost) < (def_data->cost) ? (min_cost) : (def_data ->cost)); | |||
805 | total_cost += def_data->cost; | |||
806 | } | |||
807 | } | |||
808 | } | |||
809 | ||||
810 | min_cost = MIN (min_cost, total_cost)((min_cost) < (total_cost) ? (min_cost) : (total_cost)); | |||
811 | lim_data->cost += min_cost; | |||
812 | ||||
813 | if (gimple_phi_num_args (phi) > 1) | |||
814 | { | |||
815 | basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb); | |||
816 | gimple *cond; | |||
817 | if (gsi_end_p (gsi_last_bb (dom))) | |||
818 | return false; | |||
819 | cond = gsi_stmt (gsi_last_bb (dom)); | |||
820 | if (gimple_code (cond) != GIMPLE_COND) | |||
821 | return false; | |||
822 | /* Verify that this is an extended form of a diamond and | |||
823 | the PHI arguments are completely controlled by the | |||
824 | predicate in DOM. */ | |||
825 | if (!extract_true_false_args_from_phi (dom, phi, NULLnullptr, NULLnullptr)) | |||
826 | return false; | |||
827 | ||||
828 | /* Fold in dependencies and cost of the condition. */ | |||
829 | FOR_EACH_SSA_TREE_OPERAND (val, cond, iter, SSA_OP_USE)for (val = op_iter_init_tree (&(iter), cond, 0x01); !op_iter_done (&(iter)); (void) (val = op_iter_next_tree (&(iter)) )) | |||
830 | { | |||
831 | if (!add_dependency (val, lim_data, loop, false)) | |||
832 | return false; | |||
833 | def_data = get_lim_data (SSA_NAME_DEF_STMT (val)(tree_check ((val), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 833, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt); | |||
834 | if (def_data) | |||
835 | lim_data->cost += def_data->cost; | |||
836 | } | |||
837 | ||||
838 | /* We want to avoid unconditionally executing very expensive | |||
839 | operations. As costs for our dependencies cannot be | |||
840 | negative just claim we are not invariand for this case. | |||
841 | We also are not sure whether the control-flow inside the | |||
842 | loop will vanish. */ | |||
843 | if (total_cost - min_cost >= 2 * LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive) | |||
844 | && !(min_cost != 0 | |||
845 | && total_cost / min_cost <= 2)) | |||
846 | return false; | |||
847 | ||||
848 | /* Assume that the control-flow in the loop will vanish. | |||
849 | ??? We should verify this and not artificially increase | |||
850 | the cost if that is not the case. */ | |||
851 | lim_data->cost += stmt_cost (stmt); | |||
852 | } | |||
853 | ||||
854 | return true; | |||
855 | } | |||
856 | ||||
857 | /* A stmt that receives abnormal edges cannot be hoisted. */ | |||
858 | if (is_a <gcall *> (stmt) | |||
859 | && (gimple_call_flags (stmt) & ECF_RETURNS_TWICE(1 << 7))) | |||
860 | return false; | |||
861 | ||||
862 | FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_USE)for (val = op_iter_init_tree (&(iter), stmt, 0x01); !op_iter_done (&(iter)); (void) (val = op_iter_next_tree (&(iter)) )) | |||
863 | if (!add_dependency (val, lim_data, loop, true)) | |||
864 | return false; | |||
865 | ||||
866 | if (gimple_vuse (stmt)) | |||
867 | { | |||
868 | im_mem_ref *ref | |||
869 | = lim_data ? memory_accesses.refs_list[lim_data->ref] : NULLnullptr; | |||
870 | if (ref | |||
871 | && MEM_ANALYZABLE (ref)((ref)->id != 0)) | |||
872 | { | |||
873 | lim_data->max_loop = outermost_indep_loop (lim_data->max_loop, | |||
874 | loop, ref); | |||
875 | if (!lim_data->max_loop) | |||
876 | return false; | |||
877 | } | |||
878 | else if (! add_dependency (gimple_vuse (stmt), lim_data, loop, false)) | |||
879 | return false; | |||
880 | } | |||
881 | ||||
882 | lim_data->cost += stmt_cost (stmt); | |||
883 | ||||
884 | return true; | |||
885 | } | |||
886 | ||||
887 | /* Suppose that some statement in ORIG_LOOP is hoisted to the loop LEVEL, | |||
888 | and that one of the operands of this statement is computed by STMT. | |||
889 | Ensure that STMT (together with all the statements that define its | |||
890 | operands) is hoisted at least out of the loop LEVEL. */ | |||
891 | ||||
892 | static void | |||
893 | set_level (gimple *stmt, class loop *orig_loop, class loop *level) | |||
894 | { | |||
895 | class loop *stmt_loop = gimple_bb (stmt)->loop_father; | |||
896 | struct lim_aux_data *lim_data; | |||
897 | gimple *dep_stmt; | |||
898 | unsigned i; | |||
899 | ||||
900 | stmt_loop = find_common_loop (orig_loop, stmt_loop); | |||
901 | lim_data = get_lim_data (stmt); | |||
902 | if (lim_data != NULLnullptr && lim_data->tgt_loop != NULLnullptr) | |||
903 | stmt_loop = find_common_loop (stmt_loop, | |||
904 | loop_outer (lim_data->tgt_loop)); | |||
905 | if (flow_loop_nested_p (stmt_loop, level)) | |||
906 | return; | |||
907 | ||||
908 | gcc_assert (level == lim_data->max_loop((void)(!(level == lim_data->max_loop || flow_loop_nested_p (lim_data->max_loop, level)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 909, __FUNCTION__), 0 : 0)) | |||
909 | || flow_loop_nested_p (lim_data->max_loop, level))((void)(!(level == lim_data->max_loop || flow_loop_nested_p (lim_data->max_loop, level)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 909, __FUNCTION__), 0 : 0)); | |||
910 | ||||
911 | lim_data->tgt_loop = level; | |||
912 | FOR_EACH_VEC_ELT (lim_data->depends, i, dep_stmt)for (i = 0; (lim_data->depends).iterate ((i), &(dep_stmt )); ++(i)) | |||
913 | set_level (dep_stmt, orig_loop, level); | |||
914 | } | |||
915 | ||||
916 | /* Determines an outermost loop from that we want to hoist the statement STMT. | |||
917 | For now we chose the outermost possible loop. TODO -- use profiling | |||
918 | information to set it more sanely. */ | |||
919 | ||||
920 | static void | |||
921 | set_profitable_level (gimple *stmt) | |||
922 | { | |||
923 | set_level (stmt, gimple_bb (stmt)->loop_father, get_lim_data (stmt)->max_loop); | |||
924 | } | |||
925 | ||||
926 | /* Returns true if STMT is a call that has side effects. */ | |||
927 | ||||
928 | static bool | |||
929 | nonpure_call_p (gimple *stmt) | |||
930 | { | |||
931 | if (gimple_code (stmt) != GIMPLE_CALL) | |||
932 | return false; | |||
933 | ||||
934 | return gimple_has_side_effects (stmt); | |||
935 | } | |||
936 | ||||
937 | /* Rewrite a/b to a*(1/b). Return the invariant stmt to process. */ | |||
938 | ||||
939 | static gimple * | |||
940 | rewrite_reciprocal (gimple_stmt_iterator *bsi) | |||
941 | { | |||
942 | gassign *stmt, *stmt1, *stmt2; | |||
943 | tree name, lhs, type; | |||
944 | tree real_one; | |||
945 | gimple_stmt_iterator gsi; | |||
946 | ||||
947 | stmt = as_a <gassign *> (gsi_stmt (*bsi)); | |||
948 | lhs = gimple_assign_lhs (stmt); | |||
949 | type = TREE_TYPE (lhs)((contains_struct_check ((lhs), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 949, __FUNCTION__))->typed.type); | |||
950 | ||||
951 | real_one = build_one_cst (type); | |||
952 | ||||
953 | name = make_temp_ssa_name (type, NULLnullptr, "reciptmp"); | |||
954 | stmt1 = gimple_build_assign (name, RDIV_EXPR, real_one, | |||
955 | gimple_assign_rhs2 (stmt)); | |||
956 | stmt2 = gimple_build_assign (lhs, MULT_EXPR, name, | |||
957 | gimple_assign_rhs1 (stmt)); | |||
958 | ||||
959 | /* Replace division stmt with reciprocal and multiply stmts. | |||
960 | The multiply stmt is not invariant, so update iterator | |||
961 | and avoid rescanning. */ | |||
962 | gsi = *bsi; | |||
963 | gsi_insert_before (bsi, stmt1, GSI_NEW_STMT); | |||
964 | gsi_replace (&gsi, stmt2, true); | |||
965 | ||||
966 | /* Continue processing with invariant reciprocal statement. */ | |||
967 | return stmt1; | |||
968 | } | |||
969 | ||||
970 | /* Check if the pattern at *BSI is a bittest of the form | |||
971 | (A >> B) & 1 != 0 and in this case rewrite it to A & (1 << B) != 0. */ | |||
972 | ||||
973 | static gimple * | |||
974 | rewrite_bittest (gimple_stmt_iterator *bsi) | |||
975 | { | |||
976 | gassign *stmt; | |||
977 | gimple *stmt1; | |||
978 | gassign *stmt2; | |||
979 | gimple *use_stmt; | |||
980 | gcond *cond_stmt; | |||
981 | tree lhs, name, t, a, b; | |||
982 | use_operand_p use; | |||
983 | ||||
984 | stmt = as_a <gassign *> (gsi_stmt (*bsi)); | |||
985 | lhs = gimple_assign_lhs (stmt); | |||
986 | ||||
987 | /* Verify that the single use of lhs is a comparison against zero. */ | |||
988 | if (TREE_CODE (lhs)((enum tree_code) (lhs)->base.code) != SSA_NAME | |||
989 | || !single_imm_use (lhs, &use, &use_stmt)) | |||
990 | return stmt; | |||
991 | cond_stmt = dyn_cast <gcond *> (use_stmt); | |||
992 | if (!cond_stmt) | |||
993 | return stmt; | |||
994 | if (gimple_cond_lhs (cond_stmt) != lhs | |||
995 | || (gimple_cond_code (cond_stmt) != NE_EXPR | |||
996 | && gimple_cond_code (cond_stmt) != EQ_EXPR) | |||
997 | || !integer_zerop (gimple_cond_rhs (cond_stmt))) | |||
998 | return stmt; | |||
999 | ||||
1000 | /* Get at the operands of the shift. The rhs is TMP1 & 1. */ | |||
1001 | stmt1 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt))(tree_check ((gimple_assign_rhs1 (stmt)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1001, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1002 | if (gimple_code (stmt1) != GIMPLE_ASSIGN) | |||
1003 | return stmt; | |||
1004 | ||||
1005 | /* There is a conversion in between possibly inserted by fold. */ | |||
1006 | if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt1))((gimple_assign_rhs_code (stmt1)) == NOP_EXPR || (gimple_assign_rhs_code (stmt1)) == CONVERT_EXPR)) | |||
1007 | { | |||
1008 | t = gimple_assign_rhs1 (stmt1); | |||
1009 | if (TREE_CODE (t)((enum tree_code) (t)->base.code) != SSA_NAME | |||
1010 | || !has_single_use (t)) | |||
1011 | return stmt; | |||
1012 | stmt1 = SSA_NAME_DEF_STMT (t)(tree_check ((t), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1012, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1013 | if (gimple_code (stmt1) != GIMPLE_ASSIGN) | |||
1014 | return stmt; | |||
1015 | } | |||
1016 | ||||
1017 | /* Verify that B is loop invariant but A is not. Verify that with | |||
1018 | all the stmt walking we are still in the same loop. */ | |||
1019 | if (gimple_assign_rhs_code (stmt1) != RSHIFT_EXPR | |||
1020 | || loop_containing_stmt (stmt1) != loop_containing_stmt (stmt)) | |||
1021 | return stmt; | |||
1022 | ||||
1023 | a = gimple_assign_rhs1 (stmt1); | |||
1024 | b = gimple_assign_rhs2 (stmt1); | |||
1025 | ||||
1026 | if (outermost_invariant_loop (b, loop_containing_stmt (stmt1)) != NULLnullptr | |||
1027 | && outermost_invariant_loop (a, loop_containing_stmt (stmt1)) == NULLnullptr) | |||
1028 | { | |||
1029 | gimple_stmt_iterator rsi; | |||
1030 | ||||
1031 | /* 1 << B */ | |||
1032 | t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (a),fold_build2_loc (((location_t) 0), LSHIFT_EXPR, ((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1032, __FUNCTION__))->typed.type), build_int_cst (((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1033, __FUNCTION__))->typed.type), 1), b ) | |||
1033 | build_int_cst (TREE_TYPE (a), 1), b)fold_build2_loc (((location_t) 0), LSHIFT_EXPR, ((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1032, __FUNCTION__))->typed.type), build_int_cst (((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1033, __FUNCTION__))->typed.type), 1), b ); | |||
1034 | name = make_temp_ssa_name (TREE_TYPE (a)((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1034, __FUNCTION__))->typed.type), NULLnullptr, "shifttmp"); | |||
1035 | stmt1 = gimple_build_assign (name, t); | |||
1036 | ||||
1037 | /* A & (1 << B) */ | |||
1038 | t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (a), a, name)fold_build2_loc (((location_t) 0), BIT_AND_EXPR, ((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1038, __FUNCTION__))->typed.type), a, name ); | |||
1039 | name = make_temp_ssa_name (TREE_TYPE (a)((contains_struct_check ((a), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1039, __FUNCTION__))->typed.type), NULLnullptr, "shifttmp"); | |||
1040 | stmt2 = gimple_build_assign (name, t); | |||
1041 | ||||
1042 | /* Replace the SSA_NAME we compare against zero. Adjust | |||
1043 | the type of zero accordingly. */ | |||
1044 | SET_USE (use, name)set_ssa_use_from_ptr (use, name); | |||
1045 | gimple_cond_set_rhs (cond_stmt, | |||
1046 | build_int_cst_type (TREE_TYPE (name)((contains_struct_check ((name), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1046, __FUNCTION__))->typed.type), | |||
1047 | 0)); | |||
1048 | ||||
1049 | /* Don't use gsi_replace here, none of the new assignments sets | |||
1050 | the variable originally set in stmt. Move bsi to stmt1, and | |||
1051 | then remove the original stmt, so that we get a chance to | |||
1052 | retain debug info for it. */ | |||
1053 | rsi = *bsi; | |||
1054 | gsi_insert_before (bsi, stmt1, GSI_NEW_STMT); | |||
1055 | gsi_insert_before (&rsi, stmt2, GSI_SAME_STMT); | |||
1056 | gimple *to_release = gsi_stmt (rsi); | |||
1057 | gsi_remove (&rsi, true); | |||
1058 | release_defs (to_release); | |||
1059 | ||||
1060 | return stmt1; | |||
1061 | } | |||
1062 | ||||
1063 | return stmt; | |||
1064 | } | |||
1065 | ||||
1066 | /* Determine the outermost loops in that statements in basic block BB are | |||
1067 | invariant, and record them to the LIM_DATA associated with the | |||
1068 | statements. */ | |||
1069 | ||||
1070 | static void | |||
1071 | compute_invariantness (basic_block bb) | |||
1072 | { | |||
1073 | enum move_pos pos; | |||
1074 | gimple_stmt_iterator bsi; | |||
1075 | gimple *stmt; | |||
1076 | bool maybe_never = ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) == NULLnullptr; | |||
1077 | class loop *outermost = ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux); | |||
1078 | struct lim_aux_data *lim_data; | |||
1079 | ||||
1080 | if (!loop_outer (bb->loop_father)) | |||
1081 | return; | |||
1082 | ||||
1083 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1084 | fprintf (dump_file, "Basic block %d (loop %d -- depth %d):\n\n", | |||
1085 | bb->index, bb->loop_father->num, loop_depth (bb->loop_father)); | |||
1086 | ||||
1087 | /* Look at PHI nodes, but only if there is at most two. | |||
1088 | ??? We could relax this further by post-processing the inserted | |||
1089 | code and transforming adjacent cond-exprs with the same predicate | |||
1090 | to control flow again. */ | |||
1091 | bsi = gsi_start_phis (bb); | |||
1092 | if (!gsi_end_p (bsi) | |||
1093 | && ((gsi_next (&bsi), gsi_end_p (bsi)) | |||
1094 | || (gsi_next (&bsi), gsi_end_p (bsi)))) | |||
1095 | for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi)) | |||
1096 | { | |||
1097 | stmt = gsi_stmt (bsi); | |||
1098 | ||||
1099 | pos = movement_possibility (stmt); | |||
1100 | if (pos == MOVE_IMPOSSIBLE) | |||
1101 | continue; | |||
1102 | ||||
1103 | lim_data = get_lim_data (stmt); | |||
1104 | if (! lim_data) | |||
1105 | lim_data = init_lim_data (stmt); | |||
1106 | lim_data->always_executed_in = outermost; | |||
1107 | ||||
1108 | if (!determine_max_movement (stmt, false)) | |||
1109 | { | |||
1110 | lim_data->max_loop = NULLnullptr; | |||
1111 | continue; | |||
1112 | } | |||
1113 | ||||
1114 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1115 | { | |||
1116 | print_gimple_stmt (dump_file, stmt, 2); | |||
1117 | fprintf (dump_file, " invariant up to level %d, cost %d.\n\n", | |||
1118 | loop_depth (lim_data->max_loop), | |||
1119 | lim_data->cost); | |||
1120 | } | |||
1121 | ||||
1122 | if (lim_data->cost >= LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive)) | |||
1123 | set_profitable_level (stmt); | |||
1124 | } | |||
1125 | ||||
1126 | for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) | |||
1127 | { | |||
1128 | stmt = gsi_stmt (bsi); | |||
1129 | ||||
1130 | pos = movement_possibility (stmt); | |||
1131 | if (pos == MOVE_IMPOSSIBLE) | |||
1132 | { | |||
1133 | if (nonpure_call_p (stmt)) | |||
1134 | { | |||
1135 | maybe_never = true; | |||
1136 | outermost = NULLnullptr; | |||
1137 | } | |||
1138 | /* Make sure to note always_executed_in for stores to make | |||
1139 | store-motion work. */ | |||
1140 | else if (stmt_makes_single_store (stmt)) | |||
1141 | { | |||
1142 | struct lim_aux_data *lim_data = get_lim_data (stmt); | |||
1143 | if (! lim_data) | |||
1144 | lim_data = init_lim_data (stmt); | |||
1145 | lim_data->always_executed_in = outermost; | |||
1146 | } | |||
1147 | continue; | |||
1148 | } | |||
1149 | ||||
1150 | if (is_gimple_assign (stmt) | |||
1151 | && (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) | |||
1152 | == GIMPLE_BINARY_RHS)) | |||
1153 | { | |||
1154 | tree op0 = gimple_assign_rhs1 (stmt); | |||
1155 | tree op1 = gimple_assign_rhs2 (stmt); | |||
1156 | class loop *ol1 = outermost_invariant_loop (op1, | |||
1157 | loop_containing_stmt (stmt)); | |||
1158 | ||||
1159 | /* If divisor is invariant, convert a/b to a*(1/b), allowing reciprocal | |||
1160 | to be hoisted out of loop, saving expensive divide. */ | |||
1161 | if (pos == MOVE_POSSIBLE | |||
1162 | && gimple_assign_rhs_code (stmt) == RDIV_EXPR | |||
1163 | && flag_unsafe_math_optimizationsglobal_options.x_flag_unsafe_math_optimizations | |||
1164 | && !flag_trapping_mathglobal_options.x_flag_trapping_math | |||
1165 | && ol1 != NULLnullptr | |||
1166 | && outermost_invariant_loop (op0, ol1) == NULLnullptr) | |||
1167 | stmt = rewrite_reciprocal (&bsi); | |||
1168 | ||||
1169 | /* If the shift count is invariant, convert (A >> B) & 1 to | |||
1170 | A & (1 << B) allowing the bit mask to be hoisted out of the loop | |||
1171 | saving an expensive shift. */ | |||
1172 | if (pos == MOVE_POSSIBLE | |||
1173 | && gimple_assign_rhs_code (stmt) == BIT_AND_EXPR | |||
1174 | && integer_onep (op1) | |||
1175 | && TREE_CODE (op0)((enum tree_code) (op0)->base.code) == SSA_NAME | |||
1176 | && has_single_use (op0)) | |||
1177 | stmt = rewrite_bittest (&bsi); | |||
1178 | } | |||
1179 | ||||
1180 | lim_data = get_lim_data (stmt); | |||
1181 | if (! lim_data) | |||
1182 | lim_data = init_lim_data (stmt); | |||
1183 | lim_data->always_executed_in = outermost; | |||
1184 | ||||
1185 | if (maybe_never && pos == MOVE_PRESERVE_EXECUTION) | |||
1186 | continue; | |||
1187 | ||||
1188 | if (!determine_max_movement (stmt, pos == MOVE_PRESERVE_EXECUTION)) | |||
1189 | { | |||
1190 | lim_data->max_loop = NULLnullptr; | |||
1191 | continue; | |||
1192 | } | |||
1193 | ||||
1194 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1195 | { | |||
1196 | print_gimple_stmt (dump_file, stmt, 2); | |||
1197 | fprintf (dump_file, " invariant up to level %d, cost %d.\n\n", | |||
1198 | loop_depth (lim_data->max_loop), | |||
1199 | lim_data->cost); | |||
1200 | } | |||
1201 | ||||
1202 | if (lim_data->cost >= LIM_EXPENSIVE((unsigned) global_options.x_param_lim_expensive)) | |||
1203 | set_profitable_level (stmt); | |||
1204 | } | |||
1205 | } | |||
1206 | ||||
1207 | /* Hoist the statements in basic block BB out of the loops prescribed by | |||
1208 | data stored in LIM_DATA structures associated with each statement. Callback | |||
1209 | for walk_dominator_tree. */ | |||
1210 | ||||
1211 | unsigned int | |||
1212 | move_computations_worker (basic_block bb) | |||
1213 | { | |||
1214 | class loop *level; | |||
1215 | unsigned cost = 0; | |||
1216 | struct lim_aux_data *lim_data; | |||
1217 | unsigned int todo = 0; | |||
1218 | ||||
1219 | if (!loop_outer (bb->loop_father)) | |||
1220 | return todo; | |||
1221 | ||||
1222 | for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi); ) | |||
1223 | { | |||
1224 | gassign *new_stmt; | |||
1225 | gphi *stmt = bsi.phi (); | |||
1226 | ||||
1227 | lim_data = get_lim_data (stmt); | |||
1228 | if (lim_data == NULLnullptr) | |||
1229 | { | |||
1230 | gsi_next (&bsi); | |||
1231 | continue; | |||
1232 | } | |||
1233 | ||||
1234 | cost = lim_data->cost; | |||
1235 | level = lim_data->tgt_loop; | |||
1236 | clear_lim_data (stmt); | |||
1237 | ||||
1238 | if (!level) | |||
1239 | { | |||
1240 | gsi_next (&bsi); | |||
1241 | continue; | |||
1242 | } | |||
1243 | ||||
1244 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1245 | { | |||
1246 | fprintf (dump_file, "Moving PHI node\n"); | |||
1247 | print_gimple_stmt (dump_file, stmt, 0); | |||
1248 | fprintf (dump_file, "(cost %u) out of loop %d.\n\n", | |||
1249 | cost, level->num); | |||
1250 | } | |||
1251 | ||||
1252 | if (gimple_phi_num_args (stmt) == 1) | |||
1253 | { | |||
1254 | tree arg = PHI_ARG_DEF (stmt, 0)gimple_phi_arg_def ((stmt), (0)); | |||
1255 | new_stmt = gimple_build_assign (gimple_phi_result (stmt), | |||
1256 | TREE_CODE (arg)((enum tree_code) (arg)->base.code), arg); | |||
1257 | } | |||
1258 | else | |||
1259 | { | |||
1260 | basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb); | |||
1261 | gimple *cond = gsi_stmt (gsi_last_bb (dom)); | |||
1262 | tree arg0 = NULL_TREE(tree) nullptr, arg1 = NULL_TREE(tree) nullptr, t; | |||
1263 | /* Get the PHI arguments corresponding to the true and false | |||
1264 | edges of COND. */ | |||
1265 | extract_true_false_args_from_phi (dom, stmt, &arg0, &arg1); | |||
1266 | gcc_assert (arg0 && arg1)((void)(!(arg0 && arg1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1266, __FUNCTION__), 0 : 0)); | |||
1267 | t = make_ssa_name (boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE]); | |||
1268 | new_stmt = gimple_build_assign (t, gimple_cond_code (cond), | |||
1269 | gimple_cond_lhs (cond), | |||
1270 | gimple_cond_rhs (cond)); | |||
1271 | gsi_insert_on_edge (loop_preheader_edge (level), new_stmt); | |||
1272 | new_stmt = gimple_build_assign (gimple_phi_result (stmt), | |||
1273 | COND_EXPR, t, arg0, arg1); | |||
1274 | todo |= TODO_cleanup_cfg(1 << 5); | |||
1275 | } | |||
1276 | if (!ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) | |||
1277 | || (ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) != level | |||
1278 | && !flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux), level))) | |||
1279 | reset_flow_sensitive_info (gimple_assign_lhs (new_stmt)); | |||
1280 | gsi_insert_on_edge (loop_preheader_edge (level), new_stmt); | |||
1281 | remove_phi_node (&bsi, false); | |||
1282 | } | |||
1283 | ||||
1284 | for (gimple_stmt_iterator bsi = gsi_start_bb (bb); !gsi_end_p (bsi); ) | |||
1285 | { | |||
1286 | edge e; | |||
1287 | ||||
1288 | gimple *stmt = gsi_stmt (bsi); | |||
1289 | ||||
1290 | lim_data = get_lim_data (stmt); | |||
1291 | if (lim_data == NULLnullptr) | |||
1292 | { | |||
1293 | gsi_next (&bsi); | |||
1294 | continue; | |||
1295 | } | |||
1296 | ||||
1297 | cost = lim_data->cost; | |||
1298 | level = lim_data->tgt_loop; | |||
1299 | clear_lim_data (stmt); | |||
1300 | ||||
1301 | if (!level) | |||
1302 | { | |||
1303 | gsi_next (&bsi); | |||
1304 | continue; | |||
1305 | } | |||
1306 | ||||
1307 | /* We do not really want to move conditionals out of the loop; we just | |||
1308 | placed it here to force its operands to be moved if necessary. */ | |||
1309 | if (gimple_code (stmt) == GIMPLE_COND) | |||
1310 | { | |||
1311 | gsi_next (&bsi); | |||
1312 | continue; | |||
1313 | } | |||
1314 | ||||
1315 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1316 | { | |||
1317 | fprintf (dump_file, "Moving statement\n"); | |||
1318 | print_gimple_stmt (dump_file, stmt, 0); | |||
1319 | fprintf (dump_file, "(cost %u) out of loop %d.\n\n", | |||
1320 | cost, level->num); | |||
1321 | } | |||
1322 | ||||
1323 | e = loop_preheader_edge (level); | |||
1324 | gcc_assert (!gimple_vdef (stmt))((void)(!(!gimple_vdef (stmt)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1324, __FUNCTION__), 0 : 0)); | |||
1325 | if (gimple_vuse (stmt)) | |||
1326 | { | |||
1327 | /* The new VUSE is the one from the virtual PHI in the loop | |||
1328 | header or the one already present. */ | |||
1329 | gphi_iterator gsi2; | |||
1330 | for (gsi2 = gsi_start_phis (e->dest); | |||
1331 | !gsi_end_p (gsi2); gsi_next (&gsi2)) | |||
1332 | { | |||
1333 | gphi *phi = gsi2.phi (); | |||
1334 | if (virtual_operand_p (gimple_phi_result (phi))) | |||
1335 | { | |||
1336 | SET_USE (gimple_vuse_op (stmt),set_ssa_use_from_ptr (gimple_vuse_op (stmt), gimple_phi_arg_def (((phi)), ((e)->dest_idx))) | |||
1337 | PHI_ARG_DEF_FROM_EDGE (phi, e))set_ssa_use_from_ptr (gimple_vuse_op (stmt), gimple_phi_arg_def (((phi)), ((e)->dest_idx))); | |||
1338 | break; | |||
1339 | } | |||
1340 | } | |||
1341 | } | |||
1342 | gsi_remove (&bsi, false); | |||
1343 | if (gimple_has_lhs (stmt) | |||
1344 | && TREE_CODE (gimple_get_lhs (stmt))((enum tree_code) (gimple_get_lhs (stmt))->base.code) == SSA_NAME | |||
1345 | && (!ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) | |||
1346 | || !(ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) == level | |||
1347 | || flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux), level)))) | |||
1348 | reset_flow_sensitive_info (gimple_get_lhs (stmt)); | |||
1349 | /* In case this is a stmt that is not unconditionally executed | |||
1350 | when the target loop header is executed and the stmt may | |||
1351 | invoke undefined integer or pointer overflow rewrite it to | |||
1352 | unsigned arithmetic. */ | |||
1353 | if (is_gimple_assign (stmt) | |||
1354 | && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt)))(((enum tree_code) (((contains_struct_check ((gimple_assign_lhs (stmt)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1354, __FUNCTION__))->typed.type))->base.code) == ENUMERAL_TYPE || ((enum tree_code) (((contains_struct_check ((gimple_assign_lhs (stmt)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1354, __FUNCTION__))->typed.type))->base.code) == BOOLEAN_TYPE || ((enum tree_code) (((contains_struct_check ((gimple_assign_lhs (stmt)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1354, __FUNCTION__))->typed.type))->base.code) == INTEGER_TYPE ) | |||
1355 | && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (gimple_assign_lhs (stmt)))((((enum tree_code) (((contains_struct_check ((gimple_assign_lhs (stmt)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1355, __FUNCTION__))->typed.type))->base.code) == POINTER_TYPE || ((enum tree_code) (((contains_struct_check ((gimple_assign_lhs (stmt)), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1355, __FUNCTION__))->typed.type))->base.code) == REFERENCE_TYPE ) ? !global_options.x_flag_wrapv_pointer : (!(any_integral_type_check ((((contains_struct_check ((gimple_assign_lhs (stmt)), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1355, __FUNCTION__))->typed.type)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1355, __FUNCTION__))->base.u.bits.unsigned_flag && !global_options.x_flag_wrapv && !global_options.x_flag_trapv )) | |||
1356 | && arith_code_with_undefined_signed_overflow | |||
1357 | (gimple_assign_rhs_code (stmt)) | |||
1358 | && (!ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) | |||
1359 | || !(ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux) == level | |||
1360 | || flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb)((class loop *) (bb)->aux), level)))) | |||
1361 | gsi_insert_seq_on_edge (e, rewrite_to_defined_overflow (stmt)); | |||
1362 | else | |||
1363 | gsi_insert_on_edge (e, stmt); | |||
1364 | } | |||
1365 | ||||
1366 | return todo; | |||
1367 | } | |||
1368 | ||||
1369 | /* Checks whether the statement defining variable *INDEX can be hoisted | |||
1370 | out of the loop passed in DATA. Callback for for_each_index. */ | |||
1371 | ||||
1372 | static bool | |||
1373 | may_move_till (tree ref, tree *index, void *data) | |||
1374 | { | |||
1375 | class loop *loop = (class loop *) data, *max_loop; | |||
1376 | ||||
1377 | /* If REF is an array reference, check also that the step and the lower | |||
1378 | bound is invariant in LOOP. */ | |||
1379 | if (TREE_CODE (ref)((enum tree_code) (ref)->base.code) == ARRAY_REF) | |||
1380 | { | |||
1381 | tree step = TREE_OPERAND (ref, 3)(*((const_cast<tree*> (tree_operand_check ((ref), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1381, __FUNCTION__))))); | |||
1382 | tree lbound = TREE_OPERAND (ref, 2)(*((const_cast<tree*> (tree_operand_check ((ref), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1382, __FUNCTION__))))); | |||
1383 | ||||
1384 | max_loop = outermost_invariant_loop (step, loop); | |||
1385 | if (!max_loop) | |||
1386 | return false; | |||
1387 | ||||
1388 | max_loop = outermost_invariant_loop (lbound, loop); | |||
1389 | if (!max_loop) | |||
1390 | return false; | |||
1391 | } | |||
1392 | ||||
1393 | max_loop = outermost_invariant_loop (*index, loop); | |||
1394 | if (!max_loop) | |||
1395 | return false; | |||
1396 | ||||
1397 | return true; | |||
1398 | } | |||
1399 | ||||
1400 | /* If OP is SSA NAME, force the statement that defines it to be | |||
1401 | moved out of the LOOP. ORIG_LOOP is the loop in that EXPR is used. */ | |||
1402 | ||||
1403 | static void | |||
1404 | force_move_till_op (tree op, class loop *orig_loop, class loop *loop) | |||
1405 | { | |||
1406 | gimple *stmt; | |||
1407 | ||||
1408 | if (!op | |||
1409 | || is_gimple_min_invariant (op)) | |||
1410 | return; | |||
1411 | ||||
1412 | gcc_assert (TREE_CODE (op) == SSA_NAME)((void)(!(((enum tree_code) (op)->base.code) == SSA_NAME) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1412, __FUNCTION__), 0 : 0)); | |||
1413 | ||||
1414 | stmt = SSA_NAME_DEF_STMT (op)(tree_check ((op), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1414, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
1415 | if (gimple_nop_p (stmt)) | |||
1416 | return; | |||
1417 | ||||
1418 | set_level (stmt, orig_loop, loop); | |||
1419 | } | |||
1420 | ||||
1421 | /* Forces statement defining invariants in REF (and *INDEX) to be moved out of | |||
1422 | the LOOP. The reference REF is used in the loop ORIG_LOOP. Callback for | |||
1423 | for_each_index. */ | |||
1424 | ||||
1425 | struct fmt_data | |||
1426 | { | |||
1427 | class loop *loop; | |||
1428 | class loop *orig_loop; | |||
1429 | }; | |||
1430 | ||||
1431 | static bool | |||
1432 | force_move_till (tree ref, tree *index, void *data) | |||
1433 | { | |||
1434 | struct fmt_data *fmt_data = (struct fmt_data *) data; | |||
1435 | ||||
1436 | if (TREE_CODE (ref)((enum tree_code) (ref)->base.code) == ARRAY_REF) | |||
1437 | { | |||
1438 | tree step = TREE_OPERAND (ref, 3)(*((const_cast<tree*> (tree_operand_check ((ref), (3), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1438, __FUNCTION__))))); | |||
1439 | tree lbound = TREE_OPERAND (ref, 2)(*((const_cast<tree*> (tree_operand_check ((ref), (2), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1439, __FUNCTION__))))); | |||
1440 | ||||
1441 | force_move_till_op (step, fmt_data->orig_loop, fmt_data->loop); | |||
1442 | force_move_till_op (lbound, fmt_data->orig_loop, fmt_data->loop); | |||
1443 | } | |||
1444 | ||||
1445 | force_move_till_op (*index, fmt_data->orig_loop, fmt_data->loop); | |||
1446 | ||||
1447 | return true; | |||
1448 | } | |||
1449 | ||||
1450 | /* A function to free the mem_ref object OBJ. */ | |||
1451 | ||||
1452 | static void | |||
1453 | memref_free (class im_mem_ref *mem) | |||
1454 | { | |||
1455 | mem->accesses_in_loop.release (); | |||
1456 | } | |||
1457 | ||||
1458 | /* Allocates and returns a memory reference description for MEM whose hash | |||
1459 | value is HASH and id is ID. */ | |||
1460 | ||||
1461 | static im_mem_ref * | |||
1462 | mem_ref_alloc (ao_ref *mem, unsigned hash, unsigned id) | |||
1463 | { | |||
1464 | im_mem_ref *ref = XOBNEW (&mem_ref_obstack, class im_mem_ref)((class im_mem_ref *) __extension__ ({ struct obstack *__h = ( (&mem_ref_obstack)); __extension__ ({ struct obstack *__o = (__h); size_t __len = ((sizeof (class im_mem_ref))); if (__extension__ ({ struct obstack const *__o1 = (__o); (size_t) (__o1->chunk_limit - __o1->next_free); }) < __len) _obstack_newchunk (__o , __len); ((void) ((__o)->next_free += (__len))); }); __extension__ ({ struct obstack *__o1 = (__h); void *__value = (void *) __o1 ->object_base; if (__o1->next_free == __value) __o1-> maybe_empty_object = 1; __o1->next_free = (sizeof (ptrdiff_t ) < sizeof (void *) ? ((__o1->object_base) + (((__o1-> next_free) - (__o1->object_base) + (__o1->alignment_mask )) & ~(__o1->alignment_mask))) : (char *) (((ptrdiff_t ) (__o1->next_free) + (__o1->alignment_mask)) & ~(__o1 ->alignment_mask))); if ((size_t) (__o1->next_free - (char *) __o1->chunk) > (size_t) (__o1->chunk_limit - (char *) __o1->chunk)) __o1->next_free = __o1->chunk_limit ; __o1->object_base = __o1->next_free; __value; }); })); | |||
1465 | if (mem) | |||
1466 | ref->mem = *mem; | |||
1467 | else | |||
1468 | ao_ref_init (&ref->mem, error_mark_nodeglobal_trees[TI_ERROR_MARK]); | |||
1469 | ref->id = id; | |||
1470 | ref->ref_canonical = false; | |||
1471 | ref->ref_decomposed = false; | |||
1472 | ref->hash = hash; | |||
1473 | ref->stored = NULLnullptr; | |||
1474 | ref->loaded = NULLnullptr; | |||
1475 | bitmap_initialize (&ref->dep_loop, &lim_bitmap_obstack); | |||
1476 | ref->accesses_in_loop.create (1); | |||
1477 | ||||
1478 | return ref; | |||
1479 | } | |||
1480 | ||||
1481 | /* Records memory reference location *LOC in LOOP to the memory reference | |||
1482 | description REF. The reference occurs in statement STMT. */ | |||
1483 | ||||
1484 | static void | |||
1485 | record_mem_ref_loc (im_mem_ref *ref, gimple *stmt, tree *loc) | |||
1486 | { | |||
1487 | mem_ref_loc aref; | |||
1488 | aref.stmt = stmt; | |||
1489 | aref.ref = loc; | |||
1490 | ref->accesses_in_loop.safe_push (aref); | |||
1491 | } | |||
1492 | ||||
1493 | /* Set the LOOP bit in REF stored bitmap and allocate that if | |||
1494 | necessary. Return whether a bit was changed. */ | |||
1495 | ||||
1496 | static bool | |||
1497 | set_ref_stored_in_loop (im_mem_ref *ref, class loop *loop) | |||
1498 | { | |||
1499 | if (!ref->stored) | |||
1500 | ref->stored = BITMAP_ALLOCbitmap_alloc (&lim_bitmap_obstack); | |||
1501 | return bitmap_set_bit (ref->stored, loop->num); | |||
1502 | } | |||
1503 | ||||
1504 | /* Marks reference REF as stored in LOOP. */ | |||
1505 | ||||
1506 | static void | |||
1507 | mark_ref_stored (im_mem_ref *ref, class loop *loop) | |||
1508 | { | |||
1509 | while (loop != current_loops((cfun + 0)->x_current_loops)->tree_root | |||
1510 | && set_ref_stored_in_loop (ref, loop)) | |||
1511 | loop = loop_outer (loop); | |||
1512 | } | |||
1513 | ||||
1514 | /* Set the LOOP bit in REF loaded bitmap and allocate that if | |||
1515 | necessary. Return whether a bit was changed. */ | |||
1516 | ||||
1517 | static bool | |||
1518 | set_ref_loaded_in_loop (im_mem_ref *ref, class loop *loop) | |||
1519 | { | |||
1520 | if (!ref->loaded) | |||
1521 | ref->loaded = BITMAP_ALLOCbitmap_alloc (&lim_bitmap_obstack); | |||
1522 | return bitmap_set_bit (ref->loaded, loop->num); | |||
1523 | } | |||
1524 | ||||
1525 | /* Marks reference REF as loaded in LOOP. */ | |||
1526 | ||||
1527 | static void | |||
1528 | mark_ref_loaded (im_mem_ref *ref, class loop *loop) | |||
1529 | { | |||
1530 | while (loop != current_loops((cfun + 0)->x_current_loops)->tree_root | |||
1531 | && set_ref_loaded_in_loop (ref, loop)) | |||
1532 | loop = loop_outer (loop); | |||
1533 | } | |||
1534 | ||||
1535 | /* Gathers memory references in statement STMT in LOOP, storing the | |||
1536 | information about them in the memory_accesses structure. Marks | |||
1537 | the vops accessed through unrecognized statements there as | |||
1538 | well. */ | |||
1539 | ||||
1540 | static void | |||
1541 | gather_mem_refs_stmt (class loop *loop, gimple *stmt) | |||
1542 | { | |||
1543 | tree *mem = NULLnullptr; | |||
1544 | hashval_t hash; | |||
1545 | im_mem_ref **slot; | |||
1546 | im_mem_ref *ref; | |||
1547 | bool is_stored; | |||
1548 | unsigned id; | |||
1549 | ||||
1550 | if (!gimple_vuse (stmt)) | |||
1551 | return; | |||
1552 | ||||
1553 | mem = simple_mem_ref_in_stmt (stmt, &is_stored); | |||
1554 | if (!mem
| |||
1555 | { | |||
1556 | /* For aggregate copies record distinct references but use them | |||
1557 | only for disambiguation purposes. */ | |||
1558 | id = memory_accesses.refs_list.length (); | |||
1559 | ref = mem_ref_alloc (NULLnullptr, 0, id); | |||
1560 | memory_accesses.refs_list.safe_push (ref); | |||
1561 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1562 | { | |||
1563 | fprintf (dump_file, "Unhandled memory reference %u: ", id); | |||
1564 | print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); | |||
1565 | } | |||
1566 | record_mem_ref_loc (ref, stmt, mem); | |||
1567 | is_stored = gimple_vdef (stmt); | |||
1568 | } | |||
1569 | else if (!mem
| |||
1570 | { | |||
1571 | /* We use the shared mem_ref for all unanalyzable refs. */ | |||
1572 | id = UNANALYZABLE_MEM_ID0; | |||
1573 | ref = memory_accesses.refs_list[id]; | |||
1574 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1575 | { | |||
1576 | fprintf (dump_file, "Unanalyzed memory reference %u: ", id); | |||
1577 | print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); | |||
1578 | } | |||
1579 | is_stored = gimple_vdef (stmt); | |||
1580 | } | |||
1581 | else | |||
1582 | { | |||
1583 | /* We are looking for equal refs that might differ in structure | |||
1584 | such as a.b vs. MEM[&a + 4]. So we key off the ao_ref but | |||
1585 | make sure we can canonicalize the ref in the hashtable if | |||
1586 | non-operand_equal_p refs are found. For the lookup we mark | |||
1587 | the case we want strict equality with aor.max_size == -1. */ | |||
1588 | ao_ref aor; | |||
1589 | ao_ref_init (&aor, *mem); | |||
1590 | ao_ref_base (&aor); | |||
1591 | ao_ref_alias_set (&aor); | |||
1592 | HOST_WIDE_INTlong offset, size, max_size; | |||
1593 | poly_int64 saved_maxsize = aor.max_size, mem_off; | |||
1594 | tree mem_base; | |||
1595 | bool ref_decomposed; | |||
1596 | if (aor.max_size_known_p () | |||
1597 | && aor.offset.is_constant (&offset) | |||
1598 | && aor.size.is_constant (&size) | |||
1599 | && aor.max_size.is_constant (&max_size) | |||
1600 | && size == max_size | |||
1601 | && (size % BITS_PER_UNIT(8)) == 0 | |||
1602 | /* We're canonicalizing to a MEM where TYPE_SIZE specifies the | |||
1603 | size. Make sure this is consistent with the extraction. */ | |||
1604 | && poly_int_tree_p (TYPE_SIZE (TREE_TYPE (*mem))((tree_class_check ((((contains_struct_check ((*mem), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1604, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1604, __FUNCTION__))->type_common.size)) | |||
1605 | && known_eq (wi::to_poly_offset (TYPE_SIZE (TREE_TYPE (*mem))),(!maybe_ne (wi::to_poly_offset (((tree_class_check ((((contains_struct_check ((*mem), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1605, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1605, __FUNCTION__))->type_common.size)), aor.size)) | |||
1606 | aor.size)(!maybe_ne (wi::to_poly_offset (((tree_class_check ((((contains_struct_check ((*mem), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1605, __FUNCTION__))->typed.type)), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1605, __FUNCTION__))->type_common.size)), aor.size)) | |||
1607 | && (mem_base = get_addr_base_and_unit_offset (aor.ref, &mem_off))) | |||
1608 | { | |||
1609 | ref_decomposed = true; | |||
1610 | tree base = ao_ref_base (&aor); | |||
1611 | poly_int64 moffset; | |||
1612 | HOST_WIDE_INTlong mcoffset; | |||
1613 | if (TREE_CODE (base)((enum tree_code) (base)->base.code) == MEM_REF | |||
1614 | && (mem_ref_offset (base) * BITS_PER_UNIT(8) + offset).to_shwi (&moffset) | |||
1615 | && moffset.is_constant (&mcoffset)) | |||
1616 | { | |||
1617 | hash = iterative_hash_expr (TREE_OPERAND (base, 0)(*((const_cast<tree*> (tree_operand_check ((base), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1617, __FUNCTION__))))), 0); | |||
1618 | hash = iterative_hash_host_wide_int (mcoffset, hash); | |||
1619 | } | |||
1620 | else | |||
1621 | { | |||
1622 | hash = iterative_hash_expr (base, 0); | |||
1623 | hash = iterative_hash_host_wide_int (offset, hash); | |||
1624 | } | |||
1625 | hash = iterative_hash_host_wide_int (size, hash); | |||
1626 | } | |||
1627 | else | |||
1628 | { | |||
1629 | ref_decomposed = false; | |||
1630 | hash = iterative_hash_expr (aor.ref, 0); | |||
1631 | aor.max_size = -1; | |||
1632 | } | |||
1633 | slot = memory_accesses.refs->find_slot_with_hash (&aor, hash, INSERT); | |||
1634 | aor.max_size = saved_maxsize; | |||
1635 | if (*slot) | |||
1636 | { | |||
1637 | if (!(*slot)->ref_canonical | |||
1638 | && !operand_equal_p (*mem, (*slot)->mem.ref, 0)) | |||
1639 | { | |||
1640 | /* If we didn't yet canonicalize the hashtable ref (which | |||
1641 | we'll end up using for code insertion) and hit a second | |||
1642 | equal ref that is not structurally equivalent create | |||
1643 | a canonical ref which is a bare MEM_REF. */ | |||
1644 | if (TREE_CODE (*mem)((enum tree_code) (*mem)->base.code) == MEM_REF | |||
1645 | || TREE_CODE (*mem)((enum tree_code) (*mem)->base.code) == TARGET_MEM_REF) | |||
1646 | { | |||
1647 | (*slot)->mem.ref = *mem; | |||
1648 | (*slot)->mem.base_alias_set = ao_ref_base_alias_set (&aor); | |||
1649 | } | |||
1650 | else | |||
1651 | { | |||
1652 | tree ref_alias_type = reference_alias_ptr_type (*mem); | |||
1653 | unsigned int ref_align = get_object_alignment (*mem); | |||
1654 | tree ref_type = TREE_TYPE (*mem)((contains_struct_check ((*mem), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1654, __FUNCTION__))->typed.type); | |||
1655 | tree tmp = build1 (ADDR_EXPR, ptr_type_nodeglobal_trees[TI_PTR_TYPE], | |||
1656 | unshare_expr (mem_base)); | |||
| ||||
1657 | if (TYPE_ALIGN (ref_type)(((tree_class_check ((ref_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1657, __FUNCTION__))->type_common.align) ? ((unsigned)1) << (((tree_class_check ((ref_type), (tcc_type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1657, __FUNCTION__))->type_common.align) - 1) : 0) != ref_align) | |||
1658 | ref_type = build_aligned_type (ref_type, ref_align); | |||
1659 | (*slot)->mem.ref | |||
1660 | = fold_build2 (MEM_REF, ref_type, tmp,fold_build2_loc (((location_t) 0), MEM_REF, ref_type, tmp, build_int_cst (ref_alias_type, mem_off) ) | |||
1661 | build_int_cst (ref_alias_type, mem_off))fold_build2_loc (((location_t) 0), MEM_REF, ref_type, tmp, build_int_cst (ref_alias_type, mem_off) ); | |||
1662 | if ((*slot)->mem.volatile_p) | |||
1663 | TREE_THIS_VOLATILE ((*slot)->mem.ref)(((*slot)->mem.ref)->base.volatile_flag) = 1; | |||
1664 | gcc_checking_assert (TREE_CODE ((*slot)->mem.ref) == MEM_REF((void)(!(((enum tree_code) ((*slot)->mem.ref)->base.code ) == MEM_REF && is_gimple_mem_ref_addr ((*((const_cast <tree*> (tree_operand_check (((*slot)->mem.ref), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__))))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__), 0 : 0)) | |||
1665 | && is_gimple_mem_ref_addr((void)(!(((enum tree_code) ((*slot)->mem.ref)->base.code ) == MEM_REF && is_gimple_mem_ref_addr ((*((const_cast <tree*> (tree_operand_check (((*slot)->mem.ref), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__))))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__), 0 : 0)) | |||
1666 | (TREE_OPERAND ((*slot)->mem.ref,((void)(!(((enum tree_code) ((*slot)->mem.ref)->base.code ) == MEM_REF && is_gimple_mem_ref_addr ((*((const_cast <tree*> (tree_operand_check (((*slot)->mem.ref), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__))))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__), 0 : 0)) | |||
1667 | 0)))((void)(!(((enum tree_code) ((*slot)->mem.ref)->base.code ) == MEM_REF && is_gimple_mem_ref_addr ((*((const_cast <tree*> (tree_operand_check (((*slot)->mem.ref), (0) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__))))))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1667, __FUNCTION__), 0 : 0)); | |||
1668 | (*slot)->mem.base_alias_set = (*slot)->mem.ref_alias_set; | |||
1669 | } | |||
1670 | (*slot)->ref_canonical = true; | |||
1671 | } | |||
1672 | ref = *slot; | |||
1673 | id = ref->id; | |||
1674 | } | |||
1675 | else | |||
1676 | { | |||
1677 | id = memory_accesses.refs_list.length (); | |||
1678 | ref = mem_ref_alloc (&aor, hash, id); | |||
1679 | ref->ref_decomposed = ref_decomposed; | |||
1680 | memory_accesses.refs_list.safe_push (ref); | |||
1681 | *slot = ref; | |||
1682 | ||||
1683 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
1684 | { | |||
1685 | fprintf (dump_file, "Memory reference %u: ", id); | |||
1686 | print_generic_expr (dump_file, ref->mem.ref, TDF_SLIM); | |||
1687 | fprintf (dump_file, "\n"); | |||
1688 | } | |||
1689 | } | |||
1690 | ||||
1691 | record_mem_ref_loc (ref, stmt, mem); | |||
1692 | } | |||
1693 | if (is_stored) | |||
1694 | { | |||
1695 | bitmap_set_bit (&memory_accesses.refs_stored_in_loop[loop->num], ref->id); | |||
1696 | mark_ref_stored (ref, loop); | |||
1697 | } | |||
1698 | /* A not simple memory op is also a read when it is a write. */ | |||
1699 | if (!is_stored || id == UNANALYZABLE_MEM_ID0 | |||
1700 | || ref->mem.ref == error_mark_nodeglobal_trees[TI_ERROR_MARK]) | |||
1701 | { | |||
1702 | bitmap_set_bit (&memory_accesses.refs_loaded_in_loop[loop->num], ref->id); | |||
1703 | mark_ref_loaded (ref, loop); | |||
1704 | } | |||
1705 | init_lim_data (stmt)->ref = ref->id; | |||
1706 | return; | |||
1707 | } | |||
1708 | ||||
1709 | static unsigned *bb_loop_postorder; | |||
1710 | ||||
1711 | /* qsort sort function to sort blocks after their loop fathers postorder. */ | |||
1712 | ||||
1713 | static int | |||
1714 | sort_bbs_in_loop_postorder_cmp (const void *bb1_, const void *bb2_, | |||
1715 | void *bb_loop_postorder_) | |||
1716 | { | |||
1717 | unsigned *bb_loop_postorder = (unsigned *)bb_loop_postorder_; | |||
1718 | basic_block bb1 = *(const basic_block *)bb1_; | |||
1719 | basic_block bb2 = *(const basic_block *)bb2_; | |||
1720 | class loop *loop1 = bb1->loop_father; | |||
1721 | class loop *loop2 = bb2->loop_father; | |||
1722 | if (loop1->num == loop2->num) | |||
1723 | return bb1->index - bb2->index; | |||
1724 | return bb_loop_postorder[loop1->num] < bb_loop_postorder[loop2->num] ? -1 : 1; | |||
1725 | } | |||
1726 | ||||
1727 | /* qsort sort function to sort ref locs after their loop fathers postorder. */ | |||
1728 | ||||
1729 | static int | |||
1730 | sort_locs_in_loop_postorder_cmp (const void *loc1_, const void *loc2_, | |||
1731 | void *bb_loop_postorder_) | |||
1732 | { | |||
1733 | unsigned *bb_loop_postorder = (unsigned *)bb_loop_postorder_; | |||
1734 | const mem_ref_loc *loc1 = (const mem_ref_loc *)loc1_; | |||
1735 | const mem_ref_loc *loc2 = (const mem_ref_loc *)loc2_; | |||
1736 | class loop *loop1 = gimple_bb (loc1->stmt)->loop_father; | |||
1737 | class loop *loop2 = gimple_bb (loc2->stmt)->loop_father; | |||
1738 | if (loop1->num == loop2->num) | |||
1739 | return 0; | |||
1740 | return bb_loop_postorder[loop1->num] < bb_loop_postorder[loop2->num] ? -1 : 1; | |||
1741 | } | |||
1742 | ||||
1743 | /* Gathers memory references in loops. */ | |||
1744 | ||||
1745 | static void | |||
1746 | analyze_memory_references (bool store_motion) | |||
1747 | { | |||
1748 | gimple_stmt_iterator bsi; | |||
1749 | basic_block bb, *bbs; | |||
1750 | class loop *outer; | |||
1751 | unsigned i, n; | |||
1752 | ||||
1753 | /* Collect all basic-blocks in loops and sort them after their | |||
1754 | loops postorder. */ | |||
1755 | i = 0; | |||
1756 | bbs = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS)((basic_block *) xmalloc (sizeof (basic_block) * ((((cfun + 0 ))->cfg->x_n_basic_blocks) - (2)))); | |||
1757 | FOR_EACH_BB_FN (bb, cfun)for (bb = ((cfun + 0))->cfg->x_entry_block_ptr->next_bb ; bb != ((cfun + 0))->cfg->x_exit_block_ptr; bb = bb-> next_bb) | |||
1758 | if (bb->loop_father != current_loops((cfun + 0)->x_current_loops)->tree_root) | |||
1759 | bbs[i++] = bb; | |||
1760 | n = i; | |||
1761 | gcc_sort_r (bbs, n, sizeof (basic_block), sort_bbs_in_loop_postorder_cmp, | |||
1762 | bb_loop_postorder); | |||
1763 | ||||
1764 | /* Visit blocks in loop postorder and assign mem-ref IDs in that order. | |||
1765 | That results in better locality for all the bitmaps. It also | |||
1766 | automatically sorts the location list of gathered memory references | |||
1767 | after their loop postorder number allowing to binary-search it. */ | |||
1768 | for (i = 0; i < n; ++i) | |||
1769 | { | |||
1770 | basic_block bb = bbs[i]; | |||
1771 | for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) | |||
1772 | gather_mem_refs_stmt (bb->loop_father, gsi_stmt (bsi)); | |||
1773 | } | |||
1774 | ||||
1775 | /* Verify the list of gathered memory references is sorted after their | |||
1776 | loop postorder number. */ | |||
1777 | if (flag_checkingglobal_options.x_flag_checking) | |||
1778 | { | |||
1779 | im_mem_ref *ref; | |||
1780 | FOR_EACH_VEC_ELT (memory_accesses.refs_list, i, ref)for (i = 0; (memory_accesses.refs_list).iterate ((i), &(ref )); ++(i)) | |||
1781 | for (unsigned j = 1; j < ref->accesses_in_loop.length (); ++j) | |||
1782 | gcc_assert (sort_locs_in_loop_postorder_cmp((void)(!(sort_locs_in_loop_postorder_cmp (&ref->accesses_in_loop [j-1], &ref->accesses_in_loop[j], bb_loop_postorder) <= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1784, __FUNCTION__), 0 : 0)) | |||
1783 | (&ref->accesses_in_loop[j-1], &ref->accesses_in_loop[j],((void)(!(sort_locs_in_loop_postorder_cmp (&ref->accesses_in_loop [j-1], &ref->accesses_in_loop[j], bb_loop_postorder) <= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1784, __FUNCTION__), 0 : 0)) | |||
1784 | bb_loop_postorder) <= 0)((void)(!(sort_locs_in_loop_postorder_cmp (&ref->accesses_in_loop [j-1], &ref->accesses_in_loop[j], bb_loop_postorder) <= 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1784, __FUNCTION__), 0 : 0)); | |||
1785 | } | |||
1786 | ||||
1787 | free (bbs); | |||
1788 | ||||
1789 | if (!store_motion) | |||
1790 | return; | |||
1791 | ||||
1792 | /* Propagate the information about accessed memory references up | |||
1793 | the loop hierarchy. */ | |||
1794 | for (auto loop : loops_list (cfun(cfun + 0), LI_FROM_INNERMOST)) | |||
1795 | { | |||
1796 | /* Finalize the overall touched references (including subloops). */ | |||
1797 | bitmap_ior_into (&memory_accesses.all_refs_stored_in_loop[loop->num], | |||
1798 | &memory_accesses.refs_stored_in_loop[loop->num]); | |||
1799 | ||||
1800 | /* Propagate the information about accessed memory references up | |||
1801 | the loop hierarchy. */ | |||
1802 | outer = loop_outer (loop); | |||
1803 | if (outer == current_loops((cfun + 0)->x_current_loops)->tree_root) | |||
1804 | continue; | |||
1805 | ||||
1806 | bitmap_ior_into (&memory_accesses.all_refs_stored_in_loop[outer->num], | |||
1807 | &memory_accesses.all_refs_stored_in_loop[loop->num]); | |||
1808 | } | |||
1809 | } | |||
1810 | ||||
1811 | /* Returns true if MEM1 and MEM2 may alias. TTAE_CACHE is used as a cache in | |||
1812 | tree_to_aff_combination_expand. */ | |||
1813 | ||||
1814 | static bool | |||
1815 | mem_refs_may_alias_p (im_mem_ref *mem1, im_mem_ref *mem2, | |||
1816 | hash_map<tree, name_expansion *> **ttae_cache, | |||
1817 | bool tbaa_p) | |||
1818 | { | |||
1819 | gcc_checking_assert (mem1->mem.ref != error_mark_node((void)(!(mem1->mem.ref != global_trees[TI_ERROR_MARK] && mem2->mem.ref != global_trees[TI_ERROR_MARK]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1820, __FUNCTION__), 0 : 0)) | |||
1820 | && mem2->mem.ref != error_mark_node)((void)(!(mem1->mem.ref != global_trees[TI_ERROR_MARK] && mem2->mem.ref != global_trees[TI_ERROR_MARK]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 1820, __FUNCTION__), 0 : 0)); | |||
1821 | ||||
1822 | /* Perform BASE + OFFSET analysis -- if MEM1 and MEM2 are based on the same | |||
1823 | object and their offset differ in such a way that the locations cannot | |||
1824 | overlap, then they cannot alias. */ | |||
1825 | poly_widest_int size1, size2; | |||
1826 | aff_tree off1, off2; | |||
1827 | ||||
1828 | /* Perform basic offset and type-based disambiguation. */ | |||
1829 | if (!refs_may_alias_p_1 (&mem1->mem, &mem2->mem, tbaa_p)) | |||
1830 | return false; | |||
1831 | ||||
1832 | /* The expansion of addresses may be a bit expensive, thus we only do | |||
1833 | the check at -O2 and higher optimization levels. */ | |||
1834 | if (optimizeglobal_options.x_optimize < 2) | |||
1835 | return true; | |||
1836 | ||||
1837 | get_inner_reference_aff (mem1->mem.ref, &off1, &size1); | |||
1838 | get_inner_reference_aff (mem2->mem.ref, &off2, &size2); | |||
1839 | aff_combination_expand (&off1, ttae_cache); | |||
1840 | aff_combination_expand (&off2, ttae_cache); | |||
1841 | aff_combination_scale (&off1, -1); | |||
1842 | aff_combination_add (&off2, &off1); | |||
1843 | ||||
1844 | if (aff_comb_cannot_overlap_p (&off2, size1, size2)) | |||
1845 | return false; | |||
1846 | ||||
1847 | return true; | |||
1848 | } | |||
1849 | ||||
1850 | /* Compare function for bsearch searching for reference locations | |||
1851 | in a loop. */ | |||
1852 | ||||
1853 | static int | |||
1854 | find_ref_loc_in_loop_cmp (const void *loop_, const void *loc_, | |||
1855 | void *bb_loop_postorder_) | |||
1856 | { | |||
1857 | unsigned *bb_loop_postorder = (unsigned *)bb_loop_postorder_; | |||
1858 | class loop *loop = (class loop *)const_cast<void *>(loop_); | |||
1859 | mem_ref_loc *loc = (mem_ref_loc *)const_cast<void *>(loc_); | |||
1860 | class loop *loc_loop = gimple_bb (loc->stmt)->loop_father; | |||
1861 | if (loop->num == loc_loop->num | |||
1862 | || flow_loop_nested_p (loop, loc_loop)) | |||
1863 | return 0; | |||
1864 | return (bb_loop_postorder[loop->num] < bb_loop_postorder[loc_loop->num] | |||
1865 | ? -1 : 1); | |||
1866 | } | |||
1867 | ||||
1868 | /* Iterates over all locations of REF in LOOP and its subloops calling | |||
1869 | fn.operator() with the location as argument. When that operator | |||
1870 | returns true the iteration is stopped and true is returned. | |||
1871 | Otherwise false is returned. */ | |||
1872 | ||||
1873 | template <typename FN> | |||
1874 | static bool | |||
1875 | for_all_locs_in_loop (class loop *loop, im_mem_ref *ref, FN fn) | |||
1876 | { | |||
1877 | unsigned i; | |||
1878 | mem_ref_loc *loc; | |||
1879 | ||||
1880 | /* Search for the cluster of locs in the accesses_in_loop vector | |||
1881 | which is sorted after postorder index of the loop father. */ | |||
1882 | loc = ref->accesses_in_loop.bsearch (loop, find_ref_loc_in_loop_cmp, | |||
1883 | bb_loop_postorder); | |||
1884 | if (!loc) | |||
1885 | return false; | |||
1886 | ||||
1887 | /* We have found one location inside loop or its sub-loops. Iterate | |||
1888 | both forward and backward to cover the whole cluster. */ | |||
1889 | i = loc - ref->accesses_in_loop.address (); | |||
1890 | while (i > 0) | |||
1891 | { | |||
1892 | --i; | |||
1893 | mem_ref_loc *l = &ref->accesses_in_loop[i]; | |||
1894 | if (!flow_bb_inside_loop_p (loop, gimple_bb (l->stmt))) | |||
1895 | break; | |||
1896 | if (fn (l)) | |||
1897 | return true; | |||
1898 | } | |||
1899 | for (i = loc - ref->accesses_in_loop.address (); | |||
1900 | i < ref->accesses_in_loop.length (); ++i) | |||
1901 | { | |||
1902 | mem_ref_loc *l = &ref->accesses_in_loop[i]; | |||
1903 | if (!flow_bb_inside_loop_p (loop, gimple_bb (l->stmt))) | |||
1904 | break; | |||
1905 | if (fn (l)) | |||
1906 | return true; | |||
1907 | } | |||
1908 | ||||
1909 | return false; | |||
1910 | } | |||
1911 | ||||
1912 | /* Rewrites location LOC by TMP_VAR. */ | |||
1913 | ||||
1914 | class rewrite_mem_ref_loc | |||
1915 | { | |||
1916 | public: | |||
1917 | rewrite_mem_ref_loc (tree tmp_var_) : tmp_var (tmp_var_) {} | |||
1918 | bool operator () (mem_ref_loc *loc); | |||
1919 | tree tmp_var; | |||
1920 | }; | |||
1921 | ||||
1922 | bool | |||
1923 | rewrite_mem_ref_loc::operator () (mem_ref_loc *loc) | |||
1924 | { | |||
1925 | *loc->ref = tmp_var; | |||
1926 | update_stmt (loc->stmt); | |||
1927 | return false; | |||
1928 | } | |||
1929 | ||||
1930 | /* Rewrites all references to REF in LOOP by variable TMP_VAR. */ | |||
1931 | ||||
1932 | static void | |||
1933 | rewrite_mem_refs (class loop *loop, im_mem_ref *ref, tree tmp_var) | |||
1934 | { | |||
1935 | for_all_locs_in_loop (loop, ref, rewrite_mem_ref_loc (tmp_var)); | |||
1936 | } | |||
1937 | ||||
1938 | /* Stores the first reference location in LOCP. */ | |||
1939 | ||||
1940 | class first_mem_ref_loc_1 | |||
1941 | { | |||
1942 | public: | |||
1943 | first_mem_ref_loc_1 (mem_ref_loc **locp_) : locp (locp_) {} | |||
1944 | bool operator () (mem_ref_loc *loc); | |||
1945 | mem_ref_loc **locp; | |||
1946 | }; | |||
1947 | ||||
1948 | bool | |||
1949 | first_mem_ref_loc_1::operator () (mem_ref_loc *loc) | |||
1950 | { | |||
1951 | *locp = loc; | |||
1952 | return true; | |||
1953 | } | |||
1954 | ||||
1955 | /* Returns the first reference location to REF in LOOP. */ | |||
1956 | ||||
1957 | static mem_ref_loc * | |||
1958 | first_mem_ref_loc (class loop *loop, im_mem_ref *ref) | |||
1959 | { | |||
1960 | mem_ref_loc *locp = NULLnullptr; | |||
1961 | for_all_locs_in_loop (loop, ref, first_mem_ref_loc_1 (&locp)); | |||
1962 | return locp; | |||
1963 | } | |||
1964 | ||||
1965 | /* Helper function for execute_sm. Emit code to store TMP_VAR into | |||
1966 | MEM along edge EX. | |||
1967 | ||||
1968 | The store is only done if MEM has changed. We do this so no | |||
1969 | changes to MEM occur on code paths that did not originally store | |||
1970 | into it. | |||
1971 | ||||
1972 | The common case for execute_sm will transform: | |||
1973 | ||||
1974 | for (...) { | |||
1975 | if (foo) | |||
1976 | stuff; | |||
1977 | else | |||
1978 | MEM = TMP_VAR; | |||
1979 | } | |||
1980 | ||||
1981 | into: | |||
1982 | ||||
1983 | lsm = MEM; | |||
1984 | for (...) { | |||
1985 | if (foo) | |||
1986 | stuff; | |||
1987 | else | |||
1988 | lsm = TMP_VAR; | |||
1989 | } | |||
1990 | MEM = lsm; | |||
1991 | ||||
1992 | This function will generate: | |||
1993 | ||||
1994 | lsm = MEM; | |||
1995 | ||||
1996 | lsm_flag = false; | |||
1997 | ... | |||
1998 | for (...) { | |||
1999 | if (foo) | |||
2000 | stuff; | |||
2001 | else { | |||
2002 | lsm = TMP_VAR; | |||
2003 | lsm_flag = true; | |||
2004 | } | |||
2005 | } | |||
2006 | if (lsm_flag) <-- | |||
2007 | MEM = lsm; <-- (X) | |||
2008 | ||||
2009 | In case MEM and TMP_VAR are NULL the function will return the then | |||
2010 | block so the caller can insert (X) and other related stmts. | |||
2011 | */ | |||
2012 | ||||
2013 | static basic_block | |||
2014 | execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag, | |||
2015 | edge preheader, hash_set <basic_block> *flag_bbs, | |||
2016 | edge &append_cond_position, edge &last_cond_fallthru) | |||
2017 | { | |||
2018 | basic_block new_bb, then_bb, old_dest; | |||
2019 | bool loop_has_only_one_exit; | |||
2020 | edge then_old_edge; | |||
2021 | gimple_stmt_iterator gsi; | |||
2022 | gimple *stmt; | |||
2023 | bool irr = ex->flags & EDGE_IRREDUCIBLE_LOOP; | |||
2024 | ||||
2025 | profile_count count_sum = profile_count::zero (); | |||
2026 | int nbbs = 0, ncount = 0; | |||
2027 | profile_probability flag_probability = profile_probability::uninitialized (); | |||
2028 | ||||
2029 | /* Flag is set in FLAG_BBS. Determine probability that flag will be true | |||
2030 | at loop exit. | |||
2031 | ||||
2032 | This code may look fancy, but it cannot update profile very realistically | |||
2033 | because we do not know the probability that flag will be true at given | |||
2034 | loop exit. | |||
2035 | ||||
2036 | We look for two interesting extremes | |||
2037 | - when exit is dominated by block setting the flag, we know it will | |||
2038 | always be true. This is a common case. | |||
2039 | - when all blocks setting the flag have very low frequency we know | |||
2040 | it will likely be false. | |||
2041 | In all other cases we default to 2/3 for flag being true. */ | |||
2042 | ||||
2043 | for (hash_set<basic_block>::iterator it = flag_bbs->begin (); | |||
2044 | it != flag_bbs->end (); ++it) | |||
2045 | { | |||
2046 | if ((*it)->count.initialized_p ()) | |||
2047 | count_sum += (*it)->count, ncount ++; | |||
2048 | if (dominated_by_p (CDI_DOMINATORS, ex->src, *it)) | |||
2049 | flag_probability = profile_probability::always (); | |||
2050 | nbbs++; | |||
2051 | } | |||
2052 | ||||
2053 | profile_probability cap = profile_probability::always ().apply_scale (2, 3); | |||
2054 | ||||
2055 | if (flag_probability.initialized_p ()) | |||
2056 | ; | |||
2057 | else if (ncount == nbbs | |||
2058 | && preheader->count () >= count_sum && preheader->count ().nonzero_p ()) | |||
2059 | { | |||
2060 | flag_probability = count_sum.probability_in (preheader->count ()); | |||
2061 | if (flag_probability > cap) | |||
2062 | flag_probability = cap; | |||
2063 | } | |||
2064 | ||||
2065 | if (!flag_probability.initialized_p ()) | |||
2066 | flag_probability = cap; | |||
2067 | ||||
2068 | /* ?? Insert store after previous store if applicable. See note | |||
2069 | below. */ | |||
2070 | if (append_cond_position) | |||
2071 | ex = append_cond_position; | |||
2072 | ||||
2073 | loop_has_only_one_exit = single_pred_p (ex->dest); | |||
2074 | ||||
2075 | if (loop_has_only_one_exit) | |||
2076 | ex = split_block_after_labels (ex->dest); | |||
2077 | else | |||
2078 | { | |||
2079 | for (gphi_iterator gpi = gsi_start_phis (ex->dest); | |||
2080 | !gsi_end_p (gpi); gsi_next (&gpi)) | |||
2081 | { | |||
2082 | gphi *phi = gpi.phi (); | |||
2083 | if (virtual_operand_p (gimple_phi_result (phi))) | |||
2084 | continue; | |||
2085 | ||||
2086 | /* When the destination has a non-virtual PHI node with multiple | |||
2087 | predecessors make sure we preserve the PHI structure by | |||
2088 | forcing a forwarder block so that hoisting of that PHI will | |||
2089 | still work. */ | |||
2090 | split_edge (ex); | |||
2091 | break; | |||
2092 | } | |||
2093 | } | |||
2094 | ||||
2095 | old_dest = ex->dest; | |||
2096 | new_bb = split_edge (ex); | |||
2097 | then_bb = create_empty_bb (new_bb); | |||
2098 | then_bb->count = new_bb->count.apply_probability (flag_probability); | |||
2099 | if (irr) | |||
2100 | then_bb->flags = BB_IRREDUCIBLE_LOOP; | |||
2101 | add_bb_to_loop (then_bb, new_bb->loop_father); | |||
2102 | ||||
2103 | gsi = gsi_start_bb (new_bb); | |||
2104 | stmt = gimple_build_cond (NE_EXPR, flag, boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE], | |||
2105 | NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr); | |||
2106 | gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); | |||
2107 | ||||
2108 | /* Insert actual store. */ | |||
2109 | if (mem) | |||
2110 | { | |||
2111 | gsi = gsi_start_bb (then_bb); | |||
2112 | stmt = gimple_build_assign (unshare_expr (mem), tmp_var); | |||
2113 | gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); | |||
2114 | } | |||
2115 | ||||
2116 | edge e1 = single_succ_edge (new_bb); | |||
2117 | edge e2 = make_edge (new_bb, then_bb, | |||
2118 | EDGE_TRUE_VALUE | (irr ? EDGE_IRREDUCIBLE_LOOP : 0)); | |||
2119 | e2->probability = flag_probability; | |||
2120 | ||||
2121 | e1->flags |= EDGE_FALSE_VALUE | (irr ? EDGE_IRREDUCIBLE_LOOP : 0); | |||
2122 | e1->flags &= ~EDGE_FALLTHRU; | |||
2123 | ||||
2124 | e1->probability = flag_probability.invert (); | |||
2125 | ||||
2126 | then_old_edge = make_single_succ_edge (then_bb, old_dest, | |||
2127 | EDGE_FALLTHRU | (irr ? EDGE_IRREDUCIBLE_LOOP : 0)); | |||
2128 | ||||
2129 | set_immediate_dominator (CDI_DOMINATORS, then_bb, new_bb); | |||
2130 | ||||
2131 | if (append_cond_position) | |||
2132 | { | |||
2133 | basic_block prevbb = last_cond_fallthru->src; | |||
2134 | redirect_edge_succ (last_cond_fallthru, new_bb); | |||
2135 | set_immediate_dominator (CDI_DOMINATORS, new_bb, prevbb); | |||
2136 | set_immediate_dominator (CDI_DOMINATORS, old_dest, | |||
2137 | recompute_dominator (CDI_DOMINATORS, old_dest)); | |||
2138 | } | |||
2139 | ||||
2140 | /* ?? Because stores may alias, they must happen in the exact | |||
2141 | sequence they originally happened. Save the position right after | |||
2142 | the (_lsm) store we just created so we can continue appending after | |||
2143 | it and maintain the original order. */ | |||
2144 | append_cond_position = then_old_edge; | |||
2145 | last_cond_fallthru = find_edge (new_bb, old_dest); | |||
2146 | ||||
2147 | if (!loop_has_only_one_exit) | |||
2148 | for (gphi_iterator gpi = gsi_start_phis (old_dest); | |||
2149 | !gsi_end_p (gpi); gsi_next (&gpi)) | |||
2150 | { | |||
2151 | gphi *phi = gpi.phi (); | |||
2152 | unsigned i; | |||
2153 | ||||
2154 | for (i = 0; i < gimple_phi_num_args (phi); i++) | |||
2155 | if (gimple_phi_arg_edge (phi, i)->src == new_bb) | |||
2156 | { | |||
2157 | tree arg = gimple_phi_arg_def (phi, i); | |||
2158 | add_phi_arg (phi, arg, then_old_edge, UNKNOWN_LOCATION((location_t) 0)); | |||
2159 | update_stmt (phi); | |||
2160 | } | |||
2161 | } | |||
2162 | ||||
2163 | return then_bb; | |||
2164 | } | |||
2165 | ||||
2166 | /* When REF is set on the location, set flag indicating the store. */ | |||
2167 | ||||
2168 | class sm_set_flag_if_changed | |||
2169 | { | |||
2170 | public: | |||
2171 | sm_set_flag_if_changed (tree flag_, hash_set <basic_block> *bbs_) | |||
2172 | : flag (flag_), bbs (bbs_) {} | |||
2173 | bool operator () (mem_ref_loc *loc); | |||
2174 | tree flag; | |||
2175 | hash_set <basic_block> *bbs; | |||
2176 | }; | |||
2177 | ||||
2178 | bool | |||
2179 | sm_set_flag_if_changed::operator () (mem_ref_loc *loc) | |||
2180 | { | |||
2181 | /* Only set the flag for writes. */ | |||
2182 | if (is_gimple_assign (loc->stmt) | |||
2183 | && gimple_assign_lhs_ptr (loc->stmt) == loc->ref) | |||
2184 | { | |||
2185 | gimple_stmt_iterator gsi = gsi_for_stmt (loc->stmt); | |||
2186 | gimple *stmt = gimple_build_assign (flag, boolean_true_nodeglobal_trees[TI_BOOLEAN_TRUE]); | |||
2187 | gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); | |||
2188 | bbs->add (gimple_bb (stmt)); | |||
2189 | } | |||
2190 | return false; | |||
2191 | } | |||
2192 | ||||
2193 | /* Helper function for execute_sm. On every location where REF is | |||
2194 | set, set an appropriate flag indicating the store. */ | |||
2195 | ||||
2196 | static tree | |||
2197 | execute_sm_if_changed_flag_set (class loop *loop, im_mem_ref *ref, | |||
2198 | hash_set <basic_block> *bbs) | |||
2199 | { | |||
2200 | tree flag; | |||
2201 | char *str = get_lsm_tmp_name (ref->mem.ref, ~0, "_flag"); | |||
2202 | flag = create_tmp_reg (boolean_type_nodeglobal_trees[TI_BOOLEAN_TYPE], str); | |||
2203 | for_all_locs_in_loop (loop, ref, sm_set_flag_if_changed (flag, bbs)); | |||
2204 | return flag; | |||
2205 | } | |||
2206 | ||||
2207 | struct sm_aux | |||
2208 | { | |||
2209 | tree tmp_var; | |||
2210 | tree store_flag; | |||
2211 | hash_set <basic_block> flag_bbs; | |||
2212 | }; | |||
2213 | ||||
2214 | /* Executes store motion of memory reference REF from LOOP. | |||
2215 | Exits from the LOOP are stored in EXITS. The initialization of the | |||
2216 | temporary variable is put to the preheader of the loop, and assignments | |||
2217 | to the reference from the temporary variable are emitted to exits. */ | |||
2218 | ||||
2219 | static void | |||
2220 | execute_sm (class loop *loop, im_mem_ref *ref, | |||
2221 | hash_map<im_mem_ref *, sm_aux *> &aux_map, bool maybe_mt, | |||
2222 | bool use_other_flag_var) | |||
2223 | { | |||
2224 | gassign *load; | |||
2225 | struct fmt_data fmt_data; | |||
2226 | struct lim_aux_data *lim_data; | |||
2227 | bool multi_threaded_model_p = false; | |||
2228 | gimple_stmt_iterator gsi; | |||
2229 | sm_aux *aux = new sm_aux; | |||
2230 | ||||
2231 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
2232 | { | |||
2233 | fprintf (dump_file, "Executing store motion of "); | |||
2234 | print_generic_expr (dump_file, ref->mem.ref); | |||
2235 | fprintf (dump_file, " from loop %d\n", loop->num); | |||
2236 | } | |||
2237 | ||||
2238 | aux->tmp_var = create_tmp_reg (TREE_TYPE (ref->mem.ref)((contains_struct_check ((ref->mem.ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2238, __FUNCTION__))->typed.type), | |||
2239 | get_lsm_tmp_name (ref->mem.ref, ~0)); | |||
2240 | ||||
2241 | fmt_data.loop = loop; | |||
2242 | fmt_data.orig_loop = loop; | |||
2243 | for_each_index (&ref->mem.ref, force_move_till, &fmt_data); | |||
2244 | ||||
2245 | bool always_stored = ref_always_accessed_p (loop, ref, true); | |||
2246 | if (maybe_mt | |||
2247 | && (bb_in_transaction (loop_preheader_edge (loop)->src) | |||
2248 | || (! flag_store_data_racesglobal_options.x_flag_store_data_races && ! always_stored))) | |||
2249 | multi_threaded_model_p = true; | |||
2250 | ||||
2251 | if (multi_threaded_model_p && !use_other_flag_var) | |||
2252 | aux->store_flag | |||
2253 | = execute_sm_if_changed_flag_set (loop, ref, &aux->flag_bbs); | |||
2254 | else | |||
2255 | aux->store_flag = NULL_TREE(tree) nullptr; | |||
2256 | ||||
2257 | /* Remember variable setup. */ | |||
2258 | aux_map.put (ref, aux); | |||
2259 | ||||
2260 | rewrite_mem_refs (loop, ref, aux->tmp_var); | |||
2261 | ||||
2262 | /* Emit the load code on a random exit edge or into the latch if | |||
2263 | the loop does not exit, so that we are sure it will be processed | |||
2264 | by move_computations after all dependencies. */ | |||
2265 | gsi = gsi_for_stmt (first_mem_ref_loc (loop, ref)->stmt); | |||
2266 | ||||
2267 | /* Avoid doing a load if there was no load of the ref in the loop. | |||
2268 | Esp. when the ref is not always stored we cannot optimize it | |||
2269 | away later. But when it is not always stored we must use a conditional | |||
2270 | store then. */ | |||
2271 | if ((!always_stored && !multi_threaded_model_p) | |||
2272 | || (ref->loaded && bitmap_bit_p (ref->loaded, loop->num))) | |||
2273 | load = gimple_build_assign (aux->tmp_var, unshare_expr (ref->mem.ref)); | |||
2274 | else | |||
2275 | { | |||
2276 | /* If not emitting a load mark the uninitialized state on the | |||
2277 | loop entry as not to be warned for. */ | |||
2278 | tree uninit = create_tmp_reg (TREE_TYPE (aux->tmp_var)((contains_struct_check ((aux->tmp_var), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2278, __FUNCTION__))->typed.type)); | |||
2279 | suppress_warning (uninit, OPT_Wuninitialized); | |||
2280 | load = gimple_build_assign (aux->tmp_var, uninit); | |||
2281 | } | |||
2282 | lim_data = init_lim_data (load); | |||
2283 | lim_data->max_loop = loop; | |||
2284 | lim_data->tgt_loop = loop; | |||
2285 | gsi_insert_before (&gsi, load, GSI_SAME_STMT); | |||
2286 | ||||
2287 | if (aux->store_flag) | |||
2288 | { | |||
2289 | load = gimple_build_assign (aux->store_flag, boolean_false_nodeglobal_trees[TI_BOOLEAN_FALSE]); | |||
2290 | lim_data = init_lim_data (load); | |||
2291 | lim_data->max_loop = loop; | |||
2292 | lim_data->tgt_loop = loop; | |||
2293 | gsi_insert_before (&gsi, load, GSI_SAME_STMT); | |||
2294 | } | |||
2295 | } | |||
2296 | ||||
2297 | /* sm_ord is used for ordinary stores we can retain order with respect | |||
2298 | to other stores | |||
2299 | sm_unord is used for conditional executed stores which need to be | |||
2300 | able to execute in arbitrary order with respect to other stores | |||
2301 | sm_other is used for stores we do not try to apply store motion to. */ | |||
2302 | enum sm_kind { sm_ord, sm_unord, sm_other }; | |||
2303 | struct seq_entry | |||
2304 | { | |||
2305 | seq_entry () {} | |||
2306 | seq_entry (unsigned f, sm_kind k, tree fr = NULLnullptr) | |||
2307 | : first (f), second (k), from (fr) {} | |||
2308 | unsigned first; | |||
2309 | sm_kind second; | |||
2310 | tree from; | |||
2311 | }; | |||
2312 | ||||
2313 | static void | |||
2314 | execute_sm_exit (class loop *loop, edge ex, vec<seq_entry> &seq, | |||
2315 | hash_map<im_mem_ref *, sm_aux *> &aux_map, sm_kind kind, | |||
2316 | edge &append_cond_position, edge &last_cond_fallthru) | |||
2317 | { | |||
2318 | /* Sink the stores to exit from the loop. */ | |||
2319 | for (unsigned i = seq.length (); i > 0; --i) | |||
2320 | { | |||
2321 | im_mem_ref *ref = memory_accesses.refs_list[seq[i-1].first]; | |||
2322 | if (seq[i-1].second == sm_other) | |||
2323 | { | |||
2324 | gcc_assert (kind == sm_ord && seq[i-1].from != NULL_TREE)((void)(!(kind == sm_ord && seq[i-1].from != (tree) nullptr ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2324, __FUNCTION__), 0 : 0)); | |||
2325 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
2326 | { | |||
2327 | fprintf (dump_file, "Re-issueing dependent store of "); | |||
2328 | print_generic_expr (dump_file, ref->mem.ref); | |||
2329 | fprintf (dump_file, " from loop %d on exit %d -> %d\n", | |||
2330 | loop->num, ex->src->index, ex->dest->index); | |||
2331 | } | |||
2332 | gassign *store = gimple_build_assign (unshare_expr (ref->mem.ref), | |||
2333 | seq[i-1].from); | |||
2334 | gsi_insert_on_edge (ex, store); | |||
2335 | } | |||
2336 | else | |||
2337 | { | |||
2338 | sm_aux *aux = *aux_map.get (ref); | |||
2339 | if (!aux->store_flag || kind == sm_ord) | |||
2340 | { | |||
2341 | gassign *store; | |||
2342 | store = gimple_build_assign (unshare_expr (ref->mem.ref), | |||
2343 | aux->tmp_var); | |||
2344 | gsi_insert_on_edge (ex, store); | |||
2345 | } | |||
2346 | else | |||
2347 | execute_sm_if_changed (ex, ref->mem.ref, aux->tmp_var, | |||
2348 | aux->store_flag, | |||
2349 | loop_preheader_edge (loop), &aux->flag_bbs, | |||
2350 | append_cond_position, last_cond_fallthru); | |||
2351 | } | |||
2352 | } | |||
2353 | } | |||
2354 | ||||
2355 | /* Push the SM candidate at index PTR in the sequence SEQ down until | |||
2356 | we hit the next SM candidate. Return true if that went OK and | |||
2357 | false if we could not disambiguate agains another unrelated ref. | |||
2358 | Update *AT to the index where the candidate now resides. */ | |||
2359 | ||||
2360 | static bool | |||
2361 | sm_seq_push_down (vec<seq_entry> &seq, unsigned ptr, unsigned *at) | |||
2362 | { | |||
2363 | *at = ptr; | |||
2364 | for (; ptr > 0; --ptr) | |||
2365 | { | |||
2366 | seq_entry &new_cand = seq[ptr]; | |||
2367 | seq_entry &against = seq[ptr-1]; | |||
2368 | if (against.second == sm_ord | |||
2369 | || (against.second == sm_other && against.from != NULL_TREE(tree) nullptr)) | |||
2370 | /* Found the tail of the sequence. */ | |||
2371 | break; | |||
2372 | /* We may not ignore self-dependences here. */ | |||
2373 | if (new_cand.first == against.first | |||
2374 | || !refs_independent_p (memory_accesses.refs_list[new_cand.first], | |||
2375 | memory_accesses.refs_list[against.first], | |||
2376 | false)) | |||
2377 | /* ??? Prune new_cand from the list of refs to apply SM to. */ | |||
2378 | return false; | |||
2379 | std::swap (new_cand, against); | |||
2380 | *at = ptr - 1; | |||
2381 | } | |||
2382 | return true; | |||
2383 | } | |||
2384 | ||||
2385 | /* Computes the sequence of stores from candidates in REFS_NOT_IN_SEQ to SEQ | |||
2386 | walking backwards from VDEF (or the end of BB if VDEF is NULL). */ | |||
2387 | ||||
2388 | static int | |||
2389 | sm_seq_valid_bb (class loop *loop, basic_block bb, tree vdef, | |||
2390 | vec<seq_entry> &seq, bitmap refs_not_in_seq, | |||
2391 | bitmap refs_not_supported, bool forked, | |||
2392 | bitmap fully_visited) | |||
2393 | { | |||
2394 | if (!vdef) | |||
2395 | for (gimple_stmt_iterator gsi = gsi_last_bb (bb); !gsi_end_p (gsi); | |||
2396 | gsi_prev (&gsi)) | |||
2397 | { | |||
2398 | vdef = gimple_vdef (gsi_stmt (gsi)); | |||
2399 | if (vdef) | |||
2400 | break; | |||
2401 | } | |||
2402 | if (!vdef) | |||
2403 | { | |||
2404 | gphi *vphi = get_virtual_phi (bb); | |||
2405 | if (vphi) | |||
2406 | vdef = gimple_phi_result (vphi); | |||
2407 | } | |||
2408 | if (!vdef) | |||
2409 | { | |||
2410 | if (single_pred_p (bb)) | |||
2411 | /* This handles the perfect nest case. */ | |||
2412 | return sm_seq_valid_bb (loop, single_pred (bb), vdef, | |||
2413 | seq, refs_not_in_seq, refs_not_supported, | |||
2414 | forked, fully_visited); | |||
2415 | return 0; | |||
2416 | } | |||
2417 | do | |||
2418 | { | |||
2419 | gimple *def = SSA_NAME_DEF_STMT (vdef)(tree_check ((vdef), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2419, __FUNCTION__, (SSA_NAME)))->ssa_name.def_stmt; | |||
2420 | if (gimple_bb (def) != bb) | |||
2421 | { | |||
2422 | /* If we forked by processing a PHI do not allow our walk to | |||
2423 | merge again until we handle that robustly. */ | |||
2424 | if (forked) | |||
2425 | { | |||
2426 | /* Mark refs_not_in_seq as unsupported. */ | |||
2427 | bitmap_ior_into (refs_not_supported, refs_not_in_seq); | |||
2428 | return 1; | |||
2429 | } | |||
2430 | /* Otherwise it doesn't really matter if we end up in different | |||
2431 | BBs. */ | |||
2432 | bb = gimple_bb (def); | |||
2433 | } | |||
2434 | if (gphi *phi = dyn_cast <gphi *> (def)) | |||
2435 | { | |||
2436 | /* Handle CFG merges. Until we handle forks (gimple_bb (def) != bb) | |||
2437 | this is still linear. | |||
2438 | Eventually we want to cache intermediate results per BB | |||
2439 | (but we can't easily cache for different exits?). */ | |||
2440 | /* Stop at PHIs with possible backedges. */ | |||
2441 | if (bb == bb->loop_father->header | |||
2442 | || bb->flags & BB_IRREDUCIBLE_LOOP) | |||
2443 | { | |||
2444 | /* Mark refs_not_in_seq as unsupported. */ | |||
2445 | bitmap_ior_into (refs_not_supported, refs_not_in_seq); | |||
2446 | return 1; | |||
2447 | } | |||
2448 | if (gimple_phi_num_args (phi) == 1) | |||
2449 | return sm_seq_valid_bb (loop, gimple_phi_arg_edge (phi, 0)->src, | |||
2450 | gimple_phi_arg_def (phi, 0), seq, | |||
2451 | refs_not_in_seq, refs_not_supported, | |||
2452 | false, fully_visited); | |||
2453 | if (bitmap_bit_p (fully_visited, | |||
2454 | SSA_NAME_VERSION (gimple_phi_result (phi))(tree_check ((gimple_phi_result (phi)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2454, __FUNCTION__, (SSA_NAME)))->base.u.version)) | |||
2455 | return 1; | |||
2456 | auto_vec<seq_entry> first_edge_seq; | |||
2457 | auto_bitmap tem_refs_not_in_seq (&lim_bitmap_obstack); | |||
2458 | int eret; | |||
2459 | bitmap_copy (tem_refs_not_in_seq, refs_not_in_seq); | |||
2460 | eret = sm_seq_valid_bb (loop, gimple_phi_arg_edge (phi, 0)->src, | |||
2461 | gimple_phi_arg_def (phi, 0), | |||
2462 | first_edge_seq, | |||
2463 | tem_refs_not_in_seq, refs_not_supported, | |||
2464 | true, fully_visited); | |||
2465 | if (eret != 1) | |||
2466 | return -1; | |||
2467 | /* Simplify our lives by pruning the sequence of !sm_ord. */ | |||
2468 | while (!first_edge_seq.is_empty () | |||
2469 | && first_edge_seq.last ().second != sm_ord) | |||
2470 | first_edge_seq.pop (); | |||
2471 | for (unsigned int i = 1; i < gimple_phi_num_args (phi); ++i) | |||
2472 | { | |||
2473 | tree vuse = gimple_phi_arg_def (phi, i); | |||
2474 | edge e = gimple_phi_arg_edge (phi, i); | |||
2475 | auto_vec<seq_entry> edge_seq; | |||
2476 | bitmap_and_compl (tem_refs_not_in_seq, | |||
2477 | refs_not_in_seq, refs_not_supported); | |||
2478 | /* If we've marked all refs we search for as unsupported | |||
2479 | we can stop processing and use the sequence as before | |||
2480 | the PHI. */ | |||
2481 | if (bitmap_empty_p (tem_refs_not_in_seq)) | |||
2482 | return 1; | |||
2483 | eret = sm_seq_valid_bb (loop, e->src, vuse, edge_seq, | |||
2484 | tem_refs_not_in_seq, refs_not_supported, | |||
2485 | true, fully_visited); | |||
2486 | if (eret != 1) | |||
2487 | return -1; | |||
2488 | /* Simplify our lives by pruning the sequence of !sm_ord. */ | |||
2489 | while (!edge_seq.is_empty () | |||
2490 | && edge_seq.last ().second != sm_ord) | |||
2491 | edge_seq.pop (); | |||
2492 | unsigned min_len = MIN(first_edge_seq.length (),((first_edge_seq.length ()) < (edge_seq.length ()) ? (first_edge_seq .length ()) : (edge_seq.length ())) | |||
2493 | edge_seq.length ())((first_edge_seq.length ()) < (edge_seq.length ()) ? (first_edge_seq .length ()) : (edge_seq.length ())); | |||
2494 | /* Incrementally merge seqs into first_edge_seq. */ | |||
2495 | int first_uneq = -1; | |||
2496 | auto_vec<seq_entry, 2> extra_refs; | |||
2497 | for (unsigned int i = 0; i < min_len; ++i) | |||
2498 | { | |||
2499 | /* ??? We can more intelligently merge when we face different | |||
2500 | order by additional sinking operations in one sequence. | |||
2501 | For now we simply mark them as to be processed by the | |||
2502 | not order-preserving SM code. */ | |||
2503 | if (first_edge_seq[i].first != edge_seq[i].first) | |||
2504 | { | |||
2505 | if (first_edge_seq[i].second == sm_ord) | |||
2506 | bitmap_set_bit (refs_not_supported, | |||
2507 | first_edge_seq[i].first); | |||
2508 | if (edge_seq[i].second == sm_ord) | |||
2509 | bitmap_set_bit (refs_not_supported, edge_seq[i].first); | |||
2510 | first_edge_seq[i].second = sm_other; | |||
2511 | first_edge_seq[i].from = NULL_TREE(tree) nullptr; | |||
2512 | /* Record the dropped refs for later processing. */ | |||
2513 | if (first_uneq == -1) | |||
2514 | first_uneq = i; | |||
2515 | extra_refs.safe_push (seq_entry (edge_seq[i].first, | |||
2516 | sm_other, NULL_TREE(tree) nullptr)); | |||
2517 | } | |||
2518 | /* sm_other prevails. */ | |||
2519 | else if (first_edge_seq[i].second != edge_seq[i].second) | |||
2520 | { | |||
2521 | /* Make sure the ref is marked as not supported. */ | |||
2522 | bitmap_set_bit (refs_not_supported, | |||
2523 | first_edge_seq[i].first); | |||
2524 | first_edge_seq[i].second = sm_other; | |||
2525 | first_edge_seq[i].from = NULL_TREE(tree) nullptr; | |||
2526 | } | |||
2527 | else if (first_edge_seq[i].second == sm_other | |||
2528 | && first_edge_seq[i].from != NULL_TREE(tree) nullptr | |||
2529 | && (edge_seq[i].from == NULL_TREE(tree) nullptr | |||
2530 | || !operand_equal_p (first_edge_seq[i].from, | |||
2531 | edge_seq[i].from, 0))) | |||
2532 | first_edge_seq[i].from = NULL_TREE(tree) nullptr; | |||
2533 | } | |||
2534 | /* Any excess elements become sm_other since they are now | |||
2535 | coonditionally executed. */ | |||
2536 | if (first_edge_seq.length () > edge_seq.length ()) | |||
2537 | { | |||
2538 | for (unsigned i = edge_seq.length (); | |||
2539 | i < first_edge_seq.length (); ++i) | |||
2540 | { | |||
2541 | if (first_edge_seq[i].second == sm_ord) | |||
2542 | bitmap_set_bit (refs_not_supported, | |||
2543 | first_edge_seq[i].first); | |||
2544 | first_edge_seq[i].second = sm_other; | |||
2545 | } | |||
2546 | } | |||
2547 | else if (edge_seq.length () > first_edge_seq.length ()) | |||
2548 | { | |||
2549 | if (first_uneq == -1) | |||
2550 | first_uneq = first_edge_seq.length (); | |||
2551 | for (unsigned i = first_edge_seq.length (); | |||
2552 | i < edge_seq.length (); ++i) | |||
2553 | { | |||
2554 | if (edge_seq[i].second == sm_ord) | |||
2555 | bitmap_set_bit (refs_not_supported, edge_seq[i].first); | |||
2556 | extra_refs.safe_push (seq_entry (edge_seq[i].first, | |||
2557 | sm_other, NULL_TREE(tree) nullptr)); | |||
2558 | } | |||
2559 | } | |||
2560 | /* Put unmerged refs at first_uneq to force dependence checking | |||
2561 | on them. */ | |||
2562 | if (first_uneq != -1) | |||
2563 | { | |||
2564 | /* Missing ordered_splice_at. */ | |||
2565 | if ((unsigned)first_uneq == first_edge_seq.length ()) | |||
2566 | first_edge_seq.safe_splice (extra_refs); | |||
2567 | else | |||
2568 | { | |||
2569 | unsigned fes_length = first_edge_seq.length (); | |||
2570 | first_edge_seq.safe_grow (fes_length | |||
2571 | + extra_refs.length ()); | |||
2572 | memmove (&first_edge_seq[first_uneq + extra_refs.length ()], | |||
2573 | &first_edge_seq[first_uneq], | |||
2574 | (fes_length - first_uneq) * sizeof (seq_entry)); | |||
2575 | memcpy (&first_edge_seq[first_uneq], | |||
2576 | extra_refs.address (), | |||
2577 | extra_refs.length () * sizeof (seq_entry)); | |||
2578 | } | |||
2579 | } | |||
2580 | } | |||
2581 | /* Use the sequence from the first edge and push SMs down. */ | |||
2582 | for (unsigned i = 0; i < first_edge_seq.length (); ++i) | |||
2583 | { | |||
2584 | unsigned id = first_edge_seq[i].first; | |||
2585 | seq.safe_push (first_edge_seq[i]); | |||
2586 | unsigned new_idx; | |||
2587 | if ((first_edge_seq[i].second == sm_ord | |||
2588 | || (first_edge_seq[i].second == sm_other | |||
2589 | && first_edge_seq[i].from != NULL_TREE(tree) nullptr)) | |||
2590 | && !sm_seq_push_down (seq, seq.length () - 1, &new_idx)) | |||
2591 | { | |||
2592 | if (first_edge_seq[i].second == sm_ord) | |||
2593 | bitmap_set_bit (refs_not_supported, id); | |||
2594 | /* Mark it sm_other. */ | |||
2595 | seq[new_idx].second = sm_other; | |||
2596 | seq[new_idx].from = NULL_TREE(tree) nullptr; | |||
2597 | } | |||
2598 | } | |||
2599 | bitmap_set_bit (fully_visited, | |||
2600 | SSA_NAME_VERSION (gimple_phi_result (phi))(tree_check ((gimple_phi_result (phi)), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2600, __FUNCTION__, (SSA_NAME)))->base.u.version); | |||
2601 | return 1; | |||
2602 | } | |||
2603 | lim_aux_data *data = get_lim_data (def); | |||
2604 | gcc_assert (data)((void)(!(data) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2604, __FUNCTION__), 0 : 0)); | |||
2605 | if (data->ref == UNANALYZABLE_MEM_ID0) | |||
2606 | return -1; | |||
2607 | /* Stop at memory references which we can't move. */ | |||
2608 | else if (memory_accesses.refs_list[data->ref]->mem.ref == error_mark_nodeglobal_trees[TI_ERROR_MARK] | |||
2609 | || TREE_THIS_VOLATILE((memory_accesses.refs_list[data->ref]->mem.ref)->base .volatile_flag) | |||
2610 | (memory_accesses.refs_list[data->ref]->mem.ref)((memory_accesses.refs_list[data->ref]->mem.ref)->base .volatile_flag)) | |||
2611 | { | |||
2612 | /* Mark refs_not_in_seq as unsupported. */ | |||
2613 | bitmap_ior_into (refs_not_supported, refs_not_in_seq); | |||
2614 | return 1; | |||
2615 | } | |||
2616 | /* One of the stores we want to apply SM to and we've not yet seen. */ | |||
2617 | else if (bitmap_clear_bit (refs_not_in_seq, data->ref)) | |||
2618 | { | |||
2619 | seq.safe_push (seq_entry (data->ref, sm_ord)); | |||
2620 | ||||
2621 | /* 1) push it down the queue until a SMed | |||
2622 | and not ignored ref is reached, skipping all not SMed refs | |||
2623 | and ignored refs via non-TBAA disambiguation. */ | |||
2624 | unsigned new_idx; | |||
2625 | if (!sm_seq_push_down (seq, seq.length () - 1, &new_idx) | |||
2626 | /* If that fails but we did not fork yet continue, we'll see | |||
2627 | to re-materialize all of the stores in the sequence then. | |||
2628 | Further stores will only be pushed up to this one. */ | |||
2629 | && forked) | |||
2630 | { | |||
2631 | bitmap_set_bit (refs_not_supported, data->ref); | |||
2632 | /* Mark it sm_other. */ | |||
2633 | seq[new_idx].second = sm_other; | |||
2634 | } | |||
2635 | ||||
2636 | /* 2) check whether we've seen all refs we want to SM and if so | |||
2637 | declare success for the active exit */ | |||
2638 | if (bitmap_empty_p (refs_not_in_seq)) | |||
2639 | return 1; | |||
2640 | } | |||
2641 | else | |||
2642 | /* Another store not part of the final sequence. Simply push it. */ | |||
2643 | seq.safe_push (seq_entry (data->ref, sm_other, | |||
2644 | gimple_assign_rhs1 (def))); | |||
2645 | ||||
2646 | vdef = gimple_vuse (def); | |||
2647 | } | |||
2648 | while (1); | |||
2649 | } | |||
2650 | ||||
2651 | /* Hoists memory references MEM_REFS out of LOOP. EXITS is the list of exit | |||
2652 | edges of the LOOP. */ | |||
2653 | ||||
2654 | static void | |||
2655 | hoist_memory_references (class loop *loop, bitmap mem_refs, | |||
2656 | const vec<edge> &exits) | |||
2657 | { | |||
2658 | im_mem_ref *ref; | |||
2659 | unsigned i; | |||
2660 | bitmap_iterator bi; | |||
2661 | ||||
2662 | /* There's a special case we can use ordered re-materialization for | |||
2663 | conditionally excuted stores which is when all stores in the loop | |||
2664 | happen in the same basic-block. In that case we know we'll reach | |||
2665 | all stores and thus can simply process that BB and emit a single | |||
2666 | conditional block of ordered materializations. See PR102436. */ | |||
2667 | basic_block single_store_bb = NULLnullptr; | |||
2668 | EXECUTE_IF_SET_IN_BITMAP (&memory_accesses.all_refs_stored_in_loop[loop->num],for (bmp_iter_set_init (&(bi), (&memory_accesses.all_refs_stored_in_loop [loop->num]), (0), &(i)); bmp_iter_set (&(bi), & (i)); bmp_iter_next (&(bi), &(i))) | |||
2669 | 0, i, bi)for (bmp_iter_set_init (&(bi), (&memory_accesses.all_refs_stored_in_loop [loop->num]), (0), &(i)); bmp_iter_set (&(bi), & (i)); bmp_iter_next (&(bi), &(i))) | |||
2670 | { | |||
2671 | bool fail = false; | |||
2672 | ref = memory_accesses.refs_list[i]; | |||
2673 | for (auto loc : ref->accesses_in_loop) | |||
2674 | if (!gimple_vdef (loc.stmt)) | |||
2675 | ; | |||
2676 | else if (!single_store_bb) | |||
2677 | { | |||
2678 | single_store_bb = gimple_bb (loc.stmt); | |||
2679 | bool conditional = false; | |||
2680 | for (edge e : exits) | |||
2681 | if (!dominated_by_p (CDI_DOMINATORS, e->src, single_store_bb)) | |||
2682 | { | |||
2683 | /* Conditional as seen from e. */ | |||
2684 | conditional = true; | |||
2685 | break; | |||
2686 | } | |||
2687 | if (!conditional) | |||
2688 | { | |||
2689 | fail = true; | |||
2690 | break; | |||
2691 | } | |||
2692 | } | |||
2693 | else if (single_store_bb != gimple_bb (loc.stmt)) | |||
2694 | { | |||
2695 | fail = true; | |||
2696 | break; | |||
2697 | } | |||
2698 | if (fail) | |||
2699 | { | |||
2700 | single_store_bb = NULLnullptr; | |||
2701 | break; | |||
2702 | } | |||
2703 | } | |||
2704 | if (single_store_bb) | |||
2705 | { | |||
2706 | /* Analyze the single block with stores. */ | |||
2707 | auto_bitmap fully_visited; | |||
2708 | auto_bitmap refs_not_supported; | |||
2709 | auto_bitmap refs_not_in_seq; | |||
2710 | auto_vec<seq_entry> seq; | |||
2711 | bitmap_copy (refs_not_in_seq, mem_refs); | |||
2712 | int res = sm_seq_valid_bb (loop, single_store_bb, NULL_TREE(tree) nullptr, | |||
2713 | seq, refs_not_in_seq, refs_not_supported, | |||
2714 | false, fully_visited); | |||
2715 | if (res != 1) | |||
2716 | { | |||
2717 | /* Unhandled refs can still fail this. */ | |||
2718 | bitmap_clear (mem_refs); | |||
2719 | return; | |||
2720 | } | |||
2721 | ||||
2722 | /* We cannot handle sm_other since we neither remember the | |||
2723 | stored location nor the value at the point we execute them. */ | |||
2724 | for (unsigned i = 0; i < seq.length (); ++i) | |||
2725 | { | |||
2726 | unsigned new_i; | |||
2727 | if (seq[i].second == sm_other | |||
2728 | && seq[i].from != NULL_TREE(tree) nullptr) | |||
2729 | seq[i].from = NULL_TREE(tree) nullptr; | |||
2730 | else if ((seq[i].second == sm_ord | |||
2731 | || (seq[i].second == sm_other | |||
2732 | && seq[i].from != NULL_TREE(tree) nullptr)) | |||
2733 | && !sm_seq_push_down (seq, i, &new_i)) | |||
2734 | { | |||
2735 | bitmap_set_bit (refs_not_supported, seq[new_i].first); | |||
2736 | seq[new_i].second = sm_other; | |||
2737 | seq[new_i].from = NULL_TREE(tree) nullptr; | |||
2738 | } | |||
2739 | } | |||
2740 | bitmap_and_compl_into (mem_refs, refs_not_supported); | |||
2741 | if (bitmap_empty_p (mem_refs)) | |||
2742 | return; | |||
2743 | ||||
2744 | /* Prune seq. */ | |||
2745 | while (seq.last ().second == sm_other | |||
2746 | && seq.last ().from == NULL_TREE(tree) nullptr) | |||
2747 | seq.pop (); | |||
2748 | ||||
2749 | hash_map<im_mem_ref *, sm_aux *> aux_map; | |||
2750 | ||||
2751 | /* Execute SM but delay the store materialization for ordered | |||
2752 | sequences on exit. */ | |||
2753 | bool first_p = true; | |||
2754 | EXECUTE_IF_SET_IN_BITMAP (mem_refs, 0, i, bi)for (bmp_iter_set_init (&(bi), (mem_refs), (0), &(i)) ; bmp_iter_set (&(bi), &(i)); bmp_iter_next (&(bi ), &(i))) | |||
2755 | { | |||
2756 | ref = memory_accesses.refs_list[i]; | |||
2757 | execute_sm (loop, ref, aux_map, true, !first_p); | |||
2758 | first_p = false; | |||
2759 | } | |||
2760 | ||||
2761 | /* Get at the single flag variable we eventually produced. */ | |||
2762 | im_mem_ref *ref | |||
2763 | = memory_accesses.refs_list[bitmap_first_set_bit (mem_refs)]; | |||
2764 | sm_aux *aux = *aux_map.get (ref); | |||
2765 | ||||
2766 | /* Materialize ordered store sequences on exits. */ | |||
2767 | edge e; | |||
2768 | FOR_EACH_VEC_ELT (exits, i, e)for (i = 0; (exits).iterate ((i), &(e)); ++(i)) | |||
2769 | { | |||
2770 | edge append_cond_position = NULLnullptr; | |||
2771 | edge last_cond_fallthru = NULLnullptr; | |||
2772 | edge insert_e = e; | |||
2773 | /* Construct the single flag variable control flow and insert | |||
2774 | the ordered seq of stores in the then block. With | |||
2775 | -fstore-data-races we can do the stores unconditionally. */ | |||
2776 | if (aux->store_flag) | |||
2777 | insert_e | |||
2778 | = single_pred_edge | |||
2779 | (execute_sm_if_changed (e, NULL_TREE(tree) nullptr, NULL_TREE(tree) nullptr, | |||
2780 | aux->store_flag, | |||
2781 | loop_preheader_edge (loop), | |||
2782 | &aux->flag_bbs, append_cond_position, | |||
2783 | last_cond_fallthru)); | |||
2784 | execute_sm_exit (loop, insert_e, seq, aux_map, sm_ord, | |||
2785 | append_cond_position, last_cond_fallthru); | |||
2786 | gsi_commit_one_edge_insert (insert_e, NULLnullptr); | |||
2787 | } | |||
2788 | ||||
2789 | for (hash_map<im_mem_ref *, sm_aux *>::iterator iter = aux_map.begin (); | |||
2790 | iter != aux_map.end (); ++iter) | |||
2791 | delete (*iter).second; | |||
2792 | ||||
2793 | return; | |||
2794 | } | |||
2795 | ||||
2796 | /* To address PR57359 before actually applying store-motion check | |||
2797 | the candidates found for validity with regards to reordering | |||
2798 | relative to other stores which we until here disambiguated using | |||
2799 | TBAA which isn't valid. | |||
2800 | What matters is the order of the last stores to the mem_refs | |||
2801 | with respect to the other stores of the loop at the point of the | |||
2802 | loop exits. */ | |||
2803 | ||||
2804 | /* For each exit compute the store order, pruning from mem_refs | |||
2805 | on the fly. */ | |||
2806 | /* The complexity of this is at least | |||
2807 | O(number of exits * number of SM refs) but more approaching | |||
2808 | O(number of exits * number of SM refs * number of stores). */ | |||
2809 | /* ??? Somehow do this in a single sweep over the loop body. */ | |||
2810 | auto_vec<std::pair<edge, vec<seq_entry> > > sms; | |||
2811 | auto_bitmap refs_not_supported (&lim_bitmap_obstack); | |||
2812 | edge e; | |||
2813 | FOR_EACH_VEC_ELT (exits, i, e)for (i = 0; (exits).iterate ((i), &(e)); ++(i)) | |||
2814 | { | |||
2815 | vec<seq_entry> seq; | |||
2816 | seq.create (4); | |||
2817 | auto_bitmap refs_not_in_seq (&lim_bitmap_obstack); | |||
2818 | bitmap_and_compl (refs_not_in_seq, mem_refs, refs_not_supported); | |||
2819 | if (bitmap_empty_p (refs_not_in_seq)) | |||
2820 | { | |||
2821 | seq.release (); | |||
2822 | break; | |||
2823 | } | |||
2824 | auto_bitmap fully_visited; | |||
2825 | int res = sm_seq_valid_bb (loop, e->src, NULL_TREE(tree) nullptr, | |||
2826 | seq, refs_not_in_seq, | |||
2827 | refs_not_supported, false, | |||
2828 | fully_visited); | |||
2829 | if (res != 1) | |||
2830 | { | |||
2831 | bitmap_copy (refs_not_supported, mem_refs); | |||
2832 | seq.release (); | |||
2833 | break; | |||
2834 | } | |||
2835 | sms.safe_push (std::make_pair (e, seq)); | |||
2836 | } | |||
2837 | ||||
2838 | /* Prune pruned mem_refs from earlier processed exits. */ | |||
2839 | bool changed = !bitmap_empty_p (refs_not_supported); | |||
2840 | while (changed) | |||
2841 | { | |||
2842 | changed = false; | |||
2843 | std::pair<edge, vec<seq_entry> > *seq; | |||
2844 | FOR_EACH_VEC_ELT (sms, i, seq)for (i = 0; (sms).iterate ((i), &(seq)); ++(i)) | |||
2845 | { | |||
2846 | bool need_to_push = false; | |||
2847 | for (unsigned i = 0; i < seq->second.length (); ++i) | |||
2848 | { | |||
2849 | sm_kind kind = seq->second[i].second; | |||
2850 | if (kind == sm_other && seq->second[i].from == NULL_TREE(tree) nullptr) | |||
2851 | break; | |||
2852 | unsigned id = seq->second[i].first; | |||
2853 | unsigned new_idx; | |||
2854 | if (kind == sm_ord | |||
2855 | && bitmap_bit_p (refs_not_supported, id)) | |||
2856 | { | |||
2857 | seq->second[i].second = sm_other; | |||
2858 | gcc_assert (seq->second[i].from == NULL_TREE)((void)(!(seq->second[i].from == (tree) nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2858, __FUNCTION__), 0 : 0)); | |||
2859 | need_to_push = true; | |||
2860 | } | |||
2861 | else if (need_to_push | |||
2862 | && !sm_seq_push_down (seq->second, i, &new_idx)) | |||
2863 | { | |||
2864 | /* We need to push down both sm_ord and sm_other | |||
2865 | but for the latter we need to disqualify all | |||
2866 | following refs. */ | |||
2867 | if (kind == sm_ord) | |||
2868 | { | |||
2869 | if (bitmap_set_bit (refs_not_supported, id)) | |||
2870 | changed = true; | |||
2871 | seq->second[new_idx].second = sm_other; | |||
2872 | } | |||
2873 | else | |||
2874 | { | |||
2875 | for (unsigned j = seq->second.length () - 1; | |||
2876 | j > new_idx; --j) | |||
2877 | if (seq->second[j].second == sm_ord | |||
2878 | && bitmap_set_bit (refs_not_supported, | |||
2879 | seq->second[j].first)) | |||
2880 | changed = true; | |||
2881 | seq->second.truncate (new_idx); | |||
2882 | break; | |||
2883 | } | |||
2884 | } | |||
2885 | } | |||
2886 | } | |||
2887 | } | |||
2888 | std::pair<edge, vec<seq_entry> > *seq; | |||
2889 | FOR_EACH_VEC_ELT (sms, i, seq)for (i = 0; (sms).iterate ((i), &(seq)); ++(i)) | |||
2890 | { | |||
2891 | /* Prune sm_other from the end. */ | |||
2892 | while (!seq->second.is_empty () | |||
2893 | && seq->second.last ().second == sm_other) | |||
2894 | seq->second.pop (); | |||
2895 | /* Prune duplicates from the start. */ | |||
2896 | auto_bitmap seen (&lim_bitmap_obstack); | |||
2897 | unsigned j, k; | |||
2898 | for (j = k = 0; j < seq->second.length (); ++j) | |||
2899 | if (bitmap_set_bit (seen, seq->second[j].first)) | |||
2900 | { | |||
2901 | if (k != j) | |||
2902 | seq->second[k] = seq->second[j]; | |||
2903 | ++k; | |||
2904 | } | |||
2905 | seq->second.truncate (k); | |||
2906 | /* And verify. */ | |||
2907 | seq_entry *e; | |||
2908 | FOR_EACH_VEC_ELT (seq->second, j, e)for (j = 0; (seq->second).iterate ((j), &(e)); ++(j)) | |||
2909 | gcc_assert (e->second == sm_ord((void)(!(e->second == sm_ord || (e->second == sm_other && e->from != (tree) nullptr)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2910, __FUNCTION__), 0 : 0)) | |||
2910 | || (e->second == sm_other && e->from != NULL_TREE))((void)(!(e->second == sm_ord || (e->second == sm_other && e->from != (tree) nullptr)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2910, __FUNCTION__), 0 : 0)); | |||
2911 | } | |||
2912 | ||||
2913 | /* Verify dependence for refs we cannot handle with the order preserving | |||
2914 | code (refs_not_supported) or prune them from mem_refs. */ | |||
2915 | auto_vec<seq_entry> unord_refs; | |||
2916 | EXECUTE_IF_SET_IN_BITMAP (refs_not_supported, 0, i, bi)for (bmp_iter_set_init (&(bi), (refs_not_supported), (0), &(i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (&(bi), &(i))) | |||
2917 | { | |||
2918 | ref = memory_accesses.refs_list[i]; | |||
2919 | if (!ref_indep_loop_p (loop, ref, sm_waw)) | |||
2920 | bitmap_clear_bit (mem_refs, i); | |||
2921 | /* We've now verified store order for ref with respect to all other | |||
2922 | stores in the loop does not matter. */ | |||
2923 | else | |||
2924 | unord_refs.safe_push (seq_entry (i, sm_unord)); | |||
2925 | } | |||
2926 | ||||
2927 | hash_map<im_mem_ref *, sm_aux *> aux_map; | |||
2928 | ||||
2929 | /* Execute SM but delay the store materialization for ordered | |||
2930 | sequences on exit. */ | |||
2931 | EXECUTE_IF_SET_IN_BITMAP (mem_refs, 0, i, bi)for (bmp_iter_set_init (&(bi), (mem_refs), (0), &(i)) ; bmp_iter_set (&(bi), &(i)); bmp_iter_next (&(bi ), &(i))) | |||
2932 | { | |||
2933 | ref = memory_accesses.refs_list[i]; | |||
2934 | execute_sm (loop, ref, aux_map, bitmap_bit_p (refs_not_supported, i), | |||
2935 | false); | |||
2936 | } | |||
2937 | ||||
2938 | /* Materialize ordered store sequences on exits. */ | |||
2939 | FOR_EACH_VEC_ELT (exits, i, e)for (i = 0; (exits).iterate ((i), &(e)); ++(i)) | |||
2940 | { | |||
2941 | edge append_cond_position = NULLnullptr; | |||
2942 | edge last_cond_fallthru = NULLnullptr; | |||
2943 | if (i < sms.length ()) | |||
2944 | { | |||
2945 | gcc_assert (sms[i].first == e)((void)(!(sms[i].first == e) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 2945, __FUNCTION__), 0 : 0)); | |||
2946 | execute_sm_exit (loop, e, sms[i].second, aux_map, sm_ord, | |||
2947 | append_cond_position, last_cond_fallthru); | |||
2948 | sms[i].second.release (); | |||
2949 | } | |||
2950 | if (!unord_refs.is_empty ()) | |||
2951 | execute_sm_exit (loop, e, unord_refs, aux_map, sm_unord, | |||
2952 | append_cond_position, last_cond_fallthru); | |||
2953 | /* Commit edge inserts here to preserve the order of stores | |||
2954 | when an exit exits multiple loops. */ | |||
2955 | gsi_commit_one_edge_insert (e, NULLnullptr); | |||
2956 | } | |||
2957 | ||||
2958 | for (hash_map<im_mem_ref *, sm_aux *>::iterator iter = aux_map.begin (); | |||
2959 | iter != aux_map.end (); ++iter) | |||
2960 | delete (*iter).second; | |||
2961 | } | |||
2962 | ||||
2963 | class ref_always_accessed | |||
2964 | { | |||
2965 | public: | |||
2966 | ref_always_accessed (class loop *loop_, bool stored_p_) | |||
2967 | : loop (loop_), stored_p (stored_p_) {} | |||
2968 | bool operator () (mem_ref_loc *loc); | |||
2969 | class loop *loop; | |||
2970 | bool stored_p; | |||
2971 | }; | |||
2972 | ||||
2973 | bool | |||
2974 | ref_always_accessed::operator () (mem_ref_loc *loc) | |||
2975 | { | |||
2976 | class loop *must_exec; | |||
2977 | ||||
2978 | struct lim_aux_data *lim_data = get_lim_data (loc->stmt); | |||
2979 | if (!lim_data) | |||
2980 | return false; | |||
2981 | ||||
2982 | /* If we require an always executed store make sure the statement | |||
2983 | is a store. */ | |||
2984 | if (stored_p) | |||
2985 | { | |||
2986 | tree lhs = gimple_get_lhs (loc->stmt); | |||
2987 | if (!lhs | |||
2988 | || !(DECL_P (lhs)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (lhs)->base.code))] == tcc_declaration) || REFERENCE_CLASS_P (lhs)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (lhs)->base.code))] == tcc_reference))) | |||
2989 | return false; | |||
2990 | } | |||
2991 | ||||
2992 | must_exec = lim_data->always_executed_in; | |||
2993 | if (!must_exec) | |||
2994 | return false; | |||
2995 | ||||
2996 | if (must_exec == loop | |||
2997 | || flow_loop_nested_p (must_exec, loop)) | |||
2998 | return true; | |||
2999 | ||||
3000 | return false; | |||
3001 | } | |||
3002 | ||||
3003 | /* Returns true if REF is always accessed in LOOP. If STORED_P is true | |||
3004 | make sure REF is always stored to in LOOP. */ | |||
3005 | ||||
3006 | static bool | |||
3007 | ref_always_accessed_p (class loop *loop, im_mem_ref *ref, bool stored_p) | |||
3008 | { | |||
3009 | return for_all_locs_in_loop (loop, ref, | |||
3010 | ref_always_accessed (loop, stored_p)); | |||
3011 | } | |||
3012 | ||||
3013 | /* Returns true if REF1 and REF2 are independent. */ | |||
3014 | ||||
3015 | static bool | |||
3016 | refs_independent_p (im_mem_ref *ref1, im_mem_ref *ref2, bool tbaa_p) | |||
3017 | { | |||
3018 | if (ref1 == ref2) | |||
3019 | return true; | |||
3020 | ||||
3021 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3022 | fprintf (dump_file, "Querying dependency of refs %u and %u: ", | |||
3023 | ref1->id, ref2->id); | |||
3024 | ||||
3025 | if (mem_refs_may_alias_p (ref1, ref2, &memory_accesses.ttae_cache, tbaa_p)) | |||
3026 | { | |||
3027 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3028 | fprintf (dump_file, "dependent.\n"); | |||
3029 | return false; | |||
3030 | } | |||
3031 | else | |||
3032 | { | |||
3033 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3034 | fprintf (dump_file, "independent.\n"); | |||
3035 | return true; | |||
3036 | } | |||
3037 | } | |||
3038 | ||||
3039 | /* Returns true if REF is independent on all other accessess in LOOP. | |||
3040 | KIND specifies the kind of dependence to consider. | |||
3041 | lim_raw assumes REF is not stored in LOOP and disambiguates RAW | |||
3042 | dependences so if true REF can be hoisted out of LOOP | |||
3043 | sm_war disambiguates a store REF against all other loads to see | |||
3044 | whether the store can be sunk across loads out of LOOP | |||
3045 | sm_waw disambiguates a store REF against all other stores to see | |||
3046 | whether the store can be sunk across stores out of LOOP. */ | |||
3047 | ||||
3048 | static bool | |||
3049 | ref_indep_loop_p (class loop *loop, im_mem_ref *ref, dep_kind kind) | |||
3050 | { | |||
3051 | bool indep_p = true; | |||
3052 | bitmap refs_to_check; | |||
3053 | ||||
3054 | if (kind == sm_war) | |||
3055 | refs_to_check = &memory_accesses.refs_loaded_in_loop[loop->num]; | |||
3056 | else | |||
3057 | refs_to_check = &memory_accesses.refs_stored_in_loop[loop->num]; | |||
3058 | ||||
3059 | if (bitmap_bit_p (refs_to_check, UNANALYZABLE_MEM_ID0) | |||
3060 | || ref->mem.ref == error_mark_nodeglobal_trees[TI_ERROR_MARK]) | |||
3061 | indep_p = false; | |||
3062 | else | |||
3063 | { | |||
3064 | /* tri-state, { unknown, independent, dependent } */ | |||
3065 | dep_state state = query_loop_dependence (loop, ref, kind); | |||
3066 | if (state != dep_unknown) | |||
3067 | return state == dep_independent ? true : false; | |||
3068 | ||||
3069 | class loop *inner = loop->inner; | |||
3070 | while (inner) | |||
3071 | { | |||
3072 | if (!ref_indep_loop_p (inner, ref, kind)) | |||
3073 | { | |||
3074 | indep_p = false; | |||
3075 | break; | |||
3076 | } | |||
3077 | inner = inner->next; | |||
3078 | } | |||
3079 | ||||
3080 | if (indep_p) | |||
3081 | { | |||
3082 | unsigned i; | |||
3083 | bitmap_iterator bi; | |||
3084 | EXECUTE_IF_SET_IN_BITMAP (refs_to_check, 0, i, bi)for (bmp_iter_set_init (&(bi), (refs_to_check), (0), & (i)); bmp_iter_set (&(bi), &(i)); bmp_iter_next (& (bi), &(i))) | |||
3085 | { | |||
3086 | im_mem_ref *aref = memory_accesses.refs_list[i]; | |||
3087 | if (aref->mem.ref == error_mark_nodeglobal_trees[TI_ERROR_MARK]) | |||
3088 | { | |||
3089 | gimple *stmt = aref->accesses_in_loop[0].stmt; | |||
3090 | if ((kind == sm_war | |||
3091 | && ref_maybe_used_by_stmt_p (stmt, &ref->mem, | |||
3092 | kind != sm_waw)) | |||
3093 | || stmt_may_clobber_ref_p_1 (stmt, &ref->mem, | |||
3094 | kind != sm_waw)) | |||
3095 | { | |||
3096 | indep_p = false; | |||
3097 | break; | |||
3098 | } | |||
3099 | } | |||
3100 | else if (!refs_independent_p (ref, aref, kind != sm_waw)) | |||
3101 | { | |||
3102 | indep_p = false; | |||
3103 | break; | |||
3104 | } | |||
3105 | } | |||
3106 | } | |||
3107 | } | |||
3108 | ||||
3109 | if (dump_file && (dump_flags & TDF_DETAILS)) | |||
3110 | fprintf (dump_file, "Querying %s dependencies of ref %u in loop %d: %s\n", | |||
3111 | kind == lim_raw ? "RAW" : (kind == sm_war ? "SM WAR" : "SM WAW"), | |||
3112 | ref->id, loop->num, indep_p ? "independent" : "dependent"); | |||
3113 | ||||
3114 | /* Record the computed result in the cache. */ | |||
3115 | record_loop_dependence (loop, ref, kind, | |||
3116 | indep_p ? dep_independent : dep_dependent); | |||
3117 | ||||
3118 | return indep_p; | |||
3119 | } | |||
3120 | ||||
3121 | class ref_in_loop_hot_body | |||
3122 | { | |||
3123 | public: | |||
3124 | ref_in_loop_hot_body (class loop *loop_) : l (loop_) {} | |||
3125 | bool operator () (mem_ref_loc *loc); | |||
3126 | class loop *l; | |||
3127 | }; | |||
3128 | ||||
3129 | /* Check the coldest loop between loop L and innermost loop. If there is one | |||
3130 | cold loop between L and INNER_LOOP, store motion can be performed, otherwise | |||
3131 | no cold loop means no store motion. get_coldest_out_loop also handles cases | |||
3132 | when l is inner_loop. */ | |||
3133 | bool | |||
3134 | ref_in_loop_hot_body::operator () (mem_ref_loc *loc) | |||
3135 | { | |||
3136 | basic_block curr_bb = gimple_bb (loc->stmt); | |||
3137 | class loop *inner_loop = curr_bb->loop_father; | |||
3138 | return get_coldest_out_loop (l, inner_loop, curr_bb); | |||
3139 | } | |||
3140 | ||||
3141 | ||||
3142 | /* Returns true if we can perform store motion of REF from LOOP. */ | |||
3143 | ||||
3144 | static bool | |||
3145 | can_sm_ref_p (class loop *loop, im_mem_ref *ref) | |||
3146 | { | |||
3147 | tree base; | |||
3148 | ||||
3149 | /* Can't hoist unanalyzable refs. */ | |||
3150 | if (!MEM_ANALYZABLE (ref)((ref)->id != 0)) | |||
3151 | return false; | |||
3152 | ||||
3153 | /* Can't hoist/sink aggregate copies. */ | |||
3154 | if (ref->mem.ref == error_mark_nodeglobal_trees[TI_ERROR_MARK]) | |||
3155 | return false; | |||
3156 | ||||
3157 | /* It should be movable. */ | |||
3158 | if (!is_gimple_reg_type (TREE_TYPE (ref->mem.ref)((contains_struct_check ((ref->mem.ref), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 3158, __FUNCTION__))->typed.type)) | |||
3159 | || TREE_THIS_VOLATILE (ref->mem.ref)((ref->mem.ref)->base.volatile_flag) | |||
3160 | || !for_each_index (&ref->mem.ref, may_move_till, loop)) | |||
3161 | return false; | |||
3162 | ||||
3163 | /* If it can throw fail, we do not properly update EH info. */ | |||
3164 | if (tree_could_throw_p (ref->mem.ref)) | |||
3165 | return false; | |||
3166 | ||||
3167 | /* If it can trap, it must be always executed in LOOP. | |||
3168 | Readonly memory locations may trap when storing to them, but | |||
3169 | tree_could_trap_p is a predicate for rvalues, so check that | |||
3170 | explicitly. */ | |||
3171 | base = get_base_address (ref->mem.ref); | |||
3172 | if ((tree_could_trap_p (ref->mem.ref) | |||
3173 | || (DECL_P (base)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (base)->base.code))] == tcc_declaration) && TREE_READONLY (base)((non_type_check ((base), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/tree-ssa-loop-im.cc" , 3173, __FUNCTION__))->base.readonly_flag))) | |||
3174 | /* ??? We can at least use false here, allowing loads? We | |||
3175 | are forcing conditional stores if the ref is not always | |||
3176 | stored to later anyway. So this would only guard | |||
3177 | the load we need to emit. Thus when the ref is not | |||
3178 | loaded we can elide this completely? */ | |||
3179 | && !ref_always_accessed_p (loop, ref, true)) | |||
3180 | return false; | |||
3181 | ||||
3182 | /* Verify all loads of ref can be hoisted. */ | |||
3183 | if (ref->loaded | |||
3184 | && bitmap_bit_p (ref->loaded, loop->num) | |||
3185 | && !ref_indep_loop_p (loop, ref, lim_raw)) | |||
3186 | return false; | |||
3187 | ||||
3188 | /* Verify the candidate can be disambiguated against all loads, | |||
3189 | that is, we can elide all in-loop stores. Disambiguation | |||
3190 | against stores is done later when we cannot guarantee preserving | |||
3191 | the order of stores. */ | |||
3192 | if (!ref_indep_loop_p (loop, ref, sm_war)) | |||
3193 | return false; | |||
3194 | ||||
3195 | /* Verify whether the candidate is hot for LOOP. Only do store motion if the | |||
3196 | candidate's profile count is hot. Statement in cold BB shouldn't be moved | |||
3197 | out of it's loop_father. */ | |||
3198 | if (!for_all_locs_in_loop (loop, ref, ref_in_loop_hot_body (loop))) | |||
3199 | return false; | |||
3200 | ||||
3201 | return true; | |||
3202 | } | |||
3203 | ||||
3204 | /* Marks the references in LOOP for that store motion should be performed | |||
3205 | in REFS_TO_SM. SM_EXECUTED is the set of references for that store | |||
3206 | motion was performed in one of the outer loops. */ | |||
3207 | ||||
3208 | static void | |||
3209 | find_refs_for_sm (class loop *loop, bitmap sm_executed, bitmap refs_to_sm) | |||
3210 | { | |||
3211 | bitmap refs = &memory_accesses.all_refs_stored_in_loop[loop->num]; | |||
3212 | unsigned i; | |||
3213 | bitmap_iterator bi; | |||
3214 | im_mem_ref *ref; | |||
3215 | ||||
3216 | EXECUTE_IF_AND_COMPL_IN_BITMAP (refs, sm_executed, 0, i, bi)for (bmp_iter_and_compl_init (&(bi), (refs), (sm_executed ), (0), &(i)); bmp_iter_and_compl (&(bi), &(i)); bmp_iter_next (&(bi), &(i))) | |||
3217 | { | |||
3218 | ref = memory_accesses.refs_list[i]; | |||
3219 | if (can_sm_ref_p (loop, ref) && dbg_cnt (lim)) | |||
3220 | bitmap_set_bit (refs_to_sm, i); | |||
3221 | } | |||
3222 | } | |||
3223 | ||||
3224 | /* Checks whether LOOP (with exits stored in EXITS array) is suitable | |||
3225 | for a store motion optimization (i.e. whether we can insert statement | |||
3226 | on its exits). */ | |||
3227 | ||||
3228 | static bool | |||
3229 | loop_suitable_for_sm (class loop *loop ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
3230 | const vec<edge> &exits) | |||
3231 | { | |||
3232 | unsigned i; | |||
3233 | edge ex; | |||
3234 | ||||
3235 | FOR_EACH_VEC_ELT (exits, i, ex)for (i = 0; (exits).iterate ((i), &(ex)); ++(i)) | |||
3236 | if (ex->flags & (EDGE_ABNORMAL | EDGE_EH)) | |||
3237 | return false; | |||
3238 | ||||
3239 | return true; | |||
3240 | } | |||
3241 | ||||
3242 | /* Try to perform store motion for all memory references modified inside | |||
3243 | LOOP. SM_EXECUTED is the bitmap of the memory references for that | |||
3244 | store motion was executed in one of the outer loops. */ | |||
3245 | ||||
3246 | static void | |||
3247 | store_motion_loop (class loop *loop, bitmap sm_executed) | |||
3248 | { | |||
3249 | auto_vec<edge> exits = get_loop_exit_edges (loop); | |||
3250 | class loop *subloop; | |||
3251 | bitmap sm_in_loop = BITMAP_ALLOCbitmap_alloc (&lim_bitmap_obstack); | |||
3252 | ||||
3253 | if (loop_suitable_for_sm (loop, exits)) | |||
3254 | { | |||
3255 | find_refs_for_sm (loop, sm_executed, sm_in_loop); | |||
3256 | if (!bitmap_empty_p (sm_in_loop)) | |||
3257 | hoist_memory_references (loop, sm_in_loop, exits); | |||
3258 | } | |||
3259 | ||||
3260 | bitmap_ior_into (sm_executed, sm_in_loop); | |||
3261 | for (subloop = loop->inner; subloop != NULLnullptr; subloop = subloop->next) | |||
3262 | store_motion_loop (subloop, sm_executed); | |||
3263 | bitmap_and_compl_into (sm_executed, sm_in_loop); | |||
3264 | BITMAP_FREE (sm_in_loop)((void) (bitmap_obstack_free ((bitmap) sm_in_loop), (sm_in_loop ) = (bitmap) nullptr)); | |||
3265 | } | |||
3266 | ||||
3267 | /* Try to perform store motion for all memory references modified inside | |||
3268 | loops. */ | |||
3269 | ||||
3270 | static void | |||
3271 | do_store_motion (void) | |||
3272 | { | |||
3273 | class loop *loop; | |||
3274 | bitmap sm_executed = BITMAP_ALLOCbitmap_alloc (&lim_bitmap_obstack); | |||
3275 | ||||
3276 | for (loop = current_loops((cfun + 0)->x_current_loops)->tree_root->inner; loop != NULLnullptr; loop = loop->next) | |||
3277 | store_motion_loop (loop, sm_executed); | |||
3278 | ||||
3279 | BITMAP_FREE (sm_executed)((void) (bitmap_obstack_free ((bitmap) sm_executed), (sm_executed ) = (bitmap) nullptr)); | |||
3280 | } | |||
3281 | ||||
3282 | /* Fills ALWAYS_EXECUTED_IN information for basic blocks of LOOP, i.e. | |||
3283 | for each such basic block bb records the outermost loop for that execution | |||
3284 | of its header implies execution of bb. CONTAINS_CALL is the bitmap of | |||
3285 | blocks that contain a nonpure call. */ | |||
3286 | ||||
3287 | static void | |||
3288 | fill_always_executed_in_1 (class loop *loop, sbitmap contains_call) | |||
3289 | { | |||
3290 | basic_block bb = NULLnullptr, last = NULLnullptr; | |||
3291 | edge e; | |||
3292 | class loop *inn_loop = loop; | |||
3293 | ||||
3294 | if (ALWAYS_EXECUTED_IN (loop->header)((class loop *) (loop->header)->aux) == NULLnullptr) | |||
3295 | { | |||
3296 | auto_vec<basic_block, 64> worklist; | |||
3297 | worklist.reserve_exact (loop->num_nodes); | |||
3298 | worklist.quick_push (loop->header); | |||
3299 | do | |||
3300 | { | |||
3301 | edge_iterator ei; | |||
3302 | bb = worklist.pop (); | |||
3303 | ||||
3304 | if (!flow_bb_inside_loop_p (inn_loop, bb)) | |||
3305 | { | |||
3306 | /* When we are leaving a possibly infinite inner loop | |||
3307 | we have to stop processing. */ | |||
3308 | if (!finite_loop_p (inn_loop)) | |||
3309 | break; | |||
3310 | /* If the loop was finite we can continue with processing | |||
3311 | the loop we exited to. */ | |||
3312 | inn_loop = bb->loop_father; | |||
3313 | } | |||
3314 | ||||
3315 | if (dominated_by_p (CDI_DOMINATORS, loop->latch, bb)) | |||
3316 | last = bb; | |||
3317 | ||||
3318 | if (bitmap_bit_p (contains_call, bb->index)) | |||
3319 | break; | |||
3320 | ||||
3321 | /* If LOOP exits from this BB stop processing. */ | |||
3322 | FOR_EACH_EDGE (e, ei, bb->succs)for ((ei) = ei_start_1 (&((bb->succs))); ei_cond ((ei) , &(e)); ei_next (&(ei))) | |||
3323 | if (!flow_bb_inside_loop_p (loop, e->dest)) | |||
3324 | break; | |||
3325 | if (e) | |||
3326 | break; | |||
3327 | ||||
3328 | /* A loop might be infinite (TODO use simple loop analysis | |||
3329 | to disprove this if possible). */ | |||
3330 | if (bb->flags & BB_IRREDUCIBLE_LOOP) | |||
3331 | break; | |||
3332 | ||||
3333 | if (bb->loop_father->header == bb) | |||
3334 | /* Record that we enter into a subloop since it might not | |||
3335 | be finite. */ | |||
3336 | /* ??? Entering into a not always executed subloop makes | |||
3337 | fill_always_executed_in quadratic in loop depth since | |||
3338 | we walk those loops N times. This is not a problem | |||
3339 | in practice though, see PR102253 for a worst-case testcase. */ | |||
3340 | inn_loop = bb->loop_father; | |||
3341 | ||||
3342 | /* Walk the body of LOOP sorted by dominance relation. Additionally, | |||
3343 | if a basic block S dominates the latch, then only blocks dominated | |||
3344 | by S are after it. | |||
3345 | This is get_loop_body_in_dom_order using a worklist algorithm and | |||
3346 | stopping once we are no longer interested in visiting further | |||
3347 | blocks. */ | |||
3348 | unsigned old_len = worklist.length (); | |||
3349 | unsigned postpone = 0; | |||
3350 | for (basic_block son = first_dom_son (CDI_DOMINATORS, bb); | |||
3351 | son; | |||
3352 | son = next_dom_son (CDI_DOMINATORS, son)) | |||
3353 | { | |||
3354 | if (!flow_bb_inside_loop_p (loop, son)) | |||
3355 | continue; | |||
3356 | if (dominated_by_p (CDI_DOMINATORS, loop->latch, son)) | |||
3357 | postpone = worklist.length (); | |||
3358 | worklist.quick_push (son); | |||
3359 | } | |||
3360 | if (postpone) | |||
3361 | /* Postponing the block that dominates the latch means | |||
3362 | processing it last and thus putting it earliest in the | |||
3363 | worklist. */ | |||
3364 | std::swap (worklist[old_len], worklist[postpone]); | |||
3365 | } | |||
3366 | while (!worklist.is_empty ()); | |||
3367 | ||||
3368 | while (1) | |||
3369 | { | |||
3370 | if (dump_enabled_p ()) | |||
3371 | dump_printf (MSG_NOTE, "BB %d is always executed in loop %d\n", | |||
3372 | last->index, loop->num); | |||
3373 | SET_ALWAYS_EXECUTED_IN (last, loop)((last)->aux = (void *) (loop)); | |||
3374 | if (last == loop->header) | |||
3375 | break; | |||
3376 | last = get_immediate_dominator (CDI_DOMINATORS, last); | |||
3377 | } | |||
3378 | } | |||
3379 | ||||
3380 | for (loop = loop->inner; loop; loop = loop->next) | |||
3381 | fill_always_executed_in_1 (loop, contains_call); | |||
3382 | } | |||
3383 | ||||
3384 | /* Fills ALWAYS_EXECUTED_IN information for basic blocks, i.e. | |||
3385 | for each such basic block bb records the outermost loop for that execution | |||
3386 | of its header implies execution of bb. */ | |||
3387 | ||||
3388 | static void | |||
3389 | fill_always_executed_in (void) | |||
3390 | { | |||
3391 | basic_block bb; | |||
3392 | class loop *loop; | |||
3393 | ||||
3394 | auto_sbitmap contains_call (last_basic_block_for_fn (cfun)(((cfun + 0))->cfg->x_last_basic_block)); | |||
3395 | bitmap_clear (contains_call); | |||
3396 | FOR_EACH_BB_FN (bb, cfun)for (bb = ((cfun + 0))->cfg->x_entry_block_ptr->next_bb ; bb != ((cfun + 0))->cfg->x_exit_block_ptr; bb = bb-> next_bb) | |||
3397 | { | |||
3398 | gimple_stmt_iterator gsi; | |||
3399 | for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | |||
3400 | { | |||
3401 | if (nonpure_call_p (gsi_stmt (gsi))) | |||
3402 | break; | |||
3403 | } | |||
3404 | ||||
3405 | if (!gsi_end_p (gsi)) | |||
3406 | bitmap_set_bit (contains_call, bb->index); | |||
3407 | } | |||
3408 | ||||
3409 | for (loop = current_loops((cfun + 0)->x_current_loops)->tree_root->inner; loop; loop = loop->next) | |||
3410 | fill_always_executed_in_1 (loop, contains_call); | |||
3411 | } | |||
3412 | ||||
3413 | /* Find the coldest loop preheader for LOOP, also find the nearest hotter loop | |||
3414 | to LOOP. Then recursively iterate each inner loop. */ | |||
3415 | ||||
3416 | void | |||
3417 | fill_coldest_and_hotter_out_loop (class loop *coldest_loop, | |||
3418 | class loop *hotter_loop, class loop *loop) | |||
3419 | { | |||
3420 | if (bb_colder_than_loop_preheader (loop_preheader_edge (loop)->src, | |||
3421 | coldest_loop)) | |||
3422 | coldest_loop = loop; | |||
3423 | ||||
3424 | coldest_outermost_loop[loop->num] = coldest_loop; | |||
3425 | ||||
3426 | hotter_than_inner_loop[loop->num] = NULLnullptr; | |||
3427 | class loop *outer_loop = loop_outer (loop); | |||
3428 | if (hotter_loop | |||
3429 | && bb_colder_than_loop_preheader (loop_preheader_edge (loop)->src, | |||
3430 | hotter_loop)) | |||
3431 | hotter_than_inner_loop[loop->num] = hotter_loop; | |||
3432 | ||||
3433 | if (outer_loop && outer_loop != current_loops((cfun + 0)->x_current_loops)->tree_root | |||
3434 | && bb_colder_than_loop_preheader (loop_preheader_edge (loop)->src, | |||
3435 | outer_loop)) | |||
3436 | hotter_than_inner_loop[loop->num] = outer_loop; | |||
3437 | ||||
3438 | if (dump_enabled_p ()) | |||
3439 | { | |||
3440 | dump_printf (MSG_NOTE, "loop %d's coldest_outermost_loop is %d, ", | |||
3441 | loop->num, coldest_loop->num); | |||
3442 | if (hotter_than_inner_loop[loop->num]) | |||
3443 | dump_printf (MSG_NOTE, "hotter_than_inner_loop is %d\n", | |||
3444 | hotter_than_inner_loop[loop->num]->num); | |||
3445 | else | |||
3446 | dump_printf (MSG_NOTE, "hotter_than_inner_loop is NULL\n"); | |||
3447 | } | |||
3448 | ||||
3449 | class loop *inner_loop; | |||
3450 | for (inner_loop = loop->inner; inner_loop; inner_loop = inner_loop->next) | |||
3451 | fill_coldest_and_hotter_out_loop (coldest_loop, | |||
3452 | hotter_than_inner_loop[loop->num], | |||
3453 | inner_loop); | |||
3454 | } | |||
3455 | ||||
3456 | /* Compute the global information needed by the loop invariant motion pass. */ | |||
3457 | ||||
3458 | static void | |||
3459 | tree_ssa_lim_initialize (bool store_motion) | |||
3460 | { | |||
3461 | unsigned i; | |||
3462 | ||||
3463 | bitmap_obstack_initialize (&lim_bitmap_obstack); | |||
3464 | gcc_obstack_init (&mem_ref_obstack)_obstack_begin (((&mem_ref_obstack)), (memory_block_pool:: block_size), (0), (mempool_obstack_chunk_alloc), (mempool_obstack_chunk_free )); | |||
3465 | lim_aux_data_map = new hash_map<gimple *, lim_aux_data *>; | |||
3466 | ||||
3467 | if (flag_tmglobal_options.x_flag_tm) | |||
3468 | compute_transaction_bits (); | |||
3469 | ||||
3470 | memory_accesses.refs = new hash_table<mem_ref_hasher> (100); | |||
3471 | memory_accesses.refs_list.create (100); | |||
3472 | /* Allocate a special, unanalyzable mem-ref with ID zero. */ | |||
3473 | memory_accesses.refs_list.quick_push | |||
3474 | (mem_ref_alloc (NULLnullptr, 0, UNANALYZABLE_MEM_ID0)); | |||
3475 | ||||
3476 | memory_accesses.refs_loaded_in_loop.create (number_of_loops (cfun(cfun + 0))); | |||
3477 | memory_accesses.refs_loaded_in_loop.quick_grow (number_of_loops (cfun(cfun + 0))); | |||
3478 | memory_accesses.refs_stored_in_loop.create (number_of_loops (cfun(cfun + 0))); | |||
3479 | memory_accesses.refs_stored_in_loop.quick_grow (number_of_loops (cfun(cfun + 0))); | |||
3480 | if (store_motion) | |||
3481 | { | |||
3482 | memory_accesses.all_refs_stored_in_loop.create (number_of_loops (cfun(cfun + 0))); | |||
3483 | memory_accesses.all_refs_stored_in_loop.quick_grow | |||
3484 | (number_of_loops (cfun(cfun + 0))); | |||
3485 | } | |||
3486 | ||||
3487 | for (i = 0; i < number_of_loops (cfun(cfun + 0)); i++) | |||
3488 | { | |||
3489 | bitmap_initialize (&memory_accesses.refs_loaded_in_loop[i], | |||
3490 | &lim_bitmap_obstack); | |||
3491 | bitmap_initialize (&memory_accesses.refs_stored_in_loop[i], | |||
3492 | &lim_bitmap_obstack); | |||
3493 | if (store_motion) | |||
3494 | bitmap_initialize (&memory_accesses.all_refs_stored_in_loop[i], | |||
3495 | &lim_bitmap_obstack); | |||
3496 | } | |||
3497 | ||||
3498 | memory_accesses.ttae_cache = NULLnullptr; | |||
3499 | ||||
3500 | /* Initialize bb_loop_postorder with a mapping from loop->num to | |||
3501 | its postorder index. */ | |||
3502 | i = 0; | |||
3503 | bb_loop_postorder = XNEWVEC (unsigned, number_of_loops (cfun))((unsigned *) xmalloc (sizeof (unsigned) * (number_of_loops ( (cfun + 0))))); | |||
3504 | for (auto loop : loops_list (cfun(cfun + 0), LI_FROM_INNERMOST)) | |||
3505 | bb_loop_postorder[loop->num] = i++; | |||
3506 | } | |||
3507 | ||||
3508 | /* Cleans up after the invariant motion pass. */ | |||
3509 | ||||
3510 | static void | |||
3511 | tree_ssa_lim_finalize (void) | |||
3512 | { | |||
3513 | basic_block bb; | |||
3514 | unsigned i; | |||
3515 | im_mem_ref *ref; | |||
3516 | ||||
3517 | FOR_EACH_BB_FN (bb, cfun)for (bb = ((cfun + 0))->cfg->x_entry_block_ptr->next_bb ; bb != ((cfun + 0))->cfg->x_exit_block_ptr; bb = bb-> next_bb) | |||
3518 | SET_ALWAYS_EXECUTED_IN (bb, NULL)((bb)->aux = (void *) (nullptr)); | |||
3519 | ||||
3520 | bitmap_obstack_release (&lim_bitmap_obstack); | |||
3521 | delete lim_aux_data_map; | |||
3522 | ||||
3523 | delete memory_accesses.refs; | |||
3524 | memory_accesses.refs = NULLnullptr; | |||
3525 | ||||
3526 | FOR_EACH_VEC_ELT (memory_accesses.refs_list, i, ref)for (i = 0; (memory_accesses.refs_list).iterate ((i), &(ref )); ++(i)) | |||
3527 | memref_free (ref); | |||
3528 | memory_accesses.refs_list.release (); | |||
3529 | obstack_free (&mem_ref_obstack, NULL)__extension__ ({ struct obstack *__o = (&mem_ref_obstack) ; void *__obj = (void *) (nullptr); if (__obj > (void *) __o ->chunk && __obj < (void *) __o->chunk_limit ) __o->next_free = __o->object_base = (char *) __obj; else _obstack_free (__o, __obj); }); | |||
3530 | ||||
3531 | memory_accesses.refs_loaded_in_loop.release (); | |||
3532 | memory_accesses.refs_stored_in_loop.release (); | |||
3533 | memory_accesses.all_refs_stored_in_loop.release (); | |||
3534 | ||||
3535 | if (memory_accesses.ttae_cache) | |||
3536 | free_affine_expand_cache (&memory_accesses.ttae_cache); | |||
3537 | ||||
3538 | free (bb_loop_postorder); | |||
3539 | ||||
3540 | coldest_outermost_loop.release (); | |||
3541 | hotter_than_inner_loop.release (); | |||
3542 | } | |||
3543 | ||||
3544 | /* Moves invariants from loops. Only "expensive" invariants are moved out -- | |||
3545 | i.e. those that are likely to be win regardless of the register pressure. | |||
3546 | Only perform store motion if STORE_MOTION is true. */ | |||
3547 | ||||
3548 | unsigned int | |||
3549 | loop_invariant_motion_in_fun (function *fun, bool store_motion) | |||
3550 | { | |||
3551 | unsigned int todo = 0; | |||
3552 | ||||
3553 | tree_ssa_lim_initialize (store_motion); | |||
3554 | ||||
3555 | mark_ssa_maybe_undefs (); | |||
3556 | ||||
3557 | /* Gathers information about memory accesses in the loops. */ | |||
3558 | analyze_memory_references (store_motion); | |||
3559 | ||||
3560 | /* Fills ALWAYS_EXECUTED_IN information for basic blocks. */ | |||
3561 | fill_always_executed_in (); | |||
3562 | ||||
3563 | /* Pre-compute coldest outermost loop and nearest hotter loop of each loop. | |||
3564 | */ | |||
3565 | class loop *loop; | |||
3566 | coldest_outermost_loop.create (number_of_loops (cfun(cfun + 0))); | |||
3567 | coldest_outermost_loop.safe_grow_cleared (number_of_loops (cfun(cfun + 0))); | |||
3568 | hotter_than_inner_loop.create (number_of_loops (cfun(cfun + 0))); | |||
3569 | hotter_than_inner_loop.safe_grow_cleared (number_of_loops (cfun(cfun + 0))); | |||
3570 | for (loop = current_loops((cfun + 0)->x_current_loops)->tree_root->inner; loop != NULLnullptr; loop = loop->next) | |||
3571 | fill_coldest_and_hotter_out_loop (loop, NULLnullptr, loop); | |||
3572 | ||||
3573 | int *rpo = XNEWVEC (int, last_basic_block_for_fn (fun))((int *) xmalloc (sizeof (int) * (((fun)->cfg->x_last_basic_block )))); | |||
3574 | int n = pre_and_rev_post_order_compute_fn (fun, NULLnullptr, rpo, false); | |||
3575 | ||||
3576 | /* For each statement determine the outermost loop in that it is | |||
3577 | invariant and cost for computing the invariant. */ | |||
3578 | for (int i = 0; i < n; ++i) | |||
3579 | compute_invariantness (BASIC_BLOCK_FOR_FN (fun, rpo[i])((*((fun)->cfg->x_basic_block_info))[(rpo[i])])); | |||
3580 | ||||
3581 | /* Execute store motion. Force the necessary invariants to be moved | |||
3582 | out of the loops as well. */ | |||
3583 | if (store_motion) | |||
3584 | do_store_motion (); | |||
3585 | ||||
3586 | free (rpo); | |||
3587 | rpo = XNEWVEC (int, last_basic_block_for_fn (fun))((int *) xmalloc (sizeof (int) * (((fun)->cfg->x_last_basic_block )))); | |||
3588 | n = pre_and_rev_post_order_compute_fn (fun, NULLnullptr, rpo, false); | |||
3589 | ||||
3590 | /* Move the expressions that are expensive enough. */ | |||
3591 | for (int i = 0; i < n; ++i) | |||
3592 | todo |= move_computations_worker (BASIC_BLOCK_FOR_FN (fun, rpo[i])((*((fun)->cfg->x_basic_block_info))[(rpo[i])])); | |||
3593 | ||||
3594 | free (rpo); | |||
3595 | ||||
3596 | gsi_commit_edge_inserts (); | |||
3597 | if (need_ssa_update_p (fun)) | |||
3598 | rewrite_into_loop_closed_ssa (NULLnullptr, TODO_update_ssa(1 << 11)); | |||
3599 | ||||
3600 | tree_ssa_lim_finalize (); | |||
3601 | ||||
3602 | return todo; | |||
3603 | } | |||
3604 | ||||
3605 | /* Loop invariant motion pass. */ | |||
3606 | ||||
3607 | namespace { | |||
3608 | ||||
3609 | const pass_data pass_data_lim = | |||
3610 | { | |||
3611 | GIMPLE_PASS, /* type */ | |||
3612 | "lim", /* name */ | |||
3613 | OPTGROUP_LOOP, /* optinfo_flags */ | |||
3614 | TV_LIM, /* tv_id */ | |||
3615 | PROP_cfg(1 << 3), /* properties_required */ | |||
3616 | 0, /* properties_provided */ | |||
3617 | 0, /* properties_destroyed */ | |||
3618 | 0, /* todo_flags_start */ | |||
3619 | 0, /* todo_flags_finish */ | |||
3620 | }; | |||
3621 | ||||
3622 | class pass_lim : public gimple_opt_pass | |||
3623 | { | |||
3624 | public: | |||
3625 | pass_lim (gcc::context *ctxt) | |||
3626 | : gimple_opt_pass (pass_data_lim, ctxt) | |||
3627 | {} | |||
3628 | ||||
3629 | /* opt_pass methods: */ | |||
3630 | opt_pass * clone () final override { return new pass_lim (m_ctxt); } | |||
3631 | bool gate (function *) final override { return flag_tree_loop_imglobal_options.x_flag_tree_loop_im != 0; } | |||
3632 | unsigned int execute (function *) final override; | |||
3633 | ||||
3634 | }; // class pass_lim | |||
3635 | ||||
3636 | unsigned int | |||
3637 | pass_lim::execute (function *fun) | |||
3638 | { | |||
3639 | bool in_loop_pipeline = scev_initialized_p (); | |||
3640 | if (!in_loop_pipeline) | |||
| ||||
3641 | loop_optimizer_init (LOOPS_NORMAL(LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES | LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS ) | LOOPS_HAVE_RECORDED_EXITS); | |||
3642 | ||||
3643 | if (number_of_loops (fun) <= 1) | |||
3644 | return 0; | |||
3645 | unsigned int todo = loop_invariant_motion_in_fun (fun, flag_move_loop_storesglobal_options.x_flag_move_loop_stores); | |||
3646 | ||||
3647 | if (!in_loop_pipeline) | |||
3648 | loop_optimizer_finalize (); | |||
3649 | else | |||
3650 | scev_reset (); | |||
3651 | return todo; | |||
3652 | } | |||
3653 | ||||
3654 | } // anon namespace | |||
3655 | ||||
3656 | gimple_opt_pass * | |||
3657 | make_pass_lim (gcc::context *ctxt) | |||
3658 | { | |||
3659 | return new pass_lim (ctxt); | |||
3660 | } | |||
3661 | ||||
3662 |