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



Reply via email to