OSDN Git Service

* calls.c, function.c: Always define PREFERRED_STACK_BOUNDARY
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / avr.c
index 38cd078..cb222b2 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by Denis Chertykov (denisc@overta.ru)
 
    This file is part of GNU CC.
@@ -27,7 +27,6 @@
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
@@ -39,6 +38,8 @@
 #include "function.h"
 #include "recog.h"
 #include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
 
 /* Maximal allowed offset for an address in the LD command */
 #define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
@@ -52,9 +53,15 @@ static const char * cond_string    PARAMS ((enum rtx_code));
 static int    avr_num_arg_regs     PARAMS ((enum machine_mode, tree));
 static int    out_adj_frame_ptr    PARAMS ((FILE *, int));
 static int    out_set_stack_ptr    PARAMS ((FILE *, int, int));
+static RTX_CODE compare_condition  PARAMS ((rtx insn));
+static int    compare_sign_p       PARAMS ((rtx insn));
 static int    reg_was_0            PARAMS ((rtx insn, rtx op));
 static int    io_address_p         PARAMS ((rtx x, int size));
 void          debug_hard_reg_set   PARAMS ((HARD_REG_SET set));
+static int    avr_valid_type_attribute PARAMS ((tree, tree, tree, tree));
+static int    avr_valid_decl_attribute PARAMS ((tree, tree, tree, tree));
+static void   avr_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
+static void   avr_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
 
 /* Allocate registers from r25 to r8 for parameters for function calls */
 #define FIRST_CUM_REG 26
@@ -88,6 +95,9 @@ static int commands_in_epilogues;
 static int prologue_size;
 static int epilogue_size;
 
+/* Size of all jump tables in the current function, in words.  */
+static int jump_tables_size;
+
 /* Initial stack value specified by the `-minit-stack=' option */
 const char *avr_init_stack = "__stack";
 
@@ -161,7 +171,20 @@ static const struct mcu_type_s avr_mcu_types[] = {
 };
 
 int avr_case_values_threshold = 30000;
-
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
+#undef TARGET_VALID_DECL_ATTRIBUTE
+#define TARGET_VALID_DECL_ATTRIBUTE avr_valid_decl_attribute
+
+#undef TARGET_VALID_TYPE_ATTRIBUTE
+#define TARGET_VALID_TYPE_ATTRIBUTE avr_valid_type_attribute
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 void
 avr_override_options ()
 {
@@ -177,18 +200,18 @@ avr_override_options ()
               avr_mcu_name);
       for (t = avr_mcu_types; t->name; t++)
        fprintf (stderr,"   %s\n", t->name);
-      fatal ("select right MCU name");
     }
 
   switch (t->arch)
     {
-      case AVR1:
-      default:
-       fatal ("MCU `%s' not supported", avr_mcu_name);
-      case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
-      case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
-      case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
-      case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
+    case AVR1:
+    default:
+      error ("MCU `%s' not supported", avr_mcu_name);
+      /* ... fall through ... */
+    case AVR2: avr_enhanced_p = 0; avr_mega_p = 0; break;
+    case AVR3: avr_enhanced_p = 0; avr_mega_p = 1; break;
+    case AVR4: avr_enhanced_p = 1; avr_mega_p = 0; break;
+    case AVR5: avr_enhanced_p = 1; avr_mega_p = 1; break;
     }
 
   if (optimize && !TARGET_NO_TABLEJUMP)
@@ -500,8 +523,8 @@ out_set_stack_ptr (file, before, after)
     }
 
   /* 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.  */
+     after the next instruction.  This is not clearly documented, but
+     believed to be true for all AVR devices.  */
   if (do_save)
     {
       fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
@@ -521,10 +544,10 @@ out_set_stack_ptr (file, before, after)
 
 /* Output function prologue */
 
-void
-function_prologue (file, size)
+static void
+avr_output_function_prologue (file, size)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
 {
   int reg;
   int interrupt_func_p;
@@ -549,6 +572,7 @@ function_prologue (file, size)
              && !interrupt_func_p && !signal_func_p && live_seq);
 
   last_insn_address = 0;
+  jump_tables_size = 0;
   prologue_size = 0;
   fprintf (file, "/* prologue: frame size=%d */\n", size);
   
@@ -657,10 +681,10 @@ function_prologue (file, size)
 
 /* Output function epilogue */
 
-void
-function_epilogue (file, size)
+static void
+avr_output_function_epilogue (file, size)
      FILE *file;
-     int size;
+     HOST_WIDE_INT size;
 {
   int reg;
   int interrupt_func_p;
@@ -683,6 +707,7 @@ function_epilogue (file, size)
   main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
   function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ()))
                   - INSN_ADDRESSES (INSN_UID (get_insns ())));
+  function_size += jump_tables_size;
   live_seq = sequent_regs_live ();
   minimize = (TARGET_CALL_PROLOGUES
              && !interrupt_func_p && !signal_func_p && live_seq);
@@ -796,7 +821,8 @@ legitimate_address_p (mode, x, strict)
      rtx x;
      int strict;
 {
-  int r = 0;
+  enum reg_class r = NO_REGS;
+  
   if (TARGET_ALL_DEBUG)
     {
       fprintf (stderr, "mode: (%s) %s %s %s %s:",
@@ -818,9 +844,9 @@ legitimate_address_p (mode, x, strict)
     }
   if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
                     : REG_OK_FOR_BASE_NOSTRICT_P (x)))
