LCOV - code coverage report
Current view: top level - gcc - fold-mem-offsets.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.3 % 330 288
Test Date: 2025-03-15 13:07:15 Functions: 100.0 % 14 14
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Late RTL pass to fold memory offsets.
       2                 :             :    Copyright (C) 2023-2025 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
       7                 :             : it under the terms of the GNU General Public License as published by
       8                 :             : the Free Software Foundation; either version 3, or (at your option)
       9                 :             : any later version.
      10                 :             : 
      11                 :             : GCC is distributed in the hope that it will be useful,
      12                 :             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :             : GNU General Public License 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 "tm.h"
      24                 :             : #include "rtl.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "expr.h"
      27                 :             : #include "backend.h"
      28                 :             : #include "regs.h"
      29                 :             : #include "target.h"
      30                 :             : #include "memmodel.h"
      31                 :             : #include "emit-rtl.h"
      32                 :             : #include "insn-config.h"
      33                 :             : #include "recog.h"
      34                 :             : #include "predict.h"
      35                 :             : #include "df.h"
      36                 :             : #include "tree-pass.h"
      37                 :             : #include "cfgrtl.h"
      38                 :             : #include "diagnostic-core.h"
      39                 :             : 
      40                 :             : /* This pass tries to optimize memory offset calculations by moving constants
      41                 :             :    from add instructions to the memory instructions (loads / stores).
      42                 :             :    For example it can transform code like this:
      43                 :             : 
      44                 :             :      add  t4, sp, 16
      45                 :             :      add  t2, a6, t4
      46                 :             :      shl  t3, t2, 1
      47                 :             :      ld   a2, 0(t3)
      48                 :             :      add  a2, 1
      49                 :             :      sd   a2, 8(t2)
      50                 :             : 
      51                 :             :    into the following (one instruction less):
      52                 :             : 
      53                 :             :      add  t2, a6, sp
      54                 :             :      shl  t3, t2, 1
      55                 :             :      ld   a2, 32(t3)
      56                 :             :      add  a2, 1
      57                 :             :      sd   a2, 24(t2)
      58                 :             : 
      59                 :             :    Although the previous passes try to emit efficient offset calculations
      60                 :             :    this pass is still beneficial because:
      61                 :             : 
      62                 :             :     - The mechanisms that optimize memory offsets usually work with specific
      63                 :             :       patterns or have limitations.  This pass is designed to fold offsets
      64                 :             :       through complex calculations that affect multiple memory operations
      65                 :             :       and have partially overlapping calculations.
      66                 :             : 
      67                 :             :     - There are cases where add instructions are introduced in late rtl passes
      68                 :             :       and the rest of the pipeline cannot eliminate them.  Arrays and structs
      69                 :             :       allocated on the stack can result in unwanted add instructions that
      70                 :             :       cannot be eliminated easily.
      71                 :             : 
      72                 :             :    This pass works on a basic block level and consists of 4 phases:
      73                 :             : 
      74                 :             :     - Phase 1 (Analysis): Find "foldable" instructions.
      75                 :             :       Foldable instructions are those that we know how to propagate
      76                 :             :       a constant addition through (add, shift, move, ...) and only have other
      77                 :             :       foldable instructions for uses.  In that phase a DFS traversal on the
      78                 :             :       definition tree is performed and foldable instructions are marked on
      79                 :             :       a bitmap.  The add immediate instructions that are reachable in this
      80                 :             :       DFS are candidates for folding since all the intermediate calculations
      81                 :             :       affected by them are also foldable.
      82                 :             : 
      83                 :             :     - Phase 2 (Validity): Traverse and calculate the offsets that would result
      84                 :             :       from folding the add immediate instructions.  Check whether the
      85                 :             :       calculated offsets result in a valid instruction for the target.
      86                 :             : 
      87                 :             :     - Phase 3 (Commit offsets): Traverse again.  It is now known which folds
      88                 :             :       are valid so at this point change the offsets in the memory instructions.
      89                 :             : 
      90                 :             :     - Phase 4 (Commit instruction deletions): Scan all instructions and delete
      91                 :             :       or simplify (reduce to move) all add immediate instructions that were
      92                 :             :       folded.
      93                 :             : 
      94                 :             :    This pass should run before hard register propagation because it creates
      95                 :             :    register moves that we expect to be eliminated.  */
      96                 :             : 
      97                 :             : namespace {
      98                 :             : 
      99                 :             : const pass_data pass_data_fold_mem =
     100                 :             : {
     101                 :             :   RTL_PASS, /* type */
     102                 :             :   "fold_mem_offsets", /* name */
     103                 :             :   OPTGROUP_NONE, /* optinfo_flags */
     104                 :             :   TV_FOLD_MEM_OFFSETS, /* tv_id */
     105                 :             :   0, /* properties_required */
     106                 :             :   0, /* properties_provided */
     107                 :             :   0, /* properties_destroyed */
     108                 :             :   0, /* todo_flags_start */
     109                 :             :   TODO_df_finish, /* todo_flags_finish */
     110                 :             : };
     111                 :             : 
     112                 :             : class pass_fold_mem_offsets : public rtl_opt_pass
     113                 :             : {
     114                 :             : public:
     115                 :      282866 :   pass_fold_mem_offsets (gcc::context *ctxt)
     116                 :      565732 :     : rtl_opt_pass (pass_data_fold_mem, ctxt)
     117                 :             :   {}
     118                 :             : 
     119                 :             :   /* opt_pass methods: */
     120                 :     1431630 :   virtual bool gate (function *)
     121                 :             :     {
     122                 :     1431630 :       return flag_fold_mem_offsets && optimize >= 2;
     123                 :             :     }
     124                 :             : 
     125                 :             :   virtual unsigned int execute (function *);
     126                 :             : }; // class pass_fold_mem_offsets
     127                 :             : 
     128                 :             : /* Class that holds in FOLD_INSNS the instructions that if folded the offset
     129                 :             :    of a memory instruction would increase by ADDED_OFFSET.  */
     130                 :    11773256 : class fold_mem_info {
     131                 :             : public:
     132                 :             :   auto_bitmap fold_insns;
     133                 :             :   HOST_WIDE_INT added_offset;
     134                 :             : };
     135                 :             : 
     136                 :             : typedef hash_map<rtx_insn *, fold_mem_info *> fold_info_map;
     137                 :             : 
     138                 :             : /* Tracks which instructions can be reached through instructions that can
     139                 :             :    propagate offsets for folding.  */
     140                 :             : static bitmap_head can_fold_insns;
     141                 :             : 
     142                 :             : /* Marks instructions that are currently eligible for folding.  */
     143                 :             : static bitmap_head candidate_fold_insns;
     144                 :             : 
     145                 :             : /* Tracks instructions that cannot be folded because it turned out that
     146                 :             :    folding will result in creating an invalid memory instruction.
     147                 :             :    An instruction can be in both CANDIDATE_FOLD_INSNS and CANNOT_FOLD_INSNS
     148                 :             :    at the same time, in which case it is not legal to fold.  */
     149                 :             : static bitmap_head cannot_fold_insns;
     150                 :             : 
     151                 :             : /* The number of instructions that were simplified or eliminated.  */
     152                 :             : static int stats_fold_count;
     153                 :             : 
     154                 :             : /* Get the single reaching definition of an instruction inside a BB.
     155                 :             :    The definition is desired for REG used in INSN.
     156                 :             :    Return the definition insn or NULL if there's no definition with
     157                 :             :    the desired criteria.  */
     158                 :             : static rtx_insn *
     159                 :    23649950 : get_single_def_in_bb (rtx_insn *insn, rtx reg)
     160                 :             : {
     161                 :    23649950 :   df_ref use;
     162                 :    23649950 :   struct df_link *ref_chain, *ref_link;
     163                 :             : 
     164                 :    28429628 :   FOR_EACH_INSN_USE (use, insn)
     165                 :             :     {
     166                 :    28429628 :       if (GET_CODE (DF_REF_REG (use)) == SUBREG)
     167                 :             :         return NULL;
     168                 :    28429628 :       if (REGNO (DF_REF_REG (use)) == REGNO (reg))
     169                 :             :         break;
     170                 :             :     }
     171                 :             : 
     172                 :    23649950 :   if (!use)
     173                 :             :     return NULL;
     174                 :             : 
     175                 :    23649950 :   ref_chain = DF_REF_CHAIN (use);
     176                 :             : 
     177                 :    23649950 :   if (!ref_chain)
     178                 :             :     return NULL;
     179                 :             : 
     180                 :    52788598 :   for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
     181                 :             :     {
     182                 :             :       /* Problem getting some definition for this instruction.  */
     183                 :    30106115 :       if (ref_link->ref == NULL)
     184                 :             :         return NULL;
     185                 :    30106115 :       if (DF_REF_INSN_INFO (ref_link->ref) == NULL)
     186                 :             :         return NULL;
     187                 :    29138852 :       if (global_regs[REGNO (reg)]
     188                 :    29138852 :           && !set_of (reg, DF_REF_INSN (ref_link->ref)))
     189                 :             :         return NULL;
     190                 :             :     }
     191                 :             : 
     192                 :    22682483 :   if (ref_chain->next)
     193                 :             :     return NULL;
     194                 :             : 
     195                 :    19951323 :   rtx_insn *def = DF_REF_INSN (ref_chain->ref);
     196                 :             : 
     197                 :    19951323 :   if (BLOCK_FOR_INSN (def) != BLOCK_FOR_INSN (insn))
     198                 :             :     return NULL;
     199                 :             : 
     200                 :     8043475 :   if (DF_INSN_LUID (def) > DF_INSN_LUID (insn))
     201                 :             :     return NULL;
     202                 :             : 
     203                 :             :   return def;
     204                 :             : }
     205                 :             : 
     206                 :             : /* Get all uses of REG which is set in INSN.  Return the use list or NULL if a
     207                 :             :    use is missing / irregular.  If SUCCESS is not NULL then set it to false if
     208                 :             :    there are missing / irregular uses and true otherwise.  */
     209                 :             : static df_link *
     210                 :      264913 : get_uses (rtx_insn *insn, rtx reg, bool *success)
     211                 :             : {
     212                 :      264913 :   df_ref def;
     213                 :             : 
     214                 :      264913 :   if (success)
     215                 :      264913 :     *success = false;
     216                 :             : 
     217                 :      264913 :   FOR_EACH_INSN_DEF (def, insn)
     218                 :      264913 :     if (REGNO (DF_REF_REG (def)) == REGNO (reg))
     219                 :             :       break;
     220                 :             : 
     221                 :      264913 :   if (!def)
     222                 :             :     return NULL;
     223                 :             : 
     224                 :      264913 :   df_link *ref_chain = DF_REF_CHAIN (def);
     225                 :      264913 :   int insn_luid = DF_INSN_LUID (insn);
     226                 :      264913 :   basic_block insn_bb = BLOCK_FOR_INSN (insn);
     227                 :             : 
     228                 :     1719766 :   for (df_link *ref_link = ref_chain; ref_link; ref_link = ref_link->next)
     229                 :             :     {
     230                 :             :       /* Problem getting a use for this instruction.  */
     231                 :     1615187 :       if (ref_link->ref == NULL)
     232                 :             :         return NULL;
     233                 :     1615187 :       if (DF_REF_CLASS (ref_link->ref) != DF_REF_REGULAR)
     234                 :             :         return NULL;
     235                 :             : 
     236                 :     1610651 :       rtx_insn *use = DF_REF_INSN (ref_link->ref);
     237                 :     1610651 :       if (DEBUG_INSN_P (use))
     238                 :      233193 :         continue;
     239                 :             : 
     240                 :             :       /* We do not handle REG_EQUIV/REG_EQ notes for now.  */
     241                 :     1377458 :       if (DF_REF_FLAGS (ref_link->ref) & DF_REF_IN_NOTE)
     242                 :             :         return NULL;
     243                 :     1325590 :       if (BLOCK_FOR_INSN (use) != insn_bb)
     244                 :             :         return NULL;
     245                 :             :       /* Punt if use appears before def in the basic block.  See PR111601.  */
     246                 :     1221686 :       if (DF_INSN_LUID (use) < insn_luid)
     247                 :             :         return NULL;
     248                 :             :     }
     249                 :             : 
     250                 :      104579 :   if (success)
     251                 :      104579 :     *success = true;
     252                 :             : 
     253                 :             :   return ref_chain;
     254                 :             : }
     255                 :             : 
     256                 :             : static HOST_WIDE_INT
     257                 :             : fold_offsets (rtx_insn *insn, rtx reg, bool analyze, bitmap foldable_insns);
     258                 :             : 
     259                 :             : /*  Helper function for fold_offsets.
     260                 :             : 
     261                 :             :     If DO_RECURSION is false and ANALYZE is true this function returns true iff
     262                 :             :     it understands the structure of INSN and knows how to propagate constants
     263                 :             :     through it.  In this case OFFSET_OUT and FOLDABLE_INSNS are unused.
     264                 :             : 
     265                 :             :     If DO_RECURSION is true then it also calls fold_offsets for each recognized
     266                 :             :     part of INSN with the appropriate arguments.
     267                 :             : 
     268                 :             :     If DO_RECURSION is true and ANALYZE is false then offset that would result
     269                 :             :     from folding is computed and is returned through the pointer OFFSET_OUT.
     270                 :             :     The instructions that can be folded are recorded in FOLDABLE_INSNS.  */
     271                 :             : static bool
     272                 :     1741913 : fold_offsets_1 (rtx_insn *insn, bool analyze, bool do_recursion,
     273                 :             :                 HOST_WIDE_INT *offset_out, bitmap foldable_insns)
     274                 :             : {
     275                 :             :   /* Doesn't make sense if both DO_RECURSION and ANALYZE are false.  */
     276                 :     1741913 :   gcc_checking_assert (do_recursion || analyze);
     277                 :     1741913 :   gcc_checking_assert (GET_CODE (PATTERN (insn)) == SET);
     278                 :             : 
     279                 :     1741913 :   rtx src = SET_SRC (PATTERN (insn));
     280                 :     1741913 :   HOST_WIDE_INT offset = 0;
     281                 :             : 
     282                 :     1741913 :   switch (GET_CODE (src))
     283                 :             :     {
     284                 :       81974 :     case PLUS:
     285                 :       81974 :       {
     286                 :             :         /* Propagate through add.  */
     287                 :       81974 :         rtx arg1 = XEXP (src, 0);
     288                 :       81974 :         rtx arg2 = XEXP (src, 1);
     289                 :             : 
     290                 :       81974 :         if (REG_P (arg1))
     291                 :             :           {
     292                 :       23739 :             if (do_recursion)
     293                 :        3258 :               offset += fold_offsets (insn, arg1, analyze, foldable_insns);
     294                 :             :           }
     295                 :       58235 :         else if (GET_CODE (arg1) == ASHIFT
     296                 :       45833 :                  && REG_P (XEXP (arg1, 0))
     297                 :       45833 :                  && CONST_INT_P (XEXP (arg1, 1)))
     298                 :             :           {
     299                 :             :             /* Handle R1 = (R2 << C) + ...  */
     300                 :       45833 :             if (do_recursion)
     301                 :             :               {
     302                 :       15263 :                 HOST_WIDE_INT scale
     303                 :       15263 :                   = (HOST_WIDE_INT_1U << INTVAL (XEXP (arg1, 1)));
     304                 :       15263 :                 offset += scale * fold_offsets (insn, XEXP (arg1, 0), analyze,
     305                 :             :                                                 foldable_insns);
     306                 :             :               }
     307                 :             :           }
     308                 :       12402 :         else if (GET_CODE (arg1) == PLUS
     309                 :       12344 :                  && REG_P (XEXP (arg1, 0))
     310                 :       10739 :                  && REG_P (XEXP (arg1, 1)))
     311                 :             :           {
     312                 :             :             /* Handle R1 = (R2 + R3) + ...  */
     313                 :       10739 :             if (do_recursion)
     314                 :             :               {
     315                 :        4499 :                 offset += fold_offsets (insn, XEXP (arg1, 0), analyze,
     316                 :             :                                         foldable_insns);
     317                 :        4499 :                 offset += fold_offsets (insn, XEXP (arg1, 1), analyze,
     318                 :             :                                         foldable_insns);
     319                 :             :               }
     320                 :             :           }
     321                 :        1663 :         else if (GET_CODE (arg1) == PLUS
     322                 :        1605 :                  && GET_CODE (XEXP (arg1, 0)) == ASHIFT
     323                 :        1601 :                  && REG_P (XEXP (XEXP (arg1, 0), 0))
     324                 :        1601 :                  && CONST_INT_P (XEXP (XEXP (arg1, 0), 1))
     325                 :        1601 :                  && REG_P (XEXP (arg1, 1)))
     326                 :             :           {
     327                 :             :             /* Handle R1 = ((R2 << C) + R3) + ...  */
     328                 :        1601 :             if (do_recursion)
     329                 :             :               {
     330                 :         569 :                 HOST_WIDE_INT scale
     331                 :         569 :                   = (HOST_WIDE_INT_1U << INTVAL (XEXP (XEXP (arg1, 0), 1)));
     332                 :         569 :                 offset += scale * fold_offsets (insn, XEXP (XEXP (arg1, 0), 0),
     333                 :             :                                                 analyze, foldable_insns);
     334                 :         569 :                 offset += fold_offsets (insn, XEXP (arg1, 1), analyze,
     335                 :             :                                         foldable_insns);
     336                 :             :               }
     337                 :             :           }
     338                 :             :         else
     339                 :             :           return false;
     340                 :             : 
     341                 :       81912 :         if (REG_P (arg2))
     342                 :             :           {
     343                 :       56498 :             if (do_recursion)
     344                 :       18129 :               offset += fold_offsets (insn, arg2, analyze, foldable_insns);
     345                 :             :           }
     346                 :       25414 :         else if (CONST_INT_P (arg2))
     347                 :             :           {
     348                 :       22860 :             if (REG_P (arg1))
     349                 :             :               {
     350                 :       11172 :                 offset += INTVAL (arg2);
     351                 :             :                 /* This is a R1 = R2 + C instruction, candidate for folding.  */
     352                 :       11172 :                 if (!analyze)
     353                 :         326 :                   bitmap_set_bit (foldable_insns, INSN_UID (insn));
     354                 :             :               }
     355                 :             :           }
     356                 :             :         else
     357                 :             :           return false;
     358                 :             : 
     359                 :             :         /* Pattern recognized for folding.  */
     360                 :             :         break;
     361                 :             :       }
     362                 :           0 :     case MINUS:
     363                 :           0 :       {
     364                 :             :         /* Propagate through minus.  */
     365                 :           0 :         rtx arg1 = XEXP (src, 0);
     366                 :           0 :         rtx arg2 = XEXP (src, 1);
     367                 :             : 
     368                 :           0 :         if (REG_P (arg1))
     369                 :             :           {
     370                 :           0 :             if (do_recursion)
     371                 :           0 :               offset += fold_offsets (insn, arg1, analyze, foldable_insns);
     372                 :             :           }
     373                 :             :         else
     374                 :             :           return false;
     375                 :             : 
     376                 :           0 :         if (REG_P (arg2))
     377                 :             :           {
     378                 :           0 :             if (do_recursion)
     379                 :           0 :               offset -= fold_offsets (insn, arg2, analyze, foldable_insns);
     380                 :             :           }
     381                 :           0 :         else if (CONST_INT_P (arg2))
     382                 :             :           {
     383                 :           0 :             if (REG_P (arg1))
     384                 :             :               {
     385                 :           0 :                 offset -= INTVAL (arg2);
     386                 :             :                 /* This is a R1 = R2 - C instruction, candidate for folding.  */
     387                 :           0 :                 if (!analyze)
     388                 :           0 :                   bitmap_set_bit (foldable_insns, INSN_UID (insn));
     389                 :             :               }
     390                 :             :           }
     391                 :             :         else
     392                 :             :           return false;
     393                 :             : 
     394                 :             :         /* Pattern recognized for folding.  */
     395                 :             :         break;
     396                 :             :       }
     397                 :           0 :     case NEG:
     398                 :           0 :       {
     399                 :             :         /* Propagate through negation.  */
     400                 :           0 :         rtx arg1 = XEXP (src, 0);
     401                 :           0 :         if (REG_P (arg1))
     402                 :             :           {
     403                 :           0 :             if (do_recursion)
     404                 :           0 :               offset = -fold_offsets (insn, arg1, analyze, foldable_insns);
     405                 :             :           }
     406                 :             :         else
     407                 :             :           return false;
     408                 :             : 
     409                 :             :         /* Pattern recognized for folding.  */
     410                 :             :         break;
     411                 :             :       }
     412                 :         152 :     case MULT:
     413                 :         152 :       {
     414                 :             :         /* Propagate through multiply by constant.  */
     415                 :         152 :         rtx arg1 = XEXP (src, 0);
     416                 :         152 :         rtx arg2 = XEXP (src, 1);
     417                 :             : 
     418                 :         152 :         if (REG_P (arg1) && CONST_INT_P (arg2))
     419                 :             :           {
     420                 :         152 :             if (do_recursion)
     421                 :             :               {
     422                 :           9 :                 HOST_WIDE_INT scale = INTVAL (arg2);
     423                 :           9 :                 offset = scale * fold_offsets (insn, arg1, analyze,
     424                 :             :                                                foldable_insns);
     425                 :             :               }
     426                 :             :           }
     427                 :             :         else
     428                 :             :           return false;
     429                 :             : 
     430                 :             :         /* Pattern recognized for folding.  */
     431                 :             :         break;
     432                 :             :       }
     433                 :           0 :     case ASHIFT:
     434                 :           0 :       {
     435                 :             :         /* Propagate through shift left by constant.  */
     436                 :           0 :         rtx arg1 = XEXP (src, 0);
     437                 :           0 :         rtx arg2 = XEXP (src, 1);
     438                 :             : 
     439                 :           0 :         if (REG_P (arg1) && CONST_INT_P (arg2))
     440                 :             :           {
     441                 :           0 :             if (do_recursion)
     442                 :             :               {
     443                 :           0 :                 HOST_WIDE_INT scale = (HOST_WIDE_INT_1U << INTVAL (arg2));
     444                 :           0 :                 offset = scale * fold_offsets (insn, arg1, analyze,
     445                 :             :                                                foldable_insns);
     446                 :             :               }
     447                 :             :           }
     448                 :             :         else
     449                 :             :           return false;
     450                 :             : 
     451                 :             :         /* Pattern recognized for folding.  */
     452                 :             :         break;
     453                 :             :       }
     454                 :      265635 :     case REG:
     455                 :      265635 :       {
     456                 :             :         /* Propagate through register move.  */
     457                 :      265635 :         if (do_recursion)
     458                 :       56643 :           offset = fold_offsets (insn, src, analyze, foldable_insns);
     459                 :             : 
     460                 :             :         /* Pattern recognized for folding.  */
     461                 :             :         break;
     462                 :             :       }
     463                 :          22 :     case CONST_INT:
     464                 :          22 :       {
     465                 :          22 :         offset = INTVAL (src);
     466                 :             :         /* R1 = C is candidate for folding.  */
     467                 :          22 :         if (!analyze)
     468                 :           7 :           bitmap_set_bit (foldable_insns, INSN_UID (insn));
     469                 :             : 
     470                 :             :         /* Pattern recognized for folding.  */
     471                 :             :         break;
     472                 :             :       }
     473                 :             :     default:
     474                 :             :       /* Cannot recognize.  */
     475                 :             :       return false;
     476                 :             :     }
     477                 :             : 
     478                 :      345167 :     if (do_recursion && !analyze)
     479                 :       50410 :       *offset_out = offset;
     480                 :             : 
     481                 :             :     return true;
     482                 :             : }
     483                 :             : 
     484                 :             : /* Function that computes the offset that would have to be added to all uses
     485                 :             :    of REG if the instructions marked in FOLDABLE_INSNS were to be eliminated.
     486                 :             : 
     487                 :             :    If ANALYZE is true then mark in CAN_FOLD_INSNS which instructions
     488                 :             :    transitively only affect other instructions found in CAN_FOLD_INSNS.
     489                 :             :    If ANALYZE is false then compute the offset required for folding.  */
     490                 :             : static HOST_WIDE_INT
     491                 :    23649950 : fold_offsets (rtx_insn *insn, rtx reg, bool analyze, bitmap foldable_insns)
     492                 :             : {
     493                 :    23649950 :   rtx_insn *def = get_single_def_in_bb (insn, reg);
     494                 :             : 
     495                 :    23649950 :   if (!def || RTX_FRAME_RELATED_P (def) || GET_CODE (PATTERN (def)) != SET)
     496                 :             :     return 0;
     497                 :             : 
     498                 :     3332202 :   rtx dest = SET_DEST (PATTERN (def));
     499                 :             : 
     500                 :     3332202 :   if (!REG_P (dest))
     501                 :             :     return 0;
     502                 :             : 
     503                 :             :   /* We can only affect the values of GPR registers.  */
     504                 :     2113762 :   unsigned int dest_regno = REGNO (dest);
     505                 :     2113762 :   if (fixed_regs[dest_regno]
     506                 :     2113762 :       || !TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], dest_regno))
     507                 :             :     return 0;
     508                 :             : 
     509                 :     2112383 :   if (analyze)
     510                 :             :     {
     511                 :             :       /* Check if we know how to handle DEF.  */
     512                 :     1051258 :       if (!fold_offsets_1 (def, true, false, NULL, NULL))
     513                 :     1021414 :         return 0;
     514                 :             : 
     515                 :             :       /* We only fold through instructions that are transitively used as
     516                 :             :          memory addresses and do not have other uses.  Use the same logic
     517                 :             :          from offset calculation to visit instructions that can propagate
     518                 :             :          offsets and keep track of them in CAN_FOLD_INSNS.  */
     519                 :      264913 :       bool success;
     520                 :      264913 :       struct df_link *uses = get_uses (def, dest, &success), *ref_link;
     521                 :             : 
     522                 :      264913 :       if (!success)
     523                 :             :         return 0;
     524                 :             : 
     525                 :      169897 :       for (ref_link = uses; ref_link; ref_link = ref_link->next)
     526                 :             :         {
     527                 :      140053 :           rtx_insn *use = DF_REF_INSN (ref_link->ref);
     528                 :             : 
     529                 :      140053 :           if (DEBUG_INSN_P (use))
     530                 :       10615 :             continue;
     531                 :             : 
     532                 :             :           /* Punt if the use is anything more complicated than a set
     533                 :             :              (clobber, use, etc).  */
     534                 :      129438 :           if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != SET)
     535                 :             :             return 0;
     536                 :             : 
     537                 :             :           /* This use affects instructions outside of CAN_FOLD_INSNS.  */
     538                 :      110299 :           if (!bitmap_bit_p (&can_fold_insns, INSN_UID (use)))
     539                 :             :             return 0;
     540                 :             : 
     541                 :       56126 :           rtx use_set = PATTERN (use);
     542                 :             : 
     543                 :             :           /* Special case: A foldable memory store is not foldable if it
     544                 :             :              mentions DEST outside of the address calculation.  */
     545                 :       56126 :           if (use_set && MEM_P (SET_DEST (use_set))
     546                 :       83863 :               && reg_mentioned_p (dest, SET_SRC (use_set)))
     547                 :             :             return 0;
     548                 :             :         }
     549                 :             : 
     550                 :       29844 :       bitmap_set_bit (&can_fold_insns, INSN_UID (def));
     551                 :             : 
     552                 :       29844 :       if (dump_file && (dump_flags & TDF_DETAILS))
     553                 :             :         {
     554                 :           0 :           fprintf (dump_file, "Instruction marked for propagation: ");
     555                 :           0 :           print_rtl_single (dump_file, def);
     556                 :             :         }
     557                 :             :     }
     558                 :             :   else
     559                 :             :     {
     560                 :             :       /* We cannot propagate through this instruction.  */
     561                 :     1061125 :       if (!bitmap_bit_p (&can_fold_insns, INSN_UID (def)))
     562                 :             :         return 0;
     563                 :             :     }
     564                 :             : 
     565                 :      690655 :   HOST_WIDE_INT offset = 0;
     566                 :      690655 :   bool recognized = fold_offsets_1 (def, analyze, true, &offset,
     567                 :             :                                     foldable_insns);
     568                 :             : 
     569                 :      690655 :   if (!recognized)
     570                 :             :     return 0;
     571                 :             : 
     572                 :       80254 :   return offset;
     573                 :             : }
     574                 :             : 
     575                 :             : /* Test if INSN is a memory load / store that can have an offset folded to it.
     576                 :             :    Return true iff INSN is such an instruction and return through MEM_OUT,
     577                 :             :    REG_OUT and OFFSET_OUT the RTX that has a MEM code, the register that is
     578                 :             :    used as a base address and the offset accordingly.
     579                 :             :    All of the out pointers may be NULL in which case they will be ignored.  */
     580                 :             : bool
     581                 :   228567924 : get_fold_mem_root (rtx_insn *insn, rtx *mem_out, rtx *reg_out,
     582                 :             :                    HOST_WIDE_INT *offset_out)
     583                 :             : {
     584                 :   228567924 :   rtx set = single_set (insn);
     585                 :   228567924 :   rtx mem = NULL_RTX;
     586                 :             : 
     587                 :   228567924 :   if (set != NULL_RTX)
     588                 :             :     {
     589                 :   111593192 :       rtx src = SET_SRC (set);
     590                 :   111593192 :       rtx dest = SET_DEST (set);
     591                 :             : 
     592                 :             :       /* Don't fold when we have unspec / volatile.  */
     593                 :   111593192 :       if (GET_CODE (src) == UNSPEC
     594                 :   111593192 :           || GET_CODE (src) == UNSPEC_VOLATILE
     595                 :   110914192 :           || GET_CODE (dest) == UNSPEC
     596                 :   110914192 :           || GET_CODE (dest) == UNSPEC_VOLATILE)
     597                 :             :         return false;
     598                 :             : 
     599                 :   110914192 :       if (MEM_P (src))
     600                 :             :         mem = src;
     601                 :    83141066 :       else if (MEM_P (dest))
     602                 :             :         mem = dest;
     603                 :    53874238 :       else if ((GET_CODE (src) == SIGN_EXTEND
     604                 :    53874238 :                 || GET_CODE (src) == ZERO_EXTEND)
     605                 :     1124682 :                && MEM_P (XEXP (src, 0)))
     606                 :             :         mem = XEXP (src, 0);
     607                 :             :     }
     608                 :             : 
     609                 :             :   if (mem == NULL_RTX)
     610                 :             :     return false;
     611                 :             : 
     612                 :    57497598 :   rtx mem_addr = XEXP (mem, 0);
     613                 :    57497598 :   rtx reg;
     614                 :    57497598 :   HOST_WIDE_INT offset;
     615                 :             : 
     616                 :    57497598 :   if (REG_P (mem_addr))
     617                 :             :     {
     618                 :             :       reg = mem_addr;
     619                 :             :       offset = 0;
     620                 :             :     }
     621                 :    49493078 :   else if (GET_CODE (mem_addr) == PLUS
     622                 :    40495166 :            && REG_P (XEXP (mem_addr, 0))
     623                 :    39627808 :            && CONST_INT_P (XEXP (mem_addr, 1)))
     624                 :             :     {
     625                 :    39088504 :       reg = XEXP (mem_addr, 0);
     626                 :    39088504 :       offset = INTVAL (XEXP (mem_addr, 1));
     627                 :             :     }
     628                 :             :   else
     629                 :             :     return false;
     630                 :             : 
     631                 :    47093024 :   if (mem_out)
     632                 :    35319768 :     *mem_out = mem;
     633                 :    47093024 :   if (reg_out)
     634                 :    47093024 :     *reg_out = reg;
     635                 :    47093024 :   if (offset_out)
     636                 :    35319768 :     *offset_out = offset;
     637                 :             : 
     638                 :             :   return true;
     639                 :             : }
     640                 :             : 
     641                 :             : /* If INSN is a root memory instruction then do a DFS traversal on its
     642                 :             :    definitions and find folding candidates.  */
     643                 :             : static void
     644                 :   102510706 : do_analysis (rtx_insn *insn)
     645                 :             : {
     646                 :   102510706 :   rtx reg;
     647                 :   102510706 :   if (!get_fold_mem_root (insn, NULL, &reg, NULL))
     648                 :    90737450 :     return;
     649                 :             : 
     650                 :    11773256 :   if (dump_file && (dump_flags & TDF_DETAILS))
     651                 :             :     {
     652                 :           0 :       fprintf (dump_file, "Starting analysis from root: ");
     653                 :           0 :       print_rtl_single (dump_file, insn);
     654                 :             :     }
     655                 :             : 
     656                 :             :   /* Analyse folding opportunities for this memory instruction.  */
     657                 :    11773256 :   bitmap_set_bit (&can_fold_insns, INSN_UID (insn));
     658                 :    11773256 :   fold_offsets (insn, reg, true, NULL);
     659                 :             : }
     660                 :             : 
     661                 :             : static void
     662                 :   102510706 : do_fold_info_calculation (rtx_insn *insn, fold_info_map *fold_info)
     663                 :             : {
     664                 :   102510706 :   rtx mem, reg;
     665                 :   102510706 :   HOST_WIDE_INT cur_offset;
     666                 :   102510706 :   if (!get_fold_mem_root (insn, &mem, &reg, &cur_offset))
     667                 :    90737450 :     return;
     668                 :             : 
     669                 :    11773256 :   fold_mem_info *info = new fold_mem_info;
     670                 :    11773256 :   info->added_offset = fold_offsets (insn, reg, false, info->fold_insns);
     671                 :             : 
     672                 :    11773256 :   fold_info->put (insn, info);
     673                 :             : }
     674                 :             : 
     675                 :             : /* If INSN is a root memory instruction then compute a potentially new offset
     676                 :             :    for it and test if the resulting instruction is valid.  */
     677                 :             : static void
     678                 :    11773256 : do_check_validity (rtx_insn *insn, fold_mem_info *info)
     679                 :             : {
     680                 :    11773256 :   rtx mem, reg;
     681                 :    11773256 :   HOST_WIDE_INT cur_offset;
     682                 :    11773256 :   if (!get_fold_mem_root (insn, &mem, &reg, &cur_offset))
     683                 :           0 :     return;
     684                 :             : 
     685                 :    11773256 :   HOST_WIDE_INT new_offset = cur_offset + info->added_offset;
     686                 :             : 
     687                 :             :   /* Test if it is valid to change MEM's address offset to NEW_OFFSET.  */
     688                 :    11773256 :   int icode = INSN_CODE (insn);
     689                 :    11773256 :   INSN_CODE (insn) = -1;
     690                 :    11773256 :   rtx mem_addr = XEXP (mem, 0);
     691                 :    11773256 :   machine_mode mode = GET_MODE (mem_addr);
     692                 :    11773256 :   if (new_offset != 0)
     693                 :     9772302 :     XEXP (mem, 0) = gen_rtx_PLUS (mode, reg, gen_int_mode (new_offset, mode));
     694                 :             :   else
     695                 :     2000954 :     XEXP (mem, 0) = reg;
     696                 :             : 
     697                 :    11773256 :   bool illegal = insn_invalid_p (insn, false)
     698                 :    23546506 :                  || !memory_address_addr_space_p (mode, XEXP (mem, 0),
     699                 :    11855154 :                                                   MEM_ADDR_SPACE (mem));
     700                 :             : 
     701                 :             :   /* Restore the instruction.  */
     702                 :    11773256 :   XEXP (mem, 0) = mem_addr;
     703                 :    11773256 :   INSN_CODE (insn) = icode;
     704                 :             : 
     705                 :    11773256 :   if (illegal)
     706                 :           6 :     bitmap_ior_into (&cannot_fold_insns, info->fold_insns);
     707                 :             :   else
     708                 :    11773250 :     bitmap_ior_into (&candidate_fold_insns, info->fold_insns);
     709                 :             : }
     710                 :             : 
     711                 :             : static bool
     712                 :     9613728 : compute_validity_closure (fold_info_map *fold_info)
     713                 :             : {
     714                 :             :   /* Let's say we have an arbitrary chain of foldable instructions xN = xN + C
     715                 :             :      and memory operations rN that use xN as shown below.  If folding x1 in r1
     716                 :             :      turns out to be invalid for whatever reason then it's also invalid to fold
     717                 :             :      any of the other xN into any rN.  That means that we need the transitive
     718                 :             :      closure of validity to determine whether we can fold a xN instruction.
     719                 :             : 
     720                 :             :      +--------------+    +-------------------+    +-------------------+
     721                 :             :      | r1 = mem[x1] |    | r2 = mem[x1 + x2] |    | r3 = mem[x2 + x3] |   ...
     722                 :             :      +--------------+    +-------------------+    +-------------------+
     723                 :             :             ^                ^       ^                ^       ^
     724                 :             :             |               /        |               /        |           ...
     725                 :             :             |              /         |              /         |
     726                 :             :      +-------------+      /   +-------------+      /   +-------------+
     727                 :             :      | x1 = x1 + 1 |-----+    | x2 = x2 + 1 |-----+    | x3 = x3 + 1 |--- ...
     728                 :             :      +-------------+          +-------------+          +-------------+
     729                 :             :             ^                        ^                        ^
     730                 :             :             |                        |                        |
     731                 :             :            ...                      ...                      ...
     732                 :             :   */
     733                 :             : 
     734                 :             :   /* In general three iterations should be enough for most cases, but allow up
     735                 :             :      to five when -fexpensive-optimizations is used.  */
     736                 :     9613728 :   int max_iters = 3 + 2 * flag_expensive_optimizations;
     737                 :     9613728 :   for (int pass = 0; pass < max_iters; pass++)
     738                 :             :     {
     739                 :     9613728 :       bool made_changes = false;
     740                 :    21386984 :       for (fold_info_map::iterator iter = fold_info->begin ();
     741                 :    33160240 :            iter != fold_info->end (); ++iter)
     742                 :             :         {
     743                 :    11773256 :           fold_mem_info *info = (*iter).second;
     744                 :    11773256 :           if (bitmap_intersect_p (&cannot_fold_insns, info->fold_insns))
     745                 :           6 :             made_changes |= bitmap_ior_into (&cannot_fold_insns,
     746                 :             :                                              info->fold_insns);
     747                 :             :         }
     748                 :             : 
     749                 :     9613728 :       if (!made_changes)
     750                 :             :         return true;
     751                 :             :     }
     752                 :             : 
     753                 :             :   return false;
     754                 :             : }
     755                 :             : 
     756                 :             : /* If INSN is a root memory instruction that was affected by any folding
     757                 :             :    then update its offset as necessary.  */
     758                 :             : static void
     759                 :    11773256 : do_commit_offset (rtx_insn *insn, fold_mem_info *info)
     760                 :             : {
     761                 :    11773256 :   rtx mem, reg;
     762                 :    11773256 :   HOST_WIDE_INT cur_offset;
     763                 :    11773256 :   if (!get_fold_mem_root (insn, &mem, &reg, &cur_offset))
     764                 :    11772929 :     return;
     765                 :             : 
     766                 :    11773256 :   HOST_WIDE_INT new_offset = cur_offset + info->added_offset;
     767                 :             : 
     768                 :    11773256 :   if (new_offset == cur_offset)
     769                 :             :     return;
     770                 :             : 
     771                 :         333 :   gcc_assert (!bitmap_empty_p (info->fold_insns));
     772                 :             : 
     773                 :         333 :   if (bitmap_intersect_p (&cannot_fold_insns, info->fold_insns))
     774                 :             :     return;
     775                 :             : 
     776                 :         327 :   if (dump_file)
     777                 :             :     {
     778                 :           0 :       fprintf (dump_file, "Memory offset changed from "
     779                 :             :                HOST_WIDE_INT_PRINT_DEC " to " HOST_WIDE_INT_PRINT_DEC
     780                 :             :                " for instruction:\n", cur_offset, new_offset);
     781                 :           0 :       print_rtl_single (dump_file, insn);
     782                 :             :     }
     783                 :             : 
     784                 :         327 :   machine_mode mode = GET_MODE (XEXP (mem, 0));
     785                 :         327 :   if (new_offset != 0)
     786                 :         327 :     XEXP (mem, 0) = gen_rtx_PLUS (mode, reg, gen_int_mode (new_offset, mode));
     787                 :             :   else
     788                 :           0 :     XEXP (mem, 0) = reg;
     789                 :         327 :   INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
     790                 :         327 :   df_insn_rescan (insn);
     791                 :             : }
     792                 :             : 
     793                 :             : /* If INSN is a move / add instruction that was folded then replace its
     794                 :             :    constant part with zero.  */
     795                 :             : static void
     796                 :   102510773 : do_commit_insn (rtx_insn *insn)
     797                 :             : {
     798                 :   102510773 :   if (bitmap_bit_p (&candidate_fold_insns, INSN_UID (insn))
     799                 :   102510773 :       && !bitmap_bit_p (&cannot_fold_insns, INSN_UID (insn)))
     800                 :             :     {
     801                 :          67 :       if (dump_file)
     802                 :             :         {
     803                 :           0 :           fprintf (dump_file, "Instruction folded:");
     804                 :           0 :           print_rtl_single (dump_file, insn);
     805                 :             :         }
     806                 :             : 
     807                 :          67 :       stats_fold_count++;
     808                 :             : 
     809                 :          67 :       rtx set = single_set (insn);
     810                 :          67 :       rtx dest = SET_DEST (set);
     811                 :          67 :       rtx src = SET_SRC (set);
     812                 :             : 
     813                 :             :       /* Emit a move and let subsequent passes eliminate it if possible.  */
     814                 :          67 :       if (GET_CODE (src) == CONST_INT)
     815                 :             :         {
     816                 :             :           /* INSN is R1 = C.
     817                 :             :              Replace it with R1 = 0 because C was folded.  */
     818                 :           1 :           rtx mov_rtx
     819                 :           1 :             = gen_move_insn (dest, gen_int_mode (0, GET_MODE (dest)));
     820                 :           1 :           df_insn_rescan (emit_insn_after (mov_rtx, insn));
     821                 :             :         }
     822                 :             :       else
     823                 :             :         {
     824                 :             :           /* INSN is R1 = R2 + C.
     825                 :             :              Replace it with R1 = R2 because C was folded.  */
     826                 :          66 :           rtx arg1 = XEXP (src, 0);
     827                 :             : 
     828                 :             :           /* If the DEST == ARG1 then the move is a no-op.  */
     829                 :          66 :           if (REGNO (dest) != REGNO (arg1))
     830                 :             :             {
     831                 :          66 :               gcc_checking_assert (GET_MODE (dest) == GET_MODE (arg1));
     832                 :          66 :               rtx mov_rtx = gen_move_insn (dest, arg1);
     833                 :          66 :               df_insn_rescan (emit_insn_after (mov_rtx, insn));
     834                 :             :             }
     835                 :             :         }
     836                 :             : 
     837                 :             :       /* Delete the original move / add instruction.  */
     838                 :          67 :       delete_insn (insn);
     839                 :             :     }
     840                 :   102510773 : }
     841                 :             : 
     842                 :             : unsigned int
     843                 :      927715 : pass_fold_mem_offsets::execute (function *fn)
     844                 :             : {
     845                 :             :   /* Computing UD/DU chains for flow graphs which have a high connectivity
     846                 :             :      will take a long time and is unlikely to be particularly useful.
     847                 :             : 
     848                 :             :      In normal circumstances a cfg should have about twice as many
     849                 :             :      edges as blocks.  But we do not want to punish small functions
     850                 :             :      which have a couple switch statements.  Rather than simply
     851                 :             :      threshold the number of blocks, uses something with a more
     852                 :             :      graceful degradation.  */
     853                 :      927715 :   if (n_edges_for_fn (fn) > 20000 + n_basic_blocks_for_fn (fn) * 4)
     854                 :             :     {
     855                 :           0 :       warning (OPT_Wdisabled_optimization,
     856                 :             :                "fold-mem-offsets: %d basic blocks and %d edges/basic block",
     857                 :             :                n_basic_blocks_for_fn (cfun),
     858                 :           0 :                n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun));
     859                 :           0 :       return 0;
     860                 :             :     }
     861                 :             : 
     862                 :      927715 :   df_set_flags (DF_EQ_NOTES + DF_RD_PRUNE_DEAD_DEFS + DF_DEFER_INSN_RESCAN);
     863                 :      927715 :   df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
     864                 :      927715 :   df_analyze ();
     865                 :             : 
     866                 :      927715 :   bitmap_initialize (&can_fold_insns, NULL);
     867                 :      927715 :   bitmap_initialize (&candidate_fold_insns, NULL);
     868                 :      927715 :   bitmap_initialize (&cannot_fold_insns, NULL);
     869                 :             : 
     870                 :      927715 :   stats_fold_count = 0;
     871                 :             : 
     872                 :      927715 :   basic_block bb;
     873                 :      927715 :   rtx_insn *insn;
     874                 :    12821539 :   FOR_ALL_BB_FN (bb, fn)
     875                 :             :     {
     876                 :             :       /* There is a conflict between this pass and RISCV's shorten-memrefs
     877                 :             :          pass.  For now disable folding if optimizing for size because
     878                 :             :          otherwise this cancels the effects of shorten-memrefs.  */
     879                 :    11893824 :       if (optimize_bb_for_size_p (bb))
     880                 :     2280096 :         continue;
     881                 :             : 
     882                 :     9613728 :       fold_info_map fold_info;
     883                 :             : 
     884                 :     9613728 :       bitmap_clear (&can_fold_insns);
     885                 :     9613728 :       bitmap_clear (&candidate_fold_insns);
     886                 :     9613728 :       bitmap_clear (&cannot_fold_insns);
     887                 :             : 
     888                 :   112124434 :       FOR_BB_INSNS (bb, insn)
     889                 :   102510706 :         do_analysis (insn);
     890                 :             : 
     891                 :   112124434 :       FOR_BB_INSNS (bb, insn)
     892                 :   102510706 :         do_fold_info_calculation (insn, &fold_info);
     893                 :             : 
     894                 :   112124434 :       FOR_BB_INSNS (bb, insn)
     895                 :   102510706 :         if (fold_mem_info **info = fold_info.get (insn))
     896                 :    11773256 :           do_check_validity (insn, *info);
     897                 :             : 
     898                 :     9613728 :       if (compute_validity_closure (&fold_info))
     899                 :             :         {
     900                 :   112124434 :           FOR_BB_INSNS (bb, insn)
     901                 :   102510706 :             if (fold_mem_info **info = fold_info.get (insn))
     902                 :    11773256 :               do_commit_offset (insn, *info);
     903                 :             : 
     904                 :   112124501 :           FOR_BB_INSNS (bb, insn)
     905                 :   102510773 :             do_commit_insn (insn);
     906                 :             :         }
     907                 :             : 
     908                 :    21386984 :       for (fold_info_map::iterator iter = fold_info.begin ();
     909                 :    42773968 :            iter != fold_info.end (); ++iter)
     910                 :    23546512 :         delete (*iter).second;
     911                 :     9613728 :     }
     912                 :             : 
     913                 :      927715 :   statistics_counter_event (cfun, "Number of folded instructions",
     914                 :             :                             stats_fold_count);
     915                 :             : 
     916                 :      927715 :   bitmap_release (&can_fold_insns);
     917                 :      927715 :   bitmap_release (&candidate_fold_insns);
     918                 :      927715 :   bitmap_release (&cannot_fold_insns);
     919                 :             : 
     920                 :      927715 :   return 0;
     921                 :             : }
     922                 :             : 
     923                 :             : } // anon namespace
     924                 :             : 
     925                 :             : rtl_opt_pass *
     926                 :      282866 : make_pass_fold_mem_offsets (gcc::context *ctxt)
     927                 :             : {
     928                 :      282866 :   return new pass_fold_mem_offsets (ctxt);
     929                 :             : }
        

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.