LCOV - code coverage report
Current view: top level - gcc - store-motion.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.6 % 516 483
Test Date: 2024-04-13 14:00:49 Functions: 96.4 % 28 27
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

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

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.