-    r = 'R';
+    r = POINTER_REGS;
   else if (CONSTANT_ADDRESS_P (x))
-    r = 'S';
+    r = ALL_REGS;
   else if (GET_CODE (x) == PLUS
            && REG_P (XEXP (x, 0))
           && GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -832,26 +858,26 @@ legitimate_address_p (mode, x, strict)
          if (! strict
              || REGNO (XEXP (x,0)) == REG_Y
              || REGNO (XEXP (x,0)) == REG_Z)
-             r = 'Q';
+           r = BASE_POINTER_REGS;
          if (XEXP (x,0) == frame_pointer_rtx
              || XEXP (x,0) == arg_pointer_rtx)
-           r = 'Q';
+           r = BASE_POINTER_REGS;
        }
       else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
-       r = 'U';
+       r = POINTER_Y_REGS;
     }
   else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
            && REG_P (XEXP (x, 0))
            && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
                : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
     {
-      r = 'T';
+      r = POINTER_REGS;
     }
   if (TARGET_ALL_DEBUG)
     {
       fprintf (stderr, "   ret = %c\n", r);
     }
-  return r;
+  return r == NO_REGS ? 0 : (int)r;
 }
 
 /* Attempts to replace X with a valid
@@ -903,7 +929,7 @@ ptrreg_to_str (regno)
     case REG_Y: return "Y";
     case REG_Z: return "Z";
     default:
-      fatal ("register r%d isn't a pointer\n", regno);
+      abort ();
     }
   return NULL;
 }
@@ -926,10 +952,6 @@ cond_string (code)
        return "pl";
       else
        return "ge";
-    case GT:
-      fatal ("Internal compiler bug: command `bgt'");
-    case LE:
-      fatal ("Internal compiler bug: command `ble'");
     case LT:
       if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
        return "mi";
@@ -937,10 +959,6 @@ cond_string (code)
        return "lt";
     case GEU:
       return "sh";
-    case GTU:
-      fatal ("Internal compiler bug: command `bgtu'");
-    case LEU:
-      fatal ("Internal compiler bug: command `bleu'");
     case LTU:
       return "lo";
     default:
@@ -996,10 +1014,15 @@ print_operand (file, x, code)
   if (code >= 'A' && code <= 'D')
     abcd = code - 'A';
 
-  if (REG_P (x))
+  if (code == '~')
+    {
+      if (!AVR_MEGA)
+       fputc ('r', file);
+    }
+  else if (REG_P (x))
     {
       if (x == zero_reg_rtx)
-       fprintf (file,"__zero_reg__");
+       fprintf (file, "__zero_reg__");
       else
        fprintf (file, reg_names[true_regnum (x) + abcd]);
     }
@@ -1015,6 +1038,13 @@ print_operand (file, x, code)
          output_address (addr);
          fprintf (file, ")+%d", abcd);
        }
+      else if (code == 'o')
+       {
+         if (GET_CODE (addr) != PLUS)
+           fatal_insn ("Bad address, not (reg+disp):", addr);
+
+         print_operand (file, XEXP (addr, 1), 0);
+       }
       else if (GET_CODE (addr) == PLUS)
        {
          print_operand_address (file, XEXP (addr,0));
@@ -1175,14 +1205,19 @@ avr_jump_mode (x, insn)
   return 2;
 }
 
-/* return a AVR condition jump commands.
- LEN is a number returned by avr_jump_mode function.  */
+/* return an AVR condition jump commands.
+   X is a comparison RTX.
+   LEN is a number returned by avr_jump_mode function.
+   if REVERSE nonzero then condition code in X must be reversed.  */
 
 const char *
-ret_cond_branch (cond, len)
-     RTX_CODE cond;
+ret_cond_branch (x, len, reverse)
+     rtx x;
      int len;
+     int reverse;
 {
+  RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
+  
   switch (cond)
     {
     case GT:
@@ -1243,17 +1278,34 @@ ret_cond_branch (cond, len)
                AS1 (brsh,_PC_+4) CR_TAB
               AS1 (jmp,%0)));
     default:
-      switch (len)
-        {
-        case 1:
-          return AS1 (br%j1,%0);
-        case 2:
-          return (AS1 (br%k1,_PC_+2) CR_TAB
-                  AS1 (rjmp,%0));
-        default:
-          return (AS1 (br%k1,_PC_+4) CR_TAB
-                  AS1 (jmp,%0));
-        }
+      if (reverse)
+       {
+         switch (len)
+           {
+           case 1:
+             return AS1 (br%k1,%0);
+           case 2:
+             return (AS1 (br%j1,_PC_+2) CR_TAB
+                     AS1 (rjmp,%0));
+           default:
+             return (AS1 (br%j1,_PC_+4) CR_TAB
+                     AS1 (jmp,%0));
+           }
+       }
+       else
+         {
+           switch (len)
+             {
+             case 1:
+               return AS1 (br%j1,%0);
+             case 2:
+               return (AS1 (br%k1,_PC_+2) CR_TAB
+                       AS1 (rjmp,%0));
+             default:
+               return (AS1 (br%k1,_PC_+4) CR_TAB
+                       AS1 (jmp,%0));
+             }
+         }
     }
   return "";
 }
