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 : 283157 : pass_rtl_avoid_store_forwarding (gcc::context *ctxt)
79 : 566314 : : rtl_opt_pass (pass_data_avoid_store_forwarding, ctxt)
80 : : {}
81 : :
82 : : /* opt_pass methods: */
83 : 1435849 : virtual bool gate (function *)
84 : : {
85 : 1435849 : 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 : 75 : generate_bit_insert_sequence (store_fwd_info *store_info, rtx dest)
112 : : {
113 : : /* Memory size should be a constant at this stage. */
114 : 75 : unsigned HOST_WIDE_INT store_size
115 : 75 : = MEM_SIZE (store_info->store_mem).to_constant ();
116 : :
117 : 75 : start_sequence ();
118 : :
119 : 75 : unsigned HOST_WIDE_INT bitsize = store_size * BITS_PER_UNIT;
120 : 75 : 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 : 75 : 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 : 75 : rtx mov_reg = store_info->mov_reg;
134 : 75 : store_bit_field (dest, bitsize, start, 0, 0, GET_MODE (mov_reg), mov_reg,
135 : : false, false);
136 : :
137 : 75 : rtx_insn *insns = get_insns ();
138 : 75 : unshare_all_rtl_in_chain (insns);
139 : 75 : end_sequence ();
140 : :
141 : 473 : for (rtx_insn *insn = insns; insn; insn = NEXT_INSN (insn))
142 : 398 : if (contains_mem_rtx_p (PATTERN (insn))
143 : 398 : || 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 : 347 : bool store_forwarding_analyzer::
154 : : is_store_forwarding (rtx store_mem, rtx load_mem, HOST_WIDE_INT *off_val)
155 : : {
156 : 347 : poly_int64 load_offset, store_offset;
157 : 347 : rtx load_base = strip_offset (XEXP (load_mem, 0), &load_offset);
158 : 347 : rtx store_base = strip_offset (XEXP (store_mem, 0), &store_offset);
159 : 347 : return (MEM_SIZE (load_mem).is_constant ()
160 : 347 : && rtx_equal_p (load_base, store_base)
161 : 285 : && known_subrange_p (store_offset, MEM_SIZE (store_mem),
162 : 285 : load_offset, MEM_SIZE (load_mem))
163 : 75 : && (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 : 10 : bool store_forwarding_analyzer::
172 : : process_store_forwarding (vec<store_fwd_info> &stores, rtx_insn *load_insn,
173 : : rtx load_mem)
174 : : {
175 : 10 : machine_mode load_mem_mode = GET_MODE (load_mem);
176 : : /* Memory sizes should be constants at this stage. */
177 : 10 : HOST_WIDE_INT load_size = MEM_SIZE (load_mem).to_constant ();
178 : :
179 : : /* If the stores cover all the bytes of the load without overlap then we can
180 : : eliminate the load entirely and use the computed value instead. */
181 : :
182 : 10 : sbitmap forwarded_bytes = sbitmap_alloc (load_size);
183 : 10 : bitmap_clear (forwarded_bytes);
184 : :
185 : 10 : unsigned int i;
186 : 10 : store_fwd_info* it;
187 : 68 : FOR_EACH_VEC_ELT (stores, i, it)
188 : : {
189 : 61 : HOST_WIDE_INT store_size = MEM_SIZE (it->store_mem).to_constant ();
190 : 61 : if (bitmap_bit_in_range_p (forwarded_bytes, it->offset,
191 : 61 : it->offset + store_size - 1))
192 : : break;
193 : 58 : bitmap_set_range (forwarded_bytes, it->offset, store_size);
194 : : }
195 : :
196 : 10 : bitmap_not (forwarded_bytes, forwarded_bytes);
197 : 10 : bool load_elim = bitmap_empty_p (forwarded_bytes);
198 : :
199 : 10 : stats_sf_detected++;
200 : :
201 : 10 : if (dump_file)
202 : : {
203 : 0 : fprintf (dump_file, "Store forwarding detected:\n");
204 : :
205 : 0 : FOR_EACH_VEC_ELT (stores, i, it)
206 : : {
207 : 0 : fprintf (dump_file, "From: ");
208 : 0 : print_rtl_single (dump_file, it->store_insn);
209 : : }
210 : :
211 : 0 : fprintf (dump_file, "To: ");
212 : 0 : print_rtl_single (dump_file, load_insn);
213 : :
214 : 0 : if (load_elim)
215 : 0 : fprintf (dump_file, "(Load elimination candidate)\n");
216 : : }
217 : :
218 : 10 : rtx load = single_set (load_insn);
219 : 10 : rtx dest;
220 : :
221 : 10 : if (load_elim)
222 : 6 : dest = gen_reg_rtx (load_mem_mode);
223 : : else
224 : 4 : dest = SET_DEST (load);
225 : :
226 : 10 : int move_to_front = -1;
227 : 10 : int total_cost = 0;
228 : :
229 : : /* Check if we can emit bit insert instructions for all forwarded stores. */
230 : 85 : FOR_EACH_VEC_ELT (stores, i, it)
231 : : {
232 : 75 : it->mov_reg = gen_reg_rtx (GET_MODE (it->store_mem));
233 : 75 : rtx_insn *insns = NULL;
234 : :
235 : : /* If we're eliminating the load then find the store with zero offset
236 : : and use it as the base register to avoid a bit insert if possible. */
237 : 75 : if (load_elim && it->offset == 0)
238 : : {
239 : 8 : start_sequence ();
240 : :
241 : 8 : rtx ext0 = gen_rtx_ZERO_EXTEND (GET_MODE (dest), it->mov_reg);
242 : 8 : if (ext0)
243 : : {
244 : 8 : rtx_insn *move0 = emit_move_insn (dest, ext0);
245 : 8 : if (recog_memoized (move0) >= 0)
246 : : {
247 : 0 : insns = get_insns ();
248 : 0 : move_to_front = (int) i;
249 : : }
250 : : }
251 : :
252 : 0 : end_sequence ();
253 : : }
254 : :
255 : 8 : if (!insns)
256 : 75 : insns = generate_bit_insert_sequence (&(*it), dest);
257 : :
258 : 75 : if (!insns)
259 : : {
260 : 0 : if (dump_file)
261 : : {
262 : 0 : fprintf (dump_file, "Failed due to: ");
263 : 0 : print_rtl_single (dump_file, it->store_insn);
264 : : }
265 : 0 : return false;
266 : : }
267 : :
268 : 75 : total_cost += seq_cost (insns, true);
269 : 75 : it->bits_insert_insns = insns;
270 : :
271 : 75 : rtx store_set = single_set (it->store_insn);
272 : :
273 : : /* Create a register move at the store's original position to save the
274 : : stored value. */
275 : 75 : start_sequence ();
276 : 75 : rtx_insn *insn1
277 : 75 : = emit_insn (gen_rtx_SET (it->mov_reg, SET_SRC (store_set)));
278 : 75 : end_sequence ();
279 : :
280 : 75 : if (recog_memoized (insn1) < 0)
281 : : {
282 : 0 : if (dump_file)
283 : : {
284 : 0 : fprintf (dump_file, "Failed due to unrecognizable insn: ");
285 : 0 : print_rtl_single (dump_file, insn1);
286 : : }
287 : 0 : return false;
288 : : }
289 : :
290 : 75 : it->save_store_value_insn = insn1;
291 : :
292 : : /* Create a new store after the load with the saved original value.
293 : : This avoids the forwarding stall. */
294 : 75 : start_sequence ();
295 : 75 : rtx_insn *insn2
296 : 75 : = emit_insn (gen_rtx_SET (SET_DEST (store_set), it->mov_reg));
297 : 75 : end_sequence ();
298 : :
299 : 75 : if (recog_memoized (insn2) < 0)
300 : : {
301 : 0 : if (dump_file)
302 : : {
303 : 0 : fprintf (dump_file, "Failed due to unrecognizable insn: ");
304 : 0 : print_rtl_single (dump_file, insn2);
305 : : }
306 : 0 : return false;
307 : : }
308 : :
309 : 75 : it->store_saved_value_insn = insn2;
310 : : }
311 : :
312 : 10 : if (load_elim)
313 : 6 : total_cost -= insn_cost (load_insn, true);
314 : :
315 : : /* Let the target decide if transforming this store forwarding instance is
316 : : profitable. */
317 : 10 : if (!targetm.avoid_store_forwarding_p (stores, load_mem, total_cost,
318 : : load_elim))
319 : : {
320 : 1 : if (dump_file)
321 : 0 : fprintf (dump_file, "Not transformed due to target decision.\n");
322 : :
323 : 1 : return false;
324 : : }
325 : :
326 : : /* If we have a move instead of bit insert, it needs to be emitted first in
327 : : the resulting sequence. */
328 : 9 : if (move_to_front != -1)
329 : : {
330 : 0 : store_fwd_info copy = stores[move_to_front];
331 : 0 : stores.safe_push (copy);
332 : 0 : stores.ordered_remove (move_to_front);
333 : : }
334 : :
335 : 9 : if (load_elim)
336 : : {
337 : 6 : machine_mode outer_mode = GET_MODE (SET_DEST (load));
338 : 6 : rtx load_move;
339 : 6 : rtx load_value = dest;
340 : 6 : if (outer_mode != load_mem_mode)
341 : : {
342 : 0 : load_value = simplify_gen_unary (GET_CODE (SET_SRC (load)),
343 : : outer_mode, dest, load_mem_mode);
344 : : }
345 : 6 : load_move = gen_rtx_SET (SET_DEST (load), load_value);
346 : :
347 : 6 : start_sequence ();
348 : 6 : rtx_insn *insn = emit_insn (load_move);
349 : 6 : rtx_insn *seq = get_insns ();
350 : 6 : end_sequence ();
351 : :
352 : 6 : if (recog_memoized (insn) < 0)
353 : : return false;
354 : :
355 : 6 : emit_insn_after (seq, load_insn);
356 : : }
357 : :
358 : 9 : if (dump_file)
359 : : {
360 : 0 : fprintf (dump_file, "Store forwarding avoided with bit inserts:\n");
361 : :
362 : 0 : FOR_EACH_VEC_ELT (stores, i, it)
363 : : {
364 : 0 : if (stores.length () > 1)
365 : : {
366 : 0 : fprintf (dump_file, "For: ");
367 : 0 : print_rtl_single (dump_file, it->store_insn);
368 : : }
369 : :
370 : 0 : fprintf (dump_file, "With sequence:\n");
371 : :
372 : 0 : for (rtx_insn *insn = it->bits_insert_insns; insn;
373 : 0 : insn = NEXT_INSN (insn))
374 : : {
375 : 0 : fprintf (dump_file, " ");
376 : 0 : print_rtl_single (dump_file, insn);
377 : : }
378 : : }
379 : : }
380 : :
381 : 9 : stats_sf_avoided++;
382 : :
383 : : /* Done, emit all the generated instructions and delete the stores.
384 : : Note that STORES are in reverse program order. */
385 : :
386 : 83 : FOR_EACH_VEC_ELT (stores, i, it)
387 : : {
388 : 74 : emit_insn_after (it->bits_insert_insns, load_insn);
389 : 74 : emit_insn_after (it->store_saved_value_insn, load_insn);
390 : : }
391 : :
392 : 83 : FOR_EACH_VEC_ELT (stores, i, it)
393 : : {
394 : 74 : emit_insn_before (it->save_store_value_insn, it->store_insn);
395 : 74 : delete_insn (it->store_insn);
396 : : }
397 : :
398 : 9 : df_insn_rescan (load_insn);
399 : :
400 : 9 : if (load_elim)
401 : 6 : delete_insn (load_insn);
402 : :
403 : : return true;
404 : : }
405 : :
406 : : /* Try to modify BB so that expensive store forwarding cases are avoided. */
407 : :
408 : : void
409 : 19 : store_forwarding_analyzer::avoid_store_forwarding (basic_block bb)
410 : : {
411 : 19 : if (!optimize_bb_for_speed_p (bb))
412 : 2 : return;
413 : :
414 : 17 : auto_vec<store_fwd_info, 8> store_exprs;
415 : 17 : rtx_insn *insn;
416 : 17 : unsigned int insn_cnt = 0;
417 : :
418 : 819 : FOR_BB_INSNS (bb, insn)
419 : : {
420 : 802 : if (!NONDEBUG_INSN_P (insn))
421 : 60 : continue;
422 : :
423 : 760 : vec_rtx_properties properties;
424 : 760 : properties.add_insn (insn, false);
425 : :
426 : 760 : rtx set = single_set (insn);
427 : :
428 : 760 : if (!set || insn_could_throw_p (insn))
429 : : {
430 : 18 : store_exprs.truncate (0);
431 : 18 : continue;
432 : : }
433 : :
434 : : /* The inner mem RTX if INSN is a load, NULL_RTX otherwise. */
435 : 742 : rtx load_mem = SET_SRC (set);
436 : :
437 : 742 : if (GET_CODE (load_mem) == ZERO_EXTEND
438 : 742 : || GET_CODE (load_mem) == SIGN_EXTEND)
439 : 58 : load_mem = XEXP (load_mem, 0);
440 : :
441 : 742 : if (!MEM_P (load_mem))
442 : 702 : load_mem = NULL_RTX;
443 : :
444 : : /* The mem RTX if INSN is a store, NULL_RTX otherwise. */
445 : 742 : rtx store_mem = MEM_P (SET_DEST (set)) ? SET_DEST (set) : NULL_RTX;
446 : :
447 : : /* We cannot analyze memory RTXs that have unknown size. */
448 : 236 : if ((store_mem && (!MEM_SIZE_KNOWN_P (store_mem)
449 : : || !MEM_SIZE (store_mem).is_constant ()))
450 : 782 : || (load_mem && (!MEM_SIZE_KNOWN_P (load_mem)
451 : : || !MEM_SIZE (load_mem).is_constant ())))
452 : : {
453 : 0 : store_exprs.truncate (0);
454 : 0 : continue;
455 : : }
456 : :
457 : 742 : bool is_simple = !properties.has_asm
458 : 742 : && !properties.has_side_effects ();
459 : 742 : bool is_simple_store = is_simple
460 : 742 : && store_mem
461 : 742 : && !contains_mem_rtx_p (SET_SRC (set));
462 : 742 : bool is_simple_load = is_simple
463 : 742 : && load_mem
464 : 742 : && !contains_mem_rtx_p (SET_DEST (set));
465 : :
466 : 742 : int removed_count = 0;
467 : :
468 : 742 : if (is_simple_store)
469 : : {
470 : : /* Record store forwarding candidate. */
471 : 216 : store_fwd_info info;
472 : 216 : info.store_insn = insn;
473 : 216 : info.store_mem = store_mem;
474 : 216 : info.insn_cnt = insn_cnt;
475 : 216 : info.remove = false;
476 : 216 : info.forwarded = false;
477 : 216 : store_exprs.safe_push (info);
478 : : }
479 : :
480 : 742 : bool reads_mem = false;
481 : 742 : bool writes_mem = false;
482 : 2665 : for (auto ref : properties.refs ())
483 : 1923 : if (ref.is_mem ())
484 : : {
485 : 300 : reads_mem |= ref.is_read ();
486 : 300 : writes_mem |= ref.is_write ();
487 : : }
488 : 1623 : else if (ref.is_write ())
489 : : {
490 : : /* Drop store forwarding candidates when the address register is
491 : : overwritten. */
492 : 696 : bool remove_rest = false;
493 : 696 : unsigned int i;
494 : 696 : store_fwd_info *it;
495 : 25722 : FOR_EACH_VEC_ELT_REVERSE (store_exprs, i, it)
496 : : {
497 : 22407 : if (remove_rest
498 : 44797 : || reg_overlap_mentioned_p (regno_reg_rtx[ref.regno],
499 : 22390 : it->store_mem))
500 : : {
501 : 20 : it->remove = true;
502 : 20 : removed_count++;
503 : 20 : remove_rest = true;
504 : : }
505 : : }
506 : : }
507 : :
508 : 742 : if (is_simple_load)
509 : : {
510 : : /* Process load for possible store forwarding cases.
511 : : Possible newly created/moved stores, resulted from a successful
512 : : forwarding, will be processed in subsequent iterations. */
513 : 40 : auto_vec<store_fwd_info> forwardings;
514 : 40 : bool partial_forwarding = false;
515 : 40 : bool remove_rest = false;
516 : :
517 : 40 : bool vector_load = VECTOR_MODE_P (GET_MODE (load_mem));
518 : :
519 : 40 : unsigned int i;
520 : 40 : store_fwd_info *it;
521 : 427 : FOR_EACH_VEC_ELT_REVERSE (store_exprs, i, it)
522 : : {
523 : 347 : rtx store_mem = it->store_mem;
524 : 347 : HOST_WIDE_INT off_val;
525 : :
526 : 347 : bool vector_store = VECTOR_MODE_P (GET_MODE (store_mem));
527 : :
528 : 347 : if (remove_rest)
529 : : {
530 : 0 : it->remove = true;
531 : 0 : removed_count++;
532 : : }
533 : 347 : else if (vector_load ^ vector_store)
534 : : {
535 : : /* Vector stores followed by a non-vector load or the
536 : : opposite, cause store_bit_field to generate non-canonical
537 : : expressions, like (subreg:V4SI (reg:DI ...) 0)).
538 : : Cases like that should be handled using vec_duplicate,
539 : : so we reject the transformation in those cases. */
540 : 0 : it->remove = true;
541 : 0 : removed_count++;
542 : 0 : remove_rest = true;
543 : : }
544 : 347 : else if (is_store_forwarding (store_mem, load_mem, &off_val))
545 : : {
546 : : /* Check if moving this store after the load is legal. */
547 : 75 : bool write_dep = false;
548 : 2490 : for (unsigned int j = store_exprs.length () - 1; j != i; j--)
549 : : {
550 : 2340 : if (!store_exprs[j].forwarded
551 : 4307 : && output_dependence (store_mem,
552 : 1967 : store_exprs[j].store_mem))
553 : : {
554 : : write_dep = true;
555 : : break;
556 : : }
557 : : }
558 : :
559 : 75 : if (!write_dep)
560 : : {
561 : 75 : it->forwarded = true;
562 : 75 : it->offset = off_val;
563 : 75 : forwardings.safe_push (*it);
564 : : }
565 : : else
566 : : partial_forwarding = true;
567 : :
568 : 75 : it->remove = true;
569 : 75 : removed_count++;
570 : : }
571 : 272 : else if (true_dependence (store_mem, GET_MODE (store_mem),
572 : : load_mem))
573 : : {
574 : : /* We cannot keep a store forwarding candidate if it possibly
575 : : interferes with this load. */
576 : 0 : it->remove = true;
577 : 0 : removed_count++;
578 : 0 : remove_rest = true;
579 : : }
580 : : }
581 : :
582 : 60 : if (!forwardings.is_empty () && !partial_forwarding)
583 : 10 : process_store_forwarding (forwardings, insn, load_mem);
584 : 40 : }
585 : :
586 : 742 : if ((writes_mem && !is_simple_store)
587 : 712 : || (reads_mem && !is_simple_load))
588 : 33 : store_exprs.truncate (0);
589 : :
590 : 742 : if (removed_count)
591 : : {
592 : 13 : unsigned int i, j;
593 : 13 : store_fwd_info *it;
594 : 309 : VEC_ORDERED_REMOVE_IF (store_exprs, i, j, it, it->remove);
595 : : }
596 : :
597 : : /* Don't consider store forwarding if the RTL instruction distance is
598 : : more than PARAM_STORE_FORWARDING_MAX_DISTANCE and the cost checks
599 : : are not disabled. */
600 : 742 : const bool unlimited_cost = (param_store_forwarding_max_distance == 0);
601 : 73 : if (!unlimited_cost && !store_exprs.is_empty ()
602 : 742 : && (store_exprs[0].insn_cnt
603 : 73 : + param_store_forwarding_max_distance <= insn_cnt))
604 : 0 : store_exprs.ordered_remove (0);
605 : :
606 : 742 : insn_cnt++;
607 : 760 : }
608 : 17 : }
609 : :
610 : : /* Update pass statistics. */
611 : :
612 : : void
613 : 11 : store_forwarding_analyzer::update_stats (function *fn)
614 : : {
615 : 11 : statistics_counter_event (fn, "Cases of store forwarding detected: ",
616 : 11 : stats_sf_detected);
617 : 11 : statistics_counter_event (fn, "Cases of store forwarding avoided: ",
618 : 11 : stats_sf_detected);
619 : 11 : }
620 : :
621 : : unsigned int
622 : 11 : pass_rtl_avoid_store_forwarding::execute (function *fn)
623 : : {
624 : 11 : df_set_flags (DF_DEFER_INSN_RESCAN);
625 : :
626 : 11 : init_alias_analysis ();
627 : :
628 : 11 : store_forwarding_analyzer analyzer;
629 : :
630 : 11 : basic_block bb;
631 : 30 : FOR_EACH_BB_FN (bb, fn)
632 : 19 : analyzer.avoid_store_forwarding (bb);
633 : :
634 : 11 : end_alias_analysis ();
635 : :
636 : 11 : analyzer.update_stats (fn);
637 : :
638 : 11 : return 0;
639 : : }
640 : :
641 : : } // anon namespace.
642 : :
643 : : rtl_opt_pass *
644 : 283157 : make_pass_rtl_avoid_store_forwarding (gcc::context *ctxt)
645 : : {
646 : 283157 : return new pass_rtl_avoid_store_forwarding (ctxt);
647 : : }
|