This patch makes -fcall-saved-rX for X > 7 on Thumb target when optimizing for size. It works by adding a new field x_user_set_call_save_regs in struct target_hard_regs to track whether an entry in fields x_fixed_regs, x_call_used_regs and x_call_really_used_regs was user set or is in its default value. Then it can decide whether to set a given high register as caller saved or not when optimizing for size based on this information.
ChangeLog are as follows: *** gcc/ChangeLog *** 2014-08-15 Thomas Preud'homme <thomas.preudho...@arm.com> * config/arm/arm.c (arm_conditional_register_usage): Only set high registers as caller saved when optimizing for size *and* the user did not asked otherwise through -fcall-saved-* switch. * hard-reg-set.h (x_user_set_call_save_regs): New. (user_set_call_save_regs): Define. * reginfo.c (init_reg_sets): Initialize user_set_call_save_regs. (fix_register): Indicate in user_set_call_save_regs that the value set in call_save_regs and fixed_regs is user set. *** gcc/testsuite/ChangeLog *** 2014-08-15 Thomas Preud'homme <thomas.preudho...@arm.com> * gcc.target/arm/fcall-save-rhigh.c: New. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 2f8d327..8324fa3 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -30084,7 +30084,8 @@ arm_conditional_register_usage (void) stacking them. */ for (regno = FIRST_HI_REGNUM; regno <= LAST_HI_REGNUM; ++regno) - fixed_regs[regno] = call_used_regs[regno] = 1; + if (!user_set_call_save_regs[regno]) + fixed_regs[regno] = call_used_regs[regno] = 1; } /* The link register can be clobbered by any branch insn, diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h index b8ab3df..b523637 100644 --- a/gcc/hard-reg-set.h +++ b/gcc/hard-reg-set.h @@ -614,6 +614,11 @@ struct target_hard_regs { char x_call_really_used_regs[FIRST_PSEUDO_REGISTER]; + /* Indexed by hard register number, contains 1 for registers + whose saving at function call was decided by the user + with -fcall-saved-*, -fcall-used-* or -ffixed-*. */ + char x_user_set_call_save_regs[FIRST_PSEUDO_REGISTER]; + /* The same info as a HARD_REG_SET. */ HARD_REG_SET x_call_used_reg_set; @@ -685,6 +690,8 @@ extern struct target_hard_regs *this_target_hard_regs; (this_target_hard_regs->x_call_used_regs) #define call_really_used_regs \ (this_target_hard_regs->x_call_really_used_regs) +#define user_set_call_save_regs \ + (this_target_hard_regs->x_user_set_call_save_regs) #define call_used_reg_set \ (this_target_hard_regs->x_call_used_reg_set) #define call_fixed_reg_set \ diff --git a/gcc/reginfo.c b/gcc/reginfo.c index 7668be0..0b35f7f 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -183,6 +183,7 @@ init_reg_sets (void) memcpy (call_really_used_regs, initial_call_really_used_regs, sizeof call_really_used_regs); #endif + memset (user_set_call_save_regs, 0, sizeof user_set_call_save_regs); #ifdef REG_ALLOC_ORDER memcpy (reg_alloc_order, initial_reg_alloc_order, sizeof reg_alloc_order); #endif @@ -742,6 +743,7 @@ fix_register (const char *name, int fixed, int call_used) if (fixed == 0) call_really_used_regs[i] = call_used; #endif + user_set_call_save_regs[i] = 1; } } } diff --git a/gcc/testsuite/gcc.target/arm/fcall-save-rhigh.c b/gcc/testsuite/gcc.target/arm/fcall-save-rhigh.c new file mode 100644 index 0000000..a321a2b --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/fcall-save-rhigh.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-final { scan-assembler "mov\\s+r.\\s*,\\s*r8" } } */ +/* { dg-require-effective-target arm_thumb1_ok } */ +/* { dg-options "-Os -mthumb -mcpu=cortex-m0 -fcall-saved-r8" } */ + +void +save_regs (void) +{ + asm volatile ("" ::: "r7", "r8"); +} Ok for trunk? Best regards, Thomas