@@ -1756,41 +1808,30 @@ out_movqi_r_mr (insn, op, l)
          int disp = INTVAL (XEXP (x,1));
          if (REGNO (XEXP (x,0)) != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
+
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
-           {
-             *l = 3;
-             op[4] = XEXP (x, 1);
-             return (AS2 (adiw, r28, %4-63) CR_TAB
-                     AS2 (ldd, %0,Y+63)  CR_TAB
-                     AS2 (sbiw, r28, %4-63));
-           }
-         else
-           {
-             *l = 5;
-             op[4] = XEXP (x,1);
-             return (AS2 (subi, r28, lo8(-%4))  CR_TAB
-                     AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                     AS2 (ld, %0,Y)              CR_TAB
-                     AS2 (subi, r28, lo8(%4))   CR_TAB
-                     AS2 (sbci, r29, hi8(%4)));
-           }
+           return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
+                           AS2 (ldd,%0,Y+63)     CR_TAB
+                           AS2 (sbiw,r28,%o1-63));
+
+         return *l = 5, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+                         AS2 (ld,%0,Y)            CR_TAB
+                         AS2 (subi,r28,lo8(%o1))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o1)));
        }
       else if (REGNO (XEXP (x,0)) == REG_X)
        {
-         op[4] = XEXP (x, 1);
          /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
             it but I have this situation with extremal optimizing options.  */
          if (reg_overlap_mentioned_p (dest, XEXP (x,0))
              || reg_unused_after (insn, XEXP (x,0)))
-           {
-             *l = 2;
-             return (AS2 (adiw,r26,%4) CR_TAB
-                     AS2 (ld,%0,X));
-           }
-         *l = 3;
-         return (AS2 (adiw,r26,%4) CR_TAB
-                 AS2 (ld,%0,X)     CR_TAB
-                 AS2 (sbiw,r26,%4));
+           return *l = 2, (AS2 (adiw,r26,%o1) CR_TAB
+                           AS2 (ld,%0,X));
+
+         return *l = 3, (AS2 (adiw,r26,%o1) CR_TAB
+                         AS2 (ld,%0,X)      CR_TAB
+                         AS2 (sbiw,r26,%o1));
        }
       *l = 1;
       return AS2 (ldd,%0,%1);
@@ -1851,29 +1892,21 @@ out_movhi_r_mr (insn, op, l)
       
       if (disp > MAX_LD_OFFSET (GET_MODE (src)))
        {
-         op[4] = XEXP (base, 1);
-
          if (REGNO (XEXP (base, 0)) != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
          
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
-           {
-             *l = 4;
-             return (AS2 (adiw,r28,%4-62) CR_TAB
-                     AS2 (ldd,%A0,Y+62)   CR_TAB
-                     AS2 (ldd,%B0,Y+63)   CR_TAB
-                     AS2 (sbiw,r28,%4-62));
-           }
-         else
-           {
-             *l = 6;
-             return (AS2 (subi,r28,lo8(-%4)) CR_TAB
-                     AS2 (sbci,r29,hi8(-%4)) CR_TAB
-                     AS2 (ld,%A0,Y)          CR_TAB
-                     AS2 (ldd,%B0,Y+1)       CR_TAB
-                     AS2 (subi,r28,lo8(%4))  CR_TAB
-                     AS2 (sbci,r29,hi8(%4)));
-           }
+           return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
+                           AS2 (ldd,%A0,Y+62)    CR_TAB
+                           AS2 (ldd,%B0,Y+63)    CR_TAB
+                           AS2 (sbiw,r28,%o1-62));
+
+         return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+                         AS2 (ld,%A0,Y)           CR_TAB
+                         AS2 (ldd,%B0,Y+1)        CR_TAB
+                         AS2 (subi,r28,lo8(%o1))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o1)));
        }
       if (reg_base == REG_X)
        {
@@ -1881,31 +1914,17 @@ out_movhi_r_mr (insn, op, l)
             it but I have this situation with extremal
             optimization options.  */
          
-         op[4] = XEXP (base, 1);
-         
-         if (reg_base == reg_dest)
-           {
-             *l = 4;
-             return (AS2 (adiw,r26,%4)       CR_TAB
-                     AS2 (ld,__tmp_reg__,X+) CR_TAB
-                     AS2 (ld,%B0,X)          CR_TAB
-                     AS2 (mov,%A0,__tmp_reg__));
-           }
-
-         if (INTVAL (op[4]) == 63)
-           {
-             *l = 5;
-             return (AS2 (adiw,r26,%4)   CR_TAB
-                     AS2 (ld,%A0,X+)     CR_TAB
-                     AS2 (ld,%B0,X)      CR_TAB
-                     AS2 (subi,r26,%4+1) CR_TAB
-                     AS2 (sbci,r27,0));
-           }
          *l = 4;
-         return (AS2 (adiw,r26,%4) CR_TAB
-                 AS2 (ld,%A0,X+)   CR_TAB
-                 AS2 (ld,%B0,X)    CR_TAB
-                 AS2 (sbiw,r26,%4+1));
+         if (reg_base == reg_dest)
+           return (AS2 (adiw,r26,%o1)      CR_TAB
+                   AS2 (ld,__tmp_reg__,X+) CR_TAB
+                   AS2 (ld,%B0,X)          CR_TAB
+                   AS2 (mov,%A0,__tmp_reg__));
+
+         return (AS2 (adiw,r26,%o1) CR_TAB
+                 AS2 (ld,%A0,X+)    CR_TAB
+                 AS2 (ld,%B0,X)     CR_TAB
+                 AS2 (sbiw,r26,%o1+1));
        }
 
       if (reg_base == reg_dest)
