mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /* Coalesce spilled pseudos.
 | |
|    Copyright (C) 2010-2019 Free Software Foundation, Inc.
 | |
|    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 | |
| 
 | |
| This file is part of GCC.
 | |
| 
 | |
| GCC is free software; you can redistribute it and/or modify it under
 | |
| the terms of the GNU General Public License as published by the Free
 | |
| Software Foundation; either version 3, or (at your option) any later
 | |
| version.
 | |
| 
 | |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
| FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 | |
| for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GCC; see the file COPYING3.	If not see
 | |
| <http://www.gnu.org/licenses/>.	 */
 | |
| 
 | |
| 
 | |
| /* This file contains a pass making some simple RTL code
 | |
|    transformations by coalescing pseudos to remove some move insns.
 | |
| 
 | |
|    Spilling pseudos in LRA can create memory-memory moves.  We should
 | |
|    remove potential memory-memory moves before the next constraint
 | |
|    pass because the constraint pass will generate additional insns for
 | |
|    such moves and all these insns will be hard to remove afterwards.
 | |
| 
 | |
|    Here we coalesce only spilled pseudos.  Coalescing non-spilled
 | |
|    pseudos (with different hard regs) might result in spilling
 | |
|    additional pseudos because of possible conflicts with other
 | |
|    non-spilled pseudos and, as a consequence, in more constraint
 | |
|    passes and even LRA infinite cycling.  Trivial the same hard
 | |
|    register moves will be removed by subsequent compiler passes.
 | |
| 
 | |
|    We don't coalesce special reload pseudos.  It complicates LRA code
 | |
|    a lot without visible generated code improvement.
 | |
| 
 | |
|    The pseudo live-ranges are used to find conflicting pseudos during
 | |
|    coalescing.
 | |
| 
 | |
|    Most frequently executed moves is tried to be coalesced first.  */
 | |
| 
 | |
| #include "config.h"
 | |
| #include "system.h"
 | |
| #include "coretypes.h"
 | |
| #include "backend.h"
 | |
| #include "rtl.h"
 | |
| #include "predict.h"
 | |
| #include "df.h"
 | |
| #include "insn-config.h"
 | |
| #include "regs.h"
 | |
| #include "memmodel.h"
 | |
| #include "ira.h"
 | |
| #include "recog.h"
 | |
| #include "lra-int.h"
 | |
| 
 | |
| /* Arrays whose elements represent the first and the next pseudo
 | |
|    (regno) in the coalesced pseudos group to which given pseudo (its
 | |
|    regno is the index) belongs.	 The next of the last pseudo in the
 | |
|    group refers to the first pseudo in the group, in other words the
 | |
|    group is represented by a cyclic list.  */
 | |
| static int *first_coalesced_pseudo, *next_coalesced_pseudo;
 | |
| 
 | |
| /* The function is used to sort moves according to their execution
 | |
|    frequencies.	 */
 | |
| static int
 | |
| move_freq_compare_func (const void *v1p, const void *v2p)
 | |
| {
 | |
|   rtx_insn *mv1 = *(rtx_insn * const *) v1p;
 | |
|   rtx_insn *mv2 = *(rtx_insn * const *) v2p;
 | |
|   int pri1, pri2;
 | |
| 
 | |
|   pri1 = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv1));
 | |
|   pri2 = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv2));
 | |
|   if (pri2 - pri1)
 | |
|     return pri2 - pri1;
 | |
| 
 | |
|   /* If frequencies are equal, sort by moves, so that the results of
 | |
|      qsort leave nothing to chance.  */
 | |
|   return (int) INSN_UID (mv1) - (int) INSN_UID (mv2);
 | |
| }
 | |
| 
 | |
| /* Pseudos which go away after coalescing.  */
 | |
| static bitmap_head coalesced_pseudos_bitmap;
 | |
| 
 | |
| /* Merge two sets of coalesced pseudos given correspondingly by
 | |
|    pseudos REGNO1 and REGNO2 (more accurately merging REGNO2 group
 | |
|    into REGNO1 group).	Set up COALESCED_PSEUDOS_BITMAP.  */
 | |
| static void
 | |
| merge_pseudos (int regno1, int regno2)
 | |
