]>
Commit | Line | Data |
---|---|---|
df35c271 | 1 | /* Store motion via Lazy Code Motion on the reverse CFG. |
aeee4812 | 2 | Copyright (C) 1997-2023 Free Software Foundation, Inc. |
df35c271 SB |
3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it under | |
7 | the terms of the GNU General Public License as published by the Free | |
8 | Software Foundation; either version 3, or (at your option) any later | |
9 | version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | 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" | |
c7131fb2 | 23 | #include "backend.h" |
c7131fb2 | 24 | #include "rtl.h" |
957060b5 AM |
25 | #include "tree.h" |
26 | #include "predict.h" | |
c7131fb2 | 27 | #include "df.h" |
df35c271 SB |
28 | #include "toplev.h" |
29 | ||
60393bbc AM |
30 | #include "cfgrtl.h" |
31 | #include "cfganal.h" | |
32 | #include "lcm.h" | |
33 | #include "cfgcleanup.h" | |
df35c271 | 34 | #include "expr.h" |
df35c271 | 35 | #include "tree-pass.h" |
df35c271 | 36 | #include "dbgcnt.h" |
638e18a4 | 37 | #include "rtl-iter.h" |
e4dbabfe | 38 | #include "print-rtl.h" |
df35c271 | 39 | |
6c5d4d1a SB |
40 | /* This pass implements downward store motion. |
41 | As of May 1, 2009, the pass is not enabled by default on any target, | |
42 | but bootstrap completes on ia64 and x86_64 with the pass enabled. */ | |
43 | ||
44 | /* TODO: | |
45 | - remove_reachable_equiv_notes is an incomprehensible pile of goo and | |
46 | a compile time hog that needs a rewrite (maybe cache st_exprs to | |
47 | invalidate REG_EQUAL/REG_EQUIV notes for?). | |
48 | - pattern_regs in st_expr should be a regset (on its own obstack). | |
9771b263 | 49 | - store_motion_mems should be a vec instead of a list. |
6c5d4d1a SB |
50 | - there should be an alloc pool for struct st_expr objects. |
51 | - investigate whether it is helpful to make the address of an st_expr | |
52 | a cselib VALUE. | |
53 | - when GIMPLE alias information is exported, the effectiveness of this | |
54 | pass should be re-evaluated. | |
55 | */ | |
56 | ||
57 | /* This is a list of store expressions (MEMs). The structure is used | |
58 | as an expression table to track stores which look interesting, and | |
59 | might be moveable towards the exit block. */ | |
60 | ||
61 | struct st_expr | |
df35c271 | 62 | { |
6c5d4d1a SB |
63 | /* Pattern of this mem. */ |
64 | rtx pattern; | |
65 | /* List of registers mentioned by the mem. */ | |
246af050 | 66 | vec<rtx> pattern_regs; |
6c5d4d1a | 67 | /* INSN list of stores that are locally anticipatable. */ |
6dbe4c9e | 68 | vec<rtx_insn *> antic_stores; |
6c5d4d1a | 69 | /* INSN list of stores that are locally available. */ |
e4dbabfe | 70 | vec<rtx_insn *> avail_stores; |
6c5d4d1a SB |
71 | /* Next in the list. */ |
72 | struct st_expr * next; | |
73 | /* Store ID in the dataflow bitmaps. */ | |
74 | int index; | |
75 | /* Hash value for the hash table. */ | |
76 | unsigned int hash_index; | |
77 | /* Register holding the stored expression when a store is moved. | |
78 | This field is also used as a cache in find_moveable_store, see | |
79 | LAST_AVAIL_CHECK_FAILURE below. */ | |
80 | rtx reaching_reg; | |
df35c271 SB |
81 | }; |
82 | ||
83 | /* Head of the list of load/store memory refs. */ | |
6c5d4d1a | 84 | static struct st_expr * store_motion_mems = NULL; |
df35c271 | 85 | |
6c5d4d1a SB |
86 | /* These bitmaps will hold the local dataflow properties per basic block. */ |
87 | static sbitmap *st_kill, *st_avloc, *st_antloc, *st_transp; | |
df35c271 SB |
88 | |
89 | /* Nonzero for expressions which should be inserted on a specific edge. */ | |
6c5d4d1a | 90 | static sbitmap *st_insert_map; |
df35c271 SB |
91 | |
92 | /* Nonzero for expressions which should be deleted in a specific block. */ | |
6c5d4d1a SB |
93 | static sbitmap *st_delete_map; |
94 | ||
95 | /* Global holding the number of store expressions we are dealing with. */ | |
96 | static int num_stores; | |
df35c271 SB |
97 | |
98 | /* Contains the edge_list returned by pre_edge_lcm. */ | |
99 | static struct edge_list *edge_list; | |
100 | ||
4a8fb1a1 LC |
101 | /* Hashtable helpers. */ |
102 | ||
8d67ee55 | 103 | struct st_expr_hasher : nofree_ptr_hash <st_expr> |
4a8fb1a1 | 104 | { |
67f58944 TS |
105 | static inline hashval_t hash (const st_expr *); |
106 | static inline bool equal (const st_expr *, const st_expr *); | |
4a8fb1a1 LC |
107 | }; |
108 | ||
109 | inline hashval_t | |
67f58944 | 110 | st_expr_hasher::hash (const st_expr *x) |
df35c271 SB |
111 | { |
112 | int do_not_record_p = 0; | |
df35c271 SB |
113 | return hash_rtx (x->pattern, GET_MODE (x->pattern), &do_not_record_p, NULL, false); |
114 | } | |
115 | ||
4a8fb1a1 | 116 | inline bool |
67f58944 | 117 | st_expr_hasher::equal (const st_expr *ptr1, const st_expr *ptr2) |
df35c271 | 118 | { |
df35c271 SB |
119 | return exp_equiv_p (ptr1->pattern, ptr2->pattern, 0, true); |
120 | } | |
121 | ||
4a8fb1a1 | 122 | /* Hashtable for the load/store memory refs. */ |
c203e8a7 | 123 | static hash_table<st_expr_hasher> *store_motion_mems_table; |
4a8fb1a1 | 124 | |
6c5d4d1a | 125 | /* This will search the st_expr list for a matching expression. If it |
df35c271 SB |
126 | doesn't find one, we create one and initialize it. */ |
127 | ||
6c5d4d1a SB |
128 | static struct st_expr * |
129 | st_expr_entry (rtx x) | |
df35c271 SB |
130 | { |
131 | int do_not_record_p = 0; | |
6c5d4d1a | 132 | struct st_expr * ptr; |
df35c271 | 133 | unsigned int hash; |
4a8fb1a1 | 134 | st_expr **slot; |
6c5d4d1a | 135 | struct st_expr e; |
df35c271 SB |
136 | |
137 | hash = hash_rtx (x, GET_MODE (x), &do_not_record_p, | |
138 | NULL, /*have_reg_qty=*/false); | |
139 | ||
140 | e.pattern = x; | |
c203e8a7 | 141 | slot = store_motion_mems_table->find_slot_with_hash (&e, hash, INSERT); |
df35c271 | 142 | if (*slot) |
4a8fb1a1 | 143 | return *slot; |
df35c271 | 144 | |
6c5d4d1a | 145 | ptr = XNEW (struct st_expr); |
df35c271 | 146 | |
6c5d4d1a | 147 | ptr->next = store_motion_mems; |
df35c271 | 148 | ptr->pattern = x; |
246af050 | 149 | ptr->pattern_regs.create (0); |
6dbe4c9e | 150 | ptr->antic_stores.create (0); |
e4dbabfe | 151 | ptr->avail_stores.create (0); |
df35c271 | 152 | ptr->reaching_reg = NULL_RTX; |
df35c271 SB |
153 | ptr->index = 0; |
154 | ptr->hash_index = hash; | |
6c5d4d1a | 155 | store_motion_mems = ptr; |
df35c271 SB |
156 | *slot = ptr; |
157 | ||
158 | return ptr; | |
159 | } | |
160 | ||
6c5d4d1a | 161 | /* Free up an individual st_expr entry. */ |
df35c271 SB |
162 | |
163 | static void | |
6c5d4d1a | 164 | free_st_expr_entry (struct st_expr * ptr) |
df35c271 | 165 | { |
6dbe4c9e TS |
166 | ptr->antic_stores.release (); |
167 | ptr->avail_stores.release (); | |
246af050 | 168 | ptr->pattern_regs.release (); |
df35c271 SB |
169 | |
170 | free (ptr); | |
171 | } | |
172 | ||
6c5d4d1a | 173 | /* Free up all memory associated with the st_expr list. */ |
df35c271 SB |
174 | |
175 | static void | |
6c5d4d1a | 176 | free_store_motion_mems (void) |
df35c271 | 177 | { |
c203e8a7 TS |
178 | delete store_motion_mems_table; |
179 | store_motion_mems_table = NULL; | |
df35c271 | 180 | |
6c5d4d1a | 181 | while (store_motion_mems) |
df35c271 | 182 | { |
6c5d4d1a SB |
183 | struct st_expr * tmp = store_motion_mems; |
184 | store_motion_mems = store_motion_mems->next; | |
185 | free_st_expr_entry (tmp); | |
df35c271 | 186 | } |
6c5d4d1a | 187 | store_motion_mems = NULL; |
df35c271 SB |
188 | } |
189 | ||
190 | /* Assign each element of the list of mems a monotonically increasing value. */ | |
191 | ||
192 | static int | |
6c5d4d1a | 193 | enumerate_store_motion_mems (void) |
df35c271 | 194 | { |
6c5d4d1a | 195 | struct st_expr * ptr; |
df35c271 SB |
196 | int n = 0; |
197 | ||
6c5d4d1a | 198 | for (ptr = store_motion_mems; ptr != NULL; ptr = ptr->next) |
df35c271 SB |
199 | ptr->index = n++; |
200 | ||
201 | return n; | |
202 | } | |
203 | ||
204 | /* Return first item in the list. */ | |
205 | ||
6c5d4d1a SB |
206 | static inline struct st_expr * |
207 | first_st_expr (void) | |
df35c271 | 208 | { |
6c5d4d1a | 209 | return store_motion_mems; |
df35c271 SB |
210 | } |
211 | ||
212 | /* Return the next item in the list after the specified one. */ | |
213 | ||
6c5d4d1a SB |
214 | static inline struct st_expr * |
215 | next_st_expr (struct st_expr * ptr) | |
df35c271 SB |
216 | { |
217 | return ptr->next; | |
218 | } | |
219 | ||
6c5d4d1a | 220 | /* Dump debugging info about the store_motion_mems list. */ |
df35c271 SB |
221 | |
222 | static void | |
6c5d4d1a | 223 | print_store_motion_mems (FILE * file) |
df35c271 | 224 | { |
6c5d4d1a | 225 | struct st_expr * ptr; |
df35c271 | 226 | |
6c5d4d1a | 227 | fprintf (dump_file, "STORE_MOTION list of MEM exprs considered:\n"); |
df35c271 | 228 | |
6c5d4d1a | 229 | for (ptr = first_st_expr (); ptr != NULL; ptr = next_st_expr (ptr)) |
df35c271 SB |
230 | { |
231 | fprintf (file, " Pattern (%3d): ", ptr->index); | |
232 | ||
233 | print_rtl (file, ptr->pattern); | |
234 | ||
6c5d4d1a | 235 | fprintf (file, "\n ANTIC stores : "); |
6dbe4c9e | 236 | print_rtx_insn_vec (file, ptr->antic_stores); |
df35c271 | 237 | |
6c5d4d1a | 238 | fprintf (file, "\n AVAIL stores : "); |
df35c271 | 239 | |
e4dbabfe | 240 | print_rtx_insn_vec (file, ptr->avail_stores); |
df35c271 SB |
241 | |
242 | fprintf (file, "\n\n"); | |
243 | } | |
244 | ||
245 | fprintf (file, "\n"); | |
246 | } | |
247 | \f | |
df35c271 SB |
248 | /* Return zero if some of the registers in list X are killed |
249 | due to set of registers in bitmap REGS_SET. */ | |
250 | ||
251 | static bool | |
246af050 | 252 | store_ops_ok (const vec<rtx> &x, int *regs_set) |
df35c271 | 253 | { |
3f207ab3 | 254 | for (rtx temp : x) |
246af050 TS |
255 | if (regs_set[REGNO (temp)]) |
256 | return false; | |
df35c271 SB |
257 | |
258 | return true; | |
259 | } | |
260 | ||
6c5d4d1a SB |
261 | /* Returns a list of registers mentioned in X. |
262 | FIXME: A regset would be prettier and less expensive. */ | |
263 | ||
246af050 TS |
264 | static void |
265 | extract_mentioned_regs (rtx x, vec<rtx> *mentioned_regs) | |
df35c271 | 266 | { |
638e18a4 RS |
267 | subrtx_var_iterator::array_type array; |
268 | FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST) | |
269 | { | |
270 | rtx x = *iter; | |
271 | if (REG_P (x)) | |
246af050 | 272 | mentioned_regs->safe_push (x); |
638e18a4 | 273 | } |
df35c271 SB |
274 | } |
275 | ||
276 | /* Check to see if the load X is aliased with STORE_PATTERN. | |
277 | AFTER is true if we are checking the case when STORE_PATTERN occurs | |
278 | after the X. */ | |
279 | ||
280 | static bool | |
281 | load_kills_store (const_rtx x, const_rtx store_pattern, int after) | |
282 | { | |
283 | if (after) | |
284 | return anti_dependence (x, store_pattern); | |
285 | else | |
53d9622b | 286 | return true_dependence (store_pattern, GET_MODE (store_pattern), x); |
df35c271 SB |
287 | } |
288 | ||
6c5d4d1a | 289 | /* Go through the entire rtx X, looking for any loads which might alias |
df35c271 SB |
290 | STORE_PATTERN. Return true if found. |
291 | AFTER is true if we are checking the case when STORE_PATTERN occurs | |
292 | after the insn X. */ | |
293 | ||
294 | static bool | |
295 | find_loads (const_rtx x, const_rtx store_pattern, int after) | |
296 | { | |
297 | const char * fmt; | |
298 | int i, j; | |
299 | int ret = false; | |
300 | ||
301 | if (!x) | |
302 | return false; | |
303 | ||
304 | if (GET_CODE (x) == SET) | |
305 | x = SET_SRC (x); | |
306 | ||
307 | if (MEM_P (x)) | |
308 | { | |
309 | if (load_kills_store (x, store_pattern, after)) | |
310 | return true; | |
311 | } | |
312 | ||
313 | /* Recursively process the insn. */ | |
314 | fmt = GET_RTX_FORMAT (GET_CODE (x)); | |
315 | ||
316 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0 && !ret; i--) | |
317 | { | |
318 | if (fmt[i] == 'e') | |
319 | ret |= find_loads (XEXP (x, i), store_pattern, after); | |
320 | else if (fmt[i] == 'E') | |
321 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
322 | ret |= find_loads (XVECEXP (x, i, j), store_pattern, after); | |
323 | } | |
324 | return ret; | |
325 | } | |
326 | ||
327 | /* Go through pattern PAT looking for any loads which might kill the | |
328 | store in X. Return true if found. | |
329 | AFTER is true if we are checking the case when loads kill X occurs | |
330 | after the insn for PAT. */ | |
331 | ||
332 | static inline bool | |
333 | store_killed_in_pat (const_rtx x, const_rtx pat, int after) | |
334 | { | |
335 | if (GET_CODE (pat) == SET) | |
336 | { | |
337 | rtx dest = SET_DEST (pat); | |
338 | ||
339 | if (GET_CODE (dest) == ZERO_EXTRACT) | |
340 | dest = XEXP (dest, 0); | |
341 | ||
342 | /* Check for memory stores to aliased objects. */ | |
343 | if (MEM_P (dest) | |
344 | && !exp_equiv_p (dest, x, 0, true)) | |
345 | { | |
346 | if (after) | |
347 | { | |
348 | if (output_dependence (dest, x)) | |
349 | return true; | |
350 | } | |
351 | else | |
352 | { | |
353 | if (output_dependence (x, dest)) | |
354 | return true; | |
355 | } | |
356 | } | |
357 | } | |
358 | ||
359 | if (find_loads (pat, x, after)) | |
360 | return true; | |
361 | ||
362 | return false; | |
363 | } | |
364 | ||
365 | /* Check if INSN kills the store pattern X (is aliased with it). | |
366 | AFTER is true if we are checking the case when store X occurs | |
367 | after the insn. Return true if it does. */ | |
368 | ||
369 | static bool | |
246af050 TS |
370 | store_killed_in_insn (const_rtx x, const vec<rtx> &x_regs, |
371 | const rtx_insn *insn, int after) | |
df35c271 | 372 | { |
246af050 | 373 | const_rtx note, pat; |
df35c271 | 374 | |
2ad1dda0 | 375 | if (! NONDEBUG_INSN_P (insn)) |
df35c271 SB |
376 | return false; |
377 | ||
378 | if (CALL_P (insn)) | |
379 | { | |
380 | /* A normal or pure call might read from pattern, | |
381 | but a const call will not. */ | |
382 | if (!RTL_CONST_CALL_P (insn)) | |
383 | return true; | |
384 | ||
385 | /* But even a const call reads its parameters. Check whether the | |
386 | base of some of registers used in mem is stack pointer. */ | |
3f207ab3 | 387 | for (rtx temp : x_regs) |
246af050 | 388 | if (may_be_sp_based_p (temp)) |
9e412ca3 | 389 | return true; |
df35c271 SB |
390 | |
391 | return false; | |
392 | } | |
393 | ||
394 | pat = PATTERN (insn); | |
395 | if (GET_CODE (pat) == SET) | |
396 | { | |
397 | if (store_killed_in_pat (x, pat, after)) | |
398 | return true; | |
399 | } | |
400 | else if (GET_CODE (pat) == PARALLEL) | |
401 | { | |
402 | int i; | |
403 | ||
404 | for (i = 0; i < XVECLEN (pat, 0); i++) | |
405 | if (store_killed_in_pat (x, XVECEXP (pat, 0, i), after)) | |
406 | return true; | |
407 | } | |
408 | else if (find_loads (PATTERN (insn), x, after)) | |
409 | return true; | |
410 | ||
411 | /* If this insn has a REG_EQUAL or REG_EQUIV note referencing a memory | |
412 | location aliased with X, then this insn kills X. */ | |
413 | note = find_reg_equal_equiv_note (insn); | |
414 | if (! note) | |
415 | return false; | |
416 | note = XEXP (note, 0); | |
417 | ||
418 | /* However, if the note represents a must alias rather than a may | |
419 | alias relationship, then it does not kill X. */ | |
420 | if (exp_equiv_p (note, x, 0, true)) | |
421 | return false; | |
422 | ||
423 | /* See if there are any aliased loads in the note. */ | |
424 | return find_loads (note, x, after); | |
425 | } | |
426 | ||
427 | /* Returns true if the expression X is loaded or clobbered on or after INSN | |
428 | within basic block BB. REGS_SET_AFTER is bitmap of registers set in | |
429 | or after the insn. X_REGS is list of registers mentioned in X. If the store | |
430 | is killed, return the last insn in that it occurs in FAIL_INSN. */ | |
431 | ||
432 | static bool | |
246af050 TS |
433 | store_killed_after (const_rtx x, const vec<rtx> &x_regs, |
434 | const rtx_insn *insn, const_basic_block bb, | |
df35c271 SB |
435 | int *regs_set_after, rtx *fail_insn) |
436 | { | |
b4b7724e | 437 | rtx_insn *last = BB_END (bb), *act; |
df35c271 SB |
438 | |
439 | if (!store_ops_ok (x_regs, regs_set_after)) | |
440 | { | |
441 | /* We do not know where it will happen. */ | |
442 | if (fail_insn) | |
443 | *fail_insn = NULL_RTX; | |
444 | return true; | |
445 | } | |
446 | ||
447 | /* Scan from the end, so that fail_insn is determined correctly. */ | |
448 | for (act = last; act != PREV_INSN (insn); act = PREV_INSN (act)) | |
449 | if (store_killed_in_insn (x, x_regs, act, false)) | |
450 | { | |
451 | if (fail_insn) | |
452 | *fail_insn = act; | |
453 | return true; | |
454 | } | |
455 | ||
456 | return false; | |
457 | } | |
458 | ||
459 | /* Returns true if the expression X is loaded or clobbered on or before INSN | |
460 | within basic block BB. X_REGS is list of registers mentioned in X. | |
461 | REGS_SET_BEFORE is bitmap of registers set before or in this insn. */ | |
462 | static bool | |
246af050 TS |
463 | store_killed_before (const_rtx x, const vec<rtx> &x_regs, |
464 | const rtx_insn *insn, const_basic_block bb, | |
465 | int *regs_set_before) | |
df35c271 | 466 | { |
b4b7724e | 467 | rtx_insn *first = BB_HEAD (bb); |
df35c271 SB |
468 | |
469 | if (!store_ops_ok (x_regs, regs_set_before)) | |
470 | return true; | |
471 | ||
472 | for ( ; insn != PREV_INSN (first); insn = PREV_INSN (insn)) | |
473 | if (store_killed_in_insn (x, x_regs, insn, true)) | |
474 | return true; | |
475 | ||
476 | return false; | |
477 | } | |
478 | ||
6c5d4d1a SB |
479 | /* The last insn in the basic block that compute_store_table is processing, |
480 | where store_killed_after is true for X. | |
481 | Since we go through the basic block from BB_END to BB_HEAD, this is | |
482 | also the available store at the end of the basic block. Therefore | |
483 | this is in effect a cache, to avoid calling store_killed_after for | |
484 | equivalent aliasing store expressions. | |
485 | This value is only meaningful during the computation of the store | |
486 | table. We hi-jack the REACHING_REG field of struct st_expr to save | |
487 | a bit of memory. */ | |
488 | #define LAST_AVAIL_CHECK_FAILURE(x) ((x)->reaching_reg) | |
489 | ||
df35c271 SB |
490 | /* Determine whether INSN is MEM store pattern that we will consider moving. |
491 | REGS_SET_BEFORE is bitmap of registers set before (and including) the | |
492 | current insn, REGS_SET_AFTER is bitmap of registers set after (and | |
493 | including) the insn in this basic block. We must be passing through BB from | |
494 | head to end, as we are using this fact to speed things up. | |
495 | ||
496 | The results are stored this way: | |
497 | ||
6c5d4d1a | 498 | -- the first anticipatable expression is added into ANTIC_STORES |
df35c271 SB |
499 | -- if the processed expression is not anticipatable, NULL_RTX is added |
500 | there instead, so that we can use it as indicator that no further | |
501 | expression of this type may be anticipatable | |
6c5d4d1a | 502 | -- if the expression is available, it is added as head of AVAIL_STORES; |
df35c271 SB |
503 | consequently, all of them but this head are dead and may be deleted. |
504 | -- if the expression is not available, the insn due to that it fails to be | |
6c5d4d1a | 505 | available is stored in REACHING_REG (via LAST_AVAIL_CHECK_FAILURE). |
df35c271 SB |
506 | |
507 | The things are complicated a bit by fact that there already may be stores | |
508 | to the same MEM from other blocks; also caller must take care of the | |
509 | necessary cleanup of the temporary markers after end of the basic block. | |
510 | */ | |
511 | ||
512 | static void | |
b4b7724e | 513 | find_moveable_store (rtx_insn *insn, int *regs_set_before, int *regs_set_after) |
df35c271 | 514 | { |
6c5d4d1a | 515 | struct st_expr * ptr; |
3dc99c19 | 516 | rtx dest, set; |
df35c271 SB |
517 | int check_anticipatable, check_available; |
518 | basic_block bb = BLOCK_FOR_INSN (insn); | |
519 | ||
520 | set = single_set (insn); | |
521 | if (!set) | |
522 | return; | |
523 | ||
524 | dest = SET_DEST (set); | |
525 | ||
526 | if (! MEM_P (dest) || MEM_VOLATILE_P (dest) | |
527 | || GET_MODE (dest) == BLKmode) | |
528 | return; | |
529 | ||
530 | if (side_effects_p (dest)) | |
531 | return; | |
532 | ||
533 | /* If we are handling exceptions, we must be careful with memory references | |
8f4f502f | 534 | that may trap. If we are not, the behavior is undefined, so we may just |
df35c271 | 535 | continue. */ |
8f4f502f | 536 | if (cfun->can_throw_non_call_exceptions && may_trap_p (dest)) |
df35c271 SB |
537 | return; |
538 | ||
539 | /* Even if the destination cannot trap, the source may. In this case we'd | |
540 | need to handle updating the REG_EH_REGION note. */ | |
541 | if (find_reg_note (insn, REG_EH_REGION, NULL_RTX)) | |
542 | return; | |
543 | ||
544 | /* Make sure that the SET_SRC of this store insns can be assigned to | |
545 | a register, or we will fail later on in replace_store_insn, which | |
546 | assumes that we can do this. But sometimes the target machine has | |
547 | oddities like MEM read-modify-write instruction. See for example | |
548 | PR24257. */ | |
0683fd27 KT |
549 | if (!can_assign_to_reg_without_clobbers_p (SET_SRC (set), |
550 | GET_MODE (SET_SRC (set)))) | |
df35c271 SB |
551 | return; |
552 | ||
6c5d4d1a | 553 | ptr = st_expr_entry (dest); |
246af050 TS |
554 | if (ptr->pattern_regs.is_empty ()) |
555 | extract_mentioned_regs (dest, &ptr->pattern_regs); | |
df35c271 SB |
556 | |
557 | /* Do not check for anticipatability if we either found one anticipatable | |
558 | store already, or tested for one and found out that it was killed. */ | |
559 | check_anticipatable = 0; | |
6dbe4c9e | 560 | if (ptr->antic_stores.is_empty ()) |
df35c271 SB |
561 | check_anticipatable = 1; |
562 | else | |
563 | { | |
6dbe4c9e | 564 | rtx_insn *tmp = ptr->antic_stores.last (); |
df35c271 SB |
565 | if (tmp != NULL_RTX |
566 | && BLOCK_FOR_INSN (tmp) != bb) | |
567 | check_anticipatable = 1; | |
568 | } | |
569 | if (check_anticipatable) | |
570 | { | |
3dc99c19 | 571 | rtx_insn *tmp; |
df35c271 | 572 | if (store_killed_before (dest, ptr->pattern_regs, insn, bb, regs_set_before)) |
3dc99c19 | 573 | tmp = NULL; |
df35c271 SB |
574 | else |
575 | tmp = insn; | |
6dbe4c9e | 576 | ptr->antic_stores.safe_push (tmp); |
df35c271 SB |
577 | } |
578 | ||
579 | /* It is not necessary to check whether store is available if we did | |
580 | it successfully before; if we failed before, do not bother to check | |
581 | until we reach the insn that caused us to fail. */ | |
582 | check_available = 0; | |
e4dbabfe | 583 | if (ptr->avail_stores.is_empty ()) |
df35c271 SB |
584 | check_available = 1; |
585 | else | |
586 | { | |
e4dbabfe | 587 | rtx_insn *tmp = ptr->avail_stores.last (); |
df35c271 SB |
588 | if (BLOCK_FOR_INSN (tmp) != bb) |
589 | check_available = 1; | |
590 | } | |
591 | if (check_available) | |
592 | { | |
593 | /* Check that we have already reached the insn at that the check | |
594 | failed last time. */ | |
595 | if (LAST_AVAIL_CHECK_FAILURE (ptr)) | |
596 | { | |
3dc99c19 | 597 | rtx_insn *tmp; |
df35c271 SB |
598 | for (tmp = BB_END (bb); |
599 | tmp != insn && tmp != LAST_AVAIL_CHECK_FAILURE (ptr); | |
600 | tmp = PREV_INSN (tmp)) | |
601 | continue; | |
602 | if (tmp == insn) | |
603 | check_available = 0; | |
604 | } | |
605 | else | |
606 | check_available = store_killed_after (dest, ptr->pattern_regs, insn, | |
607 | bb, regs_set_after, | |
608 | &LAST_AVAIL_CHECK_FAILURE (ptr)); | |
609 | } | |
610 | if (!check_available) | |
e4dbabfe | 611 | ptr->avail_stores.safe_push (insn); |
df35c271 SB |
612 | } |
613 | ||
614 | /* Find available and anticipatable stores. */ | |
615 | ||
616 | static int | |
617 | compute_store_table (void) | |
618 | { | |
619 | int ret; | |
620 | basic_block bb; | |
b4b7724e | 621 | rtx_insn *insn; |
3dc99c19 | 622 | rtx_insn *tmp; |
bfac633a | 623 | df_ref def; |
df35c271 | 624 | int *last_set_in, *already_set; |
6c5d4d1a | 625 | struct st_expr * ptr, **prev_next_ptr_ptr; |
df35c271 SB |
626 | unsigned int max_gcse_regno = max_reg_num (); |
627 | ||
6c5d4d1a | 628 | store_motion_mems = NULL; |
c203e8a7 | 629 | store_motion_mems_table = new hash_table<st_expr_hasher> (13); |
df35c271 SB |
630 | last_set_in = XCNEWVEC (int, max_gcse_regno); |
631 | already_set = XNEWVEC (int, max_gcse_regno); | |
632 | ||
633 | /* Find all the stores we care about. */ | |
11cd3bed | 634 | FOR_EACH_BB_FN (bb, cfun) |
df35c271 SB |
635 | { |
636 | /* First compute the registers set in this block. */ | |
df35c271 SB |
637 | FOR_BB_INSNS (bb, insn) |
638 | { | |
6c5d4d1a | 639 | |
2ad1dda0 | 640 | if (! NONDEBUG_INSN_P (insn)) |
df35c271 SB |
641 | continue; |
642 | ||
bfac633a RS |
643 | FOR_EACH_INSN_DEF (def, insn) |
644 | last_set_in[DF_REF_REGNO (def)] = INSN_UID (insn); | |
df35c271 SB |
645 | } |
646 | ||
647 | /* Now find the stores. */ | |
648 | memset (already_set, 0, sizeof (int) * max_gcse_regno); | |
df35c271 SB |
649 | FOR_BB_INSNS (bb, insn) |
650 | { | |
2ad1dda0 | 651 | if (! NONDEBUG_INSN_P (insn)) |
df35c271 SB |
652 | continue; |
653 | ||
bfac633a RS |
654 | FOR_EACH_INSN_DEF (def, insn) |
655 | already_set[DF_REF_REGNO (def)] = INSN_UID (insn); | |
df35c271 SB |
656 | |
657 | /* Now that we've marked regs, look for stores. */ | |
658 | find_moveable_store (insn, already_set, last_set_in); | |
659 | ||
660 | /* Unmark regs that are no longer set. */ | |
bfac633a RS |
661 | FOR_EACH_INSN_DEF (def, insn) |
662 | if (last_set_in[DF_REF_REGNO (def)] == INSN_UID (insn)) | |
663 | last_set_in[DF_REF_REGNO (def)] = 0; | |
df35c271 SB |
664 | } |
665 | ||
b2b29377 MM |
666 | if (flag_checking) |
667 | { | |
668 | /* last_set_in should now be all-zero. */ | |
669 | for (unsigned regno = 0; regno < max_gcse_regno; regno++) | |
670 | gcc_assert (!last_set_in[regno]); | |
671 | } | |
df35c271 SB |
672 | |
673 | /* Clear temporary marks. */ | |
6c5d4d1a | 674 | for (ptr = first_st_expr (); ptr != NULL; ptr = next_st_expr (ptr)) |
df35c271 | 675 | { |
6c5d4d1a | 676 | LAST_AVAIL_CHECK_FAILURE (ptr) = NULL_RTX; |
6dbe4c9e TS |
677 | if (!ptr->antic_stores.is_empty () |
678 | && (tmp = ptr->antic_stores.last ()) == NULL) | |
679 | ptr->antic_stores.pop (); | |
df35c271 SB |
680 | } |
681 | } | |
682 | ||
683 | /* Remove the stores that are not available anywhere, as there will | |
684 | be no opportunity to optimize them. */ | |
6c5d4d1a | 685 | for (ptr = store_motion_mems, prev_next_ptr_ptr = &store_motion_mems; |
df35c271 SB |
686 | ptr != NULL; |
687 | ptr = *prev_next_ptr_ptr) | |
688 | { | |
e4dbabfe | 689 | if (ptr->avail_stores.is_empty ()) |
df35c271 SB |
690 | { |
691 | *prev_next_ptr_ptr = ptr->next; | |
c203e8a7 | 692 | store_motion_mems_table->remove_elt_with_hash (ptr, ptr->hash_index); |
6c5d4d1a | 693 | free_st_expr_entry (ptr); |
df35c271 SB |
694 | } |
695 | else | |
696 | prev_next_ptr_ptr = &ptr->next; | |
697 | } | |
698 | ||
6c5d4d1a | 699 | ret = enumerate_store_motion_mems (); |
df35c271 SB |
700 | |
701 | if (dump_file) | |
6c5d4d1a | 702 | print_store_motion_mems (dump_file); |
df35c271 SB |
703 | |
704 | free (last_set_in); | |
705 | free (already_set); | |
706 | return ret; | |
707 | } | |
708 | ||
6c5d4d1a SB |
709 | /* In all code following after this, REACHING_REG has its original |
710 | meaning again. Avoid confusion, and undef the accessor macro for | |
711 | the temporary marks usage in compute_store_table. */ | |
712 | #undef LAST_AVAIL_CHECK_FAILURE | |
713 | ||
df35c271 SB |
714 | /* Insert an instruction at the beginning of a basic block, and update |
715 | the BB_HEAD if needed. */ | |
716 | ||
717 | static void | |
b4b7724e | 718 | insert_insn_start_basic_block (rtx_insn *insn, basic_block bb) |
df35c271 SB |
719 | { |
720 | /* Insert at start of successor block. */ | |
b4b7724e DM |
721 | rtx_insn *prev = PREV_INSN (BB_HEAD (bb)); |
722 | rtx_insn *before = BB_HEAD (bb); | |
df35c271 SB |
723 | while (before != 0) |
724 | { | |
725 | if (! LABEL_P (before) | |
726 | && !NOTE_INSN_BASIC_BLOCK_P (before)) | |
727 | break; | |
728 | prev = before; | |
729 | if (prev == BB_END (bb)) | |
730 | break; | |
731 | before = NEXT_INSN (before); | |
732 | } | |
733 | ||
734 | insn = emit_insn_after_noloc (insn, prev, bb); | |
735 | ||
736 | if (dump_file) | |
737 | { | |
738 | fprintf (dump_file, "STORE_MOTION insert store at start of BB %d:\n", | |
739 | bb->index); | |
740 | print_inline_rtx (dump_file, insn, 6); | |
741 | fprintf (dump_file, "\n"); | |
742 | } | |
743 | } | |
744 | ||
6c5d4d1a | 745 | /* This routine will insert a store on an edge. EXPR is the st_expr entry for |
df35c271 SB |
746 | the memory reference, and E is the edge to insert it on. Returns nonzero |
747 | if an edge insertion was performed. */ | |
748 | ||
749 | static int | |
6c5d4d1a | 750 | insert_store (struct st_expr * expr, edge e) |
df35c271 | 751 | { |
b4b7724e DM |
752 | rtx reg; |
753 | rtx_insn *insn; | |
df35c271 SB |
754 | basic_block bb; |
755 | edge tmp; | |
756 | edge_iterator ei; | |
757 | ||
758 | /* We did all the deleted before this insert, so if we didn't delete a | |
759 | store, then we haven't set the reaching reg yet either. */ | |
760 | if (expr->reaching_reg == NULL_RTX) | |
761 | return 0; | |
762 | ||
763 | if (e->flags & EDGE_FAKE) | |
764 | return 0; | |
765 | ||
766 | reg = expr->reaching_reg; | |
1476d1bd | 767 | insn = gen_move_insn (copy_rtx (expr->pattern), reg); |
df35c271 SB |
768 | |
769 | /* If we are inserting this expression on ALL predecessor edges of a BB, | |
770 | insert it at the start of the BB, and reset the insert bits on the other | |
771 | edges so we don't try to insert it on the other edges. */ | |
772 | bb = e->dest; | |
773 | FOR_EACH_EDGE (tmp, ei, e->dest->preds) | |
774 | if (!(tmp->flags & EDGE_FAKE)) | |
775 | { | |
776 | int index = EDGE_INDEX (edge_list, tmp->src, tmp->dest); | |
b8698a0f | 777 | |
df35c271 | 778 | gcc_assert (index != EDGE_INDEX_NO_EDGE); |
d7c028c0 | 779 | if (! bitmap_bit_p (st_insert_map[index], expr->index)) |
df35c271 SB |
780 | break; |
781 | } | |
782 | ||
783 | /* If tmp is NULL, we found an insertion on every edge, blank the | |
784 | insertion vector for these edges, and insert at the start of the BB. */ | |
fefa31b5 | 785 | if (!tmp && bb != EXIT_BLOCK_PTR_FOR_FN (cfun)) |
df35c271 SB |
786 | { |
787 | FOR_EACH_EDGE (tmp, ei, e->dest->preds) | |
788 | { | |
789 | int index = EDGE_INDEX (edge_list, tmp->src, tmp->dest); | |
d7c028c0 | 790 | bitmap_clear_bit (st_insert_map[index], expr->index); |
df35c271 SB |
791 | } |
792 | insert_insn_start_basic_block (insn, bb); | |
793 | return 0; | |
794 | } | |
795 | ||
796 | /* We can't put stores in the front of blocks pointed to by abnormal | |
797 | edges since that may put a store where one didn't used to be. */ | |
798 | gcc_assert (!(e->flags & EDGE_ABNORMAL)); | |
799 | ||
800 | insert_insn_on_edge (insn, e); | |
801 | ||
802 | if (dump_file) | |
803 | { | |
804 | fprintf (dump_file, "STORE_MOTION insert insn on edge (%d, %d):\n", | |
805 | e->src->index, e->dest->index); | |
806 | print_inline_rtx (dump_file, insn, 6); | |
807 | fprintf (dump_file, "\n"); | |
808 | } | |
809 | ||
810 | return 1; | |
811 | } | |
812 | ||
813 | /* Remove any REG_EQUAL or REG_EQUIV notes containing a reference to the | |
814 | memory location in SMEXPR set in basic block BB. | |
815 | ||
816 | This could be rather expensive. */ | |
817 | ||
818 | static void | |
6c5d4d1a | 819 | remove_reachable_equiv_notes (basic_block bb, struct st_expr *smexpr) |
df35c271 SB |
820 | { |
821 | edge_iterator *stack, ei; | |
822 | int sp; | |
823 | edge act; | |
7ba9e72d | 824 | auto_sbitmap visited (last_basic_block_for_fn (cfun)); |
6dbe4c9e | 825 | rtx note; |
b4b7724e | 826 | rtx_insn *insn; |
df35c271 SB |
827 | rtx mem = smexpr->pattern; |
828 | ||
0cae8d31 | 829 | stack = XNEWVEC (edge_iterator, n_basic_blocks_for_fn (cfun)); |
df35c271 SB |
830 | sp = 0; |
831 | ei = ei_start (bb->succs); | |
832 | ||
f61e445a | 833 | bitmap_clear (visited); |
df35c271 | 834 | |
5cf5c9da NS |
835 | act = (EDGE_COUNT (ei_container (ei)) |
836 | ? EDGE_I (ei_container (ei), 0) | |
837 | : NULL); | |
838 | for (;;) | |
df35c271 SB |
839 | { |
840 | if (!act) | |
841 | { | |
842 | if (!sp) | |
843 | { | |
844 | free (stack); | |
df35c271 SB |
845 | return; |
846 | } | |
847 | act = ei_edge (stack[--sp]); | |
848 | } | |
849 | bb = act->dest; | |
850 | ||
fefa31b5 | 851 | if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun) |
d7c028c0 | 852 | || bitmap_bit_p (visited, bb->index)) |
df35c271 SB |
853 | { |
854 | if (!ei_end_p (ei)) | |
855 | ei_next (&ei); | |
856 | act = (! ei_end_p (ei)) ? ei_edge (ei) : NULL; | |
857 | continue; | |
858 | } | |
d7c028c0 | 859 | bitmap_set_bit (visited, bb->index); |
df35c271 | 860 | |
6dbe4c9e | 861 | rtx_insn *last; |
d7c028c0 | 862 | if (bitmap_bit_p (st_antloc[bb->index], smexpr->index)) |
df35c271 | 863 | { |
6dbe4c9e TS |
864 | unsigned int i; |
865 | FOR_EACH_VEC_ELT_REVERSE (smexpr->antic_stores, i, last) | |
866 | if (BLOCK_FOR_INSN (last) == bb) | |
867 | break; | |
df35c271 SB |
868 | } |
869 | else | |
870 | last = NEXT_INSN (BB_END (bb)); | |
871 | ||
872 | for (insn = BB_HEAD (bb); insn != last; insn = NEXT_INSN (insn)) | |
2ad1dda0 | 873 | if (NONDEBUG_INSN_P (insn)) |
df35c271 SB |
874 | { |
875 | note = find_reg_equal_equiv_note (insn); | |
876 | if (!note || !exp_equiv_p (XEXP (note, 0), mem, 0, true)) | |
877 | continue; | |
878 | ||
879 | if (dump_file) | |
5cf5c9da NS |
880 | fprintf (dump_file, |
881 | "STORE_MOTION drop REG_EQUAL note at insn %d:\n", | |
df35c271 SB |
882 | INSN_UID (insn)); |
883 | remove_note (insn, note); | |
884 | } | |
885 | ||
886 | if (!ei_end_p (ei)) | |
887 | ei_next (&ei); | |
888 | act = (! ei_end_p (ei)) ? ei_edge (ei) : NULL; | |
889 | ||
890 | if (EDGE_COUNT (bb->succs) > 0) | |
891 | { | |
892 | if (act) | |
893 | stack[sp++] = ei; | |
894 | ei = ei_start (bb->succs); | |
5cf5c9da NS |
895 | act = (EDGE_COUNT (ei_container (ei)) |
896 | ? EDGE_I (ei_container (ei), 0) | |
897 | : NULL); | |
df35c271 SB |
898 | } |
899 | } | |
900 | } | |
901 | ||
902 | /* This routine will replace a store with a SET to a specified register. */ | |
903 | ||
904 | static void | |
e8a54173 DM |
905 | replace_store_insn (rtx reg, rtx_insn *del, basic_block bb, |
906 | struct st_expr *smexpr) | |
df35c271 | 907 | { |
b4b7724e | 908 | rtx_insn *insn; |
6dbe4c9e | 909 | rtx mem, note, set; |
df35c271 | 910 | |
53f2f08b | 911 | insn = prepare_copy_insn (reg, SET_SRC (single_set (del))); |
df35c271 | 912 | |
6dbe4c9e TS |
913 | unsigned int i; |
914 | rtx_insn *temp; | |
915 | FOR_EACH_VEC_ELT_REVERSE (smexpr->antic_stores, i, temp) | |
916 | if (temp == del) | |
df35c271 | 917 | { |
6dbe4c9e | 918 | smexpr->antic_stores[i] = insn; |
df35c271 SB |
919 | break; |
920 | } | |
921 | ||
922 | /* Move the notes from the deleted insn to its replacement. */ | |
923 | REG_NOTES (insn) = REG_NOTES (del); | |
924 | ||
925 | /* Emit the insn AFTER all the notes are transferred. | |
926 | This is cheaper since we avoid df rescanning for the note change. */ | |
927 | insn = emit_insn_after (insn, del); | |
928 | ||
929 | if (dump_file) | |
930 | { | |
931 | fprintf (dump_file, | |
932 | "STORE_MOTION delete insn in BB %d:\n ", bb->index); | |
933 | print_inline_rtx (dump_file, del, 6); | |
934 | fprintf (dump_file, "\nSTORE_MOTION replaced with insn:\n "); | |
935 | print_inline_rtx (dump_file, insn, 6); | |
936 | fprintf (dump_file, "\n"); | |
937 | } | |
938 | ||
939 | delete_insn (del); | |
940 | ||
941 | /* Now we must handle REG_EQUAL notes whose contents is equal to the mem; | |
942 | they are no longer accurate provided that they are reached by this | |
943 | definition, so drop them. */ | |
53f2f08b | 944 | mem = smexpr->pattern; |
df35c271 | 945 | for (; insn != NEXT_INSN (BB_END (bb)); insn = NEXT_INSN (insn)) |
2ad1dda0 | 946 | if (NONDEBUG_INSN_P (insn)) |
df35c271 SB |
947 | { |
948 | set = single_set (insn); | |
949 | if (!set) | |
950 | continue; | |
951 | if (exp_equiv_p (SET_DEST (set), mem, 0, true)) | |
952 | return; | |
953 | note = find_reg_equal_equiv_note (insn); | |
954 | if (!note || !exp_equiv_p (XEXP (note, 0), mem, 0, true)) | |
955 | continue; | |
956 | ||
957 | if (dump_file) | |
958 | fprintf (dump_file, "STORE_MOTION drop REG_EQUAL note at insn %d:\n", | |
959 | INSN_UID (insn)); | |
960 | remove_note (insn, note); | |
961 | } | |
962 | remove_reachable_equiv_notes (bb, smexpr); | |
963 | } | |
964 | ||
965 | ||
966 | /* Delete a store, but copy the value that would have been stored into | |
967 | the reaching_reg for later storing. */ | |
968 | ||
969 | static void | |
6c5d4d1a | 970 | delete_store (struct st_expr * expr, basic_block bb) |
df35c271 | 971 | { |
e8a54173 | 972 | rtx reg; |
df35c271 SB |
973 | |
974 | if (expr->reaching_reg == NULL_RTX) | |
975 | expr->reaching_reg = gen_reg_rtx_and_attrs (expr->pattern); | |
976 | ||
977 | reg = expr->reaching_reg; | |
978 | ||
e4dbabfe TS |
979 | unsigned int len = expr->avail_stores.length (); |
980 | for (unsigned int i = len - 1; i < len; i--) | |
df35c271 | 981 | { |
e4dbabfe | 982 | rtx_insn *del = expr->avail_stores[i]; |
df35c271 SB |
983 | if (BLOCK_FOR_INSN (del) == bb) |
984 | { | |
985 | /* We know there is only one since we deleted redundant | |
986 | ones during the available computation. */ | |
987 | replace_store_insn (reg, del, bb, expr); | |
988 | break; | |
989 | } | |
990 | } | |
991 | } | |
992 | ||
993 | /* Fill in available, anticipatable, transparent and kill vectors in | |
994 | STORE_DATA, based on lists of available and anticipatable stores. */ | |
995 | static void | |
996 | build_store_vectors (void) | |
997 | { | |
998 | basic_block bb; | |
999 | int *regs_set_in_block; | |
b32d5189 | 1000 | rtx_insn *insn; |
6c5d4d1a | 1001 | struct st_expr * ptr; |
df35c271 SB |
1002 | unsigned int max_gcse_regno = max_reg_num (); |
1003 | ||
1004 | /* Build the gen_vector. This is any store in the table which is not killed | |
1005 | by aliasing later in its block. */ | |
8b1c6fd7 DM |
1006 | st_avloc = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
1007 | num_stores); | |
1008 | bitmap_vector_clear (st_avloc, last_basic_block_for_fn (cfun)); | |
df35c271 | 1009 | |
8b1c6fd7 DM |
1010 | st_antloc = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
1011 | num_stores); | |
1012 | bitmap_vector_clear (st_antloc, last_basic_block_for_fn (cfun)); | |
df35c271 | 1013 | |
6c5d4d1a | 1014 | for (ptr = first_st_expr (); ptr != NULL; ptr = next_st_expr (ptr)) |
df35c271 | 1015 | { |
e4dbabfe TS |
1016 | unsigned int len = ptr->avail_stores.length (); |
1017 | for (unsigned int i = len - 1; i < len; i--) | |
df35c271 | 1018 | { |
e4dbabfe | 1019 | insn = ptr->avail_stores[i]; |
df35c271 SB |
1020 | bb = BLOCK_FOR_INSN (insn); |
1021 | ||
1022 | /* If we've already seen an available expression in this block, | |
1023 | we can delete this one (It occurs earlier in the block). We'll | |
1024 | copy the SRC expression to an unused register in case there | |
1025 | are any side effects. */ | |
d7c028c0 | 1026 | if (bitmap_bit_p (st_avloc[bb->index], ptr->index)) |
df35c271 SB |
1027 | { |
1028 | rtx r = gen_reg_rtx_and_attrs (ptr->pattern); | |
1029 | if (dump_file) | |
1030 | fprintf (dump_file, "Removing redundant store:\n"); | |
e4dbabfe | 1031 | replace_store_insn (r, insn, bb, ptr); |
df35c271 SB |
1032 | continue; |
1033 | } | |
d7c028c0 | 1034 | bitmap_set_bit (st_avloc[bb->index], ptr->index); |
df35c271 SB |
1035 | } |
1036 | ||
6dbe4c9e TS |
1037 | unsigned int i; |
1038 | FOR_EACH_VEC_ELT_REVERSE (ptr->antic_stores, i, insn) | |
df35c271 | 1039 | { |
df35c271 | 1040 | bb = BLOCK_FOR_INSN (insn); |
d7c028c0 | 1041 | bitmap_set_bit (st_antloc[bb->index], ptr->index); |
df35c271 SB |
1042 | } |
1043 | } | |
1044 | ||
8b1c6fd7 DM |
1045 | st_kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), num_stores); |
1046 | bitmap_vector_clear (st_kill, last_basic_block_for_fn (cfun)); | |
df35c271 | 1047 | |
8b1c6fd7 DM |
1048 | st_transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), num_stores); |
1049 | bitmap_vector_clear (st_transp, last_basic_block_for_fn (cfun)); | |
df35c271 SB |
1050 | regs_set_in_block = XNEWVEC (int, max_gcse_regno); |
1051 | ||
11cd3bed | 1052 | FOR_EACH_BB_FN (bb, cfun) |
df35c271 | 1053 | { |
b114d73a SB |
1054 | memset (regs_set_in_block, 0, sizeof (int) * max_gcse_regno); |
1055 | ||
df35c271 | 1056 | FOR_BB_INSNS (bb, insn) |
2ad1dda0 | 1057 | if (NONDEBUG_INSN_P (insn)) |
df35c271 | 1058 | { |
bfac633a RS |
1059 | df_ref def; |
1060 | FOR_EACH_INSN_DEF (def, insn) | |
df35c271 | 1061 | { |
bfac633a | 1062 | unsigned int ref_regno = DF_REF_REGNO (def); |
df35c271 | 1063 | if (ref_regno < max_gcse_regno) |
bfac633a | 1064 | regs_set_in_block[DF_REF_REGNO (def)] = 1; |
df35c271 SB |
1065 | } |
1066 | } | |
1067 | ||
6c5d4d1a | 1068 | for (ptr = first_st_expr (); ptr != NULL; ptr = next_st_expr (ptr)) |
df35c271 SB |
1069 | { |
1070 | if (store_killed_after (ptr->pattern, ptr->pattern_regs, BB_HEAD (bb), | |
1071 | bb, regs_set_in_block, NULL)) | |
1072 | { | |
1073 | /* It should not be necessary to consider the expression | |
1074 | killed if it is both anticipatable and available. */ | |
d7c028c0 LC |
1075 | if (!bitmap_bit_p (st_antloc[bb->index], ptr->index) |
1076 | || !bitmap_bit_p (st_avloc[bb->index], ptr->index)) | |
1077 | bitmap_set_bit (st_kill[bb->index], ptr->index); | |
df35c271 SB |
1078 | } |
1079 | else | |
d7c028c0 | 1080 | bitmap_set_bit (st_transp[bb->index], ptr->index); |
df35c271 SB |
1081 | } |
1082 | } | |
1083 | ||
1084 | free (regs_set_in_block); | |
1085 | ||
1086 | if (dump_file) | |
1087 | { | |
8b1c6fd7 DM |
1088 | dump_bitmap_vector (dump_file, "st_antloc", "", st_antloc, |
1089 | last_basic_block_for_fn (cfun)); | |
1090 | dump_bitmap_vector (dump_file, "st_kill", "", st_kill, | |
1091 | last_basic_block_for_fn (cfun)); | |
1092 | dump_bitmap_vector (dump_file, "st_transp", "", st_transp, | |
1093 | last_basic_block_for_fn (cfun)); | |
1094 | dump_bitmap_vector (dump_file, "st_avloc", "", st_avloc, | |
1095 | last_basic_block_for_fn (cfun)); | |
df35c271 SB |
1096 | } |
1097 | } | |
1098 | ||
1099 | /* Free memory used by store motion. */ | |
1100 | ||
1101 | static void | |
1102 | free_store_memory (void) | |
1103 | { | |
6c5d4d1a SB |
1104 | free_store_motion_mems (); |
1105 | ||
1106 | if (st_avloc) | |
1107 | sbitmap_vector_free (st_avloc); | |
1108 | if (st_kill) | |
1109 | sbitmap_vector_free (st_kill); | |
1110 | if (st_transp) | |
1111 | sbitmap_vector_free (st_transp); | |
df35c271 SB |
1112 | if (st_antloc) |
1113 | sbitmap_vector_free (st_antloc); | |
6c5d4d1a SB |
1114 | if (st_insert_map) |
1115 | sbitmap_vector_free (st_insert_map); | |
1116 | if (st_delete_map) | |
1117 | sbitmap_vector_free (st_delete_map); | |
df35c271 | 1118 | |
6c5d4d1a SB |
1119 | st_avloc = st_kill = st_transp = st_antloc = NULL; |
1120 | st_insert_map = st_delete_map = NULL; | |
df35c271 SB |
1121 | } |
1122 | ||
1123 | /* Perform store motion. Much like gcse, except we move expressions the | |
1124 | other way by looking at the flowgraph in reverse. | |
1125 | Return non-zero if transformations are performed by the pass. */ | |
1126 | ||
1127 | static int | |
1128 | one_store_motion_pass (void) | |
1129 | { | |
1130 | basic_block bb; | |
1131 | int x; | |
6c5d4d1a SB |
1132 | struct st_expr * ptr; |
1133 | int did_edge_inserts = 0; | |
1134 | int n_stores_deleted = 0; | |
1135 | int n_stores_created = 0; | |
df35c271 SB |
1136 | |
1137 | init_alias_analysis (); | |
1138 | ||
1139 | /* Find all the available and anticipatable stores. */ | |
1140 | num_stores = compute_store_table (); | |
1141 | if (num_stores == 0) | |
1142 | { | |
c203e8a7 TS |
1143 | delete store_motion_mems_table; |
1144 | store_motion_mems_table = NULL; | |
df35c271 SB |
1145 | end_alias_analysis (); |
1146 | return 0; | |
1147 | } | |
1148 | ||
1149 | /* Now compute kill & transp vectors. */ | |
1150 | build_store_vectors (); | |
df35c271 SB |
1151 | connect_infinite_loops_to_exit (); |
1152 | ||
6c5d4d1a SB |
1153 | edge_list = pre_edge_rev_lcm (num_stores, st_transp, st_avloc, |
1154 | st_antloc, st_kill, &st_insert_map, | |
1155 | &st_delete_map); | |
df35c271 SB |
1156 | |
1157 | /* Now we want to insert the new stores which are going to be needed. */ | |
6c5d4d1a | 1158 | for (ptr = first_st_expr (); ptr != NULL; ptr = next_st_expr (ptr)) |
df35c271 SB |
1159 | { |
1160 | /* If any of the edges we have above are abnormal, we can't move this | |
1161 | store. */ | |
1162 | for (x = NUM_EDGES (edge_list) - 1; x >= 0; x--) | |
d7c028c0 | 1163 | if (bitmap_bit_p (st_insert_map[x], ptr->index) |
df35c271 SB |
1164 | && (INDEX_EDGE (edge_list, x)->flags & EDGE_ABNORMAL)) |
1165 | break; | |
1166 | ||
1167 | if (x >= 0) | |
1168 | { | |
1169 | if (dump_file != NULL) | |
1170 | fprintf (dump_file, | |
1171 | "Can't replace store %d: abnormal edge from %d to %d\n", | |
1172 | ptr->index, INDEX_EDGE (edge_list, x)->src->index, | |
1173 | INDEX_EDGE (edge_list, x)->dest->index); | |
1174 | continue; | |
1175 | } | |
b8698a0f | 1176 | |
df35c271 SB |
1177 | /* Now we want to insert the new stores which are going to be needed. */ |
1178 | ||
11cd3bed | 1179 | FOR_EACH_BB_FN (bb, cfun) |
d7c028c0 | 1180 | if (bitmap_bit_p (st_delete_map[bb->index], ptr->index)) |
df35c271 SB |
1181 | { |
1182 | delete_store (ptr, bb); | |
6c5d4d1a | 1183 | n_stores_deleted++; |
df35c271 SB |
1184 | } |
1185 | ||
1186 | for (x = 0; x < NUM_EDGES (edge_list); x++) | |
d7c028c0 | 1187 | if (bitmap_bit_p (st_insert_map[x], ptr->index)) |
df35c271 | 1188 | { |
6c5d4d1a SB |
1189 | did_edge_inserts |= insert_store (ptr, INDEX_EDGE (edge_list, x)); |
1190 | n_stores_created++; | |
df35c271 SB |
1191 | } |
1192 | } | |
1193 | ||
6c5d4d1a | 1194 | if (did_edge_inserts) |
df35c271 SB |
1195 | commit_edge_insertions (); |
1196 | ||
1197 | free_store_memory (); | |
1198 | free_edge_list (edge_list); | |
1199 | remove_fake_exit_edges (); | |
1200 | end_alias_analysis (); | |
1201 | ||
1202 | if (dump_file) | |
1203 | { | |
1204 | fprintf (dump_file, "STORE_MOTION of %s, %d basic blocks, ", | |
0cae8d31 | 1205 | current_function_name (), n_basic_blocks_for_fn (cfun)); |
6c5d4d1a SB |
1206 | fprintf (dump_file, "%d insns deleted, %d insns created\n", |
1207 | n_stores_deleted, n_stores_created); | |
df35c271 SB |
1208 | } |
1209 | ||
6c5d4d1a | 1210 | return (n_stores_deleted > 0 || n_stores_created > 0); |
df35c271 SB |
1211 | } |
1212 | ||
1213 | \f | |
df35c271 SB |
1214 | static unsigned int |
1215 | execute_rtl_store_motion (void) | |
1216 | { | |
1217 | delete_unreachable_blocks (); | |
df35c271 SB |
1218 | df_analyze (); |
1219 | flag_rerun_cse_after_global_opts |= one_store_motion_pass (); | |
1220 | return 0; | |
1221 | } | |
1222 | ||
27a4cd48 DM |
1223 | namespace { |
1224 | ||
1225 | const pass_data pass_data_rtl_store_motion = | |
df35c271 | 1226 | { |
27a4cd48 DM |
1227 | RTL_PASS, /* type */ |
1228 | "store_motion", /* name */ | |
1229 | OPTGROUP_NONE, /* optinfo_flags */ | |
27a4cd48 DM |
1230 | TV_LSM, /* tv_id */ |
1231 | PROP_cfglayout, /* properties_required */ | |
1232 | 0, /* properties_provided */ | |
1233 | 0, /* properties_destroyed */ | |
1234 | 0, /* todo_flags_start */ | |
3bea341f | 1235 | TODO_df_finish, /* todo_flags_finish */ |
df35c271 | 1236 | }; |
27a4cd48 DM |
1237 | |
1238 | class pass_rtl_store_motion : public rtl_opt_pass | |
1239 | { | |
1240 | public: | |
c3284718 RS |
1241 | pass_rtl_store_motion (gcc::context *ctxt) |
1242 | : rtl_opt_pass (pass_data_rtl_store_motion, ctxt) | |
27a4cd48 DM |
1243 | {} |
1244 | ||
1245 | /* opt_pass methods: */ | |
725793af DM |
1246 | bool gate (function *) final override; |
1247 | unsigned int execute (function *) final override | |
be55bfe6 TS |
1248 | { |
1249 | return execute_rtl_store_motion (); | |
1250 | } | |
27a4cd48 DM |
1251 | |
1252 | }; // class pass_rtl_store_motion | |
1253 | ||
1a3d085c TS |
1254 | bool |
1255 | pass_rtl_store_motion::gate (function *fun) | |
1256 | { | |
1257 | return optimize > 0 && flag_gcse_sm | |
1258 | && !fun->calls_setjmp | |
1259 | && optimize_function_for_speed_p (fun) | |
1260 | && dbg_cnt (store_motion); | |
1261 | } | |
1262 | ||
27a4cd48 DM |
1263 | } // anon namespace |
1264 | ||
1265 | rtl_opt_pass * | |
1266 | make_pass_rtl_store_motion (gcc::context *ctxt) | |
1267 | { | |
1268 | return new pass_rtl_store_motion (ctxt); | |
1269 | } |