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