| {
 | |
|   int regno, first, first2, last, next;
 | |
| 
 | |
|   first = first_coalesced_pseudo[regno1];
 | |
|   if ((first2 = first_coalesced_pseudo[regno2]) == first)
 | |
|     return;
 | |
|   for (last = regno2, regno = next_coalesced_pseudo[regno2];;
 | |
|        regno = next_coalesced_pseudo[regno])
 | |
|     {
 | |
|       first_coalesced_pseudo[regno] = first;
 | |
|       bitmap_set_bit (&coalesced_pseudos_bitmap, regno);
 | |
|       if (regno == regno2)
 | |
| 	break;
 | |
|       last = regno;
 | |
|     }
 | |
|   next = next_coalesced_pseudo[first];
 | |
|   next_coalesced_pseudo[first] = regno2;
 | |
|   next_coalesced_pseudo[last] = next;
 | |
|   lra_reg_info[first].live_ranges
 | |
|     = (lra_merge_live_ranges
 | |
|        (lra_reg_info[first].live_ranges,
 | |
| 	lra_copy_live_range_list (lra_reg_info[first2].live_ranges)));
 | |
|   if (partial_subreg_p (lra_reg_info[first].biggest_mode,
 | |
| 			lra_reg_info[first2].biggest_mode))
 | |
|     lra_reg_info[first].biggest_mode = lra_reg_info[first2].biggest_mode;
 | |
| }
 | |
| 
 | |
| /* Change pseudos in *LOC on their coalescing group
 | |
|    representatives.  */
 | |
| static bool
 | |
| substitute (rtx *loc)
 | |
