This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

caller-save and i386


Hi
This patch makes caller save to use sane modes for saving on i386.  The benefits
are really noticeable - I've measured about 8% speedups in the compilable part
of SpecFP2000 :)

I've done so by extending HARD_REGNO_CALLER_SAVE_MODE by an MODE parameter.
The MODE specifies mode of pseudo we want to save, but can be also VOIDmode for
storing hard registers and doing the combination.

The code now works by first figuring out all possible VOIDmode saves, as it did
originally and then asks for mode when spilling out pseudo.  In case there is
no possible combination, the mode returned for mode of pseudo is used.

Currently the init_save_areas is still allocating maximal possible stack slots,
but I will fix it later, if the patch is accepted.  Also the patch don't contain
neccesary update to existing backends, except for i386 to compile (adding the
ignored parameter to macro), I would do before installing of course.

Mon Jul 14 15:16:33 CEST 2014  Jan Hubicka  <jh@suse.cz>

	* caller-save.c (reg_save_code, reg_restore_code):  Index by mode, not
	NREGS.
	(insert_save, insert_restore): New parameter save_mode.
	(init_caller_save): Update initialization of reg_save_code
	and reg_restore_code.
	(save_call_clobbered_regs):  Compute save_modes and update calls to
	reg_save_code and reg_restore_code.
	(insert_restore):  Unsignetize numbers; use save_modes to choose mode
	of spill; update use of reg_restore_code.
	(insert_save):  Likewise.
	* i386.h (HARD_REGNO_CALLER_SAVE_MODE): Update.
	* regs.h (HARD_REGNO_CALLER_SAVE_MODE): Likewise.

*** caller_save.c.old	Mon Jul 14 01:07:28 2014
--- caller-save.c	Mon Jul 14 04:10:08 2014
*************** static rtx 
*** 65,73 ****
     be recognized.  */
  
  static enum insn_code 
!   reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
  static enum insn_code 
!   reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MIN_UNITS_PER_WORD + 1];
  
  /* Set of hard regs currently residing in save area (during insn scan).  */
  
--- 65,73 ----
     be recognized.  */
  
  static enum insn_code 
!   reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
  static enum insn_code 
!   reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
  
  /* Set of hard regs currently residing in save area (during insn scan).  */
  
*************** static HARD_REG_SET this_insn_sets;
*** 89,97 ****
  static void mark_set_regs		PARAMS ((rtx, rtx, void *));
  static void mark_referenced_regs	PARAMS ((rtx));
  static int insert_save			PARAMS ((struct insn_chain *, int, int,
! 						 HARD_REG_SET *));
  static int insert_restore		PARAMS ((struct insn_chain *, int, int,
! 						 int));
  static struct insn_chain *insert_one_insn PARAMS ((struct insn_chain *, int,
  						   enum insn_code, rtx));
  static void add_stored_regs		PARAMS ((rtx, rtx, void *));
--- 89,98 ----
  static void mark_set_regs		PARAMS ((rtx, rtx, void *));
  static void mark_referenced_regs	PARAMS ((rtx));
  static int insert_save			PARAMS ((struct insn_chain *, int, int,
! 						 HARD_REG_SET *,
! 						 enum machine_mode *));
  static int insert_restore		PARAMS ((struct insn_chain *, int, int,
! 						 int, enum machine_mode *));
  static struct insn_chain *insert_one_insn PARAMS ((struct insn_chain *, int,
  						   enum insn_code, rtx));
  static void add_stored_regs		PARAMS ((rtx, rtx, void *));
*************** init_caller_save ()
*** 113,118 ****
--- 114,120 ----
    int offset;
    rtx address;
    int i, j;
+   enum machine_mode mode;
  
    /* First find all the registers that we need to deal with and all
       the modes that they can have.  If we can't find a mode to use,
*************** init_caller_save ()
*** 124,130 ****
  	{
  	  for (j = 1; j <= MOVE_MAX_WORDS; j++)
  	    {
! 	      regno_save_mode[i][j] = HARD_REGNO_CALLER_SAVE_MODE (i, j);
  	      if (regno_save_mode[i][j] == VOIDmode && j == 1)
  		{
  		  call_fixed_regs[i] = 1;
--- 126,133 ----
  	{
  	  for (j = 1; j <= MOVE_MAX_WORDS; j++)
  	    {
! 	      regno_save_mode[i][j] = HARD_REGNO_CALLER_SAVE_MODE (i, j,
! 								   VOIDmode);
  	      if (regno_save_mode[i][j] == VOIDmode && j == 1)
  		{
  		  call_fixed_regs[i] = 1;
*************** init_caller_save ()
*** 179,202 ****
    start_sequence ();
  
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
!     for (j = 1; j <= MOVE_MAX_WORDS; j++)
!       if (regno_save_mode[i][j] != VOIDmode)
          {
! 	  rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address);
! 	  rtx reg = gen_rtx_REG (regno_save_mode[i][j], i);
  	  rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
  	  rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
  	  rtx saveinsn = emit_insn (savepat);
  	  rtx restinsn = emit_insn (restpat);
  	  int ok;
  
! 	  reg_save_code[i][j] = recog_memoized (saveinsn);
! 	  reg_restore_code[i][j] = recog_memoized (restinsn);
  
  	  /* Now extract both insns and see if we can meet their
               constraints.  */
