LCOV - code coverage report
Current view: top level - gcc - mode-switching.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 66.0 % 520 343
Test Date: 2024-04-20 14:03:02 Functions: 50.0 % 20 10
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* CPU mode switching
       2                 :             :    Copyright (C) 1998-2024 Free Software Foundation, Inc.
       3                 :             : 
       4                 :             : This file is part of GCC.
       5                 :             : 
       6                 :             : GCC is free software; you can redistribute it and/or modify it under
       7                 :             : the terms of the GNU General Public License as published by the Free
       8                 :             : Software Foundation; either version 3, or (at your option) any later
       9                 :             : version.
      10                 :             : 
      11                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14                 :             : for more details.
      15                 :             : 
      16                 :             : You should have received a copy of the GNU General Public License
      17                 :             : along with GCC; see the file COPYING3.  If not see
      18                 :             : <http://www.gnu.org/licenses/>.  */
      19                 :             : 
      20                 :             : #include "config.h"
      21                 :             : #include "system.h"
      22                 :             : #include "coretypes.h"
      23                 :             : #include "backend.h"
      24                 :             : #include "target.h"
      25                 :             : #include "rtl.h"
      26                 :             : #include "cfghooks.h"
      27                 :             : #include "df.h"
      28                 :             : #include "memmodel.h"
      29                 :             : #include "tm_p.h"
      30                 :             : #include "regs.h"
      31                 :             : #include "emit-rtl.h"
      32                 :             : #include "cfgrtl.h"
      33                 :             : #include "cfganal.h"
      34                 :             : #include "lcm.h"
      35                 :             : #include "cfgcleanup.h"
      36                 :             : #include "tree-pass.h"
      37                 :             : #include "cfgbuild.h"
      38                 :             : 
      39                 :             : /* We want target macros for the mode switching code to be able to refer
      40                 :             :    to instruction attribute values.  */
      41                 :             : #include "insn-attr.h"
      42                 :             : 
      43                 :             : #ifdef OPTIMIZE_MODE_SWITCHING
      44                 :             : 
      45                 :             : /* The algorithm for setting the modes consists of scanning the insn list
      46                 :             :    and finding all the insns which require a specific mode.  Each insn gets
      47                 :             :    a unique struct seginfo element.  These structures are inserted into a list
      48                 :             :    for each basic block.  For each entity, there is an array of bb_info over
      49                 :             :    the flow graph basic blocks (local var 'bb_info'), which contains a list
      50                 :             :    of all insns within that basic block, in the order they are encountered.
      51                 :             : 
      52                 :             :    For each entity, any basic block WITHOUT any insns requiring a specific
      53                 :             :    mode are given a single entry without a mode (each basic block in the
      54                 :             :    flow graph must have at least one entry in the segment table).
      55                 :             : 
      56                 :             :    The LCM algorithm is then run over the flow graph to determine where to
      57                 :             :    place the sets to the highest-priority mode with respect to the first
      58                 :             :    insn in any one block.  Any adjustments required to the transparency
      59                 :             :    vectors are made, then the next iteration starts for the next-lower
      60                 :             :    priority mode, till for each entity all modes are exhausted.
      61                 :             : 
      62                 :             :    More details can be found in the code of optimize_mode_switching.  */
      63                 :             : 
      64                 :             : /* This structure contains the information for each insn which requires
      65                 :             :    either single or double mode to be set.
      66                 :             :    MODE is the mode this insn must be executed in.
      67                 :             :    INSN_PTR is the insn to be executed (may be the note that marks the
      68                 :             :    beginning of a basic block).
      69                 :             :    NEXT is the next insn in the same basic block.  */
      70                 :             : struct seginfo
      71                 :             : {
      72                 :             :   int prev_mode;
      73                 :             :   int mode;
      74                 :             :   rtx_insn *insn_ptr;
      75                 :             :   struct seginfo *next;
      76                 :             :   HARD_REG_SET regs_live;
      77                 :             : };
      78                 :             : 
      79                 :             : struct bb_info
      80                 :             : {
      81                 :             :   struct seginfo *seginfo;
      82                 :             :   int computing;
      83                 :             :   int mode_out;
      84                 :             :   int mode_in;
      85                 :             :   int single_succ;
      86                 :             : };
      87                 :             : 
      88                 :             : /* Clear ode I from entity J in bitmap B.  */
      89                 :             : #define clear_mode_bit(b, j, i) \
      90                 :             :        bitmap_clear_bit (b, (j * max_num_modes) + i)
      91                 :             : 
      92                 :             : /* Test mode I from entity J in bitmap B.  */
      93                 :             : #define mode_bit_p(b, j, i) \
      94                 :             :        bitmap_bit_p (b, (j * max_num_modes) + i)
      95                 :             : 
      96                 :             : /* Set mode I from entity J in bitmal B.  */
      97                 :             : #define set_mode_bit(b, j, i) \
      98                 :             :        bitmap_set_bit (b, (j * max_num_modes) + i)
      99                 :             : 
     100                 :             : /* Emit modes segments from EDGE_LIST associated with entity E.
     101                 :             :    INFO gives mode availability for each mode.  */
     102                 :             : 
     103                 :             : static bool
     104                 :       67080 : commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info)
     105                 :             : {
     106                 :       67080 :   bool need_commit = false;
     107                 :             : 
     108                 :      836689 :   for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
     109                 :             :     {
     110                 :      769609 :       edge eg = INDEX_EDGE (edge_list, ed);
     111                 :             : 
     112                 :      769609 :       if (eg->aux)
     113                 :             :         {
     114                 :        9794 :           int mode = (int) (intptr_t) eg->aux - 1;
     115                 :        9794 :           HARD_REG_SET live_at_edge;
     116                 :        9794 :           basic_block src_bb = eg->src;
     117                 :        9794 :           int cur_mode = info[src_bb->index].mode_out;
     118                 :        9794 :           rtx_insn *mode_set;
     119                 :             : 
     120                 :       19588 :           REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
     121                 :             : 
     122                 :        9794 :           rtl_profile_for_edge (eg);
     123                 :        9794 :           start_sequence ();
     124                 :             : 
     125                 :        9794 :           targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge);
     126                 :             : 
     127                 :        9794 :           mode_set = get_insns ();
     128                 :        9794 :           end_sequence ();
     129                 :        9794 :           default_rtl_profile ();
     130                 :             : 
     131                 :             :           /* Do not bother to insert empty sequence.  */
     132                 :        9794 :           if (mode_set == NULL)
     133                 :        3418 :             continue;
     134                 :             : 
     135                 :             :           /* We should not get an abnormal edge here.  */
     136                 :        6376 :           gcc_assert (! (eg->flags & EDGE_ABNORMAL));
     137                 :             : 
     138                 :        6376 :           need_commit = true;
     139                 :        6376 :           insert_insn_on_edge (mode_set, eg);
     140                 :             :         }
     141                 :             :     }
     142                 :             : 
     143                 :       67080 :   return need_commit;
     144                 :             : }
     145                 :             : 
     146                 :             : /* Allocate a new BBINFO structure, initialized with the PREV_MODE, MODE,
     147                 :             :    INSN, and REGS_LIVE parameters.
     148                 :             :    INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty
     149                 :             :    basic block; that allows us later to insert instructions in a FIFO-like
     150                 :             :    manner.  */
     151                 :             : 
     152                 :             : static struct seginfo *
     153                 :      525679 : new_seginfo (int prev_mode, int mode, rtx_insn *insn,
     154                 :             :              const HARD_REG_SET &regs_live)
     155                 :             : {
     156                 :      525679 :   struct seginfo *ptr;
     157                 :             : 
     158                 :      525679 :   gcc_assert (!NOTE_INSN_BASIC_BLOCK_P (insn)
     159                 :             :               || insn == BB_END (NOTE_BASIC_BLOCK (insn)));
     160                 :      525679 :   ptr = XNEW (struct seginfo);
     161                 :      525679 :   ptr->prev_mode = prev_mode;
     162                 :      525679 :   ptr->mode = mode;
     163                 :      525679 :   ptr->insn_ptr = insn;
     164                 :      525679 :   ptr->next = NULL;
     165                 :      525679 :   ptr->regs_live = regs_live;
     166                 :      525679 :   return ptr;
     167                 :             : }
     168                 :             : 
     169                 :             : /* Add a seginfo element to the end of a list.
     170                 :             :    TAIL is a pointer to the list's null terminator.
     171                 :             :    INFO is the structure to be linked in.  */
     172                 :             : 
     173                 :             : static void
     174                 :      525679 : add_seginfo (struct seginfo ***tail_ptr, struct seginfo *info)
     175                 :             : {
     176                 :      525679 :   **tail_ptr = info;
     177                 :      525679 :   *tail_ptr = &info->next;
     178                 :           0 : }
     179                 :             : 
     180                 :             : /* Record in LIVE that register REG died.  */
     181                 :             : 
     182                 :             : static void
     183                 :     1612111 : reg_dies (rtx reg, HARD_REG_SET *live)
     184                 :             : {
     185                 :     1612111 :   int regno;
     186                 :             : 
     187                 :     1612111 :   if (!REG_P (reg))
     188                 :             :     return;
     189                 :             : 
     190                 :     1612111 :   regno = REGNO (reg);
     191                 :     1612111 :   if (regno < FIRST_PSEUDO_REGISTER)
     192                 :     1404420 :     remove_from_hard_reg_set (live, GET_MODE (reg), regno);
     193                 :             : }
     194                 :             : 
     195                 :             : /* Record in LIVE that register REG became live.
     196                 :             :    This is called via note_stores.  */
     197                 :             : 
     198                 :             : static void
     199                 :     2778419 : reg_becomes_live (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *live)
     200                 :             : {
     201                 :     2778419 :   int regno;
     202                 :             : 
     203                 :     2778419 :   if (GET_CODE (reg) == SUBREG)
     204                 :          28 :     reg = SUBREG_REG (reg);
     205                 :             : 
     206                 :     2778419 :   if (!REG_P (reg))
     207                 :             :     return;
     208                 :             : 
     209                 :     2171165 :   regno = REGNO (reg);
     210                 :     2171165 :   if (regno < FIRST_PSEUDO_REGISTER)
     211                 :     1944930 :     add_to_hard_reg_set ((HARD_REG_SET *) live, GET_MODE (reg), regno);
     212                 :             : }
     213                 :             : 
     214                 :             : /* Split the fallthrough edge to the exit block, so that we can note
     215                 :             :    that there NORMAL_MODE is required.  Return the new block if it's
     216                 :             :    inserted before the exit block.  Otherwise return null.  */
     217                 :             : 
     218                 :             : static basic_block
     219                 :       67064 : create_pre_exit (int n_entities, int *entity_map, const int *num_modes)
     220                 :             : {
     221                 :       67064 :   edge eg;
     222                 :       67064 :   edge_iterator ei;
     223                 :       67064 :   basic_block pre_exit;
     224                 :             : 
     225                 :             :   /* The only non-call predecessor at this stage is a block with a
     226                 :             :      fallthrough edge; there can be at most one, but there could be
     227                 :             :      none at all, e.g. when exit is called.  */
     228                 :       67064 :   pre_exit = 0;
     229                 :      134053 :   FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
     230                 :       66989 :     if (eg->flags & EDGE_FALLTHRU)
     231                 :             :       {
     232                 :       65680 :         basic_block src_bb = eg->src;
     233                 :       65680 :         rtx_insn *last_insn;
     234                 :       65680 :         rtx ret_reg;
     235                 :             : 
     236                 :       65680 :         gcc_assert (!pre_exit);
     237                 :             :         /* If this function returns a value at the end, we have to
     238                 :             :            insert the final mode switch before the return value copy
     239                 :             :            to its hard register.
     240                 :             : 
     241                 :             :            x86 targets use mode-switching infrastructure to
     242                 :             :            conditionally insert vzeroupper instruction at the exit
     243                 :             :            from the function where there is no need to switch the
     244                 :             :            mode before the return value copy.  The vzeroupper insertion
     245                 :             :            pass runs after reload, so use !reload_completed as a stand-in
     246                 :             :            for x86 to skip the search for the return value copy insn.
     247                 :             : 
     248                 :             :            N.b.: the code below assumes that the return copy insn
     249                 :             :            immediately precedes its corresponding use insn.  This
     250                 :             :            assumption does not hold after reload, since sched1 pass
     251                 :             :            can schedule the return copy insn away from its
     252                 :             :            corresponding use insn.  */
     253                 :      131360 :         if (!reload_completed
     254                 :       66850 :             && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == 1
     255                 :        1170 :             && NONJUMP_INSN_P ((last_insn = BB_END (src_bb)))
     256                 :        1017 :             && GET_CODE (PATTERN (last_insn)) == USE
     257                 :       66592 :             && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG)
     258                 :             :           {
     259                 :         912 :             auto_bitmap live;
     260                 :         912 :             df_simulate_initialize_backwards (src_bb, live);
     261                 :             : 
     262                 :         912 :             int ret_start = REGNO (ret_reg);
     263                 :         912 :             int nregs = REG_NREGS (ret_reg);
     264                 :         912 :             int ret_end = ret_start + nregs;
     265                 :         912 :             bool short_block = false;
     266                 :         912 :             bool multi_reg_return = false;
     267                 :         912 :             bool forced_late_switch = false;
     268                 :         912 :             rtx_insn *before_return_copy;
     269                 :             : 
     270                 :         912 :             df_simulate_one_insn_backwards (src_bb, last_insn, live);
     271                 :             : 
     272                 :        1007 :             do
     273                 :             :               {
     274                 :        1007 :                 rtx_insn *return_copy = PREV_INSN (last_insn);
     275                 :        1007 :                 rtx return_copy_pat, copy_reg;
     276                 :        1007 :                 int copy_start, copy_num;
     277                 :        1007 :                 int j;
     278                 :             : 
     279                 :        1007 :                 df_simulate_one_insn_backwards (src_bb, return_copy, live);
     280                 :             : 
     281                 :        1007 :                 if (NONDEBUG_INSN_P (return_copy))
     282                 :             :                   {
     283                 :             :                     /* When using SJLJ exceptions, the call to the
     284                 :             :                        unregister function is inserted between the
     285                 :             :                        clobber of the return value and the copy.
     286                 :             :                        We do not want to split the block before this
     287                 :             :                        or any other call; if we have not found the
     288                 :             :                        copy yet, the copy must have been deleted.  */
     289                 :        1007 :                     if (CALL_P (return_copy))
     290                 :             :                       {
     291                 :             :                         short_block = true;
     292                 :           0 :                         break;
     293                 :             :                       }
     294                 :        1007 :                     return_copy_pat = PATTERN (return_copy);
     295                 :        1007 :                     switch (GET_CODE (return_copy_pat))
     296                 :             :                       {
     297                 :           0 :                       case USE:
     298                 :             :                         /* Skip USEs of multiple return registers.
     299                 :             :                            __builtin_apply pattern is also handled here.  */
     300                 :           0 :                         if (GET_CODE (XEXP (return_copy_pat, 0)) == REG
     301                 :           0 :                             && (targetm.calls.function_value_regno_p
     302                 :           0 :                                 (REGNO (XEXP (return_copy_pat, 0)))))
     303                 :             :                           {
     304                 :           0 :                             multi_reg_return = true;
     305                 :           0 :                             last_insn = return_copy;
     306                 :          95 :                             continue;
     307                 :             :                           }
     308                 :             :                         break;
     309                 :             : 
     310                 :           0 :                       case ASM_OPERANDS:
     311                 :             :                         /* Skip barrier insns.  */
     312                 :           0 :                         if (!MEM_VOLATILE_P (return_copy_pat))
     313                 :             :                           break;
     314                 :             : 
     315                 :             :                         /* Fall through.  */
     316                 :             : 
     317                 :          95 :                       case ASM_INPUT:
     318                 :          95 :                       case UNSPEC_VOLATILE:
     319                 :          95 :                         last_insn = return_copy;
     320                 :          95 :                         continue;
     321                 :             : 
     322                 :             :                       default:
     323                 :             :                         break;
     324                 :          95 :                       }
     325                 :             : 
     326                 :             :                     /* If the return register is not (in its entirety)
     327                 :             :                        likely spilled, the return copy might be
     328                 :             :                        partially or completely optimized away.  */
     329                 :         912 :                     return_copy_pat = single_set (return_copy);
     330                 :         912 :                     if (!return_copy_pat)
     331                 :             :                       {
     332                 :           0 :                         return_copy_pat = PATTERN (return_copy);
     333                 :           0 :                         if (GET_CODE (return_copy_pat) != CLOBBER)
     334                 :             :                           break;
     335                 :           0 :                         else if (!optimize)
     336                 :             :                           {
     337                 :             :                             /* This might be (clobber (reg [<result>]))
     338                 :             :                                when not optimizing.  Then check if
     339                 :             :                                the previous insn is the clobber for
     340                 :             :                                the return register.  */
     341                 :           0 :                             copy_reg = SET_DEST (return_copy_pat);
     342                 :           0 :                             if (GET_CODE (copy_reg) == REG
     343                 :           0 :                                 && !HARD_REGISTER_NUM_P (REGNO (copy_reg)))
     344                 :             :                               {
     345                 :           0 :                                 if (INSN_P (PREV_INSN (return_copy)))
     346                 :             :                                   {
     347                 :           0 :                                     return_copy = PREV_INSN (return_copy);
     348                 :           0 :                                     return_copy_pat = PATTERN (return_copy);
     349                 :           0 :                                     if (GET_CODE (return_copy_pat) != CLOBBER)
     350                 :             :                                       break;
     351                 :             :                                   }
     352                 :             :                               }
     353                 :             :                           }
     354                 :             :                       }
     355                 :         912 :                     copy_reg = SET_DEST (return_copy_pat);
     356                 :         912 :                     if (GET_CODE (copy_reg) == REG)
     357                 :         912 :                       copy_start = REGNO (copy_reg);
     358                 :           0 :                     else if (GET_CODE (copy_reg) == SUBREG
     359                 :           0 :                              && GET_CODE (SUBREG_REG (copy_reg)) == REG)
     360                 :           0 :                       copy_start = REGNO (SUBREG_REG (copy_reg));
     361                 :             :                     else
     362                 :             :                       {
     363                 :             :                         /* When control reaches end of non-void function,
     364                 :             :                            there are no return copy insns at all.  This
     365                 :             :                            avoids an ice on that invalid function.  */
     366                 :           0 :                         if (ret_start + nregs == ret_end)
     367                 :           0 :                           short_block = true;
     368                 :             :                         break;
     369                 :             :                       }
     370                 :         912 :                     if (!targetm.calls.function_value_regno_p (copy_start))
     371                 :             :                       copy_num = 0;
     372                 :             :                     else
     373                 :         912 :                       copy_num = hard_regno_nregs (copy_start,
     374                 :         912 :                                                    GET_MODE (copy_reg));
     375                 :             : 
     376                 :             :                     /* If the return register is not likely spilled, - as is
     377                 :             :                        the case for floating point on SH4 - then it might
     378                 :             :                        be set by an arithmetic operation that needs a
     379                 :             :                        different mode than the exit block.  */
     380                 :         912 :                     HARD_REG_SET hard_regs_live;
     381                 :        1824 :                     REG_SET_TO_HARD_REG_SET (hard_regs_live, live);
     382                 :        1838 :                     for (j = n_entities - 1; j >= 0; j--)
     383                 :             :                       {
     384                 :         926 :                         int e = entity_map[j];
     385                 :         926 :                         int mode =
     386                 :         926 :                           targetm.mode_switching.needed (e, return_copy,
     387                 :             :                                                          hard_regs_live);
     388                 :             : 
     389                 :         926 :                         if (mode != num_modes[e]
     390                 :         926 :                             && mode != targetm.mode_switching.exit (e))
     391                 :             :                           break;
     392                 :             :                       }
     393                 :         912 :                     if (j >= 0)
     394                 :             :                       {
     395                 :             :                         /* __builtin_return emits a sequence of loads to all
     396                 :             :                            return registers.  One of them might require
     397                 :             :                            another mode than MODE_EXIT, even if it is
     398                 :             :                            unrelated to the return value, so we want to put
     399                 :             :                            the final mode switch after it.  */
     400                 :           0 :                         if (multi_reg_return
     401                 :           0 :                             && targetm.calls.function_value_regno_p
     402                 :           0 :                                 (copy_start))
     403                 :             :                           forced_late_switch = true;
     404                 :             : 
     405                 :             :                         /* For the SH4, floating point loads depend on fpscr,
     406                 :             :                            thus we might need to put the final mode switch
     407                 :             :                            after the return value copy.  That is still OK,
     408                 :             :                            because a floating point return value does not
     409                 :             :                            conflict with address reloads.  */
     410                 :           0 :                         if (copy_start >= ret_start
     411                 :           0 :                             && copy_start + copy_num <= ret_end
     412                 :           0 :                             && GET_CODE (return_copy_pat) == SET
     413                 :           0 :                             && OBJECT_P (SET_SRC (return_copy_pat)))
     414                 :           0 :                           forced_late_switch = true;
     415                 :             :                         break;
     416                 :             :                       }
     417                 :         912 :                     if (copy_num == 0)
     418                 :             :                       {
     419                 :           0 :                         last_insn = return_copy;
     420                 :           0 :                         continue;
     421                 :             :                       }
     422                 :             : 
     423                 :         912 :                     if (copy_start >= ret_start
     424                 :         912 :                         && copy_start + copy_num <= ret_end)
     425                 :         912 :                       nregs -= copy_num;
     426                 :           0 :                     else if (!multi_reg_return
     427                 :           0 :                              || !targetm.calls.function_value_regno_p
     428                 :           0 :                                  (copy_start))
     429                 :             :                       break;
     430                 :         912 :                     last_insn = return_copy;
     431                 :             :                   }
     432                 :             :                 /* ??? Exception handling can lead to the return value
     433                 :             :                    copy being already separated from the return value use,
     434                 :             :                    as in  unwind-dw2.c .
     435                 :             :                    Similarly, conditionally returning without a value,
     436                 :             :                    and conditionally using builtin_return can lead to an
     437                 :             :                    isolated use.  */
     438                 :         912 :                 if (return_copy == BB_HEAD (src_bb))
     439                 :             :                   {
     440                 :             :                     short_block = true;
     441                 :             :                     break;
     442                 :             :                   }
     443                 :             :                 last_insn = return_copy;
     444                 :             :               }
     445                 :        1007 :             while (nregs);
     446                 :             : 
     447                 :             :             /* If we didn't see a full return value copy, verify that there
     448                 :             :                is a plausible reason for this.  If some, but not all of the
     449                 :             :                return register is likely spilled, we can expect that there
     450                 :             :                is a copy for the likely spilled part.  */
     451                 :         912 :             gcc_assert (!nregs
     452                 :             :                         || forced_late_switch
     453                 :             :                         || short_block
     454                 :             :                         || !(targetm.class_likely_spilled_p
     455                 :             :                              (REGNO_REG_CLASS (ret_start)))
     456                 :             :                         || nregs != REG_NREGS (ret_reg)
     457                 :             :                         /* For multi-hard-register floating point
     458                 :             :                            values, sometimes the likely-spilled part
     459                 :             :                            is ordinarily copied first, then the other
     460                 :             :                            part is set with an arithmetic operation.
     461                 :             :                            This doesn't actually cause reload
     462                 :             :                            failures, so let it pass.  */
     463                 :             :                         || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT
     464                 :             :                             && nregs != 1));
     465                 :             : 
     466                 :         912 :             if (!NOTE_INSN_BASIC_BLOCK_P (last_insn))
     467                 :             :               {
     468                 :         912 :                 before_return_copy
     469                 :         912 :                   = emit_note_before (NOTE_INSN_DELETED, last_insn);
     470                 :             :                 /* Instructions preceding LAST_INSN in the same block might
     471                 :             :                    require a different mode than MODE_EXIT, so if we might
     472                 :             :                    have such instructions, keep them in a separate block
     473                 :             :                    from pre_exit.  */
     474                 :        1824 :                 src_bb = split_block (src_bb,
     475                 :         912 :                                       PREV_INSN (before_return_copy))->dest;
     476                 :             :               }
     477                 :             :             else
     478                 :             :               before_return_copy = last_insn;
     479                 :         912 :             pre_exit = split_block (src_bb, before_return_copy)->src;
     480                 :         912 :           }
     481                 :             :         else
     482                 :             :           {
     483                 :       64768 :             pre_exit = split_edge (eg);
     484                 :             :           }
     485                 :             :       }
     486                 :             : 
     487                 :       67064 :   return pre_exit;
     488                 :             : }
     489                 :             : 
     490                 :             : /* Return the confluence of modes MODE1 and MODE2 for entity ENTITY,
     491                 :             :    using NO_MODE to represent an unknown mode if nothing more precise
     492                 :             :    is available.  */
     493                 :             : 
     494                 :             : int
     495                 :           0 : mode_confluence (int entity, int mode1, int mode2, int no_mode)
     496                 :             : {
     497                 :           0 :   if (mode1 == mode2)
     498                 :             :     return mode1;
     499                 :             : 
     500                 :           0 :   if (mode1 != no_mode
     501                 :           0 :       && mode2 != no_mode
     502                 :           0 :       && targetm.mode_switching.confluence)
     503                 :           0 :     return targetm.mode_switching.confluence (entity, mode1, mode2);
     504                 :             : 
     505                 :             :   return no_mode;
     506                 :             : }
     507                 :             : 
     508                 :             : /* Information for the dataflow problems below.  */
     509                 :             : struct
     510                 :             : {
     511                 :             :   /* Information about each basic block, indexed by block id.  */
     512                 :             :   struct bb_info *bb_info;
     513                 :             : 
     514                 :             :   /* A bitmap of blocks for which the current entity is transparent.  */
     515                 :             :   sbitmap transp;
     516                 :             : 
     517                 :             :   /* The entity that we're processing.  */
     518                 :             :   int entity;
     519                 :             : 
     520                 :             :   /* The number of modes defined for the entity, and thus the identifier
     521                 :             :      of the "don't know" mode.  */
     522                 :             :   int no_mode;
     523                 :             : } confluence_info;
     524                 :             : 
     525                 :             : /* Propagate information about any mode change on edge E to the
     526                 :             :    destination block's mode_in.  Return true if something changed.
     527                 :             : 
     528                 :             :    The mode_in and mode_out fields use no_mode + 1 to mean "not yet set".  */
     529                 :             : 
     530                 :             : static bool
     531                 :           0 : forward_confluence_n (edge e)
     532                 :             : {
     533                 :             :   /* The entry and exit blocks have no useful mode information.  */
     534                 :           0 :   if (e->src->index == ENTRY_BLOCK || e->dest->index == EXIT_BLOCK)
     535                 :             :     return false;
     536                 :             : 
     537                 :             :   /* We don't control mode changes across abnormal edges.  */
     538                 :           0 :   if (e->flags & EDGE_ABNORMAL)
     539                 :             :     return false;
     540                 :             : 
     541                 :             :   /* E->aux is nonzero if we have computed the LCM problem and scheduled
     542                 :             :      E to change the mode to E->aux - 1.  Otherwise model the change
     543                 :             :      from the source to the destination.  */
     544                 :           0 :   struct bb_info *bb_info = confluence_info.bb_info;
     545                 :           0 :   int no_mode = confluence_info.no_mode;
     546                 :           0 :   int src_mode = bb_info[e->src->index].mode_out;
     547                 :           0 :   if (e->aux)
     548                 :           0 :     src_mode = (int) (intptr_t) e->aux - 1;
     549                 :           0 :   if (src_mode == no_mode + 1)
     550                 :             :     return false;
     551                 :             : 
     552                 :           0 :   int dest_mode = bb_info[e->dest->index].mode_in;
     553                 :           0 :   if (dest_mode == no_mode + 1)
     554                 :             :     {
     555                 :           0 :       bb_info[e->dest->index].mode_in = src_mode;
     556                 :           0 :       return true;
     557                 :             :     }
     558                 :             : 
     559                 :           0 :   int entity = confluence_info.entity;
     560                 :           0 :   int new_mode = mode_confluence (entity, src_mode, dest_mode, no_mode);
     561                 :           0 :   if (dest_mode == new_mode)
     562                 :             :     return false;
     563                 :             : 
     564                 :           0 :   bb_info[e->dest->index].mode_in = new_mode;
     565                 :           0 :   return true;
     566                 :             : }
     567                 :             : 
     568                 :             : /* Update block BB_INDEX's mode_out based on its mode_in.  Return true if
     569                 :             :    something changed.  */
     570                 :             : 
     571                 :             : static bool
     572                 :           0 : forward_transfer (int bb_index)
     573                 :             : {
     574                 :             :   /* The entry and exit blocks have no useful mode information.  */
     575                 :           0 :   if (bb_index == ENTRY_BLOCK || bb_index == EXIT_BLOCK)
     576                 :             :     return false;
     577                 :             : 
     578                 :             :   /* Only propagate through a block if the entity is transparent.  */
     579                 :           0 :   struct bb_info *bb_info = confluence_info.bb_info;
     580                 :           0 :   if (bb_info[bb_index].computing != confluence_info.no_mode
     581                 :           0 :       || bb_info[bb_index].mode_out == bb_info[bb_index].mode_in)
     582                 :             :     return false;
     583                 :             : 
     584                 :           0 :   bb_info[bb_index].mode_out = bb_info[bb_index].mode_in;
     585                 :           0 :   return true;
     586                 :             : }
     587                 :             : 
     588                 :             : /* A backwards confluence function.  Update the bb_info single_succ
     589                 :             :    field for E's source block, based on changes to E's destination block.
     590                 :             :    At the end of the dataflow problem, single_succ is the single mode
     591                 :             :    that all successors require (directly or indirectly), or no_mode
     592                 :             :    if there are conflicting requirements.
     593                 :             : 
     594                 :             :    Initially, a value of no_mode + 1 means "don't know".  */
     595                 :             : 
     596                 :             : static bool
     597                 :           0 : single_succ_confluence_n (edge e)
     598                 :             : {
     599                 :             :   /* The entry block has no associated mode information.  */
     600                 :           0 :   if (e->src->index == ENTRY_BLOCK)
     601                 :             :     return false;
     602                 :             : 
     603                 :             :   /* We don't control mode changes across abnormal edges.  */
     604                 :           0 :   if (e->flags & EDGE_ABNORMAL)
     605                 :             :     return false;
     606                 :             : 
     607                 :             :   /* Do nothing if we've already found a conflict.  */
     608                 :           0 :   struct bb_info *bb_info = confluence_info.bb_info;
     609                 :           0 :   int no_mode = confluence_info.no_mode;
     610                 :           0 :   int src_mode = bb_info[e->src->index].single_succ;
     611                 :           0 :   if (src_mode == no_mode)
     612                 :             :     return false;
     613                 :             : 
     614                 :             :   /* Work out what mode the destination block (or its successors) require.  */
     615                 :           0 :   int dest_mode;
     616                 :           0 :   if (e->dest->index == EXIT_BLOCK)
     617                 :             :     dest_mode = no_mode;
     618                 :           0 :   else if (bitmap_bit_p (confluence_info.transp, e->dest->index))
     619                 :           0 :     dest_mode = bb_info[e->dest->index].single_succ;
     620                 :             :   else
     621                 :           0 :     dest_mode = bb_info[e->dest->index].seginfo->mode;
     622                 :             : 
     623                 :             :   /* Do nothing if the destination block has no new information.  */
     624                 :           0 :   if (dest_mode == no_mode + 1 || dest_mode == src_mode)
     625                 :             :     return false;
     626                 :             : 
     627                 :             :   /* Detect conflicting modes.  */
     628                 :           0 :   if (src_mode != no_mode + 1)
     629                 :           0 :     dest_mode = no_mode;
     630                 :             : 
     631                 :           0 :   bb_info[e->src->index].single_succ = dest_mode;
     632                 :           0 :   return true;
     633                 :             : }
     634                 :             : 
     635                 :             : /* A backward transfer function for computing the bb_info single_succ
     636                 :             :    fields, as described above single_succ_confluence.  */
     637                 :             : 
     638                 :             : static bool
     639                 :           0 : single_succ_transfer (int bb_index)
     640                 :             : {
     641                 :             :   /* We don't have any field to transfer to.  Assume that, after the
     642                 :             :      first iteration, we are only called if single_succ has changed.
     643                 :             :      We should then process incoming edges if the entity is transparent.  */
     644                 :           0 :   return bitmap_bit_p (confluence_info.transp, bb_index);
     645                 :             : }
     646                 :             : 
     647                 :             : /* Check whether the target wants to back-propagate a mode change across
     648                 :             :    edge E, and update the source block's computed mode if so.  Return true
     649                 :             :    if something changed.  */
     650                 :             : 
     651                 :             : static bool
     652                 :           0 : backprop_confluence_n (edge e)
     653                 :             : {
     654                 :             :   /* The entry and exit blocks have no useful mode information.  */
     655                 :           0 :   if (e->src->index == ENTRY_BLOCK || e->dest->index == EXIT_BLOCK)
     656                 :             :     return false;
     657                 :             : 
     658                 :             :   /* We don't control mode changes across abnormal edges.  */
     659                 :           0 :   if (e->flags & EDGE_ABNORMAL)
     660                 :             :     return false;
     661                 :             : 
     662                 :             :   /* We can only require a new mode in the source block if the entity
     663                 :             :      was originally transparent there.  */
     664                 :           0 :   if (!bitmap_bit_p (confluence_info.transp, e->src->index))
     665                 :             :     return false;
     666                 :             : 
     667                 :             :   /* Exit now if there is no required mode, or if all paths into the
     668                 :             :      source block leave the entity in the required mode.  */
     669                 :           0 :   struct bb_info *bb_info = confluence_info.bb_info;
     670                 :           0 :   int no_mode = confluence_info.no_mode;
     671                 :           0 :   int src_mode = bb_info[e->src->index].mode_out;
     672                 :           0 :   int dest_mode = bb_info[e->dest->index].mode_in;
     673                 :           0 :   if (dest_mode == no_mode || src_mode == dest_mode)
     674                 :             :     return false;
     675                 :             : 
     676                 :             :   /* See what the target thinks about this transition.  */
     677                 :           0 :   int entity = confluence_info.entity;
     678                 :           0 :   int new_mode = targetm.mode_switching.backprop (entity, src_mode,
     679                 :             :                                                   dest_mode);
     680                 :           0 :   if (new_mode == no_mode)
     681                 :             :     return false;
     682                 :             : 
     683                 :             :   /* The target doesn't like the current transition, but would be happy
     684                 :             :      with a transition from NEW_MODE.
     685                 :             : 
     686                 :             :      If we force the source block to use NEW_MODE, we might introduce a
     687                 :             :      double transition on at least one path through the function (one to
     688                 :             :      NEW_MODE and then one to DEST_MODE).  Therefore, if all destination
     689                 :             :      blocks require the same mode, it is usually better to bring that
     690                 :             :      mode requirement forward.
     691                 :             : 
     692                 :             :      If that isn't possible, merge the preference for this edge with
     693                 :             :      the preferences for other edges.  no_mode + 1 indicates that there
     694                 :             :      was no previous preference.  */
     695                 :           0 :   int old_mode = bb_info[e->src->index].computing;
     696                 :           0 :   if (bb_info[e->src->index].single_succ != no_mode)
     697                 :             :     new_mode = bb_info[e->src->index].single_succ;
     698                 :           0 :   else if (old_mode != no_mode + 1)
     699                 :           0 :     new_mode = mode_confluence (entity, old_mode, new_mode, no_mode);
     700                 :             : 
     701                 :           0 :   if (old_mode == new_mode)
     702                 :             :     return false;
     703                 :             : 
     704                 :           0 :   bb_info[e->src->index].computing = new_mode;
     705                 :           0 :   return true;
     706                 :             : }
     707                 :             : 
     708                 :             : /* If the current entity was originally transparent in block BB_INDEX,
     709                 :             :    update the incoming mode to match the outgoing mode.  Register a mode
     710                 :             :    change if the entity is no longer transparent.
     711                 :             : 
     712                 :             :    Also, as an on-the-fly optimization, check whether the entity was
     713                 :             :    originally transparent in BB_INDEX and if all successor blocks require
     714                 :             :    the same mode.  If so, anticipate the mode change in BB_INDEX if
     715                 :             :    doing it on the incoming edges would require no more mode changes than
     716                 :             :    doing it on the outgoing edges.  The aim is to reduce the total number
     717                 :             :    of mode changes emitted for the function (and thus reduce code size and
     718                 :             :    cfg complexity) without increasing the number of mode changes on any
     719                 :             :    given path through the function.  A typical case where it helps is:
     720                 :             : 
     721                 :             :           T
     722                 :             :          / \
     723                 :             :         T   M
     724                 :             :          \ /
     725                 :             :           M
     726                 :             : 
     727                 :             :    where the entity is transparent in the T blocks and is required to have
     728                 :             :    mode M in the M blocks.  If there are no redundancies leading up to this,
     729                 :             :    there will be two mutually-exclusive changes to mode M, one on each of
     730                 :             :    the T->M edges.  The optimization instead converts it to:
     731                 :             : 
     732                 :             :           T            T            M
     733                 :             :          / \          / \          / \
     734                 :             :         T   M   ->   M   M   ->   M   M
     735                 :             :          \ /          \ /          \ /
     736                 :             :           M            M            M
     737                 :             : 
     738                 :             :    which creates a single transition to M for both paths through the diamond.
     739                 :             : 
     740                 :             :    Return true if something changed.  */
     741                 :             : 
     742                 :             : static bool
     743                 :           0 : backprop_transfer (int bb_index)
     744                 :             : {
     745                 :             :   /* The entry and exit blocks have no useful mode information.  */
     746                 :           0 :   if (bb_index == ENTRY_BLOCK || bb_index == EXIT_BLOCK)
     747                 :             :     return false;
     748                 :             : 
     749                 :             :   /* We can only require a new mode if the entity was previously
     750                 :             :      transparent.  */
     751                 :           0 :   if (!bitmap_bit_p (confluence_info.transp, bb_index))
     752                 :             :     return false;
     753                 :             : 
     754                 :           0 :   struct bb_info *bb_info = confluence_info.bb_info;
     755                 :           0 :   basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
     756                 :           0 :   int no_mode = confluence_info.no_mode;
     757                 :           0 :   int mode_in = bb_info[bb_index].mode_in;
     758                 :           0 :   int mode_out = bb_info[bb_index].computing;
     759                 :           0 :   if (mode_out == no_mode + 1)
     760                 :             :     {
     761                 :             :       /* The entity is still transparent for this block.  See whether
     762                 :             :          all successor blocks need the same mode, either directly or
     763                 :             :          indirectly.  */
     764                 :           0 :       mode_out = bb_info[bb_index].single_succ;
     765                 :           0 :       if (mode_out == no_mode)
     766                 :             :         return false;
     767                 :             : 
     768                 :             :       /* Get a minimum bound on the number of transitions that would be
     769                 :             :          removed if BB itself required MODE_OUT.  */
     770                 :           0 :       unsigned int moved = 0;
     771                 :           0 :       for (edge e : bb->succs)
     772                 :           0 :         if (e->dest->index != EXIT_BLOCK
     773                 :           0 :             && mode_out == bb_info[e->dest->index].seginfo->mode)
     774                 :           0 :           moved += 1;
     775                 :             : 
     776                 :             :       /* See whether making the mode change on all incoming edges would
     777                 :             :          be no worse than making it on MOVED outgoing edges.  */
     778                 :           0 :       if (moved < EDGE_COUNT (bb->preds))
     779                 :             :         return false;
     780                 :             : 
     781                 :           0 :       bb_info[bb_index].mode_out = mode_out;
     782                 :           0 :       bb_info[bb_index].computing = mode_out;
     783                 :             :     }
     784                 :           0 :   else if (mode_out == mode_in)
     785                 :             :     return false;
     786                 :             : 
     787                 :           0 :   bb_info[bb_index].mode_in = mode_out;
     788                 :           0 :   bb_info[bb_index].seginfo->mode = mode_out;
     789                 :           0 :   return true;
     790                 :             : }
     791                 :             : 
     792                 :             : /* Find all insns that need a particular mode setting, and insert the
     793                 :             :    necessary mode switches.  Return true if we did work.  */
     794                 :             : 
     795                 :             : static int
     796                 :     1492499 : optimize_mode_switching (void)
     797                 :             : {
     798                 :     1492499 :   int e;
     799                 :     1492499 :   basic_block bb;
     800                 :     1492499 :   bool need_commit = false;
     801                 :     1492499 :   static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
     802                 :             : #define N_ENTITIES ARRAY_SIZE (num_modes)
     803                 :     1492499 :   int entity_map[N_ENTITIES] = {};
     804                 :     1492499 :   struct bb_info *bb_info[N_ENTITIES] = {};
     805                 :     1492499 :   int i, j;
     806                 :     1492499 :   int n_entities = 0;
     807                 :     1492499 :   int max_num_modes = 0;
     808                 :     1492499 :   bool emitted ATTRIBUTE_UNUSED = false;
     809                 :     1492499 :   basic_block post_entry = 0;
     810                 :     1492499 :   basic_block pre_exit = 0;
     811                 :     1492499 :   struct edge_list *edge_list = 0;
     812                 :             : 
     813                 :             :   /* These bitmaps are used for the LCM algorithm.  */
     814                 :     1492499 :   sbitmap *kill, *del, *insert, *antic, *transp, *comp;
     815                 :     1492499 :   sbitmap *avin, *avout;
     816                 :             : 
     817                 :    10447493 :   for (e = N_ENTITIES - 1; e >= 0; e--)
     818                 :     8954994 :     if (OPTIMIZE_MODE_SWITCHING (e))
     819                 :             :       {
     820                 :       67080 :         int entry_exit_extra = 0;
     821                 :             : 
     822                 :             :         /* Create the list of segments within each basic block.
     823                 :             :            If NORMAL_MODE is defined, allow for two extra
     824                 :             :            blocks split from the entry and exit block.  */
     825                 :       67080 :         if (targetm.mode_switching.entry && targetm.mode_switching.exit)
     826                 :       67080 :           entry_exit_extra = 3;
     827                 :             : 
     828                 :       67080 :         bb_info[n_entities]
     829                 :       67080 :           = XCNEWVEC (struct bb_info,
     830                 :             :                       last_basic_block_for_fn (cfun) + entry_exit_extra);
     831                 :       67080 :         entity_map[n_entities++] = e;
     832                 :       67080 :         if (num_modes[e] > max_num_modes)
     833                 :       67064 :           max_num_modes = num_modes[e];
     834                 :             :       }
     835                 :             : 
     836                 :     1492499 :   if (! n_entities)
     837                 :             :     return 0;
     838                 :             : 
     839                 :             :   /* Make sure if MODE_ENTRY is defined MODE_EXIT is defined.  */
     840                 :       67064 :   gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit)
     841                 :             :               || (!targetm.mode_switching.entry
     842                 :             :                   && !targetm.mode_switching.exit));
     843                 :             : 
     844                 :       67064 :   if (targetm.mode_switching.entry && targetm.mode_switching.exit)
     845                 :             :     {
     846                 :             :       /* Split the edge from the entry block, so that we can note that
     847                 :             :          there NORMAL_MODE is supplied.  */
     848                 :       67064 :       post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
     849                 :       67064 :       pre_exit = create_pre_exit (n_entities, entity_map, num_modes);
     850                 :             :     }
     851                 :             : 
     852                 :       67064 :   df_note_add_problem ();
     853                 :       67064 :   df_analyze ();
     854                 :             : 
     855                 :             :   /* Create the bitmap vectors.  */
     856                 :      134128 :   antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
     857                 :       67064 :                                 n_entities * max_num_modes);
     858                 :      134128 :   transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
     859                 :       67064 :                                  n_entities * max_num_modes);
     860                 :      134128 :   comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
     861                 :       67064 :                                n_entities * max_num_modes);
     862                 :      134128 :   avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
     863                 :       67064 :                                n_entities * max_num_modes);
     864                 :      134128 :   avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
     865                 :       67064 :                                 n_entities * max_num_modes);
     866                 :      134128 :   kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
     867                 :       67064 :                                n_entities * max_num_modes);
     868                 :             : 
     869                 :       67064 :   bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
     870                 :       67064 :   bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
     871                 :       67064 :   bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
     872                 :             : 
     873                 :       67064 :   auto_sbitmap transp_all (last_basic_block_for_fn (cfun));
     874                 :             : 
     875                 :       67064 :   auto_bitmap blocks;
     876                 :             : 
     877                 :             :   /* Forward-propagate mode information through blocks where the entity
     878                 :             :      is transparent, so that mode_in describes the mode on entry to each
     879                 :             :      block and mode_out describes the mode on exit from each block.  */
     880                 :       67064 :   auto forwprop_mode_info = [&](struct bb_info *info,
     881                 :             :                                 int entity, int no_mode)
     882                 :             :     {
     883                 :             :       /* Use no_mode + 1 to mean "not yet set".  */
     884                 :           0 :       FOR_EACH_BB_FN (bb, cfun)
     885                 :             :         {
     886                 :           0 :           if (bb_has_abnormal_pred (bb))
     887                 :           0 :             info[bb->index].mode_in = info[bb->index].seginfo->mode;
     888                 :             :           else
     889                 :           0 :             info[bb->index].mode_in = no_mode + 1;
     890                 :           0 :           if (info[bb->index].computing != no_mode)
     891                 :           0 :             info[bb->index].mode_out = info[bb->index].computing;
     892                 :             :           else
     893                 :           0 :             info[bb->index].mode_out = no_mode + 1;
     894                 :             :         }
     895                 :             : 
     896                 :           0 :       confluence_info.bb_info = info;
     897                 :           0 :       confluence_info.transp = nullptr;
     898                 :           0 :       confluence_info.entity = entity;
     899                 :           0 :       confluence_info.no_mode = no_mode;
     900                 :             : 
     901                 :           0 :       bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
     902                 :           0 :       df_simple_dataflow (DF_FORWARD, NULL, NULL, forward_confluence_n,
     903                 :             :                           forward_transfer, blocks,
     904                 :             :                           df_get_postorder (DF_FORWARD),
     905                 :             :                           df_get_n_blocks (DF_FORWARD));
     906                 :             : 
     907                 :       67064 :     };
     908                 :             : 
     909                 :       67064 :   if (targetm.mode_switching.backprop)
     910                 :           0 :     clear_aux_for_edges ();
     911                 :             : 
     912                 :      134144 :   for (j = n_entities - 1; j >= 0; j--)
     913                 :             :     {
     914                 :       67080 :       int e = entity_map[j];
     915                 :       67080 :       int no_mode = num_modes[e];
     916                 :       67080 :       struct bb_info *info = bb_info[j];
     917                 :       67080 :       rtx_insn *insn;
     918                 :             : 
     919                 :       67080 :       bitmap_ones (transp_all);
     920                 :             : 
     921                 :             :       /* Determine what the first use (if any) need for a mode of entity E is.
     922                 :             :          This will be the mode that is anticipatable for this block.
     923                 :             :          Also compute the initial transparency settings.  */
     924                 :      584354 :       FOR_EACH_BB_FN (bb, cfun)
     925                 :             :         {
     926                 :      517274 :           struct seginfo **tail_ptr = &info[bb->index].seginfo;
     927                 :      517274 :           struct seginfo *ptr;
     928                 :      517274 :           int last_mode = no_mode;
     929                 :      517274 :           bool any_set_required = false;
     930                 :      517274 :           HARD_REG_SET live_now;
     931                 :             : 
     932                 :      517274 :           info[bb->index].mode_out = info[bb->index].mode_in = no_mode;
     933                 :             : 
     934                 :     1034548 :           REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb));
     935                 :             : 
     936                 :             :           /* Pretend the mode is clobbered across abnormal edges.  */
     937                 :      517274 :           {
     938                 :      517274 :             edge_iterator ei;
     939                 :      517274 :             edge eg;
     940                 :     1216825 :             FOR_EACH_EDGE (eg, ei, bb->preds)
     941                 :      700220 :               if (eg->flags & EDGE_COMPLEX)
     942                 :             :                 break;
     943                 :      517274 :             if (eg)
     944                 :             :               {
     945                 :         669 :                 rtx_insn *ins_pos = BB_HEAD (bb);
     946                 :         669 :                 if (LABEL_P (ins_pos))
     947                 :         669 :                   ins_pos = NEXT_INSN (ins_pos);
     948                 :         669 :                 gcc_assert (NOTE_INSN_BASIC_BLOCK_P (ins_pos));
     949                 :         669 :                 if (ins_pos != BB_END (bb))
     950                 :         669 :                   ins_pos = NEXT_INSN (ins_pos);
     951                 :         669 :                 if (bb_has_eh_pred (bb)
     952                 :         669 :                     && targetm.mode_switching.eh_handler)
     953                 :           0 :                   last_mode = targetm.mode_switching.eh_handler (e);
     954                 :         669 :                 ptr = new_seginfo (no_mode, last_mode, ins_pos, live_now);
     955                 :         669 :                 add_seginfo (&tail_ptr, ptr);
     956                 :         669 :                 bitmap_clear_bit (transp_all, bb->index);
     957                 :             :               }
     958                 :             :           }
     959                 :             : 
     960                 :     5154600 :           FOR_BB_INSNS (bb, insn)
     961                 :             :             {
     962                 :     4637326 :               if (NONDEBUG_INSN_P (insn))
     963                 :             :                 {
     964                 :     2460691 :                   int mode = targetm.mode_switching.needed (e, insn, live_now);
     965                 :     2460691 :                   rtx link;
     966                 :             : 
     967                 :     2460691 :                   if (mode != no_mode && mode != last_mode)
     968                 :             :                     {
     969                 :       94142 :                       ptr = new_seginfo (last_mode, mode, insn, live_now);
     970                 :       94142 :                       add_seginfo (&tail_ptr, ptr);
     971                 :       94142 :                       bitmap_clear_bit (transp_all, bb->index);
     972                 :       94142 :                       any_set_required = true;
     973                 :       94142 :                       last_mode = mode;
     974                 :             :                     }
     975                 :             : 
     976                 :             :                   /* Update LIVE_NOW.  */
     977                 :     4655561 :                   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     978                 :     2194870 :                     if (REG_NOTE_KIND (link) == REG_DEAD)
     979                 :     1207799 :                       reg_dies (XEXP (link, 0), &live_now);
     980                 :             : 
     981                 :     2460691 :                   note_stores (insn, reg_becomes_live, &live_now);
     982                 :     4655561 :                   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     983                 :     2194870 :                     if (REG_NOTE_KIND (link) == REG_UNUSED)
     984                 :      404312 :                       reg_dies (XEXP (link, 0), &live_now);
     985                 :             : 
     986                 :     2460691 :                   if (targetm.mode_switching.after)
     987                 :     2460691 :                     last_mode = targetm.mode_switching.after (e, last_mode,
     988                 :             :                                                               insn, live_now);
     989                 :             :                 }
     990                 :             :             }
     991                 :             : 
     992                 :      517274 :           info[bb->index].computing = last_mode;
     993                 :             :           /* Check for blocks without ANY mode requirements.
     994                 :             :              N.B. because of MODE_AFTER, last_mode might still
     995                 :             :              be different from no_mode, in which case we need to
     996                 :             :              mark the block as nontransparent.  */
     997                 :      517274 :           if (!any_set_required)
     998                 :             :             {
     999                 :      430868 :               ptr = new_seginfo (last_mode, no_mode, BB_END (bb), live_now);
    1000                 :      430868 :               add_seginfo (&tail_ptr, ptr);
    1001                 :      430868 :               if (last_mode != no_mode)
    1002                 :          12 :                 bitmap_clear_bit (transp_all, bb->index);
    1003                 :             :             }
    1004                 :             :         }
    1005                 :       67080 :       if (targetm.mode_switching.entry && targetm.mode_switching.exit)
    1006                 :             :         {
    1007                 :       67080 :           info[post_entry->index].mode_out =
    1008                 :       67080 :             info[post_entry->index].mode_in = no_mode;
    1009                 :             : 
    1010                 :       67080 :           int mode = targetm.mode_switching.entry (e);
    1011                 :       67080 :           if (mode != no_mode)
    1012                 :             :             {
    1013                 :             :               /* Insert a fake computing definition of MODE into entry
    1014                 :             :                  blocks which compute no mode. This represents the mode on
    1015                 :             :                  entry.  */
    1016                 :       65736 :               info[post_entry->index].computing = mode;
    1017                 :       65736 :               bitmap_clear_bit (transp_all, post_entry->index);
    1018                 :             :             }
    1019                 :             : 
    1020                 :       67080 :           if (pre_exit)
    1021                 :             :             {
    1022                 :       65696 :               info[pre_exit->index].mode_out =
    1023                 :       65696 :                 info[pre_exit->index].mode_in = no_mode;
    1024                 :             : 
    1025                 :       65696 :               int mode = targetm.mode_switching.exit (e);
    1026                 :       65696 :               if (mode != no_mode)
    1027                 :             :                 {
    1028                 :       64494 :                   info[pre_exit->index].seginfo->mode = mode;
    1029                 :       64494 :                   bitmap_clear_bit (transp_all, pre_exit->index);
    1030                 :             :                 }
    1031                 :             :             }
    1032                 :             :         }
    1033                 :             : 
    1034                 :             :       /* If the target requests it, back-propagate selected mode requirements
    1035                 :             :          through transparent blocks.  */
    1036                 :       67080 :       if (targetm.mode_switching.backprop)
    1037                 :             :         {
    1038                 :             :           /* First work out the mode on entry to and exit from each block.  */
    1039                 :           0 :           forwprop_mode_info (info, e, no_mode);
    1040                 :             : 
    1041                 :             :           /* Compute the single_succ fields, as described above
    1042                 :             :              single_succ_confluence.  */
    1043                 :           0 :           FOR_EACH_BB_FN (bb, cfun)
    1044                 :           0 :             info[bb->index].single_succ = no_mode + 1;
    1045                 :             : 
    1046                 :           0 :           confluence_info.transp = transp_all;
    1047                 :           0 :           bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
    1048                 :           0 :           df_simple_dataflow (DF_BACKWARD, NULL, NULL,
    1049                 :             :                               single_succ_confluence_n,
    1050                 :             :                               single_succ_transfer, blocks,
    1051                 :             :                               df_get_postorder (DF_BACKWARD),
    1052                 :             :                               df_get_n_blocks (DF_BACKWARD));
    1053                 :             : 
    1054                 :           0 :           FOR_EACH_BB_FN (bb, cfun)
    1055                 :             :             {
    1056                 :             :               /* Repurpose mode_in as the first mode required by the block,
    1057                 :             :                  or the output mode if none.  */
    1058                 :           0 :               if (info[bb->index].seginfo->mode != no_mode)
    1059                 :           0 :                 info[bb->index].mode_in = info[bb->index].seginfo->mode;
    1060                 :             : 
    1061                 :             :               /* In transparent blocks, use computing == no_mode + 1
    1062                 :             :                  to indicate that no propagation has taken place.  */
    1063                 :           0 :               if (info[bb->index].computing == no_mode)
    1064                 :           0 :                 info[bb->index].computing = no_mode + 1;
    1065                 :             :             }
    1066                 :             : 
    1067                 :           0 :           bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
    1068                 :           0 :           df_simple_dataflow (DF_BACKWARD, NULL, NULL, backprop_confluence_n,
    1069                 :             :                               backprop_transfer, blocks,
    1070                 :             :                               df_get_postorder (DF_BACKWARD),
    1071                 :             :                               df_get_n_blocks (DF_BACKWARD));
    1072                 :             : 
    1073                 :             :           /* Any block that now computes a mode is no longer transparent.  */
    1074                 :           0 :           FOR_EACH_BB_FN (bb, cfun)
    1075                 :           0 :             if (info[bb->index].computing == no_mode + 1)
    1076                 :           0 :               info[bb->index].computing = no_mode;
    1077                 :           0 :             else if (info[bb->index].computing != no_mode)
    1078                 :           0 :               bitmap_clear_bit (transp_all, bb->index);
    1079                 :             :         }
    1080                 :             : 
    1081                 :             :       /* Set the anticipatable and computing arrays.  */
    1082                 :      204800 :       for (i = 0; i < no_mode; i++)
    1083                 :             :         {
    1084                 :      137720 :           int m = targetm.mode_switching.priority (entity_map[j], i);
    1085                 :             : 
    1086                 :     1436829 :           FOR_EACH_BB_FN (bb, cfun)
    1087                 :             :             {
    1088                 :     1299109 :               if (!bitmap_bit_p (transp_all, bb->index))
    1089                 :      496387 :                 clear_mode_bit (transp[bb->index], j, m);
    1090                 :             : 
    1091                 :     1299109 :               if (info[bb->index].seginfo->mode == m)
    1092                 :      150598 :                 set_mode_bit (antic[bb->index], j, m);
    1093                 :             : 
    1094                 :     1299109 :               if (info[bb->index].computing == m)
    1095                 :      150237 :                 set_mode_bit (comp[bb->index], j, m);
    1096                 :             :             }
    1097                 :             :         }
    1098                 :             :     }
    1099                 :             : 
    1100                 :             :   /* Calculate the optimal locations for the
    1101                 :             :      placement mode switches to modes with priority I.  */
    1102                 :             : 
    1103                 :      583942 :   FOR_EACH_BB_FN (bb, cfun)
    1104                 :      516878 :     bitmap_not (kill[bb->index], transp[bb->index]);
    1105                 :             : 
    1106                 :       67064 :   edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic,
    1107                 :             :                                 kill, avin, avout, &insert, &del);
    1108                 :             : 
    1109                 :       67064 :   auto_sbitmap jumping_blocks (last_basic_block_for_fn (cfun));
    1110                 :       67064 :   bitmap_clear (jumping_blocks);
    1111                 :      134144 :   for (j = n_entities - 1; j >= 0; j--)
    1112                 :             :     {
    1113                 :       67080 :       int no_mode = num_modes[entity_map[j]];
    1114                 :       67080 :       struct bb_info *info = bb_info[j];
    1115                 :             : 
    1116                 :             :       /* Insert all mode sets that have been inserted by lcm.  */
    1117                 :             : 
    1118                 :      836689 :       for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
    1119                 :             :         {
    1120                 :      769609 :           edge eg = INDEX_EDGE (edge_list, ed);
    1121                 :             : 
    1122                 :      769609 :           eg->aux = (void *) (intptr_t) 0;
    1123                 :             : 
    1124                 :     2726887 :           for (i = 0; i < no_mode; i++)
    1125                 :             :             {
    1126                 :     1967072 :               int m = targetm.mode_switching.priority (entity_map[j], i);
    1127                 :     1967072 :               if (mode_bit_p (insert[ed], j, m))
    1128                 :             :                 {
    1129                 :        9794 :                   eg->aux = (void *) (intptr_t) (m + 1);
    1130                 :        9794 :                   break;
    1131                 :             :                 }
    1132                 :             :             }
    1133                 :             :         }
    1134                 :             : 
    1135                 :             :       /* mode_in and mode_out can be calculated directly from avin and
    1136                 :             :          avout if all the modes are mutually exclusive.  Use the target-
    1137                 :             :          provided confluence function otherwise.  */
    1138                 :       67080 :       if (targetm.mode_switching.confluence)
    1139                 :           0 :         forwprop_mode_info (info, entity_map[j], no_mode);
    1140                 :             : 
    1141                 :      584354 :       FOR_EACH_BB_FN (bb, cfun)
    1142                 :             :         {
    1143                 :     1551822 :           auto modes_confluence = [&](sbitmap *av)
    1144                 :             :             {
    1145                 :     2210941 :               for (int i = 0; i < no_mode; ++i)
    1146                 :     2007290 :                 if (mode_bit_p (av[bb->index], j, i))
    1147                 :             :                   {
    1148                 :     1421825 :                     for (int i2 = i + 1; i2 < no_mode; ++i2)
    1149                 :      590928 :                       if (mode_bit_p (av[bb->index], j, i2))
    1150                 :             :                         return no_mode;
    1151                 :             :                     return i;
    1152                 :             :                   }
    1153                 :             :               return no_mode;
    1154                 :      517274 :             };
    1155                 :             : 
    1156                 :             :           /* intialize mode in/out availability for bb.  */
    1157                 :      517274 :           if (!targetm.mode_switching.confluence)
    1158                 :             :             {
    1159                 :      517274 :               info[bb->index].mode_out = modes_confluence (avout);
    1160                 :      517274 :               info[bb->index].mode_in = modes_confluence (avin);
    1161                 :             :             }
    1162                 :             : 
    1163                 :     1816383 :           for (i = 0; i < no_mode; i++)
    1164                 :     1299109 :             if (mode_bit_p (del[bb->index], j, i))
    1165                 :      123178 :               info[bb->index].seginfo->mode = no_mode;
    1166                 :             : 
    1167                 :             :           /* See whether the target can perform the first transition.
    1168                 :             :              If not, push it onto the incoming edges.  The earlier backprop
    1169                 :             :              pass should ensure that the resulting transitions are valid.  */
    1170                 :      517274 :           if (targetm.mode_switching.backprop)
    1171                 :             :             {
    1172                 :           0 :               int from_mode = info[bb->index].mode_in;
    1173                 :           0 :               int to_mode = info[bb->index].seginfo->mode;
    1174                 :           0 :               if (targetm.mode_switching.backprop (entity_map[j], from_mode,
    1175                 :           0 :                                                    to_mode) != no_mode)
    1176                 :             :                 {
    1177                 :           0 :                   for (edge e : bb->preds)
    1178                 :           0 :                     e->aux = (void *) (intptr_t) (to_mode + 1);
    1179                 :           0 :                   info[bb->index].mode_in = to_mode;
    1180                 :             :                 }
    1181                 :             :             }
    1182                 :             :         }
    1183                 :             : 
    1184                 :             :       /* Now output the remaining mode sets in all the segments.  */
    1185                 :             : 
    1186                 :             :       /* In case there was no mode inserted. the mode information on the edge
    1187                 :             :          might not be complete.
    1188                 :             :          Update mode info on edges and commit pending mode sets.  */
    1189                 :       67080 :       need_commit |= commit_mode_sets (edge_list, entity_map[j], bb_info[j]);
    1190                 :             : 
    1191                 :             :       /* Reset modes for next entity.  */
    1192                 :       67080 :       clear_aux_for_edges ();
    1193                 :             : 
    1194                 :      584354 :       FOR_EACH_BB_FN (bb, cfun)
    1195                 :             :         {
    1196                 :      517274 :           struct seginfo *ptr, *next;
    1197                 :      517274 :           struct seginfo *first = bb_info[j][bb->index].seginfo;
    1198                 :             : 
    1199                 :     1042953 :           for (ptr = first; ptr; ptr = next)
    1200                 :             :             {
    1201                 :      525679 :               next = ptr->next;
    1202                 :      525679 :               if (ptr->mode != no_mode)
    1203                 :             :                 {
    1204                 :       35458 :                   rtx_insn *mode_set;
    1205                 :             : 
    1206                 :       35458 :                   rtl_profile_for_bb (bb);
    1207                 :       35458 :                   start_sequence ();
    1208                 :             : 
    1209                 :       27420 :                   int cur_mode = (ptr == first && ptr->prev_mode == no_mode
    1210                 :       62878 :                                   ? bb_info[j][bb->index].mode_in
    1211                 :             :                                   : ptr->prev_mode);
    1212                 :             : 
    1213                 :       35458 :                   targetm.mode_switching.emit (entity_map[j], ptr->mode,
    1214                 :             :                                                cur_mode, ptr->regs_live);
    1215                 :       35458 :                   mode_set = get_insns ();
    1216                 :       35458 :                   end_sequence ();
    1217                 :             : 
    1218                 :             :                   /* Insert MODE_SET only if it is nonempty.  */
    1219                 :       35458 :                   if (mode_set != NULL_RTX)
    1220                 :             :                     {
    1221                 :       33957 :                       for (auto insn = mode_set; insn; insn = NEXT_INSN (insn))
    1222                 :       19308 :                         if (JUMP_P (insn))
    1223                 :             :                           {
    1224                 :           0 :                             rebuild_jump_labels_chain (mode_set);
    1225                 :           0 :                             bitmap_set_bit (jumping_blocks, bb->index);
    1226                 :           0 :                             break;
    1227                 :             :                           }
    1228                 :       14649 :                       emitted = true;
    1229                 :       14649 :                       if (NOTE_INSN_BASIC_BLOCK_P (ptr->insn_ptr))
    1230                 :             :                         /* We need to emit the insns in a FIFO-like manner,
    1231                 :             :                            i.e. the first to be emitted at our insertion
    1232                 :             :                            point ends up first in the instruction steam.
    1233                 :             :                            Because we made sure that NOTE_INSN_BASIC_BLOCK is
    1234                 :             :                            only used for initially empty basic blocks, we
    1235                 :             :                            can achieve this by appending at the end of
    1236                 :             :                            the block.  */
    1237                 :        5380 :                         emit_insn_after
    1238                 :        5380 :                           (mode_set, BB_END (NOTE_BASIC_BLOCK (ptr->insn_ptr)));
    1239                 :             :                       else
    1240                 :        9269 :                         emit_insn_before (mode_set, ptr->insn_ptr);
    1241                 :             :                     }
    1242                 :             : 
    1243                 :       35458 :                   default_rtl_profile ();
    1244                 :             :                 }
    1245                 :             : 
    1246                 :      525679 :               free (ptr);
    1247                 :             :             }
    1248                 :             :         }
    1249                 :             : 
    1250                 :       67080 :       free (bb_info[j]);
    1251                 :             :     }
    1252                 :             : 
    1253                 :       67064 :   free_edge_list (edge_list);
    1254                 :             : 
    1255                 :             :   /* Finished. Free up all the things we've allocated.  */
    1256                 :       67064 :   sbitmap_vector_free (del);
    1257                 :       67064 :   sbitmap_vector_free (insert);
    1258                 :       67064 :   sbitmap_vector_free (kill);
    1259                 :       67064 :   sbitmap_vector_free (antic);
    1260                 :       67064 :   sbitmap_vector_free (transp);
    1261                 :       67064 :   sbitmap_vector_free (comp);
    1262                 :       67064 :   sbitmap_vector_free (avin);
    1263                 :       67064 :   sbitmap_vector_free (avout);
    1264                 :             : 
    1265                 :       67064 :   gcc_assert (SBITMAP_SIZE ((sbitmap) jumping_blocks)
    1266                 :             :               == (unsigned int) last_basic_block_for_fn (cfun));
    1267                 :       67064 :   if (!bitmap_empty_p (jumping_blocks))
    1268                 :           0 :     find_many_sub_basic_blocks (jumping_blocks);
    1269                 :             : 
    1270                 :       67064 :   if (need_commit)
    1271                 :        1237 :     commit_edge_insertions ();
    1272                 :             : 
    1273                 :       67064 :   if (targetm.mode_switching.entry && targetm.mode_switching.exit)
    1274                 :             :     {
    1275                 :       67064 :       free_dominance_info (CDI_DOMINATORS);
    1276                 :       67064 :       cleanup_cfg (CLEANUP_NO_INSN_DEL);
    1277                 :             :     }
    1278                 :           0 :   else if (!need_commit && !emitted)
    1279                 :             :     return 0;
    1280                 :             : 
    1281                 :             :   return 1;
    1282                 :       67064 : }
    1283                 :             : 
    1284                 :             : #endif /* OPTIMIZE_MODE_SWITCHING */
    1285                 :             : 
    1286                 :             : namespace {
    1287                 :             : 
    1288                 :             : const pass_data pass_data_mode_switching =
    1289                 :             : {
    1290                 :             :   RTL_PASS, /* type */
    1291                 :             :   "mode_sw", /* name */
    1292                 :             :   OPTGROUP_NONE, /* optinfo_flags */
    1293                 :             :   TV_MODE_SWITCH, /* tv_id */
    1294                 :             :   0, /* properties_required */
    1295                 :             :   0, /* properties_provided */
    1296                 :             :   0, /* properties_destroyed */
    1297                 :             :   0, /* todo_flags_start */
    1298                 :             :   TODO_df_finish, /* todo_flags_finish */
    1299                 :             : };
    1300                 :             : 
    1301                 :             : class pass_mode_switching : public rtl_opt_pass
    1302                 :             : {
    1303                 :             : public:
    1304                 :      281914 :   pass_mode_switching (gcc::context *ctxt)
    1305                 :      563828 :     : rtl_opt_pass (pass_data_mode_switching, ctxt)
    1306                 :             :   {}
    1307                 :             : 
    1308                 :             :   /* opt_pass methods: */
    1309                 :             :   /* The epiphany backend creates a second instance of this pass, so we need
    1310                 :             :      a clone method.  */
    1311                 :           0 :   opt_pass * clone () final override { return new pass_mode_switching (m_ctxt); }
    1312                 :     1426773 :   bool gate (function *) final override
    1313                 :             :     {
    1314                 :             : #ifdef OPTIMIZE_MODE_SWITCHING
    1315                 :     1426773 :       return true;
    1316                 :             : #else
    1317                 :             :       return false;
    1318                 :             : #endif
    1319                 :             :     }
    1320                 :             : 
    1321                 :     1492499 :   unsigned int execute (function *) final override
    1322                 :             :     {
    1323                 :             : #ifdef OPTIMIZE_MODE_SWITCHING
    1324                 :     1492499 :       optimize_mode_switching ();
    1325                 :             : #endif /* OPTIMIZE_MODE_SWITCHING */
    1326                 :     1492499 :       return 0;
    1327                 :             :     }
    1328                 :             : 
    1329                 :             : }; // class pass_mode_switching
    1330                 :             : 
    1331                 :             : } // anon namespace
    1332                 :             : 
    1333                 :             : rtl_opt_pass *
    1334                 :      281914 : make_pass_mode_switching (gcc::context *ctxt)
    1335                 :             : {
    1336                 :      281914 :   return new pass_mode_switching (ctxt);
    1337                 :             : }
        

Generated by: LCOV version 2.1-beta

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