Branch data Line data Source code
1 : : /* Avoid store forwarding optimization pass.
2 : : Copyright (C) 2024-2025 Free Software Foundation, Inc.
3 : : Contributed by VRULL GmbH.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "avoid-store-forwarding.h"
22 : : #include "config.h"
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "backend.h"
26 : : #include "target.h"
27 : : #include "rtl.h"
28 : : #include "alias.h"
29 : : #include "rtlanal.h"
30 : : #include "cfgrtl.h"
31 : : #include "tree-pass.h"
32 : : #include "cselib.h"
33 : : #include "predict.h"
34 : : #include "insn-config.h"
35 : : #include "expmed.h"
36 : : #include "recog.h"
37 : : #include "regset.h"
38 : : #include "df.h"
39 : : #include "expr.h"
40 : : #include "memmodel.h"
41 : : #include "emit-rtl.h"
42 : : #include "vec.h"
43 : :
44 : : /* This pass tries to detect and avoid cases of store forwarding.
45 : : On many processors there is a large penalty when smaller stores are
46 : : forwarded to larger loads. The idea used to avoid the stall is to move
47 : : the store after the load and in addition emit a bit insert sequence so
48 : : the load register has the correct value. For example the following:
49 : :
50 : : strb w2, [x1, 1]
51 : : ldr x0, [x1]
52 : :
53 : : Will be transformed to:
54 : :
55 : : ldr x0, [x1]
56 : : strb w2, [x1]
57 : : bfi x0, x2, 0, 8
58 : : */
59 : :
60 : : namespace {
61 : :
62 : : const pass_data pass_data_avoid_store_forwarding =
63 : : {
64 : : RTL_PASS, /* type. */
65 : : "avoid_store_forwarding", /* name. */
66 : : OPTGROUP_NONE, /* optinfo_flags. */
67 : : TV_AVOID_STORE_FORWARDING, /* tv_id. */
68 : : 0, /* properties_required. */
69 : : 0, /* properties_provided. */
70 : : 0, /* properties_destroyed. */
71 : : 0, /* todo_flags_start. */
72 : : TODO_df_finish /* todo_flags_finish. */
73 : : };
74 : :
75 : : class pass_rtl_avoid_store_forwarding : public rtl_opt_pass
76 : : {
77 : : public:
78 : 285081 : pass_rtl_avoid_store_forwarding (gcc::context *ctxt)
79 : 570162 : : rtl_opt_pass (pass_data_avoid_store_forwarding, ctxt)
80 : : {}
81 : :
82 : : /* opt_pass methods: */
83 : 1449863 : virtual bool gate (function *)
84 : : {
85 : 1449863 : return flag_avoid_store_forwarding && optimize >= 1;
86 : : }
87 : :
88 : : virtual unsigned int execute (function *) override;
89 : : }; // class pass_rtl_avoid_store_forwarding
90 : :
91 : : /* Handler for finding and avoiding store forwardings. */
92 : :
93 : : class store_forwarding_analyzer
94 : : {
95 : : public:
96 : : unsigned int stats_sf_detected = 0;
97 : : unsigned int stats_sf_avoided = 0;
98 : :
99 : : bool is_store_forwarding (rtx store_mem, rtx load_mem,
100 : : HOST_WIDE_INT *off_val);
101 : : bool process_store_forwarding (vec<store_fwd_info> &, rtx_insn *load_insn,
102 : : rtx load_mem);
103 : : void avoid_store_forwarding (basic_block);
104 : : void update_stats (function *);
105 : : };
106 : :
107 : : /* Return a bit insertion sequence that would make DEST have the correct value
108 : : if the store represented by STORE_INFO were to be moved after DEST. */
109 : :
110 : : static rtx_insn *
111 : 53 : generate_bit_insert_sequence (store_fwd_info *store_info, rtx dest)
112 : : {
113 : : /* Memory size should be a constant at this stage. */
114 : 53 : unsigned HOST_WIDE_INT store_size
115 : 53 : = MEM_SIZE (store_info->store_mem).to_constant ();
116 : :
117 : 53 : start_sequence ();
118 : :
119 : 53 : unsigned HOST_WIDE_INT bitsize = store_size * BITS_PER_UNIT;
120 : 53 : unsigned HOST_WIDE_INT start = store_info->offset * BITS_PER_UNIT;
121 : :
122 : : /* Adjust START for machines with BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN.
123 : : Given that the bytes will be reversed in this case, we need to
124 : : calculate the starting position from the end of the destination
125 : : register. */
126 : 53 : if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
127 : : {
128 : : unsigned HOST_WIDE_INT load_mode_bitsize
129 : : = (GET_MODE_BITSIZE (GET_MODE (dest))).to_constant ();
130 : : start = load_mode_bitsize - bitsize - start;
131 : : }
132 : :
133 : 53 : rtx mov_reg = store_info->mov_reg;
134 : 53 : store_bit_field (dest, bitsize, start, 0, 0, GET_MODE (mov_reg), mov_reg,
135 : : false, false);
136 : :
137 : 53 : rtx_insn *insns = get_insns ();
138 : 53 : unshare_all_rtl_in_chain (insns);
139 : 53 : end_sequence ();
140 : :
141 : 367 : for (rtx_insn *insn = insns; insn; insn = NEXT_INSN (insn))
142 : 314 : if (contains_mem_rtx_p (PATTERN (insn))
143 : 314 : || recog_memoized (insn) < 0)
144 : 0 : return NULL;
145 : :
146 : : return insns;
147 : : }
148 : :
149 : : /* Return true iff a store to STORE_MEM would write to a sub-region of bytes
150 : : from what LOAD_MEM would read. If true also store the relative byte offset
151 : : of the store within the load to OFF_VAL. */
152 : :
153 : 356 : bool store_forwarding_analyzer::
154 : : is_store_forwarding (rtx store_mem, rtx load_mem, HOST_WIDE_INT *off_val)
155 : : {
156 : 356 : poly_int64 load_offset, store_offset;
157 : 356 : rtx load_base = strip_offset (XEXP (load_mem, 0), &load_offset);
158 : 356 : rtx store_base = strip_offset (XEXP (store_mem, 0), &store_offset);
159 : 356 : return (MEM_SIZE (load_mem).is_constant ()
160 : 356 : && rtx_equal_p (load_base, store_base)
161 : 281 : && known_subrange_p (store_offset, MEM_SIZE (store_mem),
162 : 281 : load_offset, MEM_SIZE (load_mem))
163 : 79 : && (store_offset - load_offset).is_constant (off_val));
164 : : }
165 : :
166 : : /* Given a list of small stores that are forwarded to LOAD_INSN, try to
167 : : rearrange them so that a store-forwarding penalty doesn't occur.
168 : : The stores must be given in reverse program order, starting from the
169 : : one closer to LOAD_INSN. */
170 : :
171 : 13 : bool store_forwarding_analyzer::
172 : : process_store_forwarding (vec<store_fwd_info> &stores, rtx_insn *load_insn,
173 : : rtx load_mem)
174 : : {
175 : 13 : machine_mode load_mem_mode = GET_MODE (load_mem);
176 : : /* Memory sizes should be constants at this stage. */
177 : 13 : HOST_WIDE_INT load_size = MEM_SIZE (load_mem).to_constant ();
178 : :
179 : : /* If the stores cover all the bytes of the load, then we can eliminate
180 : : the load entirely and use the computed value instead.
181 : : We can also eliminate stores on addresses that are overwritten
182 : : by later stores. */
183 : :
184 : 13 : sbitmap forwarded_bytes = sbitmap_alloc (load_size);
185 : 13 : bitmap_clear (forwarded_bytes);
186 : :
187 : 13 : unsigned int i;
188 : 13 : store_fwd_info* it;
189 : 13 : auto_vec<store_fwd_info> redundant_stores;
190 : 13 : auto_vec<int> store_ind_to_remove;
191 : 92 : FOR_EACH_VEC_ELT (stores, i, it)
192 : : {
193 : 79 : HOST_WIDE_INT store_size = MEM_SIZE (it->store_mem).to_constant ();
194 : 79 : if (bitmap_all_bits_in_range_p (forwarded_bytes, it->offset,
195 : 79 : it->offset + store_size - 1))
196 : : {
197 : 16 : redundant_stores.safe_push (*it);
198 : 16 : store_ind_to_remove.safe_push (i);
199 : 16 : continue;
200 : : }
201 : 63 : bitmap_set_range (forwarded_bytes, it->offset, store_size);
202 : : }
203 : :
204 : 13 : bitmap_not (forwarded_bytes, forwarded_bytes);
205 : 13 : bool load_elim = bitmap_empty_p (forwarded_bytes);
206 : :
207 : 13 : stats_sf_detected++;
208 : :
209 : 13 : if (dump_file)
210 : : {
211 : 0 : fprintf (dump_file, "Store forwarding detected:\n");
212 : :
213 : 0 : FOR_EACH_VEC_ELT (stores, i, it)
214 : : {
215 : 0 : fprintf (dump_file, "From: ");
216 : 0 : print_rtl_single (dump_file, it->store_insn);
217 : : }
218 : :
219 : 0 : fprintf (dump_file, "To: ");
220 : 0 : print_rtl_single (dump_file, load_insn);
221 : :
222 : 0 : if (load_elim)
223 : 0 : fprintf (dump_file, "(Load elimination candidate)\n");
224 : : }
225 : :
226 : : /* Remove redundant stores from the vector. Although this is quadratic,
227 : : there doesn't seem to be much point optimizing it. The number of
228 : : redundant stores is expected to be low and the length of the list is
229 : : limited by a --param. The dependence checking that we did earlier is
230 : : also quadratic in the size of this list. */
231 : 13 : store_ind_to_remove.reverse ();
232 : 35 : for (int i : store_ind_to_remove)
233 : 16 : stores.ordered_remove (i);
234 : :
235 : 13 : rtx load = single_set (load_insn);
236 : 13 : rtx dest;
237 : :
238 : 13 : if (load_elim)
239 : 10 : dest = gen_reg_rtx (load_mem_mode);
240 : : else
241 : 3 : dest = SET_DEST (load);
242 : :
243 : 13 : int move_to_front = -1;
244 : 13 : int total_cost = 0;
245 : :
246 : : /* Check if we can emit bit insert instructions for all forwarded stores. */
247 : 76 : FOR_EACH_VEC_ELT (stores, i, it)
248 : : {
249 : 63 : it->mov_reg = gen_reg_rtx (GET_MODE (it->store_mem));
250 : 63 : rtx_insn *insns = NULL;
251 : 63 : const bool has_zero_offset = it->offset == 0;
252 : :
253 : : /* If we're eliminating the load then find the store with zero offset
254 : : and use it as the base register to avoid a bit insert if possible. */
255 : 63 : if (load_elim && has_zero_offset)
256 : : {
257 : 10 : start_sequence ();
258 : :
259 : 20 : rtx base_reg = lowpart_subreg (GET_MODE (dest), it->mov_reg,
260 : 10 : GET_MODE (it->mov_reg));
261 : :
262 : 10 : if (base_reg)
263 : : {
264 : 10 : rtx_insn *move0 = emit_move_insn (dest, base_reg);
265 : 10 : if (recog_memoized (move0) >= 0)
266 : : {
267 : 10 : insns = get_insns ();
268 : 10 : move_to_front = (int) i;
269 : : }
270 : : }
271 : :
272 : 10 : end_sequence ();
273 : : }
274 : :
275 : 10 : if (!insns)
276 : 53 : insns = generate_bit_insert_sequence (&(*it), dest);
277 : :
278 : 53 : if (!insns)
279 : : {
280 : 0 : if (dump_file)
281 : : {
282 : 0 : fprintf (dump_file, "Failed due to: ");
283 : 0 : print_rtl_single (dump_file, it->store_insn);
284 : : }
285 : 0 : return false;
286 : : }
287 : :
288 : 63 : total_cost += seq_cost (insns, true);
289 : 63 : it->bits_insert_insns = insns;
290 : :
291 : 63 : rtx store_set = single_set (it->store_insn);
292 : :
293 : : /* Create a register move at the store's original position to save the
294 : : stored value. */
295 : 63 : start_sequence ();
296 : 63 : rtx_insn *insn1
297 : 63 : = emit_insn (gen_rtx_SET (it->mov_reg, SET_SRC (store_set)));
298 : 63 : end_sequence ();
299 : :
300 : 63 : if (recog_memoized (insn1) < 0)
301 : : {
302 : 0 : if (dump_file)
303 : : {
304 : 0 : fprintf (dump_file, "Failed due to unrecognizable insn: ");
305 : 0 : print_rtl_single (dump_file, insn1);
306 : : }
307 : 0 : return false;
308 : : }
309 : :
310 : 63 : it->save_store_value_insn = insn1;
311 : :
312 : : /* Create a new store after the load with the saved original value.
313 : : This avoids the forwarding stall. */
314 : 63 : start_sequence ();
315 : 63 : rtx_insn *insn2
316 : 63 : = emit_insn (gen_rtx_SET (SET_DEST (store_set), it->mov_reg));
317 : 63 : end_sequence ();
318 : :
319 : 63 : if (recog_memoized (insn2) < 0)
320 : : {
321 : 0 : if (dump_file)
322 : : {
323 : 0 : fprintf (dump_file, "Failed due to unrecognizable insn: ");
324 : 0 : print_rtl_single (dump_file, insn2);
325 : : }
326 : 0 : return false;
327 : : }
328 : :
329 : 63 : it->store_saved_value_insn = insn2;
330 : : }
331 : :
332 : 13 : if (load_elim)
333 : 10 : total_cost -= insn_cost (load_insn, true);
334 : :
335 : : /* Let the target decide if transforming this store forwarding instance is
336 : : profitable. */
337 : 13 : if (!targetm.avoid_store_forwarding_p (stores, load_mem, total_cost,
338 : : load_elim))
339 : : {
340 : 1 : if (dump_file)
341 : 0 : fprintf (dump_file, "Not transformed due to target decision.\n");
342 : :
343 : 1 : return false;
344 : : }
345 : :
346 : : /* If we have a move instead of bit insert, it needs to be emitted first in
347 : : the resulting sequence. */
348 : 12 : if (move_to_front != -1)
349 : : {
350 : 10 : store_fwd_info copy = stores[move_to_front];
351 : 10 : stores.safe_push (copy);
352 : 10 : stores.ordered_remove (move_to_front);
353 : : }
354 : :
355 : 12 : if (load_elim)
356 : : {
357 : 10 : machine_mode outer_mode = GET_MODE (SET_DEST (load));
358 : 10 : rtx load_move;
359 : 10 : rtx load_value = dest;
360 : 10 : if (outer_mode != load_mem_mode)
361 : : {
362 : 0 : load_value = simplify_gen_unary (GET_CODE (SET_SRC (load)),
363 : : outer_mode, dest, load_mem_mode);
364 : : }
365 : 10 : load_move = gen_rtx_SET (SET_DEST (load), load_value);
366 : :
367 : 10 : start_sequence ();
368 : 10 : rtx_insn *insn = emit_insn (load_move);
369 : 10 : rtx_insn *seq = end_sequence ();
370 : :
371 : 10 : if (recog_memoized (insn) < 0)
372 : : return false;
373 : :
374 : 10 : emit_insn_after (seq, load_insn);
375 : : }
376 : :
377 : 12 : if (dump_file)
378 : : {
379 : 0 : fprintf (dump_file, "Store forwarding avoided with bit inserts:\n");
380 : :
381 : 0 : FOR_EACH_VEC_ELT (stores, i, it)
382 : : {
383 : 0 : if (stores.length () > 1)
384 : : {
385 : 0 : fprintf (dump_file, "For: ");
386 : 0 : print_rtl_single (dump_file, it->store_insn);
387 : : }
388 : :
389 : 0 : fprintf (dump_file, "With sequence:\n");
390 : :
391 : 0 : for (rtx_insn *insn = it->bits_insert_insns; insn;
392 : 0 : insn = NEXT_INSN (insn))
393 : : {
394 : 0 : fprintf (dump_file, " ");
395 : 0 : print_rtl_single (dump_file, insn);
396 : : }
397 : : }
398 : :
399 : 0 : if (redundant_stores.length () > 0)
400 : : {
401 : 0 : fprintf (dump_file, "\nRedundant stores that have been removed:\n");
402 : 0 : FOR_EACH_VEC_ELT (redundant_stores, i, it)
403 : : {
404 : 0 : fprintf (dump_file, " ");
405 : 0 : print_rtl_single (dump_file, it->store_insn);
406 : : }
407 : : }
408 : : }
409 : :
410 : 12 : stats_sf_avoided++;
411 : :
412 : : /* Done, emit all the generated instructions and delete the stores.
413 : : Note that STORES are in reverse program order. */
414 : :
415 : 74 : FOR_EACH_VEC_ELT (stores, i, it)
416 : : {
417 : 62 : emit_insn_after (it->bits_insert_insns, load_insn);
418 : 62 : emit_insn_after (it->store_saved_value_insn, load_insn);
419 : : }
420 : :
421 : 74 : FOR_EACH_VEC_ELT (stores, i, it)
422 : : {
423 : 62 : emit_insn_before (it->save_store_value_insn, it->store_insn);
424 : 62 : delete_insn (it->store_insn);
425 : : }
426 : :
427 : : /* Delete redundant stores. */
428 : 28 : FOR_EACH_VEC_ELT (redundant_stores, i, it)
429 : 16 : delete_insn (it->store_insn);
430 : :
431 : 12 : df_insn_rescan (load_insn);
432 : :
433 : 12 : if (load_elim)
434 : 10 : delete_insn (load_insn);
435 : :
436 : : return true;
437 : 13 : }
438 : :
439 : : /* Try to modify BB so that expensive store forwarding cases are avoided. */
440 : :
441 : : void
442 : 51 : store_forwarding_analyzer::avoid_store_forwarding (basic_block bb)
443 : : {
444 : 51 : if (!optimize_bb_for_speed_p (bb))
445 : 9 : return;
446 : :
447 : 42 : auto_vec<store_fwd_info, 8> store_exprs;
448 : 42 : rtx_insn *insn;
449 : 42 : unsigned int insn_cnt = 0;
450 : :
451 : 1007 : FOR_BB_INSNS (bb, insn)
452 : : {
453 : 965 : if (!NONDEBUG_INSN_P (insn))
454 : 117 : continue;
455 : :
456 : 883 : vec_rtx_properties properties;
457 : 883 : properties.add_insn (insn, false);
458 : :
459 : 883 : rtx set = single_set (insn);
460 : :
461 : 883 : if (!set || insn_could_throw_p (insn))
462 : : {
463 : 35 : store_exprs.truncate (0);
464 : 35 : continue;
465 : : }
466 : :
467 : : /* The inner mem RTX if INSN is a load, NULL_RTX otherwise. */
468 : 848 : rtx load_mem = SET_SRC (set);
469 : :
470 : 848 : if (GET_CODE (load_mem) == ZERO_EXTEND
471 : 848 : || GET_CODE (load_mem) == SIGN_EXTEND)
472 : 50 : load_mem = XEXP (load_mem, 0);
473 : :
474 : 848 : if (!MEM_P (load_mem))
475 : 782 : load_mem = NULL_RTX;
476 : :
477 : : /* The mem RTX if INSN is a store, NULL_RTX otherwise. */
478 : 848 : rtx store_mem = MEM_P (SET_DEST (set)) ? SET_DEST (set) : NULL_RTX;
479 : :
480 : : /* We cannot analyze memory RTXs that have unknown size. */
481 : 350 : if ((store_mem && (!MEM_SIZE_KNOWN_P (store_mem)
482 : : || !MEM_SIZE (store_mem).is_constant ()))
483 : 914 : || (load_mem && (!MEM_SIZE_KNOWN_P (load_mem)
484 : : || !MEM_SIZE (load_mem).is_constant ())))
485 : : {
486 : 0 : store_exprs.truncate (0);
487 : 0 : continue;
488 : : }
489 : :
490 : 848 : bool is_simple = !properties.has_asm
491 : 848 : && !properties.has_side_effects ();
492 : 848 : bool is_simple_store = is_simple
493 : 848 : && store_mem
494 : 848 : && !contains_mem_rtx_p (SET_SRC (set));
495 : 848 : bool is_simple_load = is_simple
496 : 848 : && load_mem
497 : 848 : && !contains_mem_rtx_p (SET_DEST (set));
498 : :
499 : 848 : int removed_count = 0;
500 : :
501 : 848 : if (is_simple_store)
502 : : {
503 : : /* Record store forwarding candidate. */
504 : 298 : store_fwd_info info;
505 : 298 : info.store_insn = insn;
506 : 298 : info.store_mem = store_mem;
507 : 298 : info.insn_cnt = insn_cnt;
508 : 298 : info.remove = false;
509 : 298 : info.forwarded = false;
510 : 298 : store_exprs.safe_push (info);
511 : : }
512 : :
513 : 848 : bool reads_mem = false;
514 : 848 : bool writes_mem = false;
515 : 3037 : for (auto ref : properties.refs ())
516 : 2189 : if (ref.is_mem ())
517 : : {
518 : 408 : reads_mem |= ref.is_read ();
519 : 408 : writes_mem |= ref.is_write ();
520 : : }
521 : 1781 : else if (ref.is_write ())
522 : : {
523 : : /* Drop store forwarding candidates when the address register is
524 : : overwritten. */
525 : 681 : bool remove_rest = false;
526 : 681 : unsigned int i;
527 : 681 : store_fwd_info *it;
528 : 18918 : FOR_EACH_VEC_ELT_REVERSE (store_exprs, i, it)
529 : : {
530 : 15367 : if (remove_rest
531 : 30717 : || reg_overlap_mentioned_p (regno_reg_rtx[ref.regno],
532 : 15350 : it->store_mem))
533 : : {
534 : 20 : it->remove = true;
535 : 20 : removed_count++;
536 : 20 : remove_rest = true;
537 : : }
538 : : }
539 : : }
540 : :
541 : 848 : if (is_simple_load)
542 : : {
543 : : /* Process load for possible store forwarding cases.
544 : : Possible newly created/moved stores, resulted from a successful
545 : : forwarding, will be processed in subsequent iterations. */
546 : 62 : auto_vec<store_fwd_info> forwardings;
547 : 62 : bool partial_forwarding = false;
548 : 62 : bool remove_rest = false;
549 : :
550 : 62 : bool vector_load = VECTOR_MODE_P (GET_MODE (load_mem));
551 : :
552 : 62 : unsigned int i;
553 : 62 : store_fwd_info *it;
554 : 490 : FOR_EACH_VEC_ELT_REVERSE (store_exprs, i, it)
555 : : {
556 : 366 : rtx store_mem = it->store_mem;
557 : 366 : HOST_WIDE_INT off_val;
558 : :
559 : 366 : bool vector_store = VECTOR_MODE_P (GET_MODE (store_mem));
560 : :
561 : 366 : if (remove_rest)
562 : : {
563 : 9 : it->remove = true;
564 : 9 : removed_count++;
565 : : }
566 : 357 : else if (vector_load ^ vector_store)
567 : : {
568 : : /* Vector stores followed by a non-vector load or the
569 : : opposite, cause store_bit_field to generate non-canonical
570 : : expressions, like (subreg:V4SI (reg:DI ...) 0)).
571 : : Cases like that should be handled using vec_duplicate,
572 : : so we reject the transformation in those cases. */
573 : 1 : it->remove = true;
574 : 1 : removed_count++;
575 : 1 : remove_rest = true;
576 : : }
577 : 356 : else if (is_store_forwarding (store_mem, load_mem, &off_val))
578 : : {
579 : : /* Check if moving this store after the load is legal. */
580 : 79 : bool write_dep = false;
581 : 2250 : for (unsigned int j = store_exprs.length () - 1; j != i; j--)
582 : : {
583 : 2092 : if (!store_exprs[j].forwarded
584 : 3810 : && output_dependence (store_mem,
585 : 1718 : store_exprs[j].store_mem))
586 : : {
587 : : write_dep = true;
588 : : break;
589 : : }
590 : : }
591 : :
592 : 79 : if (!write_dep)
593 : : {
594 : 79 : it->forwarded = true;
595 : 79 : it->offset = off_val;
596 : 79 : forwardings.safe_push (*it);
597 : : }
598 : : else
599 : : partial_forwarding = true;
600 : :
601 : 79 : it->remove = true;
602 : 79 : removed_count++;
603 : : }
604 : 277 : else if (true_dependence (store_mem, GET_MODE (store_mem),
605 : : load_mem))
606 : : {
607 : : /* We cannot keep a store forwarding candidate if it possibly
608 : : interferes with this load. */
609 : 0 : it->remove = true;
610 : 0 : removed_count++;
611 : 0 : remove_rest = true;
612 : : }
613 : : }
614 : :
615 : 88 : if (!forwardings.is_empty () && !partial_forwarding)
616 : 13 : process_store_forwarding (forwardings, insn, load_mem);
617 : 62 : }
618 : :
619 : 848 : if ((writes_mem && !is_simple_store)
620 : 818 : || (reads_mem && !is_simple_load))
621 : 37 : store_exprs.truncate (0);
622 : :
623 : 848 : if (removed_count)
624 : : {
625 : 17 : unsigned int i, j;
626 : 17 : store_fwd_info *it;
627 : 310 : VEC_ORDERED_REMOVE_IF (store_exprs, i, j, it, it->remove);
628 : : }
629 : :
630 : : /* Don't consider store forwarding if the RTL instruction distance is
631 : : more than PARAM_STORE_FORWARDING_MAX_DISTANCE and the cost checks
632 : : are not disabled. */
633 : 848 : const bool unlimited_cost = (param_store_forwarding_max_distance == 0);
634 : 233 : if (!unlimited_cost && !store_exprs.is_empty ()
635 : 848 : && (store_exprs[0].insn_cnt
636 : 233 : + param_store_forwarding_max_distance <= insn_cnt))
637 : 64 : store_exprs.ordered_remove (0);
638 : :
639 : 848 : insn_cnt++;
640 : 883 : }
641 : 42 : }
642 : :
643 : : /* Update pass statistics. */
644 : :
645 : : void
646 : 17 : store_forwarding_analyzer::update_stats (function *fn)
647 : : {
648 : 17 : statistics_counter_event (fn, "Cases of store forwarding detected: ",
649 : 17 : stats_sf_detected);
650 : 17 : statistics_counter_event (fn, "Cases of store forwarding avoided: ",
651 : 17 : stats_sf_detected);
652 : 17 : }
653 : :
654 : : unsigned int
655 : 17 : pass_rtl_avoid_store_forwarding::execute (function *fn)
656 : : {
657 : 17 : df_set_flags (DF_DEFER_INSN_RESCAN);
658 : :
659 : 17 : init_alias_analysis ();
660 : :
661 : 17 : store_forwarding_analyzer analyzer;
662 : :
663 : 17 : basic_block bb;
664 : 68 : FOR_EACH_BB_FN (bb, fn)
665 : 51 : analyzer.avoid_store_forwarding (bb);
666 : :
667 : 17 : end_alias_analysis ();
668 : :
669 : 17 : analyzer.update_stats (fn);
670 : :
671 : 17 : return 0;
672 : : }
673 : :
674 : : } // anon namespace.
675 : :
676 : : rtl_opt_pass *
677 : 285081 : make_pass_rtl_avoid_store_forwarding (gcc::context *ctxt)
678 : : {
679 : 285081 : return new pass_rtl_avoid_store_forwarding (ctxt);
680 : : }
|