LCOV - code coverage report
Current view: top level - gcc - mode-switching.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 65.8 % 518 341
Test Date: 2026-02-28 14:20:25 Functions: 60.0 % 20 12
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-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.