LCOV - code coverage report
Current view: top level - gcc - auto-inc-dec.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 1.2 % 602 7
Test Date: 2024-03-23 14:05:01 Functions: 12.5 % 16 2
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Discovery of auto-inc and auto-dec instructions.
       2                 :             :    Copyright (C) 2006-2024 Free Software Foundation, Inc.
       3                 :             :    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
       4                 :             : 
       5                 :             : This file is part of GCC.
       6                 :             : 
       7                 :             : GCC is free software; you can redistribute it and/or modify it under
       8                 :             : the terms of the GNU General Public License as published by the Free
       9                 :             : Software Foundation; either version 3, or (at your option) any later
      10                 :             : version.
      11                 :             : 
      12                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15                 :             : for more details.
      16                 :             : 
      17                 :             : You should have received a copy of the GNU General Public License
      18                 :             : along with GCC; see the file COPYING3.  If not see
      19                 :             : <http://www.gnu.org/licenses/>.  */
      20                 :             : 
      21                 :             : #include "config.h"
      22                 :             : #include "system.h"
      23                 :             : #include "coretypes.h"
      24                 :             : #include "backend.h"
      25                 :             : #include "target.h"
      26                 :             : #include "rtl.h"
      27                 :             : #include "tree.h"
      28                 :             : #include "predict.h"
      29                 :             : #include "df.h"
      30                 :             : #include "insn-config.h"
      31                 :             : #include "memmodel.h"
      32                 :             : #include "emit-rtl.h"
      33                 :             : #include "recog.h"
      34                 :             : #include "cfgrtl.h"
      35                 :             : #include "expr.h"
      36                 :             : #include "tree-pass.h"
      37                 :             : #include "dbgcnt.h"
      38                 :             : #include "print-rtl.h"
      39                 :             : #include "valtrack.h"
      40                 :             : 
      41                 :             : /* This pass was originally removed from flow.c. However there is
      42                 :             :    almost nothing that remains of that code.
      43                 :             : 
      44                 :             :    There are (4) basic forms that are matched:
      45                 :             : 
      46                 :             :       (1) FORM_PRE_ADD
      47                 :             :            a <- b + c
      48                 :             :            ...
      49                 :             :            *a
      50                 :             : 
      51                 :             :         becomes
      52                 :             : 
      53                 :             :            a <- b
      54                 :             :            ...
      55                 :             :            *(a += c) pre
      56                 :             : 
      57                 :             :         or, alternately,
      58                 :             : 
      59                 :             :            a <- b + c
      60                 :             :            ...
      61                 :             :            *b
      62                 :             : 
      63                 :             :         becomes
      64                 :             : 
      65                 :             :            a <- b
      66                 :             :            ...
      67                 :             :            *(a += c) post
      68                 :             : 
      69                 :             :         This uses a post-add, but it's handled as FORM_PRE_ADD because
      70                 :             :         the "increment" insn appears before the memory access.
      71                 :             : 
      72                 :             : 
      73                 :             :       (2) FORM_PRE_INC
      74                 :             :            a += c
      75                 :             :            ...
      76                 :             :            *a
      77                 :             : 
      78                 :             :         becomes
      79                 :             : 
      80                 :             :            ...
      81                 :             :            *(a += c) pre
      82                 :             : 
      83                 :             : 
      84                 :             :       (3) FORM_POST_ADD
      85                 :             :            *a
      86                 :             :            ...
      87                 :             :            b <- a + c
      88                 :             : 
      89                 :             :            (For this case to be true, b must not be assigned or used between
      90                 :             :            the *a and the assignment to b.  B must also be a Pmode reg.)
      91                 :             : 
      92                 :             :         becomes
      93                 :             : 
      94                 :             :            b <- a
      95                 :             :            *(b += c) post
      96                 :             :            ...
      97                 :             : 
      98                 :             : 
      99                 :             :       (4) FORM_POST_INC
     100                 :             :            *a
     101                 :             :            ...
     102                 :             :            a <- a + c
     103                 :             : 
     104                 :             :         becomes
     105                 :             : 
     106                 :             :            *(a += c) post
     107                 :             :            ...
     108                 :             : 
     109                 :             : 
     110                 :             :   There are three types of values of c.
     111                 :             : 
     112                 :             :     1) c is a constant equal to the width of the value being accessed by
     113                 :             :        the pointer.  This is useful for machines that have
     114                 :             :        HAVE_PRE_INCREMENT, HAVE_POST_INCREMENT, HAVE_PRE_DECREMENT or
     115                 :             :        HAVE_POST_DECREMENT defined.
     116                 :             : 
     117                 :             :     2) c is a constant not equal to the width of the value being accessed
     118                 :             :        by the pointer.  This is useful for machines that have
     119                 :             :        HAVE_PRE_MODIFY_DISP, HAVE_POST_MODIFY_DISP defined.
     120                 :             : 
     121                 :             :     3) c is a register.  This is useful for machines that have
     122                 :             :        HAVE_PRE_MODIFY_REG,  HAVE_POST_MODIFY_REG
     123                 :             : 
     124                 :             :   The is one special case: if a already had an offset equal to it +-
     125                 :             :   its width and that offset is equal to -c when the increment was
     126                 :             :   before the ref or +c if the increment was after the ref, then if we
     127                 :             :   can do the combination but switch the pre/post bit.  */
     128                 :             : 
     129                 :             : 
     130                 :             : enum form
     131                 :             : {
     132                 :             :   FORM_PRE_ADD,
     133                 :             :   FORM_PRE_INC,
     134                 :             :   FORM_POST_ADD,
     135                 :             :   FORM_POST_INC,
     136                 :             :   FORM_last
     137                 :             : };
     138                 :             : 
     139                 :             : /* The states of the second operands of mem refs and inc insns.  If no
     140                 :             :    second operand of the mem_ref was found, it is assumed to just be
     141                 :             :    ZERO.  SIZE is the size of the mode accessed in the memref.  The
     142                 :             :    ANY is used for constants that are not +-size or 0.  REG is used if
     143                 :             :    the forms are reg1 + reg2.  */
     144                 :             : 
     145                 :             : enum inc_state
     146                 :             : {
     147                 :             :   INC_ZERO,           /* == 0  */
     148                 :             :   INC_NEG_SIZE,       /* == +size  */
     149                 :             :   INC_POS_SIZE,       /* == -size */
     150                 :             :   INC_NEG_ANY,        /* == some -constant  */
     151                 :             :   INC_POS_ANY,        /* == some +constant  */
     152                 :             :   INC_REG,            /* == some register  */
     153                 :             :   INC_last
     154                 :             : };
     155                 :             : 
     156                 :             : /* The eight forms that pre/post inc/dec can take.  */
     157                 :             : enum gen_form
     158                 :             : {
     159                 :             :   NOTHING,
     160                 :             :   SIMPLE_PRE_INC,     /* ++size  */
     161                 :             :   SIMPLE_POST_INC,    /* size++  */
     162                 :             :   SIMPLE_PRE_DEC,     /* --size  */
     163                 :             :   SIMPLE_POST_DEC,    /* size--  */
     164                 :             :   DISP_PRE,           /* ++con   */
     165                 :             :   DISP_POST,          /* con++   */
     166                 :             :   REG_PRE,            /* ++reg   */
     167                 :             :   REG_POST            /* reg++   */
     168                 :             : };
     169                 :             : 
     170                 :             : /* Tmp mem rtx for use in cost modeling.  */
     171                 :             : static rtx mem_tmp;
     172                 :             : 
     173                 :             : static enum inc_state
     174                 :           0 : set_inc_state (HOST_WIDE_INT val, poly_int64 size)
     175                 :             : {
     176                 :           0 :   if (val == 0)
     177                 :             :     return INC_ZERO;
     178                 :           0 :   if (val < 0)
     179                 :           0 :     return known_eq (val, -size) ? INC_NEG_SIZE : INC_NEG_ANY;
     180                 :             :   else
     181                 :           0 :     return known_eq (val, size) ? INC_POS_SIZE : INC_POS_ANY;
     182                 :             : }
     183                 :             : 
     184                 :             : /* The DECISION_TABLE that describes what form, if any, the increment
     185                 :             :    or decrement will take. It is a three dimensional table.  The first
     186                 :             :    index is the type of constant or register found as the second
     187                 :             :    operand of the inc insn.  The second index is the type of constant
     188                 :             :    or register found as the second operand of the memory reference (if
     189                 :             :    no second operand exists, 0 is used).  The third index is the form
     190                 :             :    and location (relative to the mem reference) of inc insn.  */
     191                 :             : 
     192                 :             : static bool initialized = false;
     193                 :             : static enum gen_form decision_table[INC_last][INC_last][FORM_last];
     194                 :             : 
     195                 :             : static void
     196                 :           0 : init_decision_table (void)
     197                 :             : {
     198                 :           0 :   enum gen_form value;
     199                 :             : 
     200                 :           0 :   if (HAVE_PRE_INCREMENT || HAVE_PRE_MODIFY_DISP)
     201                 :             :     {
     202                 :             :       /* Prefer the simple form if both are available.  */
     203                 :             :       value = (HAVE_PRE_INCREMENT) ? SIMPLE_PRE_INC : DISP_PRE;
     204                 :             : 
     205                 :             :       decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_ADD] = value;
     206                 :             :       decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_INC] = value;
     207                 :             : 
     208                 :             :       decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_ADD] = value;
     209                 :             :       decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_INC] = value;
     210                 :             :     }
     211                 :             : 
     212                 :           0 :   if (HAVE_POST_INCREMENT || HAVE_POST_MODIFY_DISP)
     213                 :             :     {
     214                 :             :       /* Prefer the simple form if both are available.  */
     215                 :             :       value = (HAVE_POST_INCREMENT) ? SIMPLE_POST_INC : DISP_POST;
     216                 :             : 
     217                 :             :       decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_ADD] = value;
     218                 :             :       decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_INC] = value;
     219                 :             : 
     220                 :             :       decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_ADD] = value;
     221                 :             :       decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_INC] = value;
     222                 :             :     }
     223                 :             : 
     224                 :           0 :   if (HAVE_PRE_DECREMENT || HAVE_PRE_MODIFY_DISP)
     225                 :             :     {
     226                 :             :       /* Prefer the simple form if both are available.  */
     227                 :             :       value = (HAVE_PRE_DECREMENT) ? SIMPLE_PRE_DEC : DISP_PRE;
     228                 :             : 
     229                 :             :       decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_ADD] = value;
     230                 :             :       decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_INC] = value;
     231                 :             : 
     232                 :             :       decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_ADD] = value;
     233                 :             :       decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_INC] = value;
     234                 :             :     }
     235                 :             : 
     236                 :           0 :   if (HAVE_POST_DECREMENT || HAVE_POST_MODIFY_DISP)
     237                 :             :     {
     238                 :             :       /* Prefer the simple form if both are available.  */
     239                 :             :       value = (HAVE_POST_DECREMENT) ? SIMPLE_POST_DEC : DISP_POST;
     240                 :             : 
     241                 :             :       decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_ADD] = value;
     242                 :             :       decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_INC] = value;
     243                 :             : 
     244                 :             :       decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_ADD] = value;
     245                 :             :       decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_INC] = value;
     246                 :             :     }
     247                 :             : 
     248                 :           0 :   if (HAVE_PRE_MODIFY_DISP)
     249                 :             :     {
     250                 :             :       decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE;
     251                 :             :       decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE;
     252                 :             : 
     253                 :             :       decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_ADD] = DISP_PRE;
     254                 :             :       decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_INC] = DISP_PRE;
     255                 :             : 
     256                 :             :       decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE;
     257                 :             :       decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE;
     258                 :             : 
     259                 :             :       decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_ADD] = DISP_PRE;
     260                 :             :       decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_INC] = DISP_PRE;
     261                 :             :     }
     262                 :             : 
     263                 :           0 :   if (HAVE_POST_MODIFY_DISP)
     264                 :             :     {
     265                 :             :       decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST;
     266                 :             :       decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST;
     267                 :             : 
     268                 :             :       decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_ADD] = DISP_POST;
     269                 :             :       decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_INC] = DISP_POST;
     270                 :             : 
     271                 :             :       decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST;
     272                 :             :       decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST;
     273                 :             : 
     274                 :             :       decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_ADD] = DISP_POST;
     275                 :             :       decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_INC] = DISP_POST;
     276                 :             :     }
     277                 :             : 
     278                 :             :   /* This is much simpler than the other cases because we do not look
     279                 :             :      for the reg1-reg2 case.  Note that we do not have a INC_POS_REG
     280                 :             :      and INC_NEG_REG states.  Most of the use of such states would be
     281                 :             :      on a target that had an R1 - R2 update address form.
     282                 :             : 
     283                 :             :      There is the remote possibility that you could also catch a = a +
     284                 :             :      b; *(a - b) as a postdecrement of (a + b).  However, it is
     285                 :             :      unclear if *(a - b) would ever be generated on a machine that did
     286                 :             :      not have that kind of addressing mode.  The IA-64 and RS6000 will
     287                 :             :      not do this, and I cannot speak for any other.  If any
     288                 :             :      architecture does have an a-b update for, these cases should be
     289                 :             :      added.  */
     290                 :           0 :   if (HAVE_PRE_MODIFY_REG)
     291                 :             :     {
     292                 :             :       decision_table[INC_REG][INC_ZERO][FORM_PRE_ADD] = REG_PRE;
     293                 :             :       decision_table[INC_REG][INC_ZERO][FORM_PRE_INC] = REG_PRE;
     294                 :             : 
     295                 :             :       decision_table[INC_REG][INC_REG][FORM_POST_ADD] = REG_PRE;
     296                 :             :       decision_table[INC_REG][INC_REG][FORM_POST_INC] = REG_PRE;
     297                 :             :     }
     298                 :             : 
     299                 :           0 :   if (HAVE_POST_MODIFY_REG)
     300                 :             :     {
     301                 :             :       decision_table[INC_REG][INC_ZERO][FORM_POST_ADD] = REG_POST;
     302                 :             :       decision_table[INC_REG][INC_ZERO][FORM_POST_INC] = REG_POST;
     303                 :             :     }
     304                 :             : 
     305                 :           0 :   initialized = true;
     306                 :           0 : }
     307                 :             : 
     308                 :             : /* Parsed fields of an inc insn of the form "reg_res = reg0+reg1" or
     309                 :             :    "reg_res = reg0+c".  */
     310                 :             : 
     311                 :             : static struct inc_insn
     312                 :             : {
     313                 :             :   rtx_insn *insn;     /* The insn being parsed.  */
     314                 :             :   rtx pat;            /* The pattern of the insn.  */
     315                 :             :   bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg.  */
     316                 :             :   enum form form;
     317                 :             :   rtx reg_res;
     318                 :             :   rtx reg0;
     319                 :             :   rtx reg1;
     320                 :             :   enum inc_state reg1_state;/* The form of the const if reg1 is a const.  */
     321                 :             :   HOST_WIDE_INT reg1_val;/* Value if reg1 is const.  */
     322                 :             : } inc_insn;
     323                 :             : 
     324                 :             : 
     325                 :             : /* Dump the parsed inc insn to FILE.  */
     326                 :             : 
     327                 :             : static void
     328                 :           0 : dump_inc_insn (FILE *file)
     329                 :             : {
     330                 :           0 :   const char *f = ((inc_insn.form == FORM_PRE_ADD)
     331                 :           0 :               || (inc_insn.form == FORM_PRE_INC)) ? "pre" : "post";
     332                 :             : 
     333                 :           0 :   dump_insn_slim (file, inc_insn.insn);
     334                 :             : 
     335                 :           0 :   switch (inc_insn.form)
     336                 :             :     {
     337                 :           0 :     case FORM_PRE_ADD:
     338                 :           0 :     case FORM_POST_ADD:
     339                 :           0 :       if (inc_insn.reg1_is_const)
     340                 :           0 :         fprintf (file, "found %s add(%d) r[%d]=r[%d]+%d\n",
     341                 :           0 :                  f, INSN_UID (inc_insn.insn),
     342                 :           0 :                  REGNO (inc_insn.reg_res),
     343                 :           0 :                  REGNO (inc_insn.reg0), (int) inc_insn.reg1_val);
     344                 :             :       else
     345                 :           0 :         fprintf (file, "found %s add(%d) r[%d]=r[%d]+r[%d]\n",
     346                 :           0 :                  f, INSN_UID (inc_insn.insn),
     347                 :           0 :                  REGNO (inc_insn.reg_res),
     348                 :           0 :                  REGNO (inc_insn.reg0), REGNO (inc_insn.reg1));
     349                 :             :       break;
     350                 :             : 
     351                 :           0 :     case FORM_PRE_INC:
     352                 :           0 :     case FORM_POST_INC:
     353                 :           0 :       if (inc_insn.reg1_is_const)
     354                 :           0 :         fprintf (file, "found %s inc(%d) r[%d]+=%d\n",
     355                 :           0 :                  f, INSN_UID (inc_insn.insn),
     356                 :           0 :                  REGNO (inc_insn.reg_res), (int) inc_insn.reg1_val);
     357                 :             :       else
     358                 :           0 :         fprintf (file, "found %s inc(%d) r[%d]+=r[%d]\n",
     359                 :           0 :                  f, INSN_UID (inc_insn.insn),
     360                 :           0 :                  REGNO (inc_insn.reg_res), REGNO (inc_insn.reg1));
     361                 :             :       break;
     362                 :             : 
     363                 :             :     default:
     364                 :             :       break;
     365                 :             :     }
     366                 :           0 : }
     367                 :             : 
     368                 :             : 
     369                 :             : /* Parsed fields of a mem ref of the form "*(reg0+reg1)" or "*(reg0+c)".  */
     370                 :             : 
     371                 :             : static struct mem_insn
     372                 :             : {
     373                 :             :   rtx_insn *insn;     /* The insn being parsed.  */
     374                 :             :   rtx pat;            /* The pattern of the insn.  */
     375                 :             :   rtx *mem_loc;       /* The address of the field that holds the mem */
     376                 :             :                       /* that is to be replaced.  */
     377                 :             :   bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg.  */
     378                 :             :   rtx reg0;
     379                 :             :   rtx reg1;           /* This is either a reg or a const depending on
     380                 :             :                          reg1_is_const.  */
     381                 :             :   enum inc_state reg1_state;/* The form of the const if reg1 is a const.  */
     382                 :             :   HOST_WIDE_INT reg1_val;/* Value if reg1 is const.  */
     383                 :             : } mem_insn;
     384                 :             : 
     385                 :             : 
     386                 :             : /* Dump the parsed mem insn to FILE.  */
     387                 :             : 
     388                 :             : static void
     389                 :           0 : dump_mem_insn (FILE *file)
     390                 :             : {
     391                 :           0 :   dump_insn_slim (file, mem_insn.insn);
     392                 :             : 
     393                 :           0 :   if (mem_insn.reg1_is_const)
     394                 :           0 :     fprintf (file, "found mem(%d) *(r[%d]+%d)\n",
     395                 :           0 :              INSN_UID (mem_insn.insn),
     396                 :           0 :              REGNO (mem_insn.reg0), (int) mem_insn.reg1_val);
     397                 :             :   else
     398                 :           0 :     fprintf (file, "found mem(%d) *(r[%d]+r[%d])\n",
     399                 :           0 :              INSN_UID (mem_insn.insn),
     400                 :           0 :              REGNO (mem_insn.reg0), REGNO (mem_insn.reg1));
     401                 :           0 : }
     402                 :             : 
     403                 :             : 
     404                 :             : /* The following three arrays contain pointers to instructions. They
     405                 :             :    are indexed by REGNO.  At any point in the basic block where we are
     406                 :             :    looking these three arrays contain, respectively, the next insn
     407                 :             :    that uses REGNO, the next inc or add insn that uses REGNO and the
     408                 :             :    next insn that sets REGNO.
     409                 :             : 
     410                 :             :    The arrays are not cleared when we move from block to block so
     411                 :             :    whenever an insn is retrieved from these arrays, it's block number
     412                 :             :    must be compared with the current block.
     413                 :             : */
     414                 :             : 
     415                 :             : static rtx_insn **reg_next_debug_use = NULL;
     416                 :             : static rtx_insn **reg_next_use = NULL;
     417                 :             : static rtx_insn **reg_next_inc_use = NULL;
     418                 :             : static rtx_insn **reg_next_def = NULL;
     419                 :             : 
     420                 :             : 
     421                 :             : /* Move dead note that match PATTERN to TO_INSN from FROM_INSN.  We do
     422                 :             :    not really care about moving any other notes from the inc or add
     423                 :             :    insn.  Moving the REG_EQUAL and REG_EQUIV is clearly wrong and it
     424                 :             :    does not appear that there are any other kinds of relevant notes.  */
     425                 :             : 
     426                 :             : static void
     427                 :           0 : move_dead_notes (rtx_insn *to_insn, rtx_insn *from_insn, rtx pattern)
     428                 :             : {
     429                 :           0 :   rtx note;
     430                 :           0 :   rtx next_note;
     431                 :           0 :   rtx prev_note = NULL;
     432                 :             : 
     433                 :           0 :   for (note = REG_NOTES (from_insn); note; note = next_note)
     434                 :             :     {
     435                 :           0 :       next_note = XEXP (note, 1);
     436                 :             : 
     437                 :           0 :       if ((REG_NOTE_KIND (note) == REG_DEAD)
     438                 :           0 :           && pattern == XEXP (note, 0))
     439                 :             :         {
     440                 :           0 :           XEXP (note, 1) = REG_NOTES (to_insn);
     441                 :           0 :           REG_NOTES (to_insn) = note;
     442                 :           0 :           if (prev_note)
     443                 :           0 :             XEXP (prev_note, 1) = next_note;
     444                 :             :           else
     445                 :           0 :             REG_NOTES (from_insn) = next_note;
     446                 :             :         }
     447                 :             :       else prev_note = note;
     448                 :             :     }
     449                 :           0 : }
     450                 :             : 
     451                 :             : /* Change mem_insn.mem_loc so that uses NEW_ADDR which has an
     452                 :             :    increment of INC_REG.  To have reached this point, the change is a
     453                 :             :    legitimate one from a dataflow point of view.  The only questions
     454                 :             :    are is this a valid change to the instruction and is this a
     455                 :             :    profitable change to the instruction.  */
     456                 :             : 
     457                 :             : static bool
     458                 :           0 : attempt_change (rtx new_addr, rtx inc_reg)
     459                 :             : {
     460                 :             :   /* There are four cases: For the two cases that involve an add
     461                 :             :      instruction, we are going to have to delete the add and insert a
     462                 :             :      mov.  We are going to assume that the mov is free.  This is
     463                 :             :      fairly early in the backend and there are a lot of opportunities
     464                 :             :      for removing that move later.  In particular, there is the case
     465                 :             :      where the move may be dead, this is what dead code elimination
     466                 :             :      passes are for.  The two cases where we have an inc insn will be
     467                 :             :      handled mov free.  */
     468                 :             : 
     469                 :           0 :   basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
     470                 :           0 :   rtx_insn *mov_insn = NULL;
     471                 :           0 :   int regno;
     472                 :           0 :   rtx mem = *mem_insn.mem_loc;
     473                 :           0 :   machine_mode mode = GET_MODE (mem);
     474                 :           0 :   int align = MEM_ALIGN (mem);
     475                 :           0 :   rtx new_mem;
     476                 :           0 :   int old_cost = 0;
     477                 :           0 :   int new_cost = 0;
     478                 :           0 :   bool speed = optimize_bb_for_speed_p (bb);
     479                 :             : 
     480                 :           0 :   PUT_MODE (mem_tmp, mode);
     481                 :           0 :   XEXP (mem_tmp, 0) = new_addr;
     482                 :           0 :   set_mem_align (mem_tmp, align);
     483                 :             : 
     484                 :           0 :   old_cost = (set_src_cost (mem, mode, speed)
     485                 :           0 :               + set_rtx_cost (PATTERN (inc_insn.insn), speed));
     486                 :             : 
     487                 :           0 :   new_cost = set_src_cost (mem_tmp, mode, speed);
     488                 :             : 
     489                 :             :   /* In the FORM_PRE_ADD and FORM_POST_ADD cases we emit an extra move
     490                 :             :      whose cost we should account for.  */
     491                 :           0 :   if (inc_insn.form == FORM_PRE_ADD
     492                 :           0 :       || inc_insn.form == FORM_POST_ADD)
     493                 :             :     {
     494                 :           0 :       start_sequence ();
     495                 :           0 :       emit_move_insn (inc_insn.reg_res, inc_insn.reg0);
     496                 :           0 :       mov_insn = get_insns ();
     497                 :           0 :       end_sequence ();
     498                 :           0 :       new_cost += seq_cost (mov_insn, speed);
     499                 :             :     }
     500                 :             : 
     501                 :             :   /* The first item of business is to see if this is profitable.  */
     502                 :           0 :   if (old_cost < new_cost)
     503                 :             :     {
     504                 :           0 :       if (dump_file)
     505                 :           0 :         fprintf (dump_file, "cost failure old=%d new=%d\n", old_cost, new_cost);
     506                 :           0 :       return false;
     507                 :             :     }
     508                 :             : 
     509                 :             :   /* Jump through a lot of hoops to keep the attributes up to date.  We
     510                 :             :      do not want to call one of the change address variants that take
     511                 :             :      an offset even though we know the offset in many cases.  These
     512                 :             :      assume you are changing where the address is pointing by the
     513                 :             :      offset.  */
     514                 :           0 :   new_mem = replace_equiv_address_nv (mem, new_addr);
     515                 :           0 :   if (! validate_change (mem_insn.insn, mem_insn.mem_loc, new_mem, 0))
     516                 :             :     {
     517                 :           0 :       if (dump_file)
     518                 :           0 :         fprintf (dump_file, "validation failure\n");
     519                 :           0 :       return false;
     520                 :             :     }
     521                 :             : 
     522                 :             :   /* From here to the end of the function we are committed to the
     523                 :             :      change, i.e. nothing fails.  Generate any necessary movs, move
     524                 :             :      any regnotes, and fix up the reg_next_{use,inc_use,def}.  */
     525                 :           0 :   switch (inc_insn.form)
     526                 :             :     {
     527                 :           0 :     case FORM_PRE_ADD:
     528                 :             :       /* Replace the addition with a move.  Do it at the location of
     529                 :             :          the addition since the operand of the addition may change
     530                 :             :          before the memory reference.  */
     531                 :           0 :       gcc_assert (mov_insn);
     532                 :           0 :       emit_insn_before (mov_insn, inc_insn.insn);
     533                 :           0 :       regno = REGNO (inc_insn.reg0);
     534                 :             :       /* ??? Could REGNO possibly be used in MEM_INSN other than in
     535                 :             :          the MEM address, and still die there, so that move_dead_notes
     536                 :             :          would incorrectly move the note?  */
     537                 :           0 :       if (reg_next_use[regno] == mem_insn.insn)
     538                 :           0 :         move_dead_notes (mov_insn, mem_insn.insn, inc_insn.reg0);
     539                 :             :       else
     540                 :           0 :         move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
     541                 :             : 
     542                 :           0 :       regno = REGNO (inc_insn.reg_res);
     543                 :           0 :       if (reg_next_debug_use && reg_next_debug_use[regno]
     544                 :           0 :           && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
     545                 :             :         {
     546                 :           0 :           rtx adjres = gen_rtx_PLUS (GET_MODE (inc_insn.reg_res),
     547                 :             :                                      inc_insn.reg_res, inc_insn.reg1);
     548                 :           0 :           if (dump_file)
     549                 :           0 :             fprintf (dump_file, "adjusting debug insns\n");
     550                 :           0 :           propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
     551                 :             :                                mem_insn.insn,
     552                 :             :                                inc_insn.reg_res, adjres, bb);
     553                 :           0 :           reg_next_debug_use[regno] = NULL;
     554                 :             :         }
     555                 :           0 :       reg_next_def[regno] = mov_insn;
     556                 :           0 :       reg_next_use[regno] = NULL;
     557                 :             : 
     558                 :           0 :       regno = REGNO (inc_insn.reg0);
     559                 :           0 :       if (reg_next_debug_use && reg_next_debug_use[regno]
     560                 :           0 :           && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb
     561                 :           0 :           && find_reg_note (mov_insn, REG_DEAD, inc_insn.reg0))
     562                 :             :         {
     563                 :           0 :           if (dump_file)
     564                 :           0 :             fprintf (dump_file, "remapping debug insns\n");
     565                 :           0 :           propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
     566                 :             :                                mem_insn.insn,
     567                 :             :                                inc_insn.reg0, inc_insn.reg_res, bb);
     568                 :           0 :           reg_next_debug_use[regno] = NULL;
     569                 :             :         }
     570                 :           0 :       reg_next_use[regno] = mov_insn;
     571                 :           0 :       df_recompute_luids (bb);
     572                 :           0 :       break;
     573                 :             : 
     574                 :           0 :     case FORM_POST_INC:
     575                 :           0 :       regno = REGNO (inc_insn.reg_res);
     576                 :           0 :       if (reg_next_debug_use && reg_next_debug_use[regno]
     577                 :           0 :           && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
     578                 :             :         {
     579                 :           0 :           rtx adjres = gen_rtx_MINUS (GET_MODE (inc_insn.reg_res),
     580                 :             :                                       inc_insn.reg_res, inc_insn.reg1);
     581                 :           0 :           if (dump_file)
     582                 :           0 :             fprintf (dump_file, "adjusting debug insns\n");
     583                 :           0 :           propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
     584                 :             :                                inc_insn.insn,
     585                 :             :                                inc_insn.reg_res, adjres, bb);
     586                 :           0 :           reg_next_debug_use[regno] = NULL;
     587                 :             :         }
     588                 :           0 :       if (reg_next_use[regno] == reg_next_inc_use[regno])
     589                 :           0 :         reg_next_inc_use[regno] = NULL;
     590                 :             : 
     591                 :             :       /* Fallthru.  */
     592                 :           0 :     case FORM_PRE_INC:
     593                 :           0 :       regno = REGNO (inc_insn.reg_res);
     594                 :             :       /* Despite the fall-through, we won't run this twice: we'll have
     595                 :             :          already cleared reg_next_debug_use[regno] before falling
     596                 :             :          through.  */
     597                 :           0 :       if (reg_next_debug_use && reg_next_debug_use[regno]
     598                 :           0 :           && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb)
     599                 :             :         {
     600                 :           0 :           rtx adjres = gen_rtx_PLUS (GET_MODE (inc_insn.reg_res),
     601                 :             :                                      inc_insn.reg_res, inc_insn.reg1);
     602                 :           0 :           if (dump_file)
     603                 :           0 :             fprintf (dump_file, "adjusting debug insns\n");
     604                 :           0 :           propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
     605                 :             :                                mem_insn.insn,
     606                 :             :                                inc_insn.reg_res, adjres, bb);
     607                 :           0 :           if (DF_INSN_LUID (mem_insn.insn)
     608                 :           0 :               < DF_INSN_LUID (reg_next_debug_use[regno]))
     609                 :           0 :             reg_next_debug_use[regno] = NULL;
     610                 :             :         }
     611                 :           0 :       reg_next_def[regno] = mem_insn.insn;
     612                 :           0 :       reg_next_use[regno] = NULL;
     613                 :             : 
     614                 :           0 :       break;
     615                 :             : 
     616                 :           0 :     case FORM_POST_ADD:
     617                 :           0 :       gcc_assert (mov_insn);
     618                 :           0 :       emit_insn_before (mov_insn, mem_insn.insn);
     619                 :           0 :       move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
     620                 :             : 
     621                 :             :       /* Do not move anything to the mov insn because the instruction
     622                 :             :          pointer for the main iteration has not yet hit that.  It is
     623                 :             :          still pointing to the mem insn. */
     624                 :           0 :       regno = REGNO (inc_insn.reg_res);
     625                 :             :       /* The pseudo is now set earlier, so it must have been dead in
     626                 :             :          that range, and dead registers cannot be referenced in debug
     627                 :             :          insns.  */
     628                 :           0 :       gcc_assert (!(reg_next_debug_use && reg_next_debug_use[regno]
     629                 :             :                     && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb));
     630                 :           0 :       reg_next_def[regno] = mem_insn.insn;
     631                 :           0 :       reg_next_use[regno] = NULL;
     632                 :             : 
     633                 :           0 :       regno = REGNO (inc_insn.reg0);
     634                 :           0 :       if (reg_next_debug_use && reg_next_debug_use[regno]
     635                 :           0 :           && BLOCK_FOR_INSN (reg_next_debug_use[regno]) == bb
     636                 :           0 :           && find_reg_note (mov_insn, REG_DEAD, inc_insn.reg0))
     637                 :             :         {
     638                 :           0 :           if (dump_file)
     639                 :           0 :             fprintf (dump_file, "remapping debug insns\n");
     640                 :           0 :           propagate_for_debug (PREV_INSN (reg_next_debug_use[regno]),
     641                 :             :                                inc_insn.insn,
     642                 :             :                                inc_insn.reg0, inc_insn.reg_res, bb);
     643                 :           0 :           reg_next_debug_use[regno] = NULL;
     644                 :             :         }
     645                 :           0 :       reg_next_use[regno] = mem_insn.insn;
     646                 :           0 :       if ((reg_next_use[regno] == reg_next_inc_use[regno])
     647                 :           0 :           || (reg_next_inc_use[regno] == inc_insn.insn))
     648                 :           0 :         reg_next_inc_use[regno] = NULL;
     649                 :           0 :       df_recompute_luids (bb);
     650                 :           0 :       break;
     651                 :             : 
     652                 :           0 :     case FORM_last:
     653                 :           0 :     default:
     654                 :           0 :       gcc_unreachable ();
     655                 :             :     }
     656                 :             : 
     657                 :           0 :   if (!inc_insn.reg1_is_const)
     658                 :             :     {
     659                 :           0 :       regno = REGNO (inc_insn.reg1);
     660                 :           0 :       reg_next_use[regno] = mem_insn.insn;
     661                 :           0 :       if ((reg_next_use[regno] == reg_next_inc_use[regno])
     662                 :           0 :           || (reg_next_inc_use[regno] == inc_insn.insn))
     663                 :           0 :         reg_next_inc_use[regno] = NULL;
     664                 :             :     }
     665                 :             : 
     666                 :           0 :   delete_insn (inc_insn.insn);
     667                 :             : 
     668                 :           0 :   if (dump_file && mov_insn)
     669                 :             :     {
     670                 :           0 :       fprintf (dump_file, "inserting mov ");
     671                 :           0 :       dump_insn_slim (dump_file, mov_insn);
     672                 :             :     }
     673                 :             : 
     674                 :             :   /* Record that this insn has an implicit side effect.  */
     675                 :           0 :   add_reg_note (mem_insn.insn, REG_INC, inc_reg);
     676                 :             : 
     677                 :           0 :   if (dump_file)
     678                 :             :     {
     679                 :           0 :       fprintf (dump_file, "****success ");
     680                 :           0 :       dump_insn_slim (dump_file, mem_insn.insn);
     681                 :             :     }
     682                 :             : 
     683                 :             :   return true;
     684                 :             : }
     685                 :             : 
     686                 :             : 
     687                 :             : /* Try to combine the instruction in INC_INSN with the instruction in
     688                 :             :    MEM_INSN.  First the form is determined using the DECISION_TABLE
     689                 :             :    and the results of parsing the INC_INSN and the MEM_INSN.
     690                 :             :    Assuming the form is ok, a prototype new address is built which is
     691                 :             :    passed to ATTEMPT_CHANGE for final processing.  */
     692                 :             : 
     693                 :             : static bool
     694                 :           0 : try_merge (void)
     695                 :             : {
     696                 :           0 :   enum gen_form gen_form;
     697                 :           0 :   rtx mem = *mem_insn.mem_loc;
     698                 :           0 :   rtx inc_reg = inc_insn.form == FORM_POST_ADD ?
     699                 :             :     inc_insn.reg_res : mem_insn.reg0;
     700                 :             : 
     701                 :             :   /* The width of the mem being accessed.  */
     702                 :           0 :   poly_int64 size = GET_MODE_SIZE (GET_MODE (mem));
     703                 :           0 :   rtx_insn *last_insn = NULL;
     704                 :           0 :   machine_mode reg_mode = GET_MODE (inc_reg);
     705                 :             : 
     706                 :           0 :   switch (inc_insn.form)
     707                 :             :     {
     708                 :           0 :     case FORM_PRE_ADD:
     709                 :           0 :     case FORM_PRE_INC:
     710                 :           0 :       last_insn = mem_insn.insn;
     711                 :           0 :       break;
     712                 :           0 :     case FORM_POST_INC:
     713                 :           0 :     case FORM_POST_ADD:
     714                 :           0 :       last_insn = inc_insn.insn;
     715                 :           0 :       break;
     716                 :           0 :     case FORM_last:
     717                 :           0 :     default:
     718                 :           0 :       gcc_unreachable ();
     719                 :             :     }
     720                 :             : 
     721                 :             :   /* Cannot handle auto inc of the stack.  */
     722                 :           0 :   if (inc_reg == stack_pointer_rtx)
     723                 :             :     {
     724                 :           0 :       if (dump_file)
     725                 :           0 :         fprintf (dump_file, "cannot inc stack %d failure\n", REGNO (inc_reg));
     726                 :           0 :       return false;
     727                 :             :     }
     728                 :             : 
     729                 :             :   /* Look to see if the inc register is dead after the memory
     730                 :             :      reference.  If it is, do not do the combination.  */
     731                 :           0 :   if (find_regno_note (last_insn, REG_DEAD, REGNO (inc_reg)))
     732                 :             :     {
     733                 :           0 :       if (dump_file)
     734                 :           0 :         fprintf (dump_file, "dead failure %d\n", REGNO (inc_reg));
     735                 :           0 :       return false;
     736                 :             :     }
     737                 :             : 
     738                 :           0 :   mem_insn.reg1_state = (mem_insn.reg1_is_const)
     739                 :           0 :     ? set_inc_state (mem_insn.reg1_val, size) : INC_REG;
     740                 :           0 :   inc_insn.reg1_state = (inc_insn.reg1_is_const)
     741                 :           0 :     ? set_inc_state (inc_insn.reg1_val, size) : INC_REG;
     742                 :             : 
     743                 :             :   /* Now get the form that we are generating.  */
     744                 :           0 :   gen_form = decision_table
     745                 :           0 :     [inc_insn.reg1_state][mem_insn.reg1_state][inc_insn.form];
     746                 :             : 
     747                 :           0 :   if (dbg_cnt (auto_inc_dec) == false)
     748                 :             :     return false;
     749                 :             : 
     750                 :           0 :   switch (gen_form)
     751                 :             :     {
     752                 :             :     default:
     753                 :             :     case NOTHING:
     754                 :             :       return false;
     755                 :             : 
     756                 :           0 :     case SIMPLE_PRE_INC:     /* ++size  */
     757                 :           0 :       if (dump_file)
     758                 :           0 :         fprintf (dump_file, "trying SIMPLE_PRE_INC\n");
     759                 :           0 :       return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg);
     760                 :             : 
     761                 :           0 :     case SIMPLE_POST_INC:    /* size++  */
     762                 :           0 :       if (dump_file)
     763                 :           0 :         fprintf (dump_file, "trying SIMPLE_POST_INC\n");
     764                 :           0 :       return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg);
     765                 :             : 
     766                 :           0 :     case SIMPLE_PRE_DEC:     /* --size  */
     767                 :           0 :       if (dump_file)
     768                 :           0 :         fprintf (dump_file, "trying SIMPLE_PRE_DEC\n");
     769                 :           0 :       return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg);
     770                 :             : 
     771                 :           0 :     case SIMPLE_POST_DEC:    /* size--  */
     772                 :           0 :       if (dump_file)
     773                 :           0 :         fprintf (dump_file, "trying SIMPLE_POST_DEC\n");
     774                 :           0 :       return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg);
     775                 :             : 
     776                 :           0 :     case DISP_PRE:           /* ++con   */
     777                 :           0 :       if (dump_file)
     778                 :           0 :         fprintf (dump_file, "trying DISP_PRE\n");
     779                 :           0 :       return attempt_change (gen_rtx_PRE_MODIFY (reg_mode,
     780                 :             :                                                  inc_reg,
     781                 :             :                                                  gen_rtx_PLUS (reg_mode,
     782                 :             :                                                                inc_reg,
     783                 :             :                                                                inc_insn.reg1)),
     784                 :           0 :                              inc_reg);
     785                 :             : 
     786                 :           0 :     case DISP_POST:          /* con++   */
     787                 :           0 :       if (dump_file)
     788                 :           0 :         fprintf (dump_file, "trying POST_DISP\n");
     789                 :           0 :       return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
     790                 :             :                                                   inc_reg,
     791                 :             :                                                   gen_rtx_PLUS (reg_mode,
     792                 :             :                                                                 inc_reg,
     793                 :             :                                                                 inc_insn.reg1)),
     794                 :           0 :                              inc_reg);
     795                 :             : 
     796                 :           0 :     case REG_PRE:            /* ++reg   */
     797                 :           0 :       if (dump_file)
     798                 :           0 :         fprintf (dump_file, "trying PRE_REG\n");
     799                 :           0 :       return attempt_change (gen_rtx_PRE_MODIFY (reg_mode,
     800                 :             :                                                  inc_reg,
     801                 :             :                                                  gen_rtx_PLUS (reg_mode,
     802                 :             :                                                                inc_reg,
     803                 :             :                                                                inc_insn.reg1)),
     804                 :           0 :                              inc_reg);
     805                 :             : 
     806                 :           0 :     case REG_POST:            /* reg++   */
     807                 :           0 :       if (dump_file)
     808                 :           0 :         fprintf (dump_file, "trying POST_REG\n");
     809                 :           0 :       return attempt_change (gen_rtx_POST_MODIFY (reg_mode,
     810                 :             :                                                   inc_reg,
     811                 :             :                                                   gen_rtx_PLUS (reg_mode,
     812                 :             :                                                                 inc_reg,
     813                 :             :                                                                 inc_insn.reg1)),
     814                 :           0 :                              inc_reg);
     815                 :             :     }
     816                 :             : }
     817                 :             : 
     818                 :             : /* Return the next insn that uses (if reg_next_use is passed in
     819                 :             :    NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY)
     820                 :             :    REGNO in BB.  */
     821                 :             : 
     822                 :             : static rtx_insn *
     823                 :           0 : get_next_ref (int regno, basic_block bb, rtx_insn **next_array)
     824                 :             : {
     825                 :           0 :   rtx_insn *insn = next_array[regno];
     826                 :             : 
     827                 :             :   /* Lazy about cleaning out the next_arrays.  */
     828                 :           0 :   if (insn && BLOCK_FOR_INSN (insn) != bb)
     829                 :             :     {
     830                 :           0 :       next_array[regno] = NULL;
     831                 :           0 :       insn = NULL;
     832                 :             :     }
     833                 :             : 
     834                 :           0 :   return insn;
     835                 :             : }
     836                 :             : 
     837                 :             : 
     838                 :             : /* Return true if INSN is of a form "a = b op c" where a and b are
     839                 :             :    regs.  op is + if c is a reg and +|- if c is a const.  Fill in
     840                 :             :    INC_INSN with what is found.
     841                 :             : 
     842                 :             :    This function is called in two contexts, if BEFORE_MEM is true,
     843                 :             :    this is called for each insn in the basic block.  If BEFORE_MEM is
     844                 :             :    false, it is called for the instruction in the block that uses the
     845                 :             :    index register for some memory reference that is currently being
     846                 :             :    processed.  */
     847                 :             : 
     848                 :             : static bool
     849                 :           0 : parse_add_or_inc (rtx_insn *insn, bool before_mem)
     850                 :             : {
     851                 :           0 :   rtx pat = single_set (insn);
     852                 :           0 :   if (!pat)
     853                 :             :     return false;
     854                 :             : 
     855                 :             :   /* Result must be single reg.  */
     856                 :           0 :   if (!REG_P (SET_DEST (pat)))
     857                 :             :     return false;
     858                 :             : 
     859                 :           0 :   if ((GET_CODE (SET_SRC (pat)) != PLUS)
     860                 :           0 :       && (GET_CODE (SET_SRC (pat)) != MINUS))
     861                 :             :     return false;
     862                 :             : 
     863                 :           0 :   if (!REG_P (XEXP (SET_SRC (pat), 0)))
     864                 :             :     return false;
     865                 :             : 
     866                 :           0 :   inc_insn.insn = insn;
     867                 :           0 :   inc_insn.pat = pat;
     868                 :           0 :   inc_insn.reg_res = SET_DEST (pat);
     869                 :           0 :   inc_insn.reg0 = XEXP (SET_SRC (pat), 0);
     870                 :             : 
     871                 :             :   /* Block any auto increment of the frame pointer since it expands into
     872                 :             :      an addition and cannot be removed by copy propagation.  */
     873                 :           0 :   if (inc_insn.reg0 == frame_pointer_rtx)
     874                 :             :     return false;
     875                 :             : 
     876                 :           0 :   if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg0))
     877                 :           0 :     inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
     878                 :             :   else
     879                 :           0 :     inc_insn.form = before_mem ? FORM_PRE_ADD : FORM_POST_ADD;
     880                 :             : 
     881                 :           0 :   if (CONST_INT_P (XEXP (SET_SRC (pat), 1)))
     882                 :             :     {
     883                 :             :       /* Process a = b + c where c is a const.  */
     884                 :           0 :       inc_insn.reg1_is_const = true;
     885                 :           0 :       if (GET_CODE (SET_SRC (pat)) == PLUS)
     886                 :             :         {
     887                 :           0 :           inc_insn.reg1 = XEXP (SET_SRC (pat), 1);
     888                 :           0 :           inc_insn.reg1_val = INTVAL (inc_insn.reg1);
     889                 :             :         }
     890                 :             :       else
     891                 :             :         {
     892                 :           0 :           inc_insn.reg1_val = -INTVAL (XEXP (SET_SRC (pat), 1));
     893                 :           0 :           inc_insn.reg1 = GEN_INT (inc_insn.reg1_val);
     894                 :             :         }
     895                 :           0 :       return true;
     896                 :             :     }
     897                 :             :   else if ((HAVE_PRE_MODIFY_REG || HAVE_POST_MODIFY_REG)
     898                 :             :            && (REG_P (XEXP (SET_SRC (pat), 1)))
     899                 :             :            && GET_CODE (SET_SRC (pat)) == PLUS)
     900                 :             :     {
     901                 :             :       /* Process a = b + c where c is a reg.  */
     902                 :             :       inc_insn.reg1 = XEXP (SET_SRC (pat), 1);
     903                 :             :       inc_insn.reg1_is_const = false;
     904                 :             : 
     905                 :             :       if (inc_insn.form == FORM_PRE_INC
     906                 :             :           || inc_insn.form == FORM_POST_INC)
     907                 :             :         return true;
     908                 :             :       else if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg1))
     909                 :             :         {
     910                 :             :           /* Reverse the two operands and turn *_ADD into *_INC since
     911                 :             :              a = c + a.  */
     912                 :             :           std::swap (inc_insn.reg0, inc_insn.reg1);
     913                 :             :           inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
     914                 :             :           return true;
     915                 :             :         }
     916                 :             :       else
     917                 :             :         return true;
     918                 :             :     }
     919                 :             : 
     920                 :             :   return false;
     921                 :             : }
     922                 :             : 
     923                 :             : 
     924                 :             : /* A recursive function that checks all of the mem uses in
     925                 :             :    ADDRESS_OF_X to see if any single one of them is compatible with
     926                 :             :    what has been found in inc_insn.  To avoid accidental matches, we
     927                 :             :    will only find MEMs with FINDREG, be it inc_insn.reg_res, be it
     928                 :             :    inc_insn.reg0.
     929                 :             : 
     930                 :             :    -1 is returned for success.  0 is returned if nothing was found and
     931                 :             :    1 is returned for failure. */
     932                 :             : 
     933                 :             : static int
     934                 :           0 : find_address (rtx *address_of_x, rtx findreg)
     935                 :             : {
     936                 :           0 :   rtx x = *address_of_x;
     937                 :           0 :   enum rtx_code code = GET_CODE (x);
     938                 :           0 :   const char *const fmt = GET_RTX_FORMAT (code);
     939                 :           0 :   int i;
     940                 :           0 :   int value = 0;
     941                 :           0 :   int tem;
     942                 :             : 
     943                 :           0 :   if (code == MEM && findreg == inc_insn.reg_res
     944                 :           0 :       && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res))
     945                 :             :     {
     946                 :             :       /* Match with *reg_res.  */
     947                 :           0 :       mem_insn.mem_loc = address_of_x;
     948                 :           0 :       mem_insn.reg0 = inc_insn.reg_res;
     949                 :           0 :       mem_insn.reg1_is_const = true;
     950                 :           0 :       mem_insn.reg1_val = 0;
     951                 :           0 :       mem_insn.reg1 = GEN_INT (0);
     952                 :           0 :       return -1;
     953                 :             :     }
     954                 :           0 :   if (code == MEM && inc_insn.reg1_is_const && inc_insn.reg0
     955                 :           0 :       && findreg == inc_insn.reg0
     956                 :           0 :       && rtx_equal_p (XEXP (x, 0), inc_insn.reg0))
     957                 :             :     {
     958                 :             :       /* Match with *reg0, assumed to be equivalent to
     959                 :             :          *(reg_res - reg1_val); callers must check whether this is the case.  */
     960                 :           0 :       mem_insn.mem_loc = address_of_x;
     961                 :           0 :       mem_insn.reg0 = inc_insn.reg_res;
     962                 :           0 :       mem_insn.reg1_is_const = true;
     963                 :           0 :       mem_insn.reg1_val = -inc_insn.reg1_val;
     964                 :           0 :       mem_insn.reg1 = GEN_INT (mem_insn.reg1_val);
     965                 :           0 :       return -1;
     966                 :             :     }
     967                 :           0 :   if (code == MEM && findreg == inc_insn.reg_res
     968                 :           0 :       && GET_CODE (XEXP (x, 0)) == PLUS
     969                 :           0 :       && rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res))
     970                 :             :     {
     971                 :           0 :       rtx b = XEXP (XEXP (x, 0), 1);
     972                 :           0 :       mem_insn.mem_loc = address_of_x;
     973                 :           0 :       mem_insn.reg0 = inc_insn.reg_res;
     974                 :           0 :       mem_insn.reg1 = b;
     975                 :           0 :       mem_insn.reg1_is_const = inc_insn.reg1_is_const;
     976                 :           0 :       if (CONST_INT_P (b))
     977                 :             :         {
     978                 :             :           /* Match with *(reg0 + reg1) where reg1 is a const. */
     979                 :           0 :           HOST_WIDE_INT val = INTVAL (b);
     980                 :           0 :           if (inc_insn.reg1_is_const
     981                 :           0 :               && (inc_insn.reg1_val == val || inc_insn.reg1_val == -val))
     982                 :             :             {
     983                 :           0 :               mem_insn.reg1_val = val;
     984                 :           0 :               return -1;
     985                 :             :             }
     986                 :             :         }
     987                 :           0 :       else if (!inc_insn.reg1_is_const
     988                 :           0 :                && rtx_equal_p (inc_insn.reg1, b))
     989                 :             :         /* Match with *(reg0 + reg1). */
     990                 :             :         return -1;
     991                 :             :     }
     992                 :             : 
     993                 :           0 :   if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
     994                 :             :     {
     995                 :             :       /* If REG occurs inside a MEM used in a bit-field reference,
     996                 :             :          that is unacceptable.  */
     997                 :           0 :       if (find_address (&XEXP (x, 0), findreg))
     998                 :             :         return 1;
     999                 :             :     }
    1000                 :             : 
    1001                 :           0 :   if (x == inc_insn.reg_res)
    1002                 :             :     return 1;
    1003                 :             : 
    1004                 :             :   /* Time for some deep diving.  */
    1005                 :           0 :   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    1006                 :             :     {
    1007                 :           0 :       if (fmt[i] == 'e')
    1008                 :             :         {
    1009                 :           0 :           tem = find_address (&XEXP (x, i), findreg);
    1010                 :             :           /* If this is the first use, let it go so the rest of the
    1011                 :             :              insn can be checked.  */
    1012                 :           0 :           if (value == 0)
    1013                 :             :             value = tem;
    1014                 :           0 :           else if (tem != 0)
    1015                 :             :             /* More than one match was found.  */
    1016                 :             :             return 1;
    1017                 :             :         }
    1018                 :           0 :       else if (fmt[i] == 'E')
    1019                 :             :         {
    1020                 :           0 :           int j;
    1021                 :           0 :           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
    1022                 :             :             {
    1023                 :           0 :               tem = find_address (&XVECEXP (x, i, j), findreg);
    1024                 :             :               /* If this is the first use, let it go so the rest of
    1025                 :             :                  the insn can be checked.  */
    1026                 :           0 :               if (value == 0)
    1027                 :             :                 value = tem;
    1028                 :           0 :               else if (tem != 0)
    1029                 :             :                 /* More than one match was found.  */
    1030                 :             :                 return 1;
    1031                 :             :             }
    1032                 :             :         }
    1033                 :             :     }
    1034                 :             :   return value;
    1035                 :             : }
    1036                 :             : 
    1037                 :             : /* Once a suitable mem reference has been found and the MEM_INSN
    1038                 :             :    structure has been filled in, FIND_INC is called to see if there is
    1039                 :             :    a suitable add or inc insn that follows the mem reference and
    1040                 :             :    determine if it is suitable to merge.
    1041                 :             : 
    1042                 :             :    In the case where the MEM_INSN has two registers in the reference,
    1043                 :             :    this function may be called recursively.  The first time looking
    1044                 :             :    for an add of the first register, and if that fails, looking for an
    1045                 :             :    add of the second register.  The FIRST_TRY parameter is used to
    1046                 :             :    only allow the parameters to be reversed once.  */
    1047                 :             : 
    1048                 :             : static bool
    1049                 :           0 : find_inc (bool first_try)
    1050                 :             : {
    1051                 :           0 :   rtx_insn *insn;
    1052                 :           0 :   basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
    1053                 :           0 :   rtx_insn *other_insn;
    1054                 :           0 :   df_ref def;
    1055                 :             : 
    1056                 :             :   /* Make sure this reg appears only once in this insn.  */
    1057                 :           0 :   if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1)
    1058                 :             :     {
    1059                 :           0 :       if (dump_file)
    1060                 :           0 :         fprintf (dump_file, "mem count failure\n");
    1061                 :           0 :       return false;
    1062                 :             :     }
    1063                 :             : 
    1064                 :           0 :   if (dump_file)
    1065                 :           0 :     dump_mem_insn (dump_file);
    1066                 :             : 
    1067                 :             :   /* Find the next use that is an inc.  */
    1068                 :           0 :   insn = get_next_ref (REGNO (mem_insn.reg0),
    1069                 :           0 :                        BLOCK_FOR_INSN (mem_insn.insn),
    1070                 :             :                        reg_next_inc_use);
    1071                 :           0 :   if (!insn)
    1072                 :           0 :     return false;
    1073                 :             : 
    1074                 :             :   /* Even though we know the next use is an add or inc because it came
    1075                 :             :      from the reg_next_inc_use, we must still reparse.  */
    1076                 :           0 :   if (!parse_add_or_inc (insn, false))
    1077                 :             :     {
    1078                 :             :       /* Next use was not an add.  Look for one extra case. It could be
    1079                 :             :          that we have:
    1080                 :             : 
    1081                 :             :          *(a + b)
    1082                 :             :          ...= a;
    1083                 :             :          ...= b + a
    1084                 :             : 
    1085                 :             :          if we reverse the operands in the mem ref we would
    1086                 :             :          find this.  Only try it once though.  */
    1087                 :           0 :       if (first_try && !mem_insn.reg1_is_const)
    1088                 :             :         {
    1089                 :           0 :           std::swap (mem_insn.reg0, mem_insn.reg1);
    1090                 :           0 :           return find_inc (false);
    1091                 :             :         }
    1092                 :             :       else
    1093                 :             :         return false;
    1094                 :             :     }
    1095                 :             : 
    1096                 :             :   /* Need to assure that none of the operands of the inc instruction are
    1097                 :             :      assigned to by the mem insn.  */
    1098                 :           0 :   FOR_EACH_INSN_DEF (def, mem_insn.insn)
    1099                 :             :     {
    1100                 :           0 :       unsigned int regno = DF_REF_REGNO (def);
    1101                 :           0 :       if ((regno == REGNO (inc_insn.reg0))
    1102                 :           0 :           || (regno == REGNO (inc_insn.reg_res)))
    1103                 :             :         {
    1104                 :           0 :           if (dump_file)
    1105                 :           0 :             fprintf (dump_file, "inc conflicts with store failure.\n");
    1106                 :           0 :           return false;
    1107                 :             :         }
    1108                 :           0 :       if (!inc_insn.reg1_is_const && (regno == REGNO (inc_insn.reg1)))
    1109                 :             :         {
    1110                 :           0 :           if (dump_file)
    1111                 :           0 :             fprintf (dump_file, "inc conflicts with store failure.\n");
    1112                 :           0 :           return false;
    1113                 :             :         }
    1114                 :             :     }
    1115                 :             : 
    1116                 :           0 :   if (dump_file)
    1117                 :           0 :     dump_inc_insn (dump_file);
    1118                 :             : 
    1119                 :           0 :   if (inc_insn.form == FORM_POST_ADD)
    1120                 :             :     {
    1121                 :             :       /* Make sure that there is no insn that assigns to inc_insn.res
    1122                 :             :          between the mem_insn and the inc_insn.  */
    1123                 :           0 :       rtx_insn *other_insn = get_next_ref (REGNO (inc_insn.reg_res),
    1124                 :           0 :                                            BLOCK_FOR_INSN (mem_insn.insn),
    1125                 :             :                                            reg_next_def);
    1126                 :           0 :       if (other_insn != inc_insn.insn)
    1127                 :             :         {
    1128                 :           0 :           if (dump_file)
    1129                 :           0 :             fprintf (dump_file,
    1130                 :             :                      "result of add is assigned to between mem and inc insns.\n");
    1131                 :           0 :           return false;
    1132                 :             :         }
    1133                 :             : 
    1134                 :           0 :       other_insn = get_next_ref (REGNO (inc_insn.reg_res),
    1135                 :           0 :                                  BLOCK_FOR_INSN (mem_insn.insn),
    1136                 :             :                                  reg_next_use);
    1137                 :           0 :       if (other_insn
    1138                 :           0 :           && (other_insn != inc_insn.insn)
    1139                 :           0 :           && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn)))
    1140                 :             :         {
    1141                 :           0 :           if (dump_file)
    1142                 :           0 :             fprintf (dump_file,
    1143                 :             :                      "result of add is used between mem and inc insns.\n");
    1144                 :           0 :           return false;
    1145                 :             :         }
    1146                 :             : 
    1147                 :             :       /* For the post_add to work, the result_reg of the inc must not be
    1148                 :             :          used in the mem insn since this will become the new index
    1149                 :             :          register.  */
    1150                 :           0 :       if (reg_overlap_mentioned_p (inc_insn.reg_res, PATTERN (mem_insn.insn)))
    1151                 :             :         {
    1152                 :           0 :           if (dump_file)
    1153                 :           0 :             fprintf (dump_file, "base reg replacement failure.\n");
    1154                 :           0 :           return false;
    1155                 :             :         }
    1156                 :             :     }
    1157                 :             : 
    1158                 :           0 :   if (mem_insn.reg1_is_const)
    1159                 :             :     {
    1160                 :           0 :       if (mem_insn.reg1_val == 0)
    1161                 :             :         {
    1162                 :           0 :           if (!inc_insn.reg1_is_const)
    1163                 :             :             {
    1164                 :             :               /* The mem looks like *r0 and the rhs of the add has two
    1165                 :             :                  registers.  */
    1166                 :           0 :               int luid = DF_INSN_LUID (inc_insn.insn);
    1167                 :           0 :               if (inc_insn.form == FORM_POST_ADD)
    1168                 :             :                 {
    1169                 :             :                   /* The trick is that we are not going to increment r0,
    1170                 :             :                      we are going to increment the result of the add insn.
    1171                 :             :                      For this trick to be correct, the result reg of
    1172                 :             :                      the inc must be a valid addressing reg.  */
    1173                 :           0 :                   addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
    1174                 :           0 :                   if (GET_MODE (inc_insn.reg_res)
    1175                 :           0 :                       != targetm.addr_space.address_mode (as))
    1176                 :             :                     {
    1177                 :           0 :                       if (dump_file)
    1178                 :           0 :                         fprintf (dump_file, "base reg mode failure.\n");
    1179                 :           0 :                       return false;
    1180                 :             :                     }
    1181                 :             : 
    1182                 :             :                   /* We also need to make sure that the next use of
    1183                 :             :                      inc result is after the inc.  */
    1184                 :           0 :                   other_insn
    1185                 :           0 :                     = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
    1186                 :           0 :                   if (other_insn && luid > DF_INSN_LUID (other_insn))
    1187                 :             :                     return false;
    1188                 :             : 
    1189                 :           0 :                   if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
    1190                 :           0 :                     std::swap (inc_insn.reg0, inc_insn.reg1);
    1191                 :             :                 }
    1192                 :             : 
    1193                 :           0 :               other_insn
    1194                 :           0 :                 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
    1195                 :           0 :               if (other_insn && luid > DF_INSN_LUID (other_insn))
    1196                 :             :                 return false;
    1197                 :             :             }
    1198                 :             :         }
    1199                 :             :       /* Both the inc/add and the mem have a constant.  Need to check
    1200                 :             :          that the constants are ok. */
    1201                 :           0 :       else if ((mem_insn.reg1_val != inc_insn.reg1_val)
    1202                 :           0 :                && (mem_insn.reg1_val != -inc_insn.reg1_val))
    1203                 :             :         return false;
    1204                 :             :     }
    1205                 :             :   else
    1206                 :             :     {
    1207                 :             :       /* The mem insn is of the form *(a + b) where a and b are both
    1208                 :             :          regs.  It may be that in order to match the add or inc we
    1209                 :             :          need to treat it as if it was *(b + a).  It may also be that
    1210                 :             :          the add is of the form a + c where c does not match b and
    1211                 :             :          then we just abandon this.  */
    1212                 :             : 
    1213                 :           0 :       int luid = DF_INSN_LUID (inc_insn.insn);
    1214                 :           0 :       rtx_insn *other_insn;
    1215                 :             : 
    1216                 :             :       /* Make sure this reg appears only once in this insn.  */
    1217                 :           0 :       if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1)
    1218                 :             :         return false;
    1219                 :             : 
    1220                 :           0 :       if (inc_insn.form == FORM_POST_ADD)
    1221                 :             :         {
    1222                 :             :           /* For this trick to be correct, the result reg of the inc
    1223                 :             :              must be a valid addressing reg.  */
    1224                 :           0 :           addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc);
    1225                 :           0 :           if (GET_MODE (inc_insn.reg_res)
    1226                 :           0 :               != targetm.addr_space.address_mode (as))
    1227                 :             :             {
    1228                 :           0 :               if (dump_file)
    1229                 :           0 :                 fprintf (dump_file, "base reg mode failure.\n");
    1230                 :           0 :               return false;
    1231                 :             :             }
    1232                 :             : 
    1233                 :           0 :           if (rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
    1234                 :             :             {
    1235                 :           0 :               if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
    1236                 :             :                 {
    1237                 :             :                   /* See comment above on find_inc (false) call.  */
    1238                 :           0 :                   if (first_try)
    1239                 :             :                     {
    1240                 :           0 :                       std::swap (mem_insn.reg0, mem_insn.reg1);
    1241                 :           0 :                       return find_inc (false);
    1242                 :             :                     }
    1243                 :             :                   else
    1244                 :             :                     return false;
    1245                 :             :                 }
    1246                 :             : 
    1247                 :             :               /* Need to check that there are no assignments to b
    1248                 :             :                  before the add insn.  */
    1249                 :           0 :               other_insn
    1250                 :           0 :                 = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
    1251                 :           0 :               if (other_insn && luid > DF_INSN_LUID (other_insn))
    1252                 :             :                 return false;
    1253                 :             :               /* All ok for the next step.  */
    1254                 :             :             }
    1255                 :             :           else
    1256                 :             :             {
    1257                 :             :               /* We know that mem_insn.reg0 must equal inc_insn.reg1
    1258                 :             :                  or else we would not have found the inc insn.  */
    1259                 :           0 :               std::swap (mem_insn.reg0, mem_insn.reg1);
    1260                 :           0 :               if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
    1261                 :             :                 {
    1262                 :             :                   /* See comment above on find_inc (false) call.  */
    1263                 :           0 :                   if (first_try)
    1264                 :           0 :                     return find_inc (false);
    1265                 :             :                   else
    1266                 :             :                     return false;
    1267                 :             :                 }
    1268                 :             :               /* To have gotten here know that.
    1269                 :             :                *(b + a)
    1270                 :             : 
    1271                 :             :                ... = (b + a)
    1272                 :             : 
    1273                 :             :                We also know that the lhs of the inc is not b or a.  We
    1274                 :             :                need to make sure that there are no assignments to b
    1275                 :             :                between the mem ref and the inc.  */
    1276                 :             : 
    1277                 :           0 :               other_insn
    1278                 :           0 :                 = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def);
    1279                 :           0 :               if (other_insn && luid > DF_INSN_LUID (other_insn))
    1280                 :             :                 return false;
    1281                 :             :             }
    1282                 :             : 
    1283                 :             :           /* Need to check that the next use of the add result is later than
    1284                 :             :              add insn since this will be the reg incremented.  */
    1285                 :           0 :           other_insn
    1286                 :           0 :             = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use);
    1287                 :           0 :           if (other_insn && luid > DF_INSN_LUID (other_insn))
    1288                 :             :             return false;
    1289                 :             :         }
    1290                 :             :       else /* FORM_POST_INC.  There is less to check here because we
    1291                 :             :               know that operands must line up.  */
    1292                 :             :         {
    1293                 :           0 :           if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1))
    1294                 :             :             /* See comment above on find_inc (false) call.  */
    1295                 :             :             {
    1296                 :           0 :               if (first_try)
    1297                 :             :                 {
    1298                 :           0 :                   std::swap (mem_insn.reg0, mem_insn.reg1);
    1299                 :           0 :                   return find_inc (false);
    1300                 :             :                 }
    1301                 :             :               else
    1302                 :             :                 return false;
    1303                 :             :             }
    1304                 :             : 
    1305                 :             :           /* To have gotten here know that.
    1306                 :             :            *(a + b)
    1307                 :             : 
    1308                 :             :            ... = (a + b)
    1309                 :             : 
    1310                 :             :            We also know that the lhs of the inc is not b.  We need to make
    1311                 :             :            sure that there are no assignments to b between the mem ref and
    1312                 :             :            the inc.  */
    1313                 :           0 :           other_insn
    1314                 :           0 :             = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
    1315                 :           0 :           if (other_insn && luid > DF_INSN_LUID (other_insn))
    1316                 :             :             return false;
    1317                 :             :         }
    1318                 :             :     }
    1319                 :             : 
    1320                 :           0 :   if (inc_insn.form == FORM_POST_INC)
    1321                 :             :     {
    1322                 :           0 :       other_insn
    1323                 :           0 :         = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use);
    1324                 :             :       /* When we found inc_insn, we were looking for the
    1325                 :             :          next add or inc, not the next insn that used the
    1326                 :             :          reg.  Because we are going to increment the reg
    1327                 :             :          in this form, we need to make sure that there
    1328                 :             :          were no intervening uses of reg.  */
    1329                 :           0 :       if (inc_insn.insn != other_insn)
    1330                 :             :         return false;
    1331                 :             :     }
    1332                 :             : 
    1333                 :           0 :   return try_merge ();
    1334                 :             : }
    1335                 :             : 
    1336                 :             : 
    1337                 :             : /* A recursive function that walks ADDRESS_OF_X to find all of the mem
    1338                 :             :    uses in pat that could be used as an auto inc or dec.  It then
    1339                 :             :    calls FIND_INC for each one.  */
    1340                 :             : 
    1341                 :             : static bool
    1342                 :           0 : find_mem (rtx *address_of_x)
    1343                 :             : {
    1344                 :           0 :   rtx x = *address_of_x;
    1345                 :           0 :   enum rtx_code code = GET_CODE (x);
    1346                 :           0 :   const char *const fmt = GET_RTX_FORMAT (code);
    1347                 :           0 :   int i;
    1348                 :             : 
    1349                 :           0 :   if (code == MEM && REG_P (XEXP (x, 0)))
    1350                 :             :     {
    1351                 :             :       /* Match with *reg0.  */
    1352                 :           0 :       mem_insn.mem_loc = address_of_x;
    1353                 :           0 :       mem_insn.reg0 = XEXP (x, 0);
    1354                 :           0 :       mem_insn.reg1_is_const = true;
    1355                 :           0 :       mem_insn.reg1_val = 0;
    1356                 :           0 :       mem_insn.reg1 = GEN_INT (0);
    1357                 :           0 :       if (find_inc (true))
    1358                 :             :         return true;
    1359                 :             :     }
    1360                 :           0 :   if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
    1361                 :           0 :       && REG_P (XEXP (XEXP (x, 0), 0)))
    1362                 :             :     {
    1363                 :           0 :       rtx reg1 = XEXP (XEXP (x, 0), 1);
    1364                 :           0 :       mem_insn.mem_loc = address_of_x;
    1365                 :           0 :       mem_insn.reg0 = XEXP (XEXP (x, 0), 0);
    1366                 :           0 :       mem_insn.reg1 = reg1;
    1367                 :           0 :       if (CONST_INT_P (reg1))
    1368                 :             :         {
    1369                 :           0 :           mem_insn.reg1_is_const = true;
    1370                 :             :           /* Match with *(reg0 + c) where c is a const. */
    1371                 :           0 :           mem_insn.reg1_val = INTVAL (reg1);
    1372                 :           0 :           if (find_inc (true))
    1373                 :             :             return true;
    1374                 :             :         }
    1375                 :           0 :       else if (REG_P (reg1))
    1376                 :             :         {
    1377                 :             :           /* Match with *(reg0 + reg1).  */
    1378                 :           0 :           mem_insn.reg1_is_const = false;
    1379                 :           0 :           if (find_inc (true))
    1380                 :             :             return true;
    1381                 :             :         }
    1382                 :             :     }
    1383                 :             : 
    1384                 :           0 :   if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
    1385                 :             :     {
    1386                 :             :       /* If REG occurs inside a MEM used in a bit-field reference,
    1387                 :             :          that is unacceptable.  */
    1388                 :             :       return false;
    1389                 :             :     }
    1390                 :             : 
    1391                 :             :   /* Time for some deep diving.  */
    1392                 :           0 :   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
    1393                 :             :     {
    1394                 :           0 :       if (fmt[i] == 'e')
    1395                 :             :         {
    1396                 :           0 :           if (find_mem (&XEXP (x, i)))
    1397                 :             :             return true;
    1398                 :             :         }
    1399                 :           0 :       else if (fmt[i] == 'E')
    1400                 :             :         {
    1401                 :           0 :           int j;
    1402                 :           0 :           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
    1403                 :           0 :             if (find_mem (&XVECEXP (x, i, j)))
    1404                 :             :               return true;
    1405                 :             :         }
    1406                 :             :     }
    1407                 :             :   return false;
    1408                 :             : }
    1409                 :             : 
    1410                 :             : 
    1411                 :             : /* Try to combine all incs and decs by constant values with memory
    1412                 :             :    references in BB.  */
    1413                 :             : 
    1414                 :             : static void
    1415                 :           0 : merge_in_block (int max_reg, basic_block bb)
    1416                 :             : {
    1417                 :           0 :   rtx_insn *insn;
    1418                 :           0 :   rtx_insn *curr;
    1419                 :           0 :   int success_in_block = 0;
    1420                 :             : 
    1421                 :           0 :   if (dump_file)
    1422                 :           0 :     fprintf (dump_file, "\n\nstarting bb %d\n", bb->index);
    1423                 :             : 
    1424                 :           0 :   FOR_BB_INSNS_REVERSE_SAFE (bb, insn, curr)
    1425                 :             :     {
    1426                 :           0 :       bool insn_is_add_or_inc = true;
    1427                 :             : 
    1428                 :           0 :       if (!NONDEBUG_INSN_P (insn))
    1429                 :             :         {
    1430                 :           0 :           if (DEBUG_BIND_INSN_P (insn))
    1431                 :             :             {
    1432                 :           0 :               df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
    1433                 :           0 :               df_ref use;
    1434                 :             : 
    1435                 :           0 :               if (dump_file)
    1436                 :           0 :                 dump_insn_slim (dump_file, insn);
    1437                 :             : 
    1438                 :           0 :               FOR_EACH_INSN_INFO_USE (use, insn_info)
    1439                 :           0 :                 reg_next_debug_use[DF_REF_REGNO (use)] = insn;
    1440                 :             :             }
    1441                 :           0 :           continue;
    1442                 :           0 :         }
    1443                 :             : 
    1444                 :             :       /* Reload should handle auto-inc within a jump correctly, while LRA
    1445                 :             :          is known to have issues with autoinc.  */
    1446                 :           0 :       if (JUMP_P (insn) && targetm.lra_p ())
    1447                 :           0 :         continue;
    1448                 :             : 
    1449                 :           0 :       if (dump_file)
    1450                 :           0 :         dump_insn_slim (dump_file, insn);
    1451                 :             : 
    1452                 :             :       /* Does this instruction increment or decrement a register?  */
    1453                 :           0 :       if (parse_add_or_inc (insn, true))
    1454                 :             :         {
    1455                 :           0 :           int regno = REGNO (inc_insn.reg_res);
    1456                 :             :           /* Cannot handle case where there are three separate regs
    1457                 :             :              before a mem ref.  Too many moves would be needed to be
    1458                 :             :              profitable.  */
    1459                 :           0 :           if ((inc_insn.form == FORM_PRE_INC) || inc_insn.reg1_is_const)
    1460                 :             :             {
    1461                 :           0 :               mem_insn.insn = get_next_ref (regno, bb, reg_next_use);
    1462                 :           0 :               if (mem_insn.insn)
    1463                 :             :                 {
    1464                 :           0 :                   bool ok = true;
    1465                 :           0 :                   if (!inc_insn.reg1_is_const)
    1466                 :             :                     {
    1467                 :             :                       /* We are only here if we are going to try a
    1468                 :             :                          HAVE_*_MODIFY_REG type transformation.  c is a
    1469                 :             :                          reg and we must sure that the path from the
    1470                 :             :                          inc_insn to the mem_insn.insn is both def and use
    1471                 :             :                          clear of c because the inc insn is going to move
    1472                 :             :                          into the mem_insn.insn.  */
    1473                 :           0 :                       int luid = DF_INSN_LUID (mem_insn.insn);
    1474                 :           0 :                       rtx_insn *other_insn
    1475                 :           0 :                         = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
    1476                 :             : 
    1477                 :           0 :                       if (other_insn && luid > DF_INSN_LUID (other_insn))
    1478                 :             :                         ok = false;
    1479                 :             : 
    1480                 :           0 :                       other_insn
    1481                 :           0 :                         = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def);
    1482                 :             : 
    1483                 :           0 :                       if (other_insn && luid > DF_INSN_LUID (other_insn))
    1484                 :             :                         ok = false;
    1485                 :             :                     }
    1486                 :             : 
    1487                 :           0 :                   if (dump_file)
    1488                 :           0 :                     dump_inc_insn (dump_file);
    1489                 :             : 
    1490                 :           0 :                   if (ok && find_address (&PATTERN (mem_insn.insn),
    1491                 :             :                                           inc_insn.reg_res) == -1)
    1492                 :             :                     {
    1493                 :           0 :                       if (dump_file)
    1494                 :           0 :                         dump_mem_insn (dump_file);
    1495                 :           0 :                       if (try_merge ())
    1496                 :             :                         {
    1497                 :           0 :                           success_in_block++;
    1498                 :           0 :                           insn_is_add_or_inc = false;
    1499                 :             :                         }
    1500                 :             :                     }
    1501                 :             :                 }
    1502                 :             : 
    1503                 :           0 :               if (insn_is_add_or_inc
    1504                 :             :                   /* find_address will only recognize an address
    1505                 :             :                      with a reg0 that's not reg_res when
    1506                 :             :                      reg1_is_const, so cut it off early if we
    1507                 :             :                      already know it won't match.  */
    1508                 :           0 :                   && inc_insn.reg1_is_const
    1509                 :           0 :                   && inc_insn.reg0
    1510                 :           0 :                   && inc_insn.reg0 != inc_insn.reg_res)
    1511                 :             :                 {
    1512                 :             :                   /* If we identified an inc_insn that uses two
    1513                 :             :                      different pseudos, it's of the form
    1514                 :             : 
    1515                 :             :                      (set reg_res (plus reg0 reg1))
    1516                 :             : 
    1517                 :             :                      where reg1 is a constant (*).
    1518                 :             : 
    1519                 :             :                      The next use of reg_res was not identified by
    1520                 :             :                      find_address as a mem_insn that we could turn
    1521                 :             :                      into auto-inc, so see if we find a suitable
    1522                 :             :                      MEM in the next use of reg0, as long as it's
    1523                 :             :                      before any subsequent use of reg_res:
    1524                 :             : 
    1525                 :             :                      ... (mem (... reg0 ...)) ...
    1526                 :             : 
    1527                 :             :                      ... reg_res ...
    1528                 :             : 
    1529                 :             :                      In this case, we can turn the plus into a
    1530                 :             :                      copy, and the reg0 in the MEM address into a
    1531                 :             :                      post_inc of reg_res:
    1532                 :             : 
    1533                 :             :                      (set reg_res reg0)
    1534                 :             : 
    1535                 :             :                      ... (mem (... (post_add reg_res reg1) ...)) ...
    1536                 :             : 
    1537                 :             :                      reg_res will then have the correct value at
    1538                 :             :                      subsequent uses, and reg0 will remain
    1539                 :             :                      unchanged.
    1540                 :             : 
    1541                 :             :                      (*) We could support non-const reg1, but then
    1542                 :             :                      we'd have to check that reg1 remains
    1543                 :             :                      unchanged all the way to the modified MEM,
    1544                 :             :                      and we'd have to extend find_address to
    1545                 :             :                      represent a non-const negated reg1.  */
    1546                 :           0 :                   regno = REGNO (inc_insn.reg0);
    1547                 :           0 :                   rtx_insn *reg0_use = get_next_ref (regno, bb,
    1548                 :             :                                                      reg_next_use);
    1549                 :             : 
    1550                 :             :                   /* Give up if the next use of reg0 is after the next
    1551                 :             :                      use of reg_res (same insn is ok; we might have
    1552                 :             :                      found a MEM with reg_res before, and that failed,
    1553                 :             :                      but now we try reg0, which might work), or defs
    1554                 :             :                      of reg_res (same insn is not ok, we'd introduce
    1555                 :             :                      another def in the same insn) or reg0.  */
    1556                 :           0 :                   if (reg0_use)
    1557                 :             :                     {
    1558                 :           0 :                       int luid = DF_INSN_LUID (reg0_use);
    1559                 :             : 
    1560                 :             :                       /* It might seem pointless to introduce an
    1561                 :             :                          auto-inc if there's no subsequent use of
    1562                 :             :                          reg_res (i.e., mem_insn.insn == NULL), but
    1563                 :             :                          the next use might be in the next iteration
    1564                 :             :                          of a loop, and it won't hurt if we make the
    1565                 :             :                          change even if it's not needed.  */
    1566                 :           0 :                       if (mem_insn.insn
    1567                 :           0 :                           && luid > DF_INSN_LUID (mem_insn.insn))
    1568                 :             :                         reg0_use = NULL;
    1569                 :             : 
    1570                 :           0 :                       rtx_insn *other_insn
    1571                 :           0 :                         = get_next_ref (REGNO (inc_insn.reg_res), bb,
    1572                 :             :                                         reg_next_def);
    1573                 :             : 
    1574                 :           0 :                       if (other_insn && luid >= DF_INSN_LUID (other_insn))
    1575                 :             :                         reg0_use = NULL;
    1576                 :             : 
    1577                 :           0 :                       other_insn
    1578                 :           0 :                         = get_next_ref (REGNO (inc_insn.reg0), bb,
    1579                 :             :                                         reg_next_def);
    1580                 :             : 
    1581                 :           0 :                       if (other_insn && luid > DF_INSN_LUID (other_insn))
    1582                 :             :                         reg0_use = NULL;
    1583                 :             :                     }
    1584                 :             : 
    1585                 :           0 :                   mem_insn.insn = reg0_use;
    1586                 :             : 
    1587                 :           0 :                   if (mem_insn.insn
    1588                 :           0 :                       && find_address (&PATTERN (mem_insn.insn),
    1589                 :             :                                        inc_insn.reg0) == -1)
    1590                 :             :                     {
    1591                 :           0 :                       if (dump_file)
    1592                 :           0 :                         dump_mem_insn (dump_file);
    1593                 :           0 :                       if (try_merge ())
    1594                 :             :                         {
    1595                 :           0 :                           success_in_block++;
    1596                 :           0 :                           insn_is_add_or_inc = false;
    1597                 :             :                         }
    1598                 :             :                     }
    1599                 :             :                 }
    1600                 :             :             }
    1601                 :             :         }
    1602                 :             :       else
    1603                 :             :         {
    1604                 :           0 :           insn_is_add_or_inc = false;
    1605                 :             :           /* We can't use auto inc/dec for bare USEs and CLOBBERs,
    1606                 :             :              since they aren't supposed to generate any code.  */
    1607                 :           0 :           rtx_code code = GET_CODE (PATTERN (insn));
    1608                 :           0 :           if (code != USE && code != CLOBBER)
    1609                 :             :             {
    1610                 :           0 :               mem_insn.insn = insn;
    1611                 :           0 :               if (find_mem (&PATTERN (insn)))
    1612                 :           0 :                 success_in_block++;
    1613                 :             :             }
    1614                 :             :         }
    1615                 :             : 
    1616                 :             :       /* If the inc insn was merged with a mem, the inc insn is gone
    1617                 :             :          and there is noting to update.  */
    1618                 :           0 :       if (df_insn_info *insn_info = DF_INSN_INFO_GET (insn))
    1619                 :             :         {
    1620                 :           0 :           df_ref def, use;
    1621                 :             : 
    1622                 :             :           /* Need to update next use.  */
    1623                 :           0 :           FOR_EACH_INSN_INFO_DEF (def, insn_info)
    1624                 :             :             {
    1625                 :           0 :               if (reg_next_debug_use)
    1626                 :           0 :                 reg_next_debug_use[DF_REF_REGNO (def)] = NULL;
    1627                 :           0 :               reg_next_use[DF_REF_REGNO (def)] = NULL;
    1628                 :           0 :               reg_next_inc_use[DF_REF_REGNO (def)] = NULL;
    1629                 :           0 :               reg_next_def[DF_REF_REGNO (def)] = insn;
    1630                 :             :             }
    1631                 :             : 
    1632                 :           0 :           FOR_EACH_INSN_INFO_USE (use, insn_info)
    1633                 :             :             {
    1634                 :           0 :               if (reg_next_debug_use)
    1635                 :             :                 /* This may seem surprising, but we know we may only
    1636                 :             :                    modify the value of a REG between an insn and the
    1637                 :             :                    next nondebug use thereof.  Any debug uses after
    1638                 :             :                    the next nondebug use can be left alone, the REG
    1639                 :             :                    will hold the expected value there.  */
    1640                 :           0 :                 reg_next_debug_use[DF_REF_REGNO (use)] = NULL;
    1641                 :           0 :               reg_next_use[DF_REF_REGNO (use)] = insn;
    1642                 :           0 :               if (insn_is_add_or_inc)
    1643                 :           0 :                 reg_next_inc_use[DF_REF_REGNO (use)] = insn;
    1644                 :             :               else
    1645                 :           0 :                 reg_next_inc_use[DF_REF_REGNO (use)] = NULL;
    1646                 :             :             }
    1647                 :             :         }
    1648                 :           0 :       else if (dump_file)
    1649                 :           0 :         fprintf (dump_file, "skipping update of deleted insn %d\n",
    1650                 :             :                  INSN_UID (insn));
    1651                 :             :     }
    1652                 :             : 
    1653                 :             :   /* If we were successful, try again.  There may have been several
    1654                 :             :      opportunities that were interleaved.  This is rare but
    1655                 :             :      gcc.c-torture/compile/pr17273.c actually exhibits this.  */
    1656                 :           0 :   if (success_in_block)
    1657                 :             :     {
    1658                 :             :       /* In this case, we must clear these vectors since the trick of
    1659                 :             :          testing if the stale insn in the block will not work.  */
    1660                 :           0 :       if (reg_next_debug_use)
    1661                 :           0 :         memset (reg_next_debug_use, 0, max_reg * sizeof (rtx));
    1662                 :           0 :       memset (reg_next_use, 0, max_reg * sizeof (rtx));
    1663                 :           0 :       memset (reg_next_inc_use, 0, max_reg * sizeof (rtx));
    1664                 :           0 :       memset (reg_next_def, 0, max_reg * sizeof (rtx));
    1665                 :           0 :       df_recompute_luids (bb);
    1666                 :           0 :       merge_in_block (max_reg, bb);
    1667                 :             :     }
    1668                 :           0 : }
    1669                 :             : 
    1670                 :             : /* Discover auto-inc auto-dec instructions.  */
    1671                 :             : 
    1672                 :             : namespace {
    1673                 :             : 
    1674                 :             : const pass_data pass_data_inc_dec =
    1675                 :             : {
    1676                 :             :   RTL_PASS, /* type */
    1677                 :             :   "auto_inc_dec", /* name */
    1678                 :             :   OPTGROUP_NONE, /* optinfo_flags */
    1679                 :             :   TV_AUTO_INC_DEC, /* tv_id */
    1680                 :             :   0, /* properties_required */
    1681                 :             :   0, /* properties_provided */
    1682                 :             :   0, /* properties_destroyed */
    1683                 :             :   0, /* todo_flags_start */
    1684                 :             :   TODO_df_finish, /* todo_flags_finish */
    1685                 :             : };
    1686                 :             : 
    1687                 :             : class pass_inc_dec : public rtl_opt_pass
    1688                 :             : {
    1689                 :             : public:
    1690                 :      285617 :   pass_inc_dec (gcc::context *ctxt)
    1691                 :      571234 :     : rtl_opt_pass (pass_data_inc_dec, ctxt)
    1692                 :             :   {}
    1693                 :             : 
    1694                 :             :   /* opt_pass methods: */
    1695                 :     1419745 :   bool gate (function *) final override
    1696                 :             :     {
    1697                 :     1419745 :       if (!AUTO_INC_DEC)
    1698                 :     1419745 :         return false;
    1699                 :             : 
    1700                 :             :       return (optimize > 0 && flag_auto_inc_dec);
    1701                 :             :     }
    1702                 :             : 
    1703                 :             : 
    1704                 :             :   unsigned int execute (function *) final override;
    1705                 :             : 
    1706                 :             : }; // class pass_inc_dec
    1707                 :             : 
    1708                 :             : unsigned int
    1709                 :           0 : pass_inc_dec::execute (function *fun ATTRIBUTE_UNUSED)
    1710                 :             : {
    1711                 :           0 :   if (!AUTO_INC_DEC)
    1712                 :           0 :     return 0;
    1713                 :             : 
    1714                 :             :   basic_block bb;
    1715                 :             :   int max_reg = max_reg_num ();
    1716                 :             : 
    1717                 :             :   if (!initialized)
    1718                 :             :     init_decision_table ();
    1719                 :             : 
    1720                 :             :   mem_tmp = gen_rtx_MEM (Pmode, NULL_RTX);
    1721                 :             : 
    1722                 :             :   df_note_add_problem ();
    1723                 :             :   df_analyze ();
    1724                 :             : 
    1725                 :             :   if (MAY_HAVE_DEBUG_BIND_INSNS)
    1726                 :             :     reg_next_debug_use = XCNEWVEC (rtx_insn *, max_reg);
    1727                 :             :   else
    1728                 :             :     /* An earlier function may have had debug binds.  */
    1729                 :             :     reg_next_debug_use = NULL;
    1730                 :             :   reg_next_use = XCNEWVEC (rtx_insn *, max_reg);
    1731                 :             :   reg_next_inc_use = XCNEWVEC (rtx_insn *, max_reg);
    1732                 :             :   reg_next_def = XCNEWVEC (rtx_insn *, max_reg);
    1733                 :             :   FOR_EACH_BB_FN (bb, fun)
    1734                 :             :     merge_in_block (max_reg, bb);
    1735                 :             : 
    1736                 :             :   free (reg_next_debug_use);
    1737                 :             :   free (reg_next_use);
    1738                 :             :   free (reg_next_inc_use);
    1739                 :             :   free (reg_next_def);
    1740                 :             : 
    1741                 :             :   mem_tmp = NULL;
    1742                 :             : 
    1743                 :             :   return 0;
    1744                 :             : }
    1745                 :             : 
    1746                 :             : } // anon namespace
    1747                 :             : 
    1748                 :             : rtl_opt_pass *
    1749                 :      285617 : make_pass_inc_dec (gcc::context *ctxt)
    1750                 :             : {
    1751                 :      285617 :   return new pass_inc_dec (ctxt);
    1752                 :             : }
        

Generated by: LCOV version 2.0-1

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.