avr-protos.h (avr_hard_regno_mode_ok): New prototype.
authorMarek Michalkiewicz <marekm@linux.org.pl>
Sat, 24 Jun 2000 18:01:26 +0000 (20:01 +0200)
committerDenis Chertykov <denisc@gcc.gnu.org>
Sat, 24 Jun 2000 18:01:26 +0000 (22:01 +0400)
* config/avr/avr-protos.h (avr_hard_regno_mode_ok): New prototype.
* config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr):
New functions, common code moved from function_{prologue,epilogue}
and extended to support the -mtiny-stack option.
(function_prologue, function_epilogue): Use them.
Use lo8/hi8 consistently for asm output readability.
(avr_hard_regno_mode_ok): New function.
* config/avr/avr.h (TARGET_SWITCHES): Fix typo.  Add -mtiny-stack.
(UNITS_PER_WORD): Define as 4 (not 1) when compiling libgcc2.c.
(HARD_REGNO_MODE_OK): Call the avr_hard_regno_mode_ok function.
* config/avr/avr.md (*mov_sp_r): Add support for -mtiny-stack.
Write SPH before SPL.
(*movqi): No need to disable interrupts for just one "out"
in alternative 5.  Change length attribute from 4 to 1.
* config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
Write SPH before SPL.

From-SVN: r34678

gcc/ChangeLog
gcc/config/avr/avr-protos.h
gcc/config/avr/avr.c
gcc/config/avr/avr.h
gcc/config/avr/avr.md
gcc/config/avr/libgcc.S

index 4d78128..7e39f84 100644 (file)
@@ -1,3 +1,22 @@
+2000-06-24  Marek Michalkiewicz  <marekm@linux.org.pl>
+
+       * config/avr/avr-protos.h (avr_hard_regno_mode_ok): New prototype.
+       * config/avr/avr.c (out_adj_frame_ptr, out_set_stack_ptr):
+       New functions, common code moved from function_{prologue,epilogue}
+       and extended to support the -mtiny-stack option.
+       (function_prologue, function_epilogue): Use them.
+       Use lo8/hi8 consistently for asm output readability.
+       (avr_hard_regno_mode_ok): New function.
+       * config/avr/avr.h (TARGET_SWITCHES): Fix typo.  Add -mtiny-stack.
+       (UNITS_PER_WORD): Define as 4 (not 1) when compiling libgcc2.c.
+       (HARD_REGNO_MODE_OK): Call the avr_hard_regno_mode_ok function.
+       * config/avr/avr.md (*mov_sp_r): Add support for -mtiny-stack.
+       Write SPH before SPL.
+       (*movqi): No need to disable interrupts for just one "out"
+       in alternative 5.  Change length attribute from 4 to 1.
+       * config/avr/libgcc.S (__prologue_saves__, __epilogue_restores__):
+       Write SPH before SPL.
+
 2000-06-24  Bernd Schmidt  <bernds@cygnus.co.uk>
 
        * rtl.texi (Vector Operations): New node.
