(root)/
gcc-13.2.0/
gcc/
rtl-ssa/
movement.h
       1  // RTL SSA utilities relating to instruction movement               -*- C++ -*-
       2  // Copyright (C) 2020-2023 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  namespace rtl_ssa {
      21  
      22  // Restrict movement range RANGE so that the instruction is placed later
      23  // than INSN.  (The movement range is the range of instructions after which
      24  // an instruction can be placed.)
      25  inline insn_range_info
      26  move_later_than (insn_range_info range, insn_info *insn)
      27  {
      28    return { later_insn (range.first, insn), range.last };
      29  }
      30  
      31  // Restrict movement range RANGE so that the instruction is placed no earlier
      32  // than INSN.  (The movement range is the range of instructions after which
      33  // an instruction can be placed.)
      34  inline insn_range_info
      35  move_no_earlier_than (insn_range_info range, insn_info *insn)
      36  {
      37    insn_info *first = later_insn (range.first, insn->prev_nondebug_insn ());
      38    return { first, range.last };
      39  }
      40  
      41  // Restrict movement range RANGE so that the instruction is placed no later
      42  // than INSN.  (The movement range is the range of instructions after which
      43  // an instruction can be placed.)
      44  inline insn_range_info
      45  move_no_later_than (insn_range_info range, insn_info *insn)
      46  {
      47    return { range.first, earlier_insn (range.last, insn) };
      48  }
      49  
      50  // Restrict movement range RANGE so that the instruction is placed earlier
      51  // than INSN.  (The movement range is the range of instructions after which
      52  // an instruction can be placed.)
      53  inline insn_range_info
      54  move_earlier_than (insn_range_info range, insn_info *insn)
      55  {
      56    insn_info *last = earlier_insn (range.last, insn->prev_nondebug_insn ());
      57    return { range.first, last };
      58  }
      59  
      60  // Return true if it is possible to insert a new instruction after INSN.
      61  inline bool
      62  can_insert_after (insn_info *insn)
      63  {
      64    return insn->is_bb_head () || (insn->is_real () && !insn->is_jump ());
      65  }
      66  
      67  // Try to restrict move range MOVE_RANGE so that it is possible to
      68  // insert INSN after both of the end points.  Return true on success,
      69  // otherwise leave MOVE_RANGE in an invalid state.
      70  inline bool
      71  canonicalize_move_range (insn_range_info &move_range, insn_info *insn)
      72  {
      73    while (move_range.first != insn && !can_insert_after (move_range.first))
      74      move_range.first = move_range.first->next_nondebug_insn ();
      75    while (move_range.last != insn && !can_insert_after (move_range.last))
      76      move_range.last = move_range.last->prev_nondebug_insn ();
      77    return bool (move_range);
      78  }
      79  
      80  // Try to restrict movement range MOVE_RANGE of INSN so that it can set
      81  // or clobber REGNO.  Assume that if:
      82  //
      83  // - an instruction I2 contains another access A to REGNO; and
      84  // - IGNORE (I2) is true
      85  //
      86  // then either:
      87  //
      88  // - A will be removed; or
      89  // - something will ensure that the new definition of REGNO does not
      90  //   interfere with A, without this having to be enforced by I1's move range.
      91  //
      92  // Return true on success, otherwise leave MOVE_RANGE in an invalid state.
      93  //
      94  // This function only works correctly for instructions that remain within
      95  // the same extended basic block.
      96  template<typename IgnorePredicate>
      97  bool
      98  restrict_movement_for_dead_range (insn_range_info &move_range,
      99  				  unsigned int regno, insn_info *insn,
     100  				  IgnorePredicate ignore)
     101  {
     102    // Find a definition at or neighboring INSN.
     103    resource_info resource = full_register (regno);
     104    def_lookup dl = crtl->ssa->find_def (resource, insn);
     105  
     106    def_info *prev = dl.last_def_of_prev_group ();
     107    ebb_info *ebb = insn->ebb ();
     108    if (!prev || prev->ebb () != ebb)
     109      {
     110        // REGNO is not defined or used in EBB before INSN, but it
     111        // might be live on entry.  To keep complexity under control,
     112        // handle only these cases:
     113        //
     114        // - If the register is not live on entry to EBB, the register is
     115        //   free from the start of EBB to the first definition in EBB.
     116        //
     117        // - Otherwise, if the register is live on entry to BB, refuse
     118        //   to allocate the register.  We could in principle try to move
     119        //   the instruction to later blocks in the EBB, but it's rarely
     120        //   worth the effort, and could lead to linear complexity.
     121        //
     122        // - Otherwise, don't allow INSN to move earlier than its current
     123        //   block.  Again, we could in principle look backwards to find where
     124        //   REGNO dies, but it's rarely worth the effort.
     125        bb_info *bb = insn->bb ();
     126        insn_info *limit;
     127        if (!bitmap_bit_p (DF_LR_IN (ebb->first_bb ()->cfg_bb ()), regno))
     128  	limit = ebb->phi_insn ();
     129        else if (bitmap_bit_p (DF_LR_IN (bb->cfg_bb ()), regno))
     130  	return false;
     131        else
     132  	limit = bb->head_insn ();
     133        move_range = move_later_than (move_range, limit);
     134      }
     135    else
     136      {
     137        // Stop the instruction moving beyond the previous relevant access
     138        // to REGNO.
     139        access_info *prev_access
     140  	= last_access_ignoring (prev, ignore_clobbers::YES, ignore);
     141        if (prev_access)
     142  	move_range = move_later_than (move_range, access_insn (prev_access));
     143      }
     144  
     145    // Stop the instruction moving beyond the next relevant definition of REGNO.
     146    def_info *next = dl.matching_set_or_first_def_of_next_group ();
     147    next = first_def_ignoring (next, ignore_clobbers::YES, ignore);
     148    if (next)
     149      move_range = move_earlier_than (move_range, next->insn ());
     150  
     151    return canonicalize_move_range (move_range, insn);
     152  }
     153  
     154  // Try to restrict movement range MOVE_RANGE so that it is possible for the
     155  // instruction being moved ("instruction I1") to perform all the definitions
     156  // in DEFS while still preserving dependencies between those definitions
     157  // and surrounding instructions.  Assume that if:
     158  //
     159  // - DEFS contains a definition D of resource R;
     160  // - an instruction I2 contains another access A to R; and
     161  // - IGNORE (I2) is true
     162  //
     163  // then either:
     164  //
     165  // - A will be removed; or
     166  // - something will ensure that D and A maintain their current order,
     167  //   without this having to be enforced by I1's move range.
     168  //
     169  // Return true on success, otherwise leave MOVE_RANGE in an invalid state.
     170  //
     171  // This function only works correctly for instructions that remain within
     172  // the same extended basic block.
     173  template<typename IgnorePredicate>
     174  bool
     175  restrict_movement_for_defs_ignoring (insn_range_info &move_range,
     176  				     def_array defs, IgnorePredicate ignore)
     177  {
     178    for (def_info *def : defs)
     179      {
     180        // If the definition is a clobber, we can move it with respect
     181        // to other clobbers.
     182        //
     183        // ??? We could also do this if a definition and all its uses
     184        // are being moved at once.
     185        bool is_clobber = is_a<clobber_info *> (def);
     186  
     187        // Search back for the first unfiltered use or definition of the
     188        // same resource.
     189        access_info *access;
     190        access = prev_access_ignoring (def, ignore_clobbers (is_clobber),
     191  				     ignore);
     192        if (access)
     193  	move_range = move_later_than (move_range, access_insn (access));
     194  
     195        // Search forward for the first unfiltered use of DEF,
     196        // or the first unfiltered definition that follows DEF.
     197        //
     198        // We don't need to consider uses of following definitions, since
     199        // if IGNORE (D->insn ()) is true for some definition D, the caller
     200        // is guarantees that either
     201        //
     202        // - D will be removed, and thus its uses will be removed; or
     203        // - D will occur after DEF, and thus D's uses will also occur
     204        //   after DEF.
     205        //
     206        // This is purely a simplification: we could also process D's uses,
     207        // but we don't need to.
     208        access = next_access_ignoring (def, ignore_clobbers (is_clobber),
     209  				     ignore);
     210        if (access)
     211  	move_range = move_earlier_than (move_range, access_insn (access));
     212  
     213        // If DEF sets a hard register, take any call clobbers
     214        // into account.
     215        unsigned int regno = def->regno ();
     216        if (!HARD_REGISTER_NUM_P (regno) || is_clobber)
     217  	continue;
     218  
     219        ebb_info *ebb = def->ebb ();
     220        for (ebb_call_clobbers_info *call_group : ebb->call_clobbers ())
     221  	{
     222  	  if (!call_group->clobbers (def->resource ()))
     223  	    continue;
     224  
     225  	  // Exit now if we've already failed, and if the splay accesses
     226  	  // below would be wasted work.
     227  	  if (!move_range)
     228  	    return false;
     229  
     230  	  insn_info *insn;
     231  	  insn = prev_call_clobbers_ignoring (*call_group, def->insn (),
     232  					      ignore);
     233  	  if (insn)
     234  	    move_range = move_later_than (move_range, insn);
     235  
     236  	  insn = next_call_clobbers_ignoring (*call_group, def->insn (),
     237  					      ignore);
     238  	  if (insn)
     239  	    move_range = move_earlier_than (move_range, insn);
     240  	}
     241      }
     242  
     243    // Make sure that we don't move stores between basic blocks, since we
     244    // don't have enough information to tell whether it's safe.
     245    if (def_info *def = memory_access (defs))
     246      {
     247        move_range = move_later_than (move_range, def->bb ()->head_insn ());
     248        move_range = move_earlier_than (move_range, def->bb ()->end_insn ());
     249      }
     250  
     251    return bool (move_range);
     252  }
     253  
     254  // Like restrict_movement_for_defs_ignoring, but for the uses in USES.
     255  template<typename IgnorePredicate>
     256  bool
     257  restrict_movement_for_uses_ignoring (insn_range_info &move_range,
     258  				     use_array uses, IgnorePredicate ignore)
     259  {
     260    for (const use_info *use : uses)
     261      {
     262        // Ignore uses of undefined values.
     263        set_info *set = use->def ();
     264        if (!set)
     265  	continue;
     266  
     267        // Ignore uses by debug instructions.  Debug instructions are
     268        // never supposed to move, and uses by debug instructions are
     269        // never supposed to be transferred elsewhere, so we know that
     270        // the caller must be changing the uses on the debug instruction
     271        // and checking whether all new uses are available at the debug
     272        // instruction's original location.
     273        if (use->is_in_debug_insn ())
     274  	continue;
     275  
     276        // If the used value is defined by an instruction I2 for which
     277        // IGNORE (I2) is true, the caller guarantees that I2 will occur
     278        // before change.insn ().  Otherwise, make sure that the use occurs
     279        // after the definition.
     280        insn_info *insn = set->insn ();
     281        if (!ignore (insn))
     282  	move_range = move_later_than (move_range, insn);
     283  
     284        // Search forward for the first unfiltered definition that follows SET.
     285        //
     286        // We don't need to consider the uses of these definitions, since
     287        // if IGNORE (D->insn ()) is true for some definition D, the caller
     288        // is guarantees that either
     289        //
     290        // - D will be removed, and thus its uses will be removed; or
     291        // - D will occur after USE, and thus D's uses will also occur
     292        //   after USE.
     293        //
     294        // This is purely a simplification: we could also process D's uses,
     295        // but we don't need to.
     296        def_info *def;
     297        def = first_def_ignoring (set->next_def (), ignore_clobbers::NO,
     298  				ignore);
     299        if (def)
     300  	move_range = move_earlier_than (move_range, def->insn ());
     301  
     302        // If USE uses a hard register, take any call clobbers into account too.
     303        // SET will necessarily occur after any previous call clobber, so we
     304        // only need to check for later clobbers.
     305        unsigned int regno = use->regno ();
     306        if (!HARD_REGISTER_NUM_P (regno))
     307  	continue;
     308  
     309        ebb_info *ebb = use->ebb ();
     310        for (ebb_call_clobbers_info *call_group : ebb->call_clobbers ())
     311  	{
     312  	  if (!call_group->clobbers (use->resource ()))
     313  	    continue;
     314  
     315  	  if (!move_range)
     316  	    return false;
     317  
     318  	  insn_info *insn = next_call_clobbers_ignoring (*call_group,
     319  							 use->insn (), ignore);
     320  	  if (insn)
     321  	    move_range = move_earlier_than (move_range, insn);
     322  	}
     323      }
     324  
     325    // Make sure that we don't move loads into an earlier basic block.
     326    //
     327    // ??? It would be good to relax this for loads that can be safely
     328    // speculated.
     329    if (use_info *use = memory_access (uses))
     330      move_range = move_later_than (move_range, use->bb ()->head_insn ());
     331  
     332    return bool (move_range);
     333  }
     334  
     335  }