LCOV - code coverage report
Current view: top level - gcc - avoid-store-forwarding.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 83.8 % 321 269
Test Date: 2025-09-20 13:40:47 Functions: 100.0 % 8 8
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             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                 :      285689 :   pass_rtl_avoid_store_forwarding (gcc::context *ctxt)
      79                 :      571378 :     : rtl_opt_pass (pass_data_avoid_store_forwarding, ctxt)
      80                 :             :   {}
      81                 :             : 
      82                 :             :   /* opt_pass methods: */
      83                 :     1481340 :   virtual bool gate (function *) final override
      84                 :             :     {
      85                 :     1481340 :       return flag_avoid_store_forwarding && optimize >= 1;
      86                 :             :     }
      87                 :             : 
      88                 :             :   virtual unsigned int execute (function *) final 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                 :           6 : generate_bit_insert_sequence (store_fwd_info *store_info, rtx dest)
     112                 :             : {
     113                 :             :   /* Memory size should be a constant at this stage.  */
     114                 :           6 :   unsigned HOST_WIDE_INT store_size
     115                 :           6 :     = MEM_SIZE (store_info->store_mem).to_constant ();
     116                 :             : 
     117                 :           6 :   start_sequence ();
     118                 :             : 
     119                 :           6 :   unsigned HOST_WIDE_INT bitsize = store_size * BITS_PER_UNIT;
     120                 :           6 :   unsigned HOST_WIDE_INT start = store_info->offset * BITS_PER_UNIT;
     121                 :             : 
     122                 :           6 :   rtx mov_reg = store_info->mov_reg;
     123                 :           6 :   store_bit_field (dest, bitsize, start, 0, 0, GET_MODE (mov_reg), mov_reg,
     124                 :             :                    false, false);
     125                 :             : 
     126                 :           6 :   rtx_insn *insns = get_insns ();
     127                 :           6 :   unshare_all_rtl_in_chain (insns);
     128                 :           6 :   end_sequence ();
     129                 :             : 
     130                 :          25 :   for (rtx_insn *insn = insns; insn; insn = NEXT_INSN (insn))
     131                 :          19 :     if (contains_mem_rtx_p (PATTERN (insn))
     132                 :          19 :         || recog_memoized (insn) < 0)
     133                 :           0 :       return NULL;
     134                 :             : 
     135                 :             :   return insns;
     136                 :             : }
     137                 :             : 
     138                 :             : /* Return true iff a store to STORE_MEM would write to a sub-region of bytes
     139                 :             :    from what LOAD_MEM would read.  If true also store the relative byte offset
     140                 :             :    of the store within the load to OFF_VAL.  */
     141                 :             : 
     142                 :          68 : bool store_forwarding_analyzer::
     143                 :             : is_store_forwarding (rtx store_mem, rtx load_mem, HOST_WIDE_INT *off_val)
     144                 :             : {
     145                 :          68 :   poly_int64 load_offset, store_offset;
     146                 :          68 :   rtx load_base = strip_offset (XEXP (load_mem, 0), &load_offset);
     147                 :          68 :   rtx store_base = strip_offset (XEXP (store_mem, 0), &store_offset);
     148                 :          68 :   poly_int64 off_diff = store_offset - load_offset;
     149                 :             : 
     150                 :          68 :   HOST_WIDE_INT off_val_tmp = 0;
     151                 :          68 :   bool is_off_diff_constant = off_diff.is_constant (&off_val_tmp);
     152                 :          68 :   if (off_val)
     153                 :          63 :     *off_val = off_val_tmp;
     154                 :             : 
     155                 :          68 :   return (MEM_SIZE (load_mem).is_constant ()
     156                 :          68 :           && rtx_equal_p (load_base, store_base)
     157                 :          43 :           && known_subrange_p (store_offset, MEM_SIZE (store_mem),
     158                 :          43 :                                load_offset, MEM_SIZE (load_mem))
     159                 :          68 :           && is_off_diff_constant);
     160                 :             : }
     161                 :             : 
     162                 :             : /* Given a list of small stores that are forwarded to LOAD_INSN, try to
     163                 :             :    rearrange them so that a store-forwarding penalty doesn't occur.
     164                 :             :    The stores must be given in reverse program order, starting from the
     165                 :             :    one closer to LOAD_INSN.  */
     166                 :             : 
     167                 :           8 : bool store_forwarding_analyzer::
     168                 :             : process_store_forwarding (vec<store_fwd_info> &stores, rtx_insn *load_insn,
     169                 :             :                           rtx load_mem)
     170                 :             : {
     171                 :           8 :   machine_mode load_mem_mode = GET_MODE (load_mem);
     172                 :             :   /* Memory sizes should be constants at this stage.  */
     173                 :           8 :   HOST_WIDE_INT load_size = MEM_SIZE (load_mem).to_constant ();
     174                 :             : 
     175                 :             :   /* If the stores cover all the bytes of the load, then we can eliminate
     176                 :             :      the load entirely and use the computed value instead.
     177                 :             :      We can also eliminate stores on addresses that are overwritten
     178                 :             :      by later stores.  */
     179                 :             : 
     180                 :           8 :   sbitmap forwarded_bytes = sbitmap_alloc (load_size);
     181                 :           8 :   bitmap_clear (forwarded_bytes);
     182                 :             : 
     183                 :           8 :   unsigned int i;
     184                 :           8 :   store_fwd_info* it;
     185                 :           8 :   auto_vec<store_fwd_info> redundant_stores;
     186                 :           8 :   auto_vec<int> store_ind_to_remove;
     187                 :          18 :   FOR_EACH_VEC_ELT (stores, i, it)
     188                 :             :     {
     189                 :          10 :       HOST_WIDE_INT store_size = MEM_SIZE (it->store_mem).to_constant ();
     190                 :          10 :       if (bitmap_all_bits_in_range_p (forwarded_bytes, it->offset,
     191                 :          10 :                                       it->offset + store_size - 1))
     192                 :             :         {
     193                 :           0 :           redundant_stores.safe_push (*it);
     194                 :           0 :           store_ind_to_remove.safe_push (i);
     195                 :           0 :           continue;
     196                 :             :         }
     197                 :          10 :       bitmap_set_range (forwarded_bytes, it->offset, store_size);
     198                 :             :     }
     199                 :             : 
     200                 :           8 :   bitmap_not (forwarded_bytes, forwarded_bytes);
     201                 :           8 :   bool load_elim = bitmap_empty_p (forwarded_bytes);
     202                 :             : 
     203                 :           8 :   stats_sf_detected++;
     204                 :             : 
     205                 :           8 :   if (dump_file)
     206                 :             :     {
     207                 :           0 :       fprintf (dump_file, "Store forwarding detected:\n");
     208                 :             : 
     209                 :           0 :       FOR_EACH_VEC_ELT (stores, i, it)
     210                 :             :         {
     211                 :           0 :           fprintf (dump_file, "From: ");
     212                 :           0 :           print_rtl_single (dump_file, it->store_insn);
     213                 :             :         }
     214                 :             : 
     215                 :           0 :       fprintf (dump_file, "To: ");
     216                 :           0 :       print_rtl_single (dump_file, load_insn);
     217                 :             : 
     218                 :           0 :       if (load_elim)
     219                 :           0 :         fprintf (dump_file, "(Load elimination candidate)\n");
     220                 :             :     }
     221                 :             : 
     222                 :             :   /* Remove redundant stores from the vector.  Although this is quadratic,
     223                 :             :      there doesn't seem to be much point optimizing it.  The number of
     224                 :             :      redundant stores is expected to be low and the length of the list is
     225                 :             :      limited by a --param.  The dependence checking that we did earlier is
     226                 :             :      also quadratic in the size of this list.  */
     227                 :           8 :   store_ind_to_remove.reverse ();
     228                 :           8 :   for (int i : store_ind_to_remove)
     229                 :           0 :     stores.ordered_remove (i);
     230                 :             : 
     231                 :           8 :   rtx load = single_set (load_insn);
     232                 :           8 :   rtx dest;
     233                 :             : 
     234                 :           8 :   if (load_elim)
     235                 :           4 :     dest = gen_reg_rtx (load_mem_mode);
     236                 :             :   else
     237                 :           4 :     dest = SET_DEST (load);
     238                 :             : 
     239                 :           8 :   int move_to_front = -1;
     240                 :           8 :   int total_cost = 0;
     241                 :           8 :   int base_offset_index = -1;
     242                 :             : 
     243                 :             :   /* Find the last store that has the same offset the load, in the case that
     244                 :             :      we're eliminating the load.  We will try to use it as a base register
     245                 :             :      to avoid bit inserts (see second loop below).  We want the last one, as
     246                 :             :      it will be wider and we don't want to overwrite the base register if
     247                 :             :      there are many of them.  */
     248                 :           4 :   if (load_elim)
     249                 :             :     {
     250                 :           8 :       FOR_EACH_VEC_ELT_REVERSE (stores, i, it)
     251                 :             :         {
     252                 :           4 :           const bool has_base_offset
     253                 :           4 :             = known_eq (poly_uint64 (it->offset),
     254                 :             :                         subreg_size_lowpart_offset (MEM_SIZE (it->store_mem),
     255                 :             :                                                     load_size));
     256                 :           4 :           if (has_base_offset)
     257                 :             :             {
     258                 :           4 :               base_offset_index = i;
     259                 :           4 :               break;
     260                 :             :             }
     261                 :             :         }
     262                 :             :     }
     263                 :             : 
     264                 :             :   /* Check if we can emit bit insert instructions for all forwarded stores.  */
     265                 :          18 :   FOR_EACH_VEC_ELT (stores, i, it)
     266                 :             :     {
     267                 :          10 :       it->mov_reg = gen_reg_rtx (GET_MODE (it->store_mem));
     268                 :          10 :       rtx_insn *insns = NULL;
     269                 :             : 
     270                 :             :       /* Check if this is a store with base offset, if we're eliminating the
     271                 :             :          load, and use it as the base register to avoid a bit insert if
     272                 :             :          possible.  Load elimination is implied by base_offset_index != -1.  */
     273                 :          10 :       if (i == (unsigned) base_offset_index)
     274                 :             :         {
     275                 :           4 :           start_sequence ();
     276                 :             : 
     277                 :           8 :           rtx base_reg = lowpart_subreg (GET_MODE (dest), it->mov_reg,
     278                 :           4 :                                          GET_MODE (it->mov_reg));
     279                 :             : 
     280                 :           4 :           if (base_reg)
     281                 :             :             {
     282                 :           4 :               rtx_insn *move0 = emit_move_insn (dest, base_reg);
     283                 :           4 :               if (recog_memoized (move0) >= 0)
     284                 :             :                 {
     285                 :           4 :                   insns = get_insns ();
     286                 :           4 :                   move_to_front = (int) i;
     287                 :             :                 }
     288                 :             :             }
     289                 :             : 
     290                 :           4 :           end_sequence ();
     291                 :             :         }
     292                 :             : 
     293                 :           4 :       if (!insns)
     294                 :           6 :         insns = generate_bit_insert_sequence (&(*it), dest);
     295                 :             : 
     296                 :           6 :       if (!insns)
     297                 :             :         {
     298                 :           0 :           if (dump_file)
     299                 :             :             {
     300                 :           0 :               fprintf (dump_file, "Failed due to: ");
     301                 :           0 :               print_rtl_single (dump_file, it->store_insn);
     302                 :             :             }
     303                 :           0 :           return false;
     304                 :             :         }
     305                 :             : 
     306                 :          10 :       total_cost += seq_cost (insns, true);
     307                 :          10 :       it->bits_insert_insns = insns;
     308                 :             : 
     309                 :          10 :       rtx store_set = single_set (it->store_insn);
     310                 :             : 
     311                 :             :       /* Create a register move at the store's original position to save the
     312                 :             :          stored value.  */
     313                 :          10 :       start_sequence ();
     314                 :          10 :       rtx_insn *insn1
     315                 :          10 :         = emit_insn (gen_rtx_SET (it->mov_reg, SET_SRC (store_set)));
     316                 :          10 :       end_sequence ();
     317                 :             : 
     318                 :          10 :       if (recog_memoized (insn1) < 0)
     319                 :             :         {
     320                 :           0 :           if (dump_file)
     321                 :             :             {
     322                 :           0 :               fprintf (dump_file, "Failed due to unrecognizable insn: ");
     323                 :           0 :               print_rtl_single (dump_file, insn1);
     324                 :             :             }
     325                 :           0 :           return false;
     326                 :             :         }
     327                 :             : 
     328                 :          10 :       it->save_store_value_insn = insn1;
     329                 :             : 
     330                 :             :       /* Create a new store after the load with the saved original value.
     331                 :             :          This avoids the forwarding stall.  */
     332                 :          10 :       start_sequence ();
     333                 :          10 :       rtx_insn *insn2
     334                 :          10 :         = emit_insn (gen_rtx_SET (SET_DEST (store_set), it->mov_reg));
     335                 :          10 :       end_sequence ();
     336                 :             : 
     337                 :          10 :       if (recog_memoized (insn2) < 0)
     338                 :             :         {
     339                 :           0 :           if (dump_file)
     340                 :             :             {
     341                 :           0 :               fprintf (dump_file, "Failed due to unrecognizable insn: ");
     342                 :           0 :               print_rtl_single (dump_file, insn2);
     343                 :             :             }
     344                 :           0 :           return false;
     345                 :             :         }
     346                 :             : 
     347                 :          10 :       it->store_saved_value_insn = insn2;
     348                 :             :     }
     349                 :             : 
     350                 :           8 :   if (load_elim)
     351                 :           4 :     total_cost -= insn_cost (load_insn, true);
     352                 :             : 
     353                 :             :   /* Let the target decide if transforming this store forwarding instance is
     354                 :             :      profitable.  */
     355                 :           8 :   if (!targetm.avoid_store_forwarding_p (stores, load_mem, total_cost,
     356                 :             :                                          load_elim))
     357                 :             :     {
     358                 :           1 :       if (dump_file)
     359                 :           0 :         fprintf (dump_file, "Not transformed due to target decision.\n");
     360                 :             : 
     361                 :           1 :       return false;
     362                 :             :     }
     363                 :             : 
     364                 :             :   /* If we have a move instead of bit insert, it needs to be emitted first in
     365                 :             :      the resulting sequence.  */
     366                 :           7 :   if (move_to_front != -1)
     367                 :             :     {
     368                 :           4 :       store_fwd_info copy = stores[move_to_front];
     369                 :           4 :       stores.safe_push (copy);
     370                 :           4 :       stores.ordered_remove (move_to_front);
     371                 :             :     }
     372                 :             : 
     373                 :           7 :   if (load_elim)
     374                 :             :     {
     375                 :           4 :       machine_mode outer_mode = GET_MODE (SET_DEST (load));
     376                 :           4 :       rtx load_move;
     377                 :           4 :       rtx load_value = dest;
     378                 :           4 :       if (outer_mode != load_mem_mode)
     379                 :             :         {
     380                 :           0 :           load_value = simplify_gen_unary (GET_CODE (SET_SRC (load)),
     381                 :             :                                            outer_mode, dest, load_mem_mode);
     382                 :             :         }
     383                 :           4 :       load_move = gen_rtx_SET (SET_DEST (load), load_value);
     384                 :             : 
     385                 :           4 :       start_sequence ();
     386                 :           4 :       rtx_insn *insn = emit_insn (load_move);
     387                 :           4 :       rtx_insn *seq = end_sequence ();
     388                 :             : 
     389                 :           4 :       if (recog_memoized (insn) < 0)
     390                 :             :         return false;
     391                 :             : 
     392                 :           4 :       emit_insn_after (seq, load_insn);
     393                 :             :     }
     394                 :             : 
     395                 :           7 :   if (dump_file)
     396                 :             :     {
     397                 :           0 :       fprintf (dump_file, "Store forwarding avoided with bit inserts:\n");
     398                 :             : 
     399                 :           0 :       FOR_EACH_VEC_ELT (stores, i, it)
     400                 :             :         {
     401                 :           0 :           if (stores.length () > 1)
     402                 :             :             {
     403                 :           0 :               fprintf (dump_file, "For: ");
     404                 :           0 :               print_rtl_single (dump_file, it->store_insn);
     405                 :             :             }
     406                 :             : 
     407                 :           0 :           fprintf (dump_file, "With sequence:\n");
     408                 :             : 
     409                 :           0 :           for (rtx_insn *insn = it->bits_insert_insns; insn;
     410                 :           0 :                insn = NEXT_INSN (insn))
     411                 :             :             {
     412                 :           0 :               fprintf (dump_file, "  ");
     413                 :           0 :               print_rtl_single (dump_file, insn);
     414                 :             :             }
     415                 :             :         }
     416                 :             : 
     417                 :           0 :       if (redundant_stores.length () > 0)
     418                 :             :         {
     419                 :           0 :           fprintf (dump_file, "\nRedundant stores that have been removed:\n");
     420                 :           0 :           FOR_EACH_VEC_ELT (redundant_stores, i, it)
     421                 :             :             {
     422                 :           0 :               fprintf (dump_file, "  ");
     423                 :           0 :               print_rtl_single (dump_file, it->store_insn);
     424                 :             :             }
     425                 :             :         }
     426                 :             :     }
     427                 :             : 
     428                 :           7 :   stats_sf_avoided++;
     429                 :             : 
     430                 :             :   /* Done, emit all the generated instructions and delete the stores.
     431                 :             :      Note that STORES are in reverse program order.  */
     432                 :             : 
     433                 :          16 :   FOR_EACH_VEC_ELT (stores, i, it)
     434                 :             :     {
     435                 :           9 :       emit_insn_after (it->bits_insert_insns, load_insn);
     436                 :           9 :       emit_insn_after (it->store_saved_value_insn, load_insn);
     437                 :             :     }
     438                 :             : 
     439                 :          16 :   FOR_EACH_VEC_ELT (stores, i, it)
     440                 :             :     {
     441                 :           9 :       emit_insn_before (it->save_store_value_insn, it->store_insn);
     442                 :           9 :       delete_insn (it->store_insn);
     443                 :             :     }
     444                 :             : 
     445                 :             :   /* Delete redundant stores.  */
     446                 :           7 :   FOR_EACH_VEC_ELT (redundant_stores, i, it)
     447                 :           0 :     delete_insn (it->store_insn);
     448                 :             : 
     449                 :           7 :   df_insn_rescan (load_insn);
     450                 :             : 
     451                 :           7 :   if (load_elim)
     452                 :           4 :     delete_insn (load_insn);
     453                 :             : 
     454                 :             :   return true;
     455                 :           8 : }
     456                 :             : 
     457                 :             : /* Try to modify BB so that expensive store forwarding cases are avoided.  */
     458                 :             : 
     459                 :             : void
     460                 :          64 : store_forwarding_analyzer::avoid_store_forwarding (basic_block bb)
     461                 :             : {
     462                 :          64 :   if (!optimize_bb_for_speed_p (bb))
     463                 :          25 :     return;
     464                 :             : 
     465                 :          52 :   auto_vec<store_fwd_info, 8> store_exprs;
     466                 :          52 :   auto_vec<rtx> store_exprs_del;
     467                 :          52 :   rtx_insn *insn;
     468                 :          52 :   unsigned int insn_cnt = 0;
     469                 :             : 
     470                 :             :   /* We are iterating over the basic block's instructions detecting store
     471                 :             :      instructions.  Upon reaching a load instruction, we check if any of the
     472                 :             :      previously detected stores could result in store forwarding.  In that
     473                 :             :      case, we try to reorder the load and store instructions.
     474                 :             :      We skip this transformation when we encounter complex memory operations,
     475                 :             :      instructions that might throw an exception, instruction dependencies,
     476                 :             :      etc.  This is done by clearing the vector of detected stores, while
     477                 :             :      keeping the removed stores in another vector.  By doing so, we can check
     478                 :             :      if any of the removed stores operated on the load's address range, when
     479                 :             :      reaching a subsequent store that operates on the same address range,
     480                 :             :      as this would lead to incorrect values on the register that keeps the
     481                 :             :      loaded value.  */
     482                 :         556 :   FOR_BB_INSNS (bb, insn)
     483                 :             :     {
     484                 :         517 :       if (!NONDEBUG_INSN_P (insn))
     485                 :         147 :         continue;
     486                 :             : 
     487                 :         410 :       vec_rtx_properties properties;
     488                 :         410 :       properties.add_insn (insn, false);
     489                 :             : 
     490                 :         410 :       rtx set = single_set (insn);
     491                 :             : 
     492                 :         410 :       if (!set || insn_could_throw_p (insn))
     493                 :             :         {
     494                 :             :           unsigned int i;
     495                 :             :           store_fwd_info *it;
     496                 :          71 :           FOR_EACH_VEC_ELT (store_exprs, i, it)
     497                 :          31 :             store_exprs_del.safe_push (it->store_mem);
     498                 :          40 :           store_exprs.truncate (0);
     499                 :          40 :           continue;
     500                 :          40 :         }
     501                 :             : 
     502                 :             :       /* The inner mem RTX if INSN is a load, NULL_RTX otherwise.  */
     503                 :         370 :       rtx load_mem = SET_SRC (set);
     504                 :             : 
     505                 :         370 :       if (GET_CODE (load_mem) == ZERO_EXTEND
     506                 :         370 :           || GET_CODE (load_mem) == SIGN_EXTEND)
     507                 :          12 :         load_mem = XEXP (load_mem, 0);
     508                 :             : 
     509                 :         370 :       if (!MEM_P (load_mem))
     510                 :         317 :         load_mem = NULL_RTX;
     511                 :             : 
     512                 :             :       /* The mem RTX if INSN is a store, NULL_RTX otherwise.  */
     513                 :         370 :       rtx store_mem = MEM_P (SET_DEST (set)) ? SET_DEST (set) : NULL_RTX;
     514                 :             : 
     515                 :             :       /* We cannot analyze memory RTXs that have unknown size.  */
     516                 :         194 :       if ((store_mem && (!MEM_SIZE_KNOWN_P (store_mem)
     517                 :             :                          || !MEM_SIZE (store_mem).is_constant ()))
     518                 :         423 :           || (load_mem && (!MEM_SIZE_KNOWN_P (load_mem)
     519                 :             :                            || !MEM_SIZE (load_mem).is_constant ())))
     520                 :             :         {
     521                 :             :           unsigned int i;
     522                 :             :           store_fwd_info *it;
     523                 :           0 :           FOR_EACH_VEC_ELT (store_exprs, i, it)
     524                 :           0 :             store_exprs_del.safe_push (it->store_mem);
     525                 :           0 :           store_exprs.truncate (0);
     526                 :           0 :           continue;
     527                 :           0 :         }
     528                 :             : 
     529                 :         370 :       bool is_simple = !properties.has_asm
     530                 :         370 :                        && !properties.has_side_effects ();
     531                 :         370 :       bool is_simple_store = is_simple
     532                 :         370 :                              && store_mem
     533                 :         370 :                              && !contains_mem_rtx_p (SET_SRC (set));
     534                 :         370 :       bool is_simple_load = is_simple
     535                 :         370 :                             && load_mem
     536                 :         370 :                             && !contains_mem_rtx_p (SET_DEST (set));
     537                 :             : 
     538                 :         370 :       int removed_count = 0;
     539                 :             : 
     540                 :         370 :       if (is_simple_store)
     541                 :             :         {
     542                 :             :           /* Record store forwarding candidate.  */
     543                 :         162 :           store_fwd_info info;
     544                 :         162 :           info.store_insn = insn;
     545                 :         162 :           info.store_mem = store_mem;
     546                 :         162 :           info.insn_cnt = insn_cnt;
     547                 :         162 :           info.remove = false;
     548                 :         162 :           info.forwarded = false;
     549                 :         162 :           store_exprs.safe_push (info);
     550                 :             :         }
     551                 :             : 
     552                 :         370 :       bool reads_mem = false;
     553                 :         370 :       bool writes_mem = false;
     554                 :        1291 :       for (auto ref : properties.refs ())
     555                 :         921 :         if (ref.is_mem ())
     556                 :             :           {
     557                 :         225 :             reads_mem |= ref.is_read ();
     558                 :         225 :             writes_mem |= ref.is_write ();
     559                 :             :           }
     560                 :         696 :         else if (ref.is_write ())
     561                 :             :           {
     562                 :             :             /* Drop store forwarding candidates when the address register is
     563                 :             :                overwritten.  */
     564                 :         215 :             bool remove_rest = false;
     565                 :         215 :             unsigned int i;
     566                 :         215 :             store_fwd_info *it;
     567                 :        1683 :             FOR_EACH_VEC_ELT_REVERSE (store_exprs, i, it)
     568                 :             :               {
     569                 :         332 :                 if (remove_rest
     570                 :         664 :                     || reg_overlap_mentioned_p (regno_reg_rtx[ref.regno],
     571                 :         332 :                                                 it->store_mem))
     572                 :             :                   {
     573                 :           0 :                     it->remove = true;
     574                 :           0 :                     removed_count++;
     575                 :           0 :                     remove_rest = true;
     576                 :           0 :                     store_exprs_del.safe_push (it->store_mem);
     577                 :             :                   }
     578                 :             :               }
     579                 :             :           }
     580                 :             : 
     581                 :         370 :       if (is_simple_load)
     582                 :             :         {
     583                 :             :           /* Process load for possible store forwarding cases.
     584                 :             :              Possible newly created/moved stores, resulted from a successful
     585                 :             :              forwarding, will be processed in subsequent iterations.  */
     586                 :          49 :           auto_vec<store_fwd_info> forwardings;
     587                 :          49 :           bool partial_forwarding = false;
     588                 :          49 :           bool remove_rest = false;
     589                 :             : 
     590                 :          49 :           bool vector_load = VECTOR_MODE_P (GET_MODE (load_mem));
     591                 :             : 
     592                 :          49 :           unsigned int i;
     593                 :          49 :           store_fwd_info *it;
     594                 :         171 :           FOR_EACH_VEC_ELT_REVERSE (store_exprs, i, it)
     595                 :             :             {
     596                 :          73 :               rtx store_mem = it->store_mem;
     597                 :          73 :               HOST_WIDE_INT off_val;
     598                 :             : 
     599                 :          73 :               bool vector_store = VECTOR_MODE_P (GET_MODE (store_mem));
     600                 :             : 
     601                 :          73 :               if (remove_rest)
     602                 :             :                 {
     603                 :           9 :                   it->remove = true;
     604                 :           9 :                   removed_count++;
     605                 :             :                 }
     606                 :          64 :               else if (vector_load ^ vector_store)
     607                 :             :                 {
     608                 :             :                   /* Vector stores followed by a non-vector load or the
     609                 :             :                      opposite, cause store_bit_field to generate non-canonical
     610                 :             :                      expressions, like (subreg:V4SI (reg:DI ...) 0)).
     611                 :             :                      Cases like that should be handled using vec_duplicate,
     612                 :             :                      so we reject the transformation in those cases.  */
     613                 :           1 :                   it->remove = true;
     614                 :           1 :                   removed_count++;
     615                 :           1 :                   remove_rest = true;
     616                 :           1 :                   forwardings.truncate (0);
     617                 :             :                 }
     618                 :          63 :               else if (is_store_forwarding (store_mem, load_mem, &off_val))
     619                 :             :                 {
     620                 :             :                   unsigned int j;
     621                 :             :                   rtx *del_it;
     622                 :             :                   bool same_range_as_removed = false;
     623                 :             : 
     624                 :             :                   /* Check if another store in the load's address range has
     625                 :             :                      been deleted due to a constraint violation.  In this case
     626                 :             :                      we can't forward any other stores that operate in this
     627                 :             :                      range, as it would lead to partial update of the register
     628                 :             :                      that holds the loaded value.  */
     629                 :          17 :                   FOR_EACH_VEC_ELT (store_exprs_del, j, del_it)
     630                 :             :                     {
     631                 :           5 :                       rtx del_store_mem = *del_it;
     632                 :           5 :                       same_range_as_removed
     633                 :           5 :                         = is_store_forwarding (del_store_mem, load_mem, NULL);
     634                 :           5 :                       if (same_range_as_removed)
     635                 :             :                         break;
     636                 :             :                     }
     637                 :             : 
     638                 :             :                   /* Check if moving this store after the load is legal.  */
     639                 :          13 :                   bool write_dep = false;
     640                 :          13 :                   if (!same_range_as_removed)
     641                 :             :                     {
     642                 :          12 :                       unsigned int j = store_exprs.length () - 1;
     643                 :          21 :                       for (; j != i; j--)
     644                 :             :                         {
     645                 :           9 :                           if (!store_exprs[j].forwarded
     646                 :          16 :                               && output_dependence (store_mem,
     647                 :           7 :                                                     store_exprs[j].store_mem))
     648                 :             :                             {
     649                 :             :                               write_dep = true;
     650                 :             :                               break;
     651                 :             :                             }
     652                 :             :                         }
     653                 :             :                     }
     654                 :             : 
     655                 :          12 :                   if (!same_range_as_removed && !write_dep)
     656                 :             :                     {
     657                 :          12 :                       it->forwarded = true;
     658                 :          12 :                       it->offset = off_val;
     659                 :          12 :                       forwardings.safe_push (*it);
     660                 :             :                     }
     661                 :             :                   else
     662                 :             :                     partial_forwarding = true;
     663                 :             : 
     664                 :          13 :                   it->remove = true;
     665                 :          13 :                   removed_count++;
     666                 :             :                 }
     667                 :          50 :               else if (true_dependence (store_mem, GET_MODE (store_mem),
     668                 :             :                                         load_mem))
     669                 :             :                 {
     670                 :             :                   /* We cannot keep a store forwarding candidate if it possibly
     671                 :             :                      interferes with this load.  */
     672                 :           2 :                   it->remove = true;
     673                 :           2 :                   removed_count++;
     674                 :           2 :                   remove_rest = true;
     675                 :           2 :                   forwardings.truncate (0);
     676                 :             :                 }
     677                 :             :             }
     678                 :             : 
     679                 :          67 :           if (!forwardings.is_empty () && !partial_forwarding)
     680                 :           8 :             process_store_forwarding (forwardings, insn, load_mem);
     681                 :          49 :         }
     682                 :             : 
     683                 :             :         /* Abort in case that we encounter a memory read/write that is not a
     684                 :             :            simple store/load, as we can't make safe assumptions about the
     685                 :             :            side-effects of this.  */
     686                 :         370 :         if ((writes_mem && !is_simple_store)
     687                 :         367 :              || (reads_mem && !is_simple_load))
     688                 :          13 :           return;
     689                 :             : 
     690                 :         357 :         if (removed_count)
     691                 :             :         {
     692                 :          12 :           unsigned int i, j;
     693                 :          12 :           store_fwd_info *it;
     694                 :          47 :           VEC_ORDERED_REMOVE_IF (store_exprs, i, j, it, it->remove);
     695                 :             :         }
     696                 :             : 
     697                 :             :         /* Don't consider store forwarding if the RTL instruction distance is
     698                 :             :            more than PARAM_STORE_FORWARDING_MAX_DISTANCE and the cost checks
     699                 :             :            are not disabled.  */
     700                 :         357 :         const bool unlimited_cost = (param_store_forwarding_max_distance == 0);
     701                 :         226 :         if (!unlimited_cost && !store_exprs.is_empty ()
     702                 :         357 :             && (store_exprs[0].insn_cnt
     703                 :         226 :                 + param_store_forwarding_max_distance <= insn_cnt))
     704                 :          64 :           store_exprs.ordered_remove (0);
     705                 :             : 
     706                 :         357 :         insn_cnt++;
     707                 :         410 :     }
     708                 :          52 : }
     709                 :             : 
     710                 :             : /* Update pass statistics.  */
     711                 :             : 
     712                 :             : void
     713                 :          22 : store_forwarding_analyzer::update_stats (function *fn)
     714                 :             : {
     715                 :          22 :   statistics_counter_event (fn, "Cases of store forwarding detected: ",
     716                 :          22 :                             stats_sf_detected);
     717                 :          22 :   statistics_counter_event (fn, "Cases of store forwarding avoided: ",
     718                 :          22 :                             stats_sf_detected);
     719                 :          22 : }
     720                 :             : 
     721                 :             : unsigned int
     722                 :          22 : pass_rtl_avoid_store_forwarding::execute (function *fn)
     723                 :             : {
     724                 :          22 :   df_set_flags (DF_DEFER_INSN_RESCAN);
     725                 :             : 
     726                 :          22 :   init_alias_analysis ();
     727                 :             : 
     728                 :          22 :   store_forwarding_analyzer analyzer;
     729                 :             : 
     730                 :          22 :   basic_block bb;
     731                 :          86 :   FOR_EACH_BB_FN (bb, fn)
     732                 :          64 :     analyzer.avoid_store_forwarding (bb);
     733                 :             : 
     734                 :          22 :   end_alias_analysis ();
     735                 :             : 
     736                 :          22 :   analyzer.update_stats (fn);
     737                 :             : 
     738                 :          22 :   return 0;
     739                 :             : }
     740                 :             : 
     741                 :             : } // anon namespace.
     742                 :             : 
     743                 :             : rtl_opt_pass *
     744                 :      285689 : make_pass_rtl_avoid_store_forwarding (gcc::context *ctxt)
     745                 :             : {
     746                 :      285689 :   return new pass_rtl_avoid_store_forwarding (ctxt);
     747                 :             : }
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.