index 7532754..4399dba 100644 (file)
@@ -138,6 +138,8 @@ extern int    byte_immediate_operand PARAMS ((register rtx op,
 extern int    test_hard_reg_class    PARAMS ((enum reg_class class, rtx x));
 extern int    jump_over_one_insn_p   PARAMS ((rtx insn, rtx dest));
 
+extern int    avr_hard_regno_mode_ok PARAMS ((int regno,
+                                            enum machine_mode mode));
 #endif /* RTX_CODE */
 
 #ifdef HAVE_MACHINE_MODES
index 5ac63f1..4e58c72 100644 (file)
@@ -49,6 +49,8 @@ static int    signal_function_p    PARAMS ((tree));
 static int    sequent_regs_live    PARAMS ((void));
 static char * ptrreg_to_str        PARAMS ((int));
 static char * cond_string          PARAMS ((enum rtx_code));
+static int    out_adj_frame_ptr    PARAMS ((FILE *, int));
+static int    out_set_stack_ptr    PARAMS ((FILE *, int, int));
 
 
 /* Allocate registers from r25 to r8 for parameters for function calls */
@@ -332,6 +334,124 @@ sequent_regs_live ()
 }
 
 
+/* Output to FILE the asm instructions to adjust the frame pointer by
+   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
+   (epilogue).  Returns the number of instructions generated.  */
+
+static int
+out_adj_frame_ptr (file, adj)
+     FILE *file;
+     int adj;
+{
+  int size = 0;
+
+  if (adj)
+    {
+      /* For -mtiny-stack, the high byte (r29) does not change -
+        prefer "subi" (1 cycle) over "sbiw" (2 cycles).  */
+
+      if (adj < -63 || adj > 63 || TARGET_TINY_STACK)
+       {
+         fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB), adj);
+         size++;
+
+         if (TARGET_TINY_STACK)
+           {
+             /* In addition to any local data, each level of function calls
+                needs at least 4 more bytes of stack space for the saved
+                frame pointer and return address.  So, (255 - 16) leaves
+                room for 4 levels of function calls.  */
+
+             if (adj < -(255 - 16) || adj > (255 - 16))
+               fatal ("Frame pointer change (%d) too big for -mtiny-stack",
+                      adj);
+           }
+         else
+           {
+             fprintf (file, (AS2 (sbci, r29, hi8(%d)) CR_TAB), adj);
+             size++;
+           }
+       }
+      else if (adj < 0)
+       {
+         fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
+         size++;
+       }
+      else
+       {
+         fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
+         size++;
+       }
+    }
+  return size;
+}
+
+
+/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
+   handling various cases of interrupt enable flag state BEFORE and AFTER
+   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
+   Returns the number of instructions generated.  */
+
+static int
+out_set_stack_ptr (file, before, after)
+     FILE *file;
+     int before;
+     int after;
+{
+  int do_sph, do_cli, do_save, size;
+
+  if (TARGET_NO_INTERRUPTS)
+    {
+      before = 0;
+      after = 0;
+    }
+
+  do_sph = !TARGET_TINY_STACK;
+  do_cli = (before != 0 && (after == 0 || do_sph));
+  do_save = (before == -1 && after == -1 && do_cli);
+  size = 1;
+
+  if (do_save)
+    {
+      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
+      size++;
+    }
+
+  if (do_cli)
+    {
+      fprintf (file, "cli" CR_TAB);
+      size++;
+    }
+
+  /* Do SPH first - maybe this will disable interrupts for one instruction
+     someday, much like x86 does when changing SS (a suggestion has been
+     sent to avr@atmel.com for consideration in future devices).  */
+  if (do_sph)
+    {
+      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
+      size++;
+    }
+
+  /* Set/restore the I flag now - interrupts will be really enabled only
+     after the next instruction starts.  This was not clearly documented.
+     XXX - verify this on the new devices with enhanced AVR core.  */
+  if (do_save)
+    {
+      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
+      size++;
+    }
+  else if (after == 1 && (before != 1 || do_cli))
+    {
+      fprintf (file, "sei" CR_TAB);
+      size++;
+    }
+
+  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
+
+  return size;
+}
+
+
 /* Output function prologue */
 
 void
@@ -392,8 +512,8 @@ function_prologue (FILE *file, int size)
   else if (minimize && (frame_pointer_needed || live_seq > 6)) 
     {
       fprintf (file, ("\t"
-                     AS2 (ldi, r26, %d) CR_TAB
-                     AS2 (ldi, r27, %d) CR_TAB), size & 0xff, size / 0x100);
+                     AS2 (ldi, r26, lo8(%d)) CR_TAB
+                     AS2 (ldi, r27, hi8(%d)) CR_TAB), size, size);
 
       fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
                      AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
@@ -444,44 +564,20 @@ function_prologue (FILE *file, int size)
            prologue_size += 4;
            if (size)
              {
-               if (size > 63)
-                 {
-                   fprintf (file, ("\t"
-                                   AS2 (subi,r28,%d) CR_TAB
-                                   AS2 (sbci,r29,%d) CR_TAB)
-                            , size & 0xff, size / 0x100);
-                   prologue_size += 2;
-                 }
-               else
-                 {
-                   fprintf (file, "\t" AS2 (sbiw,r28,%d) CR_TAB, size);
-                   ++prologue_size;
-                 }
+               fputs ("\t", file);
+               prologue_size += out_adj_frame_ptr (file, size);
+
                if (interrupt_func_p)
                  {
-                   fprintf (file,
-                            "cli" CR_TAB
-                            AS2 (out,__SP_L__,r28) CR_TAB
-                            "sei" CR_TAB
-                            AS2 (out,__SP_H__,r29) "\n");
-                   prologue_size += 4;
+                   prologue_size += out_set_stack_ptr (file, -1, 1);
                  }
-               else if (signal_func_p || TARGET_NO_INTERRUPTS)
+               else if (signal_func_p)
                  {
-                   fprintf (file,
-                            AS2 (out,__SP_L__,r28) CR_TAB
-                            AS2 (out,__SP_H__,r29) "\n");
-                   prologue_size += 2;
+                   prologue_size += out_set_stack_ptr (file, 0, 0);
                  }
                else
                  {
-                   fprintf (file,
-                            AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-                            "cli" CR_TAB
-                            AS2 (out,__SP_L__,r28) CR_TAB
-                            AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-                            AS2 (out,__SP_H__,r29) "\n");
-                   prologue_size += 5;
+                   prologue_size += out_set_stack_ptr (file, -1, -1);
                  }
              }
          }