! 	  ok = (reg_save_code[i][j] != (enum insn_code)-1
! 		&& reg_restore_code[i][j] != (enum insn_code)-1);
  	  if (ok)
  	    {
  	      extract_insn (saveinsn);
--- 182,205 ----
    start_sequence ();
  
    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
!     for (mode = 0 ; mode < MAX_MACHINE_MODE; mode++)
!       if (HARD_REGNO_MODE_OK (i, mode))
          {
! 	  rtx mem = gen_rtx_MEM (mode, address);
! 	  rtx reg = gen_rtx_REG (mode, i);
  	  rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
  	  rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
  	  rtx saveinsn = emit_insn (savepat);
  	  rtx restinsn = emit_insn (restpat);
  	  int ok;
  
! 	  reg_save_code[i][mode] = recog_memoized (saveinsn);
! 	  reg_restore_code[i][mode] = recog_memoized (restinsn);
  
  	  /* Now extract both insns and see if we can meet their
               constraints.  */
! 	  ok = (reg_save_code[i][mode] != (enum insn_code)-1
! 		&& reg_restore_code[i][mode] != (enum insn_code)-1);
  	  if (ok)
  	    {
  	      extract_insn (saveinsn);
*************** init_caller_save ()
*** 207,220 ****
  
  	  if (! ok)
  	    {
! 	      regno_save_mode[i][j] = VOIDmode;
! 	      if (j == 1)
! 		{
! 		  call_fixed_regs[i] = 1;
! 		  SET_HARD_REG_BIT (call_fixed_reg_set, i);
! 		}
  	    }
!       }
  
    end_sequence ();
  }
--- 210,235 ----
  
  	  if (! ok)
  	    {
! 	      reg_save_code[i][mode] = (enum insn_code) -1;
! 	      reg_restore_code[i][mode] = (enum insn_code) -1;
  	    }
!         }
!       else
! 	{
! 	  reg_save_code[i][mode] = (enum insn_code) -1;
! 	  reg_restore_code[i][mode] = (enum insn_code) -1;
! 	}
!   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
!     for (j = 1; j <= MOVE_MAX_WORDS; j++)
!       if (reg_save_code [i][regno_save_mode[i][j]] == (enum insn_code) -1)
! 	{
! 	  regno_save_mode[i][j] = VOIDmode;
! 	  if (j == 1)
! 	    {
! 	      call_fixed_regs[i] = 1;
! 	      SET_HARD_REG_BIT (call_fixed_reg_set, i);
! 	    }
! 	}
  
    end_sequence ();
  }
*************** void
*** 339,344 ****
--- 354,360 ----
  save_call_clobbered_regs ()
  {
    struct insn_chain *chain, *next;
+   enum machine_mode save_mode [FIRST_PSEUDO_REGISTER];
  
    CLEAR_HARD_REG_SET (hard_regs_saved);
    n_regs_saved = 0;
*************** save_call_clobbered_regs ()
*** 374,380 ****
  
  	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  		if (TEST_HARD_REG_BIT (referenced_regs, regno))
! 		  regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS);
  	    }
  
  	  if (code == CALL_INSN)
--- 390,396 ----
  
  	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  		if (TEST_HARD_REG_BIT (referenced_regs, regno))
! 		  regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS, save_mode);
  	    }
  
  	  if (code == CALL_INSN)
*************** save_call_clobbered_regs ()
*** 386,393 ****
  		 regs are live during the call.  */
  	      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
  				       &chain->live_throughout);
! 	      compute_use_by_pseudos (&hard_regs_to_save,
! 				      &chain->live_throughout);
  
  	      /* Record all registers set in this call insn.  These don't need
  		 to be saved.  N.B. the call insn might set a subreg of a
--- 402,438 ----
  		 regs are live during the call.  */
  	      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
  				       &chain->live_throughout);
