[PATCH][ARM] Fix -fcall-saved-rX for X > 7

Thomas Preud'homme thomas.preudhomme@arm.com
Wed Aug 20 01:28:00 GMT 2014


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.preudhomme@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.preudhomme@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




More information about the Gcc-patches mailing list