@@ -1976,12 +1995,14 @@ out_movsi_r_mr (insn, op, l)
       if (reg_base == REG_X)        /* (R26) */
         {
           if (reg_dest == REG_X)
-            return *l=6, (AS2 (adiw,r26,3) CR_TAB
-                          AS2 (ld,%D0,X)  CR_TAB
-                          AS2 (ld,%C0,-X) CR_TAB
-                          AS2 (ld,__tmp_reg__,-X)  CR_TAB
-                          AS2 (ld,%A0,-X)  CR_TAB
-                          AS2 (mov,%B0,__tmp_reg__));
+           /* "ld r26,-X" is undefined */
+           return *l=7, (AS2 (adiw,r26,3)        CR_TAB
+                         AS2 (ld,r29,X)          CR_TAB
+                         AS2 (ld,r28,-X)         CR_TAB
+                         AS2 (ld,__tmp_reg__,-X) CR_TAB
+                         AS2 (sbiw,r26,1)        CR_TAB
+                         AS2 (ld,r26,X)          CR_TAB
+                         AS2 (mov,r27,__tmp_reg__));
           else if (reg_dest == REG_X - 2)
             return *l=5, (AS2 (ld,%A0,X+)  CR_TAB
                           AS2 (ld,%B0,X+) CR_TAB
@@ -2029,31 +2050,57 @@ out_movsi_r_mr (insn, op, l)
        {
          if (REGNO (XEXP (base, 0)) != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
+
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
-           {
-             op[4] = GEN_INT (disp - 60);
-             return *l=6,(AS2 (adiw, r28, %4) CR_TAB
-                          AS2 (ldd, %A0,Y+60)       CR_TAB
-                          AS2 (ldd, %B0,Y+61)     CR_TAB
-                          AS2 (ldd, %C0,Y+62)     CR_TAB
-                          AS2 (ldd, %D0,Y+63)     CR_TAB
-                          AS2 (sbiw, r28, %4));
-           }
-         else
-           {
-             op[4] = XEXP (base, 1);
-             return *l=8,(AS2 (subi, r28, lo8(-%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                          AS2 (ld, %A0,Y)             CR_TAB
-                          AS2 (ldd, %B0,Y+1)          CR_TAB
-                          AS2 (ldd, %C0,Y+2)          CR_TAB
-                          AS2 (ldd, %D0,Y+3)          CR_TAB
-                          AS2 (subi, r28, lo8(%4))   CR_TAB
-                          AS2 (sbci, r29, hi8(%4)));
-           }
+           return *l = 6, (AS2 (adiw,r28,%o1-60) CR_TAB
+                           AS2 (ldd,%A0,Y+60)    CR_TAB
+                           AS2 (ldd,%B0,Y+61)    CR_TAB
+                           AS2 (ldd,%C0,Y+62)    CR_TAB
+                           AS2 (ldd,%D0,Y+63)    CR_TAB
+                           AS2 (sbiw,r28,%o1-60));
+
+         return *l = 8, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o1)) CR_TAB
+                         AS2 (ld,%A0,Y)           CR_TAB
+                         AS2 (ldd,%B0,Y+1)        CR_TAB
+                         AS2 (ldd,%C0,Y+2)        CR_TAB
+                         AS2 (ldd,%D0,Y+3)        CR_TAB
+                         AS2 (subi,r28,lo8(%o1))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o1)));
        }
 
       reg_base = true_regnum (XEXP (base, 0));
+      if (reg_base == REG_X)
+       {
+         /* R = (X + d) */
+         if (reg_dest == REG_X)
+           {
+             *l = 7;
+             /* "ld r26,-X" is undefined */
+             return (AS2 (adiw,r26,%o1+3)    CR_TAB
+                     AS2 (ld,r29,X)          CR_TAB
+                     AS2 (ld,r28,-X)         CR_TAB
+                     AS2 (ld,__tmp_reg__,-X) CR_TAB
+                     AS2 (sbiw,r26,1)        CR_TAB
+                     AS2 (ld,r26,X)          CR_TAB
+                     AS2 (mov,r27,__tmp_reg__));
+           }
+         *l = 6;
+         if (reg_dest == REG_X - 2)
+           return (AS2 (adiw,r26,%o1)      CR_TAB
+                   AS2 (ld,r24,X+)         CR_TAB
+                   AS2 (ld,r25,X+)         CR_TAB
+                   AS2 (ld,__tmp_reg__,X+) CR_TAB
+                   AS2 (ld,r27,X)          CR_TAB
+                   AS2 (mov,r26,__tmp_reg__));
+
+         return (AS2 (adiw,r26,%o1) CR_TAB
+                 AS2 (ld,%A0,X+)    CR_TAB
+                 AS2 (ld,%B0,X+)    CR_TAB
+                 AS2 (ld,%C0,X+)    CR_TAB
+                 AS2 (ld,%D0,X)     CR_TAB
+                 AS2 (sbiw,r26,%o1+3));
+       }
       if (reg_dest == reg_base)
         return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
                       AS2 (ldd,%C0,%C1) CR_TAB
