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