| {
 | |
|   int i, regno;
 | |
|   const char *fmt;
 | |
|   enum rtx_code code;
 | |
|   bool res;
 | |
| 
 | |
|   if (*loc == NULL_RTX)
 | |
|     return false;
 | |
|   code = GET_CODE (*loc);
 | |
|   if (code == REG)
 | |
|     {
 | |
|       regno = REGNO (*loc);
 | |
|       if (regno < FIRST_PSEUDO_REGISTER
 | |
| 	  || first_coalesced_pseudo[regno] == regno)
 | |
| 	return false;
 | |
|       *loc = regno_reg_rtx[first_coalesced_pseudo[regno]];
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|   res = false;
 | |
|   fmt = GET_RTX_FORMAT (code);
 | |
|   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
 | |
|     {
 | |
|       if (fmt[i] == 'e')
 | |
| 	{
 | |
| 	  if (substitute (&XEXP (*loc, i)))
 | |
| 	    res = true;
 | |
| 	}
 | |
|       else if (fmt[i] == 'E')
 | |
| 	{
 | |
| 	  int j;
 | |
| 
 | |
| 	  for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
 | |
| 	    if (substitute (&XVECEXP (*loc, i, j)))
 | |
| 	      res = true;
 | |
| 	}
 | |
|     }
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| /* Specialize "substitute" for use on an insn.  This can't change
 | |
|    the insn ptr, just the contents of the insn.  */
 | |
| 
 | |
| static bool
 | |
| substitute_within_insn (rtx_insn *insn)
 | |
| {
 | |
|   rtx loc = insn;
 | |
|   return substitute (&loc);
 | |
| }
 | |
| 
 | |
| /* The current iteration (1, 2, ...) of the coalescing pass.  */
 | |
| int lra_coalesce_iter;
 | |
| 
 | |
| /* Return true if the move involving REGNO1 and REGNO2 is a potential
 | |
|    memory-memory move.	*/
 | |
| static bool
 | |
| mem_move_p (int regno1, int regno2)
 | |
| {
 | |
|   return reg_renumber[regno1] < 0 && reg_renumber[regno2] < 0;
 | |
| }
 | |
| 
 | |
| /* Pseudos used instead of the coalesced pseudos.  */
 | |
| static bitmap_head used_pseudos_bitmap;
 | |
| 
 | |
| /* Set up USED_PSEUDOS_BITMAP, and update LR_BITMAP (a BB live info
 | |
|    bitmap).  */
 | |
| static void
 | |
| update_live_info (bitmap lr_bitmap)
 | |
| {
 | |
|   unsigned int j;
 | |
|   bitmap_iterator bi;
 | |
| 
 | |
|   bitmap_clear (&used_pseudos_bitmap);
 | |
|   EXECUTE_IF_AND_IN_BITMAP (&coalesced_pseudos_bitmap, lr_bitmap,
 | |
| 			    FIRST_PSEUDO_REGISTER, j, bi)
 | |
|     bitmap_set_bit (&used_pseudos_bitmap, first_coalesced_pseudo[j]);
 | |
|   if (! bitmap_empty_p (&used_pseudos_bitmap))
 | |
|     {
 | |
|       bitmap_and_compl_into (lr_bitmap, &coalesced_pseudos_bitmap);
 | |
|       bitmap_ior_into (lr_bitmap, &used_pseudos_bitmap);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Return true if pseudo REGNO can be potentially coalesced.  */
 | |
| static bool
 | |
| coalescable_pseudo_p (int regno)
 | |
| {
 | |
|   lra_assert (regno >= FIRST_PSEUDO_REGISTER);
 | |
|   return (/* We don't want to coalesce regnos with equivalences, at
 | |
| 	     least without updating this info.  */
 | |
| 	  ira_reg_equiv[regno].constant == NULL_RTX
 | |
| 	  && ira_reg_equiv[regno].memory == NULL_RTX
 | |
| 	  && ira_reg_equiv[regno].invariant == NULL_RTX);
 | |
| }
 | |
| 
 | |
| /* The major function for aggressive pseudo coalescing of moves only
 | |
|    if the both pseudos were spilled and not special reload pseudos.  */
 | |
| bool
 | |
| lra_coalesce (void)
 | |
| {
 | |
|   basic_block bb;
 | |
|   rtx_insn *mv, *insn, *next, **sorted_moves;
 | |
|   rtx set;
 | |
|   int i, mv_num, sregno, dregno;
 | |
|   int coalesced_moves;
 | |
|   int max_regno = max_reg_num ();
 | |
|   bitmap_head involved_insns_bitmap;
 | |
|   
 | |
|   timevar_push (TV_LRA_COALESCE);
 | |
| 
 | |
|   if (lra_dump_file != NULL)
 | |
|     fprintf (lra_dump_file,
 | |
| 	     "\n********** Pseudos coalescing #%d: **********\n\n",
 | |
| 	     ++lra_coalesce_iter);
 | |
|   first_coalesced_pseudo = XNEWVEC (int, max_regno);
 | |
|   next_coalesced_pseudo = XNEWVEC (int, max_regno);
 | |
|   for (i = 0; i < max_regno; i++)
 | |
|     first_coalesced_pseudo[i] = next_coalesced_pseudo[i] = i;
 | |
|   sorted_moves = XNEWVEC (rtx_insn *, get_max_uid ());
 | |
|   mv_num = 0;
 | |
|   /* Collect moves.  */
 | |
|   coalesced_moves = 0;
 | |
|   FOR_EACH_BB_FN (bb, cfun)
 | |
|     {
 | |
|       FOR_BB_INSNS_SAFE (bb, insn, next)
 | |
| 	if (INSN_P (insn)
 | |
| 	    && (set = single_set (insn)) != NULL_RTX
 | |
| 	    && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))
 | |
| 	    && (sregno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
 | |
| 	    && (dregno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER
 | |
| 	    && mem_move_p (sregno, dregno)
 | |
| 	    && coalescable_pseudo_p (sregno) && coalescable_pseudo_p (dregno)
 | |
| 	    && ! side_effects_p (set)
 | |
| 	    && !(lra_intersected_live_ranges_p
 | |
| 		 (lra_reg_info[sregno].live_ranges,
 | |
| 		  lra_reg_info[dregno].live_ranges)))
 | |
| 	  sorted_moves[mv_num++] = insn;
 | |
|     }
 | |
|   qsort (sorted_moves, mv_num, sizeof (rtx), move_freq_compare_func);
 | |
|   /* Coalesced copies, most frequently executed first.	*/
 | |
|   bitmap_initialize (&coalesced_pseudos_bitmap, ®_obstack);
 | |
|   bitmap_initialize (&involved_insns_bitmap, ®_obstack);
 | |
|   for (i = 0; i < mv_num; i++)
 | |
|     {
 | |
|       mv = sorted_moves[i];
 | |
|       set = single_set (mv);
 | |
|       lra_assert (set != NULL && REG_P (SET_SRC (set))
 | |
| 		  && REG_P (SET_DEST (set)));
 | |
|       sregno = REGNO (SET_SRC (set));
 | |
|       dregno = REGNO (SET_DEST (set));
 | |
|       if (first_coalesced_pseudo[sregno] == first_coalesced_pseudo[dregno])
 | |
| 	{
 | |
| 	  coalesced_moves++;
 | |
| 	  if (lra_dump_file != NULL)
 | |
| 	    fprintf
 | |
| 	      (lra_dump_file, "      Coalescing move %i:r%d-r%d (freq=%d)\n",
 | |
| 	       INSN_UID (mv), sregno, dregno,
 | |
| 	       REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv)));
 | |
| 	  /* We updated involved_insns_bitmap when doing the merge.  */
 | |
| 	}
 | |
|       else if (!(lra_intersected_live_ranges_p
 | |
| 		 (lra_reg_info[first_coalesced_pseudo[sregno]].live_ranges,
 | |
| 		  lra_reg_info[first_coalesced_pseudo[dregno]].live_ranges)))
 | |
| 	{
 | |
| 	  coalesced_moves++;
 | |
| 	  if (lra_dump_file != NULL)
 | |
| 	    fprintf
 | |
| 	      (lra_dump_file,
 | |
| 	       "  Coalescing move %i:r%d(%d)-r%d(%d) (freq=%d)\n",
 | |
| 	       INSN_UID (mv), sregno, ORIGINAL_REGNO (SET_SRC (set)),
 | |
| 	       dregno, ORIGINAL_REGNO (SET_DEST (set)),
 | |
| 	       REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv)));
 | |
| 	  bitmap_ior_into (&involved_insns_bitmap,
 | |
| 			   &lra_reg_info[sregno].insn_bitmap);
 | |
| 	  bitmap_ior_into (&involved_insns_bitmap,
 | |
| 			   &lra_reg_info[dregno].insn_bitmap);
 | |
| 	  merge_pseudos (sregno, dregno);
 | |
| 	}
 | |
|     }
 | |
|   bitmap_initialize (&used_pseudos_bitmap, ®_obstack);
 | |
|   FOR_EACH_BB_FN (bb, cfun)
 | |
|     {
 | |
|       update_live_info (df_get_live_in (bb));
 | |
|       update_live_info (df_get_live_out (bb));
 | |
|       FOR_BB_INSNS_SAFE (bb, insn, next)
 | |
| 	if (INSN_P (insn)
 | |
| 	    && bitmap_bit_p (&involved_insns_bitmap, INSN_UID (insn)))
 | |
| 	  {
 | |
| 	    if (! substitute_within_insn (insn))
 | |
| 	      continue;
 | |
| 	    lra_update_insn_regno_info (insn);
 | |
| 	    if ((set = single_set (insn)) != NULL_RTX && set_noop_p (set))
 | |
| 	      {
 | |
| 		/* Coalesced move.  */
 | |
| 		if (lra_dump_file != NULL)
 | |
| 		  fprintf (lra_dump_file, "	 Removing move %i (freq=%d)\n",
 | |
| 			   INSN_UID (insn),
 | |
| 			   REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn)));
 | |
| 		lra_set_insn_deleted (insn);
 | |
| 	      }
 | |
| 	  }
 | |