! 	      /* Save hard registers always in the widest mode availble.  */
! 	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
! 		if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
! 		  save_mode [regno] = regno_save_mode [regno][1];
! 		else
! 		  save_mode [regno] = VOIDmode;
! 
! 	      /* Look trought all live pseudos, mark their hard registers
! 		 and choose proper mode for saving.  */
! 	      EXECUTE_IF_SET_IN_REG_SET
! 		(&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno,
! 		 {
! 		   int r = reg_renumber[regno];
! 		   int nregs;
! 
! 		   if (r > 0)
! 		     {
! 		       enum machine_mode mode;
! 
! 		       nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (regno));
! 		       mode = HARD_REGNO_CALLER_SAVE_MODE
! 			        (r, nregs, PSEUDO_REGNO_MODE (regno));
! 		       if (GET_MODE_BITSIZE (mode)
! 			   > GET_MODE_BITSIZE (save_mode[r]))
! 			 save_mode[r] = mode;
! 		       while (nregs-- > 0)
! 			 SET_HARD_REG_BIT (hard_regs_to_save, r + nregs);
! 		     }
! 		   else
! 		     abort ();
! 		 });
  
  	      /* Record all registers set in this call insn.  These don't need
  		 to be saved.  N.B. the call insn might set a subreg of a
*************** save_call_clobbered_regs ()
*** 404,410 ****
  
  	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  		if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
! 		  regno += insert_save (chain, 1, regno, &hard_regs_to_save);
  
  	      /* Must recompute n_regs_saved.  */
  	      n_regs_saved = 0;
--- 449,455 ----
  
  	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  		if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
! 		  regno += insert_save (chain, 1, regno, &hard_regs_to_save, save_mode);
  
  	      /* Must recompute n_regs_saved.  */
  	      n_regs_saved = 0;
*************** save_call_clobbered_regs ()
*** 425,431 ****
  	    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  	      if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
  		regno += insert_restore (chain, GET_CODE (insn) == JUMP_INSN,
! 					 regno, MOVE_MAX_WORDS);
  	}
      }  
  }
--- 470,476 ----
  	    for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
  	      if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
  		regno += insert_restore (chain, GET_CODE (insn) == JUMP_INSN,
! 					 regno, MOVE_MAX_WORDS, save_mode);
  	}
      }  
  }
*************** mark_referenced_regs (x)
*** 572,588 ****
     Return the extra number of registers saved.  */
  
  static int
