Hi DJ,

  The patch below makes some changes to the way the RL78 backend handles
  the generation of interrupt functions.  Specifically it:

    * Uses register bank 3 instead of register bank 0 inside the
      handler.

    * Tweaks the need_to_save() function so only those registers that
      will be clobbered by the handler are push onto the stack.

    * Provides support for a "naked" function attribute so that
      programmers can write their own mixed C/assembler interrupt
      handlers if they want to.

   Tested, with no regressions, on an rl78-elf target.

   OK to apply ?

Cheers
  Nick

gcc/ChangeLog
2013-05-01  Nick Clifton  <ni...@redhat.com>

        * config/rl78/rl78.c (need_to_save): Make into a boolean
        function.  Do not save register bank 0 registers in interrupt
        handlers.
        (rl78_attribute_table): Add "naked".
        (rl78_is_naked_func): New function.
        (rl78_expand_prologue): Skip prologue generation for naked
        functions.  Switch to register bank 3 for interrupt handlers.
        (rl78_expand_epilogue): Skip epilogue generation for naked
        functions.  Switch back to register bank 0 in interrupt
        handlers.
        * doc/extend.texi: Document that the RL78 backend supports the
        "naked" function attribute.

Index: gcc/config/rl78/rl78.c
===================================================================
--- gcc/config/rl78/rl78.c      (revision 198496)
+++ gcc/config/rl78/rl78.c      (working copy)
@@ -373,34 +373,42 @@
   return true;
 }
 
-/* Returns nonzero if the given register needs to be saved by the
+/* Returns true if the given register needs to be saved by the
    current function.  */
-static int
-need_to_save (int regno)
+static bool
+need_to_save (unsigned int regno)
 {
   if (is_interrupt_func (cfun->decl))
     {
+      /* We don't need to save registers that have
+         been reserved for interrupt handlers.  */
+      if (regno > 23)
+       return false;
+
+      /* If the handler is a non-leaf function then it may call
+        non-interrupt aware routines which will happily clobber
+        any call_used registers, so we have to preserve them.  */
+      if (!crtl->is_leaf && call_used_regs[regno])
+       return true;
+
+      /* Interrupt functions do not use register bank 0.  */
       if (regno < 8)
-       return 1; /* don't know what devirt will need */
-      if (regno > 23)
-       return 0; /* don't need to save interrupt registers */
-      if (crtl->is_leaf)
-       {
-         return df_regs_ever_live_p (regno);
-       }
-      else
-       return 1;
+       return false;
+
+      /* Otherwise we only have to save a register, call_used
+        or not, if it is used by this handler.  */
+      return df_regs_ever_live_p (regno);
     }
   if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
-    return 1;
+    return true;
   if (fixed_regs[regno])
-    return 0;
+    return false;
   if (crtl->calls_eh_return)
-    return 1;
+    return true;
   if (df_regs_ever_live_p (regno)
       && !call_used_regs[regno])
-    return 1;
-  return 0;
+    return true;
+  return false;
 }
 
 /* We use this to wrap all emitted insns in the prologue.  */
@@ -499,6 +507,8 @@
     false },
   { "brk_interrupt",  0, 0, true, false, false, rl78_handle_func_attribute,
     false },
+  { "naked",          0, 0, true, false, false, rl78_handle_func_attribute,
+    false },
   { NULL,             0, 0, false, false, false, NULL, false }
 };
 
@@ -825,6 +833,12 @@
   return rv;
 }
 
+static int
+rl78_is_naked_func (void)
+{
+  return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) 
!= NULL_TREE);
+}
+
 /* Expand the function prologue (from the prologue pattern).  */
 void
 rl78_expand_prologue (void)
@@ -833,19 +847,22 @@
   rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
   int rb = 0;
 
+  if (rl78_is_naked_func ())
+    return;
+
+  rb = is_interrupt_func (cfun->decl) ? -1 : 0;
+
   if (!cfun->machine->computed)
     rl78_compute_frame_info ();
 
   if (flag_stack_usage_info)
     current_function_static_stack_size = cfun->machine->framesize;
 
-  if (is_interrupt_func (cfun->decl))
-    emit_insn (gen_sel_rb (GEN_INT (0)));
-
   for (i = 0; i < 16; i++)
     if (cfun->machine->need_to_push [i])
       {
        int need_bank = i/4;
+
        if (need_bank != rb)
          {
            emit_insn (gen_sel_rb (GEN_INT (need_bank)));
@@ -853,7 +870,14 @@
          }
        F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2))));
       }
-  if (rb != 0)
+
+  /* Interrupt functions use rb3 instead of rb0.  */
+  if (is_interrupt_func (cfun->decl))
+    {
+      if (rb != 3)
+       emit_insn (gen_sel_rb (GEN_INT (3)));
+    }
+  else if (rb != 0)
     emit_insn (gen_sel_rb (GEN_INT (0)));
 
   if (frame_pointer_needed)
@@ -877,6 +901,11 @@
   rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
   int rb = 0;
 
+  if (rl78_is_naked_func ())
+    return;
+
+  rb = is_interrupt_func (cfun->decl) ? 3 : 0;
+
   if (frame_pointer_needed)
     {
       emit_move_insn (gen_rtx_REG (HImode, STACK_POINTER_REGNUM),
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 198496)
+++ gcc/doc/extend.texi (working copy)
@@ -3142,7 +3142,7 @@
 
 @item naked
 @cindex function without a prologue/epilogue code
-Use this attribute on the ARM, AVR, MCORE, RX and SPU ports to indicate that
+Use this attribute on the ARM, AVR, MCORE, RL78, RX and SPU ports to indicate 
that
 the specified function does not need prologue/epilogue sequences generated by
 the compiler.  It is up to the programmer to provide these sequences. The
 only statements that can be safely included in naked functions are

          

Reply via email to