When compiling for size, live high registers are not saved in function prolog in ARM backend in Thumb mode. The problem comes from arm_conditional_register_usage setting call_used_regs for all high register to avoid them being allocated. However, this cause prolog to not save these register even if they are used. This patch marks high registers as really needing to be saved in prolog if live, no matter what is the content of call_used_regs.
ChangeLog entries are as follows: gcc/ChangeLog 2015-01-12 Thomas Preud'homme thomas.preudho...@arm.com PR target/64453 * config/arm/arm.c (callee_saved_reg_p): Define. (arm_compute_save_reg0_reg12_mask): Use callee_saved_reg_p to check if register is callee saved instead of !call_used_regs[reg]. (thumb1_compute_save_reg_mask): Likewise. gcc/testsuite/ChangeLog 2014-12-31 Thomas Preud'homme thomas.preudho...@arm.com * gcc.target/arm/pr64453.c: New. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 0ec526b..fcc14c2 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -18989,6 +18989,14 @@ output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len) fputs ("\"\n", stream); } +/* Whether a register is callee saved or not. This is necessary because high + registers are marked as caller saved when optimizing for size on Thumb-1 + targets despite being callee saved in order to avoid using them. */ +#define callee_saved_reg_p(reg) \ + (!call_used_regs[reg] \ + || (TARGET_THUMB1 && optimize_size \ + && reg >= FIRST_HI_REGNUM && reg <= LAST_HI_REGNUM)) + /* Compute the register save mask for registers 0 through 12 inclusive. This code is used by arm_compute_save_reg_mask. */ @@ -19049,7 +19057,7 @@ arm_compute_save_reg0_reg12_mask (void) /* In the normal case we only need to save those registers which are call saved and which are used by this function. */ for (reg = 0; reg <= 11; reg++) - if (df_regs_ever_live_p (reg) && ! call_used_regs[reg]) + if (df_regs_ever_live_p (reg) && callee_saved_reg_p (reg)) save_reg_mask |= (1 << reg); /* Handle the frame pointer as a special case. */ @@ -19212,7 +19220,7 @@ thumb1_compute_save_reg_mask (void) mask = 0; for (reg = 0; reg < 12; reg ++) - if (df_regs_ever_live_p (reg) && !call_used_regs[reg]) + if (df_regs_ever_live_p (reg) && callee_saved_reg_p (reg)) mask |= 1 << reg; if (flag_pic @@ -19245,7 +19253,7 @@ thumb1_compute_save_reg_mask (void) if (reg * UNITS_PER_WORD <= (unsigned) arm_size_return_regs ()) reg = LAST_LO_REGNUM; - if (! call_used_regs[reg]) + if (callee_saved_reg_p (reg)) mask |= 1 << reg; } @@ -27185,8 +27193,7 @@ arm_conditional_register_usage (void) /* When optimizing for size on Thumb-1, it's better not to use the HI regs, because of the overhead of stacking them. */ - for (regno = FIRST_HI_REGNUM; - regno <= LAST_HI_REGNUM; ++regno) + for (regno = FIRST_HI_REGNUM; regno <= LAST_HI_REGNUM; ++regno) fixed_regs[regno] = call_used_regs[regno] = 1; } diff --git a/gcc/testsuite/gcc.target/arm/pr64453.c b/gcc/testsuite/gcc.target/arm/pr64453.c new file mode 100644 index 0000000..17155af --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr64453.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-mthumb -Os " } */ +/* { dg-require-effective-target arm_thumb1_ok } */ + +void save_regs () { + __asm volatile ("" ::: "r8"); +} + +/* { dg-final { scan-assembler "\tmov\tr., r8" } } */ Tested by compiling an arm-none-eabi GCC cross-compiler and running the testsuite on QEMU emulating Cortex-M0 without any regression. Is this ok for trunk? Best regards, Thomas