|     }
 | |
|   /* If we have situation after inheritance pass:
 | |
| 
 | |
|      r1 <- p1   insn originally setting p1
 | |
|      i1 <- r1   setting inheritance i1 from reload r1
 | |
|        ...
 | |
|      ... <- ... p2 ... dead p2
 | |
|      ..
 | |
|      p1 <- i1
 | |
|      r2 <- i1
 | |
|      ...<- ... r2 ...
 | |
| 
 | |
|      And we are coalescing p1 and p2 using p1.  In this case i1 and p1
 | |
|      should have different values, otherwise they can get the same
 | |
|      hard reg and this is wrong for insn using p2 before coalescing.
 | |
|      The situation even can be more complicated when new reload
 | |
|      pseudos occur after the inheriatnce.  So invalidate the result
 | |
|      pseudos.  */
 | |
|   for (i = 0; i < max_regno; i++)
 | |
|     if (first_coalesced_pseudo[i] == i
 | |
| 	&& first_coalesced_pseudo[i] != next_coalesced_pseudo[i])
 | |
|       {
 | |
| 	lra_set_regno_unique_value (i);
 | |
| 	if (lra_dump_file != NULL)
 | |
| 	  fprintf (lra_dump_file,
 | |
| 		   "	 Make unique value for coalescing result r%d\n", i);
 | |
|       }
 | |
|   bitmap_clear (&used_pseudos_bitmap);
 | |
|   bitmap_clear (&involved_insns_bitmap);
 | |
|   bitmap_clear (&coalesced_pseudos_bitmap);
 | |
|   if (lra_dump_file != NULL && coalesced_moves != 0)
 | |
|     fprintf (lra_dump_file, "Coalesced Moves = %d\n", coalesced_moves);
 | |
|   free (sorted_moves);
 | |
|   free (next_coalesced_pseudo);
 | |
|   free (first_coalesced_pseudo);
 | |
|   timevar_pop (TV_LRA_COALESCE);
 | |
|   return coalesced_moves != 0;
 | |
| }
 |