@@ -533,20 +629,7 @@ function_epilogue (FILE *file, int size)
       ++epilogue_size;
       if (frame_pointer_needed)
        {
-         if (size)
-           {
-             if (size > 63)
-               {
-                 fprintf (file, AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
-                 fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
-                 epilogue_size += 2;
-               }
-             else
-               {
-                 fprintf (file, AS2 (adiw,r28,%d) CR_TAB, size);
-                 ++epilogue_size;
-               }
-           }
+         epilogue_size += out_adj_frame_ptr (file, -size);
        }
       else
        {
@@ -574,41 +657,16 @@ function_epilogue (FILE *file, int size)
        {
          if (size)
            {
-             if (size > 63)
-               {
-                 fprintf (file, "\t" AS2 (subi,r28,lo8(-%d)) CR_TAB, size);
-                 fprintf (file, AS2 (sbci,r29,hi8(-%d)) CR_TAB, size);
-                 epilogue_size += 2;
-               }
-             else
-               {
-                 fprintf (file, "\t" AS2 (adiw,r28,%d) CR_TAB, size);
-                 ++epilogue_size;
-               }
+             fputs ("\t", file);
+             epilogue_size += out_adj_frame_ptr (file, -size);
+
              if (interrupt_func_p | signal_func_p)
                {
-                 fprintf (file,
-                          "cli" CR_TAB
-                          AS2 (out,__SP_L__,r28) CR_TAB
-                          AS2 (out,__SP_H__,r29) "\n");
-                 epilogue_size += 3;
-               }
-             else if (TARGET_NO_INTERRUPTS)
-               {
-                 fprintf (file,
-                          AS2 (out,__SP_L__,r28) CR_TAB
-                          AS2 (out,__SP_H__,r29) "\n");
-                 epilogue_size += 2;
+                 epilogue_size += out_set_stack_ptr (file, -1, 0);
                }
              else
                {
-                 fprintf (file,
-                          AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-                          "cli" CR_TAB
-                          AS2 (out,__SP_L__,r28) CR_TAB
-                          AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-                          AS2 (out,__SP_H__,r29) "\n");
-                 epilogue_size += 5;
+                 epilogue_size += out_set_stack_ptr (file, -1, -1);
                }
            }
          fprintf (file, "\t"
@@ -3886,3 +3944,20 @@ jump_over_one_insn_p (insn, dest)
   int dest_addr = insn_addresses[uid];
   return dest_addr - jump_addr == 2;
 }
+
+/* Returns 1 if a value of mode MODE can be stored starting with hard
+   register number REGNO.  On the enhanced core, it should be a win to
+   align modes larger than QI on even register numbers (even if < 24).
+   so that the "movw" instruction can be used on them.  */
+
+int
+avr_hard_regno_mode_ok (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  if (mode == QImode)
+    return 1;
+  if (regno < 24 /* && !TARGET_ENHANCED */ )
+    return 1;
+  return !(regno & 1);
+}
index b357af5..0096629 100644 (file)
@@ -52,6 +52,7 @@ extern int target_flags;
 #define TARGET_NO_INTERRUPTS   (target_flags & 0x20000)
 #define TARGET_INSN_SIZE_DUMP  (target_flags &  0x2000)
 #define TARGET_CALL_PROLOGUES  (target_flags & 0x40000)
+#define TARGET_TINY_STACK      (target_flags & 0x80000)
 
 /* Dump each assembler insn's rtl into the output file.
    This is for debugging the compiler itself.  */
@@ -87,7 +88,8 @@ extern int target_flags;
   {"int8",0x10000,"Assume int to be 8 bit integer"},                   \
   {"no-interrupts",0x20000,"Don't output interrupt compatible code"},  \
   {"call-prologues",0x40000,                                           \
-   "Use subroutines for functions prologeu/epilogue"},                 \
+   "Use subroutines for functions prologue/epilogue"},                 \
+  {"tiny-stack", 0x80000, "Change only low 8 bits of stack pointer"},  \
   {"rtl",0x10, NULL},                                                  \
   {"size",0x2000,"Output instruction size's to the asm file"},         \
   {"deb",0xfe0, NULL},                                                 \
@@ -194,8 +196,13 @@ extern struct mcu_type_s *avr_mcu_type;
    Note that this is not necessarily the width of data type `int';  */
 #define BITS_PER_WORD 8
 
+#ifdef IN_LIBGCC2
+/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits).  */
+#define UNITS_PER_WORD 4
+#else
 /* Width of a word, in units (bytes). */
 #define UNITS_PER_WORD 1
+#endif
 
 /* Width in bits of a pointer.
    See also the macro `Pmode' defined below.  */
@@ -452,9 +459,7 @@ extern struct mcu_type_s *avr_mcu_type;
    ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1)  \
    / UNITS_PER_WORD))  */
 