@@ -2118,19 +2165,22 @@ out_movsi_mr_r (insn, op, l)
         {
           if (reg_src == REG_X)
             {
+             /* "st X+,r26" is undefined */
               if (reg_unused_after (insn, base))
-                return *l=5, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
-                              AS2 (st,%0+,%A1) CR_TAB
-                              AS2 (st,%0+,__tmp_reg__)  CR_TAB
-                              AS2 (st,%0+,%C1) CR_TAB
-                              AS2 (st,%0,%D1));
+               return *l=6, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X+,__tmp_reg__)   CR_TAB
+                             AS2 (st,X+,r28)           CR_TAB
+                             AS2 (st,X,r29));
               else
-                return *l=6, (AS2 (mov,__tmp_reg__,%B1) CR_TAB
-                              AS2 (st,%0+,%A1) CR_TAB
-                              AS2 (st,%0+,__tmp_reg__)  CR_TAB
-                              AS2 (st,%0+,%C1) CR_TAB
-                              AS2 (st,%0,%D1)  CR_TAB
-                              AS2 (sbiw,r26,3));
+                return *l=7, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X+,__tmp_reg__)   CR_TAB
+                             AS2 (st,X+,r28)           CR_TAB
+                             AS2 (st,X,r29)            CR_TAB
+                             AS2 (sbiw,r26,3));
             }
           else if (reg_base == reg_src + 2)
             {
@@ -2167,32 +2217,65 @@ out_movsi_mr_r (insn, op, l)
   else if (GET_CODE (base) == PLUS) /* (R + i) */
     {
       int disp = INTVAL (XEXP (base, 1));
+      reg_base = REGNO (XEXP (base, 0));
       if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
        {
-         if (REGNO (XEXP (base, 0)) != REG_Y)
+         if (reg_base != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
+
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+           return *l = 6, (AS2 (adiw,r28,%o0-60) CR_TAB
+                           AS2 (std,Y+60,%A1)    CR_TAB
+                           AS2 (std,Y+61,%B1)    CR_TAB
+                           AS2 (std,Y+62,%C1)    CR_TAB
+                           AS2 (std,Y+63,%D1)    CR_TAB
+                           AS2 (sbiw,r28,%o0-60));
+
+         return *l = 8, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+                         AS2 (st,Y,%A1)           CR_TAB
+                         AS2 (std,Y+1,%B1)        CR_TAB
+                         AS2 (std,Y+2,%C1)        CR_TAB
+                         AS2 (std,Y+3,%D1)        CR_TAB
+                         AS2 (subi,r28,lo8(%o0))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o0)));
+       }
+      if (reg_base == REG_X)
+       {
+         /* (X + d) = R */
+         if (reg_src == REG_X)
            {
-             op[4] = GEN_INT (disp - 60);
-             return *l=6,(AS2 (adiw, r28, %4) CR_TAB
-                          AS2 (std, Y+60,%A1)       CR_TAB
-                          AS2 (std, Y+61,%B1)     CR_TAB
-                          AS2 (std, Y+62,%C1)     CR_TAB
-                          AS2 (std, Y+63,%D1)     CR_TAB
-                          AS2 (sbiw, r28, %4));
+             *l = 9;
+             return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+                     AS2 (mov,__zero_reg__,r27) CR_TAB
+                     AS2 (adiw,r26,%o0)         CR_TAB
+                     AS2 (st,X+,__tmp_reg__)    CR_TAB
+                     AS2 (st,X+,__zero_reg__)   CR_TAB
+                     AS2 (st,X+,r28)            CR_TAB
+                     AS2 (st,X,r29)             CR_TAB
+                     AS1 (clr,__zero_reg__)     CR_TAB
+                     AS2 (sbiw,r26,%o0+3));
            }
