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\ >