-#define HARD_REGNO_MODE_OK(REGNO, MODE) (((REGNO) >= 24 && (MODE) != QImode) \
-                                        ? ! ((REGNO) & 1)                   \
-                                        : 1)
+#define HARD_REGNO_MODE_OK(REGNO, MODE) avr_hard_regno_mode_ok(REGNO, MODE)
 /* A C expression that is nonzero if it is permissible to store a
    value of mode MODE in hard register number REGNO (or in several
    registers starting with that one).  For a machine where all
index f3ac93b..4d2451e 100644 (file)
 (define_insn "*mov_sp_r"
   [(set (reg:HI 32)
         (match_operand:HI 0 "register_operand" "r"))]
-  "!TARGET_NO_INTERRUPTS"
+  "(!TARGET_TINY_STACK && !TARGET_NO_INTERRUPTS)"
   "in __tmp_reg__,__SREG__
        cli
-       out __SP_L__,%A0
+       out __SP_H__,%B0
        out __SREG__,__tmp_reg__
-       out __SP_H__,%B0"
+       out __SP_L__,%A0"
   [(set_attr "length" "5")])
 
 (define_insn "*mov_sp_r_no_interrupts"
   [(set (reg:HI 32)
         (match_operand:HI 0 "register_operand" "r"))]
-  "TARGET_NO_INTERRUPTS"
-  "out __SP_L__,%A0
-       out __SP_H__,%B0"
+  "(!TARGET_TINY_STACK && TARGET_NO_INTERRUPTS)"
+  "out __SP_H__,%B0
+       out __SP_L__,%A0"
   [(set_attr "length" "2")])
 
+(define_insn "*mov_sp_r_tiny"
+  [(set (reg:HI 32)
+        (match_operand:HI 0 "register_operand" "r"))]
+  "TARGET_TINY_STACK"
+  "out __SP_L__,%A0"
+  [(set_attr "length" "1")])
+
 ;;========================================================================
 ;; move byte
 (define_expand "movqi"
       case 4:
         return out_movqi_r_mr (insn,operands,NULL);
       case 5:
-        return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB
-               \"cli\"                       CR_TAB
-               AS2 (out,__SREG__,__tmp_reg__)CR_TAB
-               AS2 (out,%0,%1));
+        return (AS2 (out,%0,%1));
       }
 }"
-  [(set_attr "length" "1,1,1,5,5,4")
+  [(set_attr "length" "1,1,1,5,5,1")
    (set_attr "cc" "none,clobber,none,clobber,clobber,none")])
 
 ;;============================================================================
index 10fa12e..00aa50b 100644 (file)
@@ -583,9 +583,9 @@ __prologue_saves__:
        sbc     r29,r27
        in      __tmp_reg__,__SREG__
        cli
-       out     __SP_L__,r28
-       out     __SREG__,__tmp_reg__
        out     __SP_H__,r29
+       out     __SREG__,__tmp_reg__
+       out     __SP_L__,r28
 _prologue_end:
        ijmp
 .endfunc
@@ -621,9 +621,9 @@ __epilogue_restores__:
        adc     r29,__zero_reg__
        in      __tmp_reg__,__SREG__
        cli
-       out     __SP_L__,r28
-       out     __SREG__,__tmp_reg__
        out     __SP_H__,r29
+       out     __SREG__,__tmp_reg__
+       out     __SP_L__,r28
        mov     r28,r26
        mov     r29,r27
        ret