-         else
+         else if (reg_src == REG_X - 2)
            {
-             op[4] = XEXP (base, 1);
-             return *l=8,(AS2 (subi, r28, lo8(-%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                          AS2 (st, Y,%A1)             CR_TAB
-                          AS2 (std, Y+1,%B1)          CR_TAB
-                          AS2 (std, Y+2,%C1)          CR_TAB
-                          AS2 (std, Y+3,%D1)          CR_TAB
-                          AS2 (subi, r28, lo8(%4))   CR_TAB
-                          AS2 (sbci, r29, hi8(%4)));
+             *l = 9;
+             return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+                     AS2 (mov,__zero_reg__,r27) CR_TAB
+                     AS2 (adiw,r26,%o0)         CR_TAB
+                     AS2 (st,X+,r24)            CR_TAB
+                     AS2 (st,X+,r25)            CR_TAB
+                     AS2 (st,X+,__tmp_reg__)    CR_TAB
+                     AS2 (st,X,__zero_reg__)    CR_TAB
+                     AS1 (clr,__zero_reg__)     CR_TAB
+                     AS2 (sbiw,r26,%o0+3));
            }
+         *l = 6;
+         return (AS2 (adiw,r26,%o0) CR_TAB
+                 AS2 (st,X+,%A1)    CR_TAB
+                 AS2 (st,X+,%B1)    CR_TAB
+                 AS2 (st,X+,%C1)    CR_TAB
+                 AS2 (st,X,%D1)     CR_TAB
+                 AS2 (sbiw,r26,%o0+3));
        }
       return *l=4, (AS2 (std,%A0,%A1)    CR_TAB
                    AS2 (std,%B0,%B1) CR_TAB
@@ -2437,55 +2520,41 @@ out_movqi_mr_r (insn, op, l)
          int disp = INTVAL (XEXP (x,1));
          if (REGNO (XEXP (x,0)) != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
+
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
-           {
-             *l = 3;
-             op[4] = XEXP (x, 1);
-             return (AS2 (adiw, r28, %4-63) CR_TAB
-                     AS2 (std, Y+63,%1)        CR_TAB
-                     AS2 (sbiw, r28, %4-63));
-           }
-         else
-           {
-             *l = 5;
-             op[4] = XEXP (x,1);
-             return (AS2 (subi, r28, lo8(-%4))  CR_TAB
-                     AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                     AS2 (st, Y,%1)              CR_TAB
-                     AS2 (subi, r28, lo8(%4))   CR_TAB
-                     AS2 (sbci, r29, hi8(%4)));
-           }
+           return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
+                           AS2 (std,Y+63,%1)     CR_TAB
+                           AS2 (sbiw,r28,%o0-63));
+
+         return *l = 5, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+                         AS2 (st,Y,%1)            CR_TAB
+                         AS2 (subi,r28,lo8(%o0))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o0)));
        }
       else if (REGNO (XEXP (x,0)) == REG_X)
        {
-         op[4] = XEXP (x,1);
          if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
            {
              if (reg_unused_after (insn, XEXP (x,0)))
-               {
-                 *l = 3;
-                 return (AS2 (mov,__tmp_reg__,%1) CR_TAB
-                         AS2 (adiw,r26,%4)        CR_TAB
-                         AS2 (st,X,__tmp_reg__));
-               }
-             *l = 4;
-             return (AS2 (mov,__tmp_reg__,%1) CR_TAB
-                     AS2 (adiw,r26,%4)        CR_TAB
-                     AS2 (st,X,__tmp_reg__)   CR_TAB
-                     AS2 (sbiw,r26,%4));
+               return *l = 3, (AS2 (mov,__tmp_reg__,%1) CR_TAB
+                               AS2 (adiw,r26,%o0)       CR_TAB
+                               AS2 (st,X,__tmp_reg__));
+
+             return *l = 4, (AS2 (mov,__tmp_reg__,%1) CR_TAB
+                             AS2 (adiw,r26,%o0)       CR_TAB
+                             AS2 (st,X,__tmp_reg__)   CR_TAB
+                             AS2 (sbiw,r26,%o0));
            }
          else
            {
              if (reg_unused_after (insn, XEXP (x,0)))
-               {
-                 *l = 2;
-                 return (AS2 (adiw,r26,%4) CR_TAB
-                         AS2 (st,X,%1));
-               }
-             *l = 3;
-             return (AS2 (adiw,r26,%4) CR_TAB
-                     AS2 (st,X,%1)      CR_TAB
-                     AS2 (sbiw,r26,%4));
+               return *l = 2, (AS2 (adiw,r26,%o0) CR_TAB
+                               AS2 (st,X,%1));
+
+             return *l = 3, (AS2 (adiw,r26,%o0) CR_TAB
+                             AS2 (st,X,%1)      CR_TAB
+                             AS2 (sbiw,r26,%o0));
            }
        }
       *l = 1;
@@ -2526,15 +2595,18 @@ out_movhi_mr_r (insn, op, l)
         {
           if (reg_src == REG_X)
             {
+             /* "st X+,r26" is undefined */
               if (reg_unused_after (insn, src))
-                return *l=3, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-                              AS2 (st ,X+,r26) CR_TAB
-                              AS2 (st ,X,__tmp_reg__));
+               return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X,__tmp_reg__));
               else
-                return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-                              AS2 (st ,X+,r26) CR_TAB
-                              AS2 (st ,X,__tmp_reg__)   CR_TAB
-                              AS2 (sbiw,r26,1));
+               return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                             AS2 (st,X,r26)            CR_TAB
+                             AS2 (adiw,r26,1)          CR_TAB
+                             AS2 (st,X,__tmp_reg__)    CR_TAB
+                             AS2 (sbiw,r26,1));
             }
           else
             {
@@ -2554,28 +2626,44 @@ out_movhi_mr_r (insn, op, l)
   else if (GET_CODE (base) == PLUS)
     {
       int disp = INTVAL (XEXP (base, 1));
+      reg_base = REGNO (XEXP (base, 0));
       if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
        {
-         if (REGNO (XEXP (base, 0)) != REG_Y)
+         if (reg_base != REG_Y)
            fatal_insn ("Incorrect insn:",insn);
+
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+           return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
+                           AS2 (std,Y+62,%A1)    CR_TAB
+                           AS2 (std,Y+63,%B1)    CR_TAB
+                           AS2 (sbiw,r28,%o0-62));
+
+         return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+                         AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+                         AS2 (st,Y,%A1)           CR_TAB
+                         AS2 (std,Y+1,%B1)        CR_TAB
+                         AS2 (subi,r28,lo8(%o0))  CR_TAB
+                         AS2 (sbci,r29,hi8(%o0)));
+       }
+      if (reg_base == REG_X)
+       {
+         /* (X + d) = R */
+         if (reg_src == REG_X)
            {
-             op[4] = GEN_INT (disp - 62);
-             return *l=4,(AS2 (adiw, r28, %4) CR_TAB
-                          AS2 (std, Y+62,%A1) CR_TAB
-                          AS2 (std, Y+63,%B1) CR_TAB
-                          AS2 (sbiw, r28, %4));
-           }
-         else
-           {
-             op[4] = XEXP (base, 1);
-             return *l=6,(AS2 (subi, r28, lo8(-%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(-%4)) CR_TAB
-                          AS2 (st, Y,%A1)           CR_TAB
-                          AS2 (std, Y+1,%B1)        CR_TAB
-                          AS2 (subi, r28, lo8(%4))  CR_TAB
-                          AS2 (sbci, r29, hi8(%4)));
+             *l = 7;
+             return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+                     AS2 (mov,__zero_reg__,r27) CR_TAB
+                     AS2 (adiw,r26,%o0)         CR_TAB
+                     AS2 (st,X+,__tmp_reg__)    CR_TAB
+                     AS2 (st,X,__zero_reg__)    CR_TAB
+                     AS1 (clr,__zero_reg__)     CR_TAB
+                     AS2 (sbiw,r26,%o0+1));
            }
+         *l = 4;
+         return (AS2 (adiw,r26,%o0) CR_TAB
+                 AS2 (st,X+,%A1)    CR_TAB
+                 AS2 (st,X,%B1)     CR_TAB
+                 AS2 (sbiw,r26,%o0+1));
        }
       return *l=2, (AS2 (std,%A0,%A1)    CR_TAB
                    AS2 (std,%B0,%B1));