! insert_restore (chain, before_p, regno, maxrestore)
       struct insn_chain *chain;
       int before_p;
       int regno;
       int maxrestore;
  {
    int i, k;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
!   int numregs = 0;
    struct insn_chain *new;
  
    /* A common failure mode if register status is not correct in the RTL
       is for this routine to be called with a REGNO we didn't expect to
--- 617,635 ----
     Return the extra number of registers saved.  */
  
  static int
! insert_restore (chain, before_p, regno, maxrestore, save_mode)
       struct insn_chain *chain;
       int before_p;
       int regno;
       int maxrestore;
+      enum machine_mode *save_mode;
  {
    int i, k;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
!   unsigned int numregs = 0;
    struct insn_chain *new;
+   rtx mem;
  
    /* A common failure mode if register status is not correct in the RTL
       is for this routine to be called with a REGNO we didn't expect to
*************** insert_restore (chain, before_p, regno, 
*** 620,630 ****
        break;
      }
  
    pat = gen_rtx_SET (VOIDmode,
! 		     gen_rtx_REG (GET_MODE (regno_save_mem[regno][numregs]), 
! 				  regno), 
! 		     regno_save_mem[regno][numregs]);
!   code = reg_restore_code[regno][numregs];
    new = insert_one_insn (chain, before_p, code, pat);
  
    /* Clear status for all registers we restored.  */
--- 667,681 ----
        break;
      }
  
+   mem = regno_save_mem [regno][numregs];
+   if (save_mode [regno] != VOIDmode
+       && save_mode [regno] != GET_MODE (mem)
+       && numregs == HARD_REGNO_NREGS (regno, save_mode [regno]))
+     mem = change_address (mem, save_mode[regno], XEXP (mem, 0));
    pat = gen_rtx_SET (VOIDmode,
! 		     gen_rtx_REG (GET_MODE (mem), 
! 				  regno), mem);
!   code = reg_restore_code[regno][GET_MODE (mem)];
    new = insert_one_insn (chain, before_p, code, pat);
  
    /* Clear status for all registers we restored.  */
*************** insert_restore (chain, before_p, regno, 
*** 643,659 ****
  
  /* Like insert_restore above, but save registers instead.  */
  static int
! insert_save (chain, before_p, regno, to_save)
       struct insn_chain *chain;
       int before_p;
       int regno;
       HARD_REG_SET *to_save;
  {
!   int i, k;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
!   int numregs = 0;
    struct insn_chain *new;
  
    /* A common failure mode if register status is not correct in the RTL
       is for this routine to be called with a REGNO we didn't expect to
--- 694,713 ----
  
  /* Like insert_restore above, but save registers instead.  */
  static int
! insert_save (chain, before_p, regno, to_save, save_mode)
       struct insn_chain *chain;
       int before_p;
       int regno;
       HARD_REG_SET *to_save;
+      enum machine_mode *save_mode;
  {
!   int i;
!   unsigned int k;
    rtx pat = NULL_RTX;
    enum insn_code code = CODE_FOR_nothing;
!   unsigned int numregs = 0;
    struct insn_chain *new;
+   rtx mem;
  
    /* A common failure mode if register status is not correct in the RTL
       is for this routine to be called with a REGNO we didn't expect to
*************** insert_save (chain, before_p, regno, to_
*** 690,699 ****
        break;
      }
  
!   pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][numregs],
! 		     gen_rtx_REG (GET_MODE (regno_save_mem[regno][numregs]),
  				  regno));
!   code = reg_save_code[regno][numregs];
    new = insert_one_insn (chain, before_p, code, pat);
  
    /* Set hard_regs_saved and dead_or_set for all the registers we saved.  */
--- 744,758 ----
        break;
      }
  
!   mem = regno_save_mem [regno][numregs];
!   if (save_mode [regno] != VOIDmode
!       && save_mode [regno] != GET_MODE (mem)
!       && numregs == HARD_REGNO_NREGS (regno, save_mode [regno]))
!     mem = change_address (mem, save_mode[regno], XEXP (mem, 0));
!   pat = gen_rtx_SET (VOIDmode, mem,
! 		     gen_rtx_REG (GET_MODE (mem),
  				  regno));
!   code = reg_save_code[regno][GET_MODE (mem)];
    new = insert_one_insn (chain, before_p, code, pat);
  
    /* Set hard_regs_saved and dead_or_set for all the registers we saved.  */
*** /p1/egcs/gcc/config/i386/i386.h	Wed Jan 24 18:45:00 2001
--- config/i386/i386.h	Mon Jul 14 04:26:47 2014
*************** extern int ix86_arch;
*** 809,819 ****
     || ((MODE1) == HImode && (MODE2) == SImode))
  
  /* Specify the modes required to caller save a given hard regno.
!    We do this on i386 to prevent flags from being saved at all.  */
  
! #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS)		\
    (CC_REGNO_P (REGNO) ? VOIDmode				\
!    : choose_hard_reg_mode ((REGNO), (NREGS)))
  
  /* Specify the registers used for certain standard purposes.
     The values of these macros are register numbers.  */
--- 834,849 ----
     || ((MODE1) == HImode && (MODE2) == SImode))
  
  /* Specify the modes required to caller save a given hard regno.
!    We do this on i386 to prevent flags from being saved at all.
! 
!    Kill any attempts to combine saving of modes.  */
  
! #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE)		\
    (CC_REGNO_P (REGNO) ? VOIDmode				\
!    : (MODE) == VOIDmode && (NREGS) != 1 ? VOIDmode		\
!    : (MODE) == VOIDmode ? choose_hard_reg_mode ((REGNO), (NREGS)) \
!    : (MODE) == HImode && !TARGET_PARTIAL_REG_STALL ? SImode	\
!    : (MODE) == QImode && (REGNO) >= 4 ? SImode : (MODE))
  
  /* Specify the registers used for certain standard purposes.
     The values of these macros are register numbers.  */
*** regs.h.old	Mon Jul 14 15:12:48 2014
--- regs.h	Mon Jul 14 15:12:56 2014
*************** extern int caller_save_needed;
*** 192,198 ****
  
  /* Select a register mode required for caller save of hard regno REGNO.  */
  #ifndef HARD_REGNO_CALLER_SAVE_MODE
! #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS) \
    choose_hard_reg_mode (REGNO, NREGS)
  #endif
  
--- 192,198 ----
  
  /* Select a register mode required for caller save of hard regno REGNO.  */
  #ifndef HARD_REGNO_CALLER_SAVE_MODE
! #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \
    choose_hard_reg_mode (REGNO, NREGS)
  #endif
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]