a patch prototype for PR59535 (THUMB code size regression)

Richard Earnshaw rearnsha@arm.com
Thu Jan 9 15:31:00 GMT 2014


On 09/01/14 15:21, Vladimir Makarov wrote:
> Hi, Richard.
> 
>    This week I've been working on THUMB code size issues.  Here is the
> prototype of the patch for spilling into HI_REGS instead of memory.
> The patch decreases number of generated insns and makes the code faster
> as it removes a lot of loads/stores.
> 
>    I am sending the patch for your evaluation and for getting your
> opinion.  If you like the code size results, I could create the real 
> patch next week (the patch here will not work correctly when a user 
> defines fixed registers by himself).
> 
> Thanks in advance, Vlad.
> 

Do you need to take into account HARD_REGNO_NREGS (mode) when doing the
limit check?

R.

> 
> z
> 
> 
> Index: config/arm/arm.c
> ===================================================================
> --- config/arm/arm.c	(revision 206089)
> +++ config/arm/arm.c	(working copy)
> @@ -73,6 +73,8 @@ struct four_ints
>  
>  /* Forward function declarations.  */
>  static bool arm_lra_p (void);
> +static reg_class_t arm_spill_class (reg_class_t, enum machine_mode);
> +static int arm_spill_hard_regno (int, reg_class_t, enum machine_mode);
>  static bool arm_needs_doubleword_align (enum machine_mode, const_tree);
>  static int arm_compute_static_chain_stack_bytes (void);
>  static arm_stack_offsets *arm_get_frame_offsets (void);
> @@ -345,6 +347,12 @@ static const struct attribute_spec arm_a
>  #undef TARGET_LRA_P
>  #define TARGET_LRA_P arm_lra_p
>  
> +#undef TARGET_SPILL_CLASS
> +#define TARGET_SPILL_CLASS arm_spill_class
> +
> +#undef TARGET_SPILL_HARD_REGNO
> +#define TARGET_SPILL_HARD_REGNO arm_spill_hard_regno
> +
>  #undef  TARGET_ATTRIBUTE_TABLE
>  #define TARGET_ATTRIBUTE_TABLE arm_attribute_table
>  
> @@ -5597,6 +5605,28 @@ arm_lra_p (void)
>    return arm_lra_flag;
>  }
>  
> +/* Return class of registers which could be used for pseudo of MODE
> +   and of class RCLASS for spilling instead of memory.  Return NO_REGS
> +   if it is not possible or non-profitable.  */
> +static reg_class_t
> +arm_spill_class (reg_class_t rclass, enum machine_mode mode)
> +{
> +  if (TARGET_THUMB1 && mode == SImode
> +      && (rclass == LO_REGS || rclass == GENERAL_REGS))
> +    return HI_REGS;
> +  return NO_REGS;
> +}
> +
> +/* ???  */
> +static int
> +arm_spill_hard_regno (int n, reg_class_t spill_class, enum machine_mode mode)
> +{
> +  gcc_assert (TARGET_THUMB1 && mode == SImode && spill_class == HI_REGS
> +	      && n >= 0);
> +  int hard_regno = FIRST_HI_REGNUM + n;
> +  return hard_regno > 12 ? -1 : hard_regno;
> +}
> +
>  /* Return true if mode/type need doubleword alignment.  */
>  static bool
>  arm_needs_doubleword_align (enum machine_mode mode, const_tree type)
> @@ -29236,6 +29266,7 @@ arm_conditional_register_usage (void)
>        for (regno = FIRST_HI_REGNUM;
>  	   regno <= LAST_HI_REGNUM; ++regno)
>  	fixed_regs[regno] = call_used_regs[regno] = 1;
> +      fixed_regs[12] = call_used_regs[12] = 1;
>      }
>  
>    /* The link register can be clobbered by any branch insn,
> Index: doc/tm.texi
> ===================================================================
> --- doc/tm.texi	(revision 206089)
> +++ doc/tm.texi	(working copy)
> @@ -2918,6 +2918,10 @@ A target hook which returns true if an a
>  This hook defines a class of registers which could be used for spilling  pseudos of the given mode and class, or @code{NO_REGS} if only memory  should be used.  Not defining this hook is equivalent to returning  @code{NO_REGS} for all inputs.
>  @end deftypefn
>  
> +@deftypefn {Target Hook} int TARGET_SPILL_HARD_REGNO (int, @var{reg_class_t}, enum @var{machine_mode})
> +This hook defines n-th (0, ...) register which could be used for spilling  pseudos of the given mode and spill class, or -1 if there are no  such regs anymore.  The hook shoul be defined with spill_class hook  and should be defined only for classes returned by spill_class.
> +@end deftypefn
> +
>  @deftypefn {Target Hook} {enum machine_mode} TARGET_CSTORE_MODE (enum insn_code @var{icode})
>  This hook defines the machine mode to use for the boolean result of  conditional store patterns.  The ICODE argument is the instruction code  for the cstore being performed.  Not definiting this hook is the same  as accepting the mode encoded into operand 0 of the cstore expander  patterns.
>  @end deftypefn
> Index: doc/tm.texi.in
> ===================================================================
> --- doc/tm.texi.in	(revision 206089)
> +++ doc/tm.texi.in	(working copy)
> @@ -2549,6 +2549,8 @@ as below:
>  
>  @hook TARGET_SPILL_CLASS
>  
> +@hook TARGET_SPILL_HARD_REGNO
> +
>  @hook TARGET_CSTORE_MODE
>  
>  @node Old Constraints
> Index: lra-spills.c
> ===================================================================
> --- lra-spills.c	(revision 206089)
> +++ lra-spills.c	(working copy)
> @@ -252,7 +252,7 @@ pseudo_reg_slot_compare (const void *v1p
>  static int
>  assign_spill_hard_regs (int *pseudo_regnos, int n)
>  {
> -  int i, k, p, regno, res, spill_class_size, hard_regno, nr;
> +  int i, k, p, regno, res, hard_regno, nr;
>    enum reg_class rclass, spill_class;
>    enum machine_mode mode;
>    lra_live_range_t r;
> @@ -271,7 +271,7 @@ assign_spill_hard_regs (int *pseudo_regn
>    /* Set up reserved hard regs for every program point.	 */
>    reserved_hard_regs = XNEWVEC (HARD_REG_SET, lra_live_max_point);
>    for (p = 0; p < lra_live_max_point; p++)
> -    COPY_HARD_REG_SET (reserved_hard_regs[p], lra_no_alloc_regs);
> +    CLEAR_HARD_REG_SET (reserved_hard_regs[p]);
>    for (i = FIRST_PSEUDO_REGISTER; i < regs_num; i++)
>      if (lra_reg_info[i].nrefs != 0
>  	&& (hard_regno = lra_get_regno_hard_regno (i)) >= 0)
> @@ -307,15 +307,16 @@ assign_spill_hard_regs (int *pseudo_regn
>        for (r = lra_reg_info[regno].live_ranges; r != NULL; r = r->next)
>  	for (p = r->start; p <= r->finish; p++)
>  	  IOR_HARD_REG_SET (conflict_hard_regs, reserved_hard_regs[p]);
> -      spill_class_size = ira_class_hard_regs_num[spill_class];
>        mode = lra_reg_info[regno].biggest_mode;
> -      for (k = 0; k < spill_class_size; k++)
> +      for (k = 0;; k++)
>  	{
> -	  hard_regno = ira_class_hard_regs[spill_class][k];
> +	  hard_regno = targetm.spill_hard_regno (k, spill_class, mode);
> +	  if (hard_regno < 0)
> +	    break;
>  	  if (! overlaps_hard_reg_set_p (conflict_hard_regs, mode, hard_regno))
>  	    break;
>  	}
> -      if (k >= spill_class_size)
> +      if (hard_regno < 0)
>  	{
>  	   /* There is no available regs -- assign memory later.  */
>  	  pseudo_regnos[res++] = regno;
> Index: target.def
> ===================================================================
> --- target.def	(revision 206089)
> +++ target.def	(working copy)
> @@ -4399,6 +4399,17 @@ DEFHOOK
>   reg_class_t, (reg_class_t, enum machine_mode),
>   NULL)
>  
> +/* Determine class for spilling pseudos of given mode into registers
> +   instead of memory.  */
> +DEFHOOK
> +(spill_hard_regno,
> + "This hook defines n-th (0, ...) register which could be used for spilling\
> +  pseudos of the given mode and spill class, or -1 if there are no\
> +  such regs anymore.  The hook shoul be defined with spill_class hook\
> +  and should be defined only for classes returned by spill_class.",
> + int, (int, reg_class_t, enum machine_mode),
> + NULL)
> +
>  DEFHOOK
>  (cstore_mode,
>   "This hook defines the machine mode to use for the boolean result of\
> 




More information about the Gcc-patches mailing list