@@ -2601,39 +2689,52 @@ frame_pointer_required_p ()
          || get_frame_size () > 0);
 }
 
-/* Return 1 if the next insn is a JUMP_INSN with condition (GT,LE,GTU,LTU)  */
+/* Returns the condition of compare insn INSN, or UNKNOWN.  */
 
-int
-compare_diff_p (insn)
+static RTX_CODE
+compare_condition (insn)
      rtx insn;
 {
   rtx next = next_real_insn (insn);
   RTX_CODE cond = UNKNOWN;
-  if (GET_CODE (next) == JUMP_INSN)
+  if (next && GET_CODE (next) == JUMP_INSN)
     {
       rtx pat = PATTERN (next);
       rtx src = SET_SRC (pat);
-      rtx t = XEXP (src,0);
+      rtx t = XEXP (src, 0);
       cond = GET_CODE (t);
     }
+  return cond;
+}
+
+/* Returns nonzero if INSN is a tst insn that only tests the sign.  */
+
+static int
+compare_sign_p (insn)
+     rtx insn;
+{
+  RTX_CODE cond = compare_condition (insn);
+  return (cond == GE || cond == LT);
+}
+
+/* Returns nonzero if the next insn is a JUMP_INSN with a condition
+   that needs to be swapped (GT, GTU, LE, LEU).  */
+
+int
+compare_diff_p (insn)
+     rtx insn;
+{
+  RTX_CODE cond = compare_condition (insn);
   return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
 }
 
-/* Returns nonzero if INSN is a compare insn with the EQ or NE condition */
+/* Returns nonzero if INSN is a compare insn with the EQ or NE condition */
 
 int
 compare_eq_p (insn)
      rtx insn;
 {
-  rtx next = next_real_insn (insn);
-  RTX_CODE cond = UNKNOWN;
-  if (GET_CODE (next) == JUMP_INSN)
-    {
-      rtx pat = PATTERN (next);
-      rtx src = SET_SRC (pat);
-      rtx t = XEXP (src,0);
-      cond = GET_CODE (t);
-    }
+  RTX_CODE cond = compare_condition (insn);
   return (cond == EQ || cond == NE);
 }
 
