This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Committed: Allow RX fast interrupt handlers to use the stack


Hi Guys,

  I am applying the patch below to fix a thinko with the RX port.  For
  some reason I had it in my head that fast interrupt handlers should
  not be allowed to use the stack.  This is not true (although they do
  benefit if they can be coded without stack accesses) and so I have
  created this patch to fix the problem.

Cheers
  Nick

gcc/ChangeLog
2009-12-02  Nick Clifton  <nickc@redhat.com>

	* config/rx/rx.c (rx_conditional_register_usage): Do not warn if
	no fixed registers are available for interrupt handlers.  Do not
	fix normal registers.
	(MUST_SAVE_ACC_REGISTER): New macro.
	(rx_get_stack_layout): Create a stack frame for fast interrupt
	handlers, if necessary.  Push extra registers if needed in order
	to save the accumulator.
	(rx_expand_prologue): Create a stack frame for fast interrupt
	handlers, if necessary.
	(rx_expand_builtin_mvfc): Handle the case where there is no
	target.

Index: gcc/config/rx/rx.c
===================================================================
--- gcc/config/rx/rx.c	(revision 154899)
+++ gcc/config/rx/rx.c	(working copy)
@@ -887,46 +887,25 @@
 
       if (use_fixed_regs)
 	{
-	  unsigned int switched = 0;
 	  unsigned int r;
 
-	  /* This is for fast interrupt handlers.  Any register in
-	     the range r10 to r13 (inclusive) that is currently
-	     marked as fixed is now a viable, call-saved register.
-	     All other registers are fixed.  */
 	  memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs);
 	  memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs);
-	  
-	  for (r = 1; r < 10; r++)
-	    fixed_regs[r] = call_used_regs[r] = 1;
-	  
+
+	  /* This is for fast interrupt handlers.  Any register in
+	     the range r10 to r13 (inclusive) that is currently
+	     marked as fixed is now a viable, call-used register.  */	  
 	  for (r = 10; r <= 13; r++)
 	    if (fixed_regs[r])
 	      {
 		fixed_regs[r] = 0;
 		call_used_regs[r] = 1;
-		++ switched;
 	      }
-	    else
-	      {
-		fixed_regs[r] = 1;
-		call_used_regs[r] = 1;
-	      }
 
-	  fixed_regs[14] = call_used_regs[14] = 1;
-	  fixed_regs[15] = call_used_regs[15] = 1;
-
-	  if (switched == 0)
-	    {
-	      static bool warned = false;
-
-	      if (! warned)
-		{
-		  warning (0, "no fixed registers available "
-			   "for use by fast interrupt handler");
-		  warned = true;
-		}
-	    }
+	  /* Mark r7 as fixed.  This is just a hack to avoid
+	     altering the reg_alloc_order array so that the newly
+	     freed r10-r13 registers are the preferred registers.  */
+	  fixed_regs[7] = call_used_regs[7] = 1;
 	}
       else
 	{
@@ -1017,6 +996,11 @@
   return (x + (x >> 16)) & 0x3f;
 }
 
+#define MUST_SAVE_ACC_REGISTER			\
+  (TARGET_SAVE_ACC_REGISTER			\
+   && (is_interrupt_func (NULL_TREE)		\
+       || is_fast_interrupt_func (NULL_TREE)))
+
 /* Returns either the lowest numbered and highest numbered registers that
    occupy the call-saved area of the stack frame, if the registers are
    stored as a contiguous block, or else a bitmask of the individual
@@ -1040,15 +1024,10 @@
   unsigned int pushed_mask;
   unsigned int unneeded_pushes;
 
-  if (is_naked_func (NULL_TREE)
-      || is_fast_interrupt_func (NULL_TREE))
+  if (is_naked_func (NULL_TREE))
     {
       /* Naked functions do not create their own stack frame.
-	 Instead the programmer must do that for us.
-
-	 Fast interrupt handlers use fixed registers that have
-	 been epsecially released to the function, so they do
-	 not need or want a stack frame.  */
+	 Instead the programmer must do that for us.  */
       * lowest = 0;
       * highest = 0;
       * register_mask = 0;
@@ -1063,7 +1042,14 @@
 	  && (! call_used_regs[reg]
 	      /* Even call clobbered registered must
 		 be pushed inside interrupt handlers.  */
-	      || is_interrupt_func (NULL_TREE)))
+	      || is_interrupt_func (NULL_TREE)
+	      /* Likewise for fast interrupt handlers, except registers r10 -
+		 r13.  These are normally call-saved, but may have been set
+		 to call-used by rx_conditional_register_usage.  If so then
+		 they can be used in the fast interrupt handler without
+		 saving them on the stack.  */
+	      || (is_fast_interrupt_func (NULL_TREE)
+		  && ! IN_RANGE (reg, 10, 13))))
 	{
 	  if (low == 0)
 	    low = reg;
@@ -1078,6 +1064,18 @@
 	fixed_reg = reg;
     }
 
+  /* If we have to save the accumulator register, make sure
+     that at least two registers are pushed into the frame.  */
+  if (MUST_SAVE_ACC_REGISTER
+      && bit_count (save_mask) < 2)
+    {
+      save_mask |= (1 << 13) | (1 << 14);
+      if (low == 0)
+	low = 13;
+      if (high == 0)
+	high = 14;
+    }
+
   /* Decide if it would be faster fill in the call-saved area of the stack
      frame using multiple PUSH instructions instead of a single PUSHM
      instruction.
@@ -1207,9 +1205,7 @@
   rtx insn;
 
   /* Naked functions use their own, programmer provided prologues.  */
-  if (is_naked_func (NULL_TREE)
-      /* Fast interrupt functions never use the stack.  */
-      || is_fast_interrupt_func (NULL_TREE))
+  if (is_naked_func (NULL_TREE))
     return;
 
   rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size);
@@ -1236,13 +1232,13 @@
       mark_frame_related (insn);
     }
 
-  if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER)
+  if (MUST_SAVE_ACC_REGISTER)
     {
       unsigned int acc_high, acc_low;
 
       /* Interrupt handlers have to preserve the accumulator
 	 register if so requested by the user.  Use the first
-         two pushed register as intermediaries.  */
+         two pushed registers as intermediaries.  */
       if (mask)
 	{
 	  acc_low = acc_high = 0;
@@ -1510,7 +1506,7 @@
 	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 			       GEN_INT (total_size)));
 
-      if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER)
+      if (MUST_SAVE_ACC_REGISTER)
 	{
 	  unsigned int acc_low, acc_high;
 
@@ -1901,6 +1897,9 @@
   if (! CONST_INT_P (arg))
     return NULL_RTX;
 
+  if (target == NULL_RTX)
+    return NULL_RTX;
+
   if (! REG_P (target))
     target = force_reg (SImode, target);
 
@@ -2135,7 +2134,7 @@
    a function_decl or NULL if this is an indirect call, using EXP  */
 
 static bool
-rx_function_ok_for_sibcall (tree decl, tree exp)
+rx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   /* Do not allow indirect tailcalls.  The
      sibcall patterns do not support them.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]