@@ -2645,12 +2746,13 @@ out_tsthi (insn, l)
      rtx insn;
      int *l;
 {
-  if (!compare_eq_p (insn))
+  if (compare_sign_p (insn))
     {
       if (l) *l = 1;
       return AS1 (tst,%B0);
     }
-  if (reg_unused_after (insn, SET_SRC (PATTERN (insn))))
+  if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
+      && compare_eq_p (insn))
     {
       /* faster than sbiw if we can clobber the operand */
       if (l) *l = 1;
@@ -2674,7 +2776,7 @@ out_tstsi (insn, l)
      rtx insn;
      int *l;
 {
-  if (!compare_eq_p (insn))
+  if (compare_sign_p (insn))
     {
       if (l) *l = 1;
       return AS1 (tst,%D0);
@@ -4441,7 +4543,7 @@ unique_section (decl, reloc)
        prefix = ".text";
     }
   else 
-    fatal ("Strange situation: unique section is not a FUNCTION_DECL");
+    abort ();
 
   if (flag_function_sections)
     {
@@ -4453,23 +4555,6 @@ unique_section (decl, reloc)
 }
 
 
-/* Output section name to file FILE
-   We make the section read-only and executable for a function decl,
-   read-only for a const data decl, and writable for a non-const data decl.  */
-
-void
-asm_output_section_name(file, decl, name, reloc)
-     FILE *file;
-     tree decl;
-     const char *name;
-     int reloc ATTRIBUTE_UNUSED;
-{
-  fprintf (file, ".section %s, \"%s\", @progbits\n", name,
-          decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" :
-          decl && TREE_READONLY (decl) ? "a" : "aw");
-}
-
-
 /* The routine used to output NUL terminated strings.  We use a special
    version of this for most svr4 targets because doing so makes the
    generated assembly code more compact (and thus faster to assemble)
@@ -4582,8 +4667,8 @@ class_likely_spilled_p (c)
 
 /* Only `progmem' attribute valid for type.  */
 
-int
-valid_machine_type_attribute(type, attributes, identifier, args)
+static int
+avr_valid_type_attribute (type, attributes, identifier, args)
      tree type ATTRIBUTE_UNUSED;
      tree attributes ATTRIBUTE_UNUSED;
      tree identifier;
@@ -4602,8 +4687,8 @@ valid_machine_type_attribute(type, attributes, identifier, args)
    prologue interrupts are enabled;
    naked     - don't generate function prologue/epilogue and `ret' command.  */
 
-int
-valid_machine_decl_attribute (decl, attributes, attr, args)
+static int
+avr_valid_decl_attribute (decl, attributes, attr, args)
      tree decl;
      tree attributes ATTRIBUTE_UNUSED;
      tree attr;
@@ -4650,6 +4735,9 @@ avr_progmem_p (decl)
     a = TREE_TYPE(a);
   while (TREE_CODE (a) == ARRAY_TYPE);
 
+  if (a == error_mark_node)
+    return 0;
+
   if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
     return 1;
   
@@ -4664,10 +4752,9 @@ encode_section_info (decl)
 {
   if (TREE_CODE (decl) == FUNCTION_DECL)
     SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
-
-  if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
-      && TREE_CODE (decl) == VAR_DECL
-      && avr_progmem_p (decl))
+  else if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+          && TREE_CODE (decl) == VAR_DECL
+          && avr_progmem_p (decl))
     {
       const char *dsec = ".progmem.data";
       DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
@@ -4916,7 +5003,7 @@ avr_normalize_condition (condition)
     case LEU:
       return LTU;
     default:
-      fatal ("Wrong condition: %s", GET_RTX_NAME (condition));
+      abort ();
     }
 }
 
@@ -4927,20 +5014,17 @@ machine_dependent_reorg (first_insn)
      rtx first_insn;
 {
   rtx insn, pattern;
-  CC_STATUS_INIT;
   
   for (insn = first_insn; insn; insn = NEXT_INSN (insn))
     {
-      if (! (insn == 0 || GET_CODE (insn) == INSN
-            || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+      if (! (GET_CODE (insn) == INSN
+            || GET_CODE (insn) == CALL_INSN
+            || GET_CODE (insn) == JUMP_INSN)
          || !single_set (insn))
        continue;
 
       pattern = PATTERN (insn);
 
-      cc_prev_status = cc_status;
-      NOTICE_UPDATE_CC (pattern, insn);
-      
       if (GET_CODE (pattern) == PARALLEL)
        pattern = XVECEXP (pattern, 0, 0);
       if (GET_CODE (pattern) == SET
@@ -4992,16 +5076,12 @@ machine_dependent_reorg (first_insn)
              rtx src = SET_SRC (pat);
              rtx t = XEXP (src,0);
 
-             if (!(cc_prev_status.value1 != 0 && cc_status.value1 != 0
-                    && rtx_equal_p (cc_status.value1, cc_prev_status.value1)))
-                 {
-                   PUT_CODE (t, swap_condition (GET_CODE (t)));
-                   SET_SRC (pattern) = gen_rtx (NEG,
-                                                GET_MODE (SET_SRC (pattern)),
-                                                SET_SRC (pattern));
-                   INSN_CODE (next) = -1;
-                   INSN_CODE (insn) = -1;
-                 }
+             PUT_CODE (t, swap_condition (GET_CODE (t)));
+             SET_SRC (pattern) = gen_rtx (NEG,
+                                          GET_MODE (SET_SRC (pattern)),
+                                          SET_SRC (pattern));
+             INSN_CODE (next) = -1;
+             INSN_CODE (insn) = -1;
            }
        }
     }
@@ -5037,6 +5117,7 @@ avr_function_value (type, func)
      tree func ATTRIBUTE_UNUSED;
 {
   unsigned int offs;
+  
   if (TYPE_MODE (type) != BLKmode)
     return avr_libcall_value (TYPE_MODE (type));
   
@@ -5296,3 +5377,39 @@ avr_output_bld (operands, bit_nr)
   output_asm_insn (s, operands);
 }
 
+void
+avr_output_addr_vec_elt (stream, value)
+     FILE *stream;
+     int value;
+{
+  if (AVR_MEGA)
+    fprintf (stream, "\t.word pm(.L%d)\n", value);
+  else
+    fprintf (stream, "\trjmp .L%d\n", value);
+
+  jump_tables_size++;
+}
+
+/* Returns 1 if SCRATCH are safe to be allocated as a scratch
+   registers (for a define_peephole2) in the current function.  */
+
+int
+avr_peep2_scratch_safe (scratch)
+     rtx scratch;
+{
+  if ((interrupt_function_p (current_function_decl)
+       || signal_function_p (current_function_decl))
+      && leaf_function_p ())
+    {
+      int first_reg = true_regnum (scratch);
+      int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
+      int reg;
+
+      for (reg = first_reg; reg <= last_reg; reg++)
+       {
+         if (!regs_ever_live[reg])
+           return 0;
+       }
+